/ Check-in [df5bb90d]
Login

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

Overview
Comment: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.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | pager-get-method
Files: files | file ages | folders
SHA1: df5bb90d208e0633056389e97696d260e3830e8d
User & Date: drh 2016-12-13 14:32:47
Context
2016-12-13
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
2016-12-12
23:24
Add the --mmap option to the speedtest1 program and to the speed-check.sh script that is frequently used to run speedtest1. check-in: 1a636d5e user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/pager.c.

   689    689     int (*xBusyHandler)(void*); /* Function to call when busy */
   690    690     void *pBusyHandlerArg;      /* Context argument for xBusyHandler */
   691    691     int aStat[3];               /* Total cache hits, misses and writes */
   692    692   #ifdef SQLITE_TEST
   693    693     int nRead;                  /* Database pages read */
   694    694   #endif
   695    695     void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */
          696  +  int (*xGet)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */
   696    697   #ifdef SQLITE_HAS_CODEC
   697    698     void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
   698    699     void (*xCodecSizeChng)(void*,int,int); /* Notify of page size changes */
   699    700     void (*xCodecFree)(void*);             /* Destructor for the codec */
   700    701     void *pCodec;               /* First argument to xCodec... methods */
   701    702   #endif
   702    703     char *pTmpSpace;            /* Pager.pageSize bytes of space for tmp use */
................................................................................
  1014   1015         , p->journalOff, p->journalHdr
  1015   1016         , (int)p->dbSize, (int)p->dbOrigSize, (int)p->dbFileSize
  1016   1017     );
  1017   1018   
  1018   1019     return zRet;
  1019   1020   }
  1020   1021   #endif
         1022  +
         1023  +/* Forward references to the various page getters */
         1024  +static int getPageNormal(Pager*,Pgno,DbPage**,int);
         1025  +static int getPageMMap(Pager*,Pgno,DbPage**,int);
         1026  +static int getPageError(Pager*,Pgno,DbPage**,int);
         1027  +
         1028  +/*
         1029  +** Set the Pager.xGet method for the appropriate routine used to fetch
         1030  +** content from the pager.
         1031  +*/
         1032  +static void setGetterMethod(Pager *pPager){
         1033  +  if( pPager->errCode ){
         1034  +    pPager->xGet = getPageError;
         1035  +  }else if( USEFETCH(pPager)
         1036  +#ifdef SQLITE_HAS_CODEC
         1037  +   && pPager->xCodec==0
         1038  +#endif
         1039  +  ){
         1040  +    pPager->xGet = getPageMMap;
         1041  +  }else{
         1042  +    pPager->xGet = getPageNormal;
         1043  +  }
         1044  +}
  1021   1045   
  1022   1046   /*
  1023   1047   ** Return true if it is necessary to write page *pPg into the sub-journal.
  1024   1048   ** A page needs to be written into the sub-journal if there exists one
  1025   1049   ** or more open savepoints for which:
  1026   1050   **
  1027   1051   **   * The page-number is less than or equal to PagerSavepoint.nOrig, and
................................................................................
  1829   1853         pPager->changeCountDone = 0;
  1830   1854         pPager->eState = PAGER_OPEN;
  1831   1855       }else{
  1832   1856         pPager->eState = (isOpen(pPager->jfd) ? PAGER_OPEN : PAGER_READER);
  1833   1857       }
  1834   1858       if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0);
  1835   1859       pPager->errCode = SQLITE_OK;
         1860  +    setGetterMethod(pPager);
  1836   1861     }
  1837   1862   
  1838   1863     pPager->journalOff = 0;
  1839   1864     pPager->journalHdr = 0;
  1840   1865     pPager->setMaster = 0;
  1841   1866   }
  1842   1867   
................................................................................
  1866   1891          pPager->errCode==SQLITE_FULL ||
  1867   1892          pPager->errCode==SQLITE_OK ||
  1868   1893          (pPager->errCode & 0xff)==SQLITE_IOERR
  1869   1894     );
  1870   1895     if( rc2==SQLITE_FULL || rc2==SQLITE_IOERR ){
  1871   1896       pPager->errCode = rc;
  1872   1897       pPager->eState = PAGER_ERROR;
         1898  +    setGetterMethod(pPager);
  1873   1899     }
  1874   1900     return rc;
  1875   1901   }
  1876   1902   
  1877   1903   static int pager_truncate(Pager *pPager, Pgno nPage);
  1878   1904   
  1879   1905   /*
................................................................................
  3433   3459   static void pagerFixMaplimit(Pager *pPager){
  3434   3460   #if SQLITE_MAX_MMAP_SIZE>0
  3435   3461     sqlite3_file *fd = pPager->fd;
  3436   3462     if( isOpen(fd) && fd->pMethods->iVersion>=3 ){
  3437   3463       sqlite3_int64 sz;
  3438   3464       sz = pPager->szMmap;
  3439   3465       pPager->bUseFetch = (sz>0);
         3466  +    setGetterMethod(pPager);
  3440   3467       sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_MMAP_SIZE, &sz);
  3441   3468     }
  3442   3469   #endif
  3443   3470   }
  3444   3471   
  3445   3472   /*
  3446   3473   ** Change the maximum size of any memory mapping made of the database file.
................................................................................
  4850   4877       pPager->journalMode = PAGER_JOURNALMODE_OFF;
  4851   4878     }else if( memDb ){
  4852   4879       pPager->journalMode = PAGER_JOURNALMODE_MEMORY;
  4853   4880     }
  4854   4881     /* pPager->xBusyHandler = 0; */
  4855   4882     /* pPager->pBusyHandlerArg = 0; */
  4856   4883     pPager->xReiniter = xReinit;
         4884  +  setGetterMethod(pPager);
  4857   4885     /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */
  4858   4886     /* pPager->szMmap = SQLITE_DEFAULT_MMAP_SIZE // will be set by btree.c */
  4859   4887   
  4860   4888     *ppPager = pPager;
  4861   4889     return SQLITE_OK;
  4862   4890   }
  4863   4891   
