/ Check-in [11949331]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Combine various boolean variables in the BtShared structure into a single boolean vector. Also make performance improvement simplifications to sqlite3BtreeMovetoUnpacked().
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 119493318e0ad4c2858fe1484b0d71669bd81531
User & Date: drh 2012-01-05 23:32:06
Context
2012-01-06
13:58
Add missing finish_test to the end of the zerodamage.test module. Disable the zerodamage module if virtual tables are omitted from the build. check-in: d2a5685b user: drh tags: trunk
2012-01-05
23:32
Combine various boolean variables in the BtShared structure into a single boolean vector. Also make performance improvement simplifications to sqlite3BtreeMovetoUnpacked(). check-in: 11949331 user: drh tags: trunk
21:19
Make sure the name of the shared memory file has two zero-terminators in the UNIX VFS, so that sqlite3_uri_parameter() will work correctly on that name. check-in: 3d088ba5 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/backup.c.

   701    701     ** checks this assumption - (p->rc) should be set to either SQLITE_DONE 
   702    702     ** or an error code.
   703    703     */
   704    704     sqlite3_backup_step(&b, 0x7FFFFFFF);
   705    705     assert( b.rc!=SQLITE_OK );
   706    706     rc = sqlite3_backup_finish(&b);
   707    707     if( rc==SQLITE_OK ){
   708         -    pTo->pBt->pageSizeFixed = 0;
          708  +    pTo->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED;
   709    709     }else{
   710    710       sqlite3PagerClearCache(sqlite3BtreePager(b.pDest));
   711    711     }
   712    712   
   713    713     assert( sqlite3BtreeIsInTrans(pTo)==0 );
   714    714     sqlite3BtreeLeave(pFrom);
   715    715     sqlite3BtreeLeave(pTo);
   716    716     return rc;
   717    717   }
   718    718   #endif /* SQLITE_OMIT_VACUUM */

Changes to src/btree.c.

   239    239     if( !p->sharable ){
   240    240       return SQLITE_OK;
   241    241     }
   242    242   
   243    243     /* If some other connection is holding an exclusive lock, the
   244    244     ** requested lock may not be obtained.
   245    245     */
   246         -  if( pBt->pWriter!=p && pBt->isExclusive ){
          246  +  if( pBt->pWriter!=p && (pBt->btsFlags & BTS_EXCLUSIVE)!=0 ){
   247    247       sqlite3ConnectionBlocked(p->db, pBt->pWriter->db);
   248    248       return SQLITE_LOCKED_SHAREDCACHE;
   249    249     }
   250    250   
   251    251     for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
   252    252       /* The condition (pIter->eLock!=eLock) in the following if(...) 
   253    253       ** statement is a simplification of:
................................................................................
   260    260       */
   261    261       assert( pIter->eLock==READ_LOCK || pIter->eLock==WRITE_LOCK );
   262    262       assert( eLock==READ_LOCK || pIter->pBtree==p || pIter->eLock==READ_LOCK);
   263    263       if( pIter->pBtree!=p && pIter->iTable==iTab && pIter->eLock!=eLock ){
   264    264         sqlite3ConnectionBlocked(p->db, pIter->pBtree->db);
   265    265         if( eLock==WRITE_LOCK ){
   266    266           assert( p==pBt->pWriter );
   267         -        pBt->isPending = 1;
          267  +        pBt->btsFlags |= BTS_PENDING;
   268    268         }
   269    269         return SQLITE_LOCKED_SHAREDCACHE;
   270    270       }
   271    271     }
   272    272     return SQLITE_OK;
   273    273   }
   274    274   #endif /* !SQLITE_OMIT_SHARED_CACHE */
................................................................................
   348    348   
   349    349   #ifndef SQLITE_OMIT_SHARED_CACHE
   350    350   /*
   351    351   ** Release all the table locks (locks obtained via calls to
   352    352   ** the setSharedCacheTableLock() procedure) held by Btree object p.
   353    353   **
   354    354   ** This function assumes that Btree p has an open read or write 
   355         -** transaction. If it does not, then the BtShared.isPending variable
          355  +** transaction. If it does not, then the BTS_PENDING flag
   356    356   ** may be incorrectly cleared.
   357    357   */
   358    358   static void clearAllSharedCacheTableLocks(Btree *p){
   359    359     BtShared *pBt = p->pBt;
   360    360     BtLock **ppIter = &pBt->pLock;
   361    361   
   362    362     assert( sqlite3BtreeHoldsMutex(p) );
   363    363     assert( p->sharable || 0==*ppIter );
   364    364     assert( p->inTrans>0 );
   365    365   
   366    366     while( *ppIter ){
   367    367       BtLock *pLock = *ppIter;
   368         -    assert( pBt->isExclusive==0 || pBt->pWriter==pLock->pBtree );
          368  +    assert( (pBt->btsFlags & BTS_EXCLUSIVE)==0 || pBt->pWriter==pLock->pBtree );
   369    369       assert( pLock->pBtree->inTrans>=pLock->eLock );
   370    370       if( pLock->pBtree==p ){
   371    371         *ppIter = pLock->pNext;
   372    372         assert( pLock->iTable!=1 || pLock==&p->lock );
   373    373         if( pLock->iTable!=1 ){
   374    374           sqlite3_free(pLock);
   375    375         }
   376    376       }else{
   377    377         ppIter = &pLock->pNext;
   378    378       }
   379    379     }
   380    380   
   381         -  assert( pBt->isPending==0 || pBt->pWriter );
          381  +  assert( (pBt->btsFlags & BTS_PENDING)==0 || pBt->pWriter );
   382    382     if( pBt->pWriter==p ){
   383    383       pBt->pWriter = 0;
   384         -    pBt->isExclusive = 0;
   385         -    pBt->isPending = 0;
          384  +    pBt->btsFlags &= ~(BTS_EXCLUSIVE|BTS_PENDING);
   386    385     }else if( pBt->nTransaction==2 ){
   387    386       /* This function is called when Btree p is concluding its 
   388    387       ** transaction. If there currently exists a writer, and p is not
   389    388       ** that writer, then the number of locks held by connections other
   390    389       ** than the writer must be about to drop to zero. In this case
   391         -    ** set the isPending flag to 0.
          390  +    ** set the BTS_PENDING flag to 0.
   392    391       **
   393         -    ** If there is not currently a writer, then BtShared.isPending must
          392  +    ** If there is not currently a writer, then BTS_PENDING must
   394    393       ** be zero already. So this next line is harmless in that case.
   395    394       */
   396         -    pBt->isPending = 0;
          395  +    pBt->btsFlags &= ~BTS_PENDING;
   397    396     }
   398    397   }
   399    398   
   400    399   /*
   401    400   ** This function changes all write-locks held by Btree p into read-locks.
   402    401   */
   403    402   static void downgradeAllSharedCacheTableLocks(Btree *p){
   404    403     BtShared *pBt = p->pBt;
   405    404     if( pBt->pWriter==p ){
   406    405       BtLock *pLock;
   407    406       pBt->pWriter = 0;
   408         -    pBt->isExclusive = 0;
   409         -    pBt->isPending = 0;
          407  +    pBt->btsFlags &= ~(BTS_EXCLUSIVE|BTS_PENDING);
   410    408       for(pLock=pBt->pLock; pLock; pLock=pLock->pNext){
   411    409         assert( pLock->eLock==READ_LOCK || pLock->pBtree==p );
   412    410         pLock->eLock = READ_LOCK;
   413    411       }
   414    412     }
   415    413   }
   416    414   
