comparison roundup/backends/back_sqlite.py @ 5143:9cebf686c552

issue2550727: db.newid is broken with sqlite. Added proper transaction lock around the sql code to get a new id. The the locking that pysqlite attempts had to be defeated because it is broken. Had to explicitly manage transactions with BEGIN IMMEDIATE and call sql_commit. Note that this reduces performance by 30% in return for accuracy. Also use update call set newid=newid+1 rather than incrementing in python.
author John Rouillard <rouilj@ieee.org>
date Wed, 13 Jul 2016 22:30:07 -0400
parents e74c3611b138
children e1e40674a0bc
comparison
equal deleted inserted replaced
5142:93832cec4c31 5143:9cebf686c552
364 364
365 # old-skool id generation 365 # old-skool id generation
366 def newid(self, classname): 366 def newid(self, classname):
367 """ Generate a new id for the given class 367 """ Generate a new id for the given class
368 """ 368 """
369
370 # Prevent other processes from reading while we increment.
371 # Otherwise multiple processes can end up with the same
372 # new id and hilarity results.
373 #
374 # Defeat pysqlite's attempts to do locking by setting
375 # isolation_level to None. Pysqlite can commit
376 # on it's own even if we don't want it to end the transaction.
377 # If we rewrite to use another sqlite library like apsw we
378 # don't have to deal with this autocommit/autotransact foolishness.
379 self.conn.isolation_level = None;
380 # Manage the transaction locks manually.
381 self.sql("BEGIN IMMEDIATE");
382
369 # get the next ID 383 # get the next ID
370 sql = 'select num from ids where name=%s'%self.arg 384 sql = 'select num from ids where name=%s'%self.arg
371 self.sql(sql, (classname, )) 385 self.sql(sql, (classname, ))
372 newid = int(self.cursor.fetchone()[0]) 386 newid = int(self.cursor.fetchone()[0])
373 387
374 # update the counter 388 # leave the next larger number as the next newid
375 sql = 'update ids set num=%s where name=%s'%(self.arg, self.arg) 389 sql = 'update ids set num=num+1 where name=%s'%self.arg
376 vals = (int(newid)+1, classname) 390 vals = (classname,)
377 self.sql(sql, vals) 391 self.sql(sql, vals)
392
393 # reset pysqlite's auto transact stuff to default since the
394 # rest of the code expects it.
395 self.conn.isolation_level = '';
396 # commit writing the data, clearing locks for other processes
397 # and create a new cursor to the database.
398 self.sql_commit();
378 399
379 # return as string 400 # return as string
380 return str(newid) 401 return str(newid)
381 402
382 def setid(self, classname, setid): 403 def setid(self, classname, setid):

Roundup Issue Tracker: http://roundup-tracker.org/