/ Check-in [f1f94a97]
Login

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

Overview
Comment:Change the page cache so that a new sqlite3_pcache object is allocated as soon as the page cache is opened, not delayed until the first fetch request. This give a noticable performance boost. The interface between pager and the page cache has changed slightly, which might break ZIPVFS.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: f1f94a971e031e784f8c30a6faf829df58709329
User & Date: drh 2014-08-26 15:06:49
Context
2014-08-27
00:50
Performance enhancement in sqlite3VdbeMemNulTerminate(). check-in: f94cacc3 user: drh tags: trunk
2014-08-26
15:06
Change the page cache so that a new sqlite3_pcache object is allocated as soon as the page cache is opened, not delayed until the first fetch request. This give a noticable performance boost. The interface between pager and the page cache has changed slightly, which might break ZIPVFS. check-in: f1f94a97 user: drh tags: trunk
2014-08-25
22:37
Add an assert() and five testcase() macros to the OP_Cast opcode implementation to help verify that it is fully tested. check-in: af364cce user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/pager.c.

  3618   3618   
  3619   3619       if( rc==SQLITE_OK ){
  3620   3620         pager_reset(pPager);
  3621   3621         pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize);
  3622   3622         pPager->pageSize = pageSize;
  3623   3623         sqlite3PageFree(pPager->pTmpSpace);
  3624   3624         pPager->pTmpSpace = pNew;
  3625         -      sqlite3PcacheSetPageSize(pPager->pPCache, pageSize);
         3625  +      rc = sqlite3PcacheSetPageSize(pPager->pPCache, pageSize);
  3626   3626       }
  3627   3627     }
  3628   3628   
  3629   3629     *pPageSize = pPager->pageSize;
  3630   3630     if( rc==SQLITE_OK ){
  3631   3631       if( nReserve<0 ) nReserve = pPager->nReserve;
  3632   3632       assert( nReserve>=0 && nReserve<1000 );
................................................................................
  4381   4381     **
  4382   4382     ** The doNotSpill ROLLBACK and OFF bits inhibits all cache spilling
  4383   4383     ** regardless of whether or not a sync is required.  This is set during
  4384   4384     ** a rollback or by user request, respectively.
  4385   4385     **
  4386   4386     ** Spilling is also prohibited when in an error state since that could
  4387   4387     ** lead to database corruption.   In the current implementaton it 
  4388         -  ** is impossible for sqlite3PcacheFetch() to be called with createFlag==1
         4388  +  ** is impossible for sqlite3PcacheFetch() to be called with createFlag==3
  4389   4389     ** while in the error state, hence it is impossible for this routine to
  4390   4390     ** be called in the error state.  Nevertheless, we include a NEVER()
  4391   4391     ** test for the error state as a safeguard against future changes.
  4392   4392     */
  4393   4393     if( NEVER(pPager->errCode) ) return SQLITE_OK;
  4394   4394     testcase( pPager->doNotSpill & SPILLFLAG_ROLLBACK );
  4395   4395     testcase( pPager->doNotSpill & SPILLFLAG_OFF );
................................................................................
  4717   4717     */
  4718   4718     if( rc==SQLITE_OK ){
  4719   4719       assert( pPager->memDb==0 );
  4720   4720       rc = sqlite3PagerSetPagesize(pPager, &szPageDflt, -1);
  4721   4721       testcase( rc!=SQLITE_OK );
  4722   4722     }
  4723   4723   
  4724         -  /* If an error occurred in either of the blocks above, free the 
  4725         -  ** Pager structure and close the file.
         4724  +  /* Initialize the PCache object. */
         4725  +  if( rc==SQLITE_OK ){
         4726  +    assert( nExtra<1000 );
         4727  +    nExtra = ROUND8(nExtra);
         4728  +    rc = sqlite3PcacheOpen(szPageDflt, nExtra, !memDb,
         4729  +                           !memDb?pagerStress:0, (void *)pPager, pPager->pPCache);
         4730  +  }
         4731  +
         4732  +  /* If an error occurred above, free the  Pager structure and close the file.
  4726   4733     */
  4727   4734     if( rc!=SQLITE_OK ){
  4728         -    assert( !pPager->pTmpSpace );
  4729   4735       sqlite3OsClose(pPager->fd);
         4736  +    sqlite3PageFree(pPager->pTmpSpace);
  4730   4737       sqlite3_free(pPager);
  4731   4738       return rc;
  4732   4739     }
  4733   4740   
  4734         -  /* Initialize the PCache object. */
  4735         -  assert( nExtra<1000 );
  4736         -  nExtra = ROUND8(nExtra);
  4737         -  sqlite3PcacheOpen(szPageDflt, nExtra, !memDb,
  4738         -                    !memDb?pagerStress:0, (void *)pPager, pPager->pPCache);
  4739         -
  4740   4741     PAGERTRACE(("OPEN %d %s\n", FILEHANDLEID(pPager->fd), pPager->zFilename));
  4741   4742     IOTRACE(("OPEN %p %s\n", pPager, pPager->zFilename))
  4742   4743   
  4743   4744     pPager->useJournal = (u8)useJournal;
  4744   4745     /* pPager->stmtOpen = 0; */
  4745   4746     /* pPager->stmtInUse = 0; */
  4746   4747     /* pPager->nRef = 0; */
................................................................................
  5314   5315           }
  5315   5316         }
  5316   5317         if( rc!=SQLITE_OK ){
  5317   5318           goto pager_acquire_err;
  5318   5319         }
  5319   5320       }
  5320   5321   
  5321         -    rc = sqlite3PcacheFetch(pPager->pPCache, pgno, 1, ppPage);
         5322  +    rc = sqlite3PcacheFetch(pPager->pPCache, pgno, 3, ppPage);
  5322   5323     }
  5323   5324   
  5324   5325     if( rc!=SQLITE_OK ){
  5325   5326       /* Either the call to sqlite3PcacheFetch() returned an error or the
  5326   5327       ** pager was already in the error-state when this function was called.
  5327   5328       ** Set pPg to 0 and jump to the exception handler.  */
  5328   5329       pPg = 0;

Changes to src/pcache.c.

   139    139     if( p->pCache->bPurgeable ){
   140    140       if( p->pgno==1 ){
   141    141         p->pCache->pPage1 = 0;
   142    142       }
   143    143       sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 0);
   144    144     }
   145    145   }
          146  +
          147  +/*
          148  +** Compute the number of pages of cache requested.
          149  +*/
          150  +static int numberOfCachePages(PCache *p){
          151  +  if( p->szCache>=0 ){
          152  +    return p->szCache;
          153  +  }else{
          154  +    return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra));
          155  +  }
          156  +}
   146    157   
   147    158   /*************************************************** General Interfaces ******
   148    159   **
   149    160   ** Initialize and shutdown the page cache subsystem. Neither of these 
   150    161   ** functions are threadsafe.
   151    162   */
   152    163   int sqlite3PcacheInitialize(void){
................................................................................
   172    183   
   173    184   /*
   174    185   ** Create a new PCache object. Storage space to hold the object
   175    186   ** has already been allocated and is passed in as the p pointer. 
   176    187   ** The caller discovers how much space needs to be allocated by 
   177    188   ** calling sqlite3PcacheSize().
   178    189   */
   179         -void sqlite3PcacheOpen(
          190  +int sqlite3PcacheOpen(
   180    191     int szPage,                  /* Size of every page */
   181    192     int szExtra,                 /* Extra space associated with each page */
   182    193     int bPurgeable,              /* True if pages are on backing store */
   183    194     int (*xStress)(void*,PgHdr*),/* Call to try to make pages clean */
   184    195     void *pStress,               /* Argument to xStress */
   185    196     PCache *p                    /* Preallocated space for the PCache */
   186    197   ){
   187    198     memset(p, 0, sizeof(PCache));
   188         -  p->szPage = szPage;
          199  +  p->szPage = 1;
   189    200     p->szExtra = szExtra;
   190    201     p->bPurgeable = bPurgeable;
   191    202     p->eCreate = 2;
   192    203     p->xStress = xStress;
   193    204     p->pStress = pStress;
   194    205     p->szCache = 100;
          206  +  return sqlite3PcacheSetPageSize(p, szPage);
   195    207   }
   196    208   
   197    209   /*
   198    210   ** Change the page size for PCache object. The caller must ensure that there
   199    211   ** are no outstanding page references when this function is called.
   200    212   */
   201         -void sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
          213  +int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
   202    214     assert( pCache->nRef==0 && pCache->pDirty==0 );
   203         -  if( pCache->pCache ){
   204         -    sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
   205         -    pCache->pCache = 0;
          215  +  if( pCache->szPage ){
          216  +    sqlite3_pcache *pNew;
          217  +    pNew = sqlite3GlobalConfig.pcache2.xCreate(
          218  +                szPage, pCache->szExtra + sizeof(PgHdr), pCache->bPurgeable
          219  +    );
          220  +    if( pNew==0 ) return SQLITE_NOMEM;
          221  +    sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache));
          222  +    if( pCache->pCache ){
          223  +      sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
          224  +    }
          225  +    pCache->pCache = pNew;
   206    226       pCache->pPage1 = 0;
          227  +    pCache->szPage = szPage;
   207    228     }
   208         -  pCache->szPage = szPage;
   209         -}
   210         -
   211         -/*
   212         -** Compute the number of pages of cache requested.
   213         -*/
   214         -static int numberOfCachePages(PCache *p){
   215         -  if( p->szCache>=0 ){
   216         -    return p->szCache;
   217         -  }else{
   218         -    return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra));
   219         -  }
          229  +  return SQLITE_OK;
   220    230   }
   221    231   
   222    232   /*
   223    233   ** Try to obtain a page from the cache.
   224    234   */
   225    235   int sqlite3PcacheFetch(
   226    236     PCache *pCache,       /* Obtain the page from this cache */
................................................................................
   229    239     PgHdr **ppPage        /* Write the page here */
   230    240   ){
   231    241     sqlite3_pcache_page *pPage;
   232    242     PgHdr *pPgHdr = 0;
   233    243     int eCreate;
   234    244   
   235    245     assert( pCache!=0 );
   236         -  assert( createFlag==1 || createFlag==0 );
          246  +  assert( pCache->pCache!=0 );
          247  +  assert( createFlag==3 || createFlag==0 );
   237    248     assert( pgno>0 );
   238    249   
   239         -  /* If the pluggable cache (sqlite3_pcache*) has not been allocated,
   240         -  ** allocate it now.
   241         -  */
   242         -  if( !pCache->pCache ){
   243         -    sqlite3_pcache *p;
   244         -    if( !createFlag ){
   245         -      *ppPage = 0;
   246         -      return SQLITE_OK;
   247         -    }
   248         -    p = sqlite3GlobalConfig.pcache2.xCreate(
   249         -        pCache->szPage, pCache->szExtra + sizeof(PgHdr), pCache->bPurgeable
   250         -    );
   251         -    if( !p ){
   252         -      return SQLITE_NOMEM;
   253         -    }
   254         -    sqlite3GlobalConfig.pcache2.xCachesize(p, numberOfCachePages(pCache));
   255         -    pCache->pCache = p;
   256         -  }
   257         -
   258    250     /* eCreate defines what to do if the page does not exist.
   259    251     **    0     Do not allocate a new page.  (createFlag==0)
   260    252     **    1     Allocate a new page if doing so is inexpensive.
   261    253     **          (createFlag==1 AND bPurgeable AND pDirty)
   262    254     **    2     Allocate a new page even it doing so is difficult.
   263    255     **          (createFlag==1 AND !(bPurgeable AND pDirty)
   264    256     */
   265         -  eCreate = createFlag==0 ? 0 : pCache->eCreate;
   266         -  assert( (createFlag*(1+(!pCache->bPurgeable||!pCache->pDirty)))==eCreate );
          257  +  eCreate = createFlag & pCache->eCreate;
          258  +  assert( eCreate==0 || eCreate==1 || eCreate==2 );
          259  +  assert( createFlag==0 || pCache->eCreate==eCreate );
          260  +  assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) );
   267    261     pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
   268    262     if( !pPage && eCreate==1 ){
   269    263       PgHdr *pPg;
   270    264   
   271    265       /* Find a dirty page to write-out and recycle. First try to find a 
   272    266       ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
   273    267       ** cleared), but if that is not possible settle for any other 
................................................................................
   467    461     }
   468    462   }
   469    463   
   470    464   /*
   471    465   ** Close a cache.
   472    466   */
   473    467   void sqlite3PcacheClose(PCache *pCache){
   474         -  if( pCache->pCache ){
   475         -    sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
   476         -  }
          468  +  assert( pCache->pCache!=0 );
          469  +  sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
   477    470   }
   478    471   
   479    472   /* 
   480    473   ** Discard the contents of the cache.
   481    474   */
   482    475   void sqlite3PcacheClear(PCache *pCache){
   483    476     sqlite3PcacheTruncate(pCache, 0);
................................................................................
   578    571     return p->nRef;
   579    572   }
   580    573   
   581    574   /* 
   582    575   ** Return the total number of pages in the cache.
   583    576   */
   584    577   int sqlite3PcachePagecount(PCache *pCache){
   585         -  int nPage = 0;
   586         -  if( pCache->pCache ){
   587         -    nPage = sqlite3GlobalConfig.pcache2.xPagecount(pCache->pCache);
   588         -  }
   589         -  return nPage;
          578  +  assert( pCache->pCache!=0 );
          579  +  return sqlite3GlobalConfig.pcache2.xPagecount(pCache->pCache);
   590    580   }
   591    581   
   592    582   #ifdef SQLITE_TEST
   593    583   /*
   594    584   ** Get the suggested cache-size value.
   595    585   */
   596    586   int sqlite3PcacheGetCachesize(PCache *pCache){
................................................................................
   598    588   }
   599    589   #endif
   600    590   
   601    591   /*
   602    592   ** Set the suggested cache-size value.
   603    593   */
   604    594   void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
          595  +  assert( pCache->pCache!=0 );
   605    596     pCache->szCache = mxPage;
   606         -  if( pCache->pCache ){
   607         -    sqlite3GlobalConfig.pcache2.xCachesize(pCache->pCache,
   608         -                                           numberOfCachePages(pCache));
   609         -  }
          597  +  sqlite3GlobalConfig.pcache2.xCachesize(pCache->pCache,
          598  +                                         numberOfCachePages(pCache));
   610    599   }
   611    600   
   612    601   /*
   613    602   ** Free up as much memory as possible from the page cache.
   614    603   */
   615    604   void sqlite3PcacheShrink(PCache *pCache){
   616         -  if( pCache->pCache ){
   617         -    sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache);
   618         -  }
          605  +  assert( pCache->pCache!=0 );
          606  +  sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache);
   619    607   }
   620    608   
   621    609   #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
   622    610   /*
   623    611   ** For all dirty pages currently in the cache, invoke the specified
   624    612   ** callback. This is only used if the SQLITE_CHECK_PAGES macro is
   625    613   ** defined.

Changes to src/pcache.h.

    64     64   */
    65     65   void sqlite3PCacheBufferSetup(void *, int sz, int n);
    66     66   
    67     67   /* Create a new pager cache.
    68     68   ** Under memory stress, invoke xStress to try to make pages clean.
    69     69   ** Only clean and unpinned pages can be reclaimed.
    70     70   */
    71         -void sqlite3PcacheOpen(
           71  +int sqlite3PcacheOpen(
    72     72     int szPage,                    /* Size of every page */
    73     73     int szExtra,                   /* Extra space associated with each page */
    74     74     int bPurgeable,                /* True if pages are on backing store */
    75     75     int (*xStress)(void*, PgHdr*), /* Call to try to make pages clean */
    76     76     void *pStress,                 /* Argument to xStress */
    77     77     PCache *pToInit                /* Preallocated space for the PCache */
    78     78   );
    79     79   
    80     80   /* Modify the page-size after the cache has been created. */
    81         -void sqlite3PcacheSetPageSize(PCache *, int);
           81  +int sqlite3PcacheSetPageSize(PCache *, int);
    82     82   
    83     83   /* Return the size in bytes of a PCache object.  Used to preallocate
    84     84   ** storage space.
    85     85   */
    86     86   int sqlite3PcacheSize(void);
    87     87   
    88     88   /* One release per successful fetch.  Page is pinned until released.