/ Check-in [ed6620ba]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Always set BtShared.db when entering the BtShared mutex. Ticket #3793. (CVS 6480)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: ed6620ba589ddbb6ca86f42a7652e3b019195647
User & Date: danielk1977 2009-04-10 09:47:07
Context
2009-04-10
12:55
Changes to ensure that when running in shared-cache mode with a non-threadsafe build, the correct busy-handler callback is always invoked. (CVS 6481) check-in: 683e4bd7 user: danielk1977 tags: trunk
09:47
Always set BtShared.db when entering the BtShared mutex. Ticket #3793. (CVS 6480) check-in: ed6620ba user: danielk1977 tags: trunk
00:56
Force 8-byte alignment of sqlite3_value objects in the sqlite3VdbeUnpackRecord() primitive. Ticket #3777. (CVS 6479) check-in: 2cc68272 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/btmutex.c.

     6      6   **
     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   **
    13         -** $Id: btmutex.c,v 1.13 2009/03/05 04:20:32 shane Exp $
           13  +** $Id: btmutex.c,v 1.14 2009/04/10 09:47:07 danielk1977 Exp $
    14     14   **
    15     15   ** This file contains code used to implement mutexes on Btree objects.
    16     16   ** This code really belongs in btree.c.  But btree.c is getting too
    17     17   ** big and we want to break it down some.  This packaged seemed like
    18     18   ** a good breakout.
    19     19   */
    20     20   #include "btreeInt.h"
    21     21   #if SQLITE_THREADSAFE && !defined(SQLITE_OMIT_SHARED_CACHE)
    22     22   
           23  +/*
           24  +** Obtain the BtShared mutex associated with B-Tree handle p. Also,
           25  +** set BtShared.db to the database handle associated with p and the
           26  +** p->locked boolean to true.
           27  +*/
           28  +static void lockBtreeMutex(Btree *p){
           29  +  assert( p->locked==0 );
           30  +  assert( sqlite3_mutex_notheld(p->pBt->mutex) );
           31  +  assert( sqlite3_mutex_held(p->db->mutex) );
           32  +
           33  +  sqlite3_mutex_enter(p->pBt->mutex);
           34  +  p->pBt->db = p->db;
           35  +  p->locked = 1;
           36  +}
           37  +
           38  +/*
           39  +** Release the BtShared mutex associated with B-Tree handle p and
           40  +** clear the p->locked boolean.
           41  +*/
           42  +static void unlockBtreeMutex(Btree *p){
           43  +  assert( p->locked==1 );
           44  +  assert( sqlite3_mutex_held(p->pBt->mutex) );
           45  +  assert( sqlite3_mutex_held(p->db->mutex) );
           46  +  assert( p->db==p->pBt->db );
           47  +
           48  +  sqlite3_mutex_leave(p->pBt->mutex);
           49  +  p->locked = 0;
           50  +}
    23     51   
    24     52   /*
    25     53   ** Enter a mutex on the given BTree object.
    26     54   **
    27     55   ** If the object is not sharable, then no mutex is ever required
    28     56   ** and this routine is a no-op.  The underlying mutex is non-recursive.
    29     57   ** But we keep a reference count in Btree.wantToLock so the behavior
................................................................................
    53     81     /* Check for locking consistency */
    54     82     assert( !p->locked || p->wantToLock>0 );
    55     83     assert( p->sharable || p->wantToLock==0 );
    56     84   
    57     85     /* We should already hold a lock on the database connection */
    58     86     assert( sqlite3_mutex_held(p->db->mutex) );
    59     87   
           88  +  /* Unless the database is sharable and unlocked, then BtShared.db
           89  +  ** should already be set correctly. */
           90  +  assert( (p->locked==0 && p->sharable) || p->pBt->db==p->db );
           91  +
    60     92     if( !p->sharable ) return;
    61     93     p->wantToLock++;
    62     94     if( p->locked ) return;
    63     95   
    64     96     /* In most cases, we should be able to acquire the lock we
    65     97     ** want without having to go throught the ascending lock
    66     98     ** procedure that follows.  Just be sure not to block.
    67     99     */
    68    100     if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){
          101  +    p->pBt->db = p->db;
    69    102       p->locked = 1;
    70    103       return;
    71    104     }
    72    105   
    73    106     /* To avoid deadlock, first release all locks with a larger
    74    107     ** BtShared address.  Then acquire our lock.  Then reacquire
    75    108     ** the other BtShared locks that we used to hold in ascending
................................................................................
    76    109     ** order.
    77    110     */
    78    111     for(pLater=p->pNext; pLater; pLater=pLater->pNext){
    79    112       assert( pLater->sharable );
    80    113       assert( pLater->pNext==0 || pLater->pNext->pBt>pLater->pBt );
    81    114       assert( !pLater->locked || pLater->wantToLock>0 );
    82    115       if( pLater->locked ){
    83         -      sqlite3_mutex_leave(pLater->pBt->mutex);
    84         -      pLater->locked = 0;
          116  +      unlockBtreeMutex(pLater);
    85    117       }
    86    118     }
    87         -  sqlite3_mutex_enter(p->pBt->mutex);
    88         -  p->locked = 1;
          119  +  lockBtreeMutex(p);
    89    120     for(pLater=p->pNext; pLater; pLater=pLater->pNext){
    90    121       if( pLater->wantToLock ){
    91         -      sqlite3_mutex_enter(pLater->pBt->mutex);
    92         -      pLater->locked = 1;
          122  +      lockBtreeMutex(pLater);
    93    123       }
    94    124     }
    95    125   }
    96    126   
    97    127   /*
    98    128   ** Exit the recursive mutex on a Btree.
    99    129   */
   100    130   void sqlite3BtreeLeave(Btree *p){
   101    131     if( p->sharable ){
   102    132       assert( p->wantToLock>0 );
   103    133       p->wantToLock--;
   104    134       if( p->wantToLock==0 ){
   105         -      assert( p->locked );
   106         -      sqlite3_mutex_leave(p->pBt->mutex);
   107         -      p->locked = 0;
          135  +      unlockBtreeMutex(p);
   108    136       }
   109    137     }
   110    138   }
   111    139   
   112    140   #ifndef NDEBUG
   113    141   /*
   114         -** Return true if the BtShared mutex is held on the btree.  
   115         -**
   116         -** This routine makes no determination one way or another if the
   117         -** database connection mutex is held.
          142  +** Return true if the BtShared mutex is held on the btree, or if the
          143  +** B-Tree is not marked as sharable.
   118    144   **
   119    145   ** This routine is used only from within assert() statements.
   120    146   */
   121    147   int sqlite3BtreeHoldsMutex(Btree *p){
   122         -  return (p->sharable==0 ||
   123         -             (p->locked && p->wantToLock && sqlite3_mutex_held(p->pBt->mutex)));
          148  +  assert( p->sharable==0 || p->locked==0 || p->wantToLock>0 );
          149  +  assert( p->sharable==0 || p->locked==0 || p->db==p->pBt->db );
          150  +  assert( p->sharable==0 || p->locked==0 || sqlite3_mutex_held(p->pBt->mutex) );
          151  +  assert( p->sharable==0 || p->locked==0 || sqlite3_mutex_held(p->db->mutex) );
          152  +
          153  +  return (p->sharable==0 || p->locked);
   124    154   }
   125    155   #endif
   126    156   
   127    157   
   128    158   #ifndef SQLITE_OMIT_INCRBLOB
   129    159   /*
   130    160   ** Enter and leave a mutex on a Btree given a cursor owned by that
................................................................................
   156    186   */
   157    187   void sqlite3BtreeEnterAll(sqlite3 *db){
   158    188     int i;
   159    189     Btree *p, *pLater;
   160    190     assert( sqlite3_mutex_held(db->mutex) );
   161    191     for(i=0; i<db->nDb; i++){
   162    192       p = db->aDb[i].pBt;
          193  +    assert( !p || (p->locked==0 && p->sharable) || p->pBt->db==p->db );
   163    194       if( p && p->sharable ){
   164    195         p->wantToLock++;
   165    196         if( !p->locked ){
   166    197           assert( p->wantToLock==1 );
   167    198           while( p->pPrev ) p = p->pPrev;
   168    199           while( p->locked && p->pNext ) p = p->pNext;
   169    200           for(pLater = p->pNext; pLater; pLater=pLater->pNext){
   170    201             if( pLater->locked ){
   171         -            sqlite3_mutex_leave(pLater->pBt->mutex);
   172         -            pLater->locked = 0;
          202  +            unlockBtreeMutex(pLater);
   173    203             }
   174    204           }
   175    205           while( p ){
   176         -          sqlite3_mutex_enter(p->pBt->mutex);
   177         -          p->locked++;
          206  +          lockBtreeMutex(p);
   178    207             p = p->pNext;
   179    208           }
   180    209         }
   181    210       }
   182    211     }
   183    212   }
   184    213   void sqlite3BtreeLeaveAll(sqlite3 *db){
................................................................................
   187    216     assert( sqlite3_mutex_held(db->mutex) );
   188    217     for(i=0; i<db->nDb; i++){
   189    218       p = db->aDb[i].pBt;
   190    219       if( p && p->sharable ){
   191    220         assert( p->wantToLock>0 );
   192    221         p->wantToLock--;
   193    222         if( p->wantToLock==0 ){
   194         -        assert( p->locked );
   195         -        sqlite3_mutex_leave(p->pBt->mutex);
   196         -        p->locked = 0;
          223  +        unlockBtreeMutex(p);
   197    224         }
   198    225       }
   199    226     }
   200    227   }
   201    228   
   202    229   #ifndef NDEBUG
   203    230   /*
................................................................................
   278    305       assert( !p->locked || p->wantToLock>0 );
   279    306   
   280    307       /* We should already hold a lock on the database connection */
   281    308       assert( sqlite3_mutex_held(p->db->mutex) );
   282    309   
   283    310       p->wantToLock++;
   284    311       if( !p->locked && p->sharable ){
   285         -      sqlite3_mutex_enter(p->pBt->mutex);
   286         -      p->locked = 1;
          312  +      lockBtreeMutex(p);
   287    313       }
   288    314     }
   289    315   }
   290    316   
   291    317   /*
   292    318   ** Leave the mutex of every btree in the group.
   293    319   */