................................................................................
  1260   1258     assert( pPage->pBt!=0 );
  1261   1259     assert( sqlite3PagerIswriteable(pPage->pDbPage) );
  1262   1260     assert( start>=pPage->hdrOffset+6+pPage->childPtrSize );
  1263   1261     assert( (start + size) <= (int)pPage->pBt->usableSize );
  1264   1262     assert( sqlite3_mutex_held(pPage->pBt->mutex) );
  1265   1263     assert( size>=0 );   /* Minimum cell size is 4 */
  1266   1264   
  1267         -  if( pPage->pBt->secureDelete ){
         1265  +  if( pPage->pBt->btsFlags & BTS_SECURE_DELETE ){
  1268   1266       /* Overwrite deleted information with zeros when the secure_delete
  1269   1267       ** option is enabled */
  1270   1268       memset(&data[start], 0, size);
  1271   1269     }
  1272   1270   
  1273   1271     /* Add the space back into the linked list of freeblocks.  Note that
  1274   1272     ** even though the freeblock list was checked by btreeInitPage(),
................................................................................
  1363   1361       pPage->intKey = 0;
  1364   1362       pPage->hasData = 0;
  1365   1363       pPage->maxLocal = pBt->maxLocal;
  1366   1364       pPage->minLocal = pBt->minLocal;
  1367   1365     }else{
  1368   1366       return SQLITE_CORRUPT_BKPT;
  1369   1367     }
         1368  +  pPage->max1bytePayload = pBt->max1bytePayload;
  1370   1369     return SQLITE_OK;
  1371   1370   }
  1372   1371   
  1373   1372   /*
  1374   1373   ** Initialize the auxiliary information for a disk block.
  1375   1374   **
  1376   1375   ** Return SQLITE_OK on success.  If we see that the page does
................................................................................
  1498   1497     u16 first;
  1499   1498   
  1500   1499     assert( sqlite3PagerPagenumber(pPage->pDbPage)==pPage->pgno );
  1501   1500     assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage );
  1502   1501     assert( sqlite3PagerGetData(pPage->pDbPage) == data );
  1503   1502     assert( sqlite3PagerIswriteable(pPage->pDbPage) );
  1504   1503     assert( sqlite3_mutex_held(pBt->mutex) );
  1505         -  if( pBt->secureDelete ){
         1504  +  if( pBt->btsFlags & BTS_SECURE_DELETE ){
  1506   1505       memset(&data[hdr], 0, pBt->usableSize - hdr);
  1507   1506     }
  1508   1507     data[hdr] = (char)flags;
  1509   1508     first = hdr + 8 + 4*((flags&PTF_LEAF)==0 ?1:0);
  1510   1509     memset(&data[hdr+1], 0, 4);
  1511   1510     data[hdr+7] = 0;
  1512   1511     put2byte(&data[hdr+5], pBt->usableSize);
................................................................................
  1851   1850       pBt->openFlags = (u8)flags;
  1852   1851       pBt->db = db;
  1853   1852       sqlite3PagerSetBusyhandler(pBt->pPager, btreeInvokeBusyHandler, pBt);
  1854   1853       p->pBt = pBt;
  1855   1854     
  1856   1855       pBt->pCursor = 0;
  1857   1856       pBt->pPage1 = 0;
  1858         -    pBt->readOnly = sqlite3PagerIsreadonly(pBt->pPager);
         1857  +    if( sqlite3PagerIsreadonly(pBt->pPager) ) pBt->btsFlags |= BTS_READ_ONLY;
  1859   1858   #ifdef SQLITE_SECURE_DELETE
  1860         -    pBt->secureDelete = 1;
         1859  +    pBt->btsFlags |= BTS_SECURE_DELETE;
  1861   1860   #endif
  1862   1861       pBt->pageSize = (zDbHeader[16]<<8) | (zDbHeader[17]<<16);
  1863   1862       if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE
  1864   1863            || ((pBt->pageSize-1)&pBt->pageSize)!=0 ){
  1865   1864         pBt->pageSize = 0;
  1866   1865   #ifndef SQLITE_OMIT_AUTOVACUUM
  1867   1866         /* If the magic name ":memory:" will create an in-memory database, then
................................................................................
  1874   1873           pBt->autoVacuum = (SQLITE_DEFAULT_AUTOVACUUM ? 1 : 0);
  1875   1874           pBt->incrVacuum = (SQLITE_DEFAULT_AUTOVACUUM==2 ? 1 : 0);
  1876   1875         }
  1877   1876   #endif
  1878   1877         nReserve = 0;
  1879   1878       }else{
  1880   1879         nReserve = zDbHeader[20];
  1881         -      pBt->pageSizeFixed = 1;
         1880  +      pBt->btsFlags |= BTS_PAGESIZE_FIXED;
  1882   1881   #ifndef SQLITE_OMIT_AUTOVACUUM
  1883   1882         pBt->autoVacuum = (get4byte(&zDbHeader[36 + 4*4])?1:0);
  1884   1883         pBt->incrVacuum = (get4byte(&zDbHeader[36 + 7*4])?1:0);
  1885   1884   #endif
  1886   1885       }
  1887   1886       rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize, nReserve);
  1888   1887       if( rc ) goto btree_open_out;
................................................................................
  2162   2161   ** of the database file used for locking (beginning at PENDING_BYTE,
  2163   2162   ** the first byte past the 1GB boundary, 0x40000000) needs to occur
  2164   2163   ** at the beginning of a page.
  2165   2164   **
  2166   2165   ** If parameter nReserve is less than zero, then the number of reserved
  2167   2166   ** bytes per page is left unchanged.
  2168   2167   **
  2169         -** If the iFix!=0 then the pageSizeFixed flag is set so that the page size
         2168  +** If the iFix!=0 then the BTS_PAGESIZE_FIXED flag is set so that the page size
  2170   2169   ** and autovacuum mode can no longer be changed.
  2171   2170   */
  2172   2171   int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){
  2173   2172     int rc = SQLITE_OK;
  2174   2173     BtShared *pBt = p->pBt;
  2175   2174     assert( nReserve>=-1 && nReserve<=255 );
  2176   2175     sqlite3BtreeEnter(p);
  2177         -  if( pBt->pageSizeFixed ){
         2176  +  if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){
  2178   2177       sqlite3BtreeLeave(p);
  2179   2178       return SQLITE_READONLY;
  2180   2179     }
  2181   2180     if( nReserve<0 ){
  2182   2181       nReserve = pBt->pageSize - pBt->usableSize;
  2183   2182     }
  2184   2183     assert( nReserve>=0 && nReserve<=255 );
................................................................................
  2187   2186       assert( (pageSize & 7)==0 );
  2188   2187       assert( !pBt->pPage1 && !pBt->pCursor );
  2189   2188       pBt->pageSize = (u32)pageSize;
  2190   2189       freeTempSpace(pBt);
  2191   2190     }
  2192   2191     rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize, nReserve);
  2193   2192     pBt->usableSize = pBt->pageSize - (u16)nReserve;
  2194         -  if( iFix ) pBt->pageSizeFixed = 1;
         2193  +  if( iFix ) pBt->btsFlags |= BTS_PAGESIZE_FIXED;
  2195   2194     sqlite3BtreeLeave(p);
  2196   2195     return rc;
  2197   2196   }
  2198   2197   
  2199   2198   /*
  2200   2199   ** Return the currently defined page size
  2201   2200   */
