From: drh Date: Tue, 7 Apr 2009 22:06:57 +0000 (+0000) Subject: Fix the sqlite3_unlock_notify() interface so that when the callback is NULL X-Git-Tag: version-3.6.15~283 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=65a73bad9e1780acc478119d14b3f86ca2b48217;p=thirdparty%2Fsqlite.git Fix the sqlite3_unlock_notify() interface so that when the callback is NULL it simply cancels any outstanding callbacks. (CVS 6467) FossilOrigin-Name: 9ccfcb760745df28b04e746355b1b6dec49a93de --- diff --git a/manifest b/manifest index 215eda81d5..fb51e4ef2c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\stwo\sunused\stests\sfrom\sthe\sintegrity_check\spragma\slogic.\s(CVS\s6466) -D 2009-04-07T22:05:43 +C Fix\sthe\ssqlite3_unlock_notify()\sinterface\sso\sthat\swhen\sthe\scallback\sis\sNULL\nit\ssimply\scancels\sany\soutstanding\scallbacks.\s(CVS\s6467) +D 2009-04-07T22:06:57 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in 583e87706abc3026960ed759aff6371faf84c211 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -136,7 +136,7 @@ F src/mutex_noop.c f5a07671f25a1a9bd7c10ad7107bc2585446200f F src/mutex_os2.c 6b5a74f812082a8483c3df05b47bbaac2424b9a0 F src/mutex_unix.c 2f936339dfef1a4c142db290d575a3509b77315f F src/mutex_w32.c f4b6a4a48f1dfff7f0089cba9b5a371691f17b8b -F src/notify.c da6f6b999dce9203d24280fa01b4ffbd2d9ba79b +F src/notify.c 0127121816d8a861deb0dfd111b495346bf233db F src/os.c c2aa4a7d8bb845222e5c37f56cde377b20c3b087 F src/os.h fa3f4aa0119ff721a2da4b47ffd74406ac864c05 F src/os_common.h 8c61457df58f1a4bd5f5adc3e90e01b37bf7afbc @@ -159,7 +159,7 @@ F src/select.c 462d9671e91accd983110fa38674be0d2a3daa66 F src/shell.c 0a11f831603f17fea20ca97133c0f64e716af4a7 F src/sqlite.h.in 718a026b4cf3c766fc7ac5ff582faa60324b116c F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17 -F src/sqliteInt.h 3754c3c7f8549db259909882d3484250d77488cb +F src/sqliteInt.h 7b341ab7d570b271e8566e7e7ed6993453f84964 F src/sqliteLimit.h ffe93f5a0c4e7bd13e70cd7bf84cfb5c3465f45d F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76 F src/table.c 332ab0ea691e63862e2a8bdfe2c0617ee61062a3 @@ -479,7 +479,7 @@ F test/misuse.test 30b3a458e5a70c31e74c291937b6c82204c59f33 F test/mutex1.test ebd54720401fafe854799dc86b7bf60b75631935 F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660 F test/nan.test c627d79b3d36ea892563fd67584b3e8a18f0618a -F test/notify1.test 099191b6f450a7cc3208bdf826532572bdd9a204 +F test/notify1.test 533cf60a81f59c1c88a99ce46b1c14f47d14c32c F test/notify2.test 195a467e021f74197be2c4fb02d6dee644b8d8db F test/notnull.test 44d600f916b770def8b095a9962dbe3be5a70d82 F test/null.test a8b09b8ed87852742343b33441a9240022108993 @@ -715,7 +715,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e -P 2c1f59834ab7a16066ee12cb8a8342d438c23ce9 -R da69fda516423dc915653709b87d09f0 +P 22999d31418aa9ecb17ab5d135b206b967889614 +R 8662e3a26c19cc89676dfbf43f445945 U drh -Z 1ffc7b542098adaaa0308f19da4f52e8 +Z 7764f7e6b16bc4d3ac70136f1d1dcce8 diff --git a/manifest.uuid b/manifest.uuid index e07c64be3a..456cf47b70 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -22999d31418aa9ecb17ab5d135b206b967889614 \ No newline at end of file +9ccfcb760745df28b04e746355b1b6dec49a93de \ No newline at end of file diff --git a/src/notify.c b/src/notify.c index 67bb227300..afa7626290 100644 --- a/src/notify.c +++ b/src/notify.c @@ -13,7 +13,7 @@ ** This file contains the implementation of the sqlite3_unlock_notify() ** API method and its associated functionality. ** -** $Id: notify.c,v 1.3 2009/04/07 11:21:29 danielk1977 Exp $ +** $Id: notify.c,v 1.4 2009/04/07 22:06:57 drh Exp $ */ #include "sqliteInt.h" #include "btreeInt.h" @@ -128,6 +128,24 @@ static void leaveMutex(void){ /* ** Register an unlock-notify callback. +** +** This is called after connection "db" has attempted some operation +** but has received an SQLITE_LOCKED error because another connection +** (call it pOther) in the same process was busy using the same shared +** cache. pOther is found by looking at db->pBlockingConnection. +** +** If there is no blocking connection, the callback is invoked immediately, +** before this routine returns. +** +** If pOther is already blocked on db, then report SQLITE_LOCKED, to indicate +** a deadlock. +** +** Otherwise, make arrangements to invoke xNotify when pOther drops +** its locks. +** +** Each call to this routine overrides any prior callbacks registered +** on the same "db". If xNotify==0 then any prior callbacks are immediately +** cancelled. */ int sqlite3_unlock_notify( sqlite3 *db, @@ -139,7 +157,12 @@ int sqlite3_unlock_notify( sqlite3_mutex_enter(db->mutex); enterMutex(); - if( 0==db->pBlockingConnection ){ + if( xNotify==0 ){ + removeFromBlockedList(db); + db->pUnlockConnection = 0; + db->xUnlockNotify = 0; + db->pUnlockArg = 0; + }else if( 0==db->pBlockingConnection ){ /* The blocking transaction has been concluded. Or there never was a ** blocking transaction. In either case, invoke the notify callback ** immediately. @@ -148,7 +171,7 @@ int sqlite3_unlock_notify( }else{ sqlite3 *p; - for(p=db->pBlockingConnection; p && p!=db; p=p->pUnlockConnection); + for(p=db->pBlockingConnection; p && p!=db; p=p->pUnlockConnection){} if( p ){ rc = SQLITE_LOCKED; /* Deadlock detected. */ }else{ @@ -183,7 +206,8 @@ void sqlite3ConnectionBlocked(sqlite3 *db, sqlite3 *pBlocker){ } /* -** The transaction opened by database db has just finished. Locks held +** This function is called when +** the transaction opened by database db has just finished. Locks held ** by database connection db have been released. ** ** This function loops through each entry in the blocked connections @@ -204,11 +228,11 @@ void sqlite3ConnectionUnlocked(sqlite3 *db){ void (*xUnlockNotify)(void **, int) = 0; /* Unlock-notify cb to invoke */ int nArg = 0; /* Number of entries in aArg[] */ sqlite3 **pp; /* Iterator variable */ + void **aArg; /* Arguments to the unlock callback */ + void **aDyn = 0; /* Dynamically allocated space for aArg[] */ + void *aStatic[16]; /* Starter space for aArg[]. No malloc required */ - void *aStatic[16]; - void **aArg = aStatic; - void **aDyn = 0; - + aArg = aStatic; enterMutex(); /* Enter STATIC_MASTER mutex */ /* This loop runs once for each entry in the blocked-connections list. */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 625c2e1ffb..a66bb3a4f5 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.852 2009/04/07 14:14:22 danielk1977 Exp $ +** @(#) $Id: sqliteInt.h,v 1.853 2009/04/07 22:06:57 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -836,6 +836,13 @@ struct sqlite3 { #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY /* The following variables are all protected by the STATIC_MASTER ** mutex, not by sqlite3.mutex. They are used by code in notify.c. + ** + ** When X.pUnlockConnection==Y, that means that X is waiting for Y to + ** unlock so that it can proceed. + ** + ** When X.pBlockingConnection==Y, that means that something that X tried + ** tried to do recently failed with an SQLITE_LOCKED error due to locks + ** held by Y. */ sqlite3 *pBlockingConnection; /* Connection that caused SQLITE_LOCKED */ sqlite3 *pUnlockConnection; /* Connection to watch for unlock */ diff --git a/test/notify1.test b/test/notify1.test index 1b11bda7b5..1b6c516a48 100644 --- a/test/notify1.test +++ b/test/notify1.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the sqlite3_unlock_notify() API. # -# $Id: notify1.test,v 1.2 2009/03/25 15:43:09 danielk1977 Exp $ +# $Id: notify1.test,v 1.3 2009/04/07 22:06:57 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -55,6 +55,38 @@ do_test notify1-1.5 { execsql { SELECT * FROM t1 } } {1 2 3 4} +#------------------------------------------------------------------------- +# Verify that invoking the "unlock_notify" method with no arguments +# (which is the equivalent of invoking sqlite3_unlock_notify() with +# a NULL xNotify argument) cancels a pending notify callback. +# +do_test notify1-1.11 { + execsql { DROP TABLE t1; CREATE TABLE t1(a, b) } +} {} +do_test notify1-1.12 { + execsql { + BEGIN; + INSERT INTO t1 VALUES(1, 2); + } + catchsql { INSERT INTO t1 VALUES(3, 4) } db2 +} {1 {database table is locked}} +do_test notify1-1.13 { + set zScript "" + db2 unlock_notify { + set zScript "db2 eval { INSERT INTO t1 VALUES(3, 4) }" + } + execsql { SELECT * FROM t1 } +} {1 2} +do_test notify1-1.14 { + set zScript +} {} +do_test notify1-1.15 { + db2 unlock_notify + execsql { COMMIT } + eval $zScript + execsql { SELECT * FROM t1 } +} {1 2} + #------------------------------------------------------------------------- # The following tests, notify1-2.*, test that deadlock is detected # correctly.