/ Check-in [67df4446]
Login

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

Overview
Comment:Further refinements to the virtual method implementation of sqlite3PagerGet().
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | pager-get-method
Files: files | file ages | folders
SHA1: 67df44464847b43f8c0b186157e31cc66c1e5796
User & Date: drh 2016-12-13 15:53:22
Context
2016-12-13
18:34
In the pager, avoid checking for the illegal page number 0 except when creating a new page. Closed-Leaf check-in: dee20ba9 user: drh tags: pager-get-method
15:53
Further refinements to the virtual method implementation of sqlite3PagerGet(). check-in: 67df4446 user: drh tags: pager-get-method
14:32
Make the sqlite3PagerGet() interface into a virtual method, with different implementations based on the current state of the pager. This gives a small performance increase by avoiding unnecessary branches inside the various methods. check-in: df5bb90d user: drh tags: pager-get-method
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/pager.c.

  1018   1018   
  1019   1019     return zRet;
  1020   1020   }
  1021   1021   #endif
  1022   1022   
  1023   1023   /* Forward references to the various page getters */
  1024   1024   static int getPageNormal(Pager*,Pgno,DbPage**,int);
  1025         -static int getPageMMap(Pager*,Pgno,DbPage**,int);
  1026   1025   static int getPageError(Pager*,Pgno,DbPage**,int);
         1026  +#if SQLITE_MAX_MMAP_SIZE>0
         1027  +static int getPageMMap(Pager*,Pgno,DbPage**,int);
         1028  +#endif
  1027   1029   
  1028   1030   /*
  1029   1031   ** Set the Pager.xGet method for the appropriate routine used to fetch
  1030   1032   ** content from the pager.
  1031   1033   */
  1032   1034   static void setGetterMethod(Pager *pPager){
  1033   1035     if( pPager->errCode ){
  1034   1036       pPager->xGet = getPageError;
         1037  +#if SQLITE_MAX_MMAP_SIZE>0
  1035   1038     }else if( USEFETCH(pPager)
  1036   1039   #ifdef SQLITE_HAS_CODEC
  1037   1040      && pPager->xCodec==0
  1038   1041   #endif
  1039   1042     ){
  1040   1043       pPager->xGet = getPageMMap;
         1044  +#endif /* SQLITE_MAX_MMAP_SIZE>0 */
  1041   1045     }else{
  1042   1046       pPager->xGet = getPageNormal;
  1043   1047     }
  1044   1048   }
  1045   1049   
  1046   1050   /*
  1047   1051   ** Return true if it is necessary to write page *pPg into the sub-journal.
................................................................................
  5291   5295   static void pagerUnlockIfUnused(Pager *pPager){
  5292   5296     if( pPager->nMmapOut==0 && (sqlite3PcacheRefCount(pPager->pPCache)==0) ){
  5293   5297       pagerUnlockAndRollback(pPager);
  5294   5298     }
  5295   5299   }
  5296   5300   
  5297   5301   /*
  5298         -** Acquire a reference to page number pgno in pager pPager (a page
  5299         -** reference has type DbPage*). If the requested reference is 
         5302  +** The page getter methods each try to acquire a reference to a
         5303  +** page with page number pgno. If the requested reference is 
  5300   5304   ** successfully obtained, it is copied to *ppPage and SQLITE_OK returned.
  5301   5305   **
         5306  +** There are different implementations of the getter method depending
         5307  +** on the current state of the pager.
         5308  +**
         5309  +**     getPageNormal()         --  The normal getter
         5310  +**     getPageError()          --  Used if the pager is in an error state
         5311  +**     getPageMmap()           --  Used if memory-mapped I/O is enabled
         5312  +**
  5302   5313   ** If the requested page is already in the cache, it is returned. 
  5303   5314   ** Otherwise, a new page object is allocated and populated with data
  5304   5315   ** read from the database file. In some cases, the pcache module may
  5305   5316   ** choose not to allocate a new page object and may reuse an existing
  5306   5317   ** object with no outstanding references.
  5307   5318   **
  5308   5319   ** The extra data appended to a page is always initialized to zeros the 
  5309   5320   ** first time a page is loaded into memory. If the page requested is 
  5310   5321   ** already in the cache when this function is called, then the extra
  5311   5322   ** data is left as it was when the page object was last used.
  5312   5323   **
  5313         -** If the database image is smaller than the requested page or if a 
  5314         -** non-zero value is passed as the noContent parameter and the 
         5324  +** If the database image is smaller than the requested page or if 
         5325  +** the flags parameter contains the PAGER_GET_NOCONTENT bit and the 
  5315   5326   ** requested page is not already stored in the cache, then no 
  5316   5327   ** actual disk read occurs. In this case the memory image of the 
  5317   5328   ** page is initialized to all zeros. 
  5318   5329   **
  5319         -** If noContent is true, it means that we do not care about the contents
  5320         -** of the page. This occurs in two scenarios:
         5330  +** If PAGER_GET_NOCONTENT is true, it means that we do not care about
         5331  +** the contents of the page. This occurs in two scenarios:
  5321   5332   **
  5322   5333   **   a) When reading a free-list leaf page from the database, and
  5323   5334   **
  5324   5335   **   b) When a savepoint is being rolled back and we need to load
  5325   5336   **      a new page into the cache to be filled with the data read
  5326   5337   **      from the savepoint journal.
  5327   5338   **
  5328         -** If noContent is true, then the data returned is zeroed instead of
  5329         -** being read from the database. Additionally, the bits corresponding
         5339  +** If PAGER_GET_NOCONTENT is true, then the data returned is zeroed instead
         5340  +** of being read from the database. Additionally, the bits corresponding
  5330   5341   ** to pgno in Pager.pInJournal (bitvec of pages already written to the
  5331   5342   ** journal file) and the PagerSavepoint.pInSavepoint bitvecs of any open
  5332   5343   ** savepoints are set. This means if the page is made writable at any
  5333   5344   ** point in the future, using a call to sqlite3PagerWrite(), its contents
  5334   5345   ** will not be journaled. This saves IO.
  5335   5346   **
  5336   5347   ** The acquisition might fail for several reasons.  In all cases,
................................................................................
  5347   5358   static int getPageNormal(
  5348   5359     Pager *pPager,      /* The pager open on the database file */
  5349   5360     Pgno pgno,          /* Page number to fetch */
  5350   5361     DbPage **ppPage,    /* Write a pointer to the page here */
  5351   5362     int flags           /* PAGER_GET_XXX flags */
  5352   5363   ){
  5353   5364     int rc = SQLITE_OK;
  5354         -  PgHdr *pPg = 0;
  5355         -  u32 iFrame = 0;                 /* Frame to read from WAL file */
  5356         -  const int noContent = (flags & PAGER_GET_NOCONTENT);
         5365  +  PgHdr *pPg;
         5366  +  u8 noContent;                   /* True if PAGER_GET_NOCONTENT is set */
  5357   5367     sqlite3_pcache_page *pBase;
  5358   5368   
  5359   5369     if( pgno==0 ){
  5360   5370       return SQLITE_CORRUPT_BKPT;
  5361   5371     }
  5362   5372     assert( pPager->errCode==SQLITE_OK );
  5363   5373     assert( pPager->eState>=PAGER_READER );
  5364   5374     assert( assert_pager_state(pPager) );
  5365   5375     assert( pPager->hasHeldSharedLock==1 );
  5366   5376   
  5367   5377   
  5368   5378     pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3);
  5369   5379     if( pBase==0 ){
         5380  +    pPg = 0;
  5370   5381       rc = sqlite3PcacheFetchStress(pPager->pPCache, pgno, &pBase);
  5371   5382       if( rc!=SQLITE_OK ) goto pager_acquire_err;
  5372   5383       if( pBase==0 ){
  5373         -      pPg = *ppPage = 0;
  5374   5384         rc = SQLITE_NOMEM_BKPT;
  5375   5385         goto pager_acquire_err;
  5376   5386       }
  5377   5387     }
  5378   5388     pPg = *ppPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pBase);
  5379   5389     assert( pPg==(*ppPage) );
  5380   5390     assert( pPg->pgno==pgno );
  5381   5391     assert( pPg->pPager==pPager || pPg->pPager==0 );
  5382   5392   
  5383         -  if( pPg->pPager && !noContent ){
         5393  +  if( pPg->pPager ){
  5384   5394       /* In this case the pcache already contains an initialized copy of
  5385   5395       ** the page. Return without further ado.  */
  5386   5396       assert( pgno<=PAGER_MAX_PGNO && pgno!=PAGER_MJ_PGNO(pPager) );
  5387   5397       pPager->aStat[PAGER_STAT_HIT]++;
  5388   5398       return SQLITE_OK;
  5389   5399   
  5390   5400     }else{
................................................................................
  5397   5407       ** number greater than this, or the unused locking-page, is requested. */
  5398   5408       if( pgno>PAGER_MAX_PGNO || pgno==PAGER_MJ_PGNO(pPager) ){
  5399   5409         rc = SQLITE_CORRUPT_BKPT;
  5400   5410         goto pager_acquire_err;
  5401   5411       }
  5402   5412   
  5403   5413       assert( !isOpen(pPager->fd) || !MEMDB );
         5414  +    noContent = (flags & PAGER_GET_NOCONTENT)!=0;
  5404   5415       if( !isOpen(pPager->fd) || pPager->dbSize<pgno || noContent ){
  5405   5416         if( pgno>pPager->mxPgno ){
  5406   5417           rc = SQLITE_FULL;
  5407   5418           goto pager_acquire_err;
  5408   5419         }
  5409   5420         if( noContent ){
  5410   5421           /* Failure to set the bits in the InJournal bit-vectors is benign.
................................................................................
  5421   5432           TESTONLY( rc = ) addToSavepointBitvecs(pPager, pgno);
  5422   5433           testcase( rc==SQLITE_NOMEM );
  5423   5434           sqlite3EndBenignMalloc();
  5424   5435         }
  5425   5436         memset(pPg->pData, 0, pPager->pageSize);
  5426   5437         IOTRACE(("ZERO %p %d\n", pPager, pgno));
  5427   5438       }else{
  5428         -      if( pagerUseWal(pPager) /*&& bMmapOk==0*/ ){
         5439  +      u32 iFrame = 0;                 /* Frame to read from WAL file */
         5440  +      if( pagerUseWal(pPager) ){
  5429   5441           rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
  5430   5442           if( rc!=SQLITE_OK ) goto pager_acquire_err;
  5431   5443         }
  5432   5444         assert( pPg->pPager==pPager );
  5433   5445         pPager->aStat[PAGER_STAT_MISS]++;
  5434   5446         rc = readDbPage(pPg, iFrame);
  5435   5447         if( rc!=SQLITE_OK ){
................................................................................
  5446   5458       sqlite3PcacheDrop(pPg);
  5447   5459     }
  5448   5460     pagerUnlockIfUnused(pPager);
  5449   5461     *ppPage = 0;
  5450   5462     return rc;
  5451   5463   }
  5452   5464   
         5465  +#if SQLITE_MAX_MMAP_SIZE>0
  5453   5466   /* The page getter for when memory-mapped I/O is enabled */
  5454   5467   static int getPageMMap(
  5455   5468     Pager *pPager,      /* The pager open on the database file */
  5456   5469     Pgno pgno,          /* Page number to fetch */
  5457   5470     DbPage **ppPage,    /* Write a pointer to the page here */
  5458   5471     int flags           /* PAGER_GET_XXX flags */
  5459   5472   ){
................................................................................
  5516   5529       if( rc!=SQLITE_OK ){
  5517   5530         *ppPage = 0;
  5518   5531         return rc;
  5519   5532       }
  5520   5533     }
  5521   5534     return getPageNormal(pPager, pgno, ppPage, flags);
  5522   5535   }
         5536  +#endif /* SQLITE_MAX_MMAP_SIZE>0 */
  5523   5537   
  5524   5538   /* The page getter method for when the pager is an error state */
  5525   5539   static int getPageError(
  5526   5540     Pager *pPager,      /* The pager open on the database file */
  5527   5541     Pgno pgno,          /* Page number to fetch */
  5528   5542     DbPage **ppPage,    /* Write a pointer to the page here */
  5529   5543     int flags           /* PAGER_GET_XXX flags */