................................................................................
   301    327       assert( p->wantToLock>0 );
   302    328   
   303    329       /* We should already hold a lock on the database connection */
   304    330       assert( sqlite3_mutex_held(p->db->mutex) );
   305    331   
   306    332       p->wantToLock--;
   307    333       if( p->wantToLock==0 && p->locked ){
   308         -      sqlite3_mutex_leave(p->pBt->mutex);
   309         -      p->locked = 0;
          334  +      unlockBtreeMutex(p);
   310    335       }
   311    336     }
   312    337   }
   313    338   
   314    339   
   315    340   #endif  /* SQLITE_THREADSAFE && !SQLITE_OMIT_SHARED_CACHE */

Changes to src/btree.c.

     5      5   ** a legal notice, here is a blessing:
     6      6   **
     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12         -** $Id: btree.c,v 1.593 2009/04/10 00:56:28 drh Exp $
           12  +** $Id: btree.c,v 1.594 2009/04/10 09:47:07 danielk1977 Exp $
    13     13   **
    14     14   ** This file implements a external (disk-based) database using BTrees.
    15     15   ** See the header comment on "btreeInt.h" for additional information.
    16     16   ** Including a description of file format and an overview of operation.
    17     17   */
    18     18   #include "btreeInt.h"
    19     19   
