Ticket #2170: trac_no_writer_contention.patch
| File trac_no_writer_contention.patch, 4.1 KB (added by cmlenz, 3 years ago) |
|---|
-
trac/db.py
24 24 except ImportError: 25 25 import dummy_threading as threading 26 26 threading._get_ident = lambda: 0 27 import weakref 27 28 28 29 from trac.core import TracError 29 30 … … 183 184 del self._active[tid] 184 185 if cnx not in self._dormant: 185 186 cnx.rollback() 186 self._dormant.append(cnx) 187 if cnx.poolable: 188 self._dormant.append(cnx) 189 else: 190 self._cursize -= 1 187 191 self._available.notify() 188 192 finally: 189 193 self._available.release() … … 202 206 have_pysqlite = 2 203 207 204 208 class PyFormatCursor(sqlite.Cursor): 209 def _rollback_on_error(self, function, *args, **kwargs): 210 try: 211 return function(self, *args, **kwargs) 212 except sqlite.OperationalError, e: 213 self.cnx.rollback() 214 raise 205 215 def execute(self, sql, args=None): 206 216 if args: 207 217 sql = sql % (('?',) * len(args)) 208 sqlite.Cursor.execute(self, sql, args or []) 218 return self._rollback_on_error(sqlite.Cursor.execute, sql, 219 args or []) 209 220 def executemany(self, sql, args=None): 210 221 if args: 211 222 sql = sql % (('?',) * len(args[0])) 212 sqlite.Cursor.executemany(self, sql, args or []) 223 return self._rollback_on_error(sqlite.Cursor.executemany, sql, 224 args or []) 213 225 def _convert_row(self, row): 214 226 return tuple([(isinstance(v, unicode) and [v.encode('utf-8')] or [v])[0] 215 227 for v in row]) … … 224 236 rows = sqlite.Cursor.fetchall(self) 225 237 return rows != None and [self._convert_row(row) 226 238 for row in rows] or None 227 239 228 240 except ImportError: 229 241 try: 230 242 import sqlite … … 236 248 class SQLiteConnection(ConnectionWrapper): 237 249 """Connection wrapper for SQLite.""" 238 250 239 __slots__ = ['cnx' ]251 __slots__ = ['cnx', '_active_cursors'] 240 252 253 poolable = False 254 241 255 def __init__(self, path, params={}): 242 256 assert have_pysqlite > 0 243 257 self.cnx = None … … 254 268 'directory it is located in.' \ 255 269 % (getuser(), path) 256 270 257 timeout = int(params.get('timeout', 10000))258 271 if have_pysqlite == 2: 272 self._active_cursors = weakref.WeakKeyDictionary() 273 timeout = int(params.get('timeout', 10.0)) 259 274 # Convert unicode to UTF-8 bytestrings. This is case-sensitive, so 260 275 # we need two converters 261 276 sqlite.register_converter('text', str) 262 277 sqlite.register_converter('TEXT', str) 263 278 264 279 cnx = sqlite.connect(path, detect_types=sqlite.PARSE_DECLTYPES, 265 check_same_thread=False,timeout=timeout)280 timeout=timeout) 266 281 else: 282 timeout = int(params.get('timeout', 10000)) 267 283 cnx = sqlite.connect(path, timeout=timeout) 268 284 ConnectionWrapper.__init__(self, cnx) 269 285 270 286 if have_pysqlite == 2: 271 287 def cursor(self): 272 return self.cnx.cursor(PyFormatCursor) 288 cursor = self.cnx.cursor(PyFormatCursor) 289 self._active_cursors[cursor] = True 290 cursor.cnx = self 291 return cursor 292 293 def rollback(self): 294 for cursor in self._active_cursors.keys(): 295 cursor.close() 296 self.cnx.rollback() 297 273 298 else: 274 299 def cursor(self): 275 300 return self.cnx.cursor() … … 332 357 333 358 __slots__ = ['cnx'] 334 359 360 poolable = True 361 335 362 def __init__(self, path, user=None, password=None, host=None, port=None, 336 363 params={}): 337 364 if path.startswith('/'):