................................................................................
  2227   2226     sqlite3BtreeEnter(p);
  2228   2227     n = sqlite3PagerMaxPageCount(p->pBt->pPager, mxPage);
  2229   2228     sqlite3BtreeLeave(p);
  2230   2229     return n;
  2231   2230   }
  2232   2231   
  2233   2232   /*
  2234         -** Set the secureDelete flag if newFlag is 0 or 1.  If newFlag is -1,
  2235         -** then make no changes.  Always return the value of the secureDelete
         2233  +** Set the BTS_SECURE_DELETE flag if newFlag is 0 or 1.  If newFlag is -1,
         2234  +** then make no changes.  Always return the value of the BTS_SECURE_DELETE
  2236   2235   ** setting after the change.
  2237   2236   */
  2238   2237   int sqlite3BtreeSecureDelete(Btree *p, int newFlag){
  2239   2238     int b;
  2240   2239     if( p==0 ) return 0;
  2241   2240     sqlite3BtreeEnter(p);
  2242   2241     if( newFlag>=0 ){
  2243         -    p->pBt->secureDelete = (newFlag!=0) ? 1 : 0;
         2242  +    p->pBt->btsFlags &= ~BTS_SECURE_DELETE;
         2243  +    if( newFlag ) p->pBt->btsFlags |= BTS_SECURE_DELETE;
  2244   2244     } 
  2245         -  b = p->pBt->secureDelete;
         2245  +  b = (p->pBt->btsFlags & BTS_SECURE_DELETE)!=0;
  2246   2246     sqlite3BtreeLeave(p);
  2247   2247     return b;
  2248   2248   }
  2249   2249   #endif /* !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM) */
  2250   2250   
  2251   2251   /*
  2252   2252   ** Change the 'auto-vacuum' property of the database. If the 'autoVacuum'
................................................................................
  2259   2259     return SQLITE_READONLY;
  2260   2260   #else
  2261   2261     BtShared *pBt = p->pBt;
  2262   2262     int rc = SQLITE_OK;
  2263   2263     u8 av = (u8)autoVacuum;
  2264   2264   
  2265   2265     sqlite3BtreeEnter(p);
  2266         -  if( pBt->pageSizeFixed && (av ?1:0)!=pBt->autoVacuum ){
         2266  +  if( (pBt->btsFlags & BTS_PAGESIZE_FIXED)!=0 && (av ?1:0)!=pBt->autoVacuum ){
  2267   2267       rc = SQLITE_READONLY;
  2268   2268     }else{
  2269   2269       pBt->autoVacuum = av ?1:0;
  2270   2270       pBt->incrVacuum = av==2 ?1:0;
  2271   2271     }
  2272   2272     sqlite3BtreeLeave(p);
  2273   2273     return rc;
................................................................................
  2333   2333       rc = SQLITE_NOTADB;
  2334   2334       if( memcmp(page1, zMagicHeader, 16)!=0 ){
  2335   2335         goto page1_init_failed;
  2336   2336       }
  2337   2337   
  2338   2338   #ifdef SQLITE_OMIT_WAL
  2339   2339       if( page1[18]>1 ){
  2340         -      pBt->readOnly = 1;
         2340  +      pBt->btsFlags |= BTS_READ_ONLY;
  2341   2341       }
  2342   2342       if( page1[19]>1 ){
  2343   2343         goto page1_init_failed;
  2344   2344       }
  2345   2345   #else
  2346   2346       if( page1[18]>2 ){
  2347         -      pBt->readOnly = 1;
         2347  +      pBt->btsFlags |= BTS_READ_ONLY;
  2348   2348       }
  2349   2349       if( page1[19]>2 ){
  2350   2350         goto page1_init_failed;
  2351   2351       }
  2352   2352   
  2353   2353       /* If the write version is set to 2, this database should be accessed
  2354   2354       ** in WAL mode. If the log is not already open, open it now. Then 
  2355   2355       ** return SQLITE_OK and return without populating BtShared.pPage1.
  2356   2356       ** The caller detects this and calls this function again. This is
  2357   2357       ** required as the version of page 1 currently in the page1 buffer
  2358   2358       ** may not be the latest version - there may be a newer one in the log
  2359   2359       ** file.
  2360   2360       */
  2361         -    if( page1[19]==2 && pBt->doNotUseWAL==0 ){
         2361  +    if( page1[19]==2 && (pBt->btsFlags & BTS_NO_WAL)==0 ){
  2362   2362         int isOpen = 0;
  2363   2363         rc = sqlite3PagerOpenWal(pBt->pPager, &isOpen);
  2364   2364         if( rc!=SQLITE_OK ){
  2365   2365           goto page1_init_failed;
  2366   2366         }else if( isOpen==0 ){
  2367   2367           releasePage(pPage1);
  2368   2368           return SQLITE_OK;
................................................................................
  2431   2431     ** 17 bytes long, 0 to N bytes of payload, and an optional 4 byte overflow
  2432   2432     ** page pointer.
  2433   2433     */
  2434   2434     pBt->maxLocal = (u16)((pBt->usableSize-12)*64/255 - 23);
  2435   2435     pBt->minLocal = (u16)((pBt->usableSize-12)*32/255 - 23);
  2436   2436     pBt->maxLeaf = (u16)(pBt->usableSize - 35);
  2437   2437     pBt->minLeaf = (u16)((pBt->usableSize-12)*32/255 - 23);
         2438  +  if( pBt->maxLocal>127 ){
         2439  +    pBt->max1bytePayload = 127;
         2440  +  }else{
         2441  +    pBt->max1bytePayload = pBt->maxLocal;
         2442  +  }
  2438   2443     assert( pBt->maxLeaf + 23 <= MX_CELL_SIZE(pBt) );
  2439   2444     pBt->pPage1 = pPage1;
  2440   2445     pBt->nPage = nPage;
  2441   2446     return SQLITE_OK;
  2442   2447   
  2443   2448   page1_init_failed:
  2444   2449     releasePage(pPage1);
................................................................................
  2494   2499     assert( pBt->usableSize<=pBt->pageSize && pBt->usableSize+255>=pBt->pageSize);
  2495   2500     data[20] = (u8)(pBt->pageSize - pBt->usableSize);
  2496   2501     data[21] = 64;
  2497   2502     data[22] = 32;
  2498   2503     data[23] = 32;
  2499   2504     memset(&data[24], 0, 100-24);
  2500   2505     zeroPage(pP1, PTF_INTKEY|PTF_LEAF|PTF_LEAFDATA );
  2501         -  pBt->pageSizeFixed = 1;
         2506  +  pBt->btsFlags |= BTS_PAGESIZE_FIXED;
  2502   2507   #ifndef SQLITE_OMIT_AUTOVACUUM
  2503   2508     assert( pBt->autoVacuum==1 || pBt->autoVacuum==0 );
  2504   2509     assert( pBt->incrVacuum==1 || pBt->incrVacuum==0 );
  2505   2510     put4byte(&data[36 + 4*4], pBt->autoVacuum);
  2506   2511     put4byte(&data[36 + 7*4], pBt->incrVacuum);
  2507   2512   #endif
  2508   2513     pBt->nPage = 1;
................................................................................
  2558   2563     ** is requested, this is a no-op.
  2559   2564     */
  2560   2565     if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){
  2561   2566       goto trans_begun;
  2562   2567     }
  2563   2568   
  2564   2569     /* Write transactions are not possible on a read-only database */
  2565         -  if( pBt->readOnly && wrflag ){
         2570  +  if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){
  2566   2571       rc = SQLITE_READONLY;
  2567   2572       goto trans_begun;
  2568   2573     }
  2569   2574   
  2570   2575   #ifndef SQLITE_OMIT_SHARED_CACHE
  2571   2576     /* If another database handle has already opened a write transaction 
  2572   2577     ** on this shared-btree structure and a second write transaction is
  2573   2578     ** requested, return SQLITE_LOCKED.
  2574   2579     */
  2575         -  if( (wrflag && pBt->inTransaction==TRANS_WRITE) || pBt->isPending ){
         2580  +  if( (wrflag && pBt->inTransaction==TRANS_WRITE)
         2581  +   || (pBt->btsFlags & BTS_PENDING)!=0
         2582  +  ){
  2576   2583       pBlock = pBt->pWriter->db;
  2577   2584     }else if( wrflag>1 ){
  2578   2585       BtLock *pIter;
  2579   2586       for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
  2580   2587         if( pIter->pBtree!=p ){
  2581   2588           pBlock = pIter->pBtree->db;
  2582   2589           break;
................................................................................
  2592   2599   
  2593   2600     /* Any read-only or read-write transaction implies a read-lock on 
  2594   2601     ** page 1. So if some other shared-cache client already has a write-lock 
  2595   2602     ** on page 1, the transaction cannot be opened. */
  2596   2603     rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK);
  2597   2604     if( SQLITE_OK!=rc ) goto trans_begun;
  2598   2605   
  2599         -  pBt->initiallyEmpty = (u8)(pBt->nPage==0);
         2606  +  pBt->btsFlags &= ~BTS_INITIALLY_EMPTY;
         2607  +  if( pBt->nPage==0 ) pBt->btsFlags |= BTS_INITIALLY_EMPTY;
  2600   2608     do {
  2601   2609       /* Call lockBtree() until either pBt->pPage1 is populated or
  2602   2610       ** lockBtree() returns something other than SQLITE_OK. lockBtree()
  2603   2611       ** may return SQLITE_OK but leave pBt->pPage1 set to 0 if after
  2604   2612       ** reading page 1 it discovers that the page-size of the database 
  2605   2613       ** file is not pBt->pageSize. In this case lockBtree() will update
  2606   2614       ** pBt->pageSize to the page-size of the file on disk.
  2607   2615       */
  2608   2616       while( pBt->pPage1==0 && SQLITE_OK==(rc = lockBtree(pBt)) );
  2609   2617   
  2610   2618       if( rc==SQLITE_OK && wrflag ){
  2611         -      if( pBt->readOnly ){
         2619  +      if( (pBt->btsFlags & BTS_READ_ONLY)!=0 ){
  2612   2620           rc = SQLITE_READONLY;
  2613   2621         }else{
  2614   2622           rc = sqlite3PagerBegin(pBt->pPager,wrflag>1,sqlite3TempInMemory(p->db));
  2615   2623           if( rc==SQLITE_OK ){
  2616   2624             rc = newDatabase(pBt);
  2617   2625           }
  2618   2626         }
................................................................................
  2641   2649         pBt->inTransaction = p->inTrans;
  2642   2650       }
  2643   2651       if( wrflag ){
  2644   2652         MemPage *pPage1 = pBt->pPage1;
  2645   2653   #ifndef SQLITE_OMIT_SHARED_CACHE
  2646   2654         assert( !pBt->pWriter );
  2647   2655         pBt->pWriter = p;
  2648         -      pBt->isExclusive = (u8)(wrflag>1);
         2656  +      pBt->btsFlags &= ~BTS_EXCLUSIVE;
         2657  +      if( wrflag>1 ) pBt->btsFlags |= BTS_EXCLUSIVE;
  2649   2658   #endif
  2650   2659   
  2651   2660         /* If the db-size header field is incorrect (as it may be if an old
  2652   2661         ** client has been writing the database file), update it now. Doing
  2653   2662         ** this sooner rather than later means the database size can safely 
  2654   2663         ** re-read the database size from page 1 if a savepoint or transaction
  2655   2664         ** rollback occurs within the transaction.
................................................................................
  3370   3379   ** using the sqlite3BtreeSavepoint() function.
  3371   3380   */
  3372   3381   int sqlite3BtreeBeginStmt(Btree *p, int iStatement){
  3373   3382     int rc;
  3374   3383     BtShared *pBt = p->pBt;
  3375   3384     sqlite3BtreeEnter(p);
  3376   3385     assert( p->inTrans==TRANS_WRITE );
  3377         -  assert( pBt->readOnly==0 );
         3386  +  assert( (pBt->btsFlags & BTS_READ_ONLY)==0 );
  3378   3387     assert( iStatement>0 );
  3379   3388     assert( iStatement>p->db->nSavepoint );
  3380   3389     assert( pBt->inTransaction==TRANS_WRITE );
  3381   3390     /* At the pager level, a statement transaction is a savepoint with
  3382   3391     ** an index greater than all savepoints created explicitly using
  3383   3392     ** SQL statements. It is illegal to open, release or rollback any
  3384   3393     ** such savepoints while the statement transaction savepoint is active.
................................................................................
  3405   3414     if( p && p->inTrans==TRANS_WRITE ){
  3406   3415       BtShared *pBt = p->pBt;
  3407   3416       assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK );
  3408   3417       assert( iSavepoint>=0 || (iSavepoint==-1 && op==SAVEPOINT_ROLLBACK) );
  3409   3418       sqlite3BtreeEnter(p);
  3410   3419       rc = sqlite3PagerSavepoint(pBt->pPager, op, iSavepoint);
  3411   3420       if( rc==SQLITE_OK ){
  3412         -      if( iSavepoint<0 && pBt->initiallyEmpty ) pBt->nPage = 0;
         3421  +      if( iSavepoint<0 && (pBt->btsFlags & BTS_INITIALLY_EMPTY)!=0 ){
         3422  +        pBt->nPage = 0;
         3423  +      }
  3413   3424         rc = newDatabase(pBt);
  3414   3425         pBt->nPage = get4byte(28 + pBt->pPage1->aData);
  3415   3426   
  3416   3427         /* The database size was written into the offset 28 of the header
  3417   3428         ** when the transaction started, so we know that the value at offset
  3418   3429         ** 28 is nonzero. */
  3419   3430         assert( pBt->nPage>0 );
................................................................................
  3475   3486     assert( wrFlag==0 || !hasReadConflicts(p, iTable) );
  3476   3487   
  3477   3488     /* Assert that the caller has opened the required transaction. */
  3478   3489     assert( p->inTrans>TRANS_NONE );
  3479   3490     assert( wrFlag==0 || p->inTrans==TRANS_WRITE );
  3480   3491     assert( pBt->pPage1 && pBt->pPage1->aData );
  3481   3492   
  3482         -  if( NEVER(wrFlag && pBt->readOnly) ){
         3493  +  if( NEVER(wrFlag && (pBt->btsFlags & BTS_READ_ONLY)!=0) ){
  3483   3494       return SQLITE_READONLY;
  3484   3495     }
  3485   3496     if( iTable==1 && btreePagecount(pBt)==0 ){
  3486   3497       assert( wrFlag==0 );
  3487   3498       iTable = 0;
  3488   3499     }
  3489   3500   
................................................................................
  4555   4566           ** page is less than 16384 bytes and may be stored as a 2-byte
  4556   4567           ** varint. This information is used to attempt to avoid parsing 
  4557   4568           ** the entire cell by checking for the cases where the record is 
  4558   4569           ** stored entirely within the b-tree page by inspecting the first 
  4559   4570           ** 2 bytes of the cell.
  4560   4571           */
  4561   4572           int nCell = pCell[0];
  4562         -        if( !(nCell & 0x80)
  4563         -         && nCell<=pPage->maxLocal
  4564         -         && (pCell+nCell+1)<=pPage->aDataEnd
         4573  +        if( nCell<=pPage->max1bytePayload
         4574  +         /* && (pCell+nCell)<pPage->aDataEnd */
  4565   4575           ){
  4566   4576             /* This branch runs if the record-size field of the cell is a
  4567   4577             ** single byte varint and the record fits entirely on the main
  4568   4578             ** b-tree page.  */
  4569   4579             testcase( pCell+nCell+1==pPage->aDataEnd );
  4570   4580             c = sqlite3VdbeRecordCompare(nCell, (void*)&pCell[1], pIdxKey);
  4571   4581           }else if( !(pCell[1] & 0x80) 
  4572   4582             && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal
  4573         -          && (pCell+nCell+2)<=pPage->aDataEnd
         4583  +          /* && (pCell+nCell+2)<=pPage->aDataEnd */
  4574   4584           ){
  4575   4585             /* The record-size field is a 2 byte varint and the record 
  4576   4586             ** fits entirely on the main b-tree page.  */
  4577   4587             testcase( pCell+nCell+2==pPage->aDataEnd );
  4578   4588             c = sqlite3VdbeRecordCompare(nCell, (void*)&pCell[2], pIdxKey);
  4579   4589           }else{
  4580   4590             /* The record flows over onto one or more overflow pages. In
................................................................................
  5112   5122   
  5113   5123     /* Increment the free page count on pPage1 */
  5114   5124     rc = sqlite3PagerWrite(pPage1->pDbPage);
  5115   5125     if( rc ) goto freepage_out;
  5116   5126     nFree = get4byte(&pPage1->aData[36]);
  5117   5127     put4byte(&pPage1->aData[36], nFree+1);
  5118   5128   
  5119         -  if( pBt->secureDelete ){
         5129  +  if( pBt->btsFlags & BTS_SECURE_DELETE ){
  5120   5130       /* If the secure_delete option is enabled, then
  5121   5131       ** always fully overwrite deleted information with zeros.
  5122   5132       */
  5123   5133       if( (!pPage && ((rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0) )
  5124   5134        ||            ((rc = sqlite3PagerWrite(pPage->pDbPage))!=0)
  5125   5135       ){
  5126   5136         goto freepage_out;
................................................................................
  5173   5183         ** to 3.6.0 or later) we should consider fixing the conditional above
  5174   5184         ** to read "usableSize/4-2" instead of "usableSize/4-8".
  5175   5185         */
  5176   5186         rc = sqlite3PagerWrite(pTrunk->pDbPage);
  5177   5187         if( rc==SQLITE_OK ){
  5178   5188           put4byte(&pTrunk->aData[4], nLeaf+1);
  5179   5189           put4byte(&pTrunk->aData[8+nLeaf*4], iPage);
  5180         -        if( pPage && !pBt->secureDelete ){
         5190  +        if( pPage && (pBt->btsFlags & BTS_SECURE_DELETE)==0 ){
  5181   5191             sqlite3PagerDontWrite(pPage->pDbPage);
  5182   5192           }
  5183   5193           rc = btreeSetHasContent(pBt, iPage);
  5184   5194         }
  5185   5195         TRACE(("FREE-PAGE: %d leaf on trunk page %d\n",pPage->pgno,pTrunk->pgno));
  5186   5196         goto freepage_out;
  5187   5197       }
................................................................................
  6014   6024         ** later on.  
  6015   6025         **
  6016   6026         ** But not if we are in secure-delete mode. In secure-delete mode,
  6017   6027         ** the dropCell() routine will overwrite the entire cell with zeroes.
  6018   6028         ** In this case, temporarily copy the cell into the aOvflSpace[]
  6019   6029         ** buffer. It will be copied out again as soon as the aSpace[] buffer
  6020   6030         ** is allocated.  */
  6021         -      if( pBt->secureDelete ){
         6031  +      if( pBt->btsFlags & BTS_SECURE_DELETE ){
  6022   6032           int iOff;
  6023   6033   
  6024   6034           iOff = SQLITE_PTR_TO_INT(apDiv[i]) - SQLITE_PTR_TO_INT(pParent->aData);
  6025   6035           if( (iOff+szNew[i])>(int)pBt->usableSize ){
  6026   6036             rc = SQLITE_CORRUPT_BKPT;
  6027   6037             memset(apOld, 0, (i+1)*sizeof(MemPage*));
  6028   6038             goto balance_cleanup;
................................................................................
  6756   6766   
  6757   6767     if( pCur->eState==CURSOR_FAULT ){
  6758   6768       assert( pCur->skipNext!=SQLITE_OK );
  6759   6769       return pCur->skipNext;
  6760   6770     }
  6761   6771   
  6762   6772     assert( cursorHoldsMutex(pCur) );
  6763         -  assert( pCur->wrFlag && pBt->inTransaction==TRANS_WRITE && !pBt->readOnly );
         6773  +  assert( pCur->wrFlag && pBt->inTransaction==TRANS_WRITE
         6774  +              && (pBt->btsFlags & BTS_READ_ONLY)==0 );
  6764   6775     assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
  6765   6776   
  6766   6777     /* Assert that the caller has been consistent. If this cursor was opened
  6767   6778     ** expecting an index b-tree, then the caller should be inserting blob
  6768   6779     ** keys with no associated data. If the cursor was opened expecting an
  6769   6780     ** intkey table, the caller should be inserting integer keys with a
  6770   6781     ** blob of associated data.  */
................................................................................
  6885   6896     MemPage *pPage;                      /* Page to delete cell from */
  6886   6897     unsigned char *pCell;                /* Pointer to cell to delete */
  6887   6898     int iCellIdx;                        /* Index of cell to delete */
  6888   6899     int iCellDepth;                      /* Depth of node containing pCell */ 
  6889   6900   
  6890   6901     assert( cursorHoldsMutex(pCur) );
  6891   6902     assert( pBt->inTransaction==TRANS_WRITE );
  6892         -  assert( !pBt->readOnly );
         6903  +  assert( (pBt->btsFlags & BTS_READ_ONLY)==0 );
  6893   6904     assert( pCur->wrFlag );
  6894   6905     assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
  6895   6906     assert( !hasReadConflicts(p, pCur->pgnoRoot) );
  6896   6907   
  6897   6908     if( NEVER(pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell) 
  6898   6909      || NEVER(pCur->eState!=CURSOR_VALID)
  6899   6910     ){
................................................................................
  7006   7017     MemPage *pRoot;
  7007   7018     Pgno pgnoRoot;
  7008   7019     int rc;
  7009   7020     int ptfFlags;          /* Page-type flage for the root page of new table */
  7010   7021   
  7011   7022     assert( sqlite3BtreeHoldsMutex(p) );
  7012   7023     assert( pBt->inTransaction==TRANS_WRITE );
  7013         -  assert( !pBt->readOnly );
         7024  +  assert( (pBt->btsFlags & BTS_READ_ONLY)==0 );
  7014   7025   
  7015   7026   #ifdef SQLITE_OMIT_AUTOVACUUM
  7016   7027     rc = allocateBtreePage(pBt, &pRoot, &pgnoRoot, 1, 0);
  7017   7028     if( rc ){
  7018   7029       return rc;
  7019   7030     }
  7020   7031   #else
................................................................................
  7380   7391     assert( idx>=0 && idx<=15 );
  7381   7392   
  7382   7393     *pMeta = get4byte(&pBt->pPage1->aData[36 + idx*4]);
  7383   7394   
  7384   7395     /* If auto-vacuum is disabled in this build and this is an auto-vacuum
  7385   7396     ** database, mark the database as read-only.  */
  7386   7397   #ifdef SQLITE_OMIT_AUTOVACUUM
  7387         -  if( idx==BTREE_LARGEST_ROOT_PAGE && *pMeta>0 ) pBt->readOnly = 1;
         7398  +  if( idx==BTREE_LARGEST_ROOT_PAGE && *pMeta>0 ){
         7399  +    pBt->btsFlags |= BTS_READ_ONLY;
         7400  +  }
  7388   7401   #endif
  7389   7402   
  7390   7403     sqlite3BtreeLeave(p);
  7391   7404   }
  7392   7405   
  7393   7406   /*
  7394   7407   ** Write meta-information back into the database.  Meta[0] is
................................................................................
  8180   8193     **   (c) the connection holds a write-lock on the table (if required),
  8181   8194     **   (d) there are no conflicting read-locks, and
  8182   8195     **   (e) the cursor points at a valid row of an intKey table.
  8183   8196     */
  8184   8197     if( !pCsr->wrFlag ){
  8185   8198       return SQLITE_READONLY;
  8186   8199     }
  8187         -  assert( !pCsr->pBt->readOnly && pCsr->pBt->inTransaction==TRANS_WRITE );
         8200  +  assert( (pCsr->pBt->btsFlags & BTS_READ_ONLY)==0
         8201  +              && pCsr->pBt->inTransaction==TRANS_WRITE );
  8188   8202     assert( hasSharedCacheTableLock(pCsr->pBtree, pCsr->pgnoRoot, 0, 2) );
  8189   8203     assert( !hasReadConflicts(pCsr->pBtree, pCsr->pgnoRoot) );
  8190   8204     assert( pCsr->apPage[pCsr->iPage]->intKey );
  8191   8205   
  8192   8206     return accessPayload(pCsr, offset, amt, (unsigned char *)z, 1);
  8193   8207   }
  8194   8208   
................................................................................
  8220   8234     int rc;                         /* Return code */
  8221   8235    
  8222   8236     assert( iVersion==1 || iVersion==2 );
  8223   8237   
  8224   8238     /* If setting the version fields to 1, do not automatically open the
  8225   8239     ** WAL connection, even if the version fields are currently set to 2.
  8226   8240     */
  8227         -  pBt->doNotUseWAL = (u8)(iVersion==1);
         8241  +  pBt->btsFlags &= ~BTS_NO_WAL;
         8242  +  if( iVersion==1 ) pBt->btsFlags |= BTS_NO_WAL;
  8228   8243   
  8229   8244     rc = sqlite3BtreeBeginTrans(pBtree, 0);
  8230   8245     if( rc==SQLITE_OK ){
  8231   8246       u8 *aData = pBt->pPage1->aData;
  8232   8247       if( aData[18]!=(u8)iVersion || aData[19]!=(u8)iVersion ){
  8233   8248         rc = sqlite3BtreeBeginTrans(pBtree, 2);
  8234   8249         if( rc==SQLITE_OK ){
................................................................................
  8237   8252             aData[18] = (u8)iVersion;
  8238   8253             aData[19] = (u8)iVersion;
  8239   8254           }
  8240   8255         }
  8241   8256       }
  8242   8257     }
  8243   8258   
  8244         -  pBt->doNotUseWAL = 0;
         8259  +  pBt->btsFlags &= ~BTS_NO_WAL;
  8245   8260     return rc;
  8246   8261   }

Changes to src/btreeInt.h.

   273    273     u8 isInit;           /* True if previously initialized. MUST BE FIRST! */
   274    274     u8 nOverflow;        /* Number of overflow cell bodies in aCell[] */
   275    275     u8 intKey;           /* True if intkey flag is set */
   276    276     u8 leaf;             /* True if leaf flag is set */
   277    277     u8 hasData;          /* True if this page stores data */
   278    278     u8 hdrOffset;        /* 100 for page 1.  0 otherwise */
   279    279     u8 childPtrSize;     /* 0 if leaf==1.  4 if leaf==0 */
          280  +  u8 max1bytePayload;  /* min(maxLocal,127) */
   280    281     u16 maxLocal;        /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
   281    282     u16 minLocal;        /* Copy of BtShared.minLocal or BtShared.minLeaf */
   282    283     u16 cellOffset;      /* Index in aData of first cell pointer */
   283    284     u16 nFree;           /* Number of free bytes on the page */
   284    285     u16 nCell;           /* Number of cells on this page, local and ovfl */
   285    286     u16 maskPage;        /* Mask for page offset */
   286    287     struct _OvflCell {   /* Cells that will not fit on aData[] */
................................................................................
   403    404   **   This feature is included to help prevent writer-starvation.
   404    405   */
   405    406   struct BtShared {
   406    407     Pager *pPager;        /* The page cache */
   407    408     sqlite3 *db;          /* Database connection currently using this Btree */
   408    409     BtCursor *pCursor;    /* A list of all open cursors */
   409    410     MemPage *pPage1;      /* First page of the database */
   410         -  u8 readOnly;          /* True if the underlying file is readonly */
   411         -  u8 pageSizeFixed;     /* True if the page size can no longer be changed */
   412         -  u8 secureDelete;      /* True if secure_delete is enabled */
   413         -  u8 initiallyEmpty;    /* Database is empty at start of transaction */
   414    411     u8 openFlags;         /* Flags to sqlite3BtreeOpen() */
   415    412   #ifndef SQLITE_OMIT_AUTOVACUUM
   416    413     u8 autoVacuum;        /* True if auto-vacuum is enabled */
   417    414     u8 incrVacuum;        /* True if incr-vacuum is enabled */
   418    415   #endif
   419    416     u8 inTransaction;     /* Transaction state */
   420         -  u8 doNotUseWAL;       /* If true, do not open write-ahead-log file */
          417  +  u8 max1bytePayload;   /* Maximum first byte of cell for a 1-byte payload */
          418  +  u16 btsFlags;         /* Boolean parameters.  See BTS_* macros below */
   421    419     u16 maxLocal;         /* Maximum local payload in non-LEAFDATA tables */
   422    420     u16 minLocal;         /* Minimum local payload in non-LEAFDATA tables */
   423    421     u16 maxLeaf;          /* Maximum local payload in a LEAFDATA table */
   424    422     u16 minLeaf;          /* Minimum local payload in a LEAFDATA table */
   425    423     u32 pageSize;         /* Total number of bytes on a page */
   426    424     u32 usableSize;       /* Number of usable bytes on each page */
   427    425     int nTransaction;     /* Number of open transactions (read + write) */
................................................................................
   431    429     sqlite3_mutex *mutex; /* Non-recursive mutex required to access this object */
   432    430     Bitvec *pHasContent;  /* Set of pages moved to free-list this transaction */
   433    431   #ifndef SQLITE_OMIT_SHARED_CACHE
   434    432     int nRef;             /* Number of references to this structure */
   435    433     BtShared *pNext;      /* Next on a list of sharable BtShared structs */
   436    434     BtLock *pLock;        /* List of locks held on this shared-btree struct */
   437    435     Btree *pWriter;       /* Btree with currently open write transaction */
   438         -  u8 isExclusive;       /* True if pWriter has an EXCLUSIVE lock on the db */
   439         -  u8 isPending;         /* If waiting for read-locks to clear */
   440    436   #endif
   441    437     u8 *pTmpSpace;        /* BtShared.pageSize bytes of space for tmp use */
   442    438   };
   443    439   
          440  +/*
          441  +** Allowed values for BtShared.btsFlags
          442  +*/
          443  +#define BTS_READ_ONLY        0x0001   /* Underlying file is readonly */
          444  +#define BTS_PAGESIZE_FIXED   0x0002   /* Page size can no longer be changed */
          445  +#define BTS_SECURE_DELETE    0x0004   /* PRAGMA secure_delete is enabled */
          446  +#define BTS_INITIALLY_EMPTY  0x0008   /* Database was empty at trans start */
          447  +#define BTS_NO_WAL           0x0010   /* Do not open write-ahead-log files */
          448  +#define BTS_EXCLUSIVE        0x0020   /* pWriter has an exclusive lock */
          449  +#define BTS_PENDING          0x0040   /* Waiting for read-locks to clear */
          450  +
   444    451   /*
   445    452   ** An instance of the following structure is used to hold information
   446    453   ** about a cell.  The parseCellPtr() function fills in this structure
   447    454   ** based on information extract from the raw disk page.
   448    455   */
   449    456   typedef struct CellInfo CellInfo;
   450    457   struct CellInfo {