................................................................................
  5312   5340   ** to find a page in the in-memory cache first.  If the page is not already
  5313   5341   ** in memory, this routine goes to disk to read it in whereas Lookup()
  5314   5342   ** just returns 0.  This routine acquires a read-lock the first time it
  5315   5343   ** has to go to disk, and could also playback an old journal if necessary.
  5316   5344   ** Since Lookup() never goes to disk, it never has to deal with locks
  5317   5345   ** or journal files.
  5318   5346   */
  5319         -int sqlite3PagerGet(
         5347  +static int getPageNormal(
  5320   5348     Pager *pPager,      /* The pager open on the database file */
  5321   5349     Pgno pgno,          /* Page number to fetch */
  5322   5350     DbPage **ppPage,    /* Write a pointer to the page here */
  5323   5351     int flags           /* PAGER_GET_XXX flags */
  5324   5352   ){
  5325   5353     int rc = SQLITE_OK;
  5326   5354     PgHdr *pPg = 0;
  5327   5355     u32 iFrame = 0;                 /* Frame to read from WAL file */
  5328   5356     const int noContent = (flags & PAGER_GET_NOCONTENT);
         5357  +  sqlite3_pcache_page *pBase;
  5329   5358   
  5330         -  /* It is acceptable to use a read-only (mmap) page for any page except
  5331         -  ** page 1 if there is no write-transaction open or the ACQUIRE_READONLY
  5332         -  ** flag was specified by the caller. And so long as the db is not a 
  5333         -  ** temporary or in-memory database.  */
  5334         -  const int bMmapOk = (pgno>1 && USEFETCH(pPager)
  5335         -   && (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY))
  5336         -#ifdef SQLITE_HAS_CODEC
  5337         -   && pPager->xCodec==0
  5338         -#endif
  5339         -  );
  5340         -
  5341         -  /* Optimization note:  Adding the "pgno<=1" term before "pgno==0" here
  5342         -  ** allows the compiler optimizer to reuse the results of the "pgno>1"
  5343         -  ** test in the previous statement, and avoid testing pgno==0 in the
  5344         -  ** common case where pgno is large. */
  5345         -  if( pgno<=1 && pgno==0 ){
         5359  +  if( pgno==0 ){
  5346   5360       return SQLITE_CORRUPT_BKPT;
  5347   5361     }
         5362  +  assert( pPager->errCode==SQLITE_OK );
  5348   5363     assert( pPager->eState>=PAGER_READER );
  5349   5364     assert( assert_pager_state(pPager) );
  5350         -  assert( noContent==0 || bMmapOk==0 );
  5351         -
  5352   5365     assert( pPager->hasHeldSharedLock==1 );
  5353   5366   
  5354         -  /* If the pager is in the error state, return an error immediately. 
  5355         -  ** Otherwise, request the page from the PCache layer. */
  5356         -  if( pPager->errCode!=SQLITE_OK ){
  5357         -    rc = pPager->errCode;
  5358         -  }else{
  5359         -    if( bMmapOk && pagerUseWal(pPager) ){
  5360         -      rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
  5361         -      if( rc!=SQLITE_OK ) goto pager_acquire_err;
  5362         -    }
  5363         -
  5364         -    if( bMmapOk && iFrame==0 ){
  5365         -      void *pData = 0;
  5366         -
  5367         -      rc = sqlite3OsFetch(pPager->fd, 
  5368         -          (i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData
  5369         -      );
  5370         -
  5371         -      if( rc==SQLITE_OK && pData ){
  5372         -        if( pPager->eState>PAGER_READER || pPager->tempFile ){
  5373         -          pPg = sqlite3PagerLookup(pPager, pgno);
  5374         -        }
  5375         -        if( pPg==0 ){
  5376         -          rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg);
  5377         -        }else{
  5378         -          sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData);
  5379         -        }
  5380         -        if( pPg ){
  5381         -          assert( rc==SQLITE_OK );
  5382         -          *ppPage = pPg;
  5383         -          return SQLITE_OK;
  5384         -        }
  5385         -      }
  5386         -      if( rc!=SQLITE_OK ){
  5387         -        goto pager_acquire_err;
  5388         -      }
  5389         -    }
  5390         -
  5391         -    {
  5392         -      sqlite3_pcache_page *pBase;
  5393         -      pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3);
  5394         -      if( pBase==0 ){
  5395         -        rc = sqlite3PcacheFetchStress(pPager->pPCache, pgno, &pBase);
  5396         -        if( rc!=SQLITE_OK ) goto pager_acquire_err;
  5397         -        if( pBase==0 ){
  5398         -          pPg = *ppPage = 0;
  5399         -          rc = SQLITE_NOMEM_BKPT;
  5400         -          goto pager_acquire_err;
  5401         -        }
  5402         -      }
  5403         -      pPg = *ppPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pBase);
  5404         -      assert( pPg!=0 );
  5405         -    }
  5406         -  }
  5407         -
  5408         -  if( rc!=SQLITE_OK ){
  5409         -    /* Either the call to sqlite3PcacheFetch() returned an error or the
  5410         -    ** pager was already in the error-state when this function was called.
  5411         -    ** Set pPg to 0 and jump to the exception handler.  */
  5412         -    pPg = 0;
  5413         -    goto pager_acquire_err;
  5414         -  }
         5367  +
         5368  +  pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3);
         5369  +  if( pBase==0 ){
         5370  +    rc = sqlite3PcacheFetchStress(pPager->pPCache, pgno, &pBase);
         5371  +    if( rc!=SQLITE_OK ) goto pager_acquire_err;
         5372  +    if( pBase==0 ){
         5373  +      pPg = *ppPage = 0;
         5374  +      rc = SQLITE_NOMEM_BKPT;
         5375  +      goto pager_acquire_err;
         5376  +    }
         5377  +  }
         5378  +  pPg = *ppPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pBase);
  5415   5379     assert( pPg==(*ppPage) );
  5416   5380     assert( pPg->pgno==pgno );
  5417   5381     assert( pPg->pPager==pPager || pPg->pPager==0 );
  5418   5382   
  5419   5383     if( pPg->pPager && !noContent ){
  5420   5384       /* In this case the pcache already contains an initialized copy of
  5421   5385       ** the page. Return without further ado.  */
................................................................................
  5457   5421           TESTONLY( rc = ) addToSavepointBitvecs(pPager, pgno);
  5458   5422           testcase( rc==SQLITE_NOMEM );
  5459   5423           sqlite3EndBenignMalloc();
  5460   5424         }
  5461   5425         memset(pPg->pData, 0, pPager->pageSize);
  5462   5426         IOTRACE(("ZERO %p %d\n", pPager, pgno));
  5463   5427       }else{
  5464         -      if( pagerUseWal(pPager) && bMmapOk==0 ){
         5428  +      if( pagerUseWal(pPager) /*&& bMmapOk==0*/ ){
  5465   5429           rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
  5466   5430           if( rc!=SQLITE_OK ) goto pager_acquire_err;
  5467   5431         }
  5468   5432         assert( pPg->pPager==pPager );
  5469   5433         pPager->aStat[PAGER_STAT_MISS]++;
  5470   5434         rc = readDbPage(pPg, iFrame);
  5471   5435         if( rc!=SQLITE_OK ){
  5472   5436           goto pager_acquire_err;
  5473   5437         }
  5474   5438       }
  5475   5439       pager_set_pagehash(pPg);
  5476   5440     }
  5477         -
  5478   5441     return SQLITE_OK;
  5479   5442   
  5480   5443   pager_acquire_err:
  5481   5444     assert( rc!=SQLITE_OK );
  5482   5445     if( pPg ){
  5483   5446       sqlite3PcacheDrop(pPg);
  5484   5447     }
  5485   5448     pagerUnlockIfUnused(pPager);
         5449  +  *ppPage = 0;
         5450  +  return rc;
         5451  +}
  5486   5452   
         5453  +/* The page getter for when memory-mapped I/O is enabled */
         5454  +static int getPageMMap(
         5455  +  Pager *pPager,      /* The pager open on the database file */
         5456  +  Pgno pgno,          /* Page number to fetch */
         5457  +  DbPage **ppPage,    /* Write a pointer to the page here */
         5458  +  int flags           /* PAGER_GET_XXX flags */
         5459  +){
         5460  +  int rc = SQLITE_OK;
         5461  +  PgHdr *pPg = 0;
         5462  +  u32 iFrame = 0;                 /* Frame to read from WAL file */
         5463  +
         5464  +  assert( USEFETCH(pPager) );
         5465  +#ifdef SQLITE_HAS_CODEC
         5466  +  assert( pPager->xCodec==0 );
         5467  +#endif
         5468  +
         5469  +  /* It is acceptable to use a read-only (mmap) page for any page except
         5470  +  ** page 1 if there is no write-transaction open or the ACQUIRE_READONLY
         5471  +  ** flag was specified by the caller. And so long as the db is not a 
         5472  +  ** temporary or in-memory database.  */
         5473  +  const int bMmapOk = (pgno>1
         5474  +   && (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY))
         5475  +  );
         5476  +
         5477  +  /* Optimization note:  Adding the "pgno<=1" term before "pgno==0" here
         5478  +  ** allows the compiler optimizer to reuse the results of the "pgno>1"
         5479  +  ** test in the previous statement, and avoid testing pgno==0 in the
         5480  +  ** common case where pgno is large. */
         5481  +  if( pgno<=1 && pgno==0 ){
         5482  +    return SQLITE_CORRUPT_BKPT;
         5483  +  }
         5484  +  assert( pPager->eState>=PAGER_READER );
         5485  +  assert( assert_pager_state(pPager) );
         5486  +  assert( pPager->hasHeldSharedLock==1 );
         5487  +  assert( pPager->errCode==SQLITE_OK );
         5488  +
         5489  +  if( bMmapOk && pagerUseWal(pPager) ){
         5490  +    rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
         5491  +    if( rc!=SQLITE_OK ){
         5492  +      *ppPage = 0;
         5493  +      return rc;
         5494  +    }
         5495  +  }
         5496  +  if( bMmapOk && iFrame==0 ){
         5497  +    void *pData = 0;
         5498  +    rc = sqlite3OsFetch(pPager->fd, 
         5499  +        (i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData
         5500  +    );
         5501  +    if( rc==SQLITE_OK && pData ){
         5502  +      if( pPager->eState>PAGER_READER || pPager->tempFile ){
         5503  +        pPg = sqlite3PagerLookup(pPager, pgno);
         5504  +      }
         5505  +      if( pPg==0 ){
         5506  +        rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg);
         5507  +     }else{
         5508  +        sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData);
         5509  +      }
         5510  +      if( pPg ){
         5511  +        assert( rc==SQLITE_OK );
         5512  +        *ppPage = pPg;
         5513  +        return SQLITE_OK;
         5514  +      }
         5515  +    }
         5516  +    if( rc!=SQLITE_OK ){
         5517  +      *ppPage = 0;
         5518  +      return rc;
         5519  +    }
         5520  +  }
         5521  +  return getPageNormal(pPager, pgno, ppPage, flags);
         5522  +}
         5523  +
         5524  +/* The page getter method for when the pager is an error state */
         5525  +static int getPageError(
         5526  +  Pager *pPager,      /* The pager open on the database file */
         5527  +  Pgno pgno,          /* Page number to fetch */
         5528  +  DbPage **ppPage,    /* Write a pointer to the page here */
         5529  +  int flags           /* PAGER_GET_XXX flags */
         5530  +){
         5531  +  assert( pPager->errCode!=SQLITE_OK );
  5487   5532     *ppPage = 0;
  5488         -  return rc;
         5533  +  return pPager->errCode;
         5534  +}
         5535  +
         5536  +
         5537  +/* Dispatch all page fetch requests to the appropriate getter method.
         5538  +*/
         5539  +int sqlite3PagerGet(
         5540  +  Pager *pPager,      /* The pager open on the database file */
         5541  +  Pgno pgno,          /* Page number to fetch */
         5542  +  DbPage **ppPage,    /* Write a pointer to the page here */
         5543  +  int flags           /* PAGER_GET_XXX flags */
         5544  +){
         5545  +  return pPager->xGet(pPager, pgno, ppPage, flags);
  5489   5546   }
  5490   5547   
  5491   5548   /*
  5492   5549   ** Acquire a page if it is already in the in-memory cache.  Do
  5493   5550   ** not read the page from disk.  Return a pointer to the page,
  5494   5551   ** or 0 if the page is not in cache. 
  5495   5552   **
................................................................................
  6456   6513       if( !MEMDB && eState>PAGER_WRITER_LOCKED ){
  6457   6514         /* This can happen using journal_mode=off. Move the pager to the error 
  6458   6515         ** state to indicate that the contents of the cache may not be trusted.
  6459   6516         ** Any active readers will get SQLITE_ABORT.
  6460   6517         */
  6461   6518         pPager->errCode = SQLITE_ABORT;
  6462   6519         pPager->eState = PAGER_ERROR;
         6520  +      setGetterMethod(pPager);
  6463   6521         return rc;
  6464   6522       }
  6465   6523     }else{
  6466   6524       rc = pager_playback(pPager, 0);
  6467   6525     }
  6468   6526   
  6469   6527     assert( pPager->eState==PAGER_READER || rc!=SQLITE_OK );
