15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 2008 August 05
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The author disclaims copyright to this source code.  In place of
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** a legal notice, here is a blessing:
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    May you do good and not evil.
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    May you find forgiveness for yourself and forgive others.
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    May you share freely, never taking more than you give.
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*************************************************************************
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This file implements that page cache.
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sqliteInt.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** A complete page cache is an instance of this structure.
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct PCache {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgHdr *pDirty, *pDirtyTail;         /* List of dirty pages in LRU order */
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgHdr *pSynced;                     /* Last synced page in dirty page list */
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nRef;                           /* Number of referenced pages */
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nMax;                           /* Configured cache size */
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int szPage;                         /* Size of every page in this cache */
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int szExtra;                        /* Size of extra space for each page */
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int bPurgeable;                     /* True if pages are on backing store */
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int (*xStress)(void*,PgHdr*);       /* Call to try make a page clean */
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void *pStress;                      /* Argument to xStress */
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_pcache *pCache;             /* Pluggable cache module */
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgHdr *pPage1;                      /* Reference to page 1 */
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Some of the assert() macros in this code are too expensive to run
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** even during normal debugging.  Use them only rarely on long-running
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** tests.  Enable the expensive asserts using the
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** -DSQLITE_ENABLE_EXPENSIVE_ASSERT=1 compile-time option.
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# define expensive_assert(X)  assert(X)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# define expensive_assert(X)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/********************************** Linked List Management ********************/
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(NDEBUG) && defined(SQLITE_ENABLE_EXPENSIVE_ASSERT)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Check that the pCache->pSynced variable is set correctly. If it
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** is not, either fail an assert or return zero. Otherwise, return
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** non-zero. This is only used in debugging builds, as follows:
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**   expensive_assert( pcacheCheckSynced(pCache) );
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pcacheCheckSynced(PCache *pCache){
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgHdr *p;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(p=pCache->pDirtyTail; p!=pCache->pSynced; p=p->pDirtyPrev){
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert( p->nRef || (p->flags&PGHDR_NEED_SYNC) );
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (p==0 || p->nRef || (p->flags&PGHDR_NEED_SYNC)==0);
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif /* !NDEBUG && SQLITE_ENABLE_EXPENSIVE_ASSERT */
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Remove page pPage from the list of dirty pages.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void pcacheRemoveFromDirtyList(PgHdr *pPage){
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PCache *p = pPage->pCache;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pPage->pDirtyNext || pPage==p->pDirtyTail );
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pPage->pDirtyPrev || pPage==p->pDirty );
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Update the PCache1.pSynced variable if necessary. */
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( p->pSynced==pPage ){
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PgHdr *pSynced = pPage->pDirtyPrev;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pSynced = pSynced->pDirtyPrev;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p->pSynced = pSynced;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pPage->pDirtyNext ){
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert( pPage==p->pDirtyTail );
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p->pDirtyTail = pPage->pDirtyPrev;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pPage->pDirtyPrev ){
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert( pPage==p->pDirty );
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p->pDirty = pPage->pDirtyNext;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pPage->pDirtyNext = 0;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pPage->pDirtyPrev = 0;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expensive_assert( pcacheCheckSynced(p) );
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Add page pPage to the head of the dirty list (PCache1.pDirty is set to
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** pPage).
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void pcacheAddToDirtyList(PgHdr *pPage){
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PCache *p = pPage->pCache;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage );
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pPage->pDirtyNext = p->pDirty;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pPage->pDirtyNext ){
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert( pPage->pDirtyNext->pDirtyPrev==0 );
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pPage->pDirtyNext->pDirtyPrev = pPage;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->pDirty = pPage;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( !p->pDirtyTail ){
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p->pDirtyTail = pPage;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p->pSynced = pPage;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expensive_assert( pcacheCheckSynced(p) );
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Wrapper around the pluggable caches xUnpin method. If the cache is
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** being used for an in-memory database, this function is a no-op.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void pcacheUnpin(PgHdr *p){
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PCache *pCache = p->pCache;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pCache->bPurgeable ){
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( p->pgno==1 ){
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pCache->pPage1 = 0;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3GlobalConfig.pcache.xUnpin(pCache->pCache, p, 0);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*************************************************** General Interfaces ******
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Initialize and shutdown the page cache subsystem. Neither of these
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** functions are threadsafe.
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int sqlite3PcacheInitialize(void){
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( sqlite3GlobalConfig.pcache.xInit==0 ){
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* IMPLEMENTATION-OF: R-26801-64137 If the xInit() method is NULL, then the
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ** built-in default page cache is used instead of the application defined
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ** page cache. */
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3PCacheSetDefault();
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return sqlite3GlobalConfig.pcache.xInit(sqlite3GlobalConfig.pcache.pArg);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void sqlite3PcacheShutdown(void){
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( sqlite3GlobalConfig.pcache.xShutdown ){
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* IMPLEMENTATION-OF: R-26000-56589 The xShutdown() method may be NULL. */
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3GlobalConfig.pcache.xShutdown(sqlite3GlobalConfig.pcache.pArg);
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Return the size in bytes of a PCache object.
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int sqlite3PcacheSize(void){ return sizeof(PCache); }
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Create a new PCache object. Storage space to hold the object
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** has already been allocated and is passed in as the p pointer.
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The caller discovers how much space needs to be allocated by
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** calling sqlite3PcacheSize().
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void sqlite3PcacheOpen(
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int szPage,                  /* Size of every page */
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int szExtra,                 /* Extra space associated with each page */
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int bPurgeable,              /* True if pages are on backing store */
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int (*xStress)(void*,PgHdr*),/* Call to try to make pages clean */
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void *pStress,               /* Argument to xStress */
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PCache *p                    /* Preallocated space for the PCache */
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(p, 0, sizeof(PCache));
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->szPage = szPage;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->szExtra = szExtra;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->bPurgeable = bPurgeable;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->xStress = xStress;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->pStress = pStress;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->nMax = 100;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Change the page size for PCache object. The caller must ensure that there
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** are no outstanding page references when this function is called.
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pCache->nRef==0 && pCache->pDirty==0 );
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pCache->pCache ){
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3GlobalConfig.pcache.xDestroy(pCache->pCache);
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pCache->pCache = 0;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pCache->pPage1 = 0;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCache->szPage = szPage;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Try to obtain a page from the cache.
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int sqlite3PcacheFetch(
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PCache *pCache,       /* Obtain the page from this cache */
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Pgno pgno,            /* Page number to obtain */
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int createFlag,       /* If true, create page if it does not exist already */
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgHdr **ppPage        /* Write the page here */
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgHdr *pPage = 0;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int eCreate;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pCache!=0 );
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( createFlag==1 || createFlag==0 );
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pgno>0 );
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* If the pluggable cache (sqlite3_pcache*) has not been allocated,
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** allocate it now.
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  */
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( !pCache->pCache && createFlag ){
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_pcache *p;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int nByte;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nByte = pCache->szPage + pCache->szExtra + sizeof(PgHdr);
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p = sqlite3GlobalConfig.pcache.xCreate(nByte, pCache->bPurgeable);
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( !p ){
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return SQLITE_NOMEM;
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3GlobalConfig.pcache.xCachesize(p, pCache->nMax);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pCache->pCache = p;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  eCreate = createFlag * (1 + (!pCache->bPurgeable || !pCache->pDirty));
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pCache->pCache ){
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pPage = sqlite3GlobalConfig.pcache.xFetch(pCache->pCache, pgno, eCreate);
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( !pPage && eCreate==1 ){
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PgHdr *pPg;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* Find a dirty page to write-out and recycle. First try to find a
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ** cleared), but if that is not possible settle for any other
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ** unreferenced dirty page.
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    */
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    expensive_assert( pcacheCheckSynced(pCache) );
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for(pPg=pCache->pSynced;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC));
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pPg=pPg->pDirtyPrev
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    );
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pCache->pSynced = pPg;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( !pPg ){
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev);
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pPg ){
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int rc;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      rc = pCache->xStress(pCache->pStress, pPg);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return rc;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pPage = sqlite3GlobalConfig.pcache.xFetch(pCache->pCache, pgno, 2);
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pPage ){
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( !pPage->pData ){
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      memset(pPage, 0, sizeof(PgHdr));
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pPage->pData = (void *)&pPage[1];
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pPage->pExtra = (void*)&((char *)pPage->pData)[pCache->szPage];
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      memset(pPage->pExtra, 0, pCache->szExtra);
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pPage->pCache = pCache;
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pPage->pgno = pgno;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert( pPage->pCache==pCache );
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert( pPage->pgno==pgno );
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert( pPage->pData==(void *)&pPage[1] );
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert( pPage->pExtra==(void *)&((char *)&pPage[1])[pCache->szPage] );
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( 0==pPage->nRef ){
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pCache->nRef++;
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pPage->nRef++;
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pgno==1 ){
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pCache->pPage1 = pPage;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *ppPage = pPage;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (pPage==0 && eCreate) ? SQLITE_NOMEM : SQLITE_OK;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Decrement the reference count on a page. If the page is clean and the
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** reference count drops to 0, then it is made elible for recycling.
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void sqlite3PcacheRelease(PgHdr *p){
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( p->nRef>0 );
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->nRef--;
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( p->nRef==0 ){
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PCache *pCache = p->pCache;
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pCache->nRef--;
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( (p->flags&PGHDR_DIRTY)==0 ){
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pcacheUnpin(p);
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }else{
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* Move the page to the head of the dirty list. */
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pcacheRemoveFromDirtyList(p);
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pcacheAddToDirtyList(p);
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Increase the reference count of a supplied page by 1.
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void sqlite3PcacheRef(PgHdr *p){
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert(p->nRef>0);
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->nRef++;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Drop a page from the cache. There must be exactly one reference to the
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** page. This function deletes that reference, so after it returns the
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** page pointed to by p is invalid.
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void sqlite3PcacheDrop(PgHdr *p){
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PCache *pCache;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( p->nRef==1 );
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( p->flags&PGHDR_DIRTY ){
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcacheRemoveFromDirtyList(p);
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCache = p->pCache;
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCache->nRef--;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( p->pgno==1 ){
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pCache->pPage1 = 0;
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3GlobalConfig.pcache.xUnpin(pCache->pCache, p, 1);
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Make sure the page is marked as dirty. If it isn't dirty already,
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** make it so.
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void sqlite3PcacheMakeDirty(PgHdr *p){
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->flags &= ~PGHDR_DONT_WRITE;
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( p->nRef>0 );
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( 0==(p->flags & PGHDR_DIRTY) ){
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p->flags |= PGHDR_DIRTY;
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcacheAddToDirtyList( p);
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Make sure the page is marked as clean. If it isn't clean already,
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** make it so.
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void sqlite3PcacheMakeClean(PgHdr *p){
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( (p->flags & PGHDR_DIRTY) ){
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcacheRemoveFromDirtyList(p);
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC);
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( p->nRef==0 ){
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pcacheUnpin(p);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Make every page in the cache clean.
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void sqlite3PcacheCleanAll(PCache *pCache){
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgHdr *p;
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while( (p = pCache->pDirty)!=0 ){
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3PcacheMakeClean(p);
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Clear the PGHDR_NEED_SYNC flag from all dirty pages.
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void sqlite3PcacheClearSyncFlags(PCache *pCache){
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgHdr *p;
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(p=pCache->pDirty; p; p=p->pDirtyNext){
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p->flags &= ~PGHDR_NEED_SYNC;
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCache->pSynced = pCache->pDirtyTail;
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Change the page number of page p to newPgno.
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PCache *pCache = p->pCache;
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( p->nRef>0 );
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( newPgno>0 );
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3GlobalConfig.pcache.xRekey(pCache->pCache, p, p->pgno, newPgno);
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->pgno = newPgno;
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcacheRemoveFromDirtyList(p);
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcacheAddToDirtyList(p);
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Drop every cache entry whose page number is greater than "pgno". The
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** caller must ensure that there are no outstanding references to any pages
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** other than page 1 with a page number greater than pgno.
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** If there is a reference to page 1 and the pgno parameter passed to this
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** function is 0, then the data area associated with page 1 is zeroed, but
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** the page object is not dropped.
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pCache->pCache ){
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PgHdr *p;
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PgHdr *pNext;
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for(p=pCache->pDirty; p; p=pNext){
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pNext = p->pDirtyNext;
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* This routine never gets call with a positive pgno except right
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ** after sqlite3PcacheCleanAll().  So if there are dirty pages,
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ** it must be that pgno==0.
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      */
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert( p->pgno>0 );
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( ALWAYS(p->pgno>pgno) ){
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        assert( p->flags&PGHDR_DIRTY );
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sqlite3PcacheMakeClean(p);
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pgno==0 && pCache->pPage1 ){
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      memset(pCache->pPage1->pData, 0, pCache->szPage);
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pgno = 1;
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3GlobalConfig.pcache.xTruncate(pCache->pCache, pgno+1);
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Close a cache.
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void sqlite3PcacheClose(PCache *pCache){
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pCache->pCache ){
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3GlobalConfig.pcache.xDestroy(pCache->pCache);
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Discard the contents of the cache.
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void sqlite3PcacheClear(PCache *pCache){
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3PcacheTruncate(pCache, 0);
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Merge two lists of pages connected by pDirty and in pgno order.
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Do not both fixing the pDirtyPrev pointers.
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgHdr result, *pTail;
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pTail = &result;
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while( pA && pB ){
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pA->pgno<pB->pgno ){
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pTail->pDirty = pA;
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pTail = pA;
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pA = pA->pDirty;
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }else{
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pTail->pDirty = pB;
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pTail = pB;
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pB = pB->pDirty;
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pA ){
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pTail->pDirty = pA;
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else if( pB ){
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pTail->pDirty = pB;
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pTail->pDirty = 0;
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result.pDirty;
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Sort the list of pages in accending order by pgno.  Pages are
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** connected by pDirty pointers.  The pDirtyPrev pointers are
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** corrupted by this sort.
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Since there cannot be more than 2^31 distinct pages in a database,
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** there cannot be more than 31 buckets required by the merge sorter.
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** One extra bucket is added to catch overflow in case something
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** ever changes to make the previous sentence incorrect.
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define N_SORT_BUCKET  32
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static PgHdr *pcacheSortDirtyList(PgHdr *pIn){
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgHdr *a[N_SORT_BUCKET], *p;
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i;
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(a, 0, sizeof(a));
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while( pIn ){
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p = pIn;
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pIn = p->pDirty;
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p->pDirty = 0;
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for(i=0; ALWAYS(i<N_SORT_BUCKET-1); i++){
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( a[i]==0 ){
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        a[i] = p;
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }else{
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        p = pcacheMergeDirtyList(a[i], p);
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        a[i] = 0;
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( NEVER(i==N_SORT_BUCKET-1) ){
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* To get here, there need to be 2^(N_SORT_BUCKET) elements in
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ** the input list.  But that is impossible.
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      */
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      a[i] = pcacheMergeDirtyList(a[i], p);
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p = a[0];
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(i=1; i<N_SORT_BUCKET; i++){
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p = pcacheMergeDirtyList(p, a[i]);
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return p;
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Return a list of all dirty pages in the cache, sorted by page number.
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PgHdr *sqlite3PcacheDirtyList(PCache *pCache){
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgHdr *p;
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(p=pCache->pDirty; p; p=p->pDirtyNext){
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p->pDirty = p->pDirtyNext;
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pcacheSortDirtyList(pCache->pDirty);
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Return the total number of referenced pages held by the cache.
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int sqlite3PcacheRefCount(PCache *pCache){
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pCache->nRef;
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Return the number of references to the page supplied as an argument.
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int sqlite3PcachePageRefcount(PgHdr *p){
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return p->nRef;
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Return the total number of pages in the cache.
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int sqlite3PcachePagecount(PCache *pCache){
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nPage = 0;
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pCache->pCache ){
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nPage = sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache);
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return nPage;
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#ifdef SQLITE_TEST
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Get the suggested cache-size value.
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int sqlite3PcacheGetCachesize(PCache *pCache){
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pCache->nMax;
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Set the suggested cache-size value.
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCache->nMax = mxPage;
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pCache->pCache ){
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3GlobalConfig.pcache.xCachesize(pCache->pCache, mxPage);
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** For all dirty pages currently in the cache, invoke the specified
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** callback. This is only used if the SQLITE_CHECK_PAGES macro is
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** defined.
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)){
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgHdr *pDirty;
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext){
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    xIter(pDirty);
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
588