/ Check-in [f00a9e1e]
Login

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

Overview
Comment:Change the pcache module to keep track of the total number of references to all pages rather than the number of pages references, for a performance improvement and size reduction.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: f00a9e1e998c4bd249a45444dc2d71a7e4903b8b
User & Date: drh 2015-09-03 20:43:55
Context
2015-09-04
04:31
Simplification of the LRU list handling in pcache1. check-in: 05a3a2cd user: drh tags: trunk
2015-09-03
20:52
Merge performance enhancements from trunk. This branch now runs (slightly) faster than the 3.8.11.1 release, though still slightly slower than trunk. check-in: c490bfb1 user: drh tags: begin-concurrent
20:43
Change the pcache module to keep track of the total number of references to all pages rather than the number of pages references, for a performance improvement and size reduction. check-in: f00a9e1e user: drh tags: trunk
18:20
A simple optimization and size reduction in sqlite3PagerAcquire(). check-in: 618d8dd4 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/pager.c.

  5257   5257     const int bMmapOk = (pgno>1 && USEFETCH(pPager)
  5258   5258      && (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY))
  5259   5259   #ifdef SQLITE_HAS_CODEC
  5260   5260      && pPager->xCodec==0
  5261   5261   #endif
  5262   5262     );
  5263   5263   
         5264  +  /* Optimization note:  Adding the "pgno<=1" term before "pgno==0" here
         5265  +  ** allows the compiler optimizer to reuse the results of the "pgno>1"
         5266  +  ** test in the previous statement, and avoid testing pgno==0 in the
         5267  +  ** common case where pgno is large. */
  5264   5268     if( pgno<=1 && pgno==0 ){
  5265   5269       return SQLITE_CORRUPT_BKPT;
  5266   5270     }
  5267   5271     assert( pPager->eState>=PAGER_READER );
  5268   5272     assert( assert_pager_state(pPager) );
  5269   5273     assert( noContent==0 || bMmapOk==0 );
  5270   5274   
................................................................................
  6386   6390   */
  6387   6391   u8 sqlite3PagerIsreadonly(Pager *pPager){
  6388   6392     return pPager->readOnly;
  6389   6393   }
  6390   6394   
  6391   6395   #ifdef SQLITE_DEBUG
  6392   6396   /*
  6393         -** Return the number of references to the pager.
         6397  +** Return the sum of the reference counts for all pages held by pPager.
  6394   6398   */
  6395   6399   int sqlite3PagerRefcount(Pager *pPager){
  6396   6400     return sqlite3PcacheRefCount(pPager->pPCache);
  6397   6401   }
  6398   6402   #endif
  6399   6403   
  6400   6404   /*

Changes to src/pcache.c.

    15     15   
    16     16   /*
    17     17   ** A complete page cache is an instance of this structure.
    18     18   */
    19     19   struct PCache {
    20     20     PgHdr *pDirty, *pDirtyTail;         /* List of dirty pages in LRU order */
    21     21     PgHdr *pSynced;                     /* Last synced page in dirty page list */
    22         -  int nRef;                           /* Number of referenced pages */
           22  +  int nRefSum;                        /* Sum of ref counts over all pages */
    23     23     int szCache;                        /* Configured cache size */
    24     24     int szPage;                         /* Size of every page in this cache */
    25     25     int szExtra;                        /* Size of extra space for each page */
    26     26     u8 bPurgeable;                      /* True if pages are on backing store */
    27     27     u8 eCreate;                         /* eCreate value for for xFetch() */
    28     28     int (*xStress)(void*,PgHdr*);       /* Call to try make a page clean */
    29     29     void *pStress;                      /* Argument to xStress */
................................................................................
   180    180   }
   181    181   
   182    182   /*
   183    183   ** Change the page size for PCache object. The caller must ensure that there
   184    184   ** are no outstanding page references when this function is called.
   185    185   */
   186    186   int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
   187         -  assert( pCache->nRef==0 && pCache->pDirty==0 );
          187  +  assert( pCache->nRefSum==0 && pCache->pDirty==0 );
   188    188     if( pCache->szPage ){
   189    189       sqlite3_pcache *pNew;
   190    190       pNew = sqlite3GlobalConfig.pcache2.xCreate(
   191    191                   szPage, pCache->szExtra + ROUND8(sizeof(PgHdr)),
   192    192                   pCache->bPurgeable
   193    193       );
   194    194       if( pNew==0 ) return SQLITE_NOMEM;
................................................................................
   347    347   
   348    348     assert( pPage!=0 );
   349    349     pPgHdr = (PgHdr *)pPage->pExtra;
   350    350   
   351    351     if( !pPgHdr->pPage ){
   352    352       return pcacheFetchFinishWithInit(pCache, pgno, pPage);
   353    353     }
   354         -  if( 0==pPgHdr->nRef ){
   355         -    pCache->nRef++;
   356         -  }
          354  +  pCache->nRefSum++;
   357    355     pPgHdr->nRef++;
   358    356     return pPgHdr;
   359    357   }
   360    358   
   361    359   /*
   362    360   ** Decrement the reference count on a page. If the page is clean and the
   363    361   ** reference count drops to 0, then it is made eligible for recycling.
   364    362   */
   365    363   void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
   366    364     assert( p->nRef>0 );
   367         -  p->nRef--;
   368         -  if( p->nRef==0 ){
   369         -    p->pCache->nRef--;
          365  +  p->pCache->nRefSum--;
          366  +  if( (--p->nRef)==0 ){
   370    367       if( p->flags&PGHDR_CLEAN ){
   371    368         pcacheUnpin(p);
   372    369       }else if( p->pDirtyPrev!=0 ){
   373    370         /* Move the page to the head of the dirty list. */
   374    371         pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
   375    372       }
   376    373     }
................................................................................
   378    375   
   379    376   /*
   380    377   ** Increase the reference count of a supplied page by 1.
   381    378   */
   382    379   void sqlite3PcacheRef(PgHdr *p){
   383    380     assert(p->nRef>0);
   384    381     p->nRef++;
          382  +  p->pCache->nRefSum++;
   385    383   }
   386    384   
   387    385   /*
   388    386   ** Drop a page from the cache. There must be exactly one reference to the
   389    387   ** page. This function deletes that reference, so after it returns the
   390    388   ** page pointed to by p is invalid.
   391    389   */
   392    390   void sqlite3PcacheDrop(PgHdr *p){
   393    391     assert( p->nRef==1 );
   394    392     if( p->flags&PGHDR_DIRTY ){
   395    393       pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
   396    394     }
   397         -  p->pCache->nRef--;
          395  +  p->pCache->nRefSum--;
   398    396     sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 1);
   399    397   }
   400    398   
   401    399   /*
   402    400   ** Make sure the page is marked as dirty. If it isn't dirty already,
   403    401   ** make it so.
   404    402   */
