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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
U
M±dQã@s¤dZddlmZddlmZddlmZGdd„deƒZGdd    „d    eƒZ    Gd
d „d eƒZ
Gd d „d eƒZ Gdd„dƒZ Gdd„dƒZ Gdd„dƒZGdd„dƒZdS)a·PooledDB - pooling for DB-API 2 connections.
 
Implements a pool of steady, thread-safe cached connections
to a database which are transparently reused,
using an arbitrary DB-API 2 compliant database interface module.
 
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" SteadyDB 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 SteadyDB 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.
If the underlying DB-API module is thread-safe at the connection level,
the requested connections may be shared with other threads by default,
but you can also request dedicated connections in case you need them.
 
For the Python DB-API 2 specification, see:
    https://www.python.org/dev/peps/pep-0249/
For 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 PooledDB, passing the following parameters:
 
    creator: either an arbitrary function returning new DB-API 2
        connection objects or a DB-API 2 compliant database module
    mincached: the initial number of idle connections in the pool
        (the default of 0 means no connections are made at startup)
    maxcached: the maximum number of idle connections in the pool
        (the default value of 0 or None means unlimited pool size)
    maxshared: maximum number of shared connections allowed
        (the default value of 0 or None means all connections are dedicated)
        When this maximum number is reached, connections are
        shared if they have been requested as shareable.
    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", ...]
    reset: how connections should be reset when returned to the pool
        (False or None to rollback transcations started with begin(),
        the default value True always issues a rollback for safety's sake)
    failures: an optional exception class or a tuple of exception classes
        for which the connection failover mechanism shall be applied,
        if the default (OperationalError, InternalError) is not adequate
    ping: an optional flag controlling when connections are checked
        with the ping() method if such a method is available
        (0 = None = never, 1 = default = whenever fetched from the pool,
        2 = when a cursor is created, 4 = when a query is executed,
        7 = always, and all other bit combinations of these values)
 
    The creator function or the connect function of the DB-API 2 compliant
    database module specified as the creator will receive any additional
    parameters such as the host, database, user, password etc.  You may
    choose some or all of these parameters in your own creator function,
    allowing for sophisticated failover and load-balancing mechanisms.
 
For instance, if you are using pgdb as your DB-API 2 database module and
want a pool of at least five connections to your local database 'mydb':
 
    import pgdb  # import used DB-API 2 module
    from dbutils.pooled_db import PooledDB
    pool = PooledDB(pgdb, 5, database='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
DB-API 2 connections.  Actually what you get is the hardened
SteadyDB version of the underlying DB-API 2 connection.
 
Please note that the connection may be shared with other threads
by default if you set a non-zero maxshared parameter and the DB-API 2
module allows this.  If you want to have a dedicated connection, use:
 
    db = pool.connection(shareable=False)
 
You can also use this to get a dedicated connection:
 
    db = pool.dedicated_connection()
 
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.
 
Warning: In a threaded environment, never do the following:
 
    pool.connection().cursor().execute(...)
 
This would release the connection too early for reuse which may be
fatal if 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()
    cur = db.cursor()
    cur.execute(...)
    res = cur.fetchone()
    cur.close()  # or del cur
    db.close()  # or del db
 
Note that you need to explicitly start transactions by calling the
begin() method.  This ensures that the connection will not be shared
with other threads, 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.
 
 
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.
é)Ú    Conditioné)Ú __version__)Úconnectc@seZdZdZdS)Ú PooledDBErrorzGeneral PooledDB error.N©Ú__name__Ú
__module__Ú __qualname__Ú__doc__©r r úHd:\z\workplace\vscode\pyvenv\venv\Lib\site-packages\dbutils/pooled_db.pyr“src@seZdZdZdS)ÚInvalidConnectionzDatabase connection is invalid.Nrr r r r r—src@seZdZdZdS)ÚNotSupportedErrorz(DB-API module not supported by PooledDB.Nrr r r r r›src@seZdZdZdS)ÚTooManyConnectionsz*Too many database connections were opened.Nrr r r r rŸsrc
@s`eZdZdZeZddd„Zd    d
„Zdd d „Zd d„Z    dd„Z
dd„Z dd„Z dd„Z dd„ZdS)ÚPooledDBzPool for DB-API 2 connections.
 
    After you have created the connection pool, you can use
    connection() to get pooled, steady DB-API 2 connections.
    rFNTrc  sjz
|j}WnDtk
rNzt|jƒs*t‚Wntk
rDd}YnXd}YnX|s\tdƒ‚|ˆ_| | ˆ_ˆ_|ˆ_|ˆ_    |ˆ_
|    ˆ_ |
ˆ_ | ˆ_ |dkr d}|dkr¬d}|dkr¸d}|rÐ||krÈ|}|ˆ_ndˆ_|dkrð|rð|ˆ_gˆ_ndˆ_|r ||kr
|}||kr|}|ˆ_ndˆ_gˆ_tƒˆ_dˆ_‡fdd„t|ƒDƒ}|rf| ¡ ¡qPdS)a    Set up the DB-API 2 connection pool.
 
        creator: either an arbitrary function returning new DB-API 2
            connection objects or a DB-API 2 compliant database module
        mincached: initial number of idle connections in the pool
            (0 means no connections are made at startup)
        maxcached: maximum number of idle connections in the pool
            (0 or None means unlimited pool size)
        maxshared: maximum number of shared connections
            (0 or None means all connections are dedicated)
            When this maximum number is reached, connections are
            shared if they have been requested as shareable.
        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
            (False or None to rollback transcations started with begin(),
            True to always issue a rollback for safety's sake)
        failures: an optional exception class or a tuple of exception classes
            for which the connection failover mechanism shall be applied,
            if the default (OperationalError, InternalError) is not adequate
        ping: determines when the connection should be checked with ping()
            (0 = None = never, 1 = default = whenever fetched from the pool,
            2 = when a cursor is created, 4 = when a query is executed,
            7 = always, and all other bit combinations of these values)
        args, kwargs: the parameters that shall be passed to the creator
            function or the connection constructor of the DB-API 2 module
        érú#Database module is not thread-safe.Nrcsg|] }ˆ ¡‘qSr )Údedicated_connection)Ú.0Úi©Úselfr r Ú
<listcomp>sz%PooledDB.__init__.<locals>.<listcomp>)Ú threadsafetyÚAttributeErrorÚcallablerrÚ_creatorÚ_argsÚ_kwargsÚ    _blockingÚ    _maxusageÚ _setsessionÚ_resetÚ    _failuresÚ_pingÚ
_maxcachedÚ
_maxsharedÚ _shared_cacheÚ_maxconnectionsÚ _idle_cacherÚ_lockÚ _connectionsÚrangeÚpopÚclose)rZcreatorZ    mincachedZ    maxcachedZ    maxsharedZmaxconnectionsÚblockingZmaxusageZ
setsessionÚresetZfailuresZpingÚargsÚkwargsrZidler rr Ú__init__¬s^*
 
 
 
 
 
zPooledDB.__init__cCs(t|j|j|j|j|jdf|jž|jŽS)z+Get a steady, unpooled DB-API 2 connection.T)rrr!r"r$r%rrrr r r Ústeady_connection sþþþzPooledDB.steady_connectioncCs¼|r*|jr*|j ¡zø|js<|jr<|j|jkr<| ¡qt|jƒ|jkršz|j     
d¡}Wnt k
rx|  ¡}Yn
X|  ¡t|ƒ}|jd7_n^|j ¡|j 
d¡}|jjræ|j d|¡| ¡|j ¡|j 
d¡}q°|j  ¡| ¡|j |¡|j ¡W5|j ¡Xt||ƒ}nŽ|j ¡zv|jrX|j|jkrX| ¡q6z|j     
d¡}Wnt k
r†|  ¡}Yn
X|  ¡t||ƒ}|jd7_W5|j ¡X|S)zÂGet a steady, cached DB-API 2 connection from the pool.
 
        If shareable is set and the underlying DB-API 2 allows it,
        then the connection may be shared with other threads.
        rr)r'r+ÚacquireÚreleaser(r)r,Ú
_wait_lockÚlenr*r.Ú
IndexErrorr5Z _ping_checkÚSharedDBConnectionÚsortÚconÚ _transactionÚinsertÚshareÚappendÚnotifyÚPooledSharedDBConnectionÚPooledDedicatedDBConnection)rZ    shareabler=r r r Ú
connectionsV
 
ÿ
 
 
 
 
 
ÿ 
 zPooledDB.connectioncCs
| d¡S)z&Alias for connection(shareable=False).F)rErr r r rKszPooledDB.dedicated_connectioncCsh|j ¡z<| ¡|j}|sDz|j |¡Wntk
rBYnXW5|j ¡X|sd| |j    ¡dS)z7Decrease the share of a connection in the shared cache.N)
r+r6r7ÚunshareÚsharedr(ÚremoveÚ
ValueErrorÚcacher=)rr=rGr r r rFOs
 
 zPooledDB.unsharecCsr|j ¡zV|jr"t|jƒ|jkr>|j|jd|j |¡n| ¡|j    d8_    |j 
¡W5|j ¡XdS)z4Put a dedicated connection back into the idle cache.)ÚforcerN) r+r6r7r&r9r*r#rAr/r,rB©rr=r r r rJ_s
zPooledDB.cachecCs¬|j ¡z|jrB|j d¡}z | ¡Wq tk
r>Yq Xq |jrŽ|jrŽ|j d¡j    }z | ¡Wntk
r|YnX|j
d8_
qH|j  ¡W5|j ¡XdS)z"Close all connections in the pool.rrN) r+r6r7r*r.r/Ú    Exceptionr'r(r=r,Ú    notifyAllrLr r r r/ns$
   zPooledDB.closecCs&z | ¡Wntk
r YnXdS)zDelete the pool.N©r/rMrr r r Ú__del__„s zPooledDB.__del__cCs|js
t‚|j ¡dS)z'Wait until notified or report an error.N)r rr+Úwaitrr r r r8‹szPooledDB._wait_lock)
rrrrFNNTNr)T)rr    r
r rÚversionr4r5rErrFrJr/rPr8r r r r r£s*ü
_
:rc@s0eZdZdZdd„Zdd„Zdd„Zdd    „Zd
S) rDz7Auxiliary proxy class for pooled dedicated connections.cCs&d|_| ¡stdƒ‚||_||_dS)z‘Create a pooled dedicated connection.
 
        pool: the corresponding PooledDB instance
        con: the underlying SteadyDB connection
        Nr)Ú_conrrÚ_pool)rÚpoolr=r r r r4—s
z$PooledDedicatedDBConnection.__init__cCs|jr|j |j¡d|_dS)z&Close the pooled dedicated connection.N)rSrTrJrr r r r/¥sz!PooledDedicatedDBConnection.closecCs|jrt|j|ƒSt‚dS©zProxy all members of the class.N©rSÚgetattrr©rÚnamer r r Ú __getattr__­s z'PooledDedicatedDBConnection.__getattr__cCs&z | ¡Wntk
r YnXdS©zDelete the pooled connection.NrOrr r r rP´s z#PooledDedicatedDBConnection.__del__N©rr    r
r r4r/r[rPr r r r rD”s
rDc@sXeZdZdZdd„Zdd„Zdd„Zdd    „Zd
d „Zd d „Z    dd„Z
dd„Z dd„Z dS)r;z'Auxiliary class for shared connections.cCs||_d|_dS)zUCreate a shared connection.
 
        con: the underlying SteadyDB connection
        rN)r=rGrLr r r r4¿szSharedDBConnection.__init__cCs*|jj|jjkr|j|jkS|jj SdS©N©r=r>rG©rÚotherr r r Ú__lt__Çs zSharedDBConnection.__lt__cCs*|jj|jjkr|j|jkS|jj SdSr^r_r`r r r Ú__le__Ís zSharedDBConnection.__le__cCs|jj|jjko|j|jkSr^r_r`r r r Ú__eq__Ós
ÿzSharedDBConnection.__eq__cCs | |¡ Sr^)rdr`r r r Ú__ne__×szSharedDBConnection.__ne__cCs
| |¡Sr^)rbr`r r r Ú__gt__ÚszSharedDBConnection.__gt__cCs
| |¡Sr^)rcr`r r r Ú__ge__ÝszSharedDBConnection.__ge__cCs|jd7_dS)z&Increase the share of this connection.rN©rGrr r r r@àszSharedDBConnection.sharecCs|jd8_dS)z&Decrease the share of this connection.rNrhrr r r rFäszSharedDBConnection.unshareN) rr    r
r r4rbrcrdrerfrgr@rFr r r r r;¼sr;c@s0eZdZdZdd„Zdd„Zdd„Zdd    „Zd
S) rCz4Auxiliary proxy class for pooled shared connections.cCs6d|_|j}| ¡dks tdƒ‚||_||_||_dS)zCreate a pooled shared connection.
 
        pool: the corresponding PooledDB instance
        con: the underlying SharedDBConnection
        Nrz'Database connection is not thread-safe.)rSr=rrrTÚ _shared_con)rrUZ
shared_conr=r r r r4ìs z!PooledSharedDBConnection.__init__cCs$|jr |j |j¡d|_|_dS)z#Close the pooled shared connection.N)rSrTrFrirr r r r/üszPooledSharedDBConnection.closecCs|jrt|j|ƒSt‚dSrVrWrYr r r r[s z$PooledSharedDBConnection.__getattr__cCs&z | ¡Wntk
r YnXdSr\rOrr r r rP s z PooledSharedDBConnection.__del__Nr]r r r r rCés
rCN)r Ú    threadingrÚrZ    steady_dbrrMrrrrrrDr;rCr r r r Ú<module>s   r(-