/ Check-in [68e7a8c6]
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:Simplify the accessPayload() routine so that it always populates the overflow page cache. In the one case where populating the page cache can lead to problems, simply invalidate the cache as soon as accessPayload() returns. This simplification reduces code size and helps accessPayload() to run a little faster. This backs out the eOp==2 mode of accessPayload() added by check-in [da59198505].
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 68e7a8c6765649195ef1ad9407d87d44a307b462
User & Date: drh 2017-01-27 00:31:59
Context
2017-01-27
01:13
Performance optimization in accessPayload(). check-in: ebb1fd98 user: drh tags: trunk
00:31
Simplify the accessPayload() routine so that it always populates the overflow page cache. In the one case where populating the page cache can lead to problems, simply invalidate the cache as soon as accessPayload() returns. This simplification reduces code size and helps accessPayload() to run a little faster. This backs out the eOp==2 mode of accessPayload() added by check-in [da59198505]. check-in: 68e7a8c6 user: drh tags: trunk
2017-01-26
21:30
Remove an unreachable branch in the error handling logic for sqlite3BtreePayloadChecked(). check-in: 293bf3ed user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/btree.c.

  4420   4420   /*
  4421   4421   ** This function is used to read or overwrite payload information
  4422   4422   ** for the entry that the pCur cursor is pointing to. The eOp
  4423   4423   ** argument is interpreted as follows:
  4424   4424   **
  4425   4425   **   0: The operation is a read. Populate the overflow cache.
  4426   4426   **   1: The operation is a write. Populate the overflow cache.
  4427         -**   2: The operation is a read. Do not populate the overflow cache.
  4428   4427   **
  4429   4428   ** A total of "amt" bytes are read or written beginning at "offset".
  4430   4429   ** Data is read to or from the buffer pBuf.
  4431   4430   **
  4432   4431   ** The content being read or written might appear on the main page
  4433   4432   ** or be scattered out on multiple overflow pages.
  4434   4433   **
  4435         -** If the current cursor entry uses one or more overflow pages and the
  4436         -** eOp argument is not 2, this function may allocate space for and lazily 
  4437         -** populates the overflow page-list cache array (BtCursor.aOverflow). 
         4434  +** If the current cursor entry uses one or more overflow pages
         4435  +** this function may allocate space for and lazily populate
         4436  +** the overflow page-list cache array (BtCursor.aOverflow). 
  4438   4437   ** Subsequent calls use this cache to make seeking to the supplied offset 
  4439   4438   ** more efficient.
  4440   4439   **
  4441         -** Once an overflow page-list cache has been allocated, it may be
         4440  +** Once an overflow page-list cache has been allocated, it must be
  4442   4441   ** invalidated if some other cursor writes to the same table, or if
  4443   4442   ** the cursor is moved to a different row. Additionally, in auto-vacuum
  4444   4443   ** mode, the following events may invalidate an overflow page-list cache.
  4445   4444   **
  4446   4445   **   * An incremental vacuum,
  4447   4446   **   * A commit in auto_vacuum="full" mode,
  4448   4447   **   * Creating a table (may require moving an overflow page).
................................................................................
  4460   4459     MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */
  4461   4460     BtShared *pBt = pCur->pBt;                  /* Btree this cursor belongs to */
  4462   4461   #ifdef SQLITE_DIRECT_OVERFLOW_READ
  4463   4462     unsigned char * const pBufStart = pBuf;     /* Start of original out buffer */
  4464   4463   #endif
  4465   4464   
  4466   4465     assert( pPage );
         4466  +  assert( eOp==0 || eOp==1 );
  4467   4467     assert( pCur->eState==CURSOR_VALID );
  4468   4468     assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
  4469   4469     assert( cursorHoldsMutex(pCur) );
  4470         -  assert( eOp!=2 || offset==0 );    /* Always start from beginning for eOp==2 */
  4471   4470   
  4472   4471     getCellInfo(pCur);
  4473   4472     aPayload = pCur->info.pPayload;
  4474   4473     assert( offset+amt <= pCur->info.nPayload );
  4475   4474   
  4476   4475     assert( aPayload > pPage->aData );
  4477   4476     if( (uptr)(aPayload - pPage->aData) > (pBt->usableSize - pCur->info.nLocal) ){
................................................................................
  4485   4484   
  4486   4485     /* Check if data must be read/written to/from the btree page itself. */
  4487   4486     if( offset<pCur->info.nLocal ){
  4488   4487       int a = amt;
  4489   4488       if( a+offset>pCur->info.nLocal ){
  4490   4489         a = pCur->info.nLocal - offset;
  4491   4490       }
  4492         -    rc = copyPayload(&aPayload[offset], pBuf, a, (eOp & 0x01), pPage->pDbPage);
         4491  +    rc = copyPayload(&aPayload[offset], pBuf, a, eOp, pPage->pDbPage);
  4493   4492       offset = 0;
  4494   4493       pBuf += a;
  4495   4494       amt -= a;
  4496   4495     }else{
  4497   4496       offset -= pCur->info.nLocal;
  4498   4497     }
  4499   4498   
................................................................................
  4501   4500     if( rc==SQLITE_OK && amt>0 ){
  4502   4501       const u32 ovflSize = pBt->usableSize - 4;  /* Bytes content per ovfl page */
  4503   4502       Pgno nextPage;
  4504   4503   
  4505   4504       nextPage = get4byte(&aPayload[pCur->info.nLocal]);
  4506   4505   
  4507   4506       /* If the BtCursor.aOverflow[] has not been allocated, allocate it now.
  4508         -    ** Except, do not allocate aOverflow[] for eOp==2.
  4509   4507       **
  4510   4508       ** The aOverflow[] array is sized at one entry for each overflow page
  4511   4509       ** in the overflow chain. The page number of the first overflow page is
  4512   4510       ** stored in aOverflow[0], etc. A value of 0 in the aOverflow[] array
  4513   4511       ** means "not yet known" (the cache is lazily populated).
  4514   4512       */
  4515         -    if( eOp!=2 && (pCur->curFlags & BTCF_ValidOvfl)==0 ){
         4513  +    if( (pCur->curFlags & BTCF_ValidOvfl)==0 ){
  4516   4514         int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
  4517   4515         if( nOvfl>pCur->nOvflAlloc ){
  4518   4516           Pgno *aNew = (Pgno*)sqlite3Realloc(
  4519   4517               pCur->aOverflow, nOvfl*2*sizeof(Pgno)
  4520   4518           );
  4521   4519           if( aNew==0 ){
  4522   4520             return SQLITE_NOMEM_BKPT;
................................................................................
  4529   4527         pCur->curFlags |= BTCF_ValidOvfl;
  4530   4528       }
  4531   4529   
  4532   4530       /* If the overflow page-list cache has been allocated and the
  4533   4531       ** entry for the first required overflow page is valid, skip
  4534   4532       ** directly to it.
  4535   4533       */
  4536         -    if( (pCur->curFlags & BTCF_ValidOvfl)!=0
  4537         -     && pCur->aOverflow[offset/ovflSize]
  4538         -    ){
         4534  +    if( pCur->aOverflow[offset/ovflSize] ){
  4539   4535         iIdx = (offset/ovflSize);
  4540   4536         nextPage = pCur->aOverflow[iIdx];
  4541   4537         offset = (offset%ovflSize);
  4542   4538       }
  4543   4539   
  4544   4540       assert( rc==SQLITE_OK && amt>0 );
  4545   4541       while( nextPage ){
  4546   4542         /* If required, populate the overflow page-list cache. */
  4547         -      if( (pCur->curFlags & BTCF_ValidOvfl)!=0 ){
  4548         -        assert( pCur->aOverflow[iIdx]==0
  4549         -                || pCur->aOverflow[iIdx]==nextPage
  4550         -                || CORRUPT_DB );
  4551         -        pCur->aOverflow[iIdx] = nextPage;
  4552         -      }
         4543  +      assert( pCur->aOverflow[iIdx]==0
         4544  +              || pCur->aOverflow[iIdx]==nextPage
         4545  +              || CORRUPT_DB );
         4546  +      pCur->aOverflow[iIdx] = nextPage;
  4553   4547   
  4554   4548         if( offset>=ovflSize ){
  4555   4549           /* The only reason to read this page is to obtain the page
  4556   4550           ** number for the next page in the overflow chain. The page
  4557   4551           ** data is not required. So first try to lookup the overflow
  4558   4552           ** page-list cache, if any, then fall back to the getOverflowPage()
  4559   4553           ** function.
  4560         -        **
  4561         -        ** Note that the aOverflow[] array must be allocated because eOp!=2
  4562         -        ** here.  If eOp==2, then offset==0 and this branch is never taken.
  4563   4554           */
  4564         -        assert( eOp!=2 );
  4565   4555           assert( pCur->curFlags & BTCF_ValidOvfl );
  4566   4556           assert( pCur->pBtree->db==pBt->db );
  4567   4557           if( pCur->aOverflow[iIdx+1] ){
  4568   4558             nextPage = pCur->aOverflow[iIdx+1];
  4569   4559           }else{
  4570   4560             rc = getOverflowPage(pBt, nextPage, 0, &nextPage);
  4571   4561           }
................................................................................
  4592   4582           **   5) the page is not in the WAL file
  4593   4583           **   6) at least 4 bytes have already been read into the output buffer 
  4594   4584           **
  4595   4585           ** then data can be read directly from the database file into the
  4596   4586           ** output buffer, bypassing the page-cache altogether. This speeds
  4597   4587           ** up loading large records that span many overflow pages.
  4598   4588           */
  4599         -        if( (eOp&0x01)==0                                      /* (1) */
         4589  +        if( eOp==0                                             /* (1) */
  4600   4590            && offset==0                                          /* (2) */
  4601   4591            && pBt->inTransaction==TRANS_READ                     /* (3) */
  4602   4592            && (fd = sqlite3PagerFile(pBt->pPager))->pMethods     /* (4) */
  4603   4593            && 0==sqlite3PagerUseWal(pBt->pPager, nextPage)       /* (5) */
  4604   4594            && &pBuf[-4]>=pBufStart                               /* (6) */
  4605   4595           ){
  4606   4596             u8 aSave[4];
................................................................................
  4612   4602             memcpy(aWrite, aSave, 4);
  4613   4603           }else
  4614   4604   #endif
  4615   4605   
  4616   4606           {
  4617   4607             DbPage *pDbPage;
  4618   4608             rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage,
  4619         -              ((eOp&0x01)==0 ? PAGER_GET_READONLY : 0)
         4609  +              (eOp==0 ? PAGER_GET_READONLY : 0)
  4620   4610             );
  4621   4611             if( rc==SQLITE_OK ){
  4622   4612               aPayload = sqlite3PagerGetData(pDbPage);
  4623   4613               nextPage = get4byte(aPayload);
  4624         -            rc = copyPayload(&aPayload[offset+4], pBuf, a, (eOp&0x01), pDbPage);
         4614  +            rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage);
  4625   4615               sqlite3PagerUnref(pDbPage);
  4626   4616               offset = 0;
  4627   4617             }
  4628   4618           }
  4629   4619           amt -= a;
  4630   4620           pBuf += a;
  4631   4621         }
................................................................................
  5249   5239             }
  5250   5240             pCellKey = sqlite3Malloc( nCell+18 );
  5251   5241             if( pCellKey==0 ){
  5252   5242               rc = SQLITE_NOMEM_BKPT;
  5253   5243               goto moveto_finish;
  5254   5244             }
  5255   5245             pCur->aiIdx[pCur->iPage] = (u16)idx;
  5256         -          rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 2);
         5246  +          rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0);
         5247  +          pCur->curFlags &= ~BTCF_ValidOvfl;
  5257   5248             if( rc ){
  5258   5249               sqlite3_free(pCellKey);
  5259   5250               goto moveto_finish;
  5260   5251             }
  5261   5252             c = xRecordCompare(nCell, pCellKey, pIdxKey);
  5262   5253             sqlite3_free(pCellKey);
  5263   5254           }