1
1
from .connection import Connection , ConnectionInfo
2
2
3
3
from mamonsu .lib .version import parse
4
+ import threading
5
+
4
6
5
7
class Pool (object ):
6
8
ExcludeDBs = ["template0" , "template1" ]
@@ -107,10 +109,11 @@ def __init__(self, params=None):
107
109
"bootstrap" : {"storage" : {}, "counter" : 0 , "cache" : 10 , "version" : False },
108
110
"recovery" : {"storage" : {}, "counter" : 0 , "cache" : 10 },
109
111
"extension_schema" : {"pg_buffercache" : {}, "pg_stat_statements" : {}, "pg_wait_sampling" : {}, "pgpro_stats" : {}},
110
- "extension_versions" : {},
112
+ "extension_versions" : {},
111
113
"pgpro" : {"storage" : {}},
112
114
"pgproee" : {"storage" : {}}
113
115
}
116
+ self ._lock = threading .RLock ()
114
117
115
118
def connection_string (self , db = None ):
116
119
db = self ._normalize_db (db )
@@ -122,30 +125,32 @@ def query(self, query, db=None):
122
125
return self ._connections [db ].query (query )
123
126
124
127
def server_version (self , db = None ):
125
- db = self ._normalize_db (db )
126
- if db in self ._cache ["server_version" ]["storage" ]:
128
+ with self ._lock :
129
+ db = self ._normalize_db (db )
130
+ if db in self ._cache ["server_version" ]["storage" ]:
131
+ return self ._cache ["server_version" ]["storage" ][db ]
132
+
133
+ version_string = self .query ("show server_version" , db )[0 ][0 ]
134
+ result = bytes (
135
+ version_string .split (" " )[0 ], "utf-8" )
136
+ self ._cache ["server_version" ]["storage" ][db ] = "{0}" .format (
137
+ result .decode ("ascii" ))
127
138
return self ._cache ["server_version" ]["storage" ][db ]
128
139
129
- version_string = self .query ("show server_version" , db )[0 ][0 ]
130
- result = bytes (
131
- version_string .split (" " )[0 ], "utf-8" )
132
- self ._cache ["server_version" ]["storage" ][db ] = "{0}" .format (
133
- result .decode ("ascii" ))
134
- return self ._cache ["server_version" ]["storage" ][db ]
135
-
136
140
def extension_version (self , extension , db = None ):
137
- db = self ._normalize_db (db )
138
- if extension in self ._cache ["extension_versions" ] and db in self ._cache ["extension_versions" ][extension ][db ]:
141
+ with self ._lock :
142
+ db = self ._normalize_db (db )
143
+ if extension in self ._cache ["extension_versions" ] and db in self ._cache ["extension_versions" ][extension ][db ]:
144
+ return self ._cache ["extension_versions" ][extension ][db ]
145
+
146
+ version_string = self .query ("select extversion from pg_catalog.pg_extension where lower(extname) = lower('{0}');" .format (extension ), db )[0 ][0 ]
147
+ result = bytes (
148
+ version_string .split (" " )[0 ], "utf-8" )
149
+ self ._cache ["extension_versions" ][extension ] = {}
150
+ self ._cache ["extension_versions" ][extension ][db ] = "{0}" .format (
151
+ result .decode ("ascii" ))
139
152
return self ._cache ["extension_versions" ][extension ][db ]
140
153
141
- version_string = self .query ("select extversion from pg_catalog.pg_extension where lower(extname) = lower('{0}');" .format (extension ), db )[0 ][0 ]
142
- result = bytes (
143
- version_string .split (" " )[0 ], "utf-8" )
144
- self ._cache ["extension_versions" ][extension ] = {}
145
- self ._cache ["extension_versions" ][extension ][db ] = "{0}" .format (
146
- result .decode ("ascii" ))
147
- return self ._cache ["extension_versions" ][extension ][db ]
148
-
149
154
def server_version_greater (self , version , db = None ):
150
155
db = self ._normalize_db (db )
151
156
return parse (self .server_version (db )) >= parse (version )
@@ -155,49 +160,53 @@ def server_version_less(self, version, db=None):
155
160
return parse (self .server_version (db )) <= parse (version )
156
161
157
162
def bootstrap_version_greater (self , version ):
158
- return parse (str (self ._cache ["bootstrap" ]["version" ])) >= parse (version )
163
+ with self ._lock :
164
+ return parse (str (self ._cache ["bootstrap" ]["version" ])) >= parse (version )
159
165
160
166
def bootstrap_version_less (self , version ):
161
- return parse (str (self ._cache ["bootstrap" ]["version" ])) <= parse (version )
167
+ with self ._lock :
168
+ return parse (str (self ._cache ["bootstrap" ]["version" ])) <= parse (version )
162
169
163
170
def in_recovery (self , db = None ):
164
- db = self ._normalize_db (db )
165
- if db in self ._cache ["recovery" ]["storage" ]:
166
- if self ._cache ["recovery" ]["counter" ] < self ._cache ["recovery" ]["cache" ]:
167
- self ._cache ["recovery" ]["counter" ] += 1
168
- return self ._cache ["recovery" ]["storage" ][db ]
169
- self ._cache ["recovery" ]["counter" ] = 0
170
- self ._cache ["recovery" ]["storage" ][db ] = self .query (
171
- "select pg_catalog.pg_is_in_recovery()" , db )[0 ][0 ]
172
- return self ._cache ["recovery" ]["storage" ][db ]
171
+ with self ._lock :
172
+ db = self ._normalize_db (db )
173
+ if db in self ._cache ["recovery" ]["storage" ]:
174
+ if self ._cache ["recovery" ]["counter" ] < self ._cache ["recovery" ]["cache" ]:
175
+ self ._cache ["recovery" ]["counter" ] += 1
176
+ return self ._cache ["recovery" ]["storage" ][db ]
177
+ self ._cache ["recovery" ]["counter" ] = 0
178
+ self ._cache ["recovery" ]["storage" ][db ] = self .query (
179
+ "select pg_catalog.pg_is_in_recovery()" , db )[0 ][0 ]
180
+ return self ._cache ["recovery" ]["storage" ][db ]
173
181
174
182
def is_bootstraped (self , db = None ):
175
- db = self ._normalize_db (db )
176
- if db in self ._cache ["bootstrap" ]["storage" ]:
177
- if self ._cache ["bootstrap" ]["counter" ] < self ._cache ["bootstrap" ]["cache" ]:
178
- self ._cache ["bootstrap" ]["counter" ] += 1
179
- return self ._cache ["bootstrap" ]["storage" ][db ]
180
- self ._cache ["bootstrap" ]["counter" ] = 0
181
- # TODO: изменить на нормальное название, 'config' слишком общее
182
- sql = """
183
- SELECT count(*)
184
- FROM pg_catalog.pg_class
185
- WHERE relname = 'config';
186
- """
187
- result = int (self .query (sql , db )[0 ][0 ])
188
- self ._cache ["bootstrap" ]["storage" ][db ] = (result == 1 )
189
- if self ._cache ["bootstrap" ]["storage" ][db ]:
190
- self ._connections [db ].log .info ("Found mamonsu bootstrap" )
183
+ with self ._lock :
184
+ db = self ._normalize_db (db )
185
+ if db in self ._cache ["bootstrap" ]["storage" ]:
186
+ if self ._cache ["bootstrap" ]["counter" ] < self ._cache ["bootstrap" ]["cache" ]:
187
+ self ._cache ["bootstrap" ]["counter" ] += 1
188
+ return self ._cache ["bootstrap" ]["storage" ][db ]
189
+ self ._cache ["bootstrap" ]["counter" ] = 0
190
+ # TODO: изменить на нормальное название, 'config' слишком общее
191
191
sql = """
192
- SELECT max(version)
193
- FROM mamonsu.config;
192
+ SELECT count(*)
193
+ FROM pg_catalog.pg_class
194
+ WHERE relname = 'config';
194
195
"""
195
- self ._cache ["bootstrap" ]["version" ] = self .query (sql , db )[0 ][0 ]
196
- else :
197
- self ._connections [db ].log .info ("Mamonsu bootstrap is not found" )
198
- self ._connections [db ].log .info (
199
- "hint: run `mamonsu bootstrap` if you want to run without superuser rights" )
200
- return self ._cache ["bootstrap" ]["storage" ][db ]
196
+ result = int (self .query (sql , db )[0 ][0 ])
197
+ self ._cache ["bootstrap" ]["storage" ][db ] = (result == 1 )
198
+ if self ._cache ["bootstrap" ]["storage" ][db ]:
199
+ self ._connections [db ].log .info ("Found mamonsu bootstrap" )
200
+ sql = """
201
+ SELECT max(version)
202
+ FROM mamonsu.config;
203
+ """
204
+ self ._cache ["bootstrap" ]["version" ] = self .query (sql , db )[0 ][0 ]
205
+ else :
206
+ self ._connections [db ].log .info ("Mamonsu bootstrap is not found" )
207
+ self ._connections [db ].log .info (
208
+ "hint: run `mamonsu bootstrap` if you want to run without superuser rights" )
209
+ return self ._cache ["bootstrap" ]["storage" ][db ]
201
210
202
211
def is_superuser (self , db = None ):
203
212
_ = self ._normalize_db (db )
@@ -209,34 +218,36 @@ def is_superuser(self, db=None):
209
218
return False
210
219
211
220
def is_pgpro (self , db = None ):
212
- db = self ._normalize_db (db )
213
- if db in self ._cache ["pgpro" ]:
221
+ with self ._lock :
222
+ db = self ._normalize_db (db )
223
+ if db in self ._cache ["pgpro" ]:
224
+ return self ._cache ["pgpro" ][db ]
225
+ try :
226
+ self .query ("""
227
+ SELECT pgpro_version();
228
+ """ )
229
+ self ._cache ["pgpro" ][db ] = True
230
+ except :
231
+ self ._cache ["pgpro" ][db ] = False
214
232
return self ._cache ["pgpro" ][db ]
215
- try :
216
- self .query ("""
217
- SELECT pgpro_version();
218
- """ )
219
- self ._cache ["pgpro" ][db ] = True
220
- except :
221
- self ._cache ["pgpro" ][db ] = False
222
- return self ._cache ["pgpro" ][db ]
223
233
224
234
def is_pgpro_ee (self , db = None ):
225
- db = self ._normalize_db (db )
226
- if not self .is_pgpro (db ):
227
- return False
228
- if db in self ._cache ["pgproee" ]:
235
+ with self ._lock :
236
+ db = self ._normalize_db (db )
237
+ if not self .is_pgpro (db ):
238
+ return False
239
+ if db in self ._cache ["pgproee" ]:
240
+ return self ._cache ["pgproee" ][db ]
241
+ try :
242
+ ed = self .query ("""
243
+ SELECT pgpro_edition();
244
+ """ )[0 ][0 ]
245
+ self ._connections [db ].log .info ("pgpro_edition is {}" .format (ed ))
246
+ self ._cache ["pgproee" ][db ] = (ed .lower () == "enterprise" )
247
+ except :
248
+ self ._connections [db ].log .info ("pgpro_edition() is not defined" )
249
+ self ._cache ["pgproee" ][db ] = False
229
250
return self ._cache ["pgproee" ][db ]
230
- try :
231
- ed = self .query ("""
232
- SELECT pgpro_edition();
233
- """ )[0 ][0 ]
234
- self ._connections [db ].log .info ("pgpro_edition is {}" .format (ed ))
235
- self ._cache ["pgproee" ][db ] = (ed .lower () == "enterprise" )
236
- except :
237
- self ._connections [db ].log .info ("pgpro_edition() is not defined" )
238
- self ._cache ["pgproee" ][db ] = False
239
- return self ._cache ["pgproee" ][db ]
240
251
241
252
def extension_version_greater (self , extension , version , db = None ):
242
253
db = self ._normalize_db (db )
@@ -256,19 +267,20 @@ def extension_installed(self, ext, db=None):
256
267
return (int (result [0 ][0 ])) == 1
257
268
258
269
def extension_schema (self , extension , db = None ):
259
- db = self ._normalize_db (db )
260
- if db in self ._cache ["extension_schema" ][extension ]:
261
- return self ._cache ["extension_schema" ][extension ][db ]
262
- try :
263
- self ._cache ["extension_schema" ][extension ][db ] = self .query ("""
264
- SELECT n.nspname
265
- FROM pg_extension e
266
- JOIN pg_namespace n ON e.extnamespace = n.oid
267
- WHERE e.extname = '{0}'
268
- """ .format (extension ), db )[0 ][0 ]
269
- return self ._cache ["extension_schema" ][extension ][db ]
270
- except :
271
- self ._connections [db ].log .info ("{0} is not installed" .format (extension ))
270
+ with self ._lock :
271
+ db = self ._normalize_db (db )
272
+ if db in self ._cache ["extension_schema" ][extension ]:
273
+ return self ._cache ["extension_schema" ][extension ][db ]
274
+ try :
275
+ self ._cache ["extension_schema" ][extension ][db ] = self .query ("""
276
+ SELECT n.nspname
277
+ FROM pg_extension e
278
+ JOIN pg_namespace n ON e.extnamespace = n.oid
279
+ WHERE e.extname = '{0}'
280
+ """ .format (extension ), db )[0 ][0 ]
281
+ return self ._cache ["extension_schema" ][extension ][db ]
282
+ except :
283
+ self ._connections [db ].log .info ("{0} is not installed" .format (extension ))
272
284
273
285
def databases (self ):
274
286
result , databases = self .query ("""
0 commit comments