................................................................................
   486    484         */
   487    485         assert( p->pgno>0 );
   488    486         if( ALWAYS(p->pgno>pgno) ){
   489    487           assert( p->flags&PGHDR_DIRTY );
   490    488           sqlite3PcacheMakeClean(p);
   491    489         }
   492    490       }
   493         -    if( pgno==0 && pCache->nRef ){
          491  +    if( pgno==0 && pCache->nRefSum ){
   494    492         sqlite3_pcache_page *pPage1;
   495    493         pPage1 = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache,1,0);
   496    494         if( ALWAYS(pPage1) ){  /* Page 1 is always available in cache, because
   497         -                             ** pCache->nRef>0 */
          495  +                             ** pCache->nRefSum>0 */
   498    496           memset(pPage1->pBuf, 0, pCache->szPage);
   499    497           pgno = 1;
   500    498         }
   501    499       }
   502    500       sqlite3GlobalConfig.pcache2.xTruncate(pCache->pCache, pgno+1);
   503    501     }
   504    502   }
................................................................................
   596    594     for(p=pCache->pDirty; p; p=p->pDirtyNext){
   597    595       p->pDirty = p->pDirtyNext;
   598    596     }
   599    597     return pcacheSortDirtyList(pCache->pDirty);
   600    598   }
   601    599   
   602    600   /* 
   603         -** Return the total number of referenced pages held by the cache.
          601  +** Return the total number of references to all pages held by the cache.
          602  +**
          603  +** This is not the total number of pages referenced, but the sum of the
          604  +** reference count for all pages.
   604    605   */
   605    606   int sqlite3PcacheRefCount(PCache *pCache){
   606         -  return pCache->nRef;
          607  +  return pCache->nRefSum;
   607    608   }
   608    609   
   609    610   /*
   610    611   ** Return the number of references to the page supplied as an argument.
   611    612   */
   612    613   int sqlite3PcachePageRefcount(PgHdr *p){
   613    614     return p->nRef;

Changes to src/pcache1.c.

   957    957     PCache1 *pCache = (PCache1 *)p;
   958    958     PgHdr1 *pPage = 0;
   959    959   
   960    960     /* Step 1: Search the hash table for an existing entry. */
   961    961     pPage = pCache->apHash[iKey % pCache->nHash];
   962    962     while( pPage && pPage->iKey!=iKey ){ pPage = pPage->pNext; }
   963    963   
   964         -  /* Step 2: Abort if no existing page is found and createFlag is 0 */
          964  +  /* Step 2: If the page was found in the hash table, then return it.
          965  +  ** If the page was not in the hash table and createFlag is 0, abort.
          966  +  ** Otherwise (page not in hash and createFlag!=0) continue with
          967  +  ** subsequent steps to try to create the page. */
   965    968     if( pPage ){
   966    969       if( !pPage->isPinned ){
   967    970         return pcache1PinPage(pPage);
   968    971       }else{
   969    972         return pPage;
   970    973       }
   971    974     }else if( createFlag ){