Trac can't use the thread-safe version of SQLite on Linux
|Reported by:||Christian Boos||Owned by:||Jonas Borgström|
If SQLite has been configured with the
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
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
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.
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:
182 182 else: 183 183 del self._active[tid] 184 184 if cnx not in self._dormant: 185 cnx.rollback() 186 self._dormant.append(cnx) 187 self._available.notify() 185 del cnx 188 186 finally: 189 187 self._available.release()
(tested with sqlite-3.2.7 and pysqlite-2.0.4+#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.
Change History (19)
comment:4 by , 15 years ago
|Status:||new → closed|
|Summary:||Trac can't use the thread-safe version of sqlite → Trac can't use the thread-safe version of SQLite on Linux|
comment:17 by , 15 years ago
|Keywords:||sqlite3 threadsafe added|
|Status:||reopened → closed|