[Trac-tickets] [The Trac Project] #2196: Trac can't use the
thread-safe version of sqlite
The Trac Project
noreply at edgewall.com
Mon Oct 10 03:32:42 CDT 2005
#2196: Trac can't use the thread-safe version of sqlite
---------------------+------------------------------------------------------
Reporter: cboos | Owner: jonas
Type: defect | Status: new
Priority: normal | Milestone:
Component: general | Version: devel
Severity: normal | Keywords: |
---------------------+------------------------------------------------------
If SQLite has been configured with the `--enable-threadsafe` switch,
the resulting binary '''won't''' work with Trac:
{{{
Oops...
Trac detected an internal error:
library routine called out of sequence
Traceback (most recent call last):
File "/opt/trac/stable-bct-trac/lib/python2.3/site-
packages/trac/web/standalone.py", line 235, in _do_trac_req
dispatch_request(path_info, req, env)
...
File "/usr/lib/python2.3/site-packages/sqlite/main.py", line 244, in
execute
self.rs = self.con.db.execute(SQL)
ProgrammingError: library routine called out of sequence
}}}
This is because the `--enable-threadsafe` flag will enable,
at the C level, a check for thread consistency.
That check enforces that each operation involving a sqlite3* object
will be performed from within the same thread that created that
object, or a `SQLITE_MISUSE` error will be returned.
This is the same kind of check that PySQLite does when the
`check_same_thread=True` flag is given to the `Connection`
constructor.
Currently in Trac, we explicitely disable that check at the PySQLite
level, but there's no way to disable it on the SQLite binary if it
has been compiled with `--enable-threadsafe`.
The workaround is to compile SQLite without that flag,
which, fortunately for us, is the default on Linux.
But it's not intuitive, as one would expect to turn thread safety
''on'' for a library which will be used in a multi-threaded context.
The real question is: can we assume that using SQLite that
way is always safe? For now, it seems to be the case, but
I guess there were reasons for having those checks in the first
place.
In #1811, cmlenz says that it's OK to do what we do,
but from the [http://sqlite.org/faq.html#q8 SQLite FAQ] which is
cited there, I read:
''It is never safe to use the same sqlite3 structure pointer in two or
more threads.''
In the case of SQLite, it would be cleaner to ''not'' reuse
a connection once the thread which created it terminates.
The database pool idea could be kept, as it always allocate
a connection to the same thread. However, the connection
should be destroyed after its last use, instead of being
put back in the pool. With this change, it is then possible
to use the thread safe version of the SQLite library:
{{{
#!diff
--- trac/db.py Thu Sep 29 10:13:36 2005 +0200
+++ trac/db.py Mon Oct 10 10:27:49 2005 +0200
@@ -182,9 +182,7 @@
else:
del self._active[tid]
if cnx not in self._dormant:
- cnx.rollback()
- self._dormant.append(cnx)
- self._available.notify()
+ del cnx
finally:
self._available.release()
}}}
(tested with sqlite-3.2.7 and
pysqlite-2.0.4+[http://initd.org/tracker/pysqlite/ticket/126 #ps126], on
Linux).
Another approach would be to not use the database connection
pool at all, and attach a new db connection to the request object
(this approach was already suggested in #1721).
I'm pretty sure this won't affect the performance, quite
the contrary, but I haven't tested that yet.
--
Ticket URL: <http://projects.edgewall.com/trac/ticket/2196>
The Trac Project <http://trac.edgewall.com/>
More information about the Trac-Tickets
mailing list