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
diff --git a/src/btmutex.c b/src/btmutex.c
index 1f63434..36c22e8 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 @@
   ** 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->pBt<p->pBt );
-  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 @@
   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 @@
     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 @@
     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 9742106..b1e6f85 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 @@
   ** 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 @@
   ** the ReadUncommitted flag.
   */
   if( 
-    (p->pSqlite) && 
-    (p->pSqlite->flags&SQLITE_ReadUncommitted) && 
+    (p->db) && 
+    (p->db->flags&SQLITE_ReadUncommitted) && 
     (eLock==READ_LOCK) &&
     iTable!=MASTER_ROOT
   ){
@@ -1099,6 +1099,16 @@
 }
 
 /*
+** 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.
 ** 
 ** zFilename is the name of the database file.  If zFilename is NULL
@@ -1109,7 +1119,7 @@
 */
 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 @@
   #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 @@
   */
   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 @@
       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 @@
       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 @@
     if( rc!=SQLITE_OK ){
       goto btree_open_out;
     }
+    sqlite3PagerSetBusyhandler(pBt->pPager, &pBt->busyHdr);
     p->pBt = pBt;
   
     sqlite3PagerSetDestructor(pBt->pPager, pageDestructor);
@@ -1273,7 +1286,7 @@
         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 @@
   if( p->sharable ){
     int i;
     Btree *pSib;
-    for(i=0; i<pSqlite->nDb; i++){
-      if( (pSib = pSqlite->aDb[i].pBt)!=0 && pSib->sharable ){
+    for(i=0; i<db->nDb; i++){
+      if( (pSib = db->aDb[i].pBt)!=0 && pSib->sharable ){
         while( pSib->pPrev ){ pSib = pSib->pPrev; }
         if( p->pBt<pSib->pBt ){
           p->pNext = pSib;
@@ -1378,8 +1391,9 @@
   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;
@@ -1428,19 +1442,6 @@
 }
 
 /*
-** 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.
 **
 ** The maximum number of cache pages is set to the absolute
@@ -1457,7 +1458,7 @@
 */
 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 @@
 #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 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 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 @@
       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 @@
   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 @@
     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 @@
   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 @@
   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 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 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 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 rc;
   sqlite3BtreeEnter(p);
+  p->pBt->db = p->db;
   rc = btreeCursor(p, iTable, wrFlag, xCmp, pArg, ppCur);
   sqlite3BtreeLeave(p);
   return rc;
@@ -2740,6 +2750,7 @@
   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 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 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 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 @@
 ** 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 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 @@
 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 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 @@
 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 @@
   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 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 @@
   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 @@
     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 @@
 
   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 @@
 ** 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 @@
 ** 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 @@
 */
 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 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 @@
 */
 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 f7bc8e1..3bfebdb 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 @@
 #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 09f1474..18db47f 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 @@
 ** 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 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 @@
   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 @@
 **
 ** 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 515bd85..52fa315 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 <ctype.h>
@@ -766,7 +766,6 @@
   }
   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 9a44752..7ba506a 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 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 @@
     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 0576378..49906f9 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 @@
 #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 4f14330..4bf3f13 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 @@
   ** 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 @@
   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 @@
   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;
 }