zmc
2023-08-08 e792e9a60d958b93aef96050644f369feb25d61b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
U
M±dÅ*ã@s®dZzddlmZmZmZWn(ek
rDddlmZmZmZYnXddlmZddlm    Z    Gdd„de
ƒZ Gdd    „d    e ƒZ Gd
d „d e ƒZ Gd d „d ƒZGdd„dƒZdS)aÅPooledPg - pooling for classic PyGreSQL connections.
 
Implements a pool of steady, thread-safe cached connections
to a PostgreSQL database which are transparently reused,
using the classic (not DB-API 2 compliant) PyGreSQL API.
 
This should result in a speedup for persistent applications such as the
application server of "Webware for Python," without loss of robustness.
 
Robustness is provided by using "hardened" SteadyPg connections.
Even if the underlying database is restarted and all connections
are lost, they will be automatically and transparently reopened.
However, since you don't want this to happen in the middle of a database
transaction, you must explicitly start transactions with the begin()
method so that SteadyPg knows that the underlying connection shall not
be replaced and errors passed on until the transaction is completed.
 
Measures are taken to make the pool of connections thread-safe
regardless of the fact that the classic PyGreSQL pg module itself
is not thread-safe at the connection level.
 
For more information on PostgreSQL, see:
    https://www.postgresql.org/
For more information on PyGreSQL, see:
    http://www.pygresql.org
For more information on Webware for Python, see:
    https://webwareforpython.github.io/w4py/
 
 
Usage:
 
First you need to set up the database connection pool by creating
an instance of PooledPg, passing the following parameters:
 
    mincached: the initial number of connections in the pool
        (the default of 0 means no connections are made at startup)
    maxcached: the maximum number of connections in the pool
        (the default value of 0 or None means unlimited pool size)
    maxconnections: maximum number of connections generally allowed
        (the default value of 0 or None means any number of connections)
    blocking: determines behavior when exceeding the maximum
        (if this is set to true, block and wait until the number of
        connections decreases, but by default an error will be reported)
    maxusage: maximum number of reuses of a single connection
        (the default of 0 or None means unlimited reuse)
        When this maximum usage number of the connection is reached,
        the connection is automatically reset (closed and reopened).
    setsession: an optional list of SQL commands that may serve to
        prepare the session, e.g. ["set datestyle to german", ...]
 
    Additionally, you have to pass the parameters for the actual
    PostgreSQL connection which are passed via PyGreSQL,
    such as the names of the host, database, user, password etc.
 
For instance, if you want a pool of at least five connections
to your local database 'mydb':
 
    from dbutils.pooled_pg import PooledPg
    pool = PooledPg(5, dbname='mydb')
 
Once you have set up the connection pool you can request
database connections from that pool:
 
    db = pool.connection()
 
You can use these connections just as if they were ordinary
classic PyGreSQL API connections.  Actually what you get is a
proxy class for the hardened SteadyPg version of the connection.
 
The connection will not be shared with other threads.  If you don't need
it any more, you should immediately return it to the pool with db.close().
You can get another connection in the same way or with db.reopen().
 
Warning: In a threaded environment, never do the following:
 
    res = pool.connection().query(...).getresult()
 
This would release the connection too early for reuse which may be
fatal because the connections are not thread-safe.  Make sure that the
connection object stays alive as long as you are using it, like that:
 
    db = pool.connection()
    res = db.query(...).getresult()
    db.close()  # or del db
 
Note that you need to explicitly start transactions by calling the
begin() method.  This ensures that the transparent reopening will be
suspended until the end of the transaction, and that the connection will
be rolled back before being given back to the connection pool.  To end
transactions, use one of the end(), commit() or rollback() methods.
 
 
Ideas for improvement:
 
* Add a thread for monitoring, restarting (or closing) bad or expired
  connections (similar to DBConnectionPool/ResourcePool by Warren Smith).
* Optionally log usage, bad connections and exceeding of limits.
 
 
Copyright, credits and license:
 
* Contributed as supplement for Webware for Python and PyGreSQL
  by Christoph Zwerschke in September 2005
* Based on the code of DBPool, contributed to Webware for Python
  by Dan Green in December 2000
 
Licensed under the MIT license.
é)ÚQueueÚEmptyÚFullé)Ú __version__)ÚSteadyPgConnectionc@seZdZdZdS)Ú PooledPgErrorzGeneral PooledPg error.N©Ú__name__Ú
__module__Ú __qualname__Ú__doc__©rrúHd:\z\workplace\vscode\pyvenv\venv\Lib\site-packages\dbutils/pooled_pg.pyrwsrc@seZdZdZdS)ÚInvalidConnectionzDatabase connection is invalid.Nr    rrrrr{src@seZdZdZdS)ÚTooManyConnectionsz*Too many database connections were opened.Nr    rrrrrsrc@sFeZdZdZeZddd„Zdd„Zd    d
„Zd d „Z    d d„Z
dd„Z dS)ÚPooledPgz§Pool for classic PyGreSQL connections.
 
    After you have created the connection pool, you can use
    connection() to get pooled, steady PostgreSQL connections.
    rFNc sÂ||    ˆ_ˆ_|ˆ_|ˆ_|p dˆ_|dkr0d}|dkr<d}|dkrHd}|rX||krX|}|r†||krh|}ddlm}
