1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-29 08:01:23 +03:00

Clean up the locking in the btree logic. (CVS 4316)

FossilOrigin-Name: 967ab229af462a8ae663090ea36b4cc10e351653
This commit is contained in:
drh
2007-08-28 22:24:34 +00:00
parent 27a770e044
commit d0679edc7a
12 changed files with 165 additions and 108 deletions

View File

@ -1,5 +1,5 @@
C Fix\smemory\sleak\sof\sInteriorReader.term.\s\sComes\sup\swhen\sdoing\squeries\nagainst\slarge\ssegments.\s(CVS\s4315) C Clean\sup\sthe\slocking\sin\sthe\sbtree\slogic.\s(CVS\s4316)
D 2007-08-28T20:36:54 D 2007-08-28T22:24:35
F Makefile.in bfcc303429a5d9dcd552d807ee016c77427418c3 F Makefile.in bfcc303429a5d9dcd552d807ee016c77427418c3
F Makefile.linux-gcc 65241babba6faf1152bf86574477baab19190499 F Makefile.linux-gcc 65241babba6faf1152bf86574477baab19190499
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@ -81,10 +81,10 @@ F src/analyze.c a14237d869c6bea0846493b59317e4097e81a0b6
F src/attach.c a52225c75b107be8c5bc144a2b6d20201be3f8f8 F src/attach.c a52225c75b107be8c5bc144a2b6d20201be3f8f8
F src/auth.c 083c1205b45e3f52291ec539d396b4fc557856b3 F src/auth.c 083c1205b45e3f52291ec539d396b4fc557856b3
F src/btmutex.c 3a19fcb311d0d09e63d397779be881d4273f4518 F src/btmutex.c 3a19fcb311d0d09e63d397779be881d4273f4518
F src/btree.c 850cd5de860e01233153ade9b24ffc775a794e8e F src/btree.c 8796aa42fd16feb587844489a0fce8c66e52ac02
F src/btree.h a8fb26c56b745b57446c2bf29133619261313051 F src/btree.h a8fb26c56b745b57446c2bf29133619261313051
F src/btreeInt.h c1ba892252bc4dd76ad66da056536c64b23456e3 F src/btreeInt.h 5b1bc919cb80f0dd6baec1cdbae737f9806a7e3b
F src/build.c 08001e8a12b06178193dc4a8f24610f58de80dae F src/build.c 99b0b0c44ce7673c00d8c0c97ce536e3b796328b
F src/callback.c a542236a68060caad378efa30006ca46cf77b1b2 F src/callback.c a542236a68060caad378efa30006ca46cf77b1b2
F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131 F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131
F src/date.c af235f38f50809abd0a96da3bb3e0cc32be6226e F src/date.c af235f38f50809abd0a96da3bb3e0cc32be6226e
@ -107,7 +107,7 @@ F src/mem2.c 1a2ca756a285b5365d667841508cc1f98938b8d8
F src/mutex.c 40e5ba09d56863895882a0204d93832e9960ea78 F src/mutex.c 40e5ba09d56863895882a0204d93832e9960ea78
F src/mutex.h 4d3babe3a691533ac980967d394da512140b5143 F src/mutex.h 4d3babe3a691533ac980967d394da512140b5143
F src/mutex_os2.c d47e9bd495583dd31263d8fe55160a31eb600a3c F src/mutex_os2.c d47e9bd495583dd31263d8fe55160a31eb600a3c
F src/mutex_unix.c 84ae0344b0bd6591e3bfea2cb6d375233d39f8a4 F src/mutex_unix.c ff77650261a245035b79c5c8a174f4e05d3cae8a
F src/mutex_w32.c 8716478c5f1829b27fd2c9a0759230a9dc3aa9e3 F src/mutex_w32.c 8716478c5f1829b27fd2c9a0759230a9dc3aa9e3
F src/os.c a8ed3c495161475dbce255f7003144144fb425f1 F src/os.c a8ed3c495161475dbce255f7003144144fb425f1
F src/os.h 2bfbbad126a775e4d8c7d59eb4d9585a5fd7dfb5 F src/os.h 2bfbbad126a775e4d8c7d59eb4d9585a5fd7dfb5
@ -120,8 +120,8 @@ F src/os_unix.c 89bf24aa2475048a7833c45c522e7c6a81b83bb8
F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e
F src/os_win.c 3ffd3aacff4cb69848284e29dcec0feff23b0752 F src/os_win.c 3ffd3aacff4cb69848284e29dcec0feff23b0752
F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
F src/pager.c 51ca27639ab25c8838afc856d3cc6045a98752a7 F src/pager.c 97fd0bb853e01e6890ad9aae97e7f9155330ebdc
F src/pager.h 53087c6fb9db01aed17c7fd044662a27507e89b8 F src/pager.h a9872db184613ae90ae80921f5fd956aa8f3522e
F src/parse.y 2d2ce439dc6184621fb0b86f4fc5aca7f391a590 F src/parse.y 2d2ce439dc6184621fb0b86f4fc5aca7f391a590
F src/pragma.c 9b989506a1b7c8aecd6befb8235e2f57a4aba7e5 F src/pragma.c 9b989506a1b7c8aecd6befb8235e2f57a4aba7e5
F src/prepare.c 29ea14cf6b0558f2f80aa53e112bff55f1119e36 F src/prepare.c 29ea14cf6b0558f2f80aa53e112bff55f1119e36
@ -163,10 +163,10 @@ F src/utf.c 4af6259d5906b5a1bf3035cc387c4d7907bdd56e
F src/util.c 3f9c0387b54f977726790f52ab92cd3d9379b367 F src/util.c 3f9c0387b54f977726790f52ab92cd3d9379b367
F src/vacuum.c 5ec133b69edf581a232af7e2b01f45c9f2b8be32 F src/vacuum.c 5ec133b69edf581a232af7e2b01f45c9f2b8be32
F src/vdbe.c 62d210babaac906a5847d7bd4c71e7b114595e85 F src/vdbe.c 62d210babaac906a5847d7bd4c71e7b114595e85
F src/vdbe.h 5b3ee0fd91a08579f514713038fa7dbef9edf407 F src/vdbe.h 498e9ddade4baf70f2fc39e585670131dde07caa
F src/vdbeInt.h 0681e0b74a43d3adfec65780d73b2db8f826c7c9 F src/vdbeInt.h a9dcd0688783abbd60981aff7ecc5b57a9559765
F src/vdbeapi.c bdd0aea216744482dd1b7fab56de18ba5b6fbdf4 F src/vdbeapi.c bdd0aea216744482dd1b7fab56de18ba5b6fbdf4
F src/vdbeaux.c bffdf7b69de21a70520260d359e19df64f31aea4 F src/vdbeaux.c 0bbc8fbb6bcd610e98ce8eef77d0db660710f9dd
F src/vdbeblob.c d12ed95dac0992e1e372d079d76af047cc42f7c7 F src/vdbeblob.c d12ed95dac0992e1e372d079d76af047cc42f7c7
F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6 F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6
F src/vdbemem.c 896fa3f8df9d2661eb15c7ce361857741b447268 F src/vdbemem.c 896fa3f8df9d2661eb15c7ce361857741b447268
@ -403,7 +403,7 @@ F test/server1.test e328b8e641ba8fe9273132cfef497383185dc1f5
F test/shared.test 08b30d5f1939efff0517e7ff8ec7b74ad31c151b F test/shared.test 08b30d5f1939efff0517e7ff8ec7b74ad31c151b
F test/shared2.test 0ee9de8964d70e451936a48c41cb161d9134ccf4 F test/shared2.test 0ee9de8964d70e451936a48c41cb161d9134ccf4
F test/shared3.test 01e3e124dbb3859788aabc7cfb82f7ea04421749 F test/shared3.test 01e3e124dbb3859788aabc7cfb82f7ea04421749
F test/shared_err.test 9fa070e3e7d63022a81b6156ac71f114c0678e3d F test/shared_err.test 99d3d87924cedc1db2233ef59f38c389dd358698
F test/soak.test 64f9b27fbcdec43335a88c546ce1983e6ba40d7b F test/soak.test 64f9b27fbcdec43335a88c546ce1983e6ba40d7b
F test/softheap1.test 0c49aa6eee25e7d32943e85e8d1f20eff566b1dc F test/softheap1.test 0c49aa6eee25e7d32943e85e8d1f20eff566b1dc
F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5 F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5
@ -567,7 +567,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
P dd43a2de3ed1659d70361370d07a184dd8ece45f P 6c617bd89fc57881a2a308a6360e8ebb42835d46
R 70912c36e1c512cb72f986c6f3262b7a R 45b11caba5c119849cdae69b051cb491
U shess U drh
Z e249b078ef5ae37e1d80116148f5bc5a Z 8c8847e04e8b6bae7d208c08aa3c66c5

