All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ConnectionPool.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2008-2011 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(TR_PGIS("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 ? 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(TR_PGIS("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(TR_PGIS("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 }
std::size_t getMinPoolSize() const
It returns the minimum number of connections managed by the pool.
bool isValid() const
It checks if all the connections in the pool are valid (the communication channel is ok)...
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
boost::mutex m_mtx
A mutex for preventing reading/writing in the connection list.
ConnectionPool(DataSource *ds)
It creates a new connection pool for the database informed.
std::size_t getInitialPoolSize() const
It returns the initial number of connections opened by the pool at its startup.
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 setMaxPoolSize(std::size_t size)
It sets the maximum number of connections managed by the pool.
A class that implements a connection pool for PostGIS.
void setInitialPoolSize(std::size_t size)
It sets the initial number of connections opened by the pool at its startup.
std::size_t getPoolSize() const
It returns the number of connections in the pool.
void setMinPoolSize(std::size_t size)
It sets the minimum number of connections managed by the pool.
std::size_t m_initialPoolSize
It indicates the initial number of connections opened by the pool.
unsigned int m_maxIdleTime
The number of seconds waiting for releasing connections.
void idle()
It releases the connections that are not in use for a long time.
void setTimeAsInteger(bool timeIsInteger)
Definition: DataSource.cpp:125
An exception class for the PostGIS driver.
std::size_t m_minPoolSize
It indicates the minimum number of connections in the pool.
#define TR_PGIS(message)
It marks a string in order to get translated. This is a special mark used in the DataAccess module of...
Definition: Config.h:168
te::pgis::DataSource * m_ds
The data source using the pool.
std::size_t getMaxPoolSize() const
It returns the maximum number of connections managed by the pool.
#define PGIS_DEFAULT_MAX_POOL_SIZE
This sets the default maximum number of connections in the pool.
Definition: Config.h:55
bool m_initialized
A flag that indicates if the pool was initialized or not.
void release(Connection *conn)
It brings the informed connection back to the pool.
std::string m_conninfo
The connection info.
The PostGIS driver.
Definition: DataSource.h:54
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.
#define PGIS_DEFAULT_MIN_POOL_SIZE
This sets the default minimum number of connections to be kept in the pool.
Definition: Config.h:48
A class that implements a connection to a PostgreSQL database.
Definition: Connection.h:68
unsigned int getMaxIdleTime() const
It returns the maximum idle time in seconds that a connection can be maintained in the pool without b...
bool isInitialized() const
It returns true if the connection pool is initialized, otherwise it returns false.
void initialize()
It initializes the connections to be managed by the pool.
#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
ConnectionPoolImpl * m_pImpl
A pointer to the pool implementation.
std::string m_cencoding
Client encoding.
void finalize()
It closes all connections and clears all resources managed by the pool.
void setMaxIdleTime(unsigned int t)
It sets the maximum idle time that a connection can be maintained in the pool without being used...
Utility functions for PostgreSQL.
std::list< te::pgis::Connection * > m_connections
The list of available connections ready to be used.
boost::posix_time::ptime m_lastuse
It marks the last time this connection was used.
Definition: Connection.h:132
static ConnectionPoolManager & getInstance()
It returns a reference to the singleton instance.
#define PGIS_DEFAULT_INITIAL_POOL_SIZE
This sets the default initial number of connections opened by a connection pool.
Definition: Config.h:41
te::pgis::DataSource * getDataSource() const
std::string MakeConnectionStr(const std::map< std::string, std::string > &dsInfo)
Definition: Utils.cpp:346
std::size_t m_poolSize
It indicates the maximum number of connections in the pool.
Connection * getConnection()
It returns a connection from the pool.
bool m_inuse
Tells if the connection is in use or not.
Definition: Connection.h:131
Implementation of the data source for the PostGIS driver.