/ Check-in [2d96aeba]
Login

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

Overview
Comment:Fix to cause BtShared.db to be set correctly on shared-cache connections in SQLITE_THREADSAFE=0 builds. Added assert()s to verify the correct setting of BtShared.db.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 2d96aeba2460779a0a20356739a0ba49144c8a85
User & Date: drh 2016-01-07 17:19:24
References
2016-01-08
19:34
Fix the build for SQLITE_OMIT_SHARED_CACHE, which was broken, possibly by check-in [2d96aeba]. check-in: 3392f8fa user: drh tags: trunk
Context
2016-01-07
21:12
Omit performance tracking from the memsys5 memory allocator if neither SQLITE_DEBUG nor SQLITE_TEST are defined. check-in: af5c7714 user: drh tags: trunk
17:19
Fix to cause BtShared.db to be set correctly on shared-cache connections in SQLITE_THREADSAFE=0 builds. Added assert()s to verify the correct setting of BtShared.db. check-in: 2d96aeba user: drh tags: trunk
17:09
Small performance and size optimization spotted while working on the shared-cache problem. check-in: 828958ff user: drh tags: trunk
16:43
Add some assert() statements to verify, where possible, that BtShared.db is set correctly. Closed-Leaf check-in: 359277e0 user: dan tags: shared-cache-fix
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/btmutex.c.

   164    164     assert( p->sharable==0 || p->locked==0 || sqlite3_mutex_held(p->pBt->mutex) );
   165    165     assert( p->sharable==0 || p->locked==0 || sqlite3_mutex_held(p->db->mutex) );
   166    166   
   167    167     return (p->sharable==0 || p->locked);
   168    168   }
   169    169   #endif
   170    170   
   171         -
   172         -#ifndef SQLITE_OMIT_INCRBLOB
   173         -/*
   174         -** Enter and leave a mutex on a Btree given a cursor owned by that
   175         -** Btree.  These entry points are used by incremental I/O and can be
   176         -** omitted if that module is not used.
   177         -*/
   178         -void sqlite3BtreeEnterCursor(BtCursor *pCur){
   179         -  sqlite3BtreeEnter(pCur->pBtree);
   180         -}
   181         -void sqlite3BtreeLeaveCursor(BtCursor *pCur){
   182         -  sqlite3BtreeLeave(pCur->pBtree);
   183         -}
   184         -#endif /* SQLITE_OMIT_INCRBLOB */
   185         -
   186    171   
   187    172   /*
   188    173   ** Enter the mutex on every Btree associated with a database
   189    174   ** connection.  This is needed (for example) prior to parsing
   190    175   ** a statement since we will be comparing table and column names
   191    176   ** against all schemas and we do not want those schemas being
   192    177   ** reset out from under us.
................................................................................
   213    198     assert( sqlite3_mutex_held(db->mutex) );
   214    199     for(i=0; i<db->nDb; i++){
   215    200       p = db->aDb[i].pBt;
   216    201       if( p ) sqlite3BtreeLeave(p);
   217    202     }
   218    203   }
   219    204   
   220         -/*
   221         -** Return true if a particular Btree requires a lock.  Return FALSE if
   222         -** no lock is ever required since it is not sharable.
   223         -*/
   224         -int sqlite3BtreeSharable(Btree *p){
   225         -  return p->sharable;
   226         -}
   227         -
   228    205   #ifndef NDEBUG
   229    206   /*
   230    207   ** Return true if the current thread holds the database connection
   231    208   ** mutex and all required BtShared mutexes.
   232    209   **
   233    210   ** This routine is used inside assert() statements only.
   234    211   */
................................................................................
   294    271       Btree *p = db->aDb[i].pBt;
   295    272       if( p ){
   296    273         p->pBt->db = p->db;
   297    274       }
   298    275     }
   299    276   }
   300    277   #endif /* if SQLITE_THREADSAFE */
          278  +
          279  +#ifndef SQLITE_OMIT_INCRBLOB
          280  +/*
          281  +** Enter a mutex on a Btree given a cursor owned by that Btree. 
          282  +**
          283  +** These entry points are used by incremental I/O only. Enter() is required 
          284  +** any time OMIT_SHARED_CACHE is not defined, regardless of whether or not 
          285  +** the build is threadsafe. Leave() is only required by threadsafe builds.
          286  +*/
          287  +void sqlite3BtreeEnterCursor(BtCursor *pCur){
          288  +  sqlite3BtreeEnter(pCur->pBtree);
          289  +}
          290  +# if SQLITE_THREADSAFE
          291  +void sqlite3BtreeLeaveCursor(BtCursor *pCur){
          292  +  sqlite3BtreeLeave(pCur->pBtree);
          293  +}
          294  +# endif
          295  +#endif /* ifndef SQLITE_OMIT_INCRBLOB */
          296  +
   301    297   #endif /* ifndef SQLITE_OMIT_SHARED_CACHE */

