]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Faster implementation of pcache1Fetch()
authordrh <drh@noemail.net>
Sat, 23 Aug 2014 23:15:31 +0000 (23:15 +0000)
committerdrh <drh@noemail.net>
Sat, 23 Aug 2014 23:15:31 +0000 (23:15 +0000)
FossilOrigin-Name: 0371cc3bb07448bcd64fd671f3e71bb7f30deb4d

manifest
manifest.uuid
src/pcache1.c

index 1044726bb029b2fb8deff1de4bdcb0f469213a54..6e1bca5a72f908b4f9b0539a4fd27132dd771bbd 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Faster\simplementation\sof\sthe\ssqlite3ApiExit()\sroutine.
-D 2014-08-23T20:25:53.209
+C Faster\simplementation\sof\spcache1Fetch()
+D 2014-08-23T23:15:31.233
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -216,7 +216,7 @@ F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428
 F src/parse.y 22d6a074e5f5a7258947a1dc55a9bf946b765dd0
 F src/pcache.c da602c5447051705cab41604bf3276815eb569d0
 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
-F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c
+F src/pcache1.c c5af6403a55178c9d1c09e4f77b0f9c88822762c
 F src/pragma.c d10ef67c4de79f78188b965b4b7988aff1d66f2e
 F src/prepare.c 3842c1dfc0b053458e3adcf9f6efc48e03e3fe3d
 F src/printf.c 00986c86ddfffefc2fd3c73667ff51b3b9709c74
@@ -1188,7 +1188,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 6da6f46d0c43e3b68c21f514ddf8ee663c20f249
-R cfcb5b6ff857caed22b759c12472ea06
+P bd41d394d48516eb7d8ddc46abdcb427aa80173e
+R d2491d65f44f8709d1d156c840c25703
 U drh
