From: drh Date: Wed, 29 Aug 2007 17:43:19 +0000 (+0000) Subject: Improvements to mutex asserts. The quick test runs to completion without X-Git-Tag: version-3.6.10~1853 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ff0587c63224855534be400c844124d5ce8ab739;p=thirdparty%2Fsqlite.git Improvements to mutex asserts. The quick test runs to completion without assertion faults. (CVS 4324) FossilOrigin-Name: 2732af0ec77dbc90c0439b6a61d893d9ea3b5697 --- diff --git a/manifest b/manifest index 1c41fe5ca9..7a130fa31a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Use\sthe\sDbMalloc()\sand\sDbRealloc()\sfunctions\smore\sconsistently.\s(CVS\s4323) -D 2007-08-29T14:06:23 +C Improvements\sto\smutex\sasserts.\s\sThe\squick\stest\sruns\sto\scompletion\swithout\nassertion\sfaults.\s(CVS\s4324) +D 2007-08-29T17:43:20 F Makefile.in bfcc303429a5d9dcd552d807ee016c77427418c3 F Makefile.linux-gcc 65241babba6faf1152bf86574477baab19190499 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -77,12 +77,12 @@ F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc F sqlite3.def a96c1d0d39362b763d2ddba220a32da41a15c4b4 F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a F src/alter.c c9f30b4d6fbf7eff7c5518b002a217d4ecd13bcf -F src/analyze.c a28b43a5f79bfa7616ab506bb917077242098469 +F src/analyze.c 49b4bd45eb286d833793ed6bf72355a5c1974865 F src/attach.c a52225c75b107be8c5bc144a2b6d20201be3f8f8 F src/auth.c 083c1205b45e3f52291ec539d396b4fc557856b3 -F src/btmutex.c c04e67d99d949a12beb17209f307950f21313980 -F src/btree.c 7079a423e0da7eec5147d102202e2b51038002cd -F src/btree.h 7391b9e78ae441fe0fb3a6d3ae772770d35a4375 +F src/btmutex.c abc2eda085ff7729c4093db8b4e5357e932f082c +F src/btree.c ff821439edf1fdf85fee7cc7b475b02cacceb2ae +F src/btree.h a90328ee4d7aa49a1ec4309c94a9fae65f39d969 F src/btreeInt.h 1fa6510aa8601dc0358a5240d191335236d3cf76 F src/build.c 830d1a6b2de157fc4d4dd08d4433066ad83f8b72 F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0 @@ -138,7 +138,7 @@ F src/table.c 1aeb9eab57b4235db86fe15a35dec76fb445a9c4 F src/tclsqlite.c d76af53f45c9e9f7f7d39531fa4c7bee7d0adad6 F src/test1.c 8b20d1f05777ac480d3caf8d5f79ab7a543513fc F src/test2.c 4ab230fbdc0decfa7422f6a052b609ba54f4dfac -F src/test3.c de8f2a245d0adf4215487af8267c11ccca31e750 +F src/test3.c 09098991c3a94a1c7f54d28888fca2951d459585 F src/test4.c c2c0f5dc907f1346f5d4b65eb5799f11eb9e4071 F src/test5.c 3a6a5717a149d7ca2e6d14f5be72cf7555d54dc4 F src/test6.c a6223d9d938aba83f20611a2c01680d8043cd2f7 @@ -166,8 +166,8 @@ F src/vdbe.c 9f2ef520614425016881234965b8146ac771d7dc F src/vdbe.h 498e9ddade4baf70f2fc39e585670131dde07caa F src/vdbeInt.h 630145b9bfaa19190ab491f52658a7db550f2247 F src/vdbeapi.c 9c2d681b75e4b90c28b9dd01a3f2e5905267f884 -F src/vdbeaux.c 7cc1e0b33e4d5b8259fd12b7bd28c2180903146c -F src/vdbeblob.c d12ed95dac0992e1e372d079d76af047cc42f7c7 +F src/vdbeaux.c 77db89679834d55ff026c6311c34d2964bf46431 +F src/vdbeblob.c 4da667be7dff5e197b3b986d6f2095cf97a22917 F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6 F src/vdbemem.c 246d434fa60bde6553490eb686adfd86adcd6712 F src/vtab.c ace9b41a088f6ad55d2e39084d92180a2bee3276 @@ -182,7 +182,7 @@ F test/altermalloc.test b341e6515fa6cd9f0ac5d19153c556c9add70be9 F test/analyze.test 2f55535aa335785db1a2f97d3f3831c16c09f8b0 F test/async.test 464dc7c7ccb144e8c82ecca429e6d7cd1c96bd6e F test/async2.test 8f2c70b831dac7292450d0a42580cf2dab497dbb -F test/attach.test cf289abdb120053136649efd1306ab9d47fa41b2 +F test/attach.test b849e1baae863c3a6132ff8b9b1baf356ab6c178 F test/attach2.test 78bc1a25ea8785c7571b44f5947ada2bd5d78127 F test/attach3.test eafcafb107585aecc2ed1569a77914138eef46a9 F test/attachmalloc.test fdbfd9dc0b600db14f9189690c6c12511cc3a56f @@ -567,7 +567,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P d8ef7024172fffee049cfda6707220af2577e9a1 -R 02e243d6b7b8198a44d4e659876a4584 -U danielk1977 -Z e737eb1ddcb93155a8d9637fcf24015b +P c790c234c369c6b7610e67dcaaa9eee347df729c +R 673cf3ccb79c2542ccd493ed4a5e1538 +U drh +Z a367643531757313c52ae724bb0d4a7f diff --git a/manifest.uuid b/manifest.uuid index cbab80841e..57297a0329 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c790c234c369c6b7610e67dcaaa9eee347df729c \ No newline at end of file +2732af0ec77dbc90c0439b6a61d893d9ea3b5697 \ No newline at end of file diff --git a/src/analyze.c b/src/analyze.c index ae4b5ceb99..119e7f6484 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code associated with the ANALYZE command. ** -** @(#) $Id: analyze.c,v 1.22 2007/08/29 04:00:58 drh Exp $ +** @(#) $Id: analyze.c,v 1.23 2007/08/29 17:43:20 drh Exp $ */ #ifndef SQLITE_OMIT_ANALYZE #include "sqliteInt.h" @@ -386,7 +386,9 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){ char *zSql; int rc; - assert( sqlite3BtreeHoldsAllMutexes(db) ); + assert( iDb>=0 && iDbnDb ); + assert( db->aDb[iDb].pBt!=0 ); + assert( sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); /* Clear any prior statistics */ for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){ diff --git a/src/btmutex.c b/src/btmutex.c index 7df445770b..61644a8af8 100644 --- a/src/btmutex.c +++ b/src/btmutex.c @@ -10,7 +10,7 @@ ** ************************************************************************* ** -** $Id: btmutex.c,v 1.5 2007/08/29 04:00:58 drh Exp $ +** $Id: btmutex.c,v 1.6 2007/08/29 17:43:20 drh Exp $ ** ** This file contains code used to implement mutexes on Btree objects. ** This code really belongs in btree.c. But btree.c is getting too @@ -111,18 +111,35 @@ void sqlite3BtreeLeave(Btree *p){ #ifndef NDEBUG /* -** Return true if a mutex is held on the btree. +** Return true if the BtShared mutex is held on the btree. +** +** This routine makes no determination one why or another if the +** database connection mutex is held. ** ** This routine is used only from within assert() statements. */ int sqlite3BtreeHoldsMutex(Btree *p){ - return sqlite3_mutex_held(p->pSqlite->mutex) && - (p->sharable==0 || + return (p->sharable==0 || (p->locked && p->wantToLock && sqlite3_mutex_held(p->pBt->mutex))); } #endif +#ifndef SQLITE_OMIT_INCRBLOB +/* +** Enter and leave a mutex on a Btree given a cursor owned by that +** Btree. These entry points are used by incremental I/O and can be +** omitted if that module is not used. +*/ +void sqlite3BtreeEnterCursor(BtCursor *pCur){ + sqlite3BtreeEnter(pCur->pBtree); +} +void sqlite3BtreeLeaveCursor(BtCursor *pCur){ + sqlite3BtreeLeave(pCur->pBtree); +} +#endif /* SQLITE_OMIT_INCRBLOB */ + + /* ** Enter the mutex on every Btree associated with a database ** connection. This is needed (for example) prior to parsing diff --git a/src/btree.c b/src/btree.c index 46553e5240..187998a3a9 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.417 2007/08/29 12:31:26 danielk1977 Exp $ +** $Id: btree.c,v 1.418 2007/08/29 17:43:20 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. @@ -236,7 +236,7 @@ static void releasePage(MemPage *pPage); /* Forward reference */ */ #ifndef NDEBUG static int cursorHoldsMutex(BtCursor *p){ - return sqlite3BtreeHoldsMutex(p->pBtree); + return sqlite3_mutex_held(p->pBt->mutex); } #endif @@ -1150,32 +1150,43 @@ int sqlite3BtreeOpen( && isMemdb==0 && (pSqlite->flags & SQLITE_Vtab)==0 && zFilename && zFilename[0] - && sqlite3SharedCacheEnabled ){ - char *zFullPathname = (char *)sqlite3_malloc(pVfs->mxPathname); - sqlite3_mutex *mutexShared; - p->sharable = 1; - if( pSqlite ){ - pSqlite->flags |= SQLITE_SharedCache; - } - if( !zFullPathname ){ - sqlite3_free(p); - return SQLITE_NOMEM; - } - sqlite3OsFullPathname(pVfs, zFilename, zFullPathname); - mutexShared = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); - sqlite3_mutex_enter(mutexShared); - for(pBt=sqlite3SharedCacheList; pBt; pBt=pBt->pNext){ - assert( pBt->nRef>0 ); - if( 0==strcmp(zFullPathname, sqlite3PagerFilename(pBt->pPager)) - && sqlite3PagerVfs(pBt->pPager)==pVfs ){ - p->pBt = pBt; - pBt->nRef++; - break; + if( sqlite3SharedCacheEnabled ){ + char *zFullPathname = (char *)sqlite3_malloc(pVfs->mxPathname); + sqlite3_mutex *mutexShared; + p->sharable = 1; + if( pSqlite ){ + pSqlite->flags |= SQLITE_SharedCache; + } + if( !zFullPathname ){ + sqlite3_free(p); + return SQLITE_NOMEM; } + sqlite3OsFullPathname(pVfs, zFilename, zFullPathname); + mutexShared = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); + sqlite3_mutex_enter(mutexShared); + for(pBt=sqlite3SharedCacheList; pBt; pBt=pBt->pNext){ + assert( pBt->nRef>0 ); + if( 0==strcmp(zFullPathname, sqlite3PagerFilename(pBt->pPager)) + && sqlite3PagerVfs(pBt->pPager)==pVfs ){ + p->pBt = pBt; + pBt->nRef++; + break; + } + } + sqlite3_mutex_leave(mutexShared); + sqlite3_free(zFullPathname); } - sqlite3_mutex_leave(mutexShared); - sqlite3_free(zFullPathname); +#ifdef SQLITE_DEBUG + else{ + /* In debug mode, we mark all persistent databases as sharable + ** even when they are not. This exercises the locking code and + ** gives more opportunity for asserts(sqlite3_mutex_held()) + ** statements to find locking problems. + */ + p->sharable = 1; + } +#endif } #endif if( pBt==0 ){ @@ -1253,6 +1264,11 @@ int sqlite3BtreeOpen( pBt->nRef = 1; mutexShared = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); pBt->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + if( pBt->mutex==0 ){ + rc = SQLITE_NOMEM; + pSqlite->mallocFailed = 0; + goto btree_open_out; + } sqlite3_mutex_enter(mutexShared); pBt->pNext = sqlite3SharedCacheList; sqlite3SharedCacheList = pBt; @@ -2687,9 +2703,9 @@ int sqlite3BtreeCursor( */ int sqlite3BtreeCloseCursor(BtCursor *pCur){ BtShared *pBt = pCur->pBt; + Btree *pBtree = pCur->pBtree; - assert( cursorHoldsMutex(pCur) ); - assert( sqlite3_mutex_held(pCur->pBtree->pSqlite->mutex) ); + sqlite3BtreeEnter(pBtree); clearCursorPosition(pCur); if( pCur->pPrev ){ pCur->pPrev->pNext = pCur->pNext; @@ -2703,6 +2719,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){ unlockBtreeIfUnused(pBt); invalidateOverflowCache(pCur); sqlite3_free(pCur); + sqlite3BtreeLeave(pBtree); return SQLITE_OK; } @@ -6578,7 +6595,6 @@ char *sqlite3BtreeIntegrityCheck( */ const char *sqlite3BtreeGetFilename(Btree *p){ assert( p->pBt->pPager!=0 ); - /* assert( sqlite3BtreeHoldsMutex(p) ); */ return sqlite3PagerFilename(p->pBt->pPager); } @@ -6590,7 +6606,6 @@ const char *sqlite3BtreeGetFilename(Btree *p){ */ const char *sqlite3BtreeGetDirname(Btree *p){ assert( p->pBt->pPager!=0 ); - assert( sqlite3BtreeHoldsMutex(p) ); return sqlite3PagerDirname(p->pBt->pPager); } @@ -6604,7 +6619,6 @@ const char *sqlite3BtreeGetDirname(Btree *p){ */ const char *sqlite3BtreeGetJournalname(Btree *p){ assert( p->pBt->pPager!=0 ); - assert( sqlite3BtreeHoldsMutex(p) ); return sqlite3PagerJournalname(p->pBt->pPager); } diff --git a/src/btree.h b/src/btree.h index 6733daa506..032ce9f285 100644 --- a/src/btree.h +++ b/src/btree.h @@ -13,7 +13,7 @@ ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. ** -** @(#) $Id: btree.h,v 1.90 2007/08/29 04:00:58 drh Exp $ +** @(#) $Id: btree.h,v 1.91 2007/08/29 17:43:20 drh Exp $ */ #ifndef _BTREE_H_ #define _BTREE_H_ @@ -176,6 +176,8 @@ int sqlite3BtreePageDump(Btree*, int, int recursive); void sqlite3BtreeEnter(Btree*); void sqlite3BtreeLeave(Btree*); int sqlite3BtreeHoldsMutex(Btree*); + void sqlite3BtreeEnterCursor(BtCursor*); + void sqlite3BtreeLeaveCursor(BtCursor*); void sqlite3BtreeEnterAll(sqlite3*); void sqlite3BtreeLeaveAll(sqlite3*); int sqlite3BtreeHoldsAllMutexes(sqlite3*); @@ -186,6 +188,8 @@ int sqlite3BtreePageDump(Btree*, int, int recursive); # define sqlite3BtreeEnter(X) # define sqlite3BtreeLeave(X) # define sqlite3BtreeHoldsMutex(X) 1 +# define sqlite3BtreeEnterCursor(X) +# define sqlite3BtreeLeaveCursor(X) # define sqlite3BtreeEnterAll(X) # define sqlite3BtreeLeaveAll(X) # define sqlite3BtreeHoldsAllMutexes(X) 1 diff --git a/src/test3.c b/src/test3.c index d35efaab46..f132db9e8e 100644 --- a/src/test3.c +++ b/src/test3.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test3.c,v 1.83 2007/08/29 12:31:28 danielk1977 Exp $ +** $Id: test3.c,v 1.84 2007/08/29 17:43:20 drh Exp $ */ #include "sqliteInt.h" #include "btreeInt.h" @@ -146,7 +146,9 @@ static int btree_begin_transaction( return TCL_ERROR; } pBt = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pBt); rc = sqlite3BtreeBeginTrans(pBt, 1); + sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -173,7 +175,9 @@ static int btree_rollback( return TCL_ERROR; } pBt = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pBt); rc = sqlite3BtreeRollback(pBt); + sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -200,7 +204,9 @@ static int btree_commit( return TCL_ERROR; } pBt = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pBt); rc = sqlite3BtreeCommit(pBt); + sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -227,7 +233,9 @@ static int btree_begin_statement( return TCL_ERROR; } pBt = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pBt); rc = sqlite3BtreeBeginStmt(pBt); + sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -254,7 +262,9 @@ static int btree_rollback_statement( return TCL_ERROR; } pBt = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pBt); rc = sqlite3BtreeRollbackStmt(pBt); + sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -281,7 +291,9 @@ static int btree_commit_statement( return TCL_ERROR; } pBt = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pBt); rc = sqlite3BtreeCommitStmt(pBt); + sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -310,7 +322,9 @@ static int btree_create_table( } pBt = sqlite3TextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &flags) ) return TCL_ERROR; + sqlite3BtreeEnter(pBt); rc = sqlite3BtreeCreateTable(pBt, &iTable, flags); + sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -342,7 +356,9 @@ static int btree_drop_table( } pBt = sqlite3TextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; + sqlite3BtreeEnter(pBt); rc = sqlite3BtreeDropTable(pBt, iTable, ¬Used1); + sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -371,7 +387,9 @@ static int btree_clear_table( } pBt = sqlite3TextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; + sqlite3BtreeEnter(pBt); rc = sqlite3BtreeClearTable(pBt, iTable); + sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -402,7 +420,9 @@ static int btree_get_meta( for(i=0; ipSqlite->mutex); sqlite3BtreeEnter(pBt); a = sqlite3PagerStats(sqlite3BtreePager(pBt)); for(i=0; i<11; i++){ @@ -545,7 +570,6 @@ static int btree_pager_stats( Tcl_AppendElement(interp, zBuf); } sqlite3BtreeLeave(pBt); - sqlite3_mutex_leave(pBt->pSqlite->mutex); return TCL_OK; } @@ -569,7 +593,9 @@ static int btree_pager_ref_dump( } pBt = sqlite3TextToPtr(argv[1]); #ifdef SQLITE_DEBUG + sqlite3BtreeEnter(pBt); sqlite3PagerRefdump(sqlite3BtreePager(pBt)); + sqlite3BtreeLeave(pBt); #endif return TCL_OK; } @@ -606,7 +632,9 @@ static int btree_integrity_check( if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR; } #ifndef SQLITE_OMIT_INTEGRITY_CHECK + sqlite3BtreeEnter(pBt); zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot, 10000, &nErr); + sqlite3BtreeLeave(pBt); #else zResult = 0; #endif @@ -637,7 +665,9 @@ static int btree_cursor_list( return TCL_ERROR; } pBt = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pBt); sqlite3BtreeCursorList(pBt); + sqlite3BtreeLeave(pBt); return SQLITE_OK; } @@ -667,7 +697,9 @@ static int btree_cursor( pBt = sqlite3TextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR; + sqlite3BtreeEnter(pBt); rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, 0, &pCur); + sqlite3BtreeLeave(pBt); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -689,6 +721,7 @@ static int btree_close_cursor( const char **argv /* Text of each argument */ ){ BtCursor *pCur; + Btree *pBt; int rc; if( argc!=2 ){ @@ -697,7 +730,10 @@ static int btree_close_cursor( return TCL_ERROR; } pCur = sqlite3TextToPtr(argv[1]); + pBt = pCur->pBtree; + sqlite3BtreeEnter(pBt); rc = sqlite3BtreeCloseCursor(pCur); + sqlite3BtreeLeave(pBt); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -727,13 +763,18 @@ static int btree_move_to( return TCL_ERROR; } pCur = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pCur->pBtree); if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ int iKey; - if( Tcl_GetInt(interp, argv[2], &iKey) ) return TCL_ERROR; + if( Tcl_GetInt(interp, argv[2], &iKey) ){ + sqlite3BtreeLeave(pCur->pBtree); + return TCL_ERROR; + } rc = sqlite3BtreeMoveto(pCur, 0, iKey, 0, &res); }else{ rc = sqlite3BtreeMoveto(pCur, argv[2], strlen(argv[2]), 0, &res); } + sqlite3BtreeLeave(pCur->pBtree); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -765,7 +806,9 @@ static int btree_delete( return TCL_ERROR; } pCur = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pCur->pBtree); rc = sqlite3BtreeDelete(pCur); + sqlite3BtreeLeave(pCur->pBtree); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -799,11 +842,15 @@ static int btree_insert( }else{ nZero = 0; } + sqlite3BtreeEnter(pCur->pBtree); if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ i64 iKey; int len; unsigned char *pBuf; - if( Tcl_GetWideIntFromObj(interp, objv[2], &iKey) ) return TCL_ERROR; + if( Tcl_GetWideIntFromObj(interp, objv[2], &iKey) ){ + sqlite3BtreeLeave(pCur->pBtree); + return TCL_ERROR; + } pBuf = Tcl_GetByteArrayFromObj(objv[3], &len); rc = sqlite3BtreeInsert(pCur, 0, iKey, pBuf, len, nZero, 0); }else{ @@ -815,6 +862,7 @@ static int btree_insert( pDBuf = Tcl_GetByteArrayFromObj(objv[3], &dlen); rc = sqlite3BtreeInsert(pCur, pKBuf, keylen, pDBuf, dlen, nZero, 0); } + sqlite3BtreeLeave(pCur->pBtree); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -846,7 +894,9 @@ static int btree_next( return TCL_ERROR; } pCur = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pCur->pBtree); rc = sqlite3BtreeNext(pCur, &res); + sqlite3BtreeLeave(pCur->pBtree); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -880,7 +930,9 @@ static int btree_prev( return TCL_ERROR; } pCur = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pCur->pBtree); rc = sqlite3BtreePrevious(pCur, &res); + sqlite3BtreeLeave(pCur->pBtree); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -913,7 +965,9 @@ static int btree_first( return TCL_ERROR; } pCur = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pCur->pBtree); rc = sqlite3BtreeFirst(pCur, &res); + sqlite3BtreeLeave(pCur->pBtree); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -946,7 +1000,9 @@ static int btree_last( return TCL_ERROR; } pCur = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pCur->pBtree); rc = sqlite3BtreeLast(pCur, &res); + sqlite3BtreeLeave(pCur->pBtree); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -969,6 +1025,7 @@ static int btree_eof( const char **argv /* Text of each argument */ ){ BtCursor *pCur; + int rc; char zBuf[50]; if( argc!=2 ){ @@ -977,7 +1034,10 @@ static int btree_eof( return TCL_ERROR; } pCur = sqlite3TextToPtr(argv[1]); - sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", sqlite3BtreeEof(pCur)); + sqlite3BtreeEnter(pCur->pBtree); + rc = sqlite3BtreeEof(pCur); + sqlite3BtreeLeave(pCur->pBtree); + sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc); Tcl_AppendResult(interp, zBuf, 0); return SQLITE_OK; } @@ -1004,7 +1064,9 @@ static int btree_keysize( return TCL_ERROR; } pCur = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pCur->pBtree); sqlite3BtreeKeySize(pCur, (i64*)&n); + sqlite3BtreeLeave(pCur->pBtree); sqlite3_snprintf(sizeof(zBuf),zBuf, "%llu", n); Tcl_AppendResult(interp, zBuf, 0); return SQLITE_OK; @@ -1032,6 +1094,7 @@ static int btree_key( return TCL_ERROR; } pCur = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pCur->pBtree); sqlite3BtreeKeySize(pCur, (i64*)&n); if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ char zBuf2[60]; @@ -1041,6 +1104,7 @@ static int btree_key( zBuf = sqlite3_malloc( n+1 ); rc = sqlite3BtreeKey(pCur, 0, n, zBuf); if( rc ){ + sqlite3BtreeLeave(pCur->pBtree); Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; } @@ -1048,6 +1112,7 @@ static int btree_key( Tcl_AppendResult(interp, zBuf, 0); sqlite3_free(zBuf); } + sqlite3BtreeLeave(pCur->pBtree); return SQLITE_OK; } @@ -1073,6 +1138,7 @@ static int btree_data( return TCL_ERROR; } pCur = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pCur->pBtree); if( argc==2 ){ sqlite3BtreeDataSize(pCur, &n); }else{ @@ -1080,6 +1146,7 @@ static int btree_data( } zBuf = sqlite3_malloc( n+1 ); rc = sqlite3BtreeData(pCur, 0, n, zBuf); + sqlite3BtreeLeave(pCur->pBtree); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); sqlite3_free(zBuf); @@ -1117,6 +1184,7 @@ static int btree_fetch_key( } pCur = sqlite3TextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR; + sqlite3BtreeEnter(pCur->pBtree); sqlite3BtreeKeySize(pCur, (i64*)&nKey); zBuf = sqlite3BtreeKeyFetch(pCur, &amt); if( zBuf && amt>=n ){ @@ -1126,6 +1194,7 @@ static int btree_fetch_key( zStatic[nKey] = 0; Tcl_AppendResult(interp, zStatic, 0); } + sqlite3BtreeLeave(pCur->pBtree); return TCL_OK; } @@ -1155,6 +1224,7 @@ static int btree_fetch_data( } pCur = sqlite3TextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR; + sqlite3BtreeEnter(pCur->pBtree); sqlite3BtreeDataSize(pCur, &nData); zBuf = sqlite3BtreeDataFetch(pCur, &amt); if( zBuf && amt>=n ){ @@ -1164,6 +1234,7 @@ static int btree_fetch_data( zStatic[nData] = 0; Tcl_AppendResult(interp, zStatic, 0); } + sqlite3BtreeLeave(pCur->pBtree); return TCL_OK; } @@ -1189,12 +1260,14 @@ static int btree_payload_size( return TCL_ERROR; } pCur = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pCur->pBtree); if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ n1 = 0; }else{ sqlite3BtreeKeySize(pCur, (i64*)&n1); } sqlite3BtreeDataSize(pCur, (u32*)&n2); + sqlite3BtreeLeave(pCur->pBtree); sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2)); Tcl_AppendResult(interp, zBuf, 0); return SQLITE_OK; @@ -1242,9 +1315,11 @@ static int btree_cursor_info( }else{ up = 0; } + sqlite3BtreeEnter(pCur->pBtree); rc = sqlite3BtreeCursorInfo(pCur, aResult, up); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); + sqlite3BtreeLeave(pCur->pBtree); return TCL_ERROR; } j = 0; @@ -1252,6 +1327,7 @@ static int btree_cursor_info( sqlite3_snprintf(40,&zBuf[j]," %d", aResult[i]); j += strlen(&zBuf[j]); } + sqlite3BtreeLeave(pCur->pBtree); Tcl_AppendResult(interp, &zBuf[1], 0); return SQLITE_OK; } @@ -1300,10 +1376,12 @@ static int btree_ovfl_info( argv[1], 0); return TCL_ERROR; } + sqlite3BtreeEnter(pBt); pPager = sqlite3BtreePager(pBt); rc = sqlite3BtreeCursorInfo(pCur, aResult, 0); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); + sqlite3BtreeLeave(pBt); return TCL_ERROR; } dataSize = sqlite3BtreeGetPageSize(pBt) - sqlite3BtreeGetReserve(pBt); @@ -1318,12 +1396,14 @@ static int btree_ovfl_info( if( sqlite3PagerGet(pPager, pgno, &pDbPage)!=SQLITE_OK ){ Tcl_DStringFree(&str); Tcl_AppendResult(interp, "unable to get page ", zElem, 0); + sqlite3BtreeLeave(pBt); return TCL_ERROR; } pPage = sqlite3PagerGetData(pDbPage); pgno = t4Get4byte((unsigned char*)pPage); sqlite3PagerUnref(pDbPage); } + sqlite3BtreeLeave(pBt); Tcl_DStringResult(interp, &str); return SQLITE_OK; } @@ -1498,7 +1578,9 @@ static int btree_set_cache_size( if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR; sqlite3_mutex_enter(pBt->pSqlite->mutex); + sqlite3BtreeEnter(pBt); sqlite3BtreeSetCacheSize(pBt, nCache); + sqlite3BtreeLeave(pBt); sqlite3_mutex_leave(pBt->pSqlite->mutex); return TCL_OK; diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 55cb88ab36..b0dd09ee9d 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -936,7 +936,7 @@ void sqlite3VdbeMakeReady( } /* -** Close a cursor and release all the resources that cursor happens +** Close a VDBE cursor and release all the resources that cursor happens ** to hold. */ void sqlite3VdbeFreeCursor(Vdbe *p, Cursor *pCx){ @@ -966,14 +966,16 @@ void sqlite3VdbeFreeCursor(Vdbe *p, Cursor *pCx){ } /* -** Close all cursors +** Close all cursors except for VTab cursors that are currently +** in use. */ -static void closeAllCursors(Vdbe *p){ +static void closeAllCursorsExceptActiveVtabs(Vdbe *p){ int i; if( p->apCsr==0 ) return; for(i=0; inCursor; i++){ - if( !p->inVtabMethod || (p->apCsr[i] && !p->apCsr[i]->pVtabCursor) ){ - sqlite3VdbeFreeCursor(p, p->apCsr[i]); + Cursor *pC = p->apCsr[i]; + if( pC && (!p->inVtabMethod || !pC->pVtabCursor) ){ + sqlite3VdbeFreeCursor(p, pC); p->apCsr[i] = 0; } } @@ -992,7 +994,7 @@ static void Cleanup(Vdbe *p){ releaseMemArray(p->aStack, 1 + (p->pTos - p->aStack)); p->pTos = &p->aStack[-1]; } - closeAllCursors(p); + closeAllCursorsExceptActiveVtabs(p); releaseMemArray(p->aMem, p->nMem); sqlite3VdbeFifoClear(&p->sFifo); if( p->contextStack ){ @@ -1311,7 +1313,7 @@ void sqlite3AbortOtherActiveVdbes(sqlite3 *db, Vdbe *pExcept){ if( pOther==pExcept ) continue; if( pOther->magic!=VDBE_MAGIC_RUN || pOther->pc<0 ) continue; checkActiveVdbeCnt(db); - closeAllCursors(pOther); + closeAllCursorsExceptActiveVtabs(pOther); checkActiveVdbeCnt(db); pOther->aborted = 1; } @@ -1323,13 +1325,14 @@ void sqlite3AbortOtherActiveVdbes(sqlite3 *db, Vdbe *pExcept){ ** changes. If a rollback is needed, then do the rollback. ** ** This routine is the only way to move the state of a VM from -** SQLITE_MAGIC_RUN to SQLITE_MAGIC_HALT. +** SQLITE_MAGIC_RUN to SQLITE_MAGIC_HALT. It is harmless to +** call this on a VM that is in the SQLITE_MAGIC_HALT state. ** ** Return an error code. If the commit could not complete because of ** lock contention, return SQLITE_BUSY. If SQLITE_BUSY is returned, it ** means the close did not happen and needs to be repeated. */ -static int sqlite3VdbeHaltLocked(Vdbe *p){ +int sqlite3VdbeHalt(Vdbe *p){ sqlite3 *db = p->db; int i; int (*xFunc)(Btree *pBt) = 0; /* Function to call on each btree backend */ @@ -1366,20 +1369,19 @@ static int sqlite3VdbeHaltLocked(Vdbe *p){ if( p->db->mallocFailed ){ p->rc = SQLITE_NOMEM; } + closeAllCursorsExceptActiveVtabs(p); if( p->magic!=VDBE_MAGIC_RUN ){ - /* Already halted. Nothing to do. */ - assert( p->magic==VDBE_MAGIC_HALT ); -#ifndef SQLITE_OMIT_VIRTUALTABLE - closeAllCursors(p); -#endif return SQLITE_OK; } - closeAllCursors(p); checkActiveVdbeCnt(db); /* No commit or rollback needed if the program never started */ if( p->pc>=0 ){ int mrc; /* Primary error code from p->rc */ + + /* Lock all btrees used by the statement */ + sqlite3BtreeMutexArrayEnter(&p->aMutex); + /* Check for one of the special errors - SQLITE_NOMEM or SQLITE_IOERR */ mrc = p->rc & 0xff; isSpecialError = ( @@ -1423,7 +1425,8 @@ static int sqlite3VdbeHaltLocked(Vdbe *p){ break; } } - + + /* If the query was read-only, we need do no rollback at all. Otherwise, ** proceed with the special handling. */ @@ -1458,6 +1461,7 @@ static int sqlite3VdbeHaltLocked(Vdbe *p){ */ int rc = vdbeCommit(db); if( rc==SQLITE_BUSY ){ + sqlite3BtreeMutexArrayLeave(&p->aMutex); return SQLITE_BUSY; }else if( rc!=SQLITE_OK ){ p->rc = rc; @@ -1520,6 +1524,9 @@ static int sqlite3VdbeHaltLocked(Vdbe *p){ sqlite3ResetInternalSchema(db, 0); db->flags = (db->flags | SQLITE_InternChanges); } + + /* Release the locks */ + sqlite3BtreeMutexArrayLeave(&p->aMutex); } /* We have successfully halted and closed the VM. Record this fact. */ @@ -1528,16 +1535,13 @@ static int sqlite3VdbeHaltLocked(Vdbe *p){ } p->magic = VDBE_MAGIC_HALT; checkActiveVdbeCnt(db); + if( p->db->mallocFailed ){ + p->rc = SQLITE_NOMEM; + } + checkActiveVdbeCnt(db); return SQLITE_OK; } -int sqlite3VdbeHalt(Vdbe *p){ - int rc; - sqlite3BtreeMutexArrayEnter(&p->aMutex); - rc = sqlite3VdbeHaltLocked(p); - sqlite3BtreeMutexArrayLeave(&p->aMutex); - return rc; -} /* diff --git a/src/vdbeblob.c b/src/vdbeblob.c index 6acbe40232..161242db5b 100644 --- a/src/vdbeblob.c +++ b/src/vdbeblob.c @@ -12,7 +12,7 @@ ** ** This file contains code used to implement incremental BLOB I/O. ** -** $Id: vdbeblob.c,v 1.14 2007/08/21 19:33:57 drh Exp $ +** $Id: vdbeblob.c,v 1.15 2007/08/29 17:43:20 drh Exp $ */ #include "sqliteInt.h" @@ -102,6 +102,7 @@ int sqlite3_blob_open( return rc; } + sqlite3BtreeEnterAll(db); pTab = sqlite3LocateTable(&sParse, zTable, zDb); if( !pTab ){ if( sParse.zErrMsg ){ @@ -110,6 +111,7 @@ int sqlite3_blob_open( sqlite3_free(sParse.zErrMsg); rc = SQLITE_ERROR; sqlite3SafetyOff(db); + sqlite3BtreeLeaveAll(db); goto blob_open_out; } @@ -123,6 +125,7 @@ int sqlite3_blob_open( sqlite3_snprintf(sizeof(zErr), zErr, "no such column: \"%s\"", zColumn); rc = SQLITE_ERROR; sqlite3SafetyOff(db); + sqlite3BtreeLeaveAll(db); goto blob_open_out; } @@ -140,6 +143,7 @@ int sqlite3_blob_open( "cannot open indexed column for writing"); rc = SQLITE_ERROR; sqlite3SafetyOff(db); + sqlite3BtreeLeaveAll(db); goto blob_open_out; } } @@ -159,6 +163,9 @@ int sqlite3_blob_open( sqlite3VdbeChangeP1(v, 1, iDb); sqlite3VdbeChangeP2(v, 1, pTab->pSchema->schema_cookie); + /* Make sure a mutex is held on the table to be accessed */ + sqlite3VdbeUsesBtree(v, iDb, db->aDb[iDb].pBt); + /* Configure the db number pushed onto the stack */ sqlite3VdbeChangeP1(v, 2, iDb); @@ -180,7 +187,8 @@ int sqlite3_blob_open( sqlite3VdbeMakeReady(v, 1, 0, 1, 0); } } - + + sqlite3BtreeLeaveAll(db); rc = sqlite3SafetyOff(db); if( rc!=SQLITE_OK || db->mallocFailed ){ goto blob_open_out; @@ -218,7 +226,9 @@ int sqlite3_blob_open( } pBlob->flags = flags; pBlob->pCsr = v->apCsr[0]->pCursor; + sqlite3BtreeEnterCursor(pBlob->pCsr); sqlite3BtreeCacheOverflow(pBlob->pCsr); + sqlite3BtreeLeaveCursor(pBlob->pCsr); pBlob->pStmt = (sqlite3_stmt *)v; pBlob->iOffset = v->apCsr[0]->aOffset[iCol]; pBlob->nByte = sqlite3VdbeSerialTypeLen(type); @@ -247,12 +257,9 @@ blob_open_out: */ int sqlite3_blob_close(sqlite3_blob *pBlob){ Incrblob *p = (Incrblob *)pBlob; - sqlite3_mutex *mutex = p->db->mutex; int rc; - sqlite3_mutex_enter(mutex); rc = sqlite3_finalize(p->pStmt); - sqlite3_mutex_leave(mutex); sqlite3_free(p); return rc; } @@ -289,7 +296,9 @@ static int blobReadWrite( ** returned, clean-up the statement handle. */ assert( db == v->db ); + sqlite3BtreeEnterCursor(p->pCsr); rc = xCall(p->pCsr, iOffset+p->iOffset, n, z); + sqlite3BtreeLeaveCursor(p->pCsr); if( rc==SQLITE_ABORT ){ sqlite3VdbeFinalize(v); p->pStmt = 0; diff --git a/test/attach.test b/test/attach.test index b0b7870b3d..af712d04c5 100644 --- a/test/attach.test +++ b/test/attach.test @@ -12,7 +12,7 @@ # focus of this script is testing the ATTACH and DETACH commands # and related functionality. # -# $Id: attach.test,v 1.44 2007/05/09 20:31:30 drh Exp $ +# $Id: attach.test,v 1.45 2007/08/29 17:43:20 drh Exp $ # set testdir [file dirname $argv0] @@ -53,6 +53,7 @@ do_test attach-1.4 { } } {1 x 2 y} do_test attach-1.5 { +btree_breakpoint execsql { DETACH DATABASE two; SELECT * FROM t1;