Changes to src/btree.c.

   446    446   **
   447    447   ** Verify that the cursor holds the mutex on its BtShared
   448    448   */
   449    449   #ifdef SQLITE_DEBUG
   450    450   static int cursorHoldsMutex(BtCursor *p){
   451    451     return sqlite3_mutex_held(p->pBt->mutex);
   452    452   }
          453  +static int cursorOwnsBtShared(BtCursor *p){
          454  +  assert( cursorHoldsMutex(p) );
          455  +  return (p->pBtree->db==p->pBt->db);
          456  +}
   453    457   #endif
   454    458   
   455    459   /*
   456    460   ** Invalidate the overflow cache of the cursor passed as the first argument.
   457    461   ** on the shared btree structure pBt.
   458    462   */
   459    463   #define invalidateOverflowCache(pCur) (pCur->curFlags &= ~BTCF_ValidOvfl)
................................................................................
   782    786   ** saved position info stored by saveCursorPosition(), so there can be
   783    787   ** at most one effective restoreCursorPosition() call after each 
   784    788   ** saveCursorPosition().
   785    789   */
   786    790   static int btreeRestoreCursorPosition(BtCursor *pCur){
   787    791     int rc;
   788    792     int skipNext;
   789         -  assert( cursorHoldsMutex(pCur) );
          793  +  assert( cursorOwnsBtShared(pCur) );
   790    794     assert( pCur->eState>=CURSOR_REQUIRESEEK );
   791    795     if( pCur->eState==CURSOR_FAULT ){
   792    796       return pCur->skipNext;
   793    797     }
   794    798     pCur->eState = CURSOR_INVALID;
   795    799     rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &skipNext);
   796    800     if( rc==SQLITE_OK ){
................................................................................
  4282   4286   ** that the cursor has Cursor.eState==CURSOR_VALID.
  4283   4287   **
  4284   4288   ** Failure is not possible.  This function always returns SQLITE_OK.
  4285   4289   ** It might just as well be a procedure (returning void) but we continue
  4286   4290   ** to return an integer result code for historical reasons.
  4287   4291   */
  4288   4292   int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
  4289         -  assert( cursorHoldsMutex(pCur) );
         4293  +  assert( cursorOwnsBtShared(pCur) );
  4290   4294     assert( pCur->eState==CURSOR_VALID );
  4291   4295     assert( pCur->iPage>=0 );
  4292   4296     assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
  4293   4297     assert( pCur->apPage[pCur->iPage]->intKeyLeaf==1 );
  4294   4298     getCellInfo(pCur);
  4295   4299     *pSize = pCur->info.nPayload;
  4296   4300     return SQLITE_OK;
................................................................................
  4662   4666   
  4663   4667   #ifndef SQLITE_OMIT_INCRBLOB
  4664   4668     if ( pCur->eState==CURSOR_INVALID ){
  4665   4669       return SQLITE_ABORT;
  4666   4670     }
  4667   4671   #endif
  4668   4672   
  4669         -  assert( cursorHoldsMutex(pCur) );
         4673  +  assert( cursorOwnsBtShared(pCur) );
  4670   4674     rc = restoreCursorPosition(pCur);
  4671   4675     if( rc==SQLITE_OK ){
  4672   4676       assert( pCur->eState==CURSOR_VALID );
  4673   4677       assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] );
  4674   4678       assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
  4675   4679       rc = accessPayload(pCur, offset, amt, pBuf, 0);
  4676   4680     }
................................................................................
  4700   4704     BtCursor *pCur,      /* Cursor pointing to entry to read from */
  4701   4705     u32 *pAmt            /* Write the number of available bytes here */
  4702   4706   ){
  4703   4707     u32 amt;
  4704   4708     assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]);
  4705   4709     assert( pCur->eState==CURSOR_VALID );
  4706   4710     assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
  4707         -  assert( cursorHoldsMutex(pCur) );
         4711  +  assert( cursorOwnsBtShared(pCur) );
  4708   4712     assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
  4709   4713     assert( pCur->info.nSize>0 );
  4710   4714     assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB );
  4711   4715     assert( pCur->info.pPayload<pCur->apPage[pCur->iPage]->aDataEnd ||CORRUPT_DB);
  4712   4716     amt = (int)(pCur->apPage[pCur->iPage]->aDataEnd - pCur->info.pPayload);
  4713   4717     if( pCur->info.nLocal<amt ) amt = pCur->info.nLocal;
  4714   4718     *pAmt = amt;
