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:
drh 2014-08-27 23:18:01 +00:00
parent a1dc42aa91
commit bc59ac0e26
5 changed files with 155 additions and 80 deletions

View File

@ -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

View File

@ -1 +1 @@
029a6dc744c24e7be482298c678af8a115d6a87b
bdb6e4978d1a26d5f795262172605184264ede9c

View File

@ -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);
}
/*

View File

@ -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,9 +276,28 @@ 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 ){
return sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
}
/*
** 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
@ -290,14 +327,28 @@ int sqlite3PcacheFetch(
return rc;
}
}
*ppPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2);
return *ppPage==0 ? SQLITE_NOMEM : SQLITE_OK;
}
pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2);
}
if( pPage ){
pPgHdr = (PgHdr *)pPage->pExtra;
if( !pPgHdr->pPage ){
/*
** 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;
@ -305,12 +356,28 @@ int sqlite3PcacheFetch(
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] );
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++;
}
@ -318,9 +385,7 @@ int sqlite3PcacheFetch(
if( pgno==1 ){
pCache->pPage1 = pPgHdr;
}
}
*ppPage = pPgHdr;
return (pPgHdr==0 && eCreate) ? SQLITE_NOMEM : SQLITE_OK;
return pPgHdr;
}
/*

View File

@ -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 */