temboz - Check-in [290]
Not logged in
[Honeypot]  [Browse]  [Help]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline]  [Wiki
  [Patchset]  [Tagging/Branching
Check-in Number: 290
Date: 2006-Feb-26 11:32:10 (local)
2006-Feb-26 19:32:10 (UTC)
User:majid
Branch:
Comment: fix #31 by using a lock to serialize all write transactions, as SQLite3 seems to have deadlocks when writers contend.
Tickets:
#31 deadlocks with SQLite 3.x
Inspections:
Files:
temboz/singleton.py      1.16 -> 1.17     33 inserted, 1 deleted

temboz/singleton.py 1.16 -> 1.17
--- /tmp/T03sayL3	Sun Sep  5 16:34:14 2010
+++ /tmp/T14sayL3	Sun Sep  5 16:34:14 2010
@@ -2,7 +2,8 @@
 # a writer thread collide. This module wraps a SQLite object with a Python
 # mutex to prevent this from happening inside Temboz
 
-import sys, thread, threading, signal, math, time, param
+import sys, thread, threading, signal, math, time
+import param
 
 # name of the command-line executable for SQLite
 sqlite_cli = 'sqlite'
@@ -22,7 +23,13 @@
   def __getattr__(self, name):
     return getattr(self.c, name, None)
   def execute(self, *args, **kwargs):
+    global db
     from pysqlite2 import dbapi2 as sqlite
+    # SQLite3 can deadlock when multiple writers collide, so we use a lock to
+    # prevent this from happening
+    if args[0].split()[0].lower() in ['insert', 'update', 'delete'] \
+           and not self.locked:
+      db.acquire()
     before = time.time()
     if param.debug:
       print >> param.log, thread.get_ident(), time.time(), args
@@ -47,6 +54,7 @@
 
 def commit_wrapper(method):
   """Provide locking error recovery for commit/rollback"""
+  global db
   from pysqlite2 import dbapi2 as sqlite
   backoff = 0.1
   done = False
@@ -53,6 +61,7 @@
   while not done:
     try:
       method()
+      db.release()
       if param.debug:
         print >> param.log, thread.get_ident(), time.time(), 'commit'
       done = True
@@ -75,6 +84,28 @@
 objects in the threading.Thread object (not officially supported, but works
 well enough) so commits can be associated with the corresponding cursor call.
 """
+  lock = threading.Lock()
+  def acquire(self):
+    t = threading.currentThread()
+    if not getattr(t, '__singleton_locked', False):
+      if param.debug:
+        print >> param.log, thread.get_ident(), time.time(), 'ACQUIRE'
+      self.lock.acquire()
+      setattr(t, '__singleton_locked', True)
+      if param.debug:
+        print >> param.log, thread.get_ident(), time.time(), 'DONE'
+    del t
+  def release(self):
+    t = threading.currentThread()
+    if getattr(t, '__singleton_locked', False):
+      if param.debug:
+        print >> param.log, thread.get_ident(), time.time(), 'RELEASE'
+      self.lock.release()
+      setattr(t, '__singleton_locked', False)
+      if param.debug:
+        print >> param.log, thread.get_ident(), time.time(), 'DONE'
+    del t
+  
   def __getattr__(self, name):
     t = threading.currentThread()
     db = getattr(t, '__singleton_db', None)
@@ -82,6 +113,7 @@
       from pysqlite2 import dbapi2 as sqlite
       db = sqlite.connect('rss.db')
       setattr(t, '__singleton_db', db)
+      setattr(t, '__singleton_locked', False)
     del t
     if name == 'cursor':
       return lambda: PseudoCursor3(db)