Aestate
simple_pooled_pg.py
Go to the documentation of this file.
1 """SimplePooledPg - a very simple classic PyGreSQL connection pool.
2 
3 Implements a pool of threadsafe cached connections
4 to a PostgreSQL database which are transparently reused,
5 using the classic (not DB-API 2 compliant) PyGreSQL pg API.
6 
7 This should result in a speedup for persistent applications
8 such as the "Webware for Python" AppServer.
9 
10 For more information on PostgreSQL, see:
11  https://www.postgresql.org/
12 For more information on PyGreSQL, see:
13  http://www.pygresql.org
14 For more information on Webware for Python, see:
15  https://webwareforpython.github.io/w4py/
16 
17 Measures are taken to make the pool of connections threadsafe
18 regardless of the fact that the PyGreSQL pg module itself is
19 not threadsafe at the connection level. Connections will never be
20 shared between threads, so you can safely use transactions.
21 
22 Usage:
23 
24 The idea behind SimplePooledPg is that it's completely transparent.
25 After you have established your connection pool, stating the
26 number of connections to be cached in the pool and the
27 connection parameters, e.g.
28 
29  from dbutils.simple_pooled_pg import PooledPg
30  dbpool = PooledPg(5, host=..., database=..., user=..., ...)
31 
32 you can demand database connections from that pool,
33 
34  db = dbpool.connection()
35 
36 and use them just as if they were ordinary PyGreSQL pg API
37 connections. It's really just a proxy class.
38 
39 db.close() will return the connection to the pool, it will not
40 actually close it. This is so your existing code works nicely.
41 
42 Ideas for improvement:
43 
44 * Do not create the maximum number of connections on startup
45 already, but only a certain number and the rest on demand.
46 * Detect and transparently reset "bad" connections. The PyGreSQL
47 pg API provides a status attribute and a reset() method for that.
48 * Connections should have some sort of "maximum usage limit"
49 after which they should be automatically closed and reopened.
50 * Prefer or enforce thread affinity for the connections.
51 
52 Please note that these and other ideas have been already
53 implemented in in PooledPg, a more sophisticated version
54 of SimplePooledPg. You might also consider using PersistentPg
55 instead for thread-affine persistent PyGreSQL connections.
56 SimplePooledPg may still serve as a very simple reference
57 and example implementation for developers.
58 
59 
60 Copyright, credits and license:
61 
62 * Contributed as supplement for Webware for Python and PyGreSQL
63  by Christoph Zwerschke in September 2005
64 * Based on the code of DBPool, contributed to Webware for Python
65  by Dan Green in December 2000
66 
67 Licensed under the MIT license.
68 """
69 
70 from pg import DB as PgConnection
71 
72 from . import __version__
73 
74 
76  """A proxy class for pooled PostgreSQL connections.
77 
78  You don't normally deal with this class directly,
79  but use PooledPg to get new connections.
80  """
81 
82  def __init__(self, pool, con):
83  self._con = con
84  self._pool = pool
85 
86  def close(self):
87  """Close the pooled connection."""
88  # Instead of actually closing the connection,
89  # return it to the pool so it can be reused.
90  if self._con is not None:
91  self._pool.cache(self._con)
92  self._con = None
93 
94  def __getattr__(self, name):
95  # All other members are the same.
96  return getattr(self._con, name)
97 
98  def __del__(self):
99  self.close()
100 
101 
102 class PooledPg:
103  """A very simple PostgreSQL connection pool.
104 
105  After you have created the connection pool,
106  you can get connections using getConnection().
107  """
108 
109  version = __version__
110 
111  def __init__(self, maxconnections, *args, **kwargs):
112  """Set up the PostgreSQL connection pool.
113 
114  maxconnections: the number of connections cached in the pool
115  args, kwargs: the parameters that shall be used to establish
116  the PostgreSQL connections using pg.connect()
117  """
118  # Since there is no connection level safety, we
119  # build the pool using the synchronized queue class
120  # that implements all the required locking semantics.
121  try:
122  from Queue import Queue
123  except ImportError: # Python 3
124  from queue import Queue
125  self._queue = Queue(maxconnections)
126  # Establish all database connections (it would be better to
127  # only establish a part of them now, and the rest on demand).
128  for i in range(maxconnections):
129  self.cache(PgConnection(*args, **kwargs))
130 
131  def cache(self, con):
132  """Add or return a connection to the pool."""
133  self._queue.put(con)
134 
135  def connection(self):
136  """Get a connection from the pool."""
137  return PooledPgConnection(self, self._queue.get())
aestate.opera.DBPool.simple_pooled_pg.PooledPgConnection
Definition: simple_pooled_pg.py:75
aestate.opera.DBPool.simple_pooled_pg.PooledPgConnection._pool
_pool
Definition: simple_pooled_pg.py:84
aestate.opera.DBPool.simple_pooled_pg.PooledPgConnection.__getattr__
def __getattr__(self, name)
Definition: simple_pooled_pg.py:94
aestate.opera.DBPool.simple_pooled_pg.PooledPg
Definition: simple_pooled_pg.py:102
aestate.opera.DBPool.simple_pooled_pg.PooledPg._queue
_queue
Definition: simple_pooled_pg.py:125
aestate.opera.DBPool.simple_pooled_pg.PooledPg.connection
def connection(self)
Definition: simple_pooled_pg.py:135
aestate.opera.DBPool.simple_pooled_pg.PooledPg.cache
def cache(self, con)
Definition: simple_pooled_pg.py:131
aestate.opera.DBPool.simple_pooled_pg.PooledPgConnection._con
_con
Definition: simple_pooled_pg.py:83
aestate.opera.DBPool.simple_pooled_pg.PooledPgConnection.close
def close(self)
Definition: simple_pooled_pg.py:86
aestate.opera.DBPool.simple_pooled_pg.PooledPg.__init__
def __init__(self, maxconnections, *args, **kwargs)
Definition: simple_pooled_pg.py:111
aestate.opera.DBPool.simple_pooled_pg.PooledPgConnection.__init__
def __init__(self, pool, con)
Definition: simple_pooled_pg.py:82
aestate.opera.DBPool.simple_pooled_pg.PooledPgConnection.__del__
def __del__(self)
Definition: simple_pooled_pg.py:98