/ Check-in [0371cc3b]
Login

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

Overview
Comment:Faster implementation of pcache1Fetch()
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 0371cc3bb07448bcd64fd671f3e71bb7f30deb4d
User & Date: drh 2014-08-23 23:15:31
Context
2014-08-24
01:32
Patch the sqlite3PagerWrite() method in the Pager to run a bit faster. check-in: c63311e2 user: drh tags: trunk
2014-08-23
23:15
Faster implementation of pcache1Fetch() check-in: 0371cc3b user: drh tags: trunk
20:25
Faster implementation of the sqlite3ApiExit() routine. check-in: bd41d394 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/pcache1.c.

   379    379   
   380    380   /*
   381    381   ** This function is used to resize the hash table used by the cache passed
   382    382   ** as the first argument.
   383    383   **
   384    384   ** The PCache mutex must be held when this function is called.
   385    385   */
   386         -static int pcache1ResizeHash(PCache1 *p){
          386  +static void pcache1ResizeHash(PCache1 *p){
   387    387     PgHdr1 **apNew;
   388    388     unsigned int nNew;
   389    389     unsigned int i;
   390    390   
   391    391     assert( sqlite3_mutex_held(p->pGroup->mutex) );
   392    392   
   393    393     nNew = p->nHash*2;
................................................................................
   411    411           apNew[h] = pPage;
   412    412         }
   413    413       }
   414    414       sqlite3_free(p->apHash);
   415    415       p->apHash = apNew;
   416    416       p->nHash = nNew;
   417    417     }
   418         -
   419         -  return (p->apHash ? SQLITE_OK : SQLITE_NOMEM);
   420    418   }
   421    419   
   422    420   /*
   423    421   ** This function is used internally to remove the page pPage from the 
   424    422   ** PGroup LRU list, if is part of it. If pPage is not part of the PGroup
   425    423   ** LRU list, then this function is a no-op.
   426    424   **
................................................................................
   547    545   */
   548    546   static void pcache1Shutdown(void *NotUsed){
   549    547     UNUSED_PARAMETER(NotUsed);
   550    548     assert( pcache1.isInit!=0 );
   551    549     memset(&pcache1, 0, sizeof(pcache1));
   552    550   }
   553    551   
          552  +/* forward declaration */
          553  +static void pcache1Destroy(sqlite3_pcache *p);
          554  +
   554    555   /*
   555    556   ** Implementation of the sqlite3_pcache.xCreate method.
   556    557   **
   557    558   ** Allocate a new cache.
   558    559   */
   559    560   static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
   560    561     PCache1 *pCache;      /* The newly created page cache */
