Fix a bug in the demo "superlock" code preventing locks from being released in some circumstances.

FossilOrigin-Name: 65c393793ff5fdb935d5acfe5bdc3bca052f7314
This commit is contained in:
dan 2010-12-07 16:39:25 +00:00
parent 6568ffb14f
commit c216eee7ce
4 changed files with 63 additions and 42 deletions

View File

@ -1,8 +1,5 @@
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
C Version\s3.7.4\srelease\scandidate\s3
D 2010-12-07T14:59:22
C Fix\sa\sbug\sin\sthe\sdemo\s"superlock"\scode\spreventing\slocks\sfrom\sbeing\sreleased\sin\ssome\scircumstances.
D 2010-12-07T16:39:26
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 4547616ad2286053af6ccccefa242dc925e49bf0
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -220,7 +217,7 @@ F src/test_rtree.c 30c981837445a4e187ee850a49c4760d9642f7c3
F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
F src/test_stat.c f682704b5d1ba8e1d4e7e882a6d7922e2dcf066c
F src/test_superlock.c c0c0b1f73254a0c4ad5aca69e627fe32f571f7f9
F src/test_superlock.c aa91c01e42c8e1eef663b74bd1b9a762306f06b5
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
F src/test_thread.c bedd05cad673dba53326f3aa468cc803038896c0
F src/test_vfs.c e10fcca756cafa89438311b31522ac1f95bf784b
@ -657,7 +654,7 @@ F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9
F test/subquery.test b524f57c9574b2c0347045b4510ef795d4686796
F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
F test/superlock.test 070e7fd9ccf91755b6f8e03ede27995a73220672
F test/superlock.test 8468e057d8a5531ff99e504e77fcc585a0291bf2
F test/sync.test ded6b39d8d8ca3c0c5518516c6371b3316d3e3a3
F test/table.test 04ba066432430657712d167ebf28080fe878d305
F test/tableapi.test 7262a8cbaa9965d429f1cbd2747edc185fa56516
@ -897,14 +894,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
P b0634d2f909fb192d20315e59fa31fcd8f316541
R c899dedfcbfad993e519fd17027aa5c1
U drh
Z e558719848264f114302cf252022d7ad
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
iD8DBQFM/kvQoxKgR168RlERAihjAJ483qru/mKHGZtSh1P4zl69jepBKwCfe11S
MaOtcUGzrbyHLk/lC2rzkPk=
=bBvs
-----END PGP SIGNATURE-----
P 11c74c0dae0e302f248ec4af6dc8a9376203b034
R b4c637d07289308a3222d68447f4c6c3
U dan
Z 63bd98324f51b062689452a6abdd2cdc

View File

@ -1 +1 @@
11c74c0dae0e302f248ec4af6dc8a9376203b034
65c393793ff5fdb935d5acfe5bdc3bca052f7314

View File