View File

@ -1 +1 @@
6c617bd89fc57881a2a308a6360e8ebb42835d46 967ab229af462a8ae663090ea36b4cc10e351653

View File

@ -9,7 +9,7 @@
** May you share freely, never taking more than you give. ** May you share freely, never taking more than you give.
** **
************************************************************************* *************************************************************************
** $Id: btree.c,v 1.413 2007/08/28 02:27:52 drh Exp $ ** $Id: btree.c,v 1.414 2007/08/28 22:24:35 drh Exp $
** **
** This file implements a external (disk-based) database using BTrees. ** This file implements a external (disk-based) database using BTrees.
** See the header comment on "btreeInt.h" for additional information. ** See the header comment on "btreeInt.h" for additional information.
@ -96,6 +96,7 @@ static int queryTableLock(Btree *p, Pgno iTab, u8 eLock){
BtShared *pBt = p->pBt; BtShared *pBt = p->pBt;
BtLock *pIter; BtLock *pIter;
assert( sqlite3BtreeMutexHeld(p->pSqlite->mutex) );
assert( sqlite3BtreeMutexHeld(pBt->mutex) ); assert( sqlite3BtreeMutexHeld(pBt->mutex) );
/* This is a no-op if the shared-cache is not enabled */ /* This is a no-op if the shared-cache is not enabled */
@ -148,6 +149,7 @@ static int lockTable(Btree *p, Pgno iTable, u8 eLock){
BtLock *pLock = 0; BtLock *pLock = 0;
BtLock *pIter; BtLock *pIter;
assert( sqlite3BtreeMutexHeld(p->pSqlite->mutex) );
assert( sqlite3BtreeMutexHeld(pBt->mutex) ); assert( sqlite3BtreeMutexHeld(pBt->mutex) );
/* This is a no-op if the shared-cache is not enabled */ /* This is a no-op if the shared-cache is not enabled */
@ -214,6 +216,7 @@ static int lockTable(Btree *p, Pgno iTable, u8 eLock){
static void unlockAllTables(Btree *p){ static void unlockAllTables(Btree *p){
BtLock **ppIter = &p->pBt->pLock; BtLock **ppIter = &p->pBt->pLock;
assert( sqlite3BtreeMutexHeld(p->pSqlite->mutex) );
assert( sqlite3BtreeMutexHeld(p->pBt->mutex) ); assert( sqlite3BtreeMutexHeld(p->pBt->mutex) );
assert( p->sharable || 0==*ppIter ); assert( p->sharable || 0==*ppIter );
@ -236,6 +239,7 @@ static void releasePage(MemPage *pPage); /* Forward reference */
** Invalidate the overflow page-list cache for cursor pCur, if any. ** Invalidate the overflow page-list cache for cursor pCur, if any.
*/ */
static void invalidateOverflowCache(BtCursor *pCur){ static void invalidateOverflowCache(BtCursor *pCur){
assert( sqlite3BtreeMutexHeld(pCur->pBt->mutex) );
sqlite3_free(pCur->aOverflow); sqlite3_free(pCur->aOverflow);
pCur->aOverflow = 0; pCur->aOverflow = 0;
} }
@ -265,7 +269,7 @@ static int saveCursorPosition(BtCursor *pCur){
assert( CURSOR_VALID==pCur->eState ); assert( CURSOR_VALID==pCur->eState );
assert( 0==pCur->pKey ); assert( 0==pCur->pKey );
assert( sqlite3BtreeMutexHeld(pCur->pBtree->pBt->mutex) ); assert( sqlite3BtreeMutexHeld(pCur->pBt->mutex) );
rc = sqlite3BtreeKeySize(pCur, &pCur->nKey); rc = sqlite3BtreeKeySize(pCur, &pCur->nKey);
@ -308,6 +312,7 @@ static int saveCursorPosition(BtCursor *pCur){
static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){ static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){
BtCursor *p; BtCursor *p;
assert( sqlite3BtreeMutexHeld(pBt->mutex) ); assert( sqlite3BtreeMutexHeld(pBt->mutex) );
assert( pExcept==0 || pExcept->pBt==pBt );
for(p=pBt->pCursor; p; p=p->pNext){ for(p=pBt->pCursor; p; p=p->pNext){
if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) && if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) &&
p->eState==CURSOR_VALID ){ p->eState==CURSOR_VALID ){
@ -324,7 +329,7 @@ static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){
** Clear the current cursor position. ** Clear the current cursor position.
*/ */
static void clearCursorPosition(BtCursor *pCur){ static void clearCursorPosition(BtCursor *pCur){
assert( sqlite3BtreeMutexHeld(pCur->pBtree->pBt->mutex) ); assert( sqlite3BtreeMutexHeld(pCur->pBt->mutex) );
sqlite3_free(pCur->pKey); sqlite3_free(pCur->pKey);
pCur->pKey = 0; pCur->pKey = 0;
pCur->eState = CURSOR_INVALID; pCur->eState = CURSOR_INVALID;
@ -343,6 +348,7 @@ static void clearCursorPosition(BtCursor *pCur){
*/ */
int sqlite3BtreeRestoreOrClearCursorPosition(BtCursor *pCur){ int sqlite3BtreeRestoreOrClearCursorPosition(BtCursor *pCur){
int rc; int rc;
assert( sqlite3BtreeMutexHeld(pCur->pBt->mutex) );
assert( pCur->eState==CURSOR_REQUIRESEEK ); assert( pCur->eState==CURSOR_REQUIRESEEK );
#ifndef SQLITE_OMIT_INCRBLOB #ifndef SQLITE_OMIT_INCRBLOB
if( pCur->isIncrblobHandle ){ if( pCur->isIncrblobHandle ){
@ -1052,9 +1058,11 @@ static void pageDestructor(DbPage *pData, int pageSize){
MemPage *pPage; MemPage *pPage;
assert( (pageSize & 7)==0 ); assert( (pageSize & 7)==0 );
pPage = (MemPage *)sqlite3PagerGetExtra(pData); pPage = (MemPage *)sqlite3PagerGetExtra(pData);
assert( pPage->isInit==0 || sqlite3BtreeMutexHeld(pPage->pBt->mutex) );
if( pPage->pParent ){ if( pPage->pParent ){
MemPage *pParent = pPage->pParent; MemPage *pParent = pPage->pParent;
assert( sqlite3BtreeMutexHeld(pPage->pBt->mutex) ); assert( pPage->isInit==1 );
assert( pParent->pBt==pPage->pBt );
pPage->pParent = 0; pPage->pParent = 0;
releasePage(pParent); releasePage(pParent);
} }
@ -1115,13 +1123,10 @@ int sqlite3BtreeOpen(
#endif #endif
#endif #endif
if( pSqlite ){ assert( pSqlite!=0 );
pVfs = pSqlite->pVfs; assert( sqlite3_mutex_held(pSqlite->mutex) );
}else{
pVfs = sqlite3_vfs_find(0);
}
assert( sqlite3BtreeMutexHeld(pSqlite->mutex) );
pVfs = pSqlite->pVfs;
p = sqlite3MallocZero(sizeof(Btree)); p = sqlite3MallocZero(sizeof(Btree));
if( !p ){ if( !p ){
return SQLITE_NOMEM; return SQLITE_NOMEM;
@ -1136,7 +1141,7 @@ int sqlite3BtreeOpen(
*/ */
if( (flags & BTREE_PRIVATE)==0 if( (flags & BTREE_PRIVATE)==0
&& isMemdb==0 && isMemdb==0
&& (pSqlite==0 || (pSqlite->flags &SQLITE_Vtab)==0) && (pSqlite->flags & SQLITE_Vtab)==0
&& zFilename && zFilename[0] && zFilename && zFilename[0]
&& sqlite3SharedCacheEnabled && sqlite3SharedCacheEnabled
){ ){
@ -1155,7 +1160,8 @@ int sqlite3BtreeOpen(
sqlite3_mutex_enter(mutexShared); sqlite3_mutex_enter(mutexShared);
for(pBt=sqlite3SharedCacheList; pBt; pBt=pBt->pNext){ for(pBt=sqlite3SharedCacheList; pBt; pBt=pBt->pNext){
assert( pBt->nRef>0 ); assert( pBt->nRef>0 );
if( 0==strcmp(zFullPathname, sqlite3PagerFilename(pBt->pPager)) ){ if( 0==strcmp(zFullPathname, sqlite3PagerFilename(pBt->pPager))
&& sqlite3PagerVfs(pBt->pPager)==pVfs ){
p->pBt = pBt; p->pBt = pBt;
pBt->nRef++; pBt->nRef++;
break; break;
@ -1338,6 +1344,7 @@ int sqlite3BtreeClose(Btree *p){
BtCursor *pCur; BtCursor *pCur;
/* Close all cursors opened via this handle. */ /* Close all cursors opened via this handle. */
assert( sqlite3_mutex_held(p->pSqlite->mutex) );
sqlite3BtreeEnter(p); sqlite3BtreeEnter(p);
pCur = pBt->pCursor; pCur = pBt->pCursor;
while( pCur ){ while( pCur ){
@ -1390,12 +1397,8 @@ int sqlite3BtreeClose(Btree *p){
/* /*
** Short-cuts for entering and leaving mutexes on a cursor. ** Short-cuts for entering and leaving mutexes on a cursor.
*/ */
static void cursorLeave(BtCursor *p){ # define cursorEnter(X) assert( sqlite3_mutex_held(X->pBt->mutex) )
sqlite3BtreeLeave(p->pBtree); # define cursorLeave(X)
}
static void cursorEnter(BtCursor *pCur){
sqlite3BtreeEnter(pCur->pBtree);
}
#else #else
# define cursorEnter(X) # define cursorEnter(X)
# define cursorLeave(X) # define cursorLeave(X)
@ -1406,6 +1409,7 @@ static void cursorEnter(BtCursor *pCur){
*/ */
int sqlite3BtreeSetBusyHandler(Btree *p, BusyHandler *pHandler){ int sqlite3BtreeSetBusyHandler(Btree *p, BusyHandler *pHandler){
BtShared *pBt = p->pBt; BtShared *pBt = p->pBt;
assert( sqlite3_mutex_held(p->pSqlite->mutex) );
sqlite3BtreeEnter(p); sqlite3BtreeEnter(p);
pBt->pBusyHandler = pHandler; pBt->pBusyHandler = pHandler;
sqlite3PagerSetBusyhandler(pBt->pPager, pHandler); sqlite3PagerSetBusyhandler(pBt->pPager, pHandler);
@ -1430,6 +1434,7 @@ int sqlite3BtreeSetBusyHandler(Btree *p, BusyHandler *pHandler){
*/ */
int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){ int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){
BtShared *pBt = p->pBt; BtShared *pBt = p->pBt;
assert( sqlite3_mutex_held(p->pSqlite->mutex) );
sqlite3BtreeEnter(p); sqlite3BtreeEnter(p);
sqlite3PagerSetCachesize(pBt->pPager, mxPage); sqlite3PagerSetCachesize(pBt->pPager, mxPage);
sqlite3BtreeLeave(p); sqlite3BtreeLeave(p);
@ -1447,6 +1452,7 @@ int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){
#ifndef SQLITE_OMIT_PAGER_PRAGMAS #ifndef SQLITE_OMIT_PAGER_PRAGMAS
int sqlite3BtreeSetSafetyLevel(Btree *p, int level, int fullSync){ int sqlite3BtreeSetSafetyLevel(Btree *p, int level, int fullSync){
BtShared *pBt = p->pBt; BtShared *pBt = p->pBt;
assert( sqlite3_mutex_held(p->pSqlite->mutex) );
sqlite3BtreeEnter(p); sqlite3BtreeEnter(p);
sqlite3PagerSetSafetyLevel(pBt->pPager, level, fullSync); sqlite3PagerSetSafetyLevel(pBt->pPager, level, fullSync);
sqlite3BtreeLeave(p); sqlite3BtreeLeave(p);
@ -1461,8 +1467,9 @@ int sqlite3BtreeSetSafetyLevel(Btree *p, int level, int fullSync){
int sqlite3BtreeSyncDisabled(Btree *p){ int sqlite3BtreeSyncDisabled(Btree *p){
BtShared *pBt = p->pBt; BtShared *pBt = p->pBt;
int rc; int rc;
assert( pBt && pBt->pPager ); assert( sqlite3_mutex_held(p->pSqlite->mutex) );
sqlite3BtreeEnter(p); sqlite3BtreeEnter(p);
assert( pBt && pBt->pPager );
rc = sqlite3PagerNosync(pBt->pPager); rc = sqlite3PagerNosync(pBt->pPager);
sqlite3BtreeLeave(p); sqlite3BtreeLeave(p);
return rc; return rc;
@ -1986,6 +1993,7 @@ static int relocatePage(
assert( eType==PTRMAP_OVERFLOW2 || eType==PTRMAP_OVERFLOW1 || assert( eType==PTRMAP_OVERFLOW2 || eType==PTRMAP_OVERFLOW1 ||
eType==PTRMAP_BTREE || eType==PTRMAP_ROOTPAGE ); eType==PTRMAP_BTREE || eType==PTRMAP_ROOTPAGE );
assert( sqlite3BtreeMutexHeld(pBt->mutex) ); assert( sqlite3BtreeMutexHeld(pBt->mutex) );
assert( pDbPage->pBt==pBt );
/* Move page iDbPage from it's current location to page number iFreePage */ /* Move page iDbPage from it's current location to page number iFreePage */
TRACE(("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n", TRACE(("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n",
@ -2595,6 +2603,7 @@ static int btreeCursor(
BtShared *pBt = p->pBt; BtShared *pBt = p->pBt;
assert( sqlite3BtreeMutexHeld(pBt->mutex) ); assert( sqlite3BtreeMutexHeld(pBt->mutex) );
assert( sqlite3BtreeMutexHeld(p->pSqlite->mutex) );
*ppCur = 0; *ppCur = 0;
if( wrFlag ){ if( wrFlag ){
if( pBt->readOnly ){ if( pBt->readOnly ){
@ -2636,6 +2645,7 @@ static int btreeCursor(
pCur->xCompare = xCmp ? xCmp : dfltCompare; pCur->xCompare = xCmp ? xCmp : dfltCompare;
pCur->pArg = pArg; pCur->pArg = pArg;
pCur->pBtree = p; pCur->pBtree = p;
pCur->pBt = pBt;
pCur->wrFlag = wrFlag; pCur->wrFlag = wrFlag;
pCur->pNext = pBt->pCursor; pCur->pNext = pBt->pCursor;
if( pCur->pNext ){ if( pCur->pNext ){
@ -2676,9 +2686,10 @@ int sqlite3BtreeCursor(
** when the last cursor is closed. ** when the last cursor is closed.
*/ */
int sqlite3BtreeCloseCursor(BtCursor *pCur){ int sqlite3BtreeCloseCursor(BtCursor *pCur){
BtShared *pBt = pCur->pBtree->pBt; BtShared *pBt = pCur->pBt;
cursorEnter(pCur); assert( sqlite3_mutex_held(pCur->pBt->mutex) );
assert( sqlite3_mutex_held(pCur->pBtree->pSqlite->mutex) );
clearCursorPosition(pCur); clearCursorPosition(pCur);
if( pCur->pPrev ){ if( pCur->pPrev ){
pCur->pPrev->pNext = pCur->pNext; pCur->pPrev->pNext = pCur->pNext;
@ -2691,7 +2702,6 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
releasePage(pCur->pPage); releasePage(pCur->pPage);
unlockBtreeIfUnused(pBt); unlockBtreeIfUnused(pBt);
invalidateOverflowCache(pCur); invalidateOverflowCache(pCur);
cursorLeave(pCur);
sqlite3_free(pCur); sqlite3_free(pCur);
return SQLITE_OK; return SQLITE_OK;
} }
@ -2701,14 +2711,14 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
** The temporary cursor is not on the cursor list for the Btree. ** The temporary cursor is not on the cursor list for the Btree.
*/ */
void sqlite3BtreeGetTempCursor(BtCursor *pCur, BtCursor *pTempCur){ void sqlite3BtreeGetTempCursor(BtCursor *pCur, BtCursor *pTempCur){
cursorEnter(pCur);
memcpy(pTempCur, pCur, sizeof(*pCur)); memcpy(pTempCur, pCur, sizeof(*pCur));
pTempCur->pNext = 0; pTempCur->pNext = 0;
pTempCur->pPrev = 0; pTempCur->pPrev = 0;
if( pTempCur->pPage ){ if( pTempCur->pPage ){
cursorEnter(pCur);
sqlite3PagerRef(pTempCur->pPage->pDbPage); sqlite3PagerRef(pTempCur->pPage->pDbPage);
cursorLeave(pCur);
} }
cursorLeave(pCur);
} }
/* /*
@ -2716,11 +2726,11 @@ void sqlite3BtreeGetTempCursor(BtCursor *pCur, BtCursor *pTempCur){
** function above. ** function above.
*/ */
void sqlite3BtreeReleaseTempCursor(BtCursor *pCur){ void sqlite3BtreeReleaseTempCursor(BtCursor *pCur){
cursorEnter(pCur);
if( pCur->pPage ){ if( pCur->pPage ){
cursorEnter(pCur);
sqlite3PagerUnref(pCur->pPage->pDbPage); sqlite3PagerUnref(pCur->pPage->pDbPage);
cursorLeave(pCur);
} }
cursorLeave(pCur);
} }
/* /*
@ -2778,7 +2788,7 @@ void sqlite3BtreeReleaseTempCursor(BtCursor *pCur){
int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
int rc; int rc;
sqlite3BtreeEnter(pCur->pBtree); assert( sqlite3_mutex_held(pCur->pBt->mutex) );
rc = restoreOrClearCursorPosition(pCur); rc = restoreOrClearCursorPosition(pCur);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID ); assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID );
@ -2789,7 +2799,6 @@ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
*pSize = pCur->info.nKey; *pSize = pCur->info.nKey;
} }
} }
sqlite3BtreeLeave(pCur->pBtree);
return rc; return rc;
} }
@ -2803,7 +2812,7 @@ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){ int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
int rc; int rc;
sqlite3BtreeEnter(pCur->pBtree); assert( sqlite3_mutex_held(pCur->pBt->mutex) );
rc = restoreOrClearCursorPosition(pCur); rc = restoreOrClearCursorPosition(pCur);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID ); assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID );
@ -2815,7 +2824,6 @@ int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
*pSize = pCur->info.nData; *pSize = pCur->info.nData;
} }
} }
sqlite3BtreeLeave(pCur->pBtree);
return rc; return rc;
} }
@ -2978,14 +2986,14 @@ static int accessPayload(
int rc = SQLITE_OK; int rc = SQLITE_OK;
u32 nKey; u32 nKey;
int iIdx = 0; int iIdx = 0;
MemPage *pPage = pCur->pPage; /* Btree page of current cursor entry */ MemPage *pPage = pCur->pPage; /* Btree page of current cursor entry */
BtShared *pBt = pCur->pBtree->pBt; /* Btree this cursor belongs to */ BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */
assert( pPage ); assert( pPage );
assert( pCur->eState==CURSOR_VALID ); assert( pCur->eState==CURSOR_VALID );
assert( pCur->idx>=0 && pCur->idx<pPage->nCell ); assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
assert( offset>=0 ); assert( offset>=0 );
assert( sqlite3BtreeMutexHeld(pCur->pBtree->pBt->mutex) ); assert( sqlite3BtreeMutexHeld(pCur->pBt->mutex) );
getCellInfo(pCur); getCellInfo(pCur);
aPayload = pCur->info.pCell + pCur->info.nHeader; aPayload = pCur->info.pCell + pCur->info.nHeader;
@ -3111,20 +3119,20 @@ static int accessPayload(
int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
int rc; int rc;
sqlite3BtreeEnter(pCur->pBtree); cursorEnter(pCur);
rc = restoreOrClearCursorPosition(pCur); rc = restoreOrClearCursorPosition(pCur);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
assert( pCur->eState==CURSOR_VALID ); assert( pCur->eState==CURSOR_VALID );
assert( pCur->pPage!=0 ); assert( pCur->pPage!=0 );
if( pCur->pPage->intKey ){ if( pCur->pPage->intKey ){
sqlite3BtreeLeave(pCur->pBtree); cursorLeave(pCur);
return SQLITE_CORRUPT_BKPT; return SQLITE_CORRUPT_BKPT;
} }
assert( pCur->pPage->intKey==0 ); assert( pCur->pPage->intKey==0 );
assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell ); assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
rc = accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0, 0); rc = accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0, 0);
} }
sqlite3BtreeLeave(pCur->pBtree); cursorLeave(pCur);
return rc; return rc;
} }
@ -3140,7 +3148,7 @@ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
int rc; int rc;
sqlite3BtreeEnter(pCur->pBtree); cursorEnter(pCur);
rc = restoreOrClearCursorPosition(pCur); rc = restoreOrClearCursorPosition(pCur);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
assert( pCur->eState==CURSOR_VALID ); assert( pCur->eState==CURSOR_VALID );
@ -3148,7 +3156,7 @@ int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell ); assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
rc = accessPayload(pCur, offset, amt, pBuf, 1, 0); rc = accessPayload(pCur, offset, amt, pBuf, 1, 0);
} }
sqlite3BtreeLeave(pCur->pBtree); cursorLeave(pCur);
return rc; return rc;
} }
@ -3183,7 +3191,7 @@ static const unsigned char *fetchPayload(
assert( pCur!=0 && pCur->pPage!=0 ); assert( pCur!=0 && pCur->pPage!=0 );
assert( pCur->eState==CURSOR_VALID ); assert( pCur->eState==CURSOR_VALID );
assert( sqlite3BtreeMutexHeld(pCur->pBtree->pBt->mutex) ); assert( sqlite3BtreeMutexHeld(pCur->pBt->mutex) );
pPage = pCur->pPage; pPage = pCur->pPage;
assert( pCur->idx>=0 && pCur->idx<pPage->nCell ); assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
getCellInfo(pCur); getCellInfo(pCur);
@ -3223,14 +3231,14 @@ static const unsigned char *fetchPayload(
** in the common case where no overflow pages are used. ** in the common case where no overflow pages are used.
*/ */
const void *sqlite3BtreeKeyFetch(BtCursor *pCur, int *pAmt){ const void *sqlite3BtreeKeyFetch(BtCursor *pCur, int *pAmt){
assert( sqlite3BtreeMutexHeld(pCur->pBtree->pBt->mutex) ); assert( sqlite3BtreeMutexHeld(pCur->pBt->mutex) );
if( pCur->eState==CURSOR_VALID ){ if( pCur->eState==CURSOR_VALID ){
return (const void*)fetchPayload(pCur, pAmt, 0); return (const void*)fetchPayload(pCur, pAmt, 0);
} }
return 0; return 0;
} }
const void *sqlite3BtreeDataFetch(BtCursor *pCur, int *pAmt){ const void *sqlite3BtreeDataFetch(BtCursor *pCur, int *pAmt){
assert( sqlite3BtreeMutexHeld(pCur->pBtree->pBt->mutex) ); assert( sqlite3BtreeMutexHeld(pCur->pBt->mutex) );
if( pCur->eState==CURSOR_VALID ){ if( pCur->eState==CURSOR_VALID ){
return (const void*)fetchPayload(pCur, pAmt, 1); return (const void*)fetchPayload(pCur, pAmt, 1);
} }
@ -3246,7 +3254,7 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
int rc; int rc;
MemPage *pNewPage; MemPage *pNewPage;
MemPage *pOldPage; MemPage *pOldPage;
BtShared *pBt = pCur->pBtree->pBt; BtShared *pBt = pCur->pBt;
assert( sqlite3BtreeMutexHeld(pBt->mutex) ); assert( sqlite3BtreeMutexHeld(pBt->mutex) );
assert( pCur->eState==CURSOR_VALID ); assert( pCur->eState==CURSOR_VALID );
@ -3298,7 +3306,7 @@ void sqlite3BtreeMoveToParent(BtCursor *pCur){
MemPage *pPage; MemPage *pPage;
int idxParent; int idxParent;
sqlite3BtreeEnter(pCur->pBtree); cursorEnter(pCur);
assert( pCur->eState==CURSOR_VALID ); assert( pCur->eState==CURSOR_VALID );
pPage = pCur->pPage; pPage = pCur->pPage;
assert( pPage!=0 ); assert( pPage!=0 );
@ -3312,7 +3320,7 @@ void sqlite3BtreeMoveToParent(BtCursor *pCur){
pCur->info.nSize = 0; pCur->info.nSize = 0;
assert( pParent->idxShift==0 ); assert( pParent->idxShift==0 );
pCur->idx = idxParent; pCur->idx = idxParent;
sqlite3BtreeLeave(pCur->pBtree); cursorLeave(pCur);
} }
/* /*
@ -3324,7 +3332,6 @@ static int moveToRoot(BtCursor *pCur){
Btree *p = pCur->pBtree; Btree *p = pCur->pBtree;
BtShared *pBt = p->pBt; BtShared *pBt = p->pBt;
assert( sqlite3BtreeMutexHeld(p->pSqlite->mutex) );
assert( sqlite3BtreeMutexHeld(pBt->mutex) ); assert( sqlite3BtreeMutexHeld(pBt->mutex) );
if( pCur->eState==CURSOR_REQUIRESEEK ){ if( pCur->eState==CURSOR_REQUIRESEEK ){
clearCursorPosition(pCur); clearCursorPosition(pCur);
@ -3368,8 +3375,7 @@ static int moveToLeftmost(BtCursor *pCur){
int rc = SQLITE_OK; int rc = SQLITE_OK;
MemPage *pPage; MemPage *pPage;
assert( sqlite3BtreeMutexHeld(pCur->pBtree->pBt->mutex) ); assert( sqlite3BtreeMutexHeld(pCur->pBt->mutex) );
assert( sqlite3BtreeMutexHeld(pCur->pBtree->pSqlite->mutex) );
assert( pCur->eState==CURSOR_VALID ); assert( pCur->eState==CURSOR_VALID );
while( rc==SQLITE_OK && !(pPage = pCur->pPage)->leaf ){ while( rc==SQLITE_OK && !(pPage = pCur->pPage)->leaf ){
assert( pCur->idx>=0 && pCur->idx<pPage->nCell ); assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
@ -3394,8 +3400,7 @@ static int moveToRightmost(BtCursor *pCur){
int rc = SQLITE_OK; int rc = SQLITE_OK;
MemPage *pPage; MemPage *pPage;
assert( sqlite3BtreeMutexHeld(pCur->pBtree->pBt->mutex) ); assert( sqlite3BtreeMutexHeld(pCur->pBt->mutex) );
assert( sqlite3BtreeMutexHeld(pCur->pBtree->pSqlite->mutex) );
assert( pCur->eState==CURSOR_VALID ); assert( pCur->eState==CURSOR_VALID );
while( rc==SQLITE_OK && !(pPage = pCur->pPage)->leaf ){ while( rc==SQLITE_OK && !(pPage = pCur->pPage)->leaf ){
pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]); pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
@ -3416,7 +3421,7 @@ static int moveToRightmost(BtCursor *pCur){
int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
int rc; int rc;
assert( sqlite3BtreeMutexHeld(pCur->pBtree->pBt->mutex) ); assert( sqlite3BtreeMutexHeld(pCur->pBt->mutex) );
assert( sqlite3BtreeMutexHeld(pCur->pBtree->pSqlite->mutex) ); assert( sqlite3BtreeMutexHeld(pCur->pBtree->pSqlite->mutex) );
rc = moveToRoot(pCur); rc = moveToRoot(pCur);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
@ -3440,7 +3445,7 @@ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
int rc; int rc;
assert( sqlite3BtreeMutexHeld(pCur->pBtree->pBt->mutex) ); assert( sqlite3BtreeMutexHeld(pCur->pBt->mutex) );
assert( sqlite3BtreeMutexHeld(pCur->pBtree->pSqlite->mutex) ); assert( sqlite3BtreeMutexHeld(pCur->pBtree->pSqlite->mutex) );
rc = moveToRoot(pCur); rc = moveToRoot(pCur);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
@ -3493,7 +3498,7 @@ int sqlite3BtreeMoveto(
){ ){
int rc; int rc;
assert( sqlite3BtreeMutexHeld(pCur->pBtree->pBt->mutex) ); assert( sqlite3BtreeMutexHeld(pCur->pBt->mutex) );
assert( sqlite3BtreeMutexHeld(pCur->pBtree->pSqlite->mutex) ); assert( sqlite3BtreeMutexHeld(pCur->pBtree->pSqlite->mutex) );
rc = moveToRoot(pCur); rc = moveToRoot(pCur);
if( rc ){ if( rc ){
@ -3621,6 +3626,7 @@ int sqlite3BtreeEof(BtCursor *pCur){
** Return the database connection handle for a cursor. ** Return the database connection handle for a cursor.
*/ */
sqlite3 *sqlite3BtreeCursorDb(const BtCursor *pCur){ sqlite3 *sqlite3BtreeCursorDb(const BtCursor *pCur){
assert( sqlite3_mutex_held(pCur->pBtree->pSqlite->mutex) );
return pCur->pBtree->pSqlite; return pCur->pBtree->pSqlite;
} }
@ -3634,6 +3640,7 @@ static int btreeNext(BtCursor *pCur, int *pRes){
int rc; int rc;
MemPage *pPage; MemPage *pPage;
assert( sqlite3_mutex_held(pCur->pBt->mutex) );
rc = restoreOrClearCursorPosition(pCur); rc = restoreOrClearCursorPosition(pCur);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
@ -3708,6 +3715,7 @@ static int btreePrevious(BtCursor *pCur, int *pRes){
Pgno pgno; Pgno pgno;
MemPage *pPage; MemPage *pPage;
assert( sqlite3_mutex_held(pCur->pBt->mutex) );
rc = restoreOrClearCursorPosition(pCur); rc = restoreOrClearCursorPosition(pCur);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
@ -5486,20 +5494,20 @@ int sqlite3BtreeInsert(
unsigned char *oldCell; unsigned char *oldCell;
unsigned char *newCell = 0; unsigned char *newCell = 0;
sqlite3BtreeEnter(p); cursorEnter(pCur);
if( pBt->inTransaction!=TRANS_WRITE ){ if( pBt->inTransaction!=TRANS_WRITE ){
/* Must start a transaction before doing an insert */ /* Must start a transaction before doing an insert */
rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
sqlite3BtreeLeave(p); cursorLeave(pCur);
return rc; return rc;
} }
assert( !pBt->readOnly ); assert( !pBt->readOnly );
if( !pCur->wrFlag ){ if( !pCur->wrFlag ){
sqlite3BtreeLeave(p); cursorLeave(pCur);
return SQLITE_PERM; /* Cursor not open for writing */ return SQLITE_PERM; /* Cursor not open for writing */
} }
if( checkReadLocks(pCur->pBtree, pCur->pgnoRoot, pCur) ){ if( checkReadLocks(pCur->pBtree, pCur->pgnoRoot, pCur) ){
sqlite3BtreeLeave(p); cursorLeave(pCur);
return SQLITE_LOCKED; /* The table pCur points to has a read lock */ return SQLITE_LOCKED; /* The table pCur points to has a read lock */
} }
@ -5509,7 +5517,7 @@ int sqlite3BtreeInsert(
SQLITE_OK!=(rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur)) || SQLITE_OK!=(rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur)) ||
SQLITE_OK!=(rc = sqlite3BtreeMoveto(pCur, pKey, nKey, appendBias, &loc)) SQLITE_OK!=(rc = sqlite3BtreeMoveto(pCur, pKey, nKey, appendBias, &loc))
){ ){
sqlite3BtreeLeave(p); cursorLeave(pCur);
return rc; return rc;
} }
@ -5558,7 +5566,7 @@ int sqlite3BtreeInsert(
} }
end_insert: end_insert:
sqlite3_free(newCell); sqlite3_free(newCell);
sqlite3BtreeLeave(p); cursorLeave(pCur);
return rc; return rc;
} }
@ -5574,25 +5582,25 @@ int sqlite3BtreeDelete(BtCursor *pCur){
Btree *p = pCur->pBtree; Btree *p = pCur->pBtree;
BtShared *pBt = p->pBt; BtShared *pBt = p->pBt;
sqlite3BtreeEnter(p); cursorEnter(pCur);
assert( pPage->isInit ); assert( pPage->isInit );
if( pBt->inTransaction!=TRANS_WRITE ){ if( pBt->inTransaction!=TRANS_WRITE ){
/* Must start a transaction before doing a delete */ /* Must start a transaction before doing a delete */
rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
sqlite3BtreeLeave(p); cursorLeave(pCur);
return rc; return rc;
} }
assert( !pBt->readOnly ); assert( !pBt->readOnly );
if( pCur->idx >= pPage->nCell ){ if( pCur->idx >= pPage->nCell ){
sqlite3BtreeLeave(p); cursorLeave(pCur);
return SQLITE_ERROR; /* The cursor is not pointing to anything */ return SQLITE_ERROR; /* The cursor is not pointing to anything */
} }
if( !pCur->wrFlag ){ if( !pCur->wrFlag ){
sqlite3BtreeLeave(p); cursorLeave(pCur);
return SQLITE_PERM; /* Did not open this cursor for writing */ return SQLITE_PERM; /* Did not open this cursor for writing */
} }
if( checkReadLocks(pCur->pBtree, pCur->pgnoRoot, pCur) ){ if( checkReadLocks(pCur->pBtree, pCur->pgnoRoot, pCur) ){
sqlite3BtreeLeave(p); cursorLeave(pCur);
return SQLITE_LOCKED; /* The table pCur points to has a read lock */ return SQLITE_LOCKED; /* The table pCur points to has a read lock */
} }
@ -5606,7 +5614,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
(rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur))!=0 || (rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur))!=0 ||
(rc = sqlite3PagerWrite(pPage->pDbPage))!=0 (rc = sqlite3PagerWrite(pPage->pDbPage))!=0
){ ){
sqlite3BtreeLeave(p); cursorLeave(pCur);
return rc; return rc;
} }
@ -5620,7 +5628,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
} }
rc = clearCell(pPage, pCell); rc = clearCell(pPage, pCell);
if( rc ){ if( rc ){
sqlite3BtreeLeave(p); cursorLeave(pCur);
return rc; return rc;
} }
@ -5679,7 +5687,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
moveToRoot(pCur); moveToRoot(pCur);
} }
sqlite3BtreeLeave(p); cursorLeave(pCur);
return rc; return rc;
} }
@ -5700,6 +5708,8 @@ static int btreeCreateTable(Btree *p, int *piTable, int flags){
Pgno pgnoRoot; Pgno pgnoRoot;
int rc; int rc;
assert( sqlite3_mutex_held(p->pSqlite->mutex) );
assert( sqlite3_mutex_held(pBt->mutex) );
if( pBt->inTransaction!=TRANS_WRITE ){ if( pBt->inTransaction!=TRANS_WRITE ){
/* Must start a transaction first */ /* Must start a transaction first */
rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
@ -6131,6 +6141,7 @@ int sqlite3BtreeFlags(BtCursor *pCur){
*/ */
MemPage *pPage = pCur->pPage; MemPage *pPage = pCur->pPage;
assert( sqlite3BtreeMutexHeld(pPage->pBt->mutex) ); assert( sqlite3BtreeMutexHeld(pPage->pBt->mutex) );
assert( pPage->pBt==pCur->pBt );
return pPage ? pPage->aData[pPage->hdrOffset] : 0; return pPage ? pPage->aData[pPage->hdrOffset] : 0;
} }
@ -6140,8 +6151,6 @@ int sqlite3BtreeFlags(BtCursor *pCur){
** testing and debugging only. ** testing and debugging only.
*/ */
Pager *sqlite3BtreePager(Btree *p){ Pager *sqlite3BtreePager(Btree *p){
assert( sqlite3BtreeMutexHeld(p->pSqlite->mutex) );
assert( sqlite3BtreeMutexHeld(p->pBt->mutex) );
return p->pBt->pPager; return p->pBt->pPager;
} }
@ -6585,17 +6594,25 @@ char *sqlite3BtreeIntegrityCheck(
/* /*
** Return the full pathname of the underlying database file. ** Return the full pathname of the underlying database file.
**
** The pager filename is invariant as long as the pager is
** open so it is safe to access without the BtShared mutex.
*/ */
const char *sqlite3BtreeGetFilename(Btree *p){ const char *sqlite3BtreeGetFilename(Btree *p){
assert( p->pBt->pPager!=0 ); assert( p->pBt->pPager!=0 );
assert( sqlite3_mutex_held(p->pSqlite->mutex) );
return sqlite3PagerFilename(p->pBt->pPager); return sqlite3PagerFilename(p->pBt->pPager);
} }
/* /*
** Return the pathname of the directory that contains the database file. ** Return the pathname of the directory that contains the database file.
**
** The pager directory name is invariant as long as the pager is
** open so it is safe to access without the BtShared mutex.
*/ */
const char *sqlite3BtreeGetDirname(Btree *p){ const char *sqlite3BtreeGetDirname(Btree *p){
assert( p->pBt->pPager!=0 ); assert( p->pBt->pPager!=0 );
assert( sqlite3_mutex_held(p->pSqlite->mutex) );
return sqlite3PagerDirname(p->pBt->pPager); return sqlite3PagerDirname(p->pBt->pPager);
} }
@ -6603,9 +6620,13 @@ const char *sqlite3BtreeGetDirname(Btree *p){
** Return the pathname of the journal file for this database. The return ** Return the pathname of the journal file for this database. The return
** value of this routine is the same regardless of whether the journal file ** value of this routine is the same regardless of whether the journal file
** has been created or not. ** has been created or not.
**
** The pager journal filename is invariant as long as the pager is
** open so it is safe to access without the BtShared mutex.
*/ */
const char *sqlite3BtreeGetJournalname(Btree *p){ const char *sqlite3BtreeGetJournalname(Btree *p){
assert( p->pBt->pPager!=0 ); assert( p->pBt->pPager!=0 );
assert( sqlite3_mutex_held(p->pSqlite->mutex) );
return sqlite3PagerJournalname(p->pBt->pPager); return sqlite3PagerJournalname(p->pBt->pPager);
} }
@ -6685,7 +6706,7 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
** Return non-zero if a transaction is active. ** Return non-zero if a transaction is active.
*/ */
int sqlite3BtreeIsInTrans(Btree *p){ int sqlite3BtreeIsInTrans(Btree *p){
assert( sqlite3BtreeMutexHeld(p->pSqlite->mutex) ); assert( p==0 || sqlite3BtreeMutexHeld(p->pSqlite->mutex) );
return (p && (p->inTrans==TRANS_WRITE)); return (p && (p->inTrans==TRANS_WRITE));
} }
@ -6724,7 +6745,6 @@ int sqlite3BtreeIsInReadTrans(Btree *p){
*/ */
void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){ void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){
BtShared *pBt = p->pBt; BtShared *pBt = p->pBt;
assert( sqlite3BtreeMutexHeld(p->pSqlite->mutex) );
sqlite3BtreeEnter(p); sqlite3BtreeEnter(p);
if( !pBt->pSchema ){ if( !pBt->pSchema ){
pBt->pSchema = sqlite3MallocZero(nBytes); pBt->pSchema = sqlite3MallocZero(nBytes);
@ -6776,7 +6796,7 @@ int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){
** to change the length of the data stored. ** to change the length of the data stored.
*/ */
int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
assert( sqlite3BtreeMutexHeld(pCsr->pBtree->pBt->mutex) ); assert( sqlite3BtreeMutexHeld(pCsr->pBt->mutex) );
assert( sqlite3BtreeMutexHeld(pCsr->pBtree->pSqlite->mutex) ); assert( sqlite3BtreeMutexHeld(pCsr->pBtree->pSqlite->mutex) );
assert(pCsr->isIncrblobHandle); assert(pCsr->isIncrblobHandle);
if( pCsr->eState==CURSOR_REQUIRESEEK ){ if( pCsr->eState==CURSOR_REQUIRESEEK ){
@ -6791,8 +6811,8 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
if( !pCsr->wrFlag ){ if( !pCsr->wrFlag ){
return SQLITE_READONLY; return SQLITE_READONLY;
} }
assert( !pCsr->pBtree->pBt->readOnly assert( !pCsr->pBt->readOnly
&& pCsr->pBtree->pBt->inTransaction==TRANS_WRITE ); && pCsr->pBt->inTransaction==TRANS_WRITE );
if( checkReadLocks(pCsr->pBtree, pCsr->pgnoRoot, pCsr) ){ if( checkReadLocks(pCsr->pBtree, pCsr->pgnoRoot, pCsr) ){
return SQLITE_LOCKED; /* The table pCur points to has a read lock */ return SQLITE_LOCKED; /* The table pCur points to has a read lock */
} }
@ -6814,7 +6834,7 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
** sqlite3BtreePutData()). ** sqlite3BtreePutData()).
*/ */
void sqlite3BtreeCacheOverflow(BtCursor *pCur){ void sqlite3BtreeCacheOverflow(BtCursor *pCur){
assert( sqlite3BtreeMutexHeld(pCur->pBtree->pBt->mutex) ); assert( sqlite3BtreeMutexHeld(pCur->pBt->mutex) );
assert( sqlite3BtreeMutexHeld(pCur->pBtree->pSqlite->mutex) ); assert( sqlite3BtreeMutexHeld(pCur->pBtree->pSqlite->mutex) );
assert(!pCur->isIncrblobHandle); assert(!pCur->isIncrblobHandle);
assert(!pCur->aOverflow); assert(!pCur->aOverflow);

View File

@ -9,7 +9,7 @@
** May you share freely, never taking more than you give. ** May you share freely, never taking more than you give.
** **
************************************************************************* *************************************************************************
** $Id: btreeInt.h,v 1.10 2007/08/27 21:49:34 drh Exp $ ** $Id: btreeInt.h,v 1.11 2007/08/28 22:24:35 drh Exp $
** **
** This file implements a external (disk-based) database using BTrees. ** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to ** For a detailed discussion of BTrees, refer to
@ -318,7 +318,11 @@ struct MemPage {
** schema associated with the database file are all contained within ** schema associated with the database file are all contained within
** the BtShared object. ** the BtShared object.
** **
** All fields in this structure are accessed under the sqlite3.mutex. ** All fields in this structure are accessed under sqlite3.mutex.
** The pBt pointer itself may not be changed while there exists cursors
** in the referenced BtShared that point back to this Btree since those
** cursors have to do go through this Btree to find their BtShared and
** they often do so without holding sqlite3.mutex.
*/ */
struct Btree { struct Btree {
sqlite3 *pSqlite; /* The database connection holding this btree */ sqlite3 *pSqlite; /* The database connection holding this btree */
@ -419,11 +423,11 @@ struct CellInfo {
** particular database connection identified BtCursor.pBtree.pSqlite. ** particular database connection identified BtCursor.pBtree.pSqlite.
** **
** Fields in this structure are accessed under the BtShared.mutex ** Fields in this structure are accessed under the BtShared.mutex
** mutex. The pBtree field is safe to access under the ** found at self->pBt->mutex.
** BtShared->pBtree->pSqlite->mutex mutex.
*/ */
struct BtCursor { struct BtCursor {
Btree *pBtree; /* The Btree to which this cursor belongs */ Btree *pBtree; /* The Btree to which this cursor belongs */
BtShared *pBt; /* The BtShared this cursor points to */
BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */ BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
int (*xCompare)(void*,int,const void*,int,const void*); /* Key comp func */ int (*xCompare)(void*,int,const void*,int,const void*); /* Key comp func */
void *pArg; /* First arg to xCompare() */ void *pArg; /* First arg to xCompare() */

View File

@ -22,7 +22,7 @@
** COMMIT ** COMMIT
** ROLLBACK ** ROLLBACK
** **
** $Id: build.c,v 1.439 2007/08/28 02:27:52 drh Exp $ ** $Id: build.c,v 1.440 2007/08/28 22:24:35 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@ -164,7 +164,7 @@ void sqlite3FinishCoding(Parse *pParse){
sqlite3VdbeJumpHere(v, pParse->cookieGoto-1); sqlite3VdbeJumpHere(v, pParse->cookieGoto-1);
for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){ for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
if( (mask & pParse->cookieMask)==0 ) continue; if( (mask & pParse->cookieMask)==0 ) continue;
sqlite3VdbeAddMutexBtree(v, db->aDb[iDb].pBt); sqlite3VdbeUsesBtree(v, iDb, db->aDb[iDb].pBt);
sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0); sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, pParse->cookieValue[iDb]); sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, pParse->cookieValue[iDb]);
} }

View File

@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** This file contains the C functions that implement mutexes for pthreads ** This file contains the C functions that implement mutexes for pthreads
** **
** $Id: mutex_unix.c,v 1.1 2007/08/28 16:34:43 drh Exp $ ** $Id: mutex_unix.c,v 1.2 2007/08/28 22:24:35 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -34,6 +34,9 @@ struct sqlite3_mutex {
int id; /* Mutex type */ int id; /* Mutex type */
int nRef; /* Number of entrances */ int nRef; /* Number of entrances */
pthread_t owner; /* Thread that is within this mutex */ pthread_t owner; /* Thread that is within this mutex */
#ifdef SQLITE_DEBUG
int trace; /* True to trace changes */
#endif
}; };
/* /*
@ -149,6 +152,11 @@ void sqlite3_mutex_enter(sqlite3_mutex *p){
pthread_mutex_lock(&p->mutex); pthread_mutex_lock(&p->mutex);
p->owner = pthread_self(); p->owner = pthread_self();
p->nRef++; p->nRef++;
#ifdef SQLITE_DEBUG
if( p->trace ){
printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
}
#endif
} }
int sqlite3_mutex_try(sqlite3_mutex *p){ int sqlite3_mutex_try(sqlite3_mutex *p){
int rc; int rc;
@ -158,6 +166,11 @@ int sqlite3_mutex_try(sqlite3_mutex *p){
p->owner = pthread_self(); p->owner = pthread_self();
p->nRef++; p->nRef++;
rc = SQLITE_OK; rc = SQLITE_OK;
#ifdef SQLITE_DEBUG
if( p->trace ){
printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
}
#endif
}else{ }else{
rc = SQLITE_BUSY; rc = SQLITE_BUSY;
} }
@ -175,6 +188,11 @@ void sqlite3_mutex_leave(sqlite3_mutex *p){
assert( sqlite3_mutex_held(p) ); assert( sqlite3_mutex_held(p) );
p->nRef--; p->nRef--;
assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE ); assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
#ifdef SQLITE_DEBUG
if( p->trace ){
printf("leave mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
}
#endif
pthread_mutex_unlock(&p->mutex); pthread_mutex_unlock(&p->mutex);
} }

View File

@ -18,7 +18,7 @@
** file simultaneously, or one process from reading the database while ** file simultaneously, or one process from reading the database while
** another is writing. ** another is writing.
** **
** @(#) $Id: pager.c,v 1.378 2007/08/28 08:00:18 danielk1977 Exp $ ** @(#) $Id: pager.c,v 1.379 2007/08/28 22:24:35 drh Exp $
*/ */
#ifndef SQLITE_OMIT_DISKIO #ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h" #include "sqliteInt.h"
@ -4796,6 +4796,13 @@ const char *sqlite3PagerFilename(Pager *pPager){
return pPager->zFilename; return pPager->zFilename;
} }
/*
** Return the VFS structure for the pager.
*/
const sqlite3_vfs *sqlite3PagerVfs(Pager *pPager){
return pPager->pVfs;
}
/* /*
** Return the directory of the database file. ** Return the directory of the database file.
*/ */

View File

@ -13,7 +13,7 @@
** subsystem. The page cache subsystem reads and writes a file a page ** subsystem. The page cache subsystem reads and writes a file a page
** at a time and provides a journal for rollback. ** at a time and provides a journal for rollback.
** **
** @(#) $Id: pager.h,v 1.62 2007/08/17 15:53:37 danielk1977 Exp $ ** @(#) $Id: pager.h,v 1.63 2007/08/28 22:24:35 drh Exp $
*/ */
#ifndef _PAGER_H_ #ifndef _PAGER_H_
@ -85,6 +85,7 @@ void sqlite3PagerDontWrite(DbPage*);
int sqlite3PagerRefcount(Pager*); int sqlite3PagerRefcount(Pager*);
void sqlite3PagerSetSafetyLevel(Pager*,int,int); void sqlite3PagerSetSafetyLevel(Pager*,int,int);
const char *sqlite3PagerFilename(Pager*); const char *sqlite3PagerFilename(Pager*);
const sqlite3_vfs *sqlite3PagerVfs(Pager*);
const char *sqlite3PagerDirname(Pager*); const char *sqlite3PagerDirname(Pager*);
const char *sqlite3PagerJournalname(Pager*); const char *sqlite3PagerJournalname(Pager*);
int sqlite3PagerNosync(Pager*); int sqlite3PagerNosync(Pager*);

View File

@ -15,7 +15,7 @@
** or VDBE. The VDBE implements an abstract machine that runs a ** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database. ** simple program to access and modify the underlying database.
** **
** $Id: vdbe.h,v 1.111 2007/08/28 02:27:52 drh Exp $ ** $Id: vdbe.h,v 1.112 2007/08/28 22:24:35 drh Exp $
*/ */
#ifndef _SQLITE_VDBE_H_ #ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_
@ -120,7 +120,7 @@ void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
void sqlite3VdbeJumpHere(Vdbe*, int addr); void sqlite3VdbeJumpHere(Vdbe*, int addr);
void sqlite3VdbeChangeToNoop(Vdbe*, int addr, int N); void sqlite3VdbeChangeToNoop(Vdbe*, int addr, int N);
void sqlite3VdbeChangeP3(Vdbe*, int addr, const char *zP1, int N); void sqlite3VdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
void sqlite3VdbeAddMutexBtree(Vdbe*, Btree*); void sqlite3VdbeUsesBtree(Vdbe*, int, Btree*);
VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
int sqlite3VdbeMakeLabel(Vdbe*); int sqlite3VdbeMakeLabel(Vdbe*);
void sqlite3VdbeDelete(Vdbe*); void sqlite3VdbeDelete(Vdbe*);

View File

@ -332,6 +332,7 @@ struct Vdbe {
u8 inVtabMethod; /* See comments above */ u8 inVtabMethod; /* See comments above */
int nChange; /* Number of db changes made since last reset */ int nChange; /* Number of db changes made since last reset */
i64 startTime; /* Time when query started - used for profiling */ i64 startTime; /* Time when query started - used for profiling */
int btreeMask; /* Bitmask of db->aDb[] entries referenced */
BtreeMutexSet mtxSet; /* Set of Btree mutexes */ BtreeMutexSet mtxSet; /* Set of Btree mutexes */
int nSql; /* Number of bytes in zSql */ int nSql; /* Number of bytes in zSql */
char *zSql; /* Text of the SQL statement that generated this */ char *zSql; /* Text of the SQL statement that generated this */

View File

@ -659,9 +659,14 @@ static char *displayP3(Op *pOp, char *zTemp, int nTemp){
#endif #endif
/* /*
** Add a btree to the set of btrees that might need a mutex. ** Declare to the Vdbe that the BTree object at db->aDb[i] is used.
**
*/ */
void sqlite3VdbeAddMutexBtree(Vdbe *p, Btree *pBtree){ void sqlite3VdbeUsesBtree(Vdbe *p, int i, Btree *pBtree){
assert( i>=0 && i<p->db->nDb );
assert( i<sizeof(p->btreeMask)*8 );
assert( p->db->aDb[i].pBt==pBtree );
p->btreeMask |= 1<<i;
sqlite3BtreeMutexSetInsert(&p->mtxSet, pBtree); sqlite3BtreeMutexSetInsert(&p->mtxSet, pBtree);
} }
@ -1091,7 +1096,7 @@ static int vdbeCommit(sqlite3 *db){
*/ */
for(i=0; i<db->nDb; i++){ for(i=0; i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt; Btree *pBt = db->aDb[i].pBt;
if( pBt && sqlite3BtreeIsInTrans(pBt) ){ if( sqlite3BtreeIsInTrans(pBt) ){
needXcommit = 1; needXcommit = 1;
if( i!=1 ) nTrans++; if( i!=1 ) nTrans++;
} }
@ -1183,7 +1188,7 @@ static int vdbeCommit(sqlite3 *db){
for(i=0; i<db->nDb; i++){ for(i=0; i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt; Btree *pBt = db->aDb[i].pBt;
if( i==1 ) continue; /* Ignore the TEMP database */ if( i==1 ) continue; /* Ignore the TEMP database */
if( pBt && sqlite3BtreeIsInTrans(pBt) ){ if( sqlite3BtreeIsInTrans(pBt) ){
char const *zFile = sqlite3BtreeGetJournalname(pBt); char const *zFile = sqlite3BtreeGetJournalname(pBt);
if( zFile[0]==0 ) continue; /* Ignore :memory: databases */ if( zFile[0]==0 ) continue; /* Ignore :memory: databases */
if( !needSync && !sqlite3BtreeSyncDisabled(pBt) ){ if( !needSync && !sqlite3BtreeSyncDisabled(pBt) ){
@ -1225,7 +1230,7 @@ static int vdbeCommit(sqlite3 *db){
*/ */
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt; Btree *pBt = db->aDb[i].pBt;
if( pBt && sqlite3BtreeIsInTrans(pBt) ){ if( pBt ){
rc = sqlite3BtreeCommitPhaseOne(pBt, zMaster); rc = sqlite3BtreeCommitPhaseOne(pBt, zMaster);
} }
} }

View File

@ -13,7 +13,7 @@
# cache context. What happens to connection B if one connection A encounters # cache context. What happens to connection B if one connection A encounters
# an IO-error whilst reading or writing the file-system? # an IO-error whilst reading or writing the file-system?
# #
# $Id: shared_err.test,v 1.12 2007/08/25 13:37:49 danielk1977 Exp $ # $Id: shared_err.test,v 1.13 2007/08/28 22:24:35 drh Exp $
proc skip {args} {} proc skip {args} {}
@ -156,6 +156,7 @@ do_ioerr_test shared_ioerr-3 -tclprep {
sqlite3_step $::STMT ;# Cursor points at 001.001.001.001 sqlite3_step $::STMT ;# Cursor points at 001.001.001.001
} -tclbody { } -tclbody {
btree_breakpoint
execsql { execsql {
BEGIN; BEGIN;
INSERT INTO t1 VALUES('201.201.201.201.201', NULL); INSERT INTO t1 VALUES('201.201.201.201.201', NULL);