................................................................................
  4746   4750   ** the new child page does not match the flags field of the parent (i.e.
  4747   4751   ** if an intkey page appears to be the parent of a non-intkey page, or
  4748   4752   ** vice-versa).
  4749   4753   */
  4750   4754   static int moveToChild(BtCursor *pCur, u32 newPgno){
  4751   4755     BtShared *pBt = pCur->pBt;
  4752   4756   
  4753         -  assert( cursorHoldsMutex(pCur) );
         4757  +  assert( cursorOwnsBtShared(pCur) );
  4754   4758     assert( pCur->eState==CURSOR_VALID );
  4755   4759     assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
  4756   4760     assert( pCur->iPage>=0 );
  4757   4761     if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
  4758   4762       return SQLITE_CORRUPT_BKPT;
  4759   4763     }
  4760   4764     pCur->info.nSize = 0;
................................................................................
  4792   4796   **
  4793   4797   ** pCur->idx is set to the cell index that contains the pointer
  4794   4798   ** to the page we are coming from.  If we are coming from the
  4795   4799   ** right-most child page then pCur->idx is set to one more than
  4796   4800   ** the largest cell index.
  4797   4801   */
  4798   4802   static void moveToParent(BtCursor *pCur){
  4799         -  assert( cursorHoldsMutex(pCur) );
         4803  +  assert( cursorOwnsBtShared(pCur) );
  4800   4804     assert( pCur->eState==CURSOR_VALID );
  4801   4805     assert( pCur->iPage>0 );
  4802   4806     assert( pCur->apPage[pCur->iPage] );
  4803   4807     assertParentIndex(
  4804   4808       pCur->apPage[pCur->iPage-1], 
  4805   4809       pCur->aiIdx[pCur->iPage-1], 
  4806   4810       pCur->apPage[pCur->iPage]->pgno
................................................................................
  4832   4836   ** structure the flags byte is set to 0x02 or 0x0A, indicating an index
  4833   4837   ** b-tree).
  4834   4838   */
  4835   4839   static int moveToRoot(BtCursor *pCur){
  4836   4840     MemPage *pRoot;
  4837   4841     int rc = SQLITE_OK;
  4838   4842   
  4839         -  assert( cursorHoldsMutex(pCur) );
         4843  +  assert( cursorOwnsBtShared(pCur) );
  4840   4844     assert( CURSOR_INVALID < CURSOR_REQUIRESEEK );
  4841   4845     assert( CURSOR_VALID   < CURSOR_REQUIRESEEK );
  4842   4846     assert( CURSOR_FAULT   > CURSOR_REQUIRESEEK );
  4843   4847     if( pCur->eState>=CURSOR_REQUIRESEEK ){
  4844   4848       if( pCur->eState==CURSOR_FAULT ){
  4845   4849         assert( pCur->skipNext!=SQLITE_OK );
  4846   4850         return pCur->skipNext;
................................................................................
  4911   4915   ** in ascending order.
  4912   4916   */
  4913   4917   static int moveToLeftmost(BtCursor *pCur){
  4914   4918     Pgno pgno;
  4915   4919     int rc = SQLITE_OK;
  4916   4920     MemPage *pPage;
  4917   4921   
  4918         -  assert( cursorHoldsMutex(pCur) );
         4922  +  assert( cursorOwnsBtShared(pCur) );
  4919   4923     assert( pCur->eState==CURSOR_VALID );
  4920   4924     while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){
  4921   4925       assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
  4922   4926       pgno = get4byte(findCell(pPage, pCur->aiIdx[pCur->iPage]));
  4923   4927       rc = moveToChild(pCur, pgno);
  4924   4928     }
  4925   4929     return rc;
................................................................................
  4936   4940   ** key in ascending order.
  4937   4941   */
  4938   4942   static int moveToRightmost(BtCursor *pCur){
  4939   4943     Pgno pgno;
  4940   4944     int rc = SQLITE_OK;
  4941   4945     MemPage *pPage = 0;
  4942   4946   
  4943         -  assert( cursorHoldsMutex(pCur) );
         4947  +  assert( cursorOwnsBtShared(pCur) );
  4944   4948     assert( pCur->eState==CURSOR_VALID );
  4945   4949     while( !(pPage = pCur->apPage[pCur->iPage])->leaf ){
  4946   4950       pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
  4947   4951       pCur->aiIdx[pCur->iPage] = pPage->nCell;
  4948   4952       rc = moveToChild(pCur, pgno);
  4949   4953       if( rc ) return rc;
  4950   4954     }
................................................................................
  4957   4961   /* Move the cursor to the first entry in the table.  Return SQLITE_OK
  4958   4962   ** on success.  Set *pRes to 0 if the cursor actually points to something
  4959   4963   ** or set *pRes to 1 if the table is empty.
  4960   4964   */
  4961   4965   int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
  4962   4966     int rc;
  4963   4967   
  4964         -  assert( cursorHoldsMutex(pCur) );
         4968  +  assert( cursorOwnsBtShared(pCur) );
  4965   4969     assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
  4966   4970     rc = moveToRoot(pCur);
  4967   4971     if( rc==SQLITE_OK ){
  4968   4972       if( pCur->eState==CURSOR_INVALID ){
  4969   4973         assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
  4970   4974         *pRes = 1;
  4971   4975       }else{
................................................................................
  4980   4984   /* Move the cursor to the last entry in the table.  Return SQLITE_OK
  4981   4985   ** on success.  Set *pRes to 0 if the cursor actually points to something
  4982   4986   ** or set *pRes to 1 if the table is empty.
  4983   4987   */
  4984   4988   int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
  4985   4989     int rc;
  4986   4990    
  4987         -  assert( cursorHoldsMutex(pCur) );
         4991  +  assert( cursorOwnsBtShared(pCur) );
  4988   4992     assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
  4989   4993   
  4990   4994     /* If the cursor already points to the last entry, this is a no-op. */
  4991   4995     if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){
  4992   4996   #ifdef SQLITE_DEBUG
  4993   4997       /* This block serves to assert() that the cursor really does point 
  4994   4998       ** to the last entry in the b-tree. */
................................................................................
  5058   5062     i64 intKey,              /* The table key */
  5059   5063     int biasRight,           /* If true, bias the search to the high end */
  5060   5064     int *pRes                /* Write search results here */
  5061   5065   ){
  5062   5066     int rc;
  5063   5067     RecordCompare xRecordCompare;
  5064   5068   
  5065         -  assert( cursorHoldsMutex(pCur) );
         5069  +  assert( cursorOwnsBtShared(pCur) );
  5066   5070     assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
  5067   5071     assert( pRes );
  5068   5072     assert( (pIdxKey==0)==(pCur->pKeyInfo==0) );
  5069   5073   
  5070   5074     /* If the cursor is already positioned at the point we are trying
  5071   5075     ** to move to, then just return without doing any work */
  5072   5076     if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0
................................................................................
  5306   5310   ** implementation does use this hint, however.)
  5307   5311   */
  5308   5312   static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
  5309   5313     int rc;
  5310   5314     int idx;
  5311   5315     MemPage *pPage;
  5312   5316   
  5313         -  assert( cursorHoldsMutex(pCur) );
         5317  +  assert( cursorOwnsBtShared(pCur) );
  5314   5318     assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
  5315   5319     assert( *pRes==0 );
  5316   5320     if( pCur->eState!=CURSOR_VALID ){
  5317   5321       assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
  5318   5322       rc = restoreCursorPosition(pCur);
  5319   5323       if( rc!=SQLITE_OK ){
  5320   5324         return rc;
................................................................................
  5370   5374       return SQLITE_OK;
  5371   5375     }else{
  5372   5376       return moveToLeftmost(pCur);
  5373   5377     }
  5374   5378   }
  5375   5379   int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
  5376   5380     MemPage *pPage;
  5377         -  assert( cursorHoldsMutex(pCur) );
         5381  +  assert( cursorOwnsBtShared(pCur) );
  5378   5382     assert( pRes!=0 );
  5379   5383     assert( *pRes==0 || *pRes==1 );
  5380   5384     assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
  5381   5385     pCur->info.nSize = 0;
  5382   5386     pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
  5383   5387     *pRes = 0;
  5384   5388     if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur, pRes);
................................................................................
  5415   5419   ** SQLite btree implementation does not. (Note that the comdb2 btree
  5416   5420   ** implementation does use this hint, however.)
  5417   5421   */
  5418   5422   static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
  5419   5423     int rc;
  5420   5424     MemPage *pPage;
  5421   5425   
  5422         -  assert( cursorHoldsMutex(pCur) );
         5426  +  assert( cursorOwnsBtShared(pCur) );
  5423   5427     assert( pRes!=0 );
  5424   5428     assert( *pRes==0 );
  5425   5429     assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
  5426   5430     assert( (pCur->curFlags & (BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey))==0 );
  5427   5431     assert( pCur->info.nSize==0 );
  5428   5432     if( pCur->eState!=CURSOR_VALID ){
  5429   5433       rc = restoreCursorPosition(pCur);
................................................................................
  5471   5475       }else{
  5472   5476         rc = SQLITE_OK;
  5473   5477       }
  5474   5478     }
  5475   5479     return rc;
  5476   5480   }
  5477   5481   int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
  5478         -  assert( cursorHoldsMutex(pCur) );
         5482  +  assert( cursorOwnsBtShared(pCur) );
  5479   5483     assert( pRes!=0 );
  5480   5484     assert( *pRes==0 || *pRes==1 );
  5481   5485     assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
  5482   5486     *pRes = 0;
  5483   5487     pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey);
  5484   5488     pCur->info.nSize = 0;
  5485   5489     if( pCur->eState!=CURSOR_VALID
................................................................................
  7951   7955     unsigned char *newCell = 0;
  7952   7956   
  7953   7957     if( pCur->eState==CURSOR_FAULT ){
  7954   7958       assert( pCur->skipNext!=SQLITE_OK );
  7955   7959       return pCur->skipNext;
  7956   7960     }
  7957   7961   
  7958         -  assert( cursorHoldsMutex(pCur) );
         7962  +  assert( cursorOwnsBtShared(pCur) );
  7959   7963     assert( (pCur->curFlags & BTCF_WriteFlag)!=0
  7960   7964                 && pBt->inTransaction==TRANS_WRITE
  7961   7965                 && (pBt->btsFlags & BTS_READ_ONLY)==0 );
  7962   7966     assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
  7963   7967   
  7964   7968     /* Assert that the caller has been consistent. If this cursor was opened
  7965   7969     ** expecting an index b-tree, then the caller should be inserting blob
................................................................................
  8098   8102     MemPage *pPage;                      /* Page to delete cell from */
  8099   8103     unsigned char *pCell;                /* Pointer to cell to delete */
  8100   8104     int iCellIdx;                        /* Index of cell to delete */
  8101   8105     int iCellDepth;                      /* Depth of node containing pCell */ 
  8102   8106     u16 szCell;                          /* Size of the cell being deleted */
  8103   8107     int bSkipnext = 0;                   /* Leaf cursor in SKIPNEXT state */
  8104   8108   
  8105         -  assert( cursorHoldsMutex(pCur) );
         8109  +  assert( cursorOwnsBtShared(pCur) );
  8106   8110     assert( pBt->inTransaction==TRANS_WRITE );
  8107   8111     assert( (pBt->btsFlags & BTS_READ_ONLY)==0 );
  8108   8112     assert( pCur->curFlags & BTCF_WriteFlag );
  8109   8113     assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
  8110   8114     assert( !hasReadConflicts(p, pCur->pgnoRoot) );
  8111   8115     assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
  8112   8116     assert( pCur->eState==CURSOR_VALID );
................................................................................
  9560   9564   ** Only the data content may only be modified, it is not possible to 
  9561   9565   ** change the length of the data stored. If this function is called with
  9562   9566   ** parameters that attempt to write past the end of the existing data,
  9563   9567   ** no modifications are made and SQLITE_CORRUPT is returned.
  9564   9568   */
  9565   9569   int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
  9566   9570     int rc;
  9567         -  assert( cursorHoldsMutex(pCsr) );
         9571  +  assert( cursorOwnsBtShared(pCsr) );
  9568   9572     assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) );
  9569   9573     assert( pCsr->curFlags & BTCF_Incrblob );
  9570   9574   
  9571   9575     rc = restoreCursorPosition(pCsr);
  9572   9576     if( rc!=SQLITE_OK ){
  9573   9577       return rc;
  9574   9578     }
................................................................................
  9667   9671     return (p->pBt->btsFlags & BTS_READ_ONLY)!=0;
  9668   9672   }
  9669   9673   
  9670   9674   /*
  9671   9675   ** Return the size of the header added to each page by this module.
  9672   9676   */
  9673   9677   int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); }
         9678  +
         9679  +/*
         9680  +** Return true if the Btree passed as the only argument is sharable.
         9681  +*/
         9682  +int sqlite3BtreeSharable(Btree *p){
         9683  +  return p->sharable;
         9684  +}