................................................................................
  1466   1466                             EXTRA_SIZE, flags, vfsFlags);
  1467   1467       if( rc==SQLITE_OK ){
  1468   1468         rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader);
  1469   1469       }
  1470   1470       if( rc!=SQLITE_OK ){
  1471   1471         goto btree_open_out;
  1472   1472       }
         1473  +    pBt->db = db;
  1473   1474       sqlite3PagerSetBusyhandler(pBt->pPager, btreeInvokeBusyHandler, pBt);
  1474   1475       p->pBt = pBt;
  1475   1476     
  1476   1477       sqlite3PagerSetReiniter(pBt->pPager, pageReinit);
  1477   1478       pBt->pCursor = 0;
  1478   1479       pBt->pPage1 = 0;
  1479   1480       pBt->readOnly = sqlite3PagerIsreadonly(pBt->pPager);
................................................................................
  1643   1644   int sqlite3BtreeClose(Btree *p){
  1644   1645     BtShared *pBt = p->pBt;
  1645   1646     BtCursor *pCur;
  1646   1647   
  1647   1648     /* Close all cursors opened via this handle.  */
  1648   1649     assert( sqlite3_mutex_held(p->db->mutex) );
  1649   1650     sqlite3BtreeEnter(p);
  1650         -  pBt->db = p->db;
  1651   1651     pCur = pBt->pCursor;
  1652   1652     while( pCur ){
  1653   1653       BtCursor *pTmp = pCur;
  1654   1654       pCur = pCur->pNext;
  1655   1655       if( pTmp->pBtree==p ){
  1656   1656         sqlite3BtreeCloseCursor(pTmp);
  1657   1657       }
................................................................................
  2122   2122   */
  2123   2123   int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
  2124   2124     sqlite3 *pBlock = 0;
  2125   2125     BtShared *pBt = p->pBt;
  2126   2126     int rc = SQLITE_OK;
  2127   2127   
  2128   2128     sqlite3BtreeEnter(p);
  2129         -  pBt->db = p->db;
  2130   2129     btreeIntegrity(p);
  2131   2130   
  2132   2131     /* If the btree is already in a write-transaction, or it
  2133   2132     ** is already in a read-transaction and a read-transaction
  2134   2133     ** is requested, this is a no-op.
  2135   2134     */
  2136   2135     if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){
................................................................................
  2541   2540   ** SQLITE_OK is returned. Otherwise an SQLite error code. 
  2542   2541   */
  2543   2542   int sqlite3BtreeIncrVacuum(Btree *p){
  2544   2543     int rc;
  2545   2544     BtShared *pBt = p->pBt;
  2546   2545   
  2547   2546     sqlite3BtreeEnter(p);
  2548         -  pBt->db = p->db;
  2549   2547     assert( pBt->inTransaction==TRANS_WRITE && p->inTrans==TRANS_WRITE );
  2550   2548     if( !pBt->autoVacuum ){
  2551   2549       rc = SQLITE_DONE;
  2552   2550     }else{
  2553   2551       invalidateAllOverflowCache(pBt);
  2554   2552       rc = incrVacuumStep(pBt, 0, pagerPagecount(pBt));
  2555   2553     }
................................................................................
  2648   2646   ** the write-transaction for this database file is to delete the journal.
  2649   2647   */
  2650   2648   int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){
  2651   2649     int rc = SQLITE_OK;
  2652   2650     if( p->inTrans==TRANS_WRITE ){
  2653   2651       BtShared *pBt = p->pBt;
  2654   2652       sqlite3BtreeEnter(p);
  2655         -    pBt->db = p->db;
  2656   2653   #ifndef SQLITE_OMIT_AUTOVACUUM
  2657   2654       if( pBt->autoVacuum ){
  2658   2655         rc = autoVacuumCommit(pBt);
  2659   2656         if( rc!=SQLITE_OK ){
  2660   2657           sqlite3BtreeLeave(p);
  2661   2658           return rc;
  2662   2659         }
................................................................................
  2682   2679   ** This will release the write lock on the database file.  If there
  2683   2680   ** are no active cursors, it also releases the read lock.
  2684   2681   */
  2685   2682   int sqlite3BtreeCommitPhaseTwo(Btree *p){
  2686   2683     BtShared *pBt = p->pBt;
  2687   2684   
  2688   2685     sqlite3BtreeEnter(p);
  2689         -  pBt->db = p->db;
  2690   2686     btreeIntegrity(p);
  2691   2687   
  2692   2688     /* If the handle has a write-transaction open, commit the shared-btrees 
  2693   2689     ** transaction and set the shared state to TRANS_READ.
  2694   2690     */
  2695   2691     if( p->inTrans==TRANS_WRITE ){
  2696   2692       int rc;
................................................................................
  2808   2804   */
  2809   2805   int sqlite3BtreeRollback(Btree *p){
  2810   2806     int rc;
  2811   2807     BtShared *pBt = p->pBt;
  2812   2808     MemPage *pPage1;
  2813   2809   
  2814   2810     sqlite3BtreeEnter(p);
  2815         -  pBt->db = p->db;
  2816   2811     rc = saveAllCursors(pBt, 0, 0);
  2817   2812   #ifndef SQLITE_OMIT_SHARED_CACHE
  2818   2813     if( rc!=SQLITE_OK ){
  2819   2814       /* This is a horrible situation. An IO or malloc() error occurred whilst
  2820   2815       ** trying to save cursor positions. If this is an automatic rollback (as
  2821   2816       ** the result of a constraint, malloc() failure or IO error) then 
  2822   2817       ** the cache may be internally inconsistent (not contain valid trees) so
................................................................................
  2883   2878   ** iStatement is 1. This anonymous savepoint can be released or rolled back
  2884   2879   ** using the sqlite3BtreeSavepoint() function.
  2885   2880   */
  2886   2881   int sqlite3BtreeBeginStmt(Btree *p, int iStatement){
  2887   2882     int rc;
  2888   2883     BtShared *pBt = p->pBt;
  2889   2884     sqlite3BtreeEnter(p);
  2890         -  pBt->db = p->db;
  2891   2885     assert( p->inTrans==TRANS_WRITE );
  2892   2886     assert( pBt->readOnly==0 );
  2893   2887     assert( iStatement>0 );
  2894   2888     assert( iStatement>p->db->nSavepoint );
  2895   2889     if( NEVER(p->inTrans!=TRANS_WRITE || pBt->readOnly) ){
  2896   2890       rc = SQLITE_INTERNAL;
  2897   2891     }else{
................................................................................
  2922   2916   int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
  2923   2917     int rc = SQLITE_OK;
  2924   2918     if( p && p->inTrans==TRANS_WRITE ){
  2925   2919       BtShared *pBt = p->pBt;
  2926   2920       assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK );
  2927   2921       assert( iSavepoint>=0 || (iSavepoint==-1 && op==SAVEPOINT_ROLLBACK) );
  2928   2922       sqlite3BtreeEnter(p);
  2929         -    pBt->db = p->db;
  2930   2923       rc = sqlite3PagerSavepoint(pBt->pPager, op, iSavepoint);
  2931   2924       if( rc==SQLITE_OK ){
  2932   2925         rc = newDatabase(pBt);
  2933   2926       }
  2934   2927       sqlite3BtreeLeave(p);
  2935   2928     }
  2936   2929     return rc;
................................................................................
  3039   3032     int iTable,                                 /* Root page of table to open */
  3040   3033     int wrFlag,                                 /* 1 to write. 0 read-only */
  3041   3034     struct KeyInfo *pKeyInfo,                   /* First arg to xCompare() */
  3042   3035     BtCursor *pCur                              /* Write new cursor here */
  3043   3036   ){
  3044   3037     int rc;
  3045   3038     sqlite3BtreeEnter(p);
  3046         -  p->pBt->db = p->db;
  3047   3039     rc = btreeCursor(p, iTable, wrFlag, pKeyInfo, pCur);
  3048   3040     sqlite3BtreeLeave(p);
  3049   3041     return rc;
  3050   3042   }
  3051   3043   
  3052   3044   /*
  3053   3045   ** Return the size of a BtCursor object in bytes.
................................................................................
  3097   3089   */
  3098   3090   int sqlite3BtreeCloseCursor(BtCursor *pCur){
  3099   3091     Btree *pBtree = pCur->pBtree;
  3100   3092     if( pBtree ){
  3101   3093       int i;
  3102   3094       BtShared *pBt = pCur->pBt;
  3103   3095       sqlite3BtreeEnter(pBtree);
  3104         -    pBt->db = pBtree->db;
  3105   3096       sqlite3BtreeClearCursor(pCur);
  3106   3097       if( pCur->pPrev ){
  3107   3098         pCur->pPrev->pNext = pCur->pNext;
  3108   3099       }else{
  3109   3100         pBt->pCursor = pCur->pNext;
  3110   3101       }
  3111   3102       if( pCur->pNext ){
................................................................................
  6513   6504     sqlite3PagerUnref(pRoot->pDbPage);
  6514   6505     *piTable = (int)pgnoRoot;
  6515   6506     return SQLITE_OK;
  6516   6507   }
  6517   6508   int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){
  6518   6509     int rc;
  6519   6510     sqlite3BtreeEnter(p);
  6520         -  p->pBt->db = p->db;
  6521   6511     rc = btreeCreateTable(p, piTable, flags);
  6522   6512     sqlite3BtreeLeave(p);
  6523   6513     return rc;
  6524   6514   }
  6525   6515   
  6526   6516   /*
  6527   6517   ** Erase the given database page and all its children.  Return
................................................................................
  6585   6575   ** integer value pointed to by pnChange is incremented by the number of
  6586   6576   ** entries in the table.
  6587   6577   */
  6588   6578   int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){
  6589   6579     int rc;
  6590   6580     BtShared *pBt = p->pBt;
  6591   6581     sqlite3BtreeEnter(p);
  6592         -  pBt->db = p->db;
  6593   6582     assert( p->inTrans==TRANS_WRITE );
  6594   6583     if( (rc = checkForReadConflicts(p, iTable, 0, 1))!=SQLITE_OK ){
  6595   6584       /* nothing to do */
  6596   6585     }else if( SQLITE_OK!=(rc = saveAllCursors(pBt, iTable, 0)) ){
  6597   6586       /* nothing to do */
  6598   6587     }else{
  6599   6588       rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange);
................................................................................
  6727   6716       releasePage(pPage);
  6728   6717     }
  6729   6718     return rc;  
  6730   6719   }
  6731   6720   int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
  6732   6721     int rc;
  6733   6722     sqlite3BtreeEnter(p);
  6734         -  p->pBt->db = p->db;
  6735   6723     rc = btreeDropTable(p, iTable, piMoved);
  6736   6724     sqlite3BtreeLeave(p);
  6737   6725     return rc;
  6738   6726   }
  6739   6727   
  6740   6728   
  6741   6729   /*
................................................................................
  6751   6739   int sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){
  6752   6740     DbPage *pDbPage = 0;
  6753   6741     int rc;
  6754   6742     unsigned char *pP1;
  6755   6743     BtShared *pBt = p->pBt;
  6756   6744   
  6757   6745     sqlite3BtreeEnter(p);
  6758         -  pBt->db = p->db;
  6759   6746   
  6760   6747     /* Reading a meta-data value requires a read-lock on page 1 (and hence
  6761   6748     ** the sqlite_master table. We grab this lock regardless of whether or
  6762   6749     ** not the SQLITE_ReadUncommitted flag is set (the table rooted at page
  6763   6750     ** 1 is treated as a special case by querySharedCacheTableLock()
  6764   6751     ** and setSharedCacheTableLock()).
  6765   6752     */
................................................................................
  6822   6809   */
  6823   6810   int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){
  6824   6811     BtShared *pBt = p->pBt;
  6825   6812     unsigned char *pP1;
  6826   6813     int rc;
  6827   6814     assert( idx>=1 && idx<=15 );
  6828   6815     sqlite3BtreeEnter(p);
  6829         -  pBt->db = p->db;
  6830   6816     assert( p->inTrans==TRANS_WRITE );
  6831   6817     assert( pBt->pPage1!=0 );
  6832   6818     pP1 = pBt->pPage1->aData;
  6833   6819     rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
  6834   6820     if( rc==SQLITE_OK ){
  6835   6821       put4byte(&pP1[36 + idx*4], iMeta);
  6836   6822   #ifndef SQLITE_OMIT_AUTOVACUUM
................................................................................
  7296   7282     Pgno i;
  7297   7283     int nRef;
  7298   7284     IntegrityCk sCheck;
  7299   7285     BtShared *pBt = p->pBt;
  7300   7286     char zErr[100];
  7301   7287   
  7302   7288     sqlite3BtreeEnter(p);
  7303         -  pBt->db = p->db;
  7304   7289     nRef = sqlite3PagerRefcount(pBt->pPager);
  7305   7290     if( lockBtreeWithRetry(p)!=SQLITE_OK ){
  7306   7291       *pnErr = 1;
  7307   7292       sqlite3BtreeLeave(p);
  7308   7293       return sqlite3DbStrDup(0, "cannot acquire a read lock on the database");
  7309   7294     }
  7310   7295     sCheck.pBt = pBt;

Added test/tkt3793.test.

            1  +# 2009 April 10
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +# This file implements regression tests for SQLite library.
           12  +#
           13  +# This file implements tests to verify that ticket #3793 has been
           14  +# fixed.  
           15  +#
           16  +# $Id: tkt3793.test,v 1.1 2009/04/10 09:47:07 danielk1977 Exp $
           17  +
           18  +
           19  +set testdir [file dirname $argv0]
           20  +source $testdir/tester.tcl
           21  +
           22  +ifcapable !shared_cache||!attach {
           23  +  finish_test
           24  +  return
           25  +}
           26  +set ::enable_shared_cache [sqlite3_enable_shared_cache 1]
           27  +
           28  +do_test tkt3793-1.1 {
           29  +  sqlite3 db1 test.db
           30  +  sqlite3 db2 test.db
           31  +  execsql {
           32  +    BEGIN;
           33  +    CREATE TABLE t1(a, b);
           34  +    CREATE TABLE t2(a PRIMARY KEY, b);
           35  +    INSERT INTO t1 VALUES(randstr(50,50), randstr(50,50));
           36  +    INSERT INTO t1 SELECT randstr(50,50), randstr(50,50) FROM t1;
           37  +    INSERT INTO t1 SELECT randstr(50,50), randstr(50,50) FROM t1;
           38  +    INSERT INTO t1 SELECT randstr(50,50), randstr(50,50) FROM t1;
           39  +    INSERT INTO t1 SELECT randstr(50,50), randstr(50,50) FROM t1;
           40  +    INSERT INTO t1 SELECT randstr(50,50), randstr(50,50) FROM t1;
           41  +    INSERT INTO t1 SELECT randstr(50,50), randstr(50,50) FROM t1;
           42  +    INSERT INTO t1 SELECT randstr(50,50), randstr(50,50) FROM t1;
           43  +    INSERT INTO t1 SELECT randstr(50,50), randstr(50,50) FROM t1;
           44  +    INSERT INTO t1 SELECT randstr(50,50), randstr(50,50) FROM t1;
           45  +    INSERT INTO t1 SELECT randstr(50,50), randstr(50,50) FROM t1;
           46  +    INSERT INTO t2 SELECT * FROM t1;
           47  +    COMMIT;
           48  +  }
           49  +} {}
           50  +
           51  +proc busyhandler {db args} { set ::busyconnection $db ; return 1 }
           52  +db2 busy {busyhandler db2}
           53  +db1 busy {busyhandler db1}
           54  +
           55  +# Establish a read-lock on the database file using connection [db].
           56  +#
           57  +do_test tkt3793-1.2 {
           58  +  execsql {
           59  +    BEGIN;
           60  +    SELECT count(*) FROM t1;
           61  +  }
           62  +} {1024}
           63  +
           64  +# Set the size of the cache shared by [db1] and [db2] to 10. Then update
           65  +# more than 10 pages of table t1. At this point the shared-cache will
           66  +# hold a RESERVED lock on the database file. Even though there are now
           67  +# more than 10 dirty pages in memory, it cannot upgrade to an EXCLUSIVE 
           68  +# lock because of the read-lock held by [db].
           69  +#
           70  +do_test tkt3793-1.3 {
           71  +  execsql {
           72  +    PRAGMA cache_size = 10;
           73  +    BEGIN;
           74  +    UPDATE t1 SET b = randstr(50,50);
           75  +  } db1
           76  +} {}
           77  +
           78  +set x 0
           79  +
           80  +# Run one SELECT query on the shared-cache using [db1], then from within 
           81  +# the callback run another via [db2]. Because of the large number of dirty
           82  +# pages within the cache, each time a new page is read from the database
           83  +# SQLite will attempt to upgrade to an EXCLUSIVE lock, and hence invoke
           84  +# the busy-handler. The tests here verify that the correct busy-handler
           85  +# function is invoked (the busy-handler associated with the database
           86  +# connection that called sqlite3_step()). When bug #3793 existed, sometimes
           87  +# the [db2] busy-handler was invoked from within the call to sqlite3_step()
           88  +# associated with [db1]. 
           89  +#
           90  +# Note: Before the bug was fixed, if [db2] was opened with the "-fullmutex 1"
           91  +# option, then this test case would cause an assert() to fail.
           92  +#
           93  +set ::busyconnection db1
           94  +db1 eval {SELECT * FROM t2 ORDER BY a LIMIT 20} {
           95  +  do_test tkt3793-2.[incr x] { set ::busyconnection } db1
           96  +  set ::busyconnection db2
           97  +
           98  +  db2 eval { SELECT count(*) FROM t2 }
           99  +  do_test tkt3793-2.[incr x] { set ::busyconnection } db2
          100  +  set ::busyconnection db1
          101  +}
          102  +
          103  +do_test tkt3793-3 {
          104  +  db1 close
          105  +  db2 close
          106  +} {}
          107  +
          108  +sqlite3_enable_shared_cache $::enable_shared_cache
          109  +finish_test