| Index: third_party/sqlite/sqlite-src-3100200/src/pcache.c
|
| diff --git a/third_party/sqlite/src/src/pcache.c b/third_party/sqlite/sqlite-src-3100200/src/pcache.c
|
| similarity index 83%
|
| copy from third_party/sqlite/src/src/pcache.c
|
| copy to third_party/sqlite/sqlite-src-3100200/src/pcache.c
|
| index 191a9d00f41ded328642e71fa5da12138f38bc35..5ac9d34a1e3e9541fcae821828316c08a8c30c51 100644
|
| --- a/third_party/sqlite/src/src/pcache.c
|
| +++ b/third_party/sqlite/sqlite-src-3100200/src/pcache.c
|
| @@ -19,8 +19,9 @@
|
| struct PCache {
|
| PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */
|
| PgHdr *pSynced; /* Last synced page in dirty page list */
|
| - int nRef; /* Number of referenced pages */
|
| + 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 */
|
| @@ -28,21 +29,8 @@ struct PCache {
|
| int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */
|
| void *pStress; /* Argument to xStress */
|
| sqlite3_pcache *pCache; /* Pluggable cache module */
|
| - PgHdr *pPage1; /* Reference to page 1 */
|
| };
|
|
|
| -/*
|
| -** Some of the assert() macros in this code are too expensive to run
|
| -** even during normal debugging. Use them only rarely on long-running
|
| -** tests. Enable the expensive asserts using the
|
| -** -DSQLITE_ENABLE_EXPENSIVE_ASSERT=1 compile-time option.
|
| -*/
|
| -#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
|
| -# define expensive_assert(X) assert(X)
|
| -#else
|
| -# define expensive_assert(X)
|
| -#endif
|
| -
|
| /********************************** Linked List Management ********************/
|
|
|
| /* Allowed values for second argument to pcacheManageDirtyList() */
|
| @@ -118,20 +106,23 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
|
| */
|
| static void pcacheUnpin(PgHdr *p){
|
| if( p->pCache->bPurgeable ){
|
| - if( p->pgno==1 ){
|
| - p->pCache->pPage1 = 0;
|
| - }
|
| sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 0);
|
| }
|
| }
|
|
|
| /*
|
| -** Compute the number of pages of cache requested.
|
| +** 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 ){
|
| + /* IMPLEMENTATION-OF: R-42059-47211 If the argument N is positive then the
|
| + ** suggested cache size is set to N. */
|
| return p->szCache;
|
| }else{
|
| + /* IMPLEMENTATION-OF: R-61436-13639 If the argument N is negative, then
|
| + ** the number of cache pages is adjusted to use approximately abs(N*1024)
|
| + ** bytes of memory. */
|
| return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra));
|
| }
|
| }
|
| @@ -184,6 +175,7 @@ int sqlite3PcacheOpen(
|
| p->xStress = xStress;
|
| p->pStress = pStress;
|
| p->szCache = 100;
|
| + p->szSpill = 1;
|
| return sqlite3PcacheSetPageSize(p, szPage);
|
| }
|
|
|
| @@ -192,11 +184,12 @@ int sqlite3PcacheOpen(
|
| ** are no outstanding page references when this function is called.
|
| */
|
| int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
|
| - assert( pCache->nRef==0 && pCache->pDirty==0 );
|
| + assert( pCache->nRefSum==0 && pCache->pDirty==0 );
|
| if( pCache->szPage ){
|
| sqlite3_pcache *pNew;
|
| pNew = sqlite3GlobalConfig.pcache2.xCreate(
|
| - szPage, pCache->szExtra + sizeof(PgHdr), pCache->bPurgeable
|
| + szPage, pCache->szExtra + ROUND8(sizeof(PgHdr)),
|
| + pCache->bPurgeable
|
| );
|
| if( pNew==0 ) return SQLITE_NOMEM;
|
| sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache));
|
| @@ -204,7 +197,6 @@ int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
|
| sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
|
| }
|
| pCache->pCache = pNew;
|
| - pCache->pPage1 = 0;
|
| pCache->szPage = szPage;
|
| }
|
| return SQLITE_OK;
|
| @@ -279,32 +271,33 @@ int sqlite3PcacheFetchStress(
|
| 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.
|
| - */
|
| - 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( 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
|
| + ** unreferenced dirty page.
|
| + */
|
| + 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),
|
| + 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;
|
| + rc = pCache->xStress(pCache->pStress, pPg);
|
| + if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
|
| + return rc;
|
| + }
|
| }
|
| }
|
| *ppPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2);
|
| @@ -329,13 +322,14 @@ static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit(
|
| assert( pPage!=0 );
|
| pPgHdr = (PgHdr*)pPage->pExtra;
|
| assert( pPgHdr->pPage==0 );
|
| - memset(pPgHdr, 0, sizeof(PgHdr));
|
| + 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;
|
| + pPgHdr->flags = PGHDR_CLEAN;
|
| return sqlite3PcacheFetchFinish(pCache,pgno,pPage);
|
| }
|
|
|
| @@ -352,19 +346,14 @@ PgHdr *sqlite3PcacheFetchFinish(
|
| ){
|
| PgHdr *pPgHdr;
|
|
|
| - if( pPage==0 ) return 0;
|
| + assert( pPage!=0 );
|
| pPgHdr = (PgHdr *)pPage->pExtra;
|
|
|
| if( !pPgHdr->pPage ){
|
| return pcacheFetchFinishWithInit(pCache, pgno, pPage);
|
| }
|
| - if( 0==pPgHdr->nRef ){
|
| - pCache->nRef++;
|
| - }
|
| + pCache->nRefSum++;
|
| pPgHdr->nRef++;
|
| - if( pgno==1 ){
|
| - pCache->pPage1 = pPgHdr;
|
| - }
|
| return pPgHdr;
|
| }
|
|
|
| @@ -374,10 +363,9 @@ PgHdr *sqlite3PcacheFetchFinish(
|
| */
|
| void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
|
| assert( p->nRef>0 );
|
| - p->nRef--;
|
| - if( p->nRef==0 ){
|
| - p->pCache->nRef--;
|
| - if( (p->flags&PGHDR_DIRTY)==0 ){
|
| + p->pCache->nRefSum--;
|
| + if( (--p->nRef)==0 ){
|
| + if( p->flags&PGHDR_CLEAN ){
|
| pcacheUnpin(p);
|
| }else if( p->pDirtyPrev!=0 ){
|
| /* Move the page to the head of the dirty list. */
|
| @@ -392,6 +380,7 @@ void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
|
| void sqlite3PcacheRef(PgHdr *p){
|
| assert(p->nRef>0);
|
| p->nRef++;
|
| + p->pCache->nRefSum++;
|
| }
|
|
|
| /*
|
| @@ -404,10 +393,7 @@ void sqlite3PcacheDrop(PgHdr *p){
|
| if( p->flags&PGHDR_DIRTY ){
|
| pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
|
| }
|
| - p->pCache->nRef--;
|
| - if( p->pgno==1 ){
|
| - p->pCache->pPage1 = 0;
|
| - }
|
| + p->pCache->nRefSum--;
|
| sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 1);
|
| }
|
|
|
| @@ -416,11 +402,14 @@ void sqlite3PcacheDrop(PgHdr *p){
|
| ** make it so.
|
| */
|
| void sqlite3PcacheMakeDirty(PgHdr *p){
|
| - p->flags &= ~PGHDR_DONT_WRITE;
|
| assert( p->nRef>0 );
|
| - if( 0==(p->flags & PGHDR_DIRTY) ){
|
| - p->flags |= PGHDR_DIRTY;
|
| - pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD);
|
| + if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){
|
| + p->flags &= ~PGHDR_DONT_WRITE;
|
| + if( p->flags & PGHDR_CLEAN ){
|
| + p->flags ^= (PGHDR_DIRTY|PGHDR_CLEAN);
|
| + assert( (p->flags & (PGHDR_DIRTY|PGHDR_CLEAN))==PGHDR_DIRTY );
|
| + pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD);
|
| + }
|
| }
|
| }
|
|
|
| @@ -430,8 +419,10 @@ void sqlite3PcacheMakeDirty(PgHdr *p){
|
| */
|
| void sqlite3PcacheMakeClean(PgHdr *p){
|
| if( (p->flags & PGHDR_DIRTY) ){
|
| + assert( (p->flags & PGHDR_CLEAN)==0 );
|
| pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
|
| - p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC);
|
| + p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC|PGHDR_WRITEABLE);
|
| + p->flags |= PGHDR_CLEAN;
|
| if( p->nRef==0 ){
|
| pcacheUnpin(p);
|
| }
|
| @@ -498,9 +489,14 @@ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
|
| sqlite3PcacheMakeClean(p);
|
| }
|
| }
|
| - if( pgno==0 && pCache->pPage1 ){
|
| - memset(pCache->pPage1->pData, 0, pCache->szPage);
|
| - pgno = 1;
|
| + 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 */
|
| + memset(pPage1->pBuf, 0, pCache->szPage);
|
| + pgno = 1;
|
| + }
|
| }
|
| sqlite3GlobalConfig.pcache2.xTruncate(pCache->pCache, pgno+1);
|
| }
|
| @@ -603,10 +599,13 @@ PgHdr *sqlite3PcacheDirtyList(PCache *pCache){
|
| }
|
|
|
| /*
|
| -** Return the total number of referenced pages held by the cache.
|
| +** 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->nRef;
|
| + return pCache->nRefSum;
|
| }
|
|
|
| /*
|
| @@ -644,6 +643,25 @@ void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
|
| }
|
|
|
| /*
|
| +** Set the suggested cache-spill value. Make no changes if if the
|
| +** 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 res;
|
| + 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( res<p->szSpill ) res = p->szSpill;
|
| + return res;
|
| +}
|
| +
|
| +/*
|
| ** Free up as much memory as possible from the page cache.
|
| */
|
| void sqlite3PcacheShrink(PCache *pCache){
|
| @@ -651,6 +669,13 @@ void sqlite3PcacheShrink(PCache *pCache){
|
| sqlite3GlobalConfig.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)); }
|
| +
|
| +
|
| #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
|
| /*
|
| ** For all dirty pages currently in the cache, invoke the specified
|
|
|