Changes to src/btree.h.

   283    283   ** If we are not using shared cache, then there is no need to
   284    284   ** use mutexes to access the BtShared structures.  So make the
   285    285   ** Enter and Leave procedures no-ops.
   286    286   */
   287    287   #ifndef SQLITE_OMIT_SHARED_CACHE
   288    288     void sqlite3BtreeEnter(Btree*);
   289    289     void sqlite3BtreeEnterAll(sqlite3*);
          290  +  int sqlite3BtreeSharable(Btree*);
          291  +  void sqlite3BtreeEnterCursor(BtCursor*);
   290    292   #else
   291    293   # define sqlite3BtreeEnter(X) 
   292    294   # define sqlite3BtreeEnterAll(X)
          295  +# define sqlite3BtreeSharable(X) 0
          296  +# define sqlite3BtreeEnterCursor(X)
   293    297   #endif
   294    298   
   295    299   #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE
   296         -  int sqlite3BtreeSharable(Btree*);
   297    300     void sqlite3BtreeLeave(Btree*);
   298         -  void sqlite3BtreeEnterCursor(BtCursor*);
   299    301     void sqlite3BtreeLeaveCursor(BtCursor*);
   300    302     void sqlite3BtreeLeaveAll(sqlite3*);
   301    303   #ifndef NDEBUG
   302    304     /* These routines are used inside assert() statements only. */
   303    305     int sqlite3BtreeHoldsMutex(Btree*);
   304    306     int sqlite3BtreeHoldsAllMutexes(sqlite3*);
   305    307     int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*);
   306    308   #endif
   307    309   #else
   308    310   
   309         -# define sqlite3BtreeSharable(X) 0
   310    311   # define sqlite3BtreeLeave(X)
   311         -# define sqlite3BtreeEnterCursor(X)
   312    312   # define sqlite3BtreeLeaveCursor(X)
   313    313   # define sqlite3BtreeLeaveAll(X)
   314    314   
   315    315   # define sqlite3BtreeHoldsMutex(X) 1
   316    316   # define sqlite3BtreeHoldsAllMutexes(X) 1
   317    317   # define sqlite3SchemaMutexHeld(X,Y,Z) 1
   318    318   #endif
   319    319   
   320    320   
   321    321   #endif /* _BTREE_H_ */

