Author: ianb
Date: 2006-01-19 02:54:27 -0700 (Thu, 19 Jan 2006)
New Revision: 1523
Added:
SQLObject/trunk/sqlobject/tests/test_sqlite_threaded.py
Modified:
SQLObject/trunk/sqlobject/sqlite/sqliteconnection.py
Log:
Fixed problem with sqlite and threads; connections are no longer shared between threads for sqlite (except for :memory:)
Modified: SQLObject/trunk/sqlobject/sqlite/sqliteconnection.py
===================================================================
--- SQLObject/trunk/sqlobject/sqlite/sqliteconnection.py 2006-01-19 09:53:33 UTC (rev 1522)
+++ SQLObject/trunk/sqlobject/sqlite/sqliteconnection.py 2006-01-19 09:54:27 UTC (rev 1523)
@@ -1,5 +1,6 @@
from sqlobject.dbconnection import DBAPI
from sqlobject.col import popKey
+import thread
sqlite = None
using_sqlite2 = False
@@ -23,6 +24,12 @@
using_sqlite2 = False
self.module = sqlite
self.filename = filename # full path to sqlite-db-file
+ self._memory = filename == ':memory:'
+ if self._memory:
+ if not using_sqlite2:
+ raise ValueError(
+ "You must use sqlite2 to use in-memory databases")
+ #kw.setdefault('check_same_thread', False)
# connection options
opts = {}
if using_sqlite2:
@@ -58,8 +65,13 @@
opts['timeout'] = float(popKey(kw, 'timeout'))
# use only one connection for sqlite - supports multiple)
# cursors per connection
- self._conn = sqlite.connect(self.filename, **opts)
+ self._connOptions = opts
DBAPI.__init__(self, **kw)
+ self._threadPool = {}
+ self._threadOrigination = {}
+ if self._memory:
+ self._memoryConn = sqlite.connect(
+ self.filename, **self._connOptions)
def connectionFromURI(cls, uri):
user, password, host, port, path, args = cls._parseURI(uri)
@@ -69,13 +81,53 @@
assert user is None and password is None, (
"You may not provide usernames or passwords for SQLite "
"databases")
- if path == "/:memory:": path = ":memory:"
+ if path == "/:memory:":
+ path = ":memory:"
return cls(filename=path, **args)
connectionFromURI = classmethod(connectionFromURI)
def uri(self):
return 'sqlite:///%s' % self.filename
+ def getConnection(self):
+ # SQLite can't share connections between threads, and so can't
+ # pool connections. Since we are isolating threads here, we
+ # don't have to worry about locking as much.
+ if self._memory:
+ return self.makeConnection()
+ threadid = thread.get_ident()
+ if (self._pool is not None
+ and self._threadPool.has_key(threadid)):
+ conn = self._threadPool[threadid]
+ del self._threadPool[threadid]
+ if conn in self._pool:
+ self._pool.remove(conn)
+ else:
+ conn = self.makeConnection()
+ if self._pool is not None:
+ self._threadOrigination[id(conn)] = threadid
+ self._connectionNumbers[id(conn)] = self._connectionCount
+ self._connectionCount += 1
+ if self.debug:
+ s = 'ACQUIRE'
+ if self._pool is not None:
+ s += ' pool=[%s]' % ', '.join([str(self._connectionNumbers[id(v)]) for v in self._pool])
+ self.printDebug(conn, s, 'Pool')
+ return conn
+
+ def releaseConnection(self, conn, explicit=False):
+ if self._memory:
+ return
+ threadid = self._threadOrigination.get(id(conn))
+ DBAPI.releaseConnection(self, conn, explicit=explicit)
+ if (self._pool is not None and threadid
+ and not self._threadPool.has_key(threadid)):
+ self._threadPool[threadid] = conn
+ else:
+ if self._pool and conn in self._pool:
+ self._pool.remove(conn)
+ conn.close()
+
def _setAutoCommit(self, conn, auto):
if using_sqlite2:
if auto:
@@ -91,7 +143,9 @@
conn.isolation_level = level
def makeConnection(self):
- return self._conn
+ if self._memory:
+ return self._memoryConn
+ return sqlite.connect(self.filename, **self._connOptions)
def _queryInsertID(self, conn, soInstance, id, names, values):
table = soInstance.sqlmeta.table
Added: SQLObject/trunk/sqlobject/tests/test_sqlite_threaded.py
===================================================================
--- SQLObject/trunk/sqlobject/tests/test_sqlite_threaded.py 2006-01-19 09:53:33 UTC (rev 1522)
+++ SQLObject/trunk/sqlobject/tests/test_sqlite_threaded.py 2006-01-19 09:54:27 UTC (rev 1523)
@@ -0,0 +1,17 @@
+from dbtest import *
+from test_basic import TestSO1
+import threading
+
+def test_sqlite_threaded():
+ setupClass(TestSO1)
+ t = threading.Thread(target=do_select)
+ t.start()
+ t.join()
+ # This should reuse the same connection as the connection
+ # made above (at least will with most database drivers, but
+ # this will cause an error in SQLite):
+ do_select()
+
+def do_select():
+ list(TestSO1.select())
+ print "T", threading.currentThread().getName()
Property changes on: SQLObject/trunk/sqlobject/tests/test_sqlite_threaded.py
___________________________________________________________________
Name: svn:eol-style
+ native
|