[pysqlite] Releasing GIL around sqlite3_prepare

[email protected] Fri, 22 Aug 2008 15:27:26 -0700
Newsgroups gmane.comp.python.db.pysqlite.user
Message-ID <[email protected]>
Hi,

I noticed that not all calls to sqlite3_prepare() in pysqlite 2.3.2
(which is the version that ships with both Python 2.5.1 and 2.5.2)
are wrapped with Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS.

This can cause spurious timeouts ("OperationalError: database is
locked", because if sqlite3_prepare() finds the database locked by
another Python thread, it will invoke the sqlite busy handler, sleep,
and try again -- not releasing the GIL. The thread that owns the lock
will not be able to acquire the GIL, so it will not have a chance to
finish what it's doing and release the database lock so that the first
thread could make progress.

Is there a reason for this? Would the attached patch be sufficient
to fix it? Can anyone think of other sqlite3 API calls that can block,
that I should check to make sure pysqlite does not call them without
releasing the GIL?

(this patch is against the Python source distribution -- let me know
if I should make a patch against pysqlite-2.4.1 instead)

Thanks!

	~Ben

_______________________________________________
list-pysqlite mailing list
list-pysqlite-FR6EJeJVuqdwc357pe9rcyQmJico6nz3epZhswDD4dQ@public.gmane.org
http://itsystementwicklung.de/cgi-bin/mailman/listinfo/list-pysqlite
(unnamed) (text/x-patch, 1.6 KB)
diff -ru old/Modules/_sqlite/cursor.c new/Modules/_sqlite/cursor.c
--- old/Modules/_sqlite/cursor.c	2006-07-28 11:36:01.000000000 -0700
+++ new/Modules/_sqlite/cursor.c	2008-08-22 13:31:41.000000000 -0700
@@ -772,11 +772,13 @@
         }
         statement_completed = 1;
 
+        Py_BEGIN_ALLOW_THREADS
         rc = sqlite3_prepare(self->connection->db,
                              script_cstr,
                              -1,
                              &statement,
                              &script_cstr);
+        Py_END_ALLOW_THREADS
         if (rc != SQLITE_OK) {
             _seterror(self->connection->db);
             goto error;
diff -ru old/Modules/_sqlite/statement.c new/Modules/_sqlite/statement.c
--- old/Modules/_sqlite/statement.c	2006-04-23 08:24:26.000000000 -0700
+++ new/Modules/_sqlite/statement.c	2008-08-22 13:32:39.000000000 -0700
@@ -69,11 +69,13 @@
 
     sql_cstr = PyString_AsString(sql_str);
 
+    Py_BEGIN_ALLOW_THREADS
     rc = sqlite3_prepare(connection->db,
                          sql_cstr,
                          -1,
                          &self->st,
                          &tail);
+    Py_END_ALLOW_THREADS
 
     self->db = connection->db;
 
@@ -224,11 +226,13 @@
 
     sql_cstr = PyString_AsString(self->sql);
 
+    Py_BEGIN_ALLOW_THREADS
     rc = sqlite3_prepare(self->db,
                          sql_cstr,
                          -1,
                          &new_st,
                          &tail);
+    Py_END_ALLOW_THREADS
 
     if (rc == SQLITE_OK) {
         /* The efficient sqlite3_transfer_bindings is only available in SQLite