................................................................................
   591    592       }else{
   592    593         pGroup = &pcache1.grp;
   593    594       }
   594    595       pCache->pGroup = pGroup;
   595    596       pCache->szPage = szPage;
   596    597       pCache->szExtra = szExtra;
   597    598       pCache->bPurgeable = (bPurgeable ? 1 : 0);
          599  +    pcache1EnterMutex(pGroup);
          600  +    pcache1ResizeHash(pCache);
   598    601       if( bPurgeable ){
   599    602         pCache->nMin = 10;
   600         -      pcache1EnterMutex(pGroup);
   601    603         pGroup->nMinPage += pCache->nMin;
   602    604         pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
   603         -      pcache1LeaveMutex(pGroup);
          605  +    }
          606  +    pcache1LeaveMutex(pGroup);
          607  +    if( pCache->nHash==0 ){
          608  +      pcache1Destroy((sqlite3_pcache*)pCache);
          609  +      pCache = 0;
   604    610       }
   605    611     }
   606    612     return (sqlite3_pcache *)pCache;
   607    613   }
   608    614   
   609    615   /*
   610    616   ** Implementation of the sqlite3_pcache.xCachesize method. 
................................................................................
   652    658     PCache1 *pCache = (PCache1*)p;
   653    659     pcache1EnterMutex(pCache->pGroup);
   654    660     n = pCache->nPage;
   655    661     pcache1LeaveMutex(pCache->pGroup);
   656    662     return n;
   657    663   }
   658    664   
          665  +
          666  +/*
          667  +** Implement steps 3, 4, and 5 of the pcache1Fetch() algorithm described
          668  +** in the header of the pcache1Fetch() procedure.
          669  +**
          670  +** This steps are broken out into a separate procedure because they are
          671  +** usually not needed, and by avoiding the stack initialization required
          672  +** for these steps, the main pcache1Fetch() procedure can run faster.
          673  +*/
          674  +static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
          675  +  PCache1 *pCache, 
          676  +  unsigned int iKey, 
          677  +  int createFlag
          678  +){
          679  +  unsigned int nPinned;
          680  +  PGroup *pGroup = pCache->pGroup;
          681  +  PgHdr1 *pPage = 0;
          682  +
          683  +  /* Step 3: Abort if createFlag is 1 but the cache is nearly full */
          684  +  assert( pCache->nPage >= pCache->nRecyclable );
          685  +  nPinned = pCache->nPage - pCache->nRecyclable;
          686  +  assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage );
          687  +  assert( pCache->n90pct == pCache->nMax*9/10 );
          688  +  if( createFlag==1 && (
          689  +        nPinned>=pGroup->mxPinned
          690  +     || nPinned>=pCache->n90pct
          691  +     || pcache1UnderMemoryPressure(pCache)
          692  +  )){
          693  +    return 0;
          694  +  }
          695  +
          696  +  if( pCache->nPage>=pCache->nHash ) pcache1ResizeHash(pCache);
          697  +  assert( pCache->nHash>0 && pCache->apHash );
          698  +
          699  +  /* Step 4. Try to recycle a page. */
          700  +  if( pCache->bPurgeable && pGroup->pLruTail && (
          701  +         (pCache->nPage+1>=pCache->nMax)
          702  +      || pGroup->nCurrentPage>=pGroup->nMaxPage
          703  +      || pcache1UnderMemoryPressure(pCache)
          704  +  )){
          705  +    PCache1 *pOther;
          706  +    pPage = pGroup->pLruTail;
          707  +    assert( pPage->isPinned==0 );
          708  +    pcache1RemoveFromHash(pPage);
          709  +    pcache1PinPage(pPage);
          710  +    pOther = pPage->pCache;
          711  +
          712  +    /* We want to verify that szPage and szExtra are the same for pOther
          713  +    ** and pCache.  Assert that we can verify this by comparing sums. */
          714  +    assert( (pCache->szPage & (pCache->szPage-1))==0 && pCache->szPage>=512 );
          715  +    assert( pCache->szExtra<512 );
          716  +    assert( (pOther->szPage & (pOther->szPage-1))==0 && pOther->szPage>=512 );
          717  +    assert( pOther->szExtra<512 );
          718  +
          719  +    if( pOther->szPage+pOther->szExtra != pCache->szPage+pCache->szExtra ){
          720  +      pcache1FreePage(pPage);
          721  +      pPage = 0;
          722  +    }else{
          723  +      pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable);
          724  +    }
          725  +  }
          726  +
          727  +  /* Step 5. If a usable page buffer has still not been found, 
          728  +  ** attempt to allocate a new one. 
          729  +  */
          730  +  if( !pPage ){
          731  +    if( createFlag==1 ) sqlite3BeginBenignMalloc();
          732  +    pPage = pcache1AllocPage(pCache);
          733  +    if( createFlag==1 ) sqlite3EndBenignMalloc();
          734  +  }
          735  +
          736  +  if( pPage ){
          737  +    unsigned int h = iKey % pCache->nHash;
          738  +    pCache->nPage++;
          739  +    pPage->iKey = iKey;
          740  +    pPage->pNext = pCache->apHash[h];
          741  +    pPage->pCache = pCache;
          742  +    pPage->pLruPrev = 0;
          743  +    pPage->pLruNext = 0;
          744  +    pPage->isPinned = 1;
          745  +    *(void **)pPage->page.pExtra = 0;
          746  +    pCache->apHash[h] = pPage;
          747  +    if( iKey>pCache->iMaxKey ){
          748  +      pCache->iMaxKey = iKey;
          749  +    }
          750  +  }
          751  +  return pPage;
          752  +}
          753  +
   659    754   /*
   660    755   ** Implementation of the sqlite3_pcache.xFetch method. 
   661    756   **
   662    757   ** Fetch a page by key value.
   663    758   **
   664    759   ** Whether or not a new page may be allocated by this function depends on
   665    760   ** the value of the createFlag argument.  0 means do not allocate a new
................................................................................
   711    806   **   5. Otherwise, allocate and return a new page buffer.
   712    807   */
   713    808   static sqlite3_pcache_page *pcache1Fetch(
   714    809     sqlite3_pcache *p, 
   715    810     unsigned int iKey, 
   716    811     int createFlag
   717    812   ){
   718         -  unsigned int nPinned;
   719    813     PCache1 *pCache = (PCache1 *)p;
   720         -  PGroup *pGroup;
   721    814     PgHdr1 *pPage = 0;
   722    815   
   723    816     assert( offsetof(PgHdr1,page)==0 );
   724    817     assert( pCache->bPurgeable || createFlag!=1 );
   725    818     assert( pCache->bPurgeable || pCache->nMin==0 );
   726    819     assert( pCache->bPurgeable==0 || pCache->nMin==10 );
   727    820     assert( pCache->nMin==0 || pCache->bPurgeable );
   728         -  pcache1EnterMutex(pGroup = pCache->pGroup);
          821  +  assert( pCache->nHash>0 );
          822  +  pcache1EnterMutex(pCache->pGroup);
   729    823   
   730    824     /* Step 1: Search the hash table for an existing entry. */
   731         -  if( pCache->nHash>0 ){
   732         -    unsigned int h = iKey % pCache->nHash;
   733         -    for(pPage=pCache->apHash[h]; pPage&&pPage->iKey!=iKey; pPage=pPage->pNext);
   734         -  }
          825  +  pPage = pCache->apHash[iKey % pCache->nHash];
          826  +  while( pPage && pPage->iKey!=iKey ){ pPage = pPage->pNext; }
   735    827   
   736    828     /* Step 2: Abort if no existing page is found and createFlag is 0 */
   737    829     if( pPage ){
   738    830       if( !pPage->isPinned ) pcache1PinPage(pPage);
   739         -    goto fetch_out;
   740         -  }
   741         -  if( createFlag==0 ){
   742         -    goto fetch_out;
          831  +  }else if( createFlag ){
          832  +    /* Steps 3, 4, and 5 implemented by this subroutine */
          833  +    pPage = pcache1FetchStage2(pCache, iKey, createFlag);
   743    834     }
   744         -
   745         -  /* The pGroup local variable will normally be initialized by the
   746         -  ** pcache1EnterMutex() macro above.  But if SQLITE_MUTEX_OMIT is defined,
   747         -  ** then pcache1EnterMutex() is a no-op, so we have to initialize the
   748         -  ** local variable here.  Delaying the initialization of pGroup is an
   749         -  ** optimization:  The common case is to exit the module before reaching
   750         -  ** this point.
   751         -  */
   752         -#ifdef SQLITE_MUTEX_OMIT
   753         -  pGroup = pCache->pGroup;
   754         -#endif
   755         -
   756         -  /* Step 3: Abort if createFlag is 1 but the cache is nearly full */
   757         -  assert( pCache->nPage >= pCache->nRecyclable );
   758         -  nPinned = pCache->nPage - pCache->nRecyclable;
   759         -  assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage );
   760         -  assert( pCache->n90pct == pCache->nMax*9/10 );
   761         -  if( createFlag==1 && (
   762         -        nPinned>=pGroup->mxPinned
   763         -     || nPinned>=pCache->n90pct
   764         -     || pcache1UnderMemoryPressure(pCache)
   765         -  )){
   766         -    goto fetch_out;
   767         -  }
   768         -
   769         -  if( pCache->nPage>=pCache->nHash && pcache1ResizeHash(pCache) ){
   770         -    goto fetch_out;
   771         -  }
   772         -  assert( pCache->nHash>0 && pCache->apHash );
   773         -
   774         -  /* Step 4. Try to recycle a page. */
   775         -  if( pCache->bPurgeable && pGroup->pLruTail && (
   776         -         (pCache->nPage+1>=pCache->nMax)
   777         -      || pGroup->nCurrentPage>=pGroup->nMaxPage
   778         -      || pcache1UnderMemoryPressure(pCache)
   779         -  )){
   780         -    PCache1 *pOther;
   781         -    pPage = pGroup->pLruTail;
   782         -    assert( pPage->isPinned==0 );
   783         -    pcache1RemoveFromHash(pPage);
   784         -    pcache1PinPage(pPage);
   785         -    pOther = pPage->pCache;
   786         -
   787         -    /* We want to verify that szPage and szExtra are the same for pOther
   788         -    ** and pCache.  Assert that we can verify this by comparing sums. */
   789         -    assert( (pCache->szPage & (pCache->szPage-1))==0 && pCache->szPage>=512 );
   790         -    assert( pCache->szExtra<512 );
   791         -    assert( (pOther->szPage & (pOther->szPage-1))==0 && pOther->szPage>=512 );
   792         -    assert( pOther->szExtra<512 );
   793         -
   794         -    if( pOther->szPage+pOther->szExtra != pCache->szPage+pCache->szExtra ){
   795         -      pcache1FreePage(pPage);
   796         -      pPage = 0;
   797         -    }else{
   798         -      pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable);
   799         -    }
   800         -  }
   801         -
   802         -  /* Step 5. If a usable page buffer has still not been found, 
   803         -  ** attempt to allocate a new one. 
   804         -  */
   805         -  if( !pPage ){
   806         -    if( createFlag==1 ) sqlite3BeginBenignMalloc();
   807         -    pPage = pcache1AllocPage(pCache);
   808         -    if( createFlag==1 ) sqlite3EndBenignMalloc();
   809         -  }
   810         -
   811         -  if( pPage ){
   812         -    unsigned int h = iKey % pCache->nHash;
   813         -    pCache->nPage++;
   814         -    pPage->iKey = iKey;
   815         -    pPage->pNext = pCache->apHash[h];
   816         -    pPage->pCache = pCache;
   817         -    pPage->pLruPrev = 0;
   818         -    pPage->pLruNext = 0;
   819         -    pPage->isPinned = 1;
   820         -    *(void **)pPage->page.pExtra = 0;
   821         -    pCache->apHash[h] = pPage;
   822         -  }
   823         -
   824         -fetch_out:
   825         -  if( pPage && iKey>pCache->iMaxKey ){
   826         -    pCache->iMaxKey = iKey;
   827         -  }
   828         -  pcache1LeaveMutex(pGroup);
          835  +  assert( pPage==0 || pCache->iMaxKey>=iKey );
          836  +  pcache1LeaveMutex(pCache->pGroup);
   829    837     return (sqlite3_pcache_page*)pPage;
   830    838   }
   831    839   
   832    840   
   833    841   /*
   834    842   ** Implementation of the sqlite3_pcache.xUnpin method.
   835    843   **