|
|ƒˆ_|ˆ_ndˆ_t    |ƒˆ_
‡fdd„t |ƒDƒ} | r¾|   ¡  ¡q¬dS)acSet up the PostgreSQL connection pool.
 
        mincached: initial number of connections in the pool
            (0 means no connections are made at startup)
        maxcached: maximum number of connections in the pool
            (0 or None means unlimited pool size)
        maxconnections: maximum number of connections generally allowed
            (0 or None means an arbitrary number of connections)
        blocking: determines behavior when exceeding the maximum
            (if this is set to true, block and wait until the number of
            connections decreases, otherwise an error will be reported)
        maxusage: maximum number of reuses of a single connection
            (0 or None means unlimited reuse)
            When this maximum usage number of the connection is reached,
            the connection is automatically reset (closed and reopened).
        setsession: optional list of SQL commands that may serve to prepare
            the session, e.g. ["set datestyle to ...", "set time zone ..."]
        reset: how connections should be reset when returned to the pool
            (0 or None to rollback transcations started with begin(),
            1 to always issue a rollback, 2 for a complete reset)
        args, kwargs: the parameters that shall be used to establish
            the PostgreSQL connections using class PyGreSQL pg.DB()
        rN)Ú    Semaphorecsg|] }ˆ ¡‘qSr)Ú
connection)Ú.0Úi©ÚselfrrÚ
<listcomp>Àsz%PooledPg.__init__.<locals>.<listcomp>)Ú_argsÚ_kwargsÚ    _maxusageÚ _setsessionÚ_resetÚ    threadingrÚ _connectionsÚ    _blockingrÚ_cacheÚrangeÚpopÚclose) rZ    mincachedZ    maxcachedZmaxconnectionsÚblockingZmaxusageZ
setsessionÚresetÚargsÚkwargsrZidlerrrÚ__init__Œs0
 
 
zPooledPg.__init__cCst|j|jdf|jž|jŽS)z-Get a steady, unpooled PostgreSQL connection.T)rrrrrrrrrÚsteady_connectionÄs
ÿÿzPooledPg.steady_connectioncCsP|jr|j |j¡st‚z|j d¡}Wntk
rD| ¡}YnXt||ƒS)z9Get a steady, cached PostgreSQL connection from the pool.r)    r Úacquirer!rr"Úgetrr+ÚPooledPgConnection©rÚconrrrrÉszPooledPg.connectioncCs†zT|jdkr| ¡n.|js"|jrDz | ¡Wntk
rBYnX|j |d¡Wntk
rp| ¡YnX|j    r‚|j     
¡dS)z*Put a connection back into the pool cache.érN) rr'Z _transactionÚrollbackÚ    Exceptionr"Úputrr%r Úreleaser/rrrÚcacheÔs
 
  zPooledPg.cachecCsbzB|j d¡}z | ¡Wntk
r.YnX|jr@|j ¡Wqtk
rZYq^YqXqdS)z"Close all connections in the pool.rN)r"r-r%r3r r5rr/rrrr%ås  zPooledPg.closecCs&z | ¡Wntk
r YnXdS)zDelete the pool.N©r%r3rrrrÚ__del__ós zPooledPg.__del__)rrrFNNN) r
r r r rÚversionr*r+rr6r%r8rrrrrƒsý
8 rc@s8eZdZdZdd„Zdd„Zdd„Zdd    „Zd
d „Zd S) r.z.Proxy class for pooled PostgreSQL connections.cCs||_||_dS)zCreate a pooled DB-API 2 connection.
 
        pool: the corresponding PooledPg instance
        con: the underlying SteadyPg connection
        N)Ú_poolÚ_con)rÚpoolr0rrrr*szPooledPgConnection.__init__cCs|jr|j |j¡d|_dS)zClose the pooled connection.N)r;r:r6rrrrr%    szPooledPgConnection.closecCs"|jr|j ¡n |j ¡|_dS)zReopen the pooled connection.N)r;Úreopenr:rrrrrr=s zPooledPgConnection.reopencCs|jrt|j|ƒSt‚dS)zProxy all members of the class.N)r;Úgetattrr)rÚnamerrrÚ __getattr__s zPooledPgConnection.__getattr__cCs&z | ¡Wntk
r YnXdS)zDelete the pooled connection.Nr7rrrrr8"s zPooledPgConnection.__del__N)    r
r r r r*r%r=r@r8rrrrr.ýs     
r.N)r rrrÚ ImportErrorÚqueueÚrZ    steady_pgrr3rrrrr.rrrrÚ<module>sm  z