-Z c1d7ee14996f329ac13456e7bf7bb3df
+Z 15bb2365f5f8da3e5de34ee820ad0674
index 215297c16bcb78bdf1deba3354bf7a6d27c400fb..bd2aebab200a53ebc71c5eb1ebcd1ca7d3ae01cd 100644 (file)
@@ -1 +1 @@
-bd41d394d48516eb7d8ddc46abdcb427aa80173e
\ No newline at end of file
+0371cc3bb07448bcd64fd671f3e71bb7f30deb4d
\ No newline at end of file
index 1644b0693ccba05354abe8bb096d52a78cbeb5bd..82015befcec65444ead49d2dfec4e2b7b3bdab0a 100644 (file)
@@ -383,7 +383,7 @@ static int pcache1UnderMemoryPressure(PCache1 *pCache){
 **
 ** The PCache mutex must be held when this function is called.
 */
-static int pcache1ResizeHash(PCache1 *p){
+static void pcache1ResizeHash(PCache1 *p){
   PgHdr1 **apNew;
   unsigned int nNew;
   unsigned int i;
@@ -415,8 +415,6 @@ static int pcache1ResizeHash(PCache1 *p){
     p->apHash = apNew;
     p->nHash = nNew;
   }
-
-  return (p->apHash ? SQLITE_OK : SQLITE_NOMEM);
 }
 
 /*
@@ -551,6 +549,9 @@ static void pcache1Shutdown(void *NotUsed){
   memset(&pcache1, 0, sizeof(pcache1));
 }
 
+/* forward declaration */
+static void pcache1Destroy(sqlite3_pcache *p);
+
 /*
 ** Implementation of the sqlite3_pcache.xCreate method.
 **
@@ -595,12 +596,17 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
     pCache->szPage = szPage;
     pCache->szExtra = szExtra;
     pCache->bPurgeable = (bPurgeable ? 1 : 0);
+    pcache1EnterMutex(pGroup);
+    pcache1ResizeHash(pCache);
     if( bPurgeable ){
       pCache->nMin = 10;
-      pcache1EnterMutex(pGroup);
       pGroup->nMinPage += pCache->nMin;
       pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
-      pcache1LeaveMutex(pGroup);
+    }
+    pcache1LeaveMutex(pGroup);
+    if( pCache->nHash==0 ){
+      pcache1Destroy((sqlite3_pcache*)pCache);
+      pCache = 0;
     }
   }
   return (sqlite3_pcache *)pCache;
@@ -656,103 +662,24 @@ static int pcache1Pagecount(sqlite3_pcache *p){
   return n;
 }
 
+
 /*
-** Implementation of the sqlite3_pcache.xFetch method. 
-**
-** Fetch a page by key value.
+** Implement steps 3, 4, and 5 of the pcache1Fetch() algorithm described
+** in the header of the pcache1Fetch() procedure.
 **
-** Whether or not a new page may be allocated by this function depends on
-** the value of the createFlag argument.  0 means do not allocate a new
-** page.  1 means allocate a new page if space is easily available.  2 
-** means to try really hard to allocate a new page.
-**
-** For a non-purgeable cache (a cache used as the storage for an in-memory
-** database) there is really no difference between createFlag 1 and 2.  So
-** the calling function (pcache.c) will never have a createFlag of 1 on
-** a non-purgeable cache.
-**
-** There are three different approaches to obtaining space for a page,
-** depending on the value of parameter createFlag (which may be 0, 1 or 2).
-**
-**   1. Regardless of the value of createFlag, the cache is searched for a 
-**      copy of the requested page. If one is found, it is returned.
-**
-**   2. If createFlag==0 and the page is not already in the cache, NULL is
-**      returned.
-**
-**   3. If createFlag is 1, and the page is not already in the cache, then
-**      return NULL (do not allocate a new page) if any of the following
-**      conditions are true:
-**
-**       (a) the number of pages pinned by the cache is greater than
-**           PCache1.nMax, or
-**
-**       (b) the number of pages pinned by the cache is greater than
-**           the sum of nMax for all purgeable caches, less the sum of 
-**           nMin for all other purgeable caches, or
-**
-**   4. If none of the first three conditions apply and the cache is marked
-**      as purgeable, and if one of the following is true:
-**
-**       (a) The number of pages allocated for the cache is already 
-**           PCache1.nMax, or
-**
-**       (b) The number of pages allocated for all purgeable caches is
-**           already equal to or greater than the sum of nMax for all
-**           purgeable caches,
-**
-**       (c) The system is under memory pressure and wants to avoid
-**           unnecessary pages cache entry allocations
-**
-**      then attempt to recycle a page from the LRU list. If it is the right
-**      size, return the recycled buffer. Otherwise, free the buffer and
-**      proceed to step 5. 
-**
-**   5. Otherwise, allocate and return a new page buffer.
+** This steps are broken out into a separate procedure because they are
+** usually not needed, and by avoiding the stack initialization required
+** for these steps, the main pcache1Fetch() procedure can run faster.
 */
-static sqlite3_pcache_page *pcache1Fetch(
-  sqlite3_pcache *p
+static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
+  PCache1 *pCache
   unsigned int iKey, 
   int createFlag
 ){
   unsigned int nPinned;
-  PCache1 *pCache = (PCache1 *)p;
-  PGroup *pGroup;
+  PGroup *pGroup = pCache->pGroup;
   PgHdr1 *pPage = 0;
 
-  assert( offsetof(PgHdr1,page)==0 );
-  assert( pCache->bPurgeable || createFlag!=1 );
-  assert( pCache->bPurgeable || pCache->nMin==0 );
-  assert( pCache->bPurgeable==0 || pCache->nMin==10 );
-  assert( pCache->nMin==0 || pCache->bPurgeable );
-  pcache1EnterMutex(pGroup = pCache->pGroup);
-
-  /* Step 1: Search the hash table for an existing entry. */
-  if( pCache->nHash>0 ){
-    unsigned int h = iKey % pCache->nHash;
-    for(pPage=pCache->apHash[h]; pPage&&pPage->iKey!=iKey; pPage=pPage->pNext);
-  }
-
-  /* Step 2: Abort if no existing page is found and createFlag is 0 */
-  if( pPage ){
-    if( !pPage->isPinned ) pcache1PinPage(pPage);
-    goto fetch_out;
-  }
-  if( createFlag==0 ){
-    goto fetch_out;
-  }
-
-  /* The pGroup local variable will normally be initialized by the
-  ** pcache1EnterMutex() macro above.  But if SQLITE_MUTEX_OMIT is defined,
-  ** then pcache1EnterMutex() is a no-op, so we have to initialize the
-  ** local variable here.  Delaying the initialization of pGroup is an
-  ** optimization:  The common case is to exit the module before reaching
-  ** this point.
-  */
-#ifdef SQLITE_MUTEX_OMIT
-  pGroup = pCache->pGroup;
-#endif
-
   /* Step 3: Abort if createFlag is 1 but the cache is nearly full */
   assert( pCache->nPage >= pCache->nRecyclable );
   nPinned = pCache->nPage - pCache->nRecyclable;
@@ -763,12 +690,10 @@ static sqlite3_pcache_page *pcache1Fetch(
      || nPinned>=pCache->n90pct
      || pcache1UnderMemoryPressure(pCache)
   )){
-    goto fetch_out;
+    return 0;
   }
 
-  if( pCache->nPage>=pCache->nHash && pcache1ResizeHash(pCache) ){
-    goto fetch_out;
-  }
+  if( pCache->nPage>=pCache->nHash ) pcache1ResizeHash(pCache);
   assert( pCache->nHash>0 && pCache->apHash );
 
   /* Step 4. Try to recycle a page. */
@@ -819,13 +744,96 @@ static sqlite3_pcache_page *pcache1Fetch(
     pPage->isPinned = 1;
     *(void **)pPage->page.pExtra = 0;
     pCache->apHash[h] = pPage;
+    if( iKey>pCache->iMaxKey ){
+      pCache->iMaxKey = iKey;
+    }
   }
+  return pPage;
+}
+
+/*
+** Implementation of the sqlite3_pcache.xFetch method. 
+**
+** Fetch a page by key value.
+**
+** Whether or not a new page may be allocated by this function depends on
+** the value of the createFlag argument.  0 means do not allocate a new
+** page.  1 means allocate a new page if space is easily available.  2 
+** means to try really hard to allocate a new page.
+**
+** For a non-purgeable cache (a cache used as the storage for an in-memory
+** database) there is really no difference between createFlag 1 and 2.  So
+** the calling function (pcache.c) will never have a createFlag of 1 on
+** a non-purgeable cache.
+**
+** There are three different approaches to obtaining space for a page,
+** depending on the value of parameter createFlag (which may be 0, 1 or 2).
+**
+**   1. Regardless of the value of createFlag, the cache is searched for a 
+**      copy of the requested page. If one is found, it is returned.
+**
+**   2. If createFlag==0 and the page is not already in the cache, NULL is
+**      returned.
+**
+**   3. If createFlag is 1, and the page is not already in the cache, then
+**      return NULL (do not allocate a new page) if any of the following
+**      conditions are true:
+**
+**       (a) the number of pages pinned by the cache is greater than
+**           PCache1.nMax, or
+**
+**       (b) the number of pages pinned by the cache is greater than
+**           the sum of nMax for all purgeable caches, less the sum of 
+**           nMin for all other purgeable caches, or
+**
+**   4. If none of the first three conditions apply and the cache is marked
+**      as purgeable, and if one of the following is true:
+**
+**       (a) The number of pages allocated for the cache is already 
+**           PCache1.nMax, or
+**
+**       (b) The number of pages allocated for all purgeable caches is
+**           already equal to or greater than the sum of nMax for all
+**           purgeable caches,
+**
+**       (c) The system is under memory pressure and wants to avoid
+**           unnecessary pages cache entry allocations
+**
+**      then attempt to recycle a page from the LRU list. If it is the right
+**      size, return the recycled buffer. Otherwise, free the buffer and
+**      proceed to step 5. 
+**
+**   5. Otherwise, allocate and return a new page buffer.
+*/
+static sqlite3_pcache_page *pcache1Fetch(
+  sqlite3_pcache *p, 
+  unsigned int iKey, 
+  int createFlag
+){
+  PCache1 *pCache = (PCache1 *)p;
+  PgHdr1 *pPage = 0;
+
+  assert( offsetof(PgHdr1,page)==0 );
+  assert( pCache->bPurgeable || createFlag!=1 );
+  assert( pCache->bPurgeable || pCache->nMin==0 );
+  assert( pCache->bPurgeable==0 || pCache->nMin==10 );
+  assert( pCache->nMin==0 || pCache->bPurgeable );
+  assert( pCache->nHash>0 );
+  pcache1EnterMutex(pCache->pGroup);
+
+  /* Step 1: Search the hash table for an existing entry. */
+  pPage = pCache->apHash[iKey % pCache->nHash];
+  while( pPage && pPage->iKey!=iKey ){ pPage = pPage->pNext; }
 
-fetch_out:
-  if( pPage && iKey>pCache->iMaxKey ){
-    pCache->iMaxKey = iKey;
+  /* Step 2: Abort if no existing page is found and createFlag is 0 */
+  if( pPage ){
+    if( !pPage->isPinned ) pcache1PinPage(pPage);
+  }else if( createFlag ){
+    /* Steps 3, 4, and 5 implemented by this subroutine */
+    pPage = pcache1FetchStage2(pCache, iKey, createFlag);
   }
-  pcache1LeaveMutex(pGroup);
+  assert( pPage==0 || pCache->iMaxKey>=iKey );
+  pcache1LeaveMutex(pCache->pGroup);
   return (sqlite3_pcache_page*)pPage;
 }