Refactor the sqlite3PcacheFetch() routine into three separate routines,
which are significantly faster overall and about 100 bytes smaller in size as well. FossilOrigin-Name: bdb6e4978d1a26d5f795262172605184264ede9c
This commit is contained in:
parent
a1dc42aa91
commit
bc59ac0e26
18
manifest
18
manifest
@ -1,5 +1,5 @@
|
||||
C Add\sa\sVDBE\ssynopsis\scomment\sfor\sclarification.
|
||||
D 2014-08-27T17:53:40.315
|
||||
C Refactor\sthe\ssqlite3PcacheFetch()\sroutine\sinto\sthree\sseparate\sroutines,\nwhich\sare\ssignificantly\sfaster\soverall\sand\sabout\s100\sbytes\ssmaller\sin\nsize\sas\swell.
|
||||
D 2014-08-27T23:18:01.324
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -211,11 +211,11 @@ F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa
|
||||
F src/os_unix.c bd7df3094a60915c148517504c76df4fca24e542
|
||||
F src/os_win.c d067fce558a5032e6e6afe62899e5397bf63cf3e
|
||||
F src/os_win.h 09e751b20bbc107ffbd46e13555dc73576d88e21
|
||||
F src/pager.c 27fb89e62e0ccf10218805ed31315ccb2d56c0ce
|
||||
F src/pager.c 3e732d2bbdd8d8d95fed0c5ae7e718d73153c4c5
|
||||
F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428
|
||||
F src/parse.y 22d6a074e5f5a7258947a1dc55a9bf946b765dd0
|
||||
F src/pcache.c c216e4077449be57e9752a348490ffa467b85599
|
||||
F src/pcache.h 80a9c3f7d7b7080388e8654717cb45e7b99f14a6
|
||||
F src/pcache.c 3b3791297e8977002e56b4a9b8916f2039abad9b
|
||||
F src/pcache.h 9b559127b83f84ff76d735c8262f04853be0c59a
|
||||
F src/pcache1.c c5af6403a55178c9d1c09e4f77b0f9c88822762c
|
||||
F src/pragma.c d10ef67c4de79f78188b965b4b7988aff1d66f2e
|
||||
F src/prepare.c 3842c1dfc0b053458e3adcf9f6efc48e03e3fe3d
|
||||
@ -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 d8b1c4336145d436241863c3525530e24a24799b
|
||||
R 34521287dadc9603bb93e0f806afdcf3
|
||||
U mistachkin
|
||||
Z d8914cdf39bc88ab4bc7c63f9115cf85
|
||||
P 029a6dc744c24e7be482298c678af8a115d6a87b
|
||||
R dd4d11ad7a65bf573cc08ce3e7bd3aa7
|
||||
U drh
|
||||
Z c0c64dee6940e13662884c6ed139ac1a
|
||||
|
@ -1 +1 @@
|
||||
029a6dc744c24e7be482298c678af8a115d6a87b
|
||||
bdb6e4978d1a26d5f795262172605184264ede9c
|
20
src/pager.c
20
src/pager.c
@ -5286,7 +5286,6 @@ int sqlite3PagerAcquire(
|
||||
if( pPager->errCode!=SQLITE_OK ){
|
||||
rc = pPager->errCode;
|
||||
}else{
|
||||
|
||||
if( bMmapOk && pagerUseWal(pPager) ){
|
||||
rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
|
||||
if( rc!=SQLITE_OK ) goto pager_acquire_err;
|
||||
@ -5301,7 +5300,7 @@ int sqlite3PagerAcquire(
|
||||
|
||||
if( rc==SQLITE_OK && pData ){
|
||||
if( pPager->eState>PAGER_READER ){
|
||||
(void)sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &pPg);
|
||||
pPg = sqlite3PagerLookup(pPager, pgno);
|
||||
}
|
||||
if( pPg==0 ){
|
||||
rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg);
|
||||
@ -5319,7 +5318,16 @@ int sqlite3PagerAcquire(
|
||||
}
|
||||
}
|
||||
|
||||
rc = sqlite3PcacheFetch(pPager->pPCache, pgno, 3, ppPage);
|
||||
{
|
||||
sqlite3_pcache_page *pBase;
|
||||
pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3);
|
||||
if( pBase==0 ){
|
||||
rc = sqlite3PcacheFetchStress(pPager->pPCache, pgno, &pBase);
|
||||
if( rc!=SQLITE_OK ) goto pager_acquire_err;
|
||||
}
|
||||
pPg = *ppPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pBase);
|
||||
if( pPg==0 ) rc = SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
@ -5416,12 +5424,12 @@ pager_acquire_err:
|
||||
** has ever happened.
|
||||
*/
|
||||
DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
|
||||
PgHdr *pPg = 0;
|
||||
sqlite3_pcache_page *pPage;
|
||||
assert( pPager!=0 );
|
||||
assert( pgno!=0 );
|
||||
assert( pPager->pPCache!=0 );
|
||||
sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &pPg);
|
||||
return pPg;
|
||||
pPage = sqlite3PcacheFetch(pPager->pPCache, pgno, 0);
|
||||
return sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pPage);
|
||||
}
|
||||
|
||||
/*
|
||||
|
191
src/pcache.c
191
src/pcache.c
@ -231,15 +231,33 @@ int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
|
||||
|
||||
/*
|
||||
** Try to obtain a page from the cache.
|
||||
**
|
||||
** This routine returns a pointer to an sqlite3_pcache_page object if
|
||||
** such an object is already in cache, or if a new one is created.
|
||||
** This routine returns a NULL pointer if the object was not in cache
|
||||
** and could not be created.
|
||||
**
|
||||
** The createFlags should be 0 to check for existing pages and should
|
||||
** be 3 (not 1, but 3) to try to create a new page.
|
||||
**
|
||||
** If the createFlag is 0, then NULL is always returned if the page
|
||||
** is not already in the cache. If createFlag is 1, then a new page
|
||||
** is created only if that can be done without spilling dirty pages
|
||||
** and without exceeding the cache size limit.
|
||||
**
|
||||
** The caller needs to invoke sqlite3PcacheFetchFinish() to properly
|
||||
** initialize the sqlite3_pcache_page object and convert it into a
|
||||
** PgHdr object. The sqlite3PcacheFetch() and sqlite3PcacheFetchFinish()
|
||||
** routines are split this way for performance reasons. When separated
|
||||
** they can both (usually) operate without having to push values to
|
||||
** the stack on entry and pop them back off on exit, which saves a
|
||||
** lot of pushing and popping.
|
||||
*/
|
||||
int sqlite3PcacheFetch(
|
||||
sqlite3_pcache_page *sqlite3PcacheFetch(
|
||||
PCache *pCache, /* Obtain the page from this cache */
|
||||
Pgno pgno, /* Page number to obtain */
|
||||
int createFlag, /* If true, create page if it does not exist already */
|
||||
PgHdr **ppPage /* Write the page here */
|
||||
int createFlag /* If true, create page if it does not exist already */
|
||||
){
|
||||
sqlite3_pcache_page *pPage;
|
||||
PgHdr *pPgHdr = 0;
|
||||
int eCreate;
|
||||
|
||||
assert( pCache!=0 );
|
||||
@ -258,69 +276,116 @@ int sqlite3PcacheFetch(
|
||||
assert( eCreate==0 || eCreate==1 || eCreate==2 );
|
||||
assert( createFlag==0 || pCache->eCreate==eCreate );
|
||||
assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) );
|
||||
pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
|
||||
if( !pPage && eCreate==1 ){
|
||||
PgHdr *pPg;
|
||||
return sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
|
||||
}
|
||||
|
||||
/* Find a dirty page to write-out and recycle. First try to find a
|
||||
** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
|
||||
** cleared), but if that is not possible settle for any other
|
||||
** unreferenced dirty page.
|
||||
*/
|
||||
expensive_assert( pcacheCheckSynced(pCache) );
|
||||
for(pPg=pCache->pSynced;
|
||||
pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC));
|
||||
pPg=pPg->pDirtyPrev
|
||||
);
|
||||
pCache->pSynced = pPg;
|
||||
if( !pPg ){
|
||||
for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev);
|
||||
}
|
||||
if( pPg ){
|
||||
int rc;
|
||||
/*
|
||||
** If the sqlite3PcacheFetch() routine is unable to allocate a new
|
||||
** page because new clean pages are available for reuse and the cache
|
||||
** size limit has been reached, then this routine can be invoked to
|
||||
** try harder to allocate a page. This routine might invoke the stress
|
||||
** callback to spill dirty pages to the journal. It will then try to
|
||||
** allocate the new page and will only fail to allocate a new page on
|
||||
** an OOM error.
|
||||
**
|
||||
** This routine should be invoked only after sqlite3PcacheFetch() fails.
|
||||
*/
|
||||
int sqlite3PcacheFetchStress(
|
||||
PCache *pCache, /* Obtain the page from this cache */
|
||||
Pgno pgno, /* Page number to obtain */
|
||||
sqlite3_pcache_page **ppPage /* Write result here */
|
||||
){
|
||||
PgHdr *pPg;
|
||||
if( pCache->eCreate==2 ) return 0;
|
||||
|
||||
|
||||
/* Find a dirty page to write-out and recycle. First try to find a
|
||||
** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
|
||||
** cleared), but if that is not possible settle for any other
|
||||
** unreferenced dirty page.
|
||||
*/
|
||||
expensive_assert( pcacheCheckSynced(pCache) );
|
||||
for(pPg=pCache->pSynced;
|
||||
pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC));
|
||||
pPg=pPg->pDirtyPrev
|
||||
);
|
||||
pCache->pSynced = pPg;
|
||||
if( !pPg ){
|
||||
for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev);
|
||||
}
|
||||
if( pPg ){
|
||||
int rc;
|
||||
#ifdef SQLITE_LOG_CACHE_SPILL
|
||||
sqlite3_log(SQLITE_FULL,
|
||||
"spill page %d making room for %d - cache used: %d/%d",
|
||||
pPg->pgno, pgno,
|
||||
sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache),
|
||||
numberOfCachePages(pCache));
|
||||
sqlite3_log(SQLITE_FULL,
|
||||
"spill page %d making room for %d - cache used: %d/%d",
|
||||
pPg->pgno, pgno,
|
||||
sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache),
|
||||
numberOfCachePages(pCache));
|
||||
#endif
|
||||
rc = pCache->xStress(pCache->pStress, pPg);
|
||||
if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2);
|
||||
}
|
||||
|
||||
if( pPage ){
|
||||
pPgHdr = (PgHdr *)pPage->pExtra;
|
||||
|
||||
if( !pPgHdr->pPage ){
|
||||
memset(pPgHdr, 0, sizeof(PgHdr));
|
||||
pPgHdr->pPage = pPage;
|
||||
pPgHdr->pData = pPage->pBuf;
|
||||
pPgHdr->pExtra = (void *)&pPgHdr[1];
|
||||
memset(pPgHdr->pExtra, 0, pCache->szExtra);
|
||||
pPgHdr->pCache = pCache;
|
||||
pPgHdr->pgno = pgno;
|
||||
}
|
||||
assert( pPgHdr->pCache==pCache );
|
||||
assert( pPgHdr->pgno==pgno );
|
||||
assert( pPgHdr->pData==pPage->pBuf );
|
||||
assert( pPgHdr->pExtra==(void *)&pPgHdr[1] );
|
||||
|
||||
if( 0==pPgHdr->nRef ){
|
||||
pCache->nRef++;
|
||||
}
|
||||
pPgHdr->nRef++;
|
||||
if( pgno==1 ){
|
||||
pCache->pPage1 = pPgHdr;
|
||||
rc = pCache->xStress(pCache->pStress, pPg);
|
||||
if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
*ppPage = pPgHdr;
|
||||
return (pPgHdr==0 && eCreate) ? SQLITE_NOMEM : SQLITE_OK;
|
||||
*ppPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2);
|
||||
return *ppPage==0 ? SQLITE_NOMEM : SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** This is a helper routine for sqlite3PcacheFetchFinish()
|
||||
**
|
||||
** In the uncommon case where the page being fetched has not been
|
||||
** initialized, this routine is invoked to do the initialization.
|
||||
** This routine is broken out into a separate function since it
|
||||
** requires extra stack manipulation that can be avoided in the common
|
||||
** case.
|
||||
*/
|
||||
static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit(
|
||||
PCache *pCache, /* Obtain the page from this cache */
|
||||
Pgno pgno, /* Page number obtained */
|
||||
sqlite3_pcache_page *pPage /* Page obtained by prior PcacheFetch() call */
|
||||
){
|
||||
PgHdr *pPgHdr;
|
||||
assert( pPage!=0 );
|
||||
pPgHdr = (PgHdr*)pPage->pExtra;
|
||||
assert( pPgHdr->pPage==0 );
|
||||
memset(pPgHdr, 0, sizeof(PgHdr));
|
||||
pPgHdr->pPage = pPage;
|
||||
pPgHdr->pData = pPage->pBuf;
|
||||
pPgHdr->pExtra = (void *)&pPgHdr[1];
|
||||
memset(pPgHdr->pExtra, 0, pCache->szExtra);
|
||||
pPgHdr->pCache = pCache;
|
||||
pPgHdr->pgno = pgno;
|
||||
return sqlite3PcacheFetchFinish(pCache,pgno,pPage);
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine converts the sqlite3_pcache_page object returned by
|
||||
** sqlite3PcacheFetch() into an initialized PgHdr object. This routine
|
||||
** must be called after sqlite3PcacheFetch() in order to get a usable
|
||||
** result.
|
||||
*/
|
||||
PgHdr *sqlite3PcacheFetchFinish(
|
||||
PCache *pCache, /* Obtain the page from this cache */
|
||||
Pgno pgno, /* Page number obtained */
|
||||
sqlite3_pcache_page *pPage /* Page obtained by prior PcacheFetch() call */
|
||||
){
|
||||
PgHdr *pPgHdr;
|
||||
|
||||
if( pPage==0 ) return 0;
|
||||
pPgHdr = (PgHdr *)pPage->pExtra;
|
||||
|
||||
if( !pPgHdr->pPage ){
|
||||
return pcacheFetchFinishWithInit(pCache, pgno, pPage);
|
||||
}
|
||||
if( 0==pPgHdr->nRef ){
|
||||
pCache->nRef++;
|
||||
}
|
||||
pPgHdr->nRef++;
|
||||
if( pgno==1 ){
|
||||
pCache->pPage1 = pPgHdr;
|
||||
}
|
||||
return pPgHdr;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -88,7 +88,9 @@ int sqlite3PcacheSize(void);
|
||||
/* One release per successful fetch. Page is pinned until released.
|
||||
** Reference counted.
|
||||
*/
|
||||
int sqlite3PcacheFetch(PCache*, Pgno, int createFlag, PgHdr**);
|
||||
sqlite3_pcache_page *sqlite3PcacheFetch(PCache*, Pgno, int createFlag);
|
||||
int sqlite3PcacheFetchStress(PCache*, Pgno, sqlite3_pcache_page**);
|
||||
PgHdr *sqlite3PcacheFetchFinish(PCache*, Pgno, sqlite3_pcache_page *pPage);
|
||||
void sqlite3PcacheRelease(PgHdr*);
|
||||
|
||||
void sqlite3PcacheDrop(PgHdr*); /* Remove page from cache */
|
||||
|
Loading…
x
Reference in New Issue
Block a user