Changes to src/vdbeInt.h.

   485    485   void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *);
   486    486   int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *);
   487    487   int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *);
   488    488   int sqlite3VdbeSorterRewind(const VdbeCursor *, int *);
   489    489   int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *);
   490    490   int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *);
   491    491   
   492         -#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
          492  +#if !defined(SQLITE_OMIT_SHARED_CACHE) 
   493    493     void sqlite3VdbeEnter(Vdbe*);
   494         -  void sqlite3VdbeLeave(Vdbe*);
   495    494   #else
   496    495   # define sqlite3VdbeEnter(X)
          496  +#endif
          497  +
          498  +#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
          499  +  void sqlite3VdbeLeave(Vdbe*);
          500  +#else
   497    501   # define sqlite3VdbeLeave(X)
   498    502   #endif
   499    503   
   500    504   #ifdef SQLITE_DEBUG
   501    505   void sqlite3VdbeMemAboutToChange(Vdbe*,Mem*);
   502    506   int sqlite3VdbeCheckMemInvariants(Mem*);
   503    507   #endif

Changes to src/vdbeaux.c.

  1313   1313     assert( i<(int)sizeof(p->btreeMask)*8 );
  1314   1314     DbMaskSet(p->btreeMask, i);
  1315   1315     if( i!=1 && sqlite3BtreeSharable(p->db->aDb[i].pBt) ){
  1316   1316       DbMaskSet(p->lockMask, i);
  1317   1317     }
  1318   1318   }
  1319   1319   
  1320         -#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
         1320  +#if !defined(SQLITE_OMIT_SHARED_CACHE)
  1321   1321   /*
  1322   1322   ** If SQLite is compiled to support shared-cache mode and to be threadsafe,
  1323   1323   ** this routine obtains the mutex associated with each BtShared structure
  1324   1324   ** that may be accessed by the VM passed as an argument. In doing so it also
  1325   1325   ** sets the BtShared.db member of each of the BtShared structures, ensuring
  1326   1326   ** that the correct busy-handler callback is invoked if required.
  1327   1327   **