All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
ConnectionPool.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2008 National Institute For Space Research (INPE) - Brazil.
2 
3  This file is part of the TerraLib - a Framework for building GIS enabled applications.
4 
5  TerraLib is free software: you can redistribute it and/or modify
6  it under the terms of the GNU Lesser General Public License as published by
7  the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  TerraLib is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public License
16  along with TerraLib. See COPYING. If not, write to
17  TerraLib Team at <terralib-team@terralib.org>.
18  */
19 
20 /*!
21  \file terralib/postgis/ConnectionPool.cpp
22 
23  \brief A class that implements a connection pool for PostGIS.
24 */
25 
26 // TerraLib
27 #include "../common/Enums.h"
28 #include "../common/STLUtils.h"
29 #include "../common/Translator.h"
30 #include "../dataaccess/datasource/ConnectionPoolManager.h"
31 #include "Connection.h"
32 #include "ConnectionPool.h"
33 #include "DataSource.h"
34 #include "Exception.h"
35 #include "Utils.h"
36 
37 // STL
38 #include <list>
39 
40 // BOOST
41 #include <boost/thread/locks.hpp>
42 #include <boost/thread/mutex.hpp>
43 
44 // libpq
45 #include <libpq-fe.h>
46 
48 {
49  public:
50 
52  : m_ds(ds),
56  m_poolSize(0),
58  m_initialized(false)
59  {
60  }
61 
63  {
65  }
66 
67  std::string m_conninfo; //!< The connection info.
68  std::string m_cencoding; //!< Client encoding.
69  te::pgis::DataSource* m_ds; //!< The data source using the pool.
70  std::size_t m_initialPoolSize; //!< It indicates the initial number of connections opened by the pool.
71  std::size_t m_minPoolSize; //!< It indicates the minimum number of connections in the pool.
72  std::size_t m_maxPoolSize; //!< It indicates the maximum number of connections in the pool.
73  std::size_t m_poolSize; //!< It indicates the maximum number of connections in the pool.
74  unsigned int m_maxIdleTime; //!< The number of seconds waiting for releasing connections.
75  std::list<te::pgis::Connection*> m_connections; //!< The list of available connections ready to be used.
76  boost::mutex m_mtx; //!< A mutex for preventing reading/writing in the connection list.
77  bool m_initialized; //!< A flag that indicates if the pool was initialized or not.
78 };
79 
81 {
82 // acquire lock
83  boost::lock_guard<boost::mutex> lock(m_pImpl->m_mtx);
84 
85  if(isInitialized())
86  throw Exception(TE_TR("The connection pool is already initialized!"));
87 
88 // check for pool parameters...
89  const std::map<std::string, std::string>& connInfo = m_pImpl->m_ds->getConnectionInfo();
90 
91  std::map<std::string, std::string>::const_iterator itend = connInfo.end();
92 
93  std::map<std::string, std::string>::const_iterator it = connInfo.find("PG_INITIAL_POOL_SIZE");
94  m_pImpl->m_initialPoolSize = (it != itend && !it->second.empty()) ? atoi(it->second.c_str()) : PGIS_DEFAULT_INITIAL_POOL_SIZE;
95 
96  it = connInfo.find("PG_MIN_POOL_SIZE");
97  m_pImpl->m_minPoolSize = (it != itend && !it->second.empty()) ? atoi(it->second.c_str()) : PGIS_DEFAULT_MIN_POOL_SIZE;
98 
99  it = connInfo.find("PG_MAX_POOL_SIZE");
100  m_pImpl->m_maxPoolSize = (it != itend && !it->second.empty()) ? atoi(it->second.c_str()) : PGIS_DEFAULT_MAX_POOL_SIZE;
101 
102 // assure valid values for pool parameters
105 
110 
111  it = connInfo.find("PG_MAX_IDLE_TIME");
112  m_pImpl->m_maxIdleTime = (it != itend && !it->second.empty()) ? atoi(it->second.c_str()) : PGIS_DEFAULT_MAX_IDLE_TIME;
113 
114  it = connInfo.find("PG_CLIENT_ENCODING");
115  m_pImpl->m_cencoding = (it != itend ? GetPGEncoding(te::common::CharEncodingConv::getCharEncodingType(it->second)) : std::string(""));
116 
117 // make connection info
118  m_pImpl->m_conninfo = MakeConnectionStr(connInfo);
119 
120 // try to open the connections
121  for(std::size_t i = 0; i < m_pImpl->m_initialPoolSize; ++i)
122  {
123  Connection* conn = new Connection(this, m_pImpl->m_conninfo, m_pImpl->m_cencoding, false);
124  m_pImpl->m_connections.push_back(conn);
125  ++(m_pImpl->m_poolSize);
126  }
127 
128 // verify the internal date time storage
129  if(!m_pImpl->m_connections.empty())
130  {
131  std::string off = "off";
132 
133  std::string answer = PQparameterStatus(m_pImpl->m_connections.front()->m_pgconn, "integer_datetimes");
134 
135  if(answer == off)
136  m_pImpl->m_ds->setTimeAsInteger(false);
137  else
138  m_pImpl->m_ds->setTimeAsInteger(true);
139  }
140 
141  m_pImpl->m_initialized = true;
142 }
143 
145 {
146 // acquire lock
147  boost::lock_guard<boost::mutex> lock(m_pImpl->m_mtx);
148 
149 // if there is a connection in use it will raise an exception!
150  std::list<te::pgis::Connection*>::iterator it = m_pImpl->m_connections.begin();
151  std::list<te::pgis::Connection*>::iterator itend = m_pImpl->m_connections.end();
152 
153  while(it != itend)
154  {
155  if((*it)->m_inuse)
156  throw Exception(TE_TR("There are opened connections. Please, close all connections before finalizing the connection pool."));
157 
158  ++it;
159  }
160 
161 // release all connections
162  te::common::FreeContents(m_pImpl->m_connections);
163 
164  m_pImpl->m_connections.clear();
165  m_pImpl->m_poolSize = 0;
166 
167  m_pImpl->m_initialized = false;
168 }
169 
171 {
172 // acquire lock
173  boost::lock_guard<boost::mutex> lock(m_pImpl->m_mtx);
174 
175 // must we check the pool?
176 // no: we don't care about monitoring
177 // no: we weren't initialized
178 // no: if the pool has a fixed size we don't need to care about it!
179 // no: we have just the minimum pool connections
180  if((m_pImpl->m_maxIdleTime == 0) ||
181  !isInitialized() ||
182  (m_pImpl->m_maxPoolSize == m_pImpl->m_minPoolSize) ||
183  (m_pImpl->m_poolSize == m_pImpl->m_minPoolSize))
184  return;
185 
186 // what time is it?
187  boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
188 
189 // release all connections not in use whose time has expired
190  std::list<te::pgis::Connection*>::iterator it = m_pImpl->m_connections.begin();
191  std::list<te::pgis::Connection*>::iterator itend = m_pImpl->m_connections.end();
192 
193  while(it != itend)
194  {
195  if((*it)->m_inuse == false)
196  {
197  boost::posix_time::time_duration d = now - (*it)->m_lastuse;
198 
199  if(d.seconds() > static_cast<long>(m_pImpl->m_maxIdleTime))
200  {
201  std::list<te::pgis::Connection*>::iterator itaux = it;
202  ++it; // advance current iterator... we will release the connection pointed by the auxiliar iterator
203  delete *itaux;
204  m_pImpl->m_connections.erase(itaux);
205  --(m_pImpl->m_poolSize);
206 
207  if(m_pImpl->m_poolSize == m_pImpl->m_minPoolSize) // have we reached the minimum pool size?
208  break;
209 
210  continue; // we have already go on... (++it)!
211  }
212  }
213 
214  ++it;
215  }
216 }
217 
219 {
220 // acquire lock
221  boost::lock_guard<boost::mutex> lock(m_pImpl->m_mtx);
222 
223  std::list<te::pgis::Connection*>::iterator it = m_pImpl->m_connections.begin();
224  std::list<te::pgis::Connection*>::iterator itend = m_pImpl->m_connections.end();
225 
226  while(it != itend)
227  {
228  ConnStatusType status = PQstatus((*it)->m_pgconn);
229 
230  if(status != CONNECTION_OK)
231  return false;
232 
233  ++it;
234  }
235 
236  return true;
237 }
238 
240 {
241  return m_pImpl->m_initialized;
242 }
243 
245 {
246  return m_pImpl->m_ds;
247 }
248 
250 {
251  return m_pImpl->m_poolSize;
252 }
253 
255 {
256  return m_pImpl->m_initialPoolSize;
257 }
258 
260 {
261 // acquire lock
262  boost::lock_guard<boost::mutex> lock(m_pImpl->m_mtx);
263 
264  m_pImpl->m_initialPoolSize = size;
265 }
266 
268 {
269  return m_pImpl->m_minPoolSize;
270 }
271 
273 {
274 // acquire lock
275  boost::lock_guard<boost::mutex> lock(m_pImpl->m_mtx);
276 
277  m_pImpl->m_minPoolSize = size;
278 }
279 
281 {
282  return m_pImpl->m_maxPoolSize;
283 }
284 
286 {
287 // acquire lock
288  boost::lock_guard<boost::mutex> lock(m_pImpl->m_mtx);
289 
290  m_pImpl->m_maxPoolSize = size;
291 }
292 
294 {
295 // acquire lock
296  boost::lock_guard<boost::mutex> lock(m_pImpl->m_mtx);
297 
298 // search for available connections: we are optmistic - just try to open a new connection if none exist!
299  std::list<te::pgis::Connection*>::iterator it = m_pImpl->m_connections.begin();
300  std::list<te::pgis::Connection*>::iterator itend = m_pImpl->m_connections.end();
301 
302  while(it != itend)
303  {
304  if((*it)->m_inuse == false)
305  {
306  (*it)->m_inuse = true;
307  return (*it);
308  }
309 
310  ++it;
311  }
312 
313 // if we couldn't find an opened connection maybe we may create one and return it
314  if(m_pImpl->m_poolSize < m_pImpl->m_maxPoolSize)
315  {
316  Connection* newConn = new Connection(this, m_pImpl->m_conninfo.c_str(), m_pImpl->m_cencoding.c_str(), true);
317  m_pImpl->m_connections.push_back(newConn);
318  ++(m_pImpl->m_poolSize);
319 
320  return newConn;
321  }
322 
323  throw Exception(TE_TR("The connection pool has reached its maximum size!"), te::common::NO_CONNECTION_AVAILABLE);
324 }
325 
327 {
328 // acquire lock
329  boost::lock_guard<boost::mutex> lock(m_pImpl->m_mtx);
330 
331  conn->m_inuse = false;
332  conn->m_lastuse = boost::posix_time::second_clock::local_time();
333 }
334 
336 {
337  return m_pImpl->m_maxIdleTime;
338 }
339 
341 {
342 // acquire lock
343  boost::lock_guard<boost::mutex> lock(m_pImpl->m_mtx);
344 
345  m_pImpl->m_maxIdleTime = t;
346 }
347 
349  : m_pImpl(0)
350 {
351  m_pImpl = new ConnectionPoolImpl(ds);
352 
354 }
355 
357 {
359 
360  delete m_pImpl;
361 }
unsigned int m_maxIdleTime
The number of seconds waiting for releasing connections.
unsigned int getMaxIdleTime() const
It returns the maximum idle time in seconds that a connection can be maintained in the pool without b...
void idle()
It releases the connections that are not in use for a long time.
bool isValid() const
It checks if all the connections in the pool are valid (the communication channel is ok)...
std::string MakeConnectionStr(const std::map< std::string, std::string > &dsInfo)
Definition: Utils.cpp:355
void setInitialPoolSize(std::size_t size)
It sets the initial number of connections opened by the pool at its startup.
std::string m_cencoding
Client encoding.
std::list< te::pgis::Connection * > m_connections
The list of available connections ready to be used.
bool isInitialized() const
It returns true if the connection pool is initialized, otherwise it returns false.
#define PGIS_DEFAULT_INITIAL_POOL_SIZE
This sets the default initial number of connections opened by a connection pool.
Definition: Config.h:41
void setMaxIdleTime(unsigned int t)
It sets the maximum idle time that a connection can be maintained in the pool without being used...
std::size_t getPoolSize() const
It returns the number of connections in the pool.
void setMaxPoolSize(std::size_t size)
It sets the maximum number of connections managed by the pool.
boost::mutex m_mtx
A mutex for preventing reading/writing in the connection list.
A class that implements a connection to a PostgreSQL database.
Definition: Connection.h:68
const char * GetPGEncoding(te::common::CharEncoding encoding)
Definition: Utils.cpp:662
#define TE_TR(message)
It marks a string in order to get translated.
Definition: Translator.h:347
std::size_t getMinPoolSize() const
It returns the minimum number of connections managed by the pool.
void setTimeAsInteger(bool timeIsInteger)
Definition: DataSource.cpp:125
The PostGIS driver.
Definition: DataSource.h:54
void release(Connection *conn)
It brings the informed connection back to the pool.
#define PGIS_DEFAULT_MIN_POOL_SIZE
This sets the default minimum number of connections to be kept in the pool.
Definition: Config.h:48
const std::map< std::string, std::string > & getConnectionInfo() const
It returns the set of parameters used to set up the access channel to the underlying repository...
Definition: DataSource.cpp:93
static ConnectionPoolManager & getInstance()
It returns a reference to the singleton instance.
Utility functions for PostgreSQL.
boost::posix_time::ptime m_lastuse
It marks the last time this connection was used.
Definition: Connection.h:132
#define PGIS_DEFAULT_MAX_IDLE_TIME
This sets the default maximum time that a connection can be in the pool without being used...
Definition: Config.h:62
static CharEncoding getCharEncodingType(const std::string &name)
It returns the charset type of the given charset name.
#define PGIS_DEFAULT_MAX_POOL_SIZE
This sets the default maximum number of connections in the pool.
Definition: Config.h:55
void initialize()
It initializes the connections to be managed by the pool.
std::size_t getInitialPoolSize() const
It returns the initial number of connections opened by the pool at its startup.
void setMinPoolSize(std::size_t size)
It sets the minimum number of connections managed by the pool.
ConnectionPoolImpl * m_pImpl
A pointer to the pool implementation.
A class that implements a connection to a PostgreSQL database.
std::size_t m_maxPoolSize
It indicates the maximum number of connections in the pool.
Implementation of the data source for the PostGIS driver.
An exception class for the PostGIS driver.
te::pgis::DataSource * m_ds
The data source using the pool.
std::size_t m_initialPoolSize
It indicates the initial number of connections opened by the pool.
std::size_t m_minPoolSize
It indicates the minimum number of connections in the pool.
Connection * getConnection()
It returns a connection from the pool.
std::string m_conninfo
The connection info.
te::pgis::DataSource * getDataSource() const
A class that implements a connection pool for PostGIS.
std::size_t getMaxPoolSize() const
It returns the maximum number of connections managed by the pool.
ConnectionPool(DataSource *ds)
It creates a new connection pool for the database informed.
void FreeContents(boost::unordered_map< K, V * > &m)
This function can be applied to a map of pointers. It will delete each pointer in the map...
Definition: BoostUtils.h:55
void finalize()
It closes all connections and clears all resources managed by the pool.
bool m_inuse
Tells if the connection is in use or not.
Definition: Connection.h:131
std::size_t m_poolSize
It indicates the maximum number of connections in the pool.
bool m_initialized
A flag that indicates if the pool was initialized or not.