author | Adrien Di Mascio <Adrien.DiMascio@logilab.fr> |
Wed, 23 Sep 2009 09:54:25 +0200 | |
changeset 3396 | fb261afd49cd |
parent 2835 | 04034421b072 |
child 3720 | 5376aaadd16b |
permissions | -rw-r--r-- |
2835
04034421b072
[hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2765
diff
changeset
|
1 |
"""CubicWeb server connections pool : the repository has a limited number of |
04034421b072
[hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2765
diff
changeset
|
2 |
connections pools, each of them dealing with a set of connections on each source |
04034421b072
[hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2765
diff
changeset
|
3 |
used by the repository. A connections pools (`ConnectionsPool`) is an |
04034421b072
[hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2765
diff
changeset
|
4 |
abstraction for a group of connection to each source. |
0 | 5 |
|
6 |
||
7 |
:organization: Logilab |
|
1977
606923dff11b
big bunch of copyright / docstring update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1802
diff
changeset
|
8 |
:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. |
0 | 9 |
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr |
1977
606923dff11b
big bunch of copyright / docstring update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1802
diff
changeset
|
10 |
:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses |
0 | 11 |
""" |
12 |
__docformat__ = "restructuredtext en" |
|
13 |
||
14 |
import sys |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1132
diff
changeset
|
15 |
|
0 | 16 |
class ConnectionsPool(object): |
17 |
"""handle connections on a set of sources, at some point associated to a |
|
18 |
user session |
|
19 |
""" |
|
20 |
||
21 |
def __init__(self, sources): |
|
22 |
# dictionnary of (source, connection), indexed by sources'uri |
|
23 |
self.source_cnxs = {} |
|
24 |
for source in sources: |
|
25 |
self.source_cnxs[source.uri] = (source, source.get_connection()) |
|
26 |
if not 'system' in self.source_cnxs: |
|
27 |
self.source_cnxs['system'] = self.source_cnxs[sources[0].uri] |
|
28 |
self._cursors = {} |
|
29 |
||
2765
5e2525d7b1b1
reconnect without argument reconnect all sources
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2063
diff
changeset
|
30 |
def __getitem__(self, uri): |
5e2525d7b1b1
reconnect without argument reconnect all sources
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2063
diff
changeset
|
31 |
"""subscription notation provide access to sources'cursors""" |
5e2525d7b1b1
reconnect without argument reconnect all sources
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2063
diff
changeset
|
32 |
try: |
5e2525d7b1b1
reconnect without argument reconnect all sources
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2063
diff
changeset
|
33 |
cursor = self._cursors[uri] |
5e2525d7b1b1
reconnect without argument reconnect all sources
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2063
diff
changeset
|
34 |
except KeyError: |
5e2525d7b1b1
reconnect without argument reconnect all sources
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2063
diff
changeset
|
35 |
cursor = self.source_cnxs[uri][1].cursor() |
5e2525d7b1b1
reconnect without argument reconnect all sources
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2063
diff
changeset
|
36 |
if cursor is not None: |
5e2525d7b1b1
reconnect without argument reconnect all sources
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2063
diff
changeset
|
37 |
# None possible on sources without cursor support such as ldap |
5e2525d7b1b1
reconnect without argument reconnect all sources
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2063
diff
changeset
|
38 |
self._cursors[uri] = cursor |
5e2525d7b1b1
reconnect without argument reconnect all sources
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2063
diff
changeset
|
39 |
return cursor |
5e2525d7b1b1
reconnect without argument reconnect all sources
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2063
diff
changeset
|
40 |
|
0 | 41 |
def commit(self): |
42 |
"""commit the current transaction for this user""" |
|
43 |
# FIXME: what happends if a commit fail |
|
44 |
# would need a two phases commit or like, but I don't know how to do |
|
45 |
# this using the db-api... |
|
46 |
for source, cnx in self.source_cnxs.values(): |
|
47 |
# let exception propagates |
|
48 |
cnx.commit() |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1132
diff
changeset
|
49 |
|
0 | 50 |
def rollback(self): |
51 |
"""rollback the current transaction for this user""" |
|
52 |
for source, cnx in self.source_cnxs.values(): |
|
53 |
# catch exceptions, rollback other sources anyway |
|
54 |
try: |
|
55 |
cnx.rollback() |
|
56 |
except: |
|
57 |
source.critical('rollback error', exc_info=sys.exc_info()) |
|
58 |
||
59 |
def close(self, i_know_what_i_do=False): |
|
60 |
"""close all connections in the pool""" |
|
61 |
if i_know_what_i_do is not True: # unexpected closing safety belt |
|
62 |
raise RuntimeError('pool shouldn\'t be closed') |
|
63 |
for cu in self._cursors.values(): |
|
64 |
try: |
|
65 |
cu.close() |
|
66 |
except: |
|
67 |
continue |
|
68 |
for _, cnx in self.source_cnxs.values(): |
|
69 |
try: |
|
70 |
cnx.close() |
|
71 |
except: |
|
72 |
continue |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1132
diff
changeset
|
73 |
|
0 | 74 |
# internals ############################################################### |
75 |
||
2063
fe4278b50388
fix [re]set_pool prototype
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1977
diff
changeset
|
76 |
def pool_set(self): |
0 | 77 |
"""pool is being set""" |
78 |
self.check_connections() |
|
79 |
||
2063
fe4278b50388
fix [re]set_pool prototype
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
1977
diff
changeset
|
80 |
def pool_reset(self): |
0 | 81 |
"""pool is being reseted""" |
82 |
for source, cnx in self.source_cnxs.values(): |
|
83 |
source.pool_reset(cnx) |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1132
diff
changeset
|
84 |
|
0 | 85 |
def sources(self): |
86 |
"""return the source objects handled by this pool""" |
|
87 |
# implementation details of flying insert requires the system source |
|
88 |
# first |
|
2765
5e2525d7b1b1
reconnect without argument reconnect all sources
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2063
diff
changeset
|
89 |
yield self.source_cnxs['system'][0] |
0 | 90 |
for uri, (source, cursor) in self.source_cnxs.items(): |
91 |
if uri == 'system': |
|
92 |
continue |
|
93 |
yield source |
|
94 |
#return [source_cnx[0] for source_cnx in self.source_cnxs.values()] |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1132
diff
changeset
|
95 |
|
0 | 96 |
def source(self, uid): |
97 |
"""return the source object with the given uri""" |
|
98 |
return self.source_cnxs[uid][0] |
|
1802
d628defebc17
delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
1132
diff
changeset
|
99 |
|
0 | 100 |
def connection(self, uid): |
101 |
"""return the connection on the source object with the given uri""" |
|
102 |
return self.source_cnxs[uid][1] |
|
103 |
||
2765
5e2525d7b1b1
reconnect without argument reconnect all sources
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2063
diff
changeset
|
104 |
def reconnect(self, source=None): |
5e2525d7b1b1
reconnect without argument reconnect all sources
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2063
diff
changeset
|
105 |
"""reopen a connection for this source or all sources if none specified |
5e2525d7b1b1
reconnect without argument reconnect all sources
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2063
diff
changeset
|
106 |
""" |
5e2525d7b1b1
reconnect without argument reconnect all sources
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2063
diff
changeset
|
107 |
if source is None: |
5e2525d7b1b1
reconnect without argument reconnect all sources
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2063
diff
changeset
|
108 |
sources = self.sources() |
5e2525d7b1b1
reconnect without argument reconnect all sources
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2063
diff
changeset
|
109 |
else: |
5e2525d7b1b1
reconnect without argument reconnect all sources
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2063
diff
changeset
|
110 |
sources = (source,) |
5e2525d7b1b1
reconnect without argument reconnect all sources
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2063
diff
changeset
|
111 |
for source in sources: |
5e2525d7b1b1
reconnect without argument reconnect all sources
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2063
diff
changeset
|
112 |
source.info('trying to reconnect') |
5e2525d7b1b1
reconnect without argument reconnect all sources
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2063
diff
changeset
|
113 |
self.source_cnxs[source.uri] = (source, source.get_connection()) |
5e2525d7b1b1
reconnect without argument reconnect all sources
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2063
diff
changeset
|
114 |
self._cursors.pop(source.uri, None) |
0 | 115 |
|
116 |
def check_connections(self): |
|
117 |
for source, cnx in self.source_cnxs.itervalues(): |
|
118 |
newcnx = source.check_connection(cnx) |
|
119 |
if newcnx is not None: |
|
120 |
self.reset_connection(source, newcnx) |
|
121 |
||
122 |
def reset_connection(self, source, cnx): |
|
123 |
self.source_cnxs[source.uri] = (source, cnx) |
|
124 |
self._cursors.pop(source.uri, None) |
|
125 |
||
2835
04034421b072
[hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2765
diff
changeset
|
126 |
from cubicweb.server.hook import (Operation, LateOperation, SingleOperation, |
04034421b072
[hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2765
diff
changeset
|
127 |
SingleLastOperation) |
04034421b072
[hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2765
diff
changeset
|
128 |
from logilab.common.deprecation import class_moved, class_renamed |
04034421b072
[hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2765
diff
changeset
|
129 |
Operation = class_moved(Operation) |
04034421b072
[hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2765
diff
changeset
|
130 |
PreCommitOperation = class_renamed('PreCommitOperation', Operation) |
04034421b072
[hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2765
diff
changeset
|
131 |
LateOperation = class_moved(LateOperation) |
04034421b072
[hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2765
diff
changeset
|
132 |
SingleOperation = class_moved(SingleOperation) |
04034421b072
[hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
2765
diff
changeset
|
133 |
SingleLastOperation = class_moved(SingleLastOperation) |