Faster implementation of pcache1Fetch()
FossilOrigin-Name: 0371cc3bb07448bcd64fd671f3e71bb7f30deb4d
This commit is contained in:
@@ -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
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
bd41d394d48516eb7d8ddc46abdcb427aa80173e
|
||||
0371cc3bb07448bcd64fd671f3e71bb7f30deb4d
|
||||
+109
-101
@@ -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,6 +662,95 @@ static int pcache1Pagecount(sqlite3_pcache *p){
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Implement steps 3, 4, and 5 of the pcache1Fetch() algorithm described
|
||||
** in the header of the pcache1Fetch() procedure.
|
||||
**
|
||||
** 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 SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
|
||||
PCache1 *pCache,
|
||||
unsigned int iKey,
|
||||
int createFlag
|
||||
){
|
||||
unsigned int nPinned;
|
||||
PGroup *pGroup = pCache->pGroup;
|
||||
PgHdr1 *pPage = 0;
|
||||
|
||||
/* Step 3: Abort if createFlag is 1 but the cache is nearly full */
|
||||
assert( pCache->nPage >= pCache->nRecyclable );
|
||||
nPinned = pCache->nPage - pCache->nRecyclable;
|
||||
assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage );
|
||||
assert( pCache->n90pct == pCache->nMax*9/10 );
|
||||
if( createFlag==1 && (
|
||||
nPinned>=pGroup->mxPinned
|
||||
|| nPinned>=pCache->n90pct
|
||||
|| pcache1UnderMemoryPressure(pCache)
|
||||
)){
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( pCache->nPage>=pCache->nHash ) pcache1ResizeHash(pCache);
|
||||
assert( pCache->nHash>0 && pCache->apHash );
|
||||
|
||||
/* Step 4. Try to recycle a page. */
|
||||
if( pCache->bPurgeable && pGroup->pLruTail && (
|
||||
(pCache->nPage+1>=pCache->nMax)
|
||||
|| pGroup->nCurrentPage>=pGroup->nMaxPage
|
||||
|| pcache1UnderMemoryPressure(pCache)
|
||||
)){
|
||||
PCache1 *pOther;
|
||||
pPage = pGroup->pLruTail;
|
||||
assert( pPage->isPinned==0 );
|
||||
pcache1RemoveFromHash(pPage);
|
||||
pcache1PinPage(pPage);
|
||||
pOther = pPage->pCache;
|
||||
|
||||
/* We want to verify that szPage and szExtra are the same for pOther
|
||||
** and pCache. Assert that we can verify this by comparing sums. */
|
||||
assert( (pCache->szPage & (pCache->szPage-1))==0 && pCache->szPage>=512 );
|
||||
assert( pCache->szExtra<512 );
|
||||
assert( (pOther->szPage & (pOther->szPage-1))==0 && pOther->szPage>=512 );
|
||||
assert( pOther->szExtra<512 );
|
||||
|
||||
if( pOther->szPage+pOther->szExtra != pCache->szPage+pCache->szExtra ){
|
||||
pcache1FreePage(pPage);
|
||||
pPage = 0;
|
||||
}else{
|
||||
pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable);
|
||||
}
|
||||
}
|
||||
|
||||
/* Step 5. If a usable page buffer has still not been found,
|
||||
** attempt to allocate a new one.
|
||||
*/
|
||||
if( !pPage ){
|
||||
if( createFlag==1 ) sqlite3BeginBenignMalloc();
|
||||
pPage = pcache1AllocPage(pCache);
|
||||
if( createFlag==1 ) sqlite3EndBenignMalloc();
|
||||
}
|
||||
|
||||
if( pPage ){
|
||||
unsigned int h = iKey % pCache->nHash;
|
||||
pCache->nPage++;
|
||||
pPage->iKey = iKey;
|
||||
pPage->pNext = pCache->apHash[h];
|
||||
pPage->pCache = pCache;
|
||||
pPage->pLruPrev = 0;
|
||||
pPage->pLruNext = 0;
|
||||
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.
|
||||
**
|
||||
@@ -715,9 +810,7 @@ static sqlite3_pcache_page *pcache1Fetch(
|
||||
unsigned int iKey,
|
||||
int createFlag
|
||||
){
|
||||
unsigned int nPinned;
|
||||
PCache1 *pCache = (PCache1 *)p;
|
||||
PGroup *pGroup;
|
||||
PgHdr1 *pPage = 0;
|
||||
|
||||
assert( offsetof(PgHdr1,page)==0 );
|
||||
@@ -725,107 +818,22 @@ static sqlite3_pcache_page *pcache1Fetch(
|
||||
assert( pCache->bPurgeable || pCache->nMin==0 );
|
||||
assert( pCache->bPurgeable==0 || pCache->nMin==10 );
|
||||
assert( pCache->nMin==0 || pCache->bPurgeable );
|
||||
pcache1EnterMutex(pGroup = pCache->pGroup);
|
||||
assert( pCache->nHash>0 );
|
||||
pcache1EnterMutex(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);
|
||||
}
|
||||
pPage = pCache->apHash[iKey % pCache->nHash];
|
||||
while( 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;
|
||||
}else if( createFlag ){
|
||||
/* Steps 3, 4, and 5 implemented by this subroutine */
|
||||
pPage = pcache1FetchStage2(pCache, iKey, createFlag);
|
||||
}
|
||||
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;
|
||||
assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage );
|
||||
assert( pCache->n90pct == pCache->nMax*9/10 );
|
||||
if( createFlag==1 && (
|
||||
nPinned>=pGroup->mxPinned
|
||||
|| nPinned>=pCache->n90pct
|
||||
|| pcache1UnderMemoryPressure(pCache)
|
||||
)){
|
||||
goto fetch_out;
|
||||
}
|
||||
|
||||
if( pCache->nPage>=pCache->nHash && pcache1ResizeHash(pCache) ){
|
||||
goto fetch_out;
|
||||
}
|
||||
assert( pCache->nHash>0 && pCache->apHash );
|
||||
|
||||
/* Step 4. Try to recycle a page. */
|
||||
if( pCache->bPurgeable && pGroup->pLruTail && (
|
||||
(pCache->nPage+1>=pCache->nMax)
|
||||
|| pGroup->nCurrentPage>=pGroup->nMaxPage
|
||||
|| pcache1UnderMemoryPressure(pCache)
|
||||
)){
|
||||
PCache1 *pOther;
|
||||
pPage = pGroup->pLruTail;
|
||||
assert( pPage->isPinned==0 );
|
||||
pcache1RemoveFromHash(pPage);
|
||||
pcache1PinPage(pPage);
|
||||
pOther = pPage->pCache;
|
||||
|
||||
/* We want to verify that szPage and szExtra are the same for pOther
|
||||
** and pCache. Assert that we can verify this by comparing sums. */
|
||||
assert( (pCache->szPage & (pCache->szPage-1))==0 && pCache->szPage>=512 );
|
||||
assert( pCache->szExtra<512 );
|
||||
assert( (pOther->szPage & (pOther->szPage-1))==0 && pOther->szPage>=512 );
|
||||
assert( pOther->szExtra<512 );
|
||||
|
||||
if( pOther->szPage+pOther->szExtra != pCache->szPage+pCache->szExtra ){
|
||||
pcache1FreePage(pPage);
|
||||
pPage = 0;
|
||||
}else{
|
||||
pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable);
|
||||
}
|
||||
}
|
||||
|
||||
/* Step 5. If a usable page buffer has still not been found,
|
||||
** attempt to allocate a new one.
|
||||
*/
|
||||
if( !pPage ){
|
||||
if( createFlag==1 ) sqlite3BeginBenignMalloc();
|
||||
pPage = pcache1AllocPage(pCache);
|
||||
if( createFlag==1 ) sqlite3EndBenignMalloc();
|
||||
}
|
||||
|
||||
if( pPage ){
|
||||
unsigned int h = iKey % pCache->nHash;
|
||||
pCache->nPage++;
|
||||
pPage->iKey = iKey;
|
||||
pPage->pNext = pCache->apHash[h];
|
||||
pPage->pCache = pCache;
|
||||
pPage->pLruPrev = 0;
|
||||
pPage->pLruNext = 0;
|
||||
pPage->isPinned = 1;
|
||||
*(void **)pPage->page.pExtra = 0;
|
||||
pCache->apHash[h] = pPage;
|
||||
}
|
||||
|
||||
fetch_out:
|
||||
if( pPage && iKey>pCache->iMaxKey ){
|
||||
pCache->iMaxKey = iKey;
|
||||
}
|
||||
pcache1LeaveMutex(pGroup);
|
||||
assert( pPage==0 || pCache->iMaxKey>=iKey );
|
||||
pcache1LeaveMutex(pCache->pGroup);
|
||||
return (sqlite3_pcache_page*)pPage;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user