Annotation of embedaddon/sqlite3/src/pcache.c, revision 1.1

1.1     ! misho       1: /*
        !             2: ** 2008 August 05
        !             3: **
        !             4: ** The author disclaims copyright to this source code.  In place of
        !             5: ** a legal notice, here is a blessing:
        !             6: **
        !             7: **    May you do good and not evil.
        !             8: **    May you find forgiveness for yourself and forgive others.
        !             9: **    May you share freely, never taking more than you give.
        !            10: **
        !            11: *************************************************************************
        !            12: ** This file implements that page cache.
        !            13: */
        !            14: #include "sqliteInt.h"
        !            15: 
        !            16: /*
        !            17: ** A complete page cache is an instance of this structure.
        !            18: */
        !            19: struct PCache {
        !            20:   PgHdr *pDirty, *pDirtyTail;         /* List of dirty pages in LRU order */
        !            21:   PgHdr *pSynced;                     /* Last synced page in dirty page list */
        !            22:   int nRef;                           /* Number of referenced pages */
        !            23:   int szCache;                        /* Configured cache size */
        !            24:   int szPage;                         /* Size of every page in this cache */
        !            25:   int szExtra;                        /* Size of extra space for each page */
        !            26:   int bPurgeable;                     /* True if pages are on backing store */
        !            27:   int (*xStress)(void*,PgHdr*);       /* Call to try make a page clean */
        !            28:   void *pStress;                      /* Argument to xStress */
        !            29:   sqlite3_pcache *pCache;             /* Pluggable cache module */
        !            30:   PgHdr *pPage1;                      /* Reference to page 1 */
        !            31: };
        !            32: 
        !            33: /*
        !            34: ** Some of the assert() macros in this code are too expensive to run
        !            35: ** even during normal debugging.  Use them only rarely on long-running
        !            36: ** tests.  Enable the expensive asserts using the
        !            37: ** -DSQLITE_ENABLE_EXPENSIVE_ASSERT=1 compile-time option.
        !            38: */
        !            39: #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
        !            40: # define expensive_assert(X)  assert(X)
        !            41: #else
        !            42: # define expensive_assert(X)
        !            43: #endif
        !            44: 
        !            45: /********************************** Linked List Management ********************/
        !            46: 
        !            47: #if !defined(NDEBUG) && defined(SQLITE_ENABLE_EXPENSIVE_ASSERT)
        !            48: /*
        !            49: ** Check that the pCache->pSynced variable is set correctly. If it
        !            50: ** is not, either fail an assert or return zero. Otherwise, return
        !            51: ** non-zero. This is only used in debugging builds, as follows:
        !            52: **
        !            53: **   expensive_assert( pcacheCheckSynced(pCache) );
        !            54: */
        !            55: static int pcacheCheckSynced(PCache *pCache){
        !            56:   PgHdr *p;
        !            57:   for(p=pCache->pDirtyTail; p!=pCache->pSynced; p=p->pDirtyPrev){
        !            58:     assert( p->nRef || (p->flags&PGHDR_NEED_SYNC) );
        !            59:   }
        !            60:   return (p==0 || p->nRef || (p->flags&PGHDR_NEED_SYNC)==0);
        !            61: }
        !            62: #endif /* !NDEBUG && SQLITE_ENABLE_EXPENSIVE_ASSERT */
        !            63: 
        !            64: /*
        !            65: ** Remove page pPage from the list of dirty pages.
        !            66: */
        !            67: static void pcacheRemoveFromDirtyList(PgHdr *pPage){
        !            68:   PCache *p = pPage->pCache;
        !            69: 
        !            70:   assert( pPage->pDirtyNext || pPage==p->pDirtyTail );
        !            71:   assert( pPage->pDirtyPrev || pPage==p->pDirty );
        !            72: 
        !            73:   /* Update the PCache1.pSynced variable if necessary. */
        !            74:   if( p->pSynced==pPage ){
        !            75:     PgHdr *pSynced = pPage->pDirtyPrev;
        !            76:     while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){
        !            77:       pSynced = pSynced->pDirtyPrev;
        !            78:     }
        !            79:     p->pSynced = pSynced;
        !            80:   }
        !            81: 
        !            82:   if( pPage->pDirtyNext ){
        !            83:     pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev;
        !            84:   }else{
        !            85:     assert( pPage==p->pDirtyTail );
        !            86:     p->pDirtyTail = pPage->pDirtyPrev;
        !            87:   }
        !            88:   if( pPage->pDirtyPrev ){
        !            89:     pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext;
        !            90:   }else{
        !            91:     assert( pPage==p->pDirty );
        !            92:     p->pDirty = pPage->pDirtyNext;
        !            93:   }
        !            94:   pPage->pDirtyNext = 0;
        !            95:   pPage->pDirtyPrev = 0;
        !            96: 
        !            97:   expensive_assert( pcacheCheckSynced(p) );
        !            98: }
        !            99: 
        !           100: /*
        !           101: ** Add page pPage to the head of the dirty list (PCache1.pDirty is set to
        !           102: ** pPage).
        !           103: */
        !           104: static void pcacheAddToDirtyList(PgHdr *pPage){
        !           105:   PCache *p = pPage->pCache;
        !           106: 
        !           107:   assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage );
        !           108: 
        !           109:   pPage->pDirtyNext = p->pDirty;
        !           110:   if( pPage->pDirtyNext ){
        !           111:     assert( pPage->pDirtyNext->pDirtyPrev==0 );
        !           112:     pPage->pDirtyNext->pDirtyPrev = pPage;
        !           113:   }
        !           114:   p->pDirty = pPage;
        !           115:   if( !p->pDirtyTail ){
        !           116:     p->pDirtyTail = pPage;
        !           117:   }
        !           118:   if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){
        !           119:     p->pSynced = pPage;
        !           120:   }
        !           121:   expensive_assert( pcacheCheckSynced(p) );
        !           122: }
        !           123: 
        !           124: /*
        !           125: ** Wrapper around the pluggable caches xUnpin method. If the cache is
        !           126: ** being used for an in-memory database, this function is a no-op.
        !           127: */
        !           128: static void pcacheUnpin(PgHdr *p){
        !           129:   PCache *pCache = p->pCache;
        !           130:   if( pCache->bPurgeable ){
        !           131:     if( p->pgno==1 ){
        !           132:       pCache->pPage1 = 0;
        !           133:     }
        !           134:     sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, p->pPage, 0);
        !           135:   }
        !           136: }
        !           137: 
        !           138: /*************************************************** General Interfaces ******
        !           139: **
        !           140: ** Initialize and shutdown the page cache subsystem. Neither of these 
        !           141: ** functions are threadsafe.
        !           142: */
        !           143: int sqlite3PcacheInitialize(void){
        !           144:   if( sqlite3GlobalConfig.pcache2.xInit==0 ){
        !           145:     /* IMPLEMENTATION-OF: R-26801-64137 If the xInit() method is NULL, then the
        !           146:     ** built-in default page cache is used instead of the application defined
        !           147:     ** page cache. */
        !           148:     sqlite3PCacheSetDefault();
        !           149:   }
        !           150:   return sqlite3GlobalConfig.pcache2.xInit(sqlite3GlobalConfig.pcache2.pArg);
        !           151: }
        !           152: void sqlite3PcacheShutdown(void){
        !           153:   if( sqlite3GlobalConfig.pcache2.xShutdown ){
        !           154:     /* IMPLEMENTATION-OF: R-26000-56589 The xShutdown() method may be NULL. */
        !           155:     sqlite3GlobalConfig.pcache2.xShutdown(sqlite3GlobalConfig.pcache2.pArg);
        !           156:   }
        !           157: }
        !           158: 
        !           159: /*
        !           160: ** Return the size in bytes of a PCache object.
        !           161: */
        !           162: int sqlite3PcacheSize(void){ return sizeof(PCache); }
        !           163: 
        !           164: /*
        !           165: ** Create a new PCache object. Storage space to hold the object
        !           166: ** has already been allocated and is passed in as the p pointer. 
        !           167: ** The caller discovers how much space needs to be allocated by 
        !           168: ** calling sqlite3PcacheSize().
        !           169: */
        !           170: void sqlite3PcacheOpen(
        !           171:   int szPage,                  /* Size of every page */
        !           172:   int szExtra,                 /* Extra space associated with each page */
        !           173:   int bPurgeable,              /* True if pages are on backing store */
        !           174:   int (*xStress)(void*,PgHdr*),/* Call to try to make pages clean */
        !           175:   void *pStress,               /* Argument to xStress */
        !           176:   PCache *p                    /* Preallocated space for the PCache */
        !           177: ){
        !           178:   memset(p, 0, sizeof(PCache));
        !           179:   p->szPage = szPage;
        !           180:   p->szExtra = szExtra;
        !           181:   p->bPurgeable = bPurgeable;
        !           182:   p->xStress = xStress;
        !           183:   p->pStress = pStress;
        !           184:   p->szCache = 100;
        !           185: }
        !           186: 
        !           187: /*
        !           188: ** Change the page size for PCache object. The caller must ensure that there
        !           189: ** are no outstanding page references when this function is called.
        !           190: */
        !           191: void sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
        !           192:   assert( pCache->nRef==0 && pCache->pDirty==0 );
        !           193:   if( pCache->pCache ){
        !           194:     sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
        !           195:     pCache->pCache = 0;
        !           196:     pCache->pPage1 = 0;
        !           197:   }
        !           198:   pCache->szPage = szPage;
        !           199: }
        !           200: 
        !           201: /*
        !           202: ** Compute the number of pages of cache requested.
        !           203: */
        !           204: static int numberOfCachePages(PCache *p){
        !           205:   if( p->szCache>=0 ){
        !           206:     return p->szCache;
        !           207:   }else{
        !           208:     return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra));
        !           209:   }
        !           210: }
        !           211: 
        !           212: /*
        !           213: ** Try to obtain a page from the cache.
        !           214: */
        !           215: int sqlite3PcacheFetch(
        !           216:   PCache *pCache,       /* Obtain the page from this cache */
        !           217:   Pgno pgno,            /* Page number to obtain */
        !           218:   int createFlag,       /* If true, create page if it does not exist already */
        !           219:   PgHdr **ppPage        /* Write the page here */
        !           220: ){
        !           221:   sqlite3_pcache_page *pPage = 0;
        !           222:   PgHdr *pPgHdr = 0;
        !           223:   int eCreate;
        !           224: 
        !           225:   assert( pCache!=0 );
        !           226:   assert( createFlag==1 || createFlag==0 );
        !           227:   assert( pgno>0 );
        !           228: 
        !           229:   /* If the pluggable cache (sqlite3_pcache*) has not been allocated,
        !           230:   ** allocate it now.
        !           231:   */
        !           232:   if( !pCache->pCache && createFlag ){
        !           233:     sqlite3_pcache *p;
        !           234:     p = sqlite3GlobalConfig.pcache2.xCreate(
        !           235:         pCache->szPage, pCache->szExtra + sizeof(PgHdr), pCache->bPurgeable
        !           236:     );
        !           237:     if( !p ){
        !           238:       return SQLITE_NOMEM;
        !           239:     }
        !           240:     sqlite3GlobalConfig.pcache2.xCachesize(p, numberOfCachePages(pCache));
        !           241:     pCache->pCache = p;
        !           242:   }
        !           243: 
        !           244:   eCreate = createFlag * (1 + (!pCache->bPurgeable || !pCache->pDirty));
        !           245:   if( pCache->pCache ){
        !           246:     pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
        !           247:   }
        !           248: 
        !           249:   if( !pPage && eCreate==1 ){
        !           250:     PgHdr *pPg;
        !           251: 
        !           252:     /* Find a dirty page to write-out and recycle. First try to find a 
        !           253:     ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
        !           254:     ** cleared), but if that is not possible settle for any other 
        !           255:     ** unreferenced dirty page.
        !           256:     */
        !           257:     expensive_assert( pcacheCheckSynced(pCache) );
        !           258:     for(pPg=pCache->pSynced; 
        !           259:         pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); 
        !           260:         pPg=pPg->pDirtyPrev
        !           261:     );
        !           262:     pCache->pSynced = pPg;
        !           263:     if( !pPg ){
        !           264:       for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev);
        !           265:     }
        !           266:     if( pPg ){
        !           267:       int rc;
        !           268: #ifdef SQLITE_LOG_CACHE_SPILL
        !           269:       sqlite3_log(SQLITE_FULL, 
        !           270:                   "spill page %d making room for %d - cache used: %d/%d",
        !           271:                   pPg->pgno, pgno,
        !           272:                   sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache),
        !           273:                   numberOfCachePages(pCache));
        !           274: #endif
        !           275:       rc = pCache->xStress(pCache->pStress, pPg);
        !           276:       if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
        !           277:         return rc;
        !           278:       }
        !           279:     }
        !           280: 
        !           281:     pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2);
        !           282:   }
        !           283: 
        !           284:   if( pPage ){
        !           285:     pPgHdr = (PgHdr *)pPage->pExtra;
        !           286: 
        !           287:     if( !pPgHdr->pPage ){
        !           288:       memset(pPgHdr, 0, sizeof(PgHdr));
        !           289:       pPgHdr->pPage = pPage;
        !           290:       pPgHdr->pData = pPage->pBuf;
        !           291:       pPgHdr->pExtra = (void *)&pPgHdr[1];
        !           292:       memset(pPgHdr->pExtra, 0, pCache->szExtra);
        !           293:       pPgHdr->pCache = pCache;
        !           294:       pPgHdr->pgno = pgno;
        !           295:     }
        !           296:     assert( pPgHdr->pCache==pCache );
        !           297:     assert( pPgHdr->pgno==pgno );
        !           298:     assert( pPgHdr->pData==pPage->pBuf );
        !           299:     assert( pPgHdr->pExtra==(void *)&pPgHdr[1] );
        !           300: 
        !           301:     if( 0==pPgHdr->nRef ){
        !           302:       pCache->nRef++;
        !           303:     }
        !           304:     pPgHdr->nRef++;
        !           305:     if( pgno==1 ){
        !           306:       pCache->pPage1 = pPgHdr;
        !           307:     }
        !           308:   }
        !           309:   *ppPage = pPgHdr;
        !           310:   return (pPgHdr==0 && eCreate) ? SQLITE_NOMEM : SQLITE_OK;
        !           311: }
        !           312: 
        !           313: /*
        !           314: ** Decrement the reference count on a page. If the page is clean and the
        !           315: ** reference count drops to 0, then it is made elible for recycling.
        !           316: */
        !           317: void sqlite3PcacheRelease(PgHdr *p){
        !           318:   assert( p->nRef>0 );
        !           319:   p->nRef--;
        !           320:   if( p->nRef==0 ){
        !           321:     PCache *pCache = p->pCache;
        !           322:     pCache->nRef--;
        !           323:     if( (p->flags&PGHDR_DIRTY)==0 ){
        !           324:       pcacheUnpin(p);
        !           325:     }else{
        !           326:       /* Move the page to the head of the dirty list. */
        !           327:       pcacheRemoveFromDirtyList(p);
        !           328:       pcacheAddToDirtyList(p);
        !           329:     }
        !           330:   }
        !           331: }
        !           332: 
        !           333: /*
        !           334: ** Increase the reference count of a supplied page by 1.
        !           335: */
        !           336: void sqlite3PcacheRef(PgHdr *p){
        !           337:   assert(p->nRef>0);
        !           338:   p->nRef++;
        !           339: }
        !           340: 
        !           341: /*
        !           342: ** Drop a page from the cache. There must be exactly one reference to the
        !           343: ** page. This function deletes that reference, so after it returns the
        !           344: ** page pointed to by p is invalid.
        !           345: */
        !           346: void sqlite3PcacheDrop(PgHdr *p){
        !           347:   PCache *pCache;
        !           348:   assert( p->nRef==1 );
        !           349:   if( p->flags&PGHDR_DIRTY ){
        !           350:     pcacheRemoveFromDirtyList(p);
        !           351:   }
        !           352:   pCache = p->pCache;
        !           353:   pCache->nRef--;
        !           354:   if( p->pgno==1 ){
        !           355:     pCache->pPage1 = 0;
        !           356:   }
        !           357:   sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, p->pPage, 1);
        !           358: }
        !           359: 
        !           360: /*
        !           361: ** Make sure the page is marked as dirty. If it isn't dirty already,
        !           362: ** make it so.
        !           363: */
        !           364: void sqlite3PcacheMakeDirty(PgHdr *p){
        !           365:   p->flags &= ~PGHDR_DONT_WRITE;
        !           366:   assert( p->nRef>0 );
        !           367:   if( 0==(p->flags & PGHDR_DIRTY) ){
        !           368:     p->flags |= PGHDR_DIRTY;
        !           369:     pcacheAddToDirtyList( p);
        !           370:   }
        !           371: }
        !           372: 
        !           373: /*
        !           374: ** Make sure the page is marked as clean. If it isn't clean already,
        !           375: ** make it so.
        !           376: */
        !           377: void sqlite3PcacheMakeClean(PgHdr *p){
        !           378:   if( (p->flags & PGHDR_DIRTY) ){
        !           379:     pcacheRemoveFromDirtyList(p);
        !           380:     p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC);
        !           381:     if( p->nRef==0 ){
        !           382:       pcacheUnpin(p);
        !           383:     }
        !           384:   }
        !           385: }
        !           386: 
        !           387: /*
        !           388: ** Make every page in the cache clean.
        !           389: */
        !           390: void sqlite3PcacheCleanAll(PCache *pCache){
        !           391:   PgHdr *p;
        !           392:   while( (p = pCache->pDirty)!=0 ){
        !           393:     sqlite3PcacheMakeClean(p);
        !           394:   }
        !           395: }
        !           396: 
        !           397: /*
        !           398: ** Clear the PGHDR_NEED_SYNC flag from all dirty pages.
        !           399: */
        !           400: void sqlite3PcacheClearSyncFlags(PCache *pCache){
        !           401:   PgHdr *p;
        !           402:   for(p=pCache->pDirty; p; p=p->pDirtyNext){
        !           403:     p->flags &= ~PGHDR_NEED_SYNC;
        !           404:   }
        !           405:   pCache->pSynced = pCache->pDirtyTail;
        !           406: }
        !           407: 
        !           408: /*
        !           409: ** Change the page number of page p to newPgno. 
        !           410: */
        !           411: void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
        !           412:   PCache *pCache = p->pCache;
        !           413:   assert( p->nRef>0 );
        !           414:   assert( newPgno>0 );
        !           415:   sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno);
        !           416:   p->pgno = newPgno;
        !           417:   if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
        !           418:     pcacheRemoveFromDirtyList(p);
        !           419:     pcacheAddToDirtyList(p);
        !           420:   }
        !           421: }
        !           422: 
        !           423: /*
        !           424: ** Drop every cache entry whose page number is greater than "pgno". The
        !           425: ** caller must ensure that there are no outstanding references to any pages
        !           426: ** other than page 1 with a page number greater than pgno.
        !           427: **
        !           428: ** If there is a reference to page 1 and the pgno parameter passed to this
        !           429: ** function is 0, then the data area associated with page 1 is zeroed, but
        !           430: ** the page object is not dropped.
        !           431: */
        !           432: void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
        !           433:   if( pCache->pCache ){
        !           434:     PgHdr *p;
        !           435:     PgHdr *pNext;
        !           436:     for(p=pCache->pDirty; p; p=pNext){
        !           437:       pNext = p->pDirtyNext;
        !           438:       /* This routine never gets call with a positive pgno except right
        !           439:       ** after sqlite3PcacheCleanAll().  So if there are dirty pages,
        !           440:       ** it must be that pgno==0.
        !           441:       */
        !           442:       assert( p->pgno>0 );
        !           443:       if( ALWAYS(p->pgno>pgno) ){
        !           444:         assert( p->flags&PGHDR_DIRTY );
        !           445:         sqlite3PcacheMakeClean(p);
        !           446:       }
        !           447:     }
        !           448:     if( pgno==0 && pCache->pPage1 ){
        !           449:       memset(pCache->pPage1->pData, 0, pCache->szPage);
        !           450:       pgno = 1;
        !           451:     }
        !           452:     sqlite3GlobalConfig.pcache2.xTruncate(pCache->pCache, pgno+1);
        !           453:   }
        !           454: }
        !           455: 
        !           456: /*
        !           457: ** Close a cache.
        !           458: */
        !           459: void sqlite3PcacheClose(PCache *pCache){
        !           460:   if( pCache->pCache ){
        !           461:     sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
        !           462:   }
        !           463: }
        !           464: 
        !           465: /* 
        !           466: ** Discard the contents of the cache.
        !           467: */
        !           468: void sqlite3PcacheClear(PCache *pCache){
        !           469:   sqlite3PcacheTruncate(pCache, 0);
        !           470: }
        !           471: 
        !           472: /*
        !           473: ** Merge two lists of pages connected by pDirty and in pgno order.
        !           474: ** Do not both fixing the pDirtyPrev pointers.
        !           475: */
        !           476: static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){
        !           477:   PgHdr result, *pTail;
        !           478:   pTail = &result;
        !           479:   while( pA && pB ){
        !           480:     if( pA->pgno<pB->pgno ){
        !           481:       pTail->pDirty = pA;
        !           482:       pTail = pA;
        !           483:       pA = pA->pDirty;
        !           484:     }else{
        !           485:       pTail->pDirty = pB;
        !           486:       pTail = pB;
        !           487:       pB = pB->pDirty;
        !           488:     }
        !           489:   }
        !           490:   if( pA ){
        !           491:     pTail->pDirty = pA;
        !           492:   }else if( pB ){
        !           493:     pTail->pDirty = pB;
        !           494:   }else{
        !           495:     pTail->pDirty = 0;
        !           496:   }
        !           497:   return result.pDirty;
        !           498: }
        !           499: 
        !           500: /*
        !           501: ** Sort the list of pages in accending order by pgno.  Pages are
        !           502: ** connected by pDirty pointers.  The pDirtyPrev pointers are
        !           503: ** corrupted by this sort.
        !           504: **
        !           505: ** Since there cannot be more than 2^31 distinct pages in a database,
        !           506: ** there cannot be more than 31 buckets required by the merge sorter.
        !           507: ** One extra bucket is added to catch overflow in case something
        !           508: ** ever changes to make the previous sentence incorrect.
        !           509: */
        !           510: #define N_SORT_BUCKET  32
        !           511: static PgHdr *pcacheSortDirtyList(PgHdr *pIn){
        !           512:   PgHdr *a[N_SORT_BUCKET], *p;
        !           513:   int i;
        !           514:   memset(a, 0, sizeof(a));
        !           515:   while( pIn ){
        !           516:     p = pIn;
        !           517:     pIn = p->pDirty;
        !           518:     p->pDirty = 0;
        !           519:     for(i=0; ALWAYS(i<N_SORT_BUCKET-1); i++){
        !           520:       if( a[i]==0 ){
        !           521:         a[i] = p;
        !           522:         break;
        !           523:       }else{
        !           524:         p = pcacheMergeDirtyList(a[i], p);
        !           525:         a[i] = 0;
        !           526:       }
        !           527:     }
        !           528:     if( NEVER(i==N_SORT_BUCKET-1) ){
        !           529:       /* To get here, there need to be 2^(N_SORT_BUCKET) elements in
        !           530:       ** the input list.  But that is impossible.
        !           531:       */
        !           532:       a[i] = pcacheMergeDirtyList(a[i], p);
        !           533:     }
        !           534:   }
        !           535:   p = a[0];
        !           536:   for(i=1; i<N_SORT_BUCKET; i++){
        !           537:     p = pcacheMergeDirtyList(p, a[i]);
        !           538:   }
        !           539:   return p;
        !           540: }
        !           541: 
        !           542: /*
        !           543: ** Return a list of all dirty pages in the cache, sorted by page number.
        !           544: */
        !           545: PgHdr *sqlite3PcacheDirtyList(PCache *pCache){
        !           546:   PgHdr *p;
        !           547:   for(p=pCache->pDirty; p; p=p->pDirtyNext){
        !           548:     p->pDirty = p->pDirtyNext;
        !           549:   }
        !           550:   return pcacheSortDirtyList(pCache->pDirty);
        !           551: }
        !           552: 
        !           553: /* 
        !           554: ** Return the total number of referenced pages held by the cache.
        !           555: */
        !           556: int sqlite3PcacheRefCount(PCache *pCache){
        !           557:   return pCache->nRef;
        !           558: }
        !           559: 
        !           560: /*
        !           561: ** Return the number of references to the page supplied as an argument.
        !           562: */
        !           563: int sqlite3PcachePageRefcount(PgHdr *p){
        !           564:   return p->nRef;
        !           565: }
        !           566: 
        !           567: /* 
        !           568: ** Return the total number of pages in the cache.
        !           569: */
        !           570: int sqlite3PcachePagecount(PCache *pCache){
        !           571:   int nPage = 0;
        !           572:   if( pCache->pCache ){
        !           573:     nPage = sqlite3GlobalConfig.pcache2.xPagecount(pCache->pCache);
        !           574:   }
        !           575:   return nPage;
        !           576: }
        !           577: 
        !           578: #ifdef SQLITE_TEST
        !           579: /*
        !           580: ** Get the suggested cache-size value.
        !           581: */
        !           582: int sqlite3PcacheGetCachesize(PCache *pCache){
        !           583:   return numberOfCachePages(pCache);
        !           584: }
        !           585: #endif
        !           586: 
        !           587: /*
        !           588: ** Set the suggested cache-size value.
        !           589: */
        !           590: void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
        !           591:   pCache->szCache = mxPage;
        !           592:   if( pCache->pCache ){
        !           593:     sqlite3GlobalConfig.pcache2.xCachesize(pCache->pCache,
        !           594:                                            numberOfCachePages(pCache));
        !           595:   }
        !           596: }
        !           597: 
        !           598: /*
        !           599: ** Free up as much memory as possible from the page cache.
        !           600: */
        !           601: void sqlite3PcacheShrink(PCache *pCache){
        !           602:   if( pCache->pCache ){
        !           603:     sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache);
        !           604:   }
        !           605: }
        !           606: 
        !           607: #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
        !           608: /*
        !           609: ** For all dirty pages currently in the cache, invoke the specified
        !           610: ** callback. This is only used if the SQLITE_CHECK_PAGES macro is
        !           611: ** defined.
        !           612: */
        !           613: void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)){
        !           614:   PgHdr *pDirty;
        !           615:   for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext){
        !           616:     xIter(pDirty);
        !           617:   }
        !           618: }
        !           619: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>