................................................................................
  6717   6775       ** can be rolled back at the ZipVFS level.  */
  6718   6776       else if( 
  6719   6777           pPager->journalMode==PAGER_JOURNALMODE_OFF 
  6720   6778        && pPager->eState>=PAGER_WRITER_CACHEMOD
  6721   6779       ){
  6722   6780         pPager->errCode = SQLITE_ABORT;
  6723   6781         pPager->eState = PAGER_ERROR;
         6782  +      setGettterMethod(pPager);
  6724   6783       }
  6725   6784   #endif
  6726   6785     }
  6727   6786   
  6728   6787     return rc;
  6729   6788   }
  6730   6789   
................................................................................
  6789   6848     void *pCodec
  6790   6849   ){
  6791   6850     if( pPager->xCodecFree ) pPager->xCodecFree(pPager->pCodec);
  6792   6851     pPager->xCodec = pPager->memDb ? 0 : xCodec;
  6793   6852     pPager->xCodecSizeChng = xCodecSizeChng;
  6794   6853     pPager->xCodecFree = xCodecFree;
  6795   6854     pPager->pCodec = pCodec;
         6855  +  setGetterMethod(pPager);
  6796   6856     pagerReportSize(pPager);
  6797   6857   }
  6798   6858   void *sqlite3PagerGetCodec(Pager *pPager){
  6799   6859     return pPager->pCodec;
  6800   6860   }
  6801   6861   
  6802   6862   /*