diff --git a/source/libs/tdb/src/sqlite/pcache.c b/source/libs/tdb/src/sqlite/pcache.c index 14d1e7cde0..d66d012c3e 100644 --- a/source/libs/tdb/src/sqlite/pcache.c +++ b/source/libs/tdb/src/sqlite/pcache.c @@ -31,7 +31,7 @@ ** ** The PCache.pSynced variable is used to optimize searching for a dirty ** page to eject from the cache mid-transaction. It is better to eject -** a page that does not require a journal sync than one that does. +** a page that does not require a journal sync than one that does. ** Therefore, pSynced is maintained so that it *almost* always points ** to either the oldest page in the pDirty/pDirtyTail list that has a ** clear PGHDR_NEED_SYNC flag or to a page that is older than this one @@ -39,18 +39,18 @@ ** pointers). */ struct PCache { - PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */ - PgHdr *pSynced; /* Last synced page in dirty page list */ - int nRefSum; /* Sum of ref counts over all pages */ - int szCache; /* Configured cache size */ - int szSpill; /* Size before spilling occurs */ - int szPage; /* Size of every page in this cache */ - int szExtra; /* Size of extra space for each page */ - u8 bPurgeable; /* True if pages are on backing store */ - u8 eCreate; /* eCreate value for for xFetch() */ - int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */ - void *pStress; /* Argument to xStress */ - sqlite3_pcache *pCache; /* Pluggable cache module */ + PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */ + PgHdr *pSynced; /* Last synced page in dirty page list */ + int nRefSum; /* Sum of ref counts over all pages */ + int szCache; /* Configured cache size */ + int szSpill; /* Size before spilling occurs */ + int szPage; /* Size of every page in this cache */ + int szExtra; /* Size of extra space for each page */ + u8 bPurgeable; /* True if pages are on backing store */ + u8 eCreate; /* eCreate value for for xFetch() */ + int (*xStress)(void *, PgHdr *); /* Call to try make a page clean */ + void * pStress; /* Argument to xStress */ + sqlite3_pcache *pCache; /* Pluggable cache module */ }; /********************************** Test and Debug Logic **********************/ @@ -63,36 +63,39 @@ struct PCache { ** is displayed for many operations, resulting in a lot of output. */ #if defined(SQLITE_DEBUG) && 0 - int sqlite3PcacheTrace = 2; /* 0: off 1: simple 2: cache dumps */ - int sqlite3PcacheMxDump = 9999; /* Max cache entries for pcacheDump() */ -# define pcacheTrace(X) if(sqlite3PcacheTrace){sqlite3DebugPrintf X;} - void pcacheDump(PCache *pCache){ - int N; - int i, j; - sqlite3_pcache_page *pLower; - PgHdr *pPg; - unsigned char *a; - - if( sqlite3PcacheTrace<2 ) return; - if( pCache->pCache==0 ) return; - N = sqlite3PcachePagecount(pCache); - if( N>sqlite3PcacheMxDump ) N = sqlite3PcacheMxDump; - for(i=1; i<=N; i++){ - pLower = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0); - if( pLower==0 ) continue; - pPg = (PgHdr*)pLower->pExtra; - printf("%3d: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags); - a = (unsigned char *)pLower->pBuf; - for(j=0; j<12; j++) printf("%02x", a[j]); - printf("\n"); - if( pPg->pPage==0 ){ - sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, pLower, 0); - } +int sqlite3PcacheTrace = 2; /* 0: off 1: simple 2: cache dumps */ +int sqlite3PcacheMxDump = 9999; /* Max cache entries for pcacheDump() */ +#define pcacheTrace(X) \ + if (sqlite3PcacheTrace) { \ + sqlite3DebugPrintf X; \ + } +void pcacheDump(PCache *pCache) { + int N; + int i, j; + sqlite3_pcache_page *pLower; + PgHdr * pPg; + unsigned char * a; + + if (sqlite3PcacheTrace < 2) return; + if (pCache->pCache == 0) return; + N = sqlite3PcachePagecount(pCache); + if (N > sqlite3PcacheMxDump) N = sqlite3PcacheMxDump; + for (i = 1; i <= N; i++) { + pLower = pcache2.xFetch(pCache->pCache, i, 0); + if (pLower == 0) continue; + pPg = (PgHdr *)pLower->pExtra; + printf("%3d: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags); + a = (unsigned char *)pLower->pBuf; + for (j = 0; j < 12; j++) printf("%02x", a[j]); + printf("\n"); + if (pPg->pPage == 0) { + pcache2.xUnpin(pCache->pCache, pLower, 0); } } - #else -# define pcacheTrace(X) -# define pcacheDump(X) +} +#else +#define pcacheTrace(X) +#define pcacheDump(X) #endif /* @@ -105,20 +108,20 @@ struct PCache { ** assert( sqlite3PcachePageSanity(pPg) ); */ #ifdef SQLITE_DEBUG -int sqlite3PcachePageSanity(PgHdr *pPg){ +int sqlite3PcachePageSanity(PgHdr *pPg) { PCache *pCache; - assert( pPg!=0 ); - assert( pPg->pgno>0 || pPg->pPager==0 ); /* Page number is 1 or more */ + assert(pPg != 0); + assert(pPg->pgno > 0 || pPg->pPager == 0); /* Page number is 1 or more */ pCache = pPg->pCache; - assert( pCache!=0 ); /* Every page has an associated PCache */ - if( pPg->flags & PGHDR_CLEAN ){ - assert( (pPg->flags & PGHDR_DIRTY)==0 );/* Cannot be both CLEAN and DIRTY */ - assert( pCache->pDirty!=pPg ); /* CLEAN pages not on dirty list */ - assert( pCache->pDirtyTail!=pPg ); + assert(pCache != 0); /* Every page has an associated PCache */ + if (pPg->flags & PGHDR_CLEAN) { + assert((pPg->flags & PGHDR_DIRTY) == 0); /* Cannot be both CLEAN and DIRTY */ + assert(pCache->pDirty != pPg); /* CLEAN pages not on dirty list */ + assert(pCache->pDirtyTail != pPg); } /* WRITEABLE pages must also be DIRTY */ - if( pPg->flags & PGHDR_WRITEABLE ){ - assert( pPg->flags & PGHDR_DIRTY ); /* WRITEABLE implies DIRTY */ + if (pPg->flags & PGHDR_WRITEABLE) { + assert(pPg->flags & PGHDR_DIRTY); /* WRITEABLE implies DIRTY */ } /* NEED_SYNC can be set independently of WRITEABLE. This can happen, ** for example, when using the sqlite3PagerDontWrite() optimization: @@ -141,13 +144,12 @@ int sqlite3PcachePageSanity(PgHdr *pPg){ } #endif /* SQLITE_DEBUG */ - /********************************** Linked List Management ********************/ /* Allowed values for second argument to pcacheManageDirtyList() */ -#define PCACHE_DIRTYLIST_REMOVE 1 /* Remove pPage from dirty list */ -#define PCACHE_DIRTYLIST_ADD 2 /* Add pPage to the dirty list */ -#define PCACHE_DIRTYLIST_FRONT 3 /* Move pPage to the front of the list */ +#define PCACHE_DIRTYLIST_REMOVE 1 /* Remove pPage from dirty list */ +#define PCACHE_DIRTYLIST_ADD 2 /* Add pPage to the dirty list */ +#define PCACHE_DIRTYLIST_FRONT 3 /* Move pPage to the front of the list */ /* ** Manage pPage's participation on the dirty list. Bits of the addRemove @@ -155,66 +157,63 @@ int sqlite3PcachePageSanity(PgHdr *pPg){ ** remove pPage from the dirty list. The 0x02 means add pPage back to ** the dirty list. Doing both moves pPage to the front of the dirty list. */ -static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){ +static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove) { PCache *p = pPage->pCache; - pcacheTrace(("%p.DIRTYLIST.%s %d\n", p, - addRemove==1 ? "REMOVE" : addRemove==2 ? "ADD" : "FRONT", - pPage->pgno)); - if( addRemove & PCACHE_DIRTYLIST_REMOVE ){ - assert( pPage->pDirtyNext || pPage==p->pDirtyTail ); - assert( pPage->pDirtyPrev || pPage==p->pDirty ); - + pcacheTrace(("%p.DIRTYLIST.%s %d\n", p, addRemove == 1 ? "REMOVE" : addRemove == 2 ? "ADD" : "FRONT", pPage->pgno)); + if (addRemove & PCACHE_DIRTYLIST_REMOVE) { + assert(pPage->pDirtyNext || pPage == p->pDirtyTail); + assert(pPage->pDirtyPrev || pPage == p->pDirty); + /* Update the PCache1.pSynced variable if necessary. */ - if( p->pSynced==pPage ){ + if (p->pSynced == pPage) { p->pSynced = pPage->pDirtyPrev; } - - if( pPage->pDirtyNext ){ + + if (pPage->pDirtyNext) { pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev; - }else{ - assert( pPage==p->pDirtyTail ); + } else { + assert(pPage == p->pDirtyTail); p->pDirtyTail = pPage->pDirtyPrev; } - if( pPage->pDirtyPrev ){ + if (pPage->pDirtyPrev) { pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext; - }else{ - /* If there are now no dirty pages in the cache, set eCreate to 2. + } else { + /* If there are now no dirty pages in the cache, set eCreate to 2. ** This is an optimization that allows sqlite3PcacheFetch() to skip ** searching for a dirty page to eject from the cache when it might ** otherwise have to. */ - assert( pPage==p->pDirty ); + assert(pPage == p->pDirty); p->pDirty = pPage->pDirtyNext; - assert( p->bPurgeable || p->eCreate==2 ); - if( p->pDirty==0 ){ /*OPTIMIZATION-IF-TRUE*/ - assert( p->bPurgeable==0 || p->eCreate==1 ); + assert(p->bPurgeable || p->eCreate == 2); + if (p->pDirty == 0) { /*OPTIMIZATION-IF-TRUE*/ + assert(p->bPurgeable == 0 || p->eCreate == 1); p->eCreate = 2; } } } - if( addRemove & PCACHE_DIRTYLIST_ADD ){ + if (addRemove & PCACHE_DIRTYLIST_ADD) { pPage->pDirtyPrev = 0; pPage->pDirtyNext = p->pDirty; - if( pPage->pDirtyNext ){ - assert( pPage->pDirtyNext->pDirtyPrev==0 ); + if (pPage->pDirtyNext) { + assert(pPage->pDirtyNext->pDirtyPrev == 0); pPage->pDirtyNext->pDirtyPrev = pPage; - }else{ + } else { p->pDirtyTail = pPage; - if( p->bPurgeable ){ - assert( p->eCreate==2 ); + if (p->bPurgeable) { + assert(p->eCreate == 2); p->eCreate = 1; } } p->pDirty = pPage; /* If pSynced is NULL and this page has a clear NEED_SYNC flag, set - ** pSynced to point to it. Checking the NEED_SYNC flag is an + ** pSynced to point to it. Checking the NEED_SYNC flag is an ** optimization, as if pSynced points to a page with the NEED_SYNC - ** flag set sqlite3PcacheFetchStress() searches through all newer + ** flag set sqlite3PcacheFetchStress() searches through all newer ** entries of the dirty-list for a page with NEED_SYNC clear anyway. */ - if( !p->pSynced - && 0==(pPage->flags&PGHDR_NEED_SYNC) /*OPTIMIZATION-IF-FALSE*/ - ){ + if (!p->pSynced && 0 == (pPage->flags & PGHDR_NEED_SYNC) /*OPTIMIZATION-IF-FALSE*/ + ) { p->pSynced = pPage; } } @@ -225,10 +224,10 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){ ** Wrapper around the pluggable caches xUnpin method. If the cache is ** being used for an in-memory database, this function is a no-op. */ -static void pcacheUnpin(PgHdr *p){ - if( p->pCache->bPurgeable ){ +static void pcacheUnpin(PgHdr *p) { + if (p->pCache->bPurgeable) { pcacheTrace(("%p.UNPIN %d\n", p->pCache, p->pgno)); - sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 0); + pcache2.xUnpin(p->pCache->pCache, p->pPage, 0); pcacheDump(p->pCache); } } @@ -237,54 +236,45 @@ static void pcacheUnpin(PgHdr *p){ ** Compute the number of pages of cache requested. p->szCache is the ** cache size requested by the "PRAGMA cache_size" statement. */ -static int numberOfCachePages(PCache *p){ - if( p->szCache>=0 ){ +static int numberOfCachePages(PCache *p) { + if (p->szCache >= 0) { /* IMPLEMENTATION-OF: R-42059-47211 If the argument N is positive then the ** suggested cache size is set to N. */ return p->szCache; - }else{ + } else { i64 n; /* IMPLEMANTATION-OF: R-59858-46238 If the argument N is negative, then the ** number of cache pages is adjusted to be a number of pages that would ** use approximately abs(N*1024) bytes of memory based on the current ** page size. */ - n = ((-1024*(i64)p->szCache)/(p->szPage+p->szExtra)); - if( n>1000000000 ) n = 1000000000; + n = ((-1024 * (i64)p->szCache) / (p->szPage + p->szExtra)); + if (n > 1000000000) n = 1000000000; return (int)n; } } /*************************************************** General Interfaces ****** ** -** Initialize and shutdown the page cache subsystem. Neither of these +** Initialize and shutdown the page cache subsystem. Neither of these ** functions are threadsafe. */ -int sqlite3PcacheInitialize(void){ - if( sqlite3GlobalConfig.pcache2.xInit==0 ){ - /* IMPLEMENTATION-OF: R-26801-64137 If the xInit() method is NULL, then the - ** built-in default page cache is used instead of the application defined - ** page cache. */ - sqlite3PCacheSetDefault(); - assert( sqlite3GlobalConfig.pcache2.xInit!=0 ); - } - return sqlite3GlobalConfig.pcache2.xInit(sqlite3GlobalConfig.pcache2.pArg); -} -void sqlite3PcacheShutdown(void){ - if( sqlite3GlobalConfig.pcache2.xShutdown ){ +int sqlite3PcacheInitialize(void) { return pcache2.xInit(pcache2.pArg); } +void sqlite3PcacheShutdown(void) { + if (pcache2.xShutdown) { /* IMPLEMENTATION-OF: R-26000-56589 The xShutdown() method may be NULL. */ - sqlite3GlobalConfig.pcache2.xShutdown(sqlite3GlobalConfig.pcache2.pArg); + pcache2.xShutdown(pcache2.pArg); } } /* ** Return the size in bytes of a PCache object. */ -int sqlite3PcacheSize(void){ return sizeof(PCache); } +int sqlite3PcacheSize(void) { return sizeof(PCache); } /* ** Create a new PCache object. Storage space to hold the object -** has already been allocated and is passed in as the p pointer. -** The caller discovers how much space needs to be allocated by +** has already been allocated and is passed in as the p pointer. +** The caller discovers how much space needs to be allocated by ** calling sqlite3PcacheSize(). ** ** szExtra is some extra space allocated for each page. The first @@ -293,25 +283,24 @@ int sqlite3PcacheSize(void){ return sizeof(PCache); } ** to this module, the extra space really ends up being the MemPage ** structure in the pager. */ -int sqlite3PcacheOpen( - int szPage, /* Size of every page */ - int szExtra, /* Extra space associated with each page */ - int bPurgeable, /* True if pages are on backing store */ - int (*xStress)(void*,PgHdr*),/* Call to try to make pages clean */ - void *pStress, /* Argument to xStress */ - PCache *p /* Preallocated space for the PCache */ -){ +int sqlite3PcacheOpen(int szPage, /* Size of every page */ + int szExtra, /* Extra space associated with each page */ + int bPurgeable, /* True if pages are on backing store */ + int (*xStress)(void *, PgHdr *), /* Call to try to make pages clean */ + void * pStress, /* Argument to xStress */ + PCache *p /* Preallocated space for the PCache */ +) { memset(p, 0, sizeof(PCache)); p->szPage = 1; p->szExtra = szExtra; - assert( szExtra>=8 ); /* First 8 bytes will be zeroed */ + assert(szExtra >= 8); /* First 8 bytes will be zeroed */ p->bPurgeable = bPurgeable; p->eCreate = 2; p->xStress = xStress; p->pStress = pStress; p->szCache = 100; p->szSpill = 1; - pcacheTrace(("%p.OPEN szPage %d bPurgeable %d\n",p,szPage,bPurgeable)); + pcacheTrace(("%p.OPEN szPage %d bPurgeable %d\n", p, szPage, bPurgeable)); return sqlite3PcacheSetPageSize(p, szPage); } @@ -319,22 +308,19 @@ int sqlite3PcacheOpen( ** Change the page size for PCache object. The caller must ensure that there ** are no outstanding page references when this function is called. */ -int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){ - assert( pCache->nRefSum==0 && pCache->pDirty==0 ); - if( pCache->szPage ){ +int sqlite3PcacheSetPageSize(PCache *pCache, int szPage) { + assert(pCache->nRefSum == 0 && pCache->pDirty == 0); + if (pCache->szPage) { sqlite3_pcache *pNew; - pNew = sqlite3GlobalConfig.pcache2.xCreate( - szPage, pCache->szExtra + ROUND8(sizeof(PgHdr)), - pCache->bPurgeable - ); - if( pNew==0 ) return SQLITE_NOMEM_BKPT; - sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache)); - if( pCache->pCache ){ - sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache); + pNew = pcache2.xCreate(szPage, pCache->szExtra + ROUND8(sizeof(PgHdr)), pCache->bPurgeable); + if (pNew == 0) return SQLITE_NOMEM_BKPT; + pcache2.xCachesize(pNew, numberOfCachePages(pCache)); + if (pCache->pCache) { + pcache2.xDestroy(pCache->pCache); } pCache->pCache = pNew; pCache->szPage = szPage; - pcacheTrace(("%p.PAGESIZE %d\n",pCache,szPage)); + pcacheTrace(("%p.PAGESIZE %d\n", pCache, szPage)); } return SQLITE_OK; } @@ -363,18 +349,17 @@ int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){ ** the stack on entry and pop them back off on exit, which saves a ** lot of pushing and popping. */ -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 */ -){ - int eCreate; +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 */ +) { + int eCreate; sqlite3_pcache_page *pRes; - assert( pCache!=0 ); - assert( pCache->pCache!=0 ); - assert( createFlag==3 || createFlag==0 ); - assert( pCache->eCreate==((pCache->bPurgeable && pCache->pDirty) ? 1 : 2) ); + assert(pCache != 0); + assert(pCache->pCache != 0); + assert(createFlag == 3 || createFlag == 0); + assert(pCache->eCreate == ((pCache->bPurgeable && pCache->pDirty) ? 1 : 2)); /* eCreate defines what to do if the page does not exist. ** 0 Do not allocate a new page. (createFlag==0) @@ -384,19 +369,18 @@ sqlite3_pcache_page *sqlite3PcacheFetch( ** (createFlag==1 AND !(bPurgeable AND pDirty) */ eCreate = createFlag & pCache->eCreate; - assert( eCreate==0 || eCreate==1 || eCreate==2 ); - assert( createFlag==0 || pCache->eCreate==eCreate ); - assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) ); - pRes = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate); - pcacheTrace(("%p.FETCH %d%s (result: %p)\n",pCache,pgno, - createFlag?" create":"",pRes)); + assert(eCreate == 0 || eCreate == 1 || eCreate == 2); + assert(createFlag == 0 || pCache->eCreate == eCreate); + assert(createFlag == 0 || eCreate == 1 + (!pCache->bPurgeable || !pCache->pDirty)); + pRes = pcache2.xFetch(pCache->pCache, pgno, eCreate); + pcacheTrace(("%p.FETCH %d%s (result: %p)\n", pCache, pgno, createFlag ? " create" : "", pRes)); return pRes; } /* ** If the sqlite3PcacheFetch() routine is unable to allocate a new ** page because no clean pages are available for reuse and the cache -** size limit has been reached, then this routine can be invoked to +** 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 @@ -404,51 +388,46 @@ sqlite3_pcache_page *sqlite3PcacheFetch( ** ** 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 */ -){ +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; + if (pCache->eCreate == 2) return 0; - if( sqlite3PcachePagecount(pCache)>pCache->szSpill ){ - /* Find a dirty page to write-out and recycle. First try to find a + if (sqlite3PcachePagecount(pCache) > pCache->szSpill) { + /* 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 + ** cleared), but if that is not possible settle for any other ** unreferenced dirty page. ** ** If the LRU page in the dirty list that has a clear PGHDR_NEED_SYNC ** flag is currently referenced, then the following may leave pSynced ** set incorrectly (pointing to other than the LRU page with NEED_SYNC ** cleared). This is Ok, as pSynced is just an optimization. */ - for(pPg=pCache->pSynced; - pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); - pPg=pPg->pDirtyPrev - ); + 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) { + for (pPg = pCache->pDirtyTail; pPg && pPg->nRef; pPg = pPg->pDirtyPrev) + ; } - if( pPg ){ + 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.pcache2.xPagecount(pCache->pCache), - numberOfCachePages(pCache)); + sqlite3_log(SQLITE_FULL, "spill page %d making room for %d - cache used: %d/%d", pPg->pgno, pgno, + pcache2.xPagecount(pCache->pCache), numberOfCachePages(pCache)); #endif - pcacheTrace(("%p.SPILL %d\n",pCache,pPg->pgno)); + pcacheTrace(("%p.SPILL %d\n", pCache, pPg->pgno)); rc = pCache->xStress(pCache->pStress, pPg); pcacheDump(pCache); - if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ + if (rc != SQLITE_OK && rc != SQLITE_BUSY) { return rc; } } } - *ppPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2); - return *ppPage==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK; + *ppPage = pcache2.xFetch(pCache->pCache, pgno, 2); + return *ppPage == 0 ? SQLITE_NOMEM_BKPT : SQLITE_OK; } /* @@ -461,15 +440,15 @@ int sqlite3PcacheFetchStress( ** 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 */ -){ + 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->pDirty, 0, sizeof(PgHdr) - offsetof(PgHdr,pDirty)); + assert(pPage != 0); + pPgHdr = (PgHdr *)pPage->pExtra; + assert(pPgHdr->pPage == 0); + memset(&pPgHdr->pDirty, 0, sizeof(PgHdr) - offsetof(PgHdr, pDirty)); pPgHdr->pPage = pPage; pPgHdr->pData = pPage->pBuf; pPgHdr->pExtra = (void *)&pPgHdr[1]; @@ -477,7 +456,7 @@ static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit( pPgHdr->pCache = pCache; pPgHdr->pgno = pgno; pPgHdr->flags = PGHDR_CLEAN; - return sqlite3PcacheFetchFinish(pCache,pgno,pPage); + return sqlite3PcacheFetchFinish(pCache, pgno, pPage); } /* @@ -486,22 +465,21 @@ static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit( ** 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 *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; - assert( pPage!=0 ); + assert(pPage != 0); pPgHdr = (PgHdr *)pPage->pExtra; - if( !pPgHdr->pPage ){ + if (!pPgHdr->pPage) { return pcacheFetchFinishWithInit(pCache, pgno, pPage); } pCache->nRefSum++; pPgHdr->nRef++; - assert( sqlite3PcachePageSanity(pPgHdr) ); + assert(sqlite3PcachePageSanity(pPgHdr)); return pPgHdr; } @@ -509,13 +487,13 @@ PgHdr *sqlite3PcacheFetchFinish( ** Decrement the reference count on a page. If the page is clean and the ** reference count drops to 0, then it is made eligible for recycling. */ -void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){ - assert( p->nRef>0 ); +void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p) { + assert(p->nRef > 0); p->pCache->nRefSum--; - if( (--p->nRef)==0 ){ - if( p->flags&PGHDR_CLEAN ){ + if ((--p->nRef) == 0) { + if (p->flags & PGHDR_CLEAN) { pcacheUnpin(p); - }else{ + } else { pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT); } } @@ -524,9 +502,9 @@ void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){ /* ** Increase the reference count of a supplied page by 1. */ -void sqlite3PcacheRef(PgHdr *p){ - assert(p->nRef>0); - assert( sqlite3PcachePageSanity(p) ); +void sqlite3PcacheRef(PgHdr *p) { + assert(p->nRef > 0); + assert(sqlite3PcachePageSanity(p)); p->nRef++; p->pCache->nRefSum++; } @@ -536,32 +514,32 @@ void sqlite3PcacheRef(PgHdr *p){ ** page. This function deletes that reference, so after it returns the ** page pointed to by p is invalid. */ -void sqlite3PcacheDrop(PgHdr *p){ - assert( p->nRef==1 ); - assert( sqlite3PcachePageSanity(p) ); - if( p->flags&PGHDR_DIRTY ){ +void sqlite3PcacheDrop(PgHdr *p) { + assert(p->nRef == 1); + assert(sqlite3PcachePageSanity(p)); + if (p->flags & PGHDR_DIRTY) { pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE); } p->pCache->nRefSum--; - sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 1); + pcache2.xUnpin(p->pCache->pCache, p->pPage, 1); } /* ** Make sure the page is marked as dirty. If it isn't dirty already, ** make it so. */ -void sqlite3PcacheMakeDirty(PgHdr *p){ - assert( p->nRef>0 ); - assert( sqlite3PcachePageSanity(p) ); - if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){ /*OPTIMIZATION-IF-FALSE*/ +void sqlite3PcacheMakeDirty(PgHdr *p) { + assert(p->nRef > 0); + assert(sqlite3PcachePageSanity(p)); + if (p->flags & (PGHDR_CLEAN | PGHDR_DONT_WRITE)) { /*OPTIMIZATION-IF-FALSE*/ p->flags &= ~PGHDR_DONT_WRITE; - if( p->flags & PGHDR_CLEAN ){ - p->flags ^= (PGHDR_DIRTY|PGHDR_CLEAN); - pcacheTrace(("%p.DIRTY %d\n",p->pCache,p->pgno)); - assert( (p->flags & (PGHDR_DIRTY|PGHDR_CLEAN))==PGHDR_DIRTY ); + if (p->flags & PGHDR_CLEAN) { + p->flags ^= (PGHDR_DIRTY | PGHDR_CLEAN); + pcacheTrace(("%p.DIRTY %d\n", p->pCache, p->pgno)); + assert((p->flags & (PGHDR_DIRTY | PGHDR_CLEAN)) == PGHDR_DIRTY); pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD); } - assert( sqlite3PcachePageSanity(p) ); + assert(sqlite3PcachePageSanity(p)); } } @@ -569,16 +547,16 @@ void sqlite3PcacheMakeDirty(PgHdr *p){ ** Make sure the page is marked as clean. If it isn't clean already, ** make it so. */ -void sqlite3PcacheMakeClean(PgHdr *p){ - assert( sqlite3PcachePageSanity(p) ); - assert( (p->flags & PGHDR_DIRTY)!=0 ); - assert( (p->flags & PGHDR_CLEAN)==0 ); +void sqlite3PcacheMakeClean(PgHdr *p) { + assert(sqlite3PcachePageSanity(p)); + assert((p->flags & PGHDR_DIRTY) != 0); + assert((p->flags & PGHDR_CLEAN) == 0); pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE); - p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC|PGHDR_WRITEABLE); + p->flags &= ~(PGHDR_DIRTY | PGHDR_NEED_SYNC | PGHDR_WRITEABLE); p->flags |= PGHDR_CLEAN; - pcacheTrace(("%p.CLEAN %d\n",p->pCache,p->pgno)); - assert( sqlite3PcachePageSanity(p) ); - if( p->nRef==0 ){ + pcacheTrace(("%p.CLEAN %d\n", p->pCache, p->pgno)); + assert(sqlite3PcachePageSanity(p)); + if (p->nRef == 0) { pcacheUnpin(p); } } @@ -586,10 +564,10 @@ void sqlite3PcacheMakeClean(PgHdr *p){ /* ** Make every page in the cache clean. */ -void sqlite3PcacheCleanAll(PCache *pCache){ +void sqlite3PcacheCleanAll(PCache *pCache) { PgHdr *p; - pcacheTrace(("%p.CLEAN-ALL\n",pCache)); - while( (p = pCache->pDirty)!=0 ){ + pcacheTrace(("%p.CLEAN-ALL\n", pCache)); + while ((p = pCache->pDirty) != 0) { sqlite3PcacheMakeClean(p); } } @@ -597,11 +575,11 @@ void sqlite3PcacheCleanAll(PCache *pCache){ /* ** Clear the PGHDR_NEED_SYNC and PGHDR_WRITEABLE flag from all dirty pages. */ -void sqlite3PcacheClearWritable(PCache *pCache){ +void sqlite3PcacheClearWritable(PCache *pCache) { PgHdr *p; - pcacheTrace(("%p.CLEAR-WRITEABLE\n",pCache)); - for(p=pCache->pDirty; p; p=p->pDirtyNext){ - p->flags &= ~(PGHDR_NEED_SYNC|PGHDR_WRITEABLE); + pcacheTrace(("%p.CLEAR-WRITEABLE\n", pCache)); + for (p = pCache->pDirty; p; p = p->pDirtyNext) { + p->flags &= ~(PGHDR_NEED_SYNC | PGHDR_WRITEABLE); } pCache->pSynced = pCache->pDirtyTail; } @@ -609,26 +587,26 @@ void sqlite3PcacheClearWritable(PCache *pCache){ /* ** Clear the PGHDR_NEED_SYNC flag from all dirty pages. */ -void sqlite3PcacheClearSyncFlags(PCache *pCache){ +void sqlite3PcacheClearSyncFlags(PCache *pCache) { PgHdr *p; - for(p=pCache->pDirty; p; p=p->pDirtyNext){ + for (p = pCache->pDirty; p; p = p->pDirtyNext) { p->flags &= ~PGHDR_NEED_SYNC; } pCache->pSynced = pCache->pDirtyTail; } /* -** Change the page number of page p to newPgno. +** Change the page number of page p to newPgno. */ -void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){ +void sqlite3PcacheMove(PgHdr *p, Pgno newPgno) { PCache *pCache = p->pCache; - assert( p->nRef>0 ); - assert( newPgno>0 ); - assert( sqlite3PcachePageSanity(p) ); - pcacheTrace(("%p.MOVE %d -> %d\n",pCache,p->pgno,newPgno)); - sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno); + assert(p->nRef > 0); + assert(newPgno > 0); + assert(sqlite3PcachePageSanity(p)); + pcacheTrace(("%p.MOVE %d -> %d\n", pCache, p->pgno, newPgno)); + pcache2.xRekey(pCache->pCache, p->pPage, p->pgno, newPgno); p->pgno = newPgno; - if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){ + if ((p->flags & PGHDR_DIRTY) && (p->flags & PGHDR_NEED_SYNC)) { pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT); } } @@ -642,74 +620,72 @@ void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){ ** function is 0, then the data area associated with page 1 is zeroed, but ** the page object is not dropped. */ -void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){ - if( pCache->pCache ){ +void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno) { + if (pCache->pCache) { PgHdr *p; PgHdr *pNext; - pcacheTrace(("%p.TRUNCATE %d\n",pCache,pgno)); - for(p=pCache->pDirty; p; p=pNext){ + pcacheTrace(("%p.TRUNCATE %d\n", pCache, pgno)); + for (p = pCache->pDirty; p; p = pNext) { pNext = p->pDirtyNext; /* This routine never gets call with a positive pgno except right ** after sqlite3PcacheCleanAll(). So if there are dirty pages, ** it must be that pgno==0. */ - assert( p->pgno>0 ); - if( p->pgno>pgno ){ - assert( p->flags&PGHDR_DIRTY ); + assert(p->pgno > 0); + if (p->pgno > pgno) { + assert(p->flags & PGHDR_DIRTY); sqlite3PcacheMakeClean(p); } } - if( pgno==0 && pCache->nRefSum ){ + if (pgno == 0 && pCache->nRefSum) { sqlite3_pcache_page *pPage1; - pPage1 = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache,1,0); - if( ALWAYS(pPage1) ){ /* Page 1 is always available in cache, because - ** pCache->nRefSum>0 */ + pPage1 = pcache2.xFetch(pCache->pCache, 1, 0); + if (ALWAYS(pPage1)) { /* Page 1 is always available in cache, because + ** pCache->nRefSum>0 */ memset(pPage1->pBuf, 0, pCache->szPage); pgno = 1; } } - sqlite3GlobalConfig.pcache2.xTruncate(pCache->pCache, pgno+1); + pcache2.xTruncate(pCache->pCache, pgno + 1); } } /* ** Close a cache. */ -void sqlite3PcacheClose(PCache *pCache){ - assert( pCache->pCache!=0 ); - pcacheTrace(("%p.CLOSE\n",pCache)); - sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache); +void sqlite3PcacheClose(PCache *pCache) { + assert(pCache->pCache != 0); + pcacheTrace(("%p.CLOSE\n", pCache)); + pcache2.xDestroy(pCache->pCache); } -/* +/* ** Discard the contents of the cache. */ -void sqlite3PcacheClear(PCache *pCache){ - sqlite3PcacheTruncate(pCache, 0); -} +void sqlite3PcacheClear(PCache *pCache) { sqlite3PcacheTruncate(pCache, 0); } /* ** Merge two lists of pages connected by pDirty and in pgno order. ** Do not bother fixing the pDirtyPrev pointers. */ -static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){ +static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB) { PgHdr result, *pTail; pTail = &result; - assert( pA!=0 && pB!=0 ); - for(;;){ - if( pA->pgnopgno ){ + assert(pA != 0 && pB != 0); + for (;;) { + if (pA->pgno < pB->pgno) { pTail->pDirty = pA; pTail = pA; pA = pA->pDirty; - if( pA==0 ){ + if (pA == 0) { pTail->pDirty = pB; break; } - }else{ + } else { pTail->pDirty = pB; pTail = pB; pB = pB->pDirty; - if( pB==0 ){ + if (pB == 0) { pTail->pDirty = pA; break; } @@ -728,25 +704,25 @@ static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){ ** One extra bucket is added to catch overflow in case something ** ever changes to make the previous sentence incorrect. */ -#define N_SORT_BUCKET 32 -static PgHdr *pcacheSortDirtyList(PgHdr *pIn){ +#define N_SORT_BUCKET 32 +static PgHdr *pcacheSortDirtyList(PgHdr *pIn) { PgHdr *a[N_SORT_BUCKET], *p; - int i; + int i; memset(a, 0, sizeof(a)); - while( pIn ){ + while (pIn) { p = pIn; pIn = p->pDirty; p->pDirty = 0; - for(i=0; ALWAYS(ipDirty; p; p=p->pDirtyNext){ + for (p = pCache->pDirty; p; p = p->pDirtyNext) { p->pDirty = p->pDirtyNext; } return pcacheSortDirtyList(pCache->pDirty); } -/* +/* ** Return the total number of references to all pages held by the cache. ** ** This is not the total number of pages referenced, but the sum of the ** reference count for all pages. */ -int sqlite3PcacheRefCount(PCache *pCache){ - return pCache->nRefSum; -} +int sqlite3PcacheRefCount(PCache *pCache) { return pCache->nRefSum; } /* ** Return the number of references to the page supplied as an argument. */ -int sqlite3PcachePageRefcount(PgHdr *p){ - return p->nRef; -} +int sqlite3PcachePageRefcount(PgHdr *p) { return p->nRef; } -/* +/* ** Return the total number of pages in the cache. */ -int sqlite3PcachePagecount(PCache *pCache){ - assert( pCache->pCache!=0 ); - return sqlite3GlobalConfig.pcache2.xPagecount(pCache->pCache); +int sqlite3PcachePagecount(PCache *pCache) { + assert(pCache->pCache != 0); + return pcache2.xPagecount(pCache->pCache); } #ifdef SQLITE_TEST /* ** Get the suggested cache-size value. */ -int sqlite3PcacheGetCachesize(PCache *pCache){ - return numberOfCachePages(pCache); -} +int sqlite3PcacheGetCachesize(PCache *pCache) { return numberOfCachePages(pCache); } #endif /* ** Set the suggested cache-size value. */ -void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){ - assert( pCache->pCache!=0 ); +void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage) { + assert(pCache->pCache != 0); pCache->szCache = mxPage; - sqlite3GlobalConfig.pcache2.xCachesize(pCache->pCache, - numberOfCachePages(pCache)); + pcache2.xCachesize(pCache->pCache, numberOfCachePages(pCache)); } /* @@ -821,53 +790,51 @@ void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){ ** argument is zero. Return the effective cache-spill size, which will ** be the larger of the szSpill and szCache. */ -int sqlite3PcacheSetSpillsize(PCache *p, int mxPage){ +int sqlite3PcacheSetSpillsize(PCache *p, int mxPage) { int res; - assert( p->pCache!=0 ); - if( mxPage ){ - if( mxPage<0 ){ - mxPage = (int)((-1024*(i64)mxPage)/(p->szPage+p->szExtra)); + assert(p->pCache != 0); + if (mxPage) { + if (mxPage < 0) { + mxPage = (int)((-1024 * (i64)mxPage) / (p->szPage + p->szExtra)); } p->szSpill = mxPage; } res = numberOfCachePages(p); - if( resszSpill ) res = p->szSpill; + if (res < p->szSpill) res = p->szSpill; return res; } /* ** Free up as much memory as possible from the page cache. */ -void sqlite3PcacheShrink(PCache *pCache){ - assert( pCache->pCache!=0 ); - sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache); +void sqlite3PcacheShrink(PCache *pCache) { + assert(pCache->pCache != 0); + pcache2.xShrink(pCache->pCache); } /* ** Return the size of the header added by this middleware layer ** in the page-cache hierarchy. */ -int sqlite3HeaderSizePcache(void){ return ROUND8(sizeof(PgHdr)); } +int sqlite3HeaderSizePcache(void) { return ROUND8(sizeof(PgHdr)); } /* ** Return the number of dirty pages currently in the cache, as a percentage ** of the configured cache size. */ -int sqlite3PCachePercentDirty(PCache *pCache){ +int sqlite3PCachePercentDirty(PCache *pCache) { PgHdr *pDirty; - int nDirty = 0; - int nCache = numberOfCachePages(pCache); - for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext) nDirty++; + int nDirty = 0; + int nCache = numberOfCachePages(pCache); + for (pDirty = pCache->pDirty; pDirty; pDirty = pDirty->pDirtyNext) nDirty++; return nCache ? (int)(((i64)nDirty * 100) / nCache) : 0; } #ifdef SQLITE_DIRECT_OVERFLOW_READ -/* +/* ** Return true if there are one or more dirty pages in the cache. Else false. */ -int sqlite3PCacheIsDirty(PCache *pCache){ - return (pCache->pDirty!=0); -} +int sqlite3PCacheIsDirty(PCache *pCache) { return (pCache->pDirty != 0); } #endif #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG) @@ -876,9 +843,9 @@ int sqlite3PCacheIsDirty(PCache *pCache){ ** callback. This is only used if the SQLITE_CHECK_PAGES macro is ** defined. */ -void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)){ +void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)) { PgHdr *pDirty; - for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext){ + for (pDirty = pCache->pDirty; pDirty; pDirty = pDirty->pDirtyNext) { xIter(pDirty); } } diff --git a/source/libs/tdb/src/sqlite/pcache1.c b/source/libs/tdb/src/sqlite/pcache1.c index a93b146894..497ef28ffe 100644 --- a/source/libs/tdb/src/sqlite/pcache1.c +++ b/source/libs/tdb/src/sqlite/pcache1.c @@ -199,10 +199,26 @@ struct PgFreeslot { PgFreeslot *pNext; /* Next free slot */ }; +sqlite3_pcache_methods2 pcache2 = { + 1, /* iVersion */ + 0, /* pArg */ + pcache1Init, /* xInit */ + pcache1Shutdown, /* xShutdown */ + pcache1Create, /* xCreate */ + pcache1Cachesize, /* xCachesize */ + pcache1Pagecount, /* xPagecount */ + pcache1Fetch, /* xFetch */ + pcache1Unpin, /* xUnpin */ + pcache1Rekey, /* xRekey */ + pcache1Truncate, /* xTruncate */ + pcache1Destroy, /* xDestroy */ + pcache1Shrink /* xShrink */ +}; + /* ** Global data used by this cache. */ -static SQLITE_WSD struct PCacheGlobal { +static struct PCacheGlobal { PGroup grp; /* The global PGroup for mode (2) */ /* Variables related to SQLITE_CONFIG_PAGECACHE settings. The @@ -226,14 +242,7 @@ static SQLITE_WSD struct PCacheGlobal { ** (2) even if an incorrect value is read, no great harm is done since this ** is really just an optimization. */ int bUnderPressure; /* True if low on PAGECACHE memory */ -} pcache1_g; - -/* -** All code in this file should access the global structure above via the -** alias "pcache1". This ensures that the WSD emulation is used when -** compiling for systems that do not support real WSD. -*/ -#define pcache1 (GLOBAL(struct PCacheGlobal, pcache1_g)) +} pcache1; /* ** Macros to enter and leave the PCache LRU mutex. diff --git a/source/libs/tdb/src/sqliteinc/pcache.h b/source/libs/tdb/src/sqliteinc/pcache.h index eb55396afa..62e36991f0 100644 --- a/source/libs/tdb/src/sqliteinc/pcache.h +++ b/source/libs/tdb/src/sqliteinc/pcache.h @@ -10,12 +10,12 @@ ** ************************************************************************* ** This header file defines the interface that the sqlite page cache -** subsystem. +** subsystem. */ #ifndef _PCACHE_H_ -typedef struct PgHdr PgHdr; +typedef struct PgHdr PgHdr; typedef struct PCache PCache; /* @@ -23,43 +23,44 @@ typedef struct PCache PCache; ** structure. */ struct PgHdr { - sqlite3_pcache_page *pPage; /* Pcache object page handle */ - void *pData; /* Page data */ - void *pExtra; /* Extra content */ - PCache *pCache; /* PRIVATE: Cache that owns this page */ - PgHdr *pDirty; /* Transient list of dirty sorted by pgno */ - Pager *pPager; /* The pager this page is part of */ - Pgno pgno; /* Page number for this page */ + sqlite3_pcache_page *pPage; /* Pcache object page handle */ + void * pData; /* Page data */ + void * pExtra; /* Extra content */ + PCache * pCache; /* PRIVATE: Cache that owns this page */ + PgHdr * pDirty; /* Transient list of dirty sorted by pgno */ + Pager * pPager; /* The pager this page is part of */ + Pgno pgno; /* Page number for this page */ #ifdef SQLITE_CHECK_PAGES - u32 pageHash; /* Hash of page content */ + u32 pageHash; /* Hash of page content */ #endif - u16 flags; /* PGHDR flags defined below */ + u16 flags; /* PGHDR flags defined below */ /********************************************************************** - ** Elements above, except pCache, are public. All that follow are + ** Elements above, except pCache, are public. All that follow are ** private to pcache.c and should not be accessed by other modules. ** pCache is grouped with the public elements for efficiency. */ - i16 nRef; /* Number of users of this page */ - PgHdr *pDirtyNext; /* Next element in list of dirty pages */ - PgHdr *pDirtyPrev; /* Previous element in list of dirty pages */ - /* NB: pDirtyNext and pDirtyPrev are undefined if the - ** PgHdr object is not dirty */ + i16 nRef; /* Number of users of this page */ + PgHdr *pDirtyNext; /* Next element in list of dirty pages */ + PgHdr *pDirtyPrev; /* Previous element in list of dirty pages */ + /* NB: pDirtyNext and pDirtyPrev are undefined if the + ** PgHdr object is not dirty */ }; /* Bit values for PgHdr.flags */ -#define PGHDR_CLEAN 0x001 /* Page not on the PCache.pDirty list */ -#define PGHDR_DIRTY 0x002 /* Page is on the PCache.pDirty list */ -#define PGHDR_WRITEABLE 0x004 /* Journaled and ready to modify */ -#define PGHDR_NEED_SYNC 0x008 /* Fsync the rollback journal before - ** writing this page to the database */ -#define PGHDR_DONT_WRITE 0x010 /* Do not write content to disk */ -#define PGHDR_MMAP 0x020 /* This is an mmap page object */ +#define PGHDR_CLEAN 0x001 /* Page not on the PCache.pDirty list */ +#define PGHDR_DIRTY 0x002 /* Page is on the PCache.pDirty list */ +#define PGHDR_WRITEABLE 0x004 /* Journaled and ready to modify */ +#define PGHDR_NEED_SYNC \ + 0x008 /* Fsync the rollback journal before \ + ** writing this page to the database */ +#define PGHDR_DONT_WRITE 0x010 /* Do not write content to disk */ +#define PGHDR_MMAP 0x020 /* This is an mmap page object */ -#define PGHDR_WAL_APPEND 0x040 /* Appended to wal file */ +#define PGHDR_WAL_APPEND 0x040 /* Appended to wal file */ /* Initialize and shutdown the page cache subsystem */ -int sqlite3PcacheInitialize(void); +int sqlite3PcacheInitialize(void); void sqlite3PcacheShutdown(void); /* Page cache buffer management: @@ -71,13 +72,12 @@ void sqlite3PCacheBufferSetup(void *, int sz, int n); ** Under memory stress, invoke xStress to try to make pages clean. ** Only clean and unpinned pages can be reclaimed. */ -int sqlite3PcacheOpen( - int szPage, /* Size of every page */ - int szExtra, /* Extra space associated with each page */ - int bPurgeable, /* True if pages are on backing store */ - int (*xStress)(void*, PgHdr*), /* Call to try to make pages clean */ - void *pStress, /* Argument to xStress */ - PCache *pToInit /* Preallocated space for the PCache */ +int sqlite3PcacheOpen(int szPage, /* Size of every page */ + int szExtra, /* Extra space associated with each page */ + int bPurgeable, /* True if pages are on backing store */ + int (*xStress)(void *, PgHdr *), /* Call to try to make pages clean */ + void * pStress, /* Argument to xStress */ + PCache *pToInit /* Preallocated space for the PCache */ ); /* Modify the page-size after the cache has been created. */ @@ -89,51 +89,51 @@ int sqlite3PcacheSetPageSize(PCache *, int); int sqlite3PcacheSize(void); /* One release per successful fetch. Page is pinned until released. -** Reference counted. +** Reference counted. */ -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*); +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 */ -void sqlite3PcacheMakeDirty(PgHdr*); /* Make sure page is marked dirty */ -void sqlite3PcacheMakeClean(PgHdr*); /* Mark a single page as clean */ -void sqlite3PcacheCleanAll(PCache*); /* Mark all dirty list pages as clean */ -void sqlite3PcacheClearWritable(PCache*); +void sqlite3PcacheDrop(PgHdr *); /* Remove page from cache */ +void sqlite3PcacheMakeDirty(PgHdr *); /* Make sure page is marked dirty */ +void sqlite3PcacheMakeClean(PgHdr *); /* Mark a single page as clean */ +void sqlite3PcacheCleanAll(PCache *); /* Mark all dirty list pages as clean */ +void sqlite3PcacheClearWritable(PCache *); /* Change a page number. Used by incr-vacuum. */ -void sqlite3PcacheMove(PgHdr*, Pgno); +void sqlite3PcacheMove(PgHdr *, Pgno); /* Remove all pages with pgno>x. Reset the cache if x==0 */ -void sqlite3PcacheTruncate(PCache*, Pgno x); +void sqlite3PcacheTruncate(PCache *, Pgno x); /* Get a list of all dirty pages in the cache, sorted by page number */ -PgHdr *sqlite3PcacheDirtyList(PCache*); +PgHdr *sqlite3PcacheDirtyList(PCache *); /* Reset and close the cache object */ -void sqlite3PcacheClose(PCache*); +void sqlite3PcacheClose(PCache *); /* Clear flags from pages of the page cache */ void sqlite3PcacheClearSyncFlags(PCache *); /* Discard the contents of the cache */ -void sqlite3PcacheClear(PCache*); +void sqlite3PcacheClear(PCache *); /* Return the total number of outstanding page references */ -int sqlite3PcacheRefCount(PCache*); +int sqlite3PcacheRefCount(PCache *); /* Increment the reference count of an existing page */ -void sqlite3PcacheRef(PgHdr*); +void sqlite3PcacheRef(PgHdr *); -int sqlite3PcachePageRefcount(PgHdr*); +int sqlite3PcachePageRefcount(PgHdr *); /* Return the total number of pages stored in the cache */ -int sqlite3PcachePagecount(PCache*); +int sqlite3PcachePagecount(PCache *); #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG) /* Iterate through all dirty pages currently stored in the cache. This -** interface is only available if SQLITE_CHECK_PAGES is defined when the +** interface is only available if SQLITE_CHECK_PAGES is defined when the ** library is built. */ void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)); @@ -141,7 +141,7 @@ void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)); #if defined(SQLITE_DEBUG) /* Check invariants on a PgHdr object */ -int sqlite3PcachePageSanity(PgHdr*); +int sqlite3PcachePageSanity(PgHdr *); #endif /* Set and get the suggested cache-size for the specified pager-cache. @@ -163,7 +163,7 @@ int sqlite3PcacheGetCachesize(PCache *); int sqlite3PcacheSetSpillsize(PCache *, int); /* Free up as much memory as possible from the page cache */ -void sqlite3PcacheShrink(PCache*); +void sqlite3PcacheShrink(PCache *); #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT /* Try to return memory used by the pcache module to the main memory heap */ @@ -171,7 +171,7 @@ int sqlite3PcacheReleaseMemory(int); #endif #ifdef SQLITE_TEST -void sqlite3PcacheStats(int*,int*,int*,int*); +void sqlite3PcacheStats(int *, int *, int *, int *); #endif void sqlite3PCacheSetDefault(void); @@ -181,10 +181,30 @@ int sqlite3HeaderSizePcache(void); int sqlite3HeaderSizePcache1(void); /* Number of dirty pages as a percentage of the configured cache size */ -int sqlite3PCachePercentDirty(PCache*); +int sqlite3PCachePercentDirty(PCache *); #ifdef SQLITE_DIRECT_OVERFLOW_READ int sqlite3PCacheIsDirty(PCache *pCache); #endif +// For real implementation of sqlite3_pcache ======================================== +typedef struct sqlite3_pcache sqlite3_pcache; +typedef struct sqlite3_pcache_methods2 { + int iVersion; + void *pArg; + int (*xInit)(void *); + void (*xShutdown)(void *); + sqlite3_pcache *(*xCreate)(int szPage, int szExtra, int bPurgeable); + void (*xCachesize)(sqlite3_pcache *, int nCachesize); + int (*xPagecount)(sqlite3_pcache *); + sqlite3_pcache_page *(*xFetch)(sqlite3_pcache *, unsigned key, int createFlag); + void (*xUnpin)(sqlite3_pcache *, sqlite3_pcache_page *, int discard); + void (*xRekey)(sqlite3_pcache *, sqlite3_pcache_page *, unsigned oldKey, unsigned newKey); + void (*xTruncate)(sqlite3_pcache *, unsigned iLimit); + void (*xDestroy)(sqlite3_pcache *); + void (*xShrink)(sqlite3_pcache *); +} sqlite3_pcache_methods2; + +extern sqlite3_pcache_methods2 pcache2; + #endif /* _PCACHE_H_ */