2
2
from __future__ import absolute_import , division , print_function
3
3
4
4
from collections import deque
5
- import sys
6
5
import warnings
7
6
8
7
from tornado .ioloop import IOLoop
9
8
from tornado .gen import coroutine , Return
10
- from tornado .concurrent import Future
9
+ from tornado .concurrent import Future , chain_future
10
+
11
11
from tornado_mysql import connect
12
+ from tornado_mysql .connections import Connection
12
13
13
14
14
15
DEBUG = False
@@ -32,52 +33,84 @@ def __init__(self,
32
33
connect_kwargs ,
33
34
max_idle_connections = 1 ,
34
35
max_recycle_sec = 3600 ,
36
+ max_open_connections = 0 ,
35
37
io_loop = None ,
36
38
):
37
39
"""
38
40
:param dict connect_kwargs: kwargs for tornado_mysql.connect()
39
41
:param int max_idle_connections: Max number of keeping connections.
40
42
:param int max_recycle_sec: How long connections are recycled.
43
+ :param int max_open_connections:
44
+ Max number of opened connections. 0 means no limit.
41
45
"""
42
46
connect_kwargs ['autocommit' ] = True
43
47
self .io_loop = io_loop or IOLoop .current ()
44
48
self .connect_kwargs = connect_kwargs
45
- self .max_idle_connections = max_idle_connections
49
+ self .max_idle = max_idle_connections
50
+ self .max_open = max_open_connections
46
51
self .max_recycle_sec = max_recycle_sec
47
52
48
53
self ._opened_conns = 0
49
54
self ._free_conn = deque ()
55
+ self ._waitings = deque ()
56
+
57
+ def stat (self ):
58
+ return (self ._opened_conns , len (self ._free_conn ), len (self ._waitings ))
50
59
51
60
def _get_conn (self ):
52
61
now = self .io_loop .time ()
62
+
63
+ # Try to reuse in free pool
53
64
while self ._free_conn :
54
65
conn = self ._free_conn .popleft ()
55
66
if now - conn .connected_time > self .max_recycle_sec :
56
67
self ._close_async (conn )
57
68
continue
58
- _debug ("Reusing connection from pool (opened=%d)" % ( self ._opened_conns , ))
69
+ _debug ("Reusing connection from pool:" , self .stat ( ))
59
70
fut = Future ()
60
71
fut .set_result (conn )
61
72
return fut
62
73
63
- self ._opened_conns += 1
64
- _debug ("Creating new connection (opened=%d)" % (self ._opened_conns ,))
65
- return connect (** self .connect_kwargs )
74
+ # Open new connection
75
+ if self .max_open and self ._opened_conns < self .max_open :
76
+ self ._opened_conns += 1
77
+ _debug ("Creating new connection:" , self .stat ())
78
+ return connect (** self .connect_kwargs )
79
+
80
+ # Wait to other connection is released.
81
+ fut = Future ()
82
+ self ._waitings .append (fut )
83
+ return fut
66
84
67
85
def _put_conn (self , conn ):
68
- if (len (self ._free_conn ) < self .max_idle_connections and
86
+ if (len (self ._free_conn ) < self .max_idle and
69
87
self .io_loop .time () - conn .connected_time < self .max_recycle_sec ):
70
- self ._free_conn .append (conn )
88
+ if self ._waitings :
89
+ fut = self ._waitings .popleft ()
90
+ fut .set_result (conn )
91
+ _debug ("Passing returned connection to waiter:" , self .stat ())
92
+ else :
93
+ self ._free_conn .append (conn )
94
+ _debug ("Add conn to free pool:" , self .stat ())
71
95
else :
72
96
self ._close_async (conn )
73
97
74
98
def _close_async (self , conn ):
75
- self .io_loop .add_future (conn .close_async (), callback = lambda f : None )
76
- self ._opened_conns -= 1
99
+ self .io_loop .add_future (conn .close_async (), callback = self ._after_close )
77
100
78
101
def _close_conn (self , conn ):
79
102
conn .close ()
80
- self ._opened_conns -= 1
103
+ self ._after_close ()
104
+
105
+ def _after_close (self , fut = None ):
106
+ if self ._waitings :
107
+ fut = self ._waitings .popleft ()
108
+ conn = Connection (** self .connect_kwargs )
109
+ cf = conn .connect ()
110
+ self .io_loop .add_future (cf , callback = lambda f : fut .set_result (conn ))
111
+ else :
112
+ self ._opened_conns -= 1
113
+ _debug ("Connection closed:" , self .stat ())
81
114
82
115
@coroutine
83
116
def execute (self , query , params = None ):
@@ -94,11 +127,11 @@ def execute(self, query, params=None):
94
127
cur = conn .cursor ()
95
128
yield cur .execute (query , params )
96
129
yield cur .close ()
97
- self ._put_conn (conn )
98
130
except :
99
- self ._opened_conns -= 1
100
- conn .close ()
131
+ self ._close_conn (conn )
101
132
raise
133
+ else :
134
+ self ._put_conn (conn )
102
135
raise Return (cur )
103
136
104
137
@coroutine
0 commit comments