From e5fe690d75d9b98e91428d949deb7e53622b1010 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 7 Dec 2007 18:55:28 +0000 Subject: [PATCH] In shared-cache mode, make sure the busy hander invoked is the busy handler associated with the database connection that caused the lock contention in the first place. (CVS 4598) FossilOrigin-Name: c9eb65912f61ce0a6b66fe253652a1827e46b12a --- manifest | 26 +++++------ manifest.uuid | 2 +- src/btmutex.c | 12 ++--- src/btree.c | 114 ++++++++++++++++++++++++++++-------------------- src/btree.h | 3 +- src/btreeInt.h | 15 ++++--- src/main.c | 3 +- src/pager.c | 6 ++- src/sqliteInt.h | 4 +- src/test3.c | 10 ++--- 10 files changed, 110 insertions(+), 85 deletions(-) diff --git a/manifest b/manifest index eb084eb06c..ee238a3dae 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Get\sthe\sLIKE\sand\sGLOB\soperators\sworking\sagain\son\ssystems\susing\sthe\nEBCDIC\scharacter\sset.\s(CVS\s4597) -D 2007-12-07T18:39:05 +C In\sshared-cache\smode,\smake\ssure\sthe\sbusy\shander\sinvoked\sis\sthe\nbusy\shandler\sassociated\swith\sthe\sdatabase\sconnection\sthat\scaused\nthe\slock\scontention\sin\sthe\sfirst\splace.\s(CVS\s4598) +D 2007-12-07T18:55:28 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7 F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -82,10 +82,10 @@ F src/alter.c 8512ed319aa5f7b9bbbd4e17953809e3ff398fdd F src/analyze.c fd1a3d756c1a20fca3c505bed0398f4cdca83cb8 F src/attach.c a01d55157d46a1234909f3a7f21fb09549c947bd F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627 -F src/btmutex.c 442be6f068d77ca9ffd69899cf0a3943c244548c -F src/btree.c c5844bb4bbe997a7c8400a714fcf304d91855383 -F src/btree.h d0736ebca4b6eafbdd823c46a8de574cea078211 -F src/btreeInt.h 4330c19b8314545fdb209cc77e2a57f6a5290e9c +F src/btmutex.c 5d39da37c9d1282f3c6f9967afae6a34ee36b7ff +F src/btree.c 45c65b60efb1eb20edcda08cecbd15279c9e220c +F src/btree.h 19dcf5ad23c17b98855da548e9a8e3eb4429d5eb +F src/btreeInt.h 68ec997e34e426093f706da965c147ece75185b9 F src/build.c 580561a0d9e070ff2741f3b115cae51c1ef08260 F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0 F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131 @@ -101,7 +101,7 @@ F src/journal.c 807bed7a158979ac8d63953e1774e8d85bff65e2 F src/legacy.c 4ac53191fad2e3c4d59bde1228879b2dc5a96d66 F src/limits.h 71ab25f17e35e0a9f3f6f234b8ed49cc56731d35 F src/loadext.c 124e566563d1c03e68e1396cb44df9870612c6e9 -F src/main.c 53e71b4d4a0dbc1eb3a73520970973689cabea18 +F src/main.c bdeb906fb112ff60f3612d4fd91abba05ae6d397 F src/malloc.c 60e392a4c12c839517f9b0db7b995f825444fb35 F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217 F src/mem1.c 6d1a11864963d249c67e72ad5f6533b040333880 @@ -124,7 +124,7 @@ F src/os_unix.c 10641ed959b960915deaf2d053105e1ee9849d88 F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e F src/os_win.c a92769a7ec45ff908ca5e83553c8582215bb58c5 F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b -F src/pager.c 65298fee4e815c269fb374d3fe3cd1cf4f05ad94 +F src/pager.c 2f420d4605159f3a3cd06c70c927cb00a731affa F src/pager.h f504f7ae84060fee0416a853e368d3d113c3d6fa F src/parse.y a780b33ef45dd7b3272319cf91e609d6f109a31c F src/pragma.c 0246032dbe681dded8710ac43eaf654eead1434e @@ -136,13 +136,13 @@ F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/shell.c c97be281cfc3dcb14902f45e4b16f20038eb83ff F src/sqlite.h.in 544587c10005dde0ad8f132dd9b7816b132b2bea F src/sqlite3ext.h a93f59cdee3638dc0c9c086f80df743a4e68c3cb -F src/sqliteInt.h a941ccf797b45c27bc0face4e75935b5cc019202 +F src/sqliteInt.h 5c86734aaecc6c498c1ed0497935f3f1d3c2f842 F src/sqliteLimit.h 15ffe2116746c27ace2b428a26a4fcd6dba6fa65 F src/table.c 1aeb9eab57b4235db86fe15a35dec76fb445a9c4 F src/tclsqlite.c 9923abeffc9b3d7dad58e92b319661521f60debf F src/test1.c ba01f4b8bb742ec5869167bbc87491eaafb7da3f F src/test2.c 77b34303883b9d722c65a6879bb0163a400e3789 -F src/test3.c 73c1fd55d1ece61f295a6b9204fd97a139de86ae +F src/test3.c df62cd5c971dc1ae0be0a1842f9df3390934e7a6 F src/test4.c c2c0f5dc907f1346f5d4b65eb5799f11eb9e4071 F src/test5.c 3a6a5717a149d7ca2e6d14f5be72cf7555d54dc4 F src/test6.c a9fc983d32d6f262eab300d742e49ff239b0bdbd @@ -597,7 +597,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P f29deb5f0bfcd6d00795aeb66dece717a6c1768a -R 914411460f2d77a89cfca0420655917f +P 754298a74e3d889f3767daba058262613d20a601 +R 0ae36f66eb071af9c23c05039a009307 U drh -Z dab0e24c447ca0aa1c74119b9b014915 +Z 974b15de4ea104f24852fc03b178d3ac diff --git a/manifest.uuid b/manifest.uuid index be5d794c22..97615b565b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -754298a74e3d889f3767daba058262613d20a601 \ No newline at end of file +c9eb65912f61ce0a6b66fe253652a1827e46b12a \ No newline at end of file diff --git a/src/btmutex.c b/src/btmutex.c index 1f63434231..36c22e8cf8 100644 --- a/src/btmutex.c +++ b/src/btmutex.c @@ -10,7 +10,7 @@ ** ************************************************************************* ** -** $Id: btmutex.c,v 1.7 2007/08/30 01:19:59 drh Exp $ +** $Id: btmutex.c,v 1.8 2007/12/07 18:55:28 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 @@ -46,8 +46,8 @@ void sqlite3BtreeEnter(Btree *p){ ** the same connection. Only shared Btrees are on the list. */ assert( p->pNext==0 || p->pNext->pBt>p->pBt ); assert( p->pPrev==0 || p->pPrev->pBtpBt ); - assert( p->pNext==0 || p->pNext->pSqlite==p->pSqlite ); - assert( p->pPrev==0 || p->pPrev->pSqlite==p->pSqlite ); + assert( p->pNext==0 || p->pNext->db==p->db ); + assert( p->pPrev==0 || p->pPrev->db==p->db ); assert( p->sharable || (p->pNext==0 && p->pPrev==0) ); /* Check for locking consistency */ @@ -55,7 +55,7 @@ void sqlite3BtreeEnter(Btree *p){ assert( p->sharable || p->wantToLock==0 ); /* We should already hold a lock on the database connection */ - assert( sqlite3_mutex_held(p->pSqlite->mutex) ); + assert( sqlite3_mutex_held(p->db->mutex) ); if( !p->sharable ) return; p->wantToLock++; @@ -278,7 +278,7 @@ void sqlite3BtreeMutexArrayEnter(BtreeMutexArray *pArray){ assert( !p->locked || p->wantToLock>0 ); /* We should already hold a lock on the database connection */ - assert( sqlite3_mutex_held(p->pSqlite->mutex) ); + assert( sqlite3_mutex_held(p->db->mutex) ); p->wantToLock++; if( !p->locked && p->sharable ){ @@ -301,7 +301,7 @@ void sqlite3BtreeMutexArrayLeave(BtreeMutexArray *pArray){ assert( p->wantToLock>0 ); /* We should already hold a lock on the database connection */ - assert( sqlite3_mutex_held(p->pSqlite->mutex) ); + assert( sqlite3_mutex_held(p->db->mutex) ); p->wantToLock--; if( p->wantToLock==0 && p->locked ){ diff --git a/src/btree.c b/src/btree.c index 97421063ac..b1e6f85111 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.431 2007/11/28 16:19:56 drh Exp $ +** $Id: btree.c,v 1.432 2007/12/07 18:55:28 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. @@ -118,8 +118,8 @@ static int queryTableLock(Btree *p, Pgno iTab, u8 eLock){ ** write-cursor does not change. */ if( - !p->pSqlite || - 0==(p->pSqlite->flags&SQLITE_ReadUncommitted) || + !p->db || + 0==(p->db->flags&SQLITE_ReadUncommitted) || eLock==WRITE_LOCK || iTab==MASTER_ROOT ){ @@ -163,8 +163,8 @@ static int lockTable(Btree *p, Pgno iTable, u8 eLock){ ** the ReadUncommitted flag. */ if( - (p->pSqlite) && - (p->pSqlite->flags&SQLITE_ReadUncommitted) && + (p->db) && + (p->db->flags&SQLITE_ReadUncommitted) && (eLock==READ_LOCK) && iTable!=MASTER_ROOT ){ @@ -1098,6 +1098,16 @@ static void pageReinit(DbPage *pData, int pageSize){ } } +/* +** Invoke the busy handler for a btree. +*/ +static int sqlite3BtreeInvokeBusyHandler(void *pArg, int n){ + BtShared *pBt = (BtShared*)pArg; + assert( pBt->db ); + assert( sqlite3_mutex_held(pBt->db->mutex) ); + return sqlite3InvokeBusyHandler(&pBt->db->busyHandler); +} + /* ** Open a database file. ** @@ -1109,7 +1119,7 @@ static void pageReinit(DbPage *pData, int pageSize){ */ int sqlite3BtreeOpen( const char *zFilename, /* Name of the file containing the BTree database */ - sqlite3 *pSqlite, /* Associated database handle */ + sqlite3 *db, /* Associated database handle */ Btree **ppBtree, /* Pointer to new Btree object written here */ int flags, /* Options */ int vfsFlags /* Flags passed through to sqlite3_vfs.xOpen() */ @@ -1134,16 +1144,16 @@ int sqlite3BtreeOpen( #endif #endif - assert( pSqlite!=0 ); - assert( sqlite3_mutex_held(pSqlite->mutex) ); + assert( db!=0 ); + assert( sqlite3_mutex_held(db->mutex) ); - pVfs = pSqlite->pVfs; + pVfs = db->pVfs; p = sqlite3MallocZero(sizeof(Btree)); if( !p ){ return SQLITE_NOMEM; } p->inTrans = TRANS_NONE; - p->pSqlite = pSqlite; + p->db = db; #if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) /* @@ -1152,7 +1162,7 @@ int sqlite3BtreeOpen( */ if( (flags & BTREE_PRIVATE)==0 && isMemdb==0 - && (pSqlite->flags & SQLITE_Vtab)==0 + && (db->flags & SQLITE_Vtab)==0 && zFilename && zFilename[0] ){ if( sqlite3SharedCacheEnabled ){ @@ -1160,8 +1170,8 @@ int sqlite3BtreeOpen( char *zFullPathname = (char *)sqlite3_malloc(nFullPathname); sqlite3_mutex *mutexShared; p->sharable = 1; - if( pSqlite ){ - pSqlite->flags |= SQLITE_SharedCache; + if( db ){ + db->flags |= SQLITE_SharedCache; } if( !zFullPathname ){ sqlite3_free(p); @@ -1211,6 +1221,8 @@ int sqlite3BtreeOpen( rc = SQLITE_NOMEM; goto btree_open_out; } + pBt->busyHdr.xFunc = sqlite3BtreeInvokeBusyHandler; + pBt->busyHdr.pArg = pBt; rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename, EXTRA_SIZE, flags, vfsFlags); if( rc==SQLITE_OK ){ @@ -1219,6 +1231,7 @@ int sqlite3BtreeOpen( if( rc!=SQLITE_OK ){ goto btree_open_out; } + sqlite3PagerSetBusyhandler(pBt->pPager, &pBt->busyHdr); p->pBt = pBt; sqlite3PagerSetDestructor(pBt->pPager, pageDestructor); @@ -1273,7 +1286,7 @@ int sqlite3BtreeOpen( pBt->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); if( pBt->mutex==0 ){ rc = SQLITE_NOMEM; - pSqlite->mallocFailed = 0; + db->mallocFailed = 0; goto btree_open_out; } } @@ -1293,8 +1306,8 @@ int sqlite3BtreeOpen( if( p->sharable ){ int i; Btree *pSib; - for(i=0; inDb; i++){ - if( (pSib = pSqlite->aDb[i].pBt)!=0 && pSib->sharable ){ + for(i=0; inDb; i++){ + if( (pSib = db->aDb[i].pBt)!=0 && pSib->sharable ){ while( pSib->pPrev ){ pSib = pSib->pPrev; } if( p->pBtpBt ){ p->pNext = pSib; @@ -1378,8 +1391,9 @@ int sqlite3BtreeClose(Btree *p){ BtCursor *pCur; /* Close all cursors opened via this handle. */ - assert( sqlite3_mutex_held(p->pSqlite->mutex) ); + assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); + pBt->db = p->db; pCur = pBt->pCursor; while( pCur ){ BtCursor *pTmp = pCur; @@ -1427,19 +1441,6 @@ int sqlite3BtreeClose(Btree *p){ return SQLITE_OK; } -/* -** Change the busy handler callback function. -*/ -int sqlite3BtreeSetBusyHandler(Btree *p, BusyHandler *pHandler){ - BtShared *pBt = p->pBt; - assert( sqlite3_mutex_held(p->pSqlite->mutex) ); - sqlite3BtreeEnter(p); - pBt->pBusyHandler = pHandler; - sqlite3PagerSetBusyhandler(pBt->pPager, pHandler); - sqlite3BtreeLeave(p); - return SQLITE_OK; -} - /* ** Change the limit on the number of pages allowed in the cache. ** @@ -1457,7 +1458,7 @@ int sqlite3BtreeSetBusyHandler(Btree *p, BusyHandler *pHandler){ */ int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){ BtShared *pBt = p->pBt; - assert( sqlite3_mutex_held(p->pSqlite->mutex) ); + assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); sqlite3PagerSetCachesize(pBt->pPager, mxPage); sqlite3BtreeLeave(p); @@ -1475,7 +1476,7 @@ int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){ #ifndef SQLITE_OMIT_PAGER_PRAGMAS int sqlite3BtreeSetSafetyLevel(Btree *p, int level, int fullSync){ BtShared *pBt = p->pBt; - assert( sqlite3_mutex_held(p->pSqlite->mutex) ); + assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); sqlite3PagerSetSafetyLevel(pBt->pPager, level, fullSync); sqlite3BtreeLeave(p); @@ -1490,7 +1491,7 @@ int sqlite3BtreeSetSafetyLevel(Btree *p, int level, int fullSync){ int sqlite3BtreeSyncDisabled(Btree *p){ BtShared *pBt = p->pBt; int rc; - assert( sqlite3_mutex_held(p->pSqlite->mutex) ); + assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); assert( pBt && pBt->pPager ); rc = sqlite3PagerNosync(pBt->pPager); @@ -1823,6 +1824,7 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ int rc = SQLITE_OK; sqlite3BtreeEnter(p); + pBt->db = p->db; btreeIntegrity(p); /* If the btree is already in a write-transaction, or it @@ -1870,7 +1872,7 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ unlockBtreeIfUnused(pBt); } }while( rc==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE && - sqlite3InvokeBusyHandler(pBt->pBusyHandler) ); + sqlite3BtreeInvokeBusyHandler(pBt, 0) ); if( rc==SQLITE_OK ){ if( p->inTrans==TRANS_NONE ){ @@ -2196,6 +2198,7 @@ int sqlite3BtreeIncrVacuum(Btree *p){ BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); + pBt->db = p->db; assert( pBt->inTransaction==TRANS_WRITE && p->inTrans==TRANS_WRITE ); if( !pBt->autoVacuum ){ rc = SQLITE_DONE; @@ -2312,6 +2315,7 @@ int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){ BtShared *pBt = p->pBt; Pgno nTrunc = 0; sqlite3BtreeEnter(p); + pBt->db = p->db; #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ rc = autoVacuumCommit(pBt, &nTrunc); @@ -2345,6 +2349,7 @@ int sqlite3BtreeCommitPhaseTwo(Btree *p){ BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); + pBt->db = p->db; btreeIntegrity(p); /* If the handle has a write-transaction open, commit the shared-btrees @@ -2465,6 +2470,7 @@ int sqlite3BtreeRollback(Btree *p){ MemPage *pPage1; sqlite3BtreeEnter(p); + pBt->db = p->db; rc = saveAllCursors(pBt, 0, 0); #ifndef SQLITE_OMIT_SHARED_CACHE if( rc!=SQLITE_OK ){ @@ -2540,6 +2546,7 @@ int sqlite3BtreeBeginStmt(Btree *p){ int rc; BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); + pBt->db = p->db; if( (p->inTrans!=TRANS_WRITE) || pBt->inStmt ){ rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; }else{ @@ -2560,6 +2567,7 @@ int sqlite3BtreeCommitStmt(Btree *p){ int rc; BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); + pBt->db = p->db; if( pBt->inStmt && !pBt->readOnly ){ rc = sqlite3PagerStmtCommit(pBt->pPager); }else{ @@ -2582,6 +2590,7 @@ int sqlite3BtreeRollbackStmt(Btree *p){ int rc = SQLITE_OK; BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); + pBt->db = p->db; if( pBt->inStmt && !pBt->readOnly ){ rc = sqlite3PagerStmtRollback(pBt->pPager); assert( countWriteCursors(pBt)==0 ); @@ -2725,6 +2734,7 @@ int sqlite3BtreeCursor( ){ int rc; sqlite3BtreeEnter(p); + p->pBt->db = p->db; rc = btreeCursor(p, iTable, wrFlag, xCmp, pArg, ppCur); sqlite3BtreeLeave(p); return rc; @@ -2740,6 +2750,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){ Btree *pBtree = pCur->pBtree; sqlite3BtreeEnter(pBtree); + pBt->db = pBtree->db; clearCursorPosition(pCur); if( pCur->pPrev ){ pCur->pPrev->pNext = pCur->pNext; @@ -3474,7 +3485,7 @@ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ int rc; assert( cursorHoldsMutex(pCur) ); - assert( sqlite3_mutex_held(pCur->pBtree->pSqlite->mutex) ); + assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); rc = moveToRoot(pCur); if( rc==SQLITE_OK ){ if( pCur->eState==CURSOR_INVALID ){ @@ -3498,7 +3509,7 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ int rc; assert( cursorHoldsMutex(pCur) ); - assert( sqlite3_mutex_held(pCur->pBtree->pSqlite->mutex) ); + assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); rc = moveToRoot(pCur); if( rc==SQLITE_OK ){ if( CURSOR_INVALID==pCur->eState ){ @@ -3551,7 +3562,7 @@ int sqlite3BtreeMoveto( int rc; assert( cursorHoldsMutex(pCur) ); - assert( sqlite3_mutex_held(pCur->pBtree->pSqlite->mutex) ); + assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); rc = moveToRoot(pCur); if( rc ){ return rc; @@ -3678,8 +3689,8 @@ int sqlite3BtreeEof(BtCursor *pCur){ ** Return the database connection handle for a cursor. */ sqlite3 *sqlite3BtreeCursorDb(const BtCursor *pCur){ - assert( sqlite3_mutex_held(pCur->pBtree->pSqlite->mutex) ); - return pCur->pBtree->pSqlite; + assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); + return pCur->pBtree->db; } /* @@ -5500,14 +5511,14 @@ static int balance(MemPage *pPage, int insert){ static int checkReadLocks(Btree *pBtree, Pgno pgnoRoot, BtCursor *pExclude){ BtCursor *p; BtShared *pBt = pBtree->pBt; - sqlite3 *db = pBtree->pSqlite; + sqlite3 *db = pBtree->db; assert( sqlite3BtreeHoldsMutex(pBtree) ); for(p=pBt->pCursor; p; p=p->pNext){ if( p==pExclude ) continue; if( p->eState!=CURSOR_VALID ) continue; if( p->pgnoRoot!=pgnoRoot ) continue; if( p->wrFlag==0 ){ - sqlite3 *dbOther = p->pBtree->pSqlite; + sqlite3 *dbOther = p->pBtree->db; if( dbOther==0 || (dbOther!=db && (dbOther->flags & SQLITE_ReadUncommitted)==0) ){ return SQLITE_LOCKED; @@ -5880,6 +5891,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int flags){ int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){ int rc; sqlite3BtreeEnter(p); + p->pBt->db = p->db; rc = btreeCreateTable(p, piTable, flags); sqlite3BtreeLeave(p); return rc; @@ -5944,6 +5956,7 @@ int sqlite3BtreeClearTable(Btree *p, int iTable){ int rc; BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); + pBt->db = p->db; if( p->inTrans!=TRANS_WRITE ){ rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; }else if( (rc = checkReadLocks(p, iTable, 0))!=SQLITE_OK ){ @@ -6087,6 +6100,7 @@ static int btreeDropTable(Btree *p, int iTable, int *piMoved){ int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){ int rc; sqlite3BtreeEnter(p); + p->pBt->db = p->db; rc = btreeDropTable(p, iTable, piMoved); sqlite3BtreeLeave(p); return rc; @@ -6110,6 +6124,7 @@ int sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){ BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); + pBt->db = p->db; /* Reading a meta-data value requires a read-lock on page 1 (and hence ** the sqlite_master table. We grab this lock regardless of whether or @@ -6155,6 +6170,7 @@ int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){ int rc; assert( idx>=1 && idx<=15 ); sqlite3BtreeEnter(p); + pBt->db = p->db; if( p->inTrans!=TRANS_WRITE ){ rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; }else{ @@ -6543,6 +6559,7 @@ char *sqlite3BtreeIntegrityCheck( BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); + pBt->db = p->db; nRef = sqlite3PagerRefcount(pBt->pPager); if( lockBtreeWithRetry(p)!=SQLITE_OK ){ sqlite3BtreeLeave(p); @@ -6569,7 +6586,7 @@ char *sqlite3BtreeIntegrityCheck( unlockBtreeIfUnused(pBt); *pnErr = 1; sqlite3BtreeLeave(p); - return sqlite3MPrintf(p->pSqlite, "Unable to malloc %d bytes", + return sqlite3MPrintf(p->db, "Unable to malloc %d bytes", (sCheck.nPage+1)*sizeof(sCheck.anRef[0])); } for(i=0; i<=sCheck.nPage; i++){ sCheck.anRef[i] = 0; } @@ -6686,6 +6703,9 @@ static int btreeCopyFile(Btree *pTo, Btree *pFrom){ BtShared *pBtTo = pTo->pBt; BtShared *pBtFrom = pFrom->pBt; + pBtTo->db = pTo->db; + pBtFrom->db = pFrom->db; + if( pTo->inTrans!=TRANS_WRITE || pFrom->inTrans!=TRANS_WRITE ){ return SQLITE_ERROR; @@ -6748,7 +6768,7 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ ** Return non-zero if a transaction is active. */ int sqlite3BtreeIsInTrans(Btree *p){ - assert( p==0 || sqlite3_mutex_held(p->pSqlite->mutex) ); + assert( p==0 || sqlite3_mutex_held(p->db->mutex) ); return (p && (p->inTrans==TRANS_WRITE)); } @@ -6764,7 +6784,7 @@ int sqlite3BtreeIsInStmt(Btree *p){ ** Return non-zero if a read (or write) transaction is active. */ int sqlite3BtreeIsInReadTrans(Btree *p){ - assert( sqlite3_mutex_held(p->pSqlite->mutex) ); + assert( sqlite3_mutex_held(p->db->mutex) ); return (p && (p->inTrans!=TRANS_NONE)); } @@ -6801,7 +6821,7 @@ void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){ */ int sqlite3BtreeSchemaLocked(Btree *p){ int rc; - assert( sqlite3_mutex_held(p->pSqlite->mutex) ); + assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); rc = (queryTableLock(p, MASTER_ROOT, READ_LOCK)!=SQLITE_OK); sqlite3BtreeLeave(p); @@ -6838,7 +6858,7 @@ int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){ */ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){ assert( cursorHoldsMutex(pCsr) ); - assert( sqlite3_mutex_held(pCsr->pBtree->pSqlite->mutex) ); + assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) ); assert(pCsr->isIncrblobHandle); if( pCsr->eState>=CURSOR_REQUIRESEEK ){ if( pCsr->eState==CURSOR_FAULT ){ @@ -6880,7 +6900,7 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){ */ void sqlite3BtreeCacheOverflow(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); - assert( sqlite3_mutex_held(pCur->pBtree->pSqlite->mutex) ); + assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert(!pCur->isIncrblobHandle); assert(!pCur->aOverflow); pCur->isIncrblobHandle = 1; diff --git a/src/btree.h b/src/btree.h index f7bc8e12d9..3bfebdb651 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.93 2007/09/03 15:19:35 drh Exp $ +** @(#) $Id: btree.h,v 1.94 2007/12/07 18:55:28 drh Exp $ */ #ifndef _BTREE_H_ #define _BTREE_H_ @@ -82,7 +82,6 @@ int sqlite3BtreeOpen( #define BTREE_PRIVATE 64 /* Never share with other connections */ int sqlite3BtreeClose(Btree*); -int sqlite3BtreeSetBusyHandler(Btree*,BusyHandler*); int sqlite3BtreeSetCacheSize(Btree*,int); int sqlite3BtreeSetSafetyLevel(Btree*,int,int); int sqlite3BtreeSyncDisabled(Btree*); diff --git a/src/btreeInt.h b/src/btreeInt.h index 09f1474239..18db47f01f 100644 --- a/src/btreeInt.h +++ b/src/btreeInt.h @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btreeInt.h,v 1.13 2007/08/30 01:19:59 drh Exp $ +** $Id: btreeInt.h,v 1.14 2007/12/07 18:55:28 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -325,13 +325,13 @@ struct MemPage { ** they often do so without holding sqlite3.mutex. */ struct Btree { - sqlite3 *pSqlite; /* The database connection holding this btree */ + sqlite3 *db; /* The database connection holding this btree */ BtShared *pBt; /* Sharable content of this btree */ u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */ - u8 sharable; /* True if we can share pBt with other pSqlite */ - u8 locked; /* True if pSqlite currently has pBt locked */ + u8 sharable; /* True if we can share pBt with another db */ + u8 locked; /* True if db currently has pBt locked */ int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */ - Btree *pNext; /* List of other sharable Btrees from the same pSqlite */ + Btree *pNext; /* List of other sharable Btrees from the same db */ Btree *pPrev; /* Back pointer of the same list */ }; @@ -365,6 +365,7 @@ struct Btree { */ struct BtShared { Pager *pPager; /* The page cache */ + sqlite3 *db; /* Database connection currently using this Btree */ BtCursor *pCursor; /* A list of all open cursors */ MemPage *pPage1; /* First page of the database */ u8 inStmt; /* True if we are in a statement subtransaction */ @@ -384,12 +385,12 @@ struct BtShared { int minLocal; /* Minimum local payload in non-LEAFDATA tables */ int maxLeaf; /* Maximum local payload in a LEAFDATA table */ int minLeaf; /* Minimum local payload in a LEAFDATA table */ - BusyHandler *pBusyHandler; /* Callback for when there is lock contention */ u8 inTransaction; /* Transaction state */ int nTransaction; /* Number of open transactions (read + write) */ void *pSchema; /* Pointer to space allocated by sqlite3BtreeSchema() */ void (*xFreeSchema)(void*); /* Destructor for BtShared.pSchema */ sqlite3_mutex *mutex; /* Non-recursive mutex required to access this struct */ + BusyHandler busyHdr; /* The busy handler for this btree */ #ifndef SQLITE_OMIT_SHARED_CACHE int nRef; /* Number of references to this structure */ BtShared *pNext; /* Next on a list of sharable BtShared structs */ @@ -423,7 +424,7 @@ struct CellInfo { ** ** When a single database file can shared by two more database connections, ** but cursors cannot be shared. Each cursor is associated with a -** particular database connection identified BtCursor.pBtree.pSqlite. +** particular database connection identified BtCursor.pBtree.db. ** ** Fields in this structure are accessed under the BtShared.mutex ** found at self->pBt->mutex. diff --git a/src/main.c b/src/main.c index 515bd85eac..52fa3151ad 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.408 2007/12/05 01:38:23 drh Exp $ +** $Id: main.c,v 1.409 2007/12/07 18:55:28 drh Exp $ */ #include "sqliteInt.h" #include @@ -766,7 +766,6 @@ int sqlite3BtreeFactory( } rc = sqlite3BtreeOpen(zFilename, (sqlite3 *)db, ppBtree, btFlags, vfsFlags); if( rc==SQLITE_OK ){ - sqlite3BtreeSetBusyHandler(*ppBtree, (void*)&db->busyHandler); sqlite3BtreeSetCacheSize(*ppBtree, nCache); } return rc; diff --git a/src/pager.c b/src/pager.c index 9a44752693..7ba506af44 100644 --- a/src/pager.c +++ b/src/pager.c @@ -18,7 +18,7 @@ ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.397 2007/11/29 18:44:27 drh Exp $ +** @(#) $Id: pager.c,v 1.398 2007/12/07 18:55:28 drh Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" @@ -3151,6 +3151,7 @@ int sqlite3PagerReleaseMemory(int nReq){ int nReleased = 0; /* Bytes of memory released so far */ sqlite3_mutex *mutex; /* The MEM2 mutex */ Pager *pPager; /* For looping over pagers */ + BusyHandler *savedBusy; /* Saved copy of the busy handler */ int rc = SQLITE_OK; /* Acquire the memory-management mutex @@ -3195,7 +3196,10 @@ int sqlite3PagerReleaseMemory(int nReq){ assert(!pPg->needSync || pPg==pPager->lru.pFirst); assert(pPg->needSync || pPg==pPager->lru.pFirstSynced); + savedBusy = pPager->pBusyHandler; + pPager->pBusyHandler = 0; rc = pager_recycle(pPager, &pRecycled); + pPager->pBusyHandler = savedBusy; assert(pRecycled==pPg || rc!=SQLITE_OK); if( rc==SQLITE_OK ){ /* We've found a page to free. At this point the page has been diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 0576378c0e..49906f9955 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.623 2007/12/05 01:38:24 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.624 2007/12/07 18:55:29 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1620,8 +1620,10 @@ typedef struct { #ifdef SQLITE_DEBUG int sqlite3Corrupt(void); # define SQLITE_CORRUPT_BKPT sqlite3Corrupt() +# define DEBUGONLY(X) X #else # define SQLITE_CORRUPT_BKPT SQLITE_CORRUPT +# define DEBUGONLY(X) #endif /* diff --git a/src/test3.c b/src/test3.c index 4f14330520..4bf3f13690 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.87 2007/09/12 17:01:45 danielk1977 Exp $ +** $Id: test3.c,v 1.88 2007/12/07 18:55:29 drh Exp $ */ #include "sqliteInt.h" #include "btreeInt.h" @@ -566,7 +566,7 @@ static int btree_pager_stats( ** we need to obtain the mutex for the controlling SQLite handle before ** it is safe to call sqlite3BtreeEnter(). */ - sqlite3_mutex_enter(pBt->pSqlite->mutex); + sqlite3_mutex_enter(pBt->db->mutex); sqlite3BtreeEnter(pBt); a = sqlite3PagerStats(sqlite3BtreePager(pBt)); @@ -583,7 +583,7 @@ static int btree_pager_stats( sqlite3BtreeLeave(pBt); /* Release the mutex on the SQLite handle that controls this b-tree */ - sqlite3_mutex_leave(pBt->pSqlite->mutex); + sqlite3_mutex_leave(pBt->db->mutex); return TCL_OK; } @@ -1591,11 +1591,11 @@ static int btree_set_cache_size( pBt = sqlite3TextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR; - sqlite3_mutex_enter(pBt->pSqlite->mutex); + sqlite3_mutex_enter(pBt->db->mutex); sqlite3BtreeEnter(pBt); sqlite3BtreeSetCacheSize(pBt, nCache); sqlite3BtreeLeave(pBt); - sqlite3_mutex_leave(pBt->pSqlite->mutex); + sqlite3_mutex_leave(pBt->db->mutex); return TCL_OK; }