@ -33,6 +33,17 @@ struct SuperlockBusy {
};
typedef struct SuperlockBusy SuperlockBusy;
/*
** An instance of the following structure is allocated for each active
** superlock. The opaque handle returned by sqlite3demo_superlock() is
** actually a pointer to an instance of this structure.
*/
struct Superlock {
sqlite3 *db; /* Database handle used to lock db */
int bWal; /* True if db is a WAL database */
};
typedef struct Superlock Superlock;
/*
** The pCtx pointer passed to this function is actually a pointer to a
** SuperlockBusy structure. Invoke the busy-handler function encapsulated
@ -53,18 +64,18 @@ static int superlockBusyHandler(void *pCtx, int UNUSED){
** If an error occurs, return an SQLite error code. The value of *pbWal
** is undefined in this case.
*/
static int superlockIsWal(sqlite3 *db, int *pbWal){
static int superlockIsWal(Superlock *pLock){
int rc; /* Return Code */
sqlite3_stmt *pStmt; /* Compiled PRAGMA journal_mode statement */
rc = sqlite3_prepare(db, "PRAGMA main.journal_mode", -1, &pStmt, 0);
rc = sqlite3_prepare(pLock->db, "PRAGMA main.journal_mode", -1, &pStmt, 0);
if( rc!=SQLITE_OK ) return rc;
*pbWal = 0;
pLock->bWal = 0;
if( SQLITE_ROW==sqlite3_step(pStmt) ){
const char *zMode = (const char *)sqlite3_column_text(pStmt, 0);
if( zMode && strlen(zMode)==3 && sqlite3_strnicmp("wal", zMode, 3)==0 ){
*pbWal = 1;
pLock->bWal = 1;
}
}
@ -132,6 +143,23 @@ static int superlockWalLock(
return rc;
}
/*
** Release a superlock held on a database file. The argument passed to
** this function must have been obtained from a successful call to
** sqlite3demo_superlock().
*/
void sqlite3demo_superunlock(void *pLock){
Superlock *p = (Superlock *)pLock;
if( p->bWal ){
int flags = SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE;
sqlite3_file *fd = 0;
sqlite3_file_control(p->db, "main", SQLITE_FCNTL_FILE_POINTER, (void *)&fd);
fd->pMethods->xShmLock(fd, 2, SQLITE_SHM_NLOCK-2, flags);
}
sqlite3_close(p->db);
sqlite3_free(p);
}
/*
** Obtain a superlock on the database file identified by zPath, using the
** locking primitives provided by VFS zVfs. If successful, SQLITE_OK is
@ -154,13 +182,17 @@ int sqlite3demo_superlock(
void *pBusyArg, /* Context arg for busy handler */
void **ppLock /* OUT: Context to pass to superunlock() */
){
sqlite3 *db = 0; /* Database handle open on zPath */
SuperlockBusy busy = {0, 0, 0}; /* Busy handler wrapper object */
int rc; /* Return code */
Superlock *pLock;
pLock = sqlite3_malloc(sizeof(Superlock));
if( !pLock ) return SQLITE_NOMEM;
memset(pLock, 0, sizeof(Superlock));
/* Open a database handle on the file to superlock. */
rc = sqlite3_open_v2(
zPath, &db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, zVfs
zPath, &pLock->db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, zVfs
);
/* Install a busy-handler and execute a BEGIN EXCLUSIVE. If this is not
@ -179,8 +211,8 @@ int sqlite3demo_superlock(
if( rc==SQLITE_OK ){
busy.xBusy = xBusy;
busy.pBusyArg = pBusyArg;
sqlite3_busy_handler(db, superlockBusyHandler, (void *)&busy);
rc = sqlite3_exec(db, "BEGIN EXCLUSIVE", 0, 0, 0);
sqlite3_busy_handler(pLock->db, superlockBusyHandler, (void *)&busy);
rc = sqlite3_exec(pLock->db, "BEGIN EXCLUSIVE", 0, 0, 0);
}
/* If the BEGIN EXCLUSIVE was executed successfully and this is a WAL
@ -193,34 +225,24 @@ int sqlite3demo_superlock(
** new WAL locks may conflict with the old.
*/
if( rc==SQLITE_OK ){
int bWal; /* True for a WAL database, false otherwise */
if( SQLITE_OK==(rc = superlockIsWal(db, &bWal)) && bWal ){
rc = sqlite3_exec(db, "COMMIT", 0, 0, 0);
if( SQLITE_OK==(rc = superlockIsWal(pLock)) && pLock->bWal ){
rc = sqlite3_exec(pLock->db, "COMMIT", 0, 0, 0);
if( rc==SQLITE_OK ){
rc = superlockWalLock(db, &busy);
rc = superlockWalLock(pLock->db, &busy);
}
}
}
if( rc!=SQLITE_OK ){
sqlite3_close(db);
sqlite3demo_superunlock(pLock);
*ppLock = 0;
}else{
*ppLock = (void *)db;
*ppLock = pLock;
}
return rc;
}
/*
** Release a superlock held on a database file. The argument passed to
** this function must have been obtained from a successful call to
** sqlite3demo_superlock().
*/
void sqlite3demo_superunlock(void *pLock){
sqlite3_close((sqlite3 *)pLock);
}
/*
** End of example code. Everything below here is the test harness.
**************************************************************************

View File

@ -143,6 +143,15 @@ do_multiclient_test tn {
list [catch {sqlite3demo_superlock unlock test.db} msg] $msg
} {0 unlock}
unlock
do_test 5.$tn.13 { sql1 { SELECT * FROM t1 } } {1 2 3 4 5 6}
do_test 5.$tn.14 { sql2 { SELECT * FROM t1 } } {1 2 3 4 5 6}
do_test 5.$tn.15 { sqlite3demo_superlock unlock test.db } {unlock}
do_test 5.$tn.16 { unlock } {}
do_test 5.$tn.17 { sql2 { SELECT * FROM t1 } } {1 2 3 4 5 6}
do_test 5.$tn.18 { sql1 { SELECT * FROM t1 } } {1 2 3 4 5 6}
do_test 5.$tn.19 { sql2 { SELECT * FROM t1 } } {1 2 3 4 5 6}
}
proc read_content {file} {