xref: /sqlite-3.40.0/src/pcache.c (revision a002cc17)
18c0a791aSdanielk1977 /*
28c0a791aSdanielk1977 ** 2008 August 05
38c0a791aSdanielk1977 **
48c0a791aSdanielk1977 ** The author disclaims copyright to this source code.  In place of
58c0a791aSdanielk1977 ** a legal notice, here is a blessing:
68c0a791aSdanielk1977 **
78c0a791aSdanielk1977 **    May you do good and not evil.
88c0a791aSdanielk1977 **    May you find forgiveness for yourself and forgive others.
98c0a791aSdanielk1977 **    May you share freely, never taking more than you give.
108c0a791aSdanielk1977 **
118c0a791aSdanielk1977 *************************************************************************
128c0a791aSdanielk1977 ** This file implements that page cache.
138c0a791aSdanielk1977 */
148c0a791aSdanielk1977 #include "sqliteInt.h"
158c0a791aSdanielk1977 
168c0a791aSdanielk1977 /*
1772e6a399Sdrh ** A complete page cache is an instance of this structure.  Every
1872e6a399Sdrh ** entry in the cache holds a single page of the database file.  The
1972e6a399Sdrh ** btree layer only operates on the cached copy of the database pages.
2072e6a399Sdrh **
2172e6a399Sdrh ** A page cache entry is "clean" if it exactly matches what is currently
2272e6a399Sdrh ** on disk.  A page is "dirty" if it has been modified and needs to be
2372e6a399Sdrh ** persisted to disk.
24b2ef900aSdan **
25b2ef900aSdan ** pDirty, pDirtyTail, pSynced:
26b2ef900aSdan **   All dirty pages are linked into the doubly linked list using
27b2ef900aSdan **   PgHdr.pDirtyNext and pDirtyPrev. The list is maintained in LRU order
28b2ef900aSdan **   such that p was added to the list more recently than p->pDirtyNext.
29b2ef900aSdan **   PCache.pDirty points to the first (newest) element in the list and
30b2ef900aSdan **   pDirtyTail to the last (oldest).
31b2ef900aSdan **
32b2ef900aSdan **   The PCache.pSynced variable is used to optimize searching for a dirty
33b2ef900aSdan **   page to eject from the cache mid-transaction. It is better to eject
34b2ef900aSdan **   a page that does not require a journal sync than one that does.
355eaebf3aSdrh **   Therefore, pSynced is maintained so that it *almost* always points
36b2ef900aSdan **   to either the oldest page in the pDirty/pDirtyTail list that has a
37b2ef900aSdan **   clear PGHDR_NEED_SYNC flag or to a page that is older than this one
38b2ef900aSdan **   (so that the right page to eject can be found by following pDirtyPrev
39b2ef900aSdan **   pointers).
408c0a791aSdanielk1977 */
418c0a791aSdanielk1977 struct PCache {
42d491e1bfSdanielk1977   PgHdr *pDirty, *pDirtyTail;         /* List of dirty pages in LRU order */
43d491e1bfSdanielk1977   PgHdr *pSynced;                     /* Last synced page in dirty page list */
4495a0b371Sdrh   int nRefSum;                        /* Sum of ref counts over all pages */
453b42abb3Sdrh   int szCache;                        /* Configured cache size */
469b0cf34fSdrh   int szSpill;                        /* Size before spilling occurs */
47a85f7e36Sdrh   int szPage;                         /* Size of every page in this cache */
48a85f7e36Sdrh   int szExtra;                        /* Size of extra space for each page */
49fe21a796Sdrh   u8 bPurgeable;                      /* True if pages are on backing store */
50fe21a796Sdrh   u8 eCreate;                         /* eCreate value for for xFetch() */
51a85f7e36Sdrh   int (*xStress)(void*,PgHdr*);       /* Call to try make a page clean */
52a85f7e36Sdrh   void *pStress;                      /* Argument to xStress */
53bc2ca9ebSdanielk1977   sqlite3_pcache *pCache;             /* Pluggable cache module */
548c0a791aSdanielk1977 };
558c0a791aSdanielk1977 
56a0f6b124Sdrh /********************************** Test and Debug Logic **********************/
575c8e0928Sdrh /*
58a0f6b124Sdrh ** Debug tracing macros.  Enable by by changing the "0" to "1" and
59a0f6b124Sdrh ** recompiling.
60a0f6b124Sdrh **
61a0f6b124Sdrh ** When sqlite3PcacheTrace is 1, single line trace messages are issued.
62a0f6b124Sdrh ** When sqlite3PcacheTrace is 2, a dump of the pcache showing all cache entries
63a0f6b124Sdrh ** is displayed for many operations, resulting in a lot of output.
645c8e0928Sdrh */
655c8e0928Sdrh #if defined(SQLITE_DEBUG) && 0
66a0f6b124Sdrh   int sqlite3PcacheTrace = 2;       /* 0: off  1: simple  2: cache dumps */
67a0f6b124Sdrh   int sqlite3PcacheMxDump = 9999;   /* Max cache entries for pcacheDump() */
685c8e0928Sdrh # define pcacheTrace(X) if(sqlite3PcacheTrace){sqlite3DebugPrintf X;}
pcachePageTrace(int i,sqlite3_pcache_page * pLower)69f6e3e316Sdrh   static void pcachePageTrace(int i, sqlite3_pcache_page *pLower){
707aeb216aSdrh     PgHdr *pPg;
717aeb216aSdrh     unsigned char *a;
72f6e3e316Sdrh     int j;
73f6e3e316Sdrh     pPg = (PgHdr*)pLower->pExtra;
74f6e3e316Sdrh     printf("%3d: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags);
75f6e3e316Sdrh     a = (unsigned char *)pLower->pBuf;
76f6e3e316Sdrh     for(j=0; j<12; j++) printf("%02x", a[j]);
77f6e3e316Sdrh     printf(" ptr %p\n", pPg);
78f6e3e316Sdrh   }
pcacheDump(PCache * pCache)79f6e3e316Sdrh   static void pcacheDump(PCache *pCache){
80f6e3e316Sdrh     int N;
81f6e3e316Sdrh     int i;
82f6e3e316Sdrh     sqlite3_pcache_page *pLower;
837aeb216aSdrh 
847aeb216aSdrh     if( sqlite3PcacheTrace<2 ) return;
857aeb216aSdrh     if( pCache->pCache==0 ) return;
867aeb216aSdrh     N = sqlite3PcachePagecount(pCache);
87a0f6b124Sdrh     if( N>sqlite3PcacheMxDump ) N = sqlite3PcacheMxDump;
887aeb216aSdrh     for(i=1; i<=N; i++){
897aeb216aSdrh        pLower = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0);
907aeb216aSdrh        if( pLower==0 ) continue;
91f6e3e316Sdrh        pcachePageTrace(i, pLower);
92f6e3e316Sdrh        if( ((PgHdr*)pLower)->pPage==0 ){
937aeb216aSdrh          sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, pLower, 0);
947aeb216aSdrh        }
957aeb216aSdrh     }
967aeb216aSdrh   }
975c8e0928Sdrh #else
985c8e0928Sdrh # define pcacheTrace(X)
99f6e3e316Sdrh # define pcachePageTrace(PGNO, X)
1007aeb216aSdrh # define pcacheDump(X)
1015c8e0928Sdrh #endif
1025c8e0928Sdrh 
103a0f6b124Sdrh /*
104f0f025b3Sdrh ** Return 1 if pPg is on the dirty list for pCache.  Return 0 if not.
105f0f025b3Sdrh ** This routine runs inside of assert() statements only.
106f0f025b3Sdrh */
107f0f025b3Sdrh #ifdef SQLITE_DEBUG
pageOnDirtyList(PCache * pCache,PgHdr * pPg)108f0f025b3Sdrh static int pageOnDirtyList(PCache *pCache, PgHdr *pPg){
109f0f025b3Sdrh   PgHdr *p;
110f0f025b3Sdrh   for(p=pCache->pDirty; p; p=p->pDirtyNext){
111f0f025b3Sdrh     if( p==pPg ) return 1;
112f0f025b3Sdrh   }
113f0f025b3Sdrh   return 0;
114f0f025b3Sdrh }
115f0f025b3Sdrh #endif
116f0f025b3Sdrh 
117f0f025b3Sdrh /*
118a0f6b124Sdrh ** Check invariants on a PgHdr entry.  Return true if everything is OK.
119a0f6b124Sdrh ** Return false if any invariant is violated.
120a0f6b124Sdrh **
121a0f6b124Sdrh ** This routine is for use inside of assert() statements only.  For
122a0f6b124Sdrh ** example:
123a0f6b124Sdrh **
124a0f6b124Sdrh **          assert( sqlite3PcachePageSanity(pPg) );
125a0f6b124Sdrh */
126d879e3ebSdrh #ifdef SQLITE_DEBUG
sqlite3PcachePageSanity(PgHdr * pPg)127a0f6b124Sdrh int sqlite3PcachePageSanity(PgHdr *pPg){
128a0f6b124Sdrh   PCache *pCache;
129a0f6b124Sdrh   assert( pPg!=0 );
130cbed604fSdrh   assert( pPg->pgno>0 || pPg->pPager==0 );    /* Page number is 1 or more */
131a0f6b124Sdrh   pCache = pPg->pCache;
132a0f6b124Sdrh   assert( pCache!=0 );      /* Every page has an associated PCache */
133a0f6b124Sdrh   if( pPg->flags & PGHDR_CLEAN ){
134a0f6b124Sdrh     assert( (pPg->flags & PGHDR_DIRTY)==0 );/* Cannot be both CLEAN and DIRTY */
135f0f025b3Sdrh     assert( !pageOnDirtyList(pCache, pPg) );/* CLEAN pages not on dirty list */
136f6e3e316Sdrh   }else{
137f6e3e316Sdrh     assert( (pPg->flags & PGHDR_DIRTY)!=0 );/* If not CLEAN must be DIRTY */
138f6e3e316Sdrh     assert( pPg->pDirtyNext==0 || pPg->pDirtyNext->pDirtyPrev==pPg );
139f6e3e316Sdrh     assert( pPg->pDirtyPrev==0 || pPg->pDirtyPrev->pDirtyNext==pPg );
140f6e3e316Sdrh     assert( pPg->pDirtyPrev!=0 || pCache->pDirty==pPg );
141f0f025b3Sdrh     assert( pageOnDirtyList(pCache, pPg) );
142a0f6b124Sdrh   }
143a0f6b124Sdrh   /* WRITEABLE pages must also be DIRTY */
144a0f6b124Sdrh   if( pPg->flags & PGHDR_WRITEABLE ){
145a0f6b124Sdrh     assert( pPg->flags & PGHDR_DIRTY );     /* WRITEABLE implies DIRTY */
146a0f6b124Sdrh   }
147a0f6b124Sdrh   /* NEED_SYNC can be set independently of WRITEABLE.  This can happen,
148a0f6b124Sdrh   ** for example, when using the sqlite3PagerDontWrite() optimization:
149a0f6b124Sdrh   **    (1)  Page X is journalled, and gets WRITEABLE and NEED_SEEK.
150a0f6b124Sdrh   **    (2)  Page X moved to freelist, WRITEABLE is cleared
151a0f6b124Sdrh   **    (3)  Page X reused, WRITEABLE is set again
152a0f6b124Sdrh   ** If NEED_SYNC had been cleared in step 2, then it would not be reset
153a0f6b124Sdrh   ** in step 3, and page might be written into the database without first
154a0f6b124Sdrh   ** syncing the rollback journal, which might cause corruption on a power
155a0f6b124Sdrh   ** loss.
1563b02a07eSdrh   **
1573b02a07eSdrh   ** Another example is when the database page size is smaller than the
1583b02a07eSdrh   ** disk sector size.  When any page of a sector is journalled, all pages
1593b02a07eSdrh   ** in that sector are marked NEED_SYNC even if they are still CLEAN, just
1603b02a07eSdrh   ** in case they are later modified, since all pages in the same sector
1613b02a07eSdrh   ** must be journalled and synced before any of those pages can be safely
1623b02a07eSdrh   ** written.
163a0f6b124Sdrh   */
164a0f6b124Sdrh   return 1;
165a0f6b124Sdrh }
166a0f6b124Sdrh #endif /* SQLITE_DEBUG */
167a0f6b124Sdrh 
168a0f6b124Sdrh 
1698c0a791aSdanielk1977 /********************************** Linked List Management ********************/
1708c0a791aSdanielk1977 
171a8dcba91Sdrh /* Allowed values for second argument to pcacheManageDirtyList() */
172a8dcba91Sdrh #define PCACHE_DIRTYLIST_REMOVE   1    /* Remove pPage from dirty list */
173a8dcba91Sdrh #define PCACHE_DIRTYLIST_ADD      2    /* Add pPage to the dirty list */
174a8dcba91Sdrh #define PCACHE_DIRTYLIST_FRONT    3    /* Move pPage to the front of the list */
175a8dcba91Sdrh 
1768c0a791aSdanielk1977 /*
177a8dcba91Sdrh ** Manage pPage's participation on the dirty list.  Bits of the addRemove
178a8dcba91Sdrh ** argument determines what operation to do.  The 0x01 bit means first
179a8dcba91Sdrh ** remove pPage from the dirty list.  The 0x02 means add pPage back to
180a8dcba91Sdrh ** the dirty list.  Doing both moves pPage to the front of the dirty list.
1818c0a791aSdanielk1977 */
pcacheManageDirtyList(PgHdr * pPage,u8 addRemove)182a8dcba91Sdrh static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
183bc2ca9ebSdanielk1977   PCache *p = pPage->pCache;
1848c0a791aSdanielk1977 
1855c8e0928Sdrh   pcacheTrace(("%p.DIRTYLIST.%s %d\n", p,
1865c8e0928Sdrh                 addRemove==1 ? "REMOVE" : addRemove==2 ? "ADD" : "FRONT",
1875c8e0928Sdrh                 pPage->pgno));
188a8dcba91Sdrh   if( addRemove & PCACHE_DIRTYLIST_REMOVE ){
189bc2ca9ebSdanielk1977     assert( pPage->pDirtyNext || pPage==p->pDirtyTail );
190bc2ca9ebSdanielk1977     assert( pPage->pDirtyPrev || pPage==p->pDirty );
1918c0a791aSdanielk1977 
192bc2ca9ebSdanielk1977     /* Update the PCache1.pSynced variable if necessary. */
193bc2ca9ebSdanielk1977     if( p->pSynced==pPage ){
194b2ef900aSdan       p->pSynced = pPage->pDirtyPrev;
1958c0a791aSdanielk1977     }
1968c0a791aSdanielk1977 
197bc2ca9ebSdanielk1977     if( pPage->pDirtyNext ){
198bc2ca9ebSdanielk1977       pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev;
1998c0a791aSdanielk1977     }else{
200bc2ca9ebSdanielk1977       assert( pPage==p->pDirtyTail );
201bc2ca9ebSdanielk1977       p->pDirtyTail = pPage->pDirtyPrev;
2028c0a791aSdanielk1977     }
203bc2ca9ebSdanielk1977     if( pPage->pDirtyPrev ){
204bc2ca9ebSdanielk1977       pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext;
2058c0a791aSdanielk1977     }else{
206401907e3Sdan       /* If there are now no dirty pages in the cache, set eCreate to 2.
207401907e3Sdan       ** This is an optimization that allows sqlite3PcacheFetch() to skip
208401907e3Sdan       ** searching for a dirty page to eject from the cache when it might
209401907e3Sdan       ** otherwise have to.  */
210bc2ca9ebSdanielk1977       assert( pPage==p->pDirty );
211bc2ca9ebSdanielk1977       p->pDirty = pPage->pDirtyNext;
212401907e3Sdan       assert( p->bPurgeable || p->eCreate==2 );
213401907e3Sdan       if( p->pDirty==0 ){         /*OPTIMIZATION-IF-TRUE*/
214401907e3Sdan         assert( p->bPurgeable==0 || p->eCreate==1 );
215fe21a796Sdrh         p->eCreate = 2;
216fe21a796Sdrh       }
2178c0a791aSdanielk1977     }
2188c0a791aSdanielk1977   }
219a8dcba91Sdrh   if( addRemove & PCACHE_DIRTYLIST_ADD ){
220f0dae6d0Sdrh     pPage->pDirtyPrev = 0;
221bc2ca9ebSdanielk1977     pPage->pDirtyNext = p->pDirty;
222bc2ca9ebSdanielk1977     if( pPage->pDirtyNext ){
223bc2ca9ebSdanielk1977       assert( pPage->pDirtyNext->pDirtyPrev==0 );
224bc2ca9ebSdanielk1977       pPage->pDirtyNext->pDirtyPrev = pPage;
22536ce9191Sdrh     }else{
22636ce9191Sdrh       p->pDirtyTail = pPage;
22736ce9191Sdrh       if( p->bPurgeable ){
228fe21a796Sdrh         assert( p->eCreate==2 );
229fe21a796Sdrh         p->eCreate = 1;
2308c0a791aSdanielk1977       }
231bc2ca9ebSdanielk1977     }
23236ce9191Sdrh     p->pDirty = pPage;
233613723d9Sdan 
234613723d9Sdan     /* If pSynced is NULL and this page has a clear NEED_SYNC flag, set
235613723d9Sdan     ** pSynced to point to it. Checking the NEED_SYNC flag is an
236613723d9Sdan     ** optimization, as if pSynced points to a page with the NEED_SYNC
237613723d9Sdan     ** flag set sqlite3PcacheFetchStress() searches through all newer
238613723d9Sdan     ** entries of the dirty-list for a page with NEED_SYNC clear anyway.  */
239613723d9Sdan     if( !p->pSynced
240613723d9Sdan      && 0==(pPage->flags&PGHDR_NEED_SYNC)   /*OPTIMIZATION-IF-FALSE*/
241613723d9Sdan     ){
242bc2ca9ebSdanielk1977       p->pSynced = pPage;
243bc2ca9ebSdanielk1977     }
2448c0a791aSdanielk1977   }
2457aeb216aSdrh   pcacheDump(p);
246a8dcba91Sdrh }
2478c0a791aSdanielk1977 
2488c0a791aSdanielk1977 /*
249bc2ca9ebSdanielk1977 ** Wrapper around the pluggable caches xUnpin method. If the cache is
250bc2ca9ebSdanielk1977 ** being used for an in-memory database, this function is a no-op.
2518c0a791aSdanielk1977 */
pcacheUnpin(PgHdr * p)252bc2ca9ebSdanielk1977 static void pcacheUnpin(PgHdr *p){
253a8dcba91Sdrh   if( p->pCache->bPurgeable ){
2545c8e0928Sdrh     pcacheTrace(("%p.UNPIN %d\n", p->pCache, p->pgno));
255a8dcba91Sdrh     sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 0);
2567aeb216aSdrh     pcacheDump(p->pCache);
2578c0a791aSdanielk1977   }
2588c0a791aSdanielk1977 }
2598c0a791aSdanielk1977 
260c3031c61Sdrh /*
261e0e84295Sdrh ** Compute the number of pages of cache requested.   p->szCache is the
262e0e84295Sdrh ** cache size requested by the "PRAGMA cache_size" statement.
263c3031c61Sdrh */
numberOfCachePages(PCache * p)264c3031c61Sdrh static int numberOfCachePages(PCache *p){
265c3031c61Sdrh   if( p->szCache>=0 ){
266e0e84295Sdrh     /* IMPLEMENTATION-OF: R-42059-47211 If the argument N is positive then the
267e0e84295Sdrh     ** suggested cache size is set to N. */
268c3031c61Sdrh     return p->szCache;
269c3031c61Sdrh   }else{
270e7e9539dSdrh     i64 n;
2710ce974d1Sdrh     /* IMPLEMANTATION-OF: R-59858-46238 If the argument N is negative, then the
2720ce974d1Sdrh     ** number of cache pages is adjusted to be a number of pages that would
2730ce974d1Sdrh     ** use approximately abs(N*1024) bytes of memory based on the current
2740ce974d1Sdrh     ** page size. */
275e7e9539dSdrh     n = ((-1024*(i64)p->szCache)/(p->szPage+p->szExtra));
276e7e9539dSdrh     if( n>1000000000 ) n = 1000000000;
277e7e9539dSdrh     return (int)n;
278c3031c61Sdrh   }
279c3031c61Sdrh }
280c3031c61Sdrh 
2818c0a791aSdanielk1977 /*************************************************** General Interfaces ******
2828c0a791aSdanielk1977 **
2838c0a791aSdanielk1977 ** Initialize and shutdown the page cache subsystem. Neither of these
2848c0a791aSdanielk1977 ** functions are threadsafe.
2858c0a791aSdanielk1977 */
sqlite3PcacheInitialize(void)2868c0a791aSdanielk1977 int sqlite3PcacheInitialize(void){
28722e21ff4Sdan   if( sqlite3GlobalConfig.pcache2.xInit==0 ){
288f759bb83Sdrh     /* IMPLEMENTATION-OF: R-26801-64137 If the xInit() method is NULL, then the
289f759bb83Sdrh     ** built-in default page cache is used instead of the application defined
290f759bb83Sdrh     ** page cache. */
291bc2ca9ebSdanielk1977     sqlite3PCacheSetDefault();
29255f66b34Sdrh     assert( sqlite3GlobalConfig.pcache2.xInit!=0 );
2938c0a791aSdanielk1977   }
29422e21ff4Sdan   return sqlite3GlobalConfig.pcache2.xInit(sqlite3GlobalConfig.pcache2.pArg);
2958c0a791aSdanielk1977 }
sqlite3PcacheShutdown(void)2968c0a791aSdanielk1977 void sqlite3PcacheShutdown(void){
29722e21ff4Sdan   if( sqlite3GlobalConfig.pcache2.xShutdown ){
298f759bb83Sdrh     /* IMPLEMENTATION-OF: R-26000-56589 The xShutdown() method may be NULL. */
29922e21ff4Sdan     sqlite3GlobalConfig.pcache2.xShutdown(sqlite3GlobalConfig.pcache2.pArg);
300bc2ca9ebSdanielk1977   }
3018c0a791aSdanielk1977 }
3028c0a791aSdanielk1977 
3038c0a791aSdanielk1977 /*
3048c0a791aSdanielk1977 ** Return the size in bytes of a PCache object.
3058c0a791aSdanielk1977 */
sqlite3PcacheSize(void)3068c0a791aSdanielk1977 int sqlite3PcacheSize(void){ return sizeof(PCache); }
3078c0a791aSdanielk1977 
3088c0a791aSdanielk1977 /*
3098c0a791aSdanielk1977 ** Create a new PCache object. Storage space to hold the object
3108c0a791aSdanielk1977 ** has already been allocated and is passed in as the p pointer.
311bc2ca9ebSdanielk1977 ** The caller discovers how much space needs to be allocated by
312bc2ca9ebSdanielk1977 ** calling sqlite3PcacheSize().
313a2ee589cSdrh **
314a2ee589cSdrh ** szExtra is some extra space allocated for each page.  The first
315a2ee589cSdrh ** 8 bytes of the extra space will be zeroed as the page is allocated,
316a2ee589cSdrh ** but remaining content will be uninitialized.  Though it is opaque
317a2ee589cSdrh ** to this module, the extra space really ends up being the MemPage
318a2ee589cSdrh ** structure in the pager.
3198c0a791aSdanielk1977 */
sqlite3PcacheOpen(int szPage,int szExtra,int bPurgeable,int (* xStress)(void *,PgHdr *),void * pStress,PCache * p)320c3031c61Sdrh int sqlite3PcacheOpen(
3218c0a791aSdanielk1977   int szPage,                  /* Size of every page */
3228c0a791aSdanielk1977   int szExtra,                 /* Extra space associated with each page */
3238c0a791aSdanielk1977   int bPurgeable,              /* True if pages are on backing store */
324a858aa2eSdanielk1977   int (*xStress)(void*,PgHdr*),/* Call to try to make pages clean */
3258c0a791aSdanielk1977   void *pStress,               /* Argument to xStress */
3268c0a791aSdanielk1977   PCache *p                    /* Preallocated space for the PCache */
3278c0a791aSdanielk1977 ){
3288c0a791aSdanielk1977   memset(p, 0, sizeof(PCache));
329c3031c61Sdrh   p->szPage = 1;
3308c0a791aSdanielk1977   p->szExtra = szExtra;
331a2ee589cSdrh   assert( szExtra>=8 );  /* First 8 bytes will be zeroed */
3328c0a791aSdanielk1977   p->bPurgeable = bPurgeable;
333fe21a796Sdrh   p->eCreate = 2;
3348c0a791aSdanielk1977   p->xStress = xStress;
3358c0a791aSdanielk1977   p->pStress = pStress;
3363b42abb3Sdrh   p->szCache = 100;
3379b0cf34fSdrh   p->szSpill = 1;
3385c8e0928Sdrh   pcacheTrace(("%p.OPEN szPage %d bPurgeable %d\n",p,szPage,bPurgeable));
339c3031c61Sdrh   return sqlite3PcacheSetPageSize(p, szPage);
3408c0a791aSdanielk1977 }
3418c0a791aSdanielk1977 
34241d3027cSdrh /*
343bc2ca9ebSdanielk1977 ** Change the page size for PCache object. The caller must ensure that there
344bc2ca9ebSdanielk1977 ** are no outstanding page references when this function is called.
34541d3027cSdrh */
sqlite3PcacheSetPageSize(PCache * pCache,int szPage)346c3031c61Sdrh int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
34795a0b371Sdrh   assert( pCache->nRefSum==0 && pCache->pDirty==0 );
348c3031c61Sdrh   if( pCache->szPage ){
349c3031c61Sdrh     sqlite3_pcache *pNew;
350c3031c61Sdrh     pNew = sqlite3GlobalConfig.pcache2.xCreate(
35151dc84ebSdrh                 szPage, pCache->szExtra + ROUND8(sizeof(PgHdr)),
35251dc84ebSdrh                 pCache->bPurgeable
353c3031c61Sdrh     );
354fad3039cSmistachkin     if( pNew==0 ) return SQLITE_NOMEM_BKPT;
355c3031c61Sdrh     sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache));
356bc2ca9ebSdanielk1977     if( pCache->pCache ){
35722e21ff4Sdan       sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
358bc2ca9ebSdanielk1977     }
359c3031c61Sdrh     pCache->pCache = pNew;
3608c0a791aSdanielk1977     pCache->szPage = szPage;
3615c8e0928Sdrh     pcacheTrace(("%p.PAGESIZE %d\n",pCache,szPage));
3628c0a791aSdanielk1977   }
363c3031c61Sdrh   return SQLITE_OK;
3643b42abb3Sdrh }
3653b42abb3Sdrh 
3663b42abb3Sdrh /*
3678c0a791aSdanielk1977 ** Try to obtain a page from the cache.
368bc59ac0eSdrh **
369bc59ac0eSdrh ** This routine returns a pointer to an sqlite3_pcache_page object if
370bc59ac0eSdrh ** such an object is already in cache, or if a new one is created.
371bc59ac0eSdrh ** This routine returns a NULL pointer if the object was not in cache
372bc59ac0eSdrh ** and could not be created.
373bc59ac0eSdrh **
374bc59ac0eSdrh ** The createFlags should be 0 to check for existing pages and should
375bc59ac0eSdrh ** be 3 (not 1, but 3) to try to create a new page.
376bc59ac0eSdrh **
377bc59ac0eSdrh ** If the createFlag is 0, then NULL is always returned if the page
378bc59ac0eSdrh ** is not already in the cache.  If createFlag is 1, then a new page
379bc59ac0eSdrh ** is created only if that can be done without spilling dirty pages
380bc59ac0eSdrh ** and without exceeding the cache size limit.
381bc59ac0eSdrh **
382bc59ac0eSdrh ** The caller needs to invoke sqlite3PcacheFetchFinish() to properly
383bc59ac0eSdrh ** initialize the sqlite3_pcache_page object and convert it into a
384bc59ac0eSdrh ** PgHdr object.  The sqlite3PcacheFetch() and sqlite3PcacheFetchFinish()
385bc59ac0eSdrh ** routines are split this way for performance reasons. When separated
386bc59ac0eSdrh ** they can both (usually) operate without having to push values to
387bc59ac0eSdrh ** the stack on entry and pop them back off on exit, which saves a
388bc59ac0eSdrh ** lot of pushing and popping.
3898c0a791aSdanielk1977 */
sqlite3PcacheFetch(PCache * pCache,Pgno pgno,int createFlag)390bc59ac0eSdrh sqlite3_pcache_page *sqlite3PcacheFetch(
3918c0a791aSdanielk1977   PCache *pCache,       /* Obtain the page from this cache */
3928c0a791aSdanielk1977   Pgno pgno,            /* Page number to obtain */
393bc59ac0eSdrh   int createFlag        /* If true, create page if it does not exist already */
3948c0a791aSdanielk1977 ){
395bc2ca9ebSdanielk1977   int eCreate;
3965c8e0928Sdrh   sqlite3_pcache_page *pRes;
397f599a199Sdanielk1977 
3988c0a791aSdanielk1977   assert( pCache!=0 );
399c3031c61Sdrh   assert( pCache->pCache!=0 );
400c3031c61Sdrh   assert( createFlag==3 || createFlag==0 );
401401907e3Sdan   assert( pCache->eCreate==((pCache->bPurgeable && pCache->pDirty) ? 1 : 2) );
4028c0a791aSdanielk1977 
403fe21a796Sdrh   /* eCreate defines what to do if the page does not exist.
404fe21a796Sdrh   **    0     Do not allocate a new page.  (createFlag==0)
405fe21a796Sdrh   **    1     Allocate a new page if doing so is inexpensive.
406fe21a796Sdrh   **          (createFlag==1 AND bPurgeable AND pDirty)
407fe21a796Sdrh   **    2     Allocate a new page even it doing so is difficult.
408fe21a796Sdrh   **          (createFlag==1 AND !(bPurgeable AND pDirty)
409fe21a796Sdrh   */
410c3031c61Sdrh   eCreate = createFlag & pCache->eCreate;
411c3031c61Sdrh   assert( eCreate==0 || eCreate==1 || eCreate==2 );
412c3031c61Sdrh   assert( createFlag==0 || pCache->eCreate==eCreate );
413c3031c61Sdrh   assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) );
4145c8e0928Sdrh   pRes = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
415f6e3e316Sdrh   pcacheTrace(("%p.FETCH %d%s (result: %p) ",pCache,pgno,
4165c8e0928Sdrh                createFlag?" create":"",pRes));
417f6e3e316Sdrh   pcachePageTrace(pgno, pRes);
4185c8e0928Sdrh   return pRes;
419bc59ac0eSdrh }
420bc59ac0eSdrh 
421bc59ac0eSdrh /*
422bc59ac0eSdrh ** If the sqlite3PcacheFetch() routine is unable to allocate a new
42341113b64Sdan ** page because no clean pages are available for reuse and the cache
424bc59ac0eSdrh ** size limit has been reached, then this routine can be invoked to
425bc59ac0eSdrh ** try harder to allocate a page.  This routine might invoke the stress
426bc59ac0eSdrh ** callback to spill dirty pages to the journal.  It will then try to
427bc59ac0eSdrh ** allocate the new page and will only fail to allocate a new page on
428bc59ac0eSdrh ** an OOM error.
429bc59ac0eSdrh **
430bc59ac0eSdrh ** This routine should be invoked only after sqlite3PcacheFetch() fails.
431bc59ac0eSdrh */
sqlite3PcacheFetchStress(PCache * pCache,Pgno pgno,sqlite3_pcache_page ** ppPage)432bc59ac0eSdrh int sqlite3PcacheFetchStress(
433bc59ac0eSdrh   PCache *pCache,                 /* Obtain the page from this cache */
434bc59ac0eSdrh   Pgno pgno,                      /* Page number to obtain */
435bc59ac0eSdrh   sqlite3_pcache_page **ppPage    /* Write result here */
436bc59ac0eSdrh ){
437bc2ca9ebSdanielk1977   PgHdr *pPg;
438bc59ac0eSdrh   if( pCache->eCreate==2 ) return 0;
439bc59ac0eSdrh 
4409b0cf34fSdrh   if( sqlite3PcachePagecount(pCache)>pCache->szSpill ){
441bc2ca9ebSdanielk1977     /* Find a dirty page to write-out and recycle. First try to find a
442bc2ca9ebSdanielk1977     ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
443bc2ca9ebSdanielk1977     ** cleared), but if that is not possible settle for any other
444bc2ca9ebSdanielk1977     ** unreferenced dirty page.
445b2ef900aSdan     **
446b2ef900aSdan     ** If the LRU page in the dirty list that has a clear PGHDR_NEED_SYNC
447b2ef900aSdan     ** flag is currently referenced, then the following may leave pSynced
448b2ef900aSdan     ** set incorrectly (pointing to other than the LRU page with NEED_SYNC
449b2ef900aSdan     ** cleared). This is Ok, as pSynced is just an optimization.  */
450bc2ca9ebSdanielk1977     for(pPg=pCache->pSynced;
451bc2ca9ebSdanielk1977         pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC));
452bc2ca9ebSdanielk1977         pPg=pPg->pDirtyPrev
453bc2ca9ebSdanielk1977     );
454a9638967Sdrh     pCache->pSynced = pPg;
455bc2ca9ebSdanielk1977     if( !pPg ){
456bc2ca9ebSdanielk1977       for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev);
457bc2ca9ebSdanielk1977     }
458bc2ca9ebSdanielk1977     if( pPg ){
459bc2ca9ebSdanielk1977       int rc;
460c97125ebSdrh #ifdef SQLITE_LOG_CACHE_SPILL
461c97125ebSdrh       sqlite3_log(SQLITE_FULL,
462c97125ebSdrh                   "spill page %d making room for %d - cache used: %d/%d",
463c97125ebSdrh                   pPg->pgno, pgno,
46458db4c76Sdan                   sqlite3GlobalConfig.pcache2.xPagecount(pCache->pCache),
4653b42abb3Sdrh                 numberOfCachePages(pCache));
466c97125ebSdrh #endif
4675c8e0928Sdrh       pcacheTrace(("%p.SPILL %d\n",pCache,pPg->pgno));
468bc2ca9ebSdanielk1977       rc = pCache->xStress(pCache->pStress, pPg);
4697aeb216aSdrh       pcacheDump(pCache);
470bc2ca9ebSdanielk1977       if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
471bc2ca9ebSdanielk1977         return rc;
472bc2ca9ebSdanielk1977       }
473bc2ca9ebSdanielk1977     }
4749b0cf34fSdrh   }
475bc59ac0eSdrh   *ppPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2);
476fad3039cSmistachkin   return *ppPage==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK;
477bc2ca9ebSdanielk1977 }
478bc2ca9ebSdanielk1977 
479bc59ac0eSdrh /*
480bc59ac0eSdrh ** This is a helper routine for sqlite3PcacheFetchFinish()
481bc59ac0eSdrh **
482bc59ac0eSdrh ** In the uncommon case where the page being fetched has not been
483bc59ac0eSdrh ** initialized, this routine is invoked to do the initialization.
484bc59ac0eSdrh ** This routine is broken out into a separate function since it
485bc59ac0eSdrh ** requires extra stack manipulation that can be avoided in the common
486bc59ac0eSdrh ** case.
487bc59ac0eSdrh */
pcacheFetchFinishWithInit(PCache * pCache,Pgno pgno,sqlite3_pcache_page * pPage)488bc59ac0eSdrh static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit(
489bc59ac0eSdrh   PCache *pCache,             /* Obtain the page from this cache */
490bc59ac0eSdrh   Pgno pgno,                  /* Page number obtained */
491bc59ac0eSdrh   sqlite3_pcache_page *pPage  /* Page obtained by prior PcacheFetch() call */
492bc59ac0eSdrh ){
493bc59ac0eSdrh   PgHdr *pPgHdr;
494bc59ac0eSdrh   assert( pPage!=0 );
49522e21ff4Sdan   pPgHdr = (PgHdr*)pPage->pExtra;
496bc59ac0eSdrh   assert( pPgHdr->pPage==0 );
497216b70ffSdrh   memset(&pPgHdr->pDirty, 0, sizeof(PgHdr) - offsetof(PgHdr,pDirty));
49822e21ff4Sdan   pPgHdr->pPage = pPage;
49922e21ff4Sdan   pPgHdr->pData = pPage->pBuf;
50022e21ff4Sdan   pPgHdr->pExtra = (void *)&pPgHdr[1];
501a2ee589cSdrh   memset(pPgHdr->pExtra, 0, 8);
50222e21ff4Sdan   pPgHdr->pCache = pCache;
50322e21ff4Sdan   pPgHdr->pgno = pgno;
504c78ae916Sdrh   pPgHdr->flags = PGHDR_CLEAN;
505bc59ac0eSdrh   return sqlite3PcacheFetchFinish(pCache,pgno,pPage);
50622e21ff4Sdan }
50722e21ff4Sdan 
508bc59ac0eSdrh /*
509bc59ac0eSdrh ** This routine converts the sqlite3_pcache_page object returned by
510bc59ac0eSdrh ** sqlite3PcacheFetch() into an initialized PgHdr object.  This routine
511bc59ac0eSdrh ** must be called after sqlite3PcacheFetch() in order to get a usable
512bc59ac0eSdrh ** result.
513bc59ac0eSdrh */
sqlite3PcacheFetchFinish(PCache * pCache,Pgno pgno,sqlite3_pcache_page * pPage)514bc59ac0eSdrh PgHdr *sqlite3PcacheFetchFinish(
515bc59ac0eSdrh   PCache *pCache,             /* Obtain the page from this cache */
516bc59ac0eSdrh   Pgno pgno,                  /* Page number obtained */
517bc59ac0eSdrh   sqlite3_pcache_page *pPage  /* Page obtained by prior PcacheFetch() call */
518bc59ac0eSdrh ){
519bc59ac0eSdrh   PgHdr *pPgHdr;
520bc59ac0eSdrh 
521d8c0ba3bSdrh   assert( pPage!=0 );
522bc59ac0eSdrh   pPgHdr = (PgHdr *)pPage->pExtra;
523bc59ac0eSdrh 
524bc59ac0eSdrh   if( !pPgHdr->pPage ){
525bc59ac0eSdrh     return pcacheFetchFinishWithInit(pCache, pgno, pPage);
526bc59ac0eSdrh   }
52795a0b371Sdrh   pCache->nRefSum++;
52822e21ff4Sdan   pPgHdr->nRef++;
529a0f6b124Sdrh   assert( sqlite3PcachePageSanity(pPgHdr) );
530bc59ac0eSdrh   return pPgHdr;
5318c0a791aSdanielk1977 }
5328c0a791aSdanielk1977 
5338c0a791aSdanielk1977 /*
534bc2ca9ebSdanielk1977 ** Decrement the reference count on a page. If the page is clean and the
53560ec914cSpeter.d.reid ** reference count drops to 0, then it is made eligible for recycling.
5368c0a791aSdanielk1977 */
sqlite3PcacheRelease(PgHdr * p)537a8dcba91Sdrh void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
5388c0a791aSdanielk1977   assert( p->nRef>0 );
53995a0b371Sdrh   p->pCache->nRefSum--;
54095a0b371Sdrh   if( (--p->nRef)==0 ){
541c78ae916Sdrh     if( p->flags&PGHDR_CLEAN ){
542bc2ca9ebSdanielk1977       pcacheUnpin(p);
543dfcdc663Sdrh     }else{
544a8dcba91Sdrh       pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
545f0f025b3Sdrh       assert( sqlite3PcachePageSanity(p) );
546d491e1bfSdanielk1977     }
5478c0a791aSdanielk1977   }
548502b7430Sdanielk1977 }
5498c0a791aSdanielk1977 
550bc2ca9ebSdanielk1977 /*
551bc2ca9ebSdanielk1977 ** Increase the reference count of a supplied page by 1.
552bc2ca9ebSdanielk1977 */
sqlite3PcacheRef(PgHdr * p)5538c0a791aSdanielk1977 void sqlite3PcacheRef(PgHdr *p){
554502b7430Sdanielk1977   assert(p->nRef>0);
555a0f6b124Sdrh   assert( sqlite3PcachePageSanity(p) );
556502b7430Sdanielk1977   p->nRef++;
55795a0b371Sdrh   p->pCache->nRefSum++;
5588c0a791aSdanielk1977 }
5598c0a791aSdanielk1977 
5608c0a791aSdanielk1977 /*
5614abdfa45Sdanielk1977 ** Drop a page from the cache. There must be exactly one reference to the
5624abdfa45Sdanielk1977 ** page. This function deletes that reference, so after it returns the
5634abdfa45Sdanielk1977 ** page pointed to by p is invalid.
5648c0a791aSdanielk1977 */
sqlite3PcacheDrop(PgHdr * p)5658c0a791aSdanielk1977 void sqlite3PcacheDrop(PgHdr *p){
5668c0a791aSdanielk1977   assert( p->nRef==1 );
567a0f6b124Sdrh   assert( sqlite3PcachePageSanity(p) );
568bc2ca9ebSdanielk1977   if( p->flags&PGHDR_DIRTY ){
569a8dcba91Sdrh     pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
570bc2ca9ebSdanielk1977   }
57195a0b371Sdrh   p->pCache->nRefSum--;
572a8dcba91Sdrh   sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 1);
5738c0a791aSdanielk1977 }
5748c0a791aSdanielk1977 
5758c0a791aSdanielk1977 /*
5768c0a791aSdanielk1977 ** Make sure the page is marked as dirty. If it isn't dirty already,
5778c0a791aSdanielk1977 ** make it so.
5788c0a791aSdanielk1977 */
sqlite3PcacheMakeDirty(PgHdr * p)5798c0a791aSdanielk1977 void sqlite3PcacheMakeDirty(PgHdr *p){
580c63e4095Sdrh   assert( p->nRef>0 );
581a0f6b124Sdrh   assert( sqlite3PcachePageSanity(p) );
58282c04477Sdan   if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){    /*OPTIMIZATION-IF-FALSE*/
583c78ae916Sdrh     p->flags &= ~PGHDR_DONT_WRITE;
584c78ae916Sdrh     if( p->flags & PGHDR_CLEAN ){
585c78ae916Sdrh       p->flags ^= (PGHDR_DIRTY|PGHDR_CLEAN);
5865c8e0928Sdrh       pcacheTrace(("%p.DIRTY %d\n",p->pCache,p->pgno));
587c78ae916Sdrh       assert( (p->flags & (PGHDR_DIRTY|PGHDR_CLEAN))==PGHDR_DIRTY );
588a8dcba91Sdrh       pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD);
589f0f025b3Sdrh       assert( sqlite3PcachePageSanity(p) );
5908c0a791aSdanielk1977     }
591a0f6b124Sdrh     assert( sqlite3PcachePageSanity(p) );
592f599a199Sdanielk1977   }
593c78ae916Sdrh }
594f599a199Sdanielk1977 
595f599a199Sdanielk1977 /*
596f599a199Sdanielk1977 ** Make sure the page is marked as clean. If it isn't clean already,
597f599a199Sdanielk1977 ** make it so.
598f599a199Sdanielk1977 */
sqlite3PcacheMakeClean(PgHdr * p)599f599a199Sdanielk1977 void sqlite3PcacheMakeClean(PgHdr *p){
600a0f6b124Sdrh   assert( sqlite3PcachePageSanity(p) );
6019d9c41e2Sdrh   assert( (p->flags & PGHDR_DIRTY)!=0 );
602c78ae916Sdrh   assert( (p->flags & PGHDR_CLEAN)==0 );
603a8dcba91Sdrh   pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
6041aacbdb3Sdrh   p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC|PGHDR_WRITEABLE);
605c78ae916Sdrh   p->flags |= PGHDR_CLEAN;
6065c8e0928Sdrh   pcacheTrace(("%p.CLEAN %d\n",p->pCache,p->pgno));
607a0f6b124Sdrh   assert( sqlite3PcachePageSanity(p) );
608bc2ca9ebSdanielk1977   if( p->nRef==0 ){
609bc2ca9ebSdanielk1977     pcacheUnpin(p);
610bc2ca9ebSdanielk1977   }
6118c0a791aSdanielk1977 }
6128c0a791aSdanielk1977 
6138c0a791aSdanielk1977 /*
6148c0a791aSdanielk1977 ** Make every page in the cache clean.
6158c0a791aSdanielk1977 */
sqlite3PcacheCleanAll(PCache * pCache)6168c0a791aSdanielk1977 void sqlite3PcacheCleanAll(PCache *pCache){
6178c0a791aSdanielk1977   PgHdr *p;
6187aeb216aSdrh   pcacheTrace(("%p.CLEAN-ALL\n",pCache));
6198c0a791aSdanielk1977   while( (p = pCache->pDirty)!=0 ){
620bc2ca9ebSdanielk1977     sqlite3PcacheMakeClean(p);
621d491e1bfSdanielk1977   }
622a858aa2eSdanielk1977 }
6238c0a791aSdanielk1977 
6248c0a791aSdanielk1977 /*
62541113b64Sdan ** Clear the PGHDR_NEED_SYNC and PGHDR_WRITEABLE flag from all dirty pages.
62641113b64Sdan */
sqlite3PcacheClearWritable(PCache * pCache)62741113b64Sdan void sqlite3PcacheClearWritable(PCache *pCache){
62841113b64Sdan   PgHdr *p;
6297aeb216aSdrh   pcacheTrace(("%p.CLEAR-WRITEABLE\n",pCache));
63041113b64Sdan   for(p=pCache->pDirty; p; p=p->pDirtyNext){
63141113b64Sdan     p->flags &= ~(PGHDR_NEED_SYNC|PGHDR_WRITEABLE);
63241113b64Sdan   }
63341113b64Sdan   pCache->pSynced = pCache->pDirtyTail;
63441113b64Sdan }
63541113b64Sdan 
63641113b64Sdan /*
637bc2ca9ebSdanielk1977 ** Clear the PGHDR_NEED_SYNC flag from all dirty pages.
638bc2ca9ebSdanielk1977 */
sqlite3PcacheClearSyncFlags(PCache * pCache)639bc2ca9ebSdanielk1977 void sqlite3PcacheClearSyncFlags(PCache *pCache){
640bc2ca9ebSdanielk1977   PgHdr *p;
641bc2ca9ebSdanielk1977   for(p=pCache->pDirty; p; p=p->pDirtyNext){
642bc2ca9ebSdanielk1977     p->flags &= ~PGHDR_NEED_SYNC;
643bc2ca9ebSdanielk1977   }
644bc2ca9ebSdanielk1977   pCache->pSynced = pCache->pDirtyTail;
645bc2ca9ebSdanielk1977 }
646bc2ca9ebSdanielk1977 
647bc2ca9ebSdanielk1977 /*
648bc2ca9ebSdanielk1977 ** Change the page number of page p to newPgno.
6498c0a791aSdanielk1977 */
sqlite3PcacheMove(PgHdr * p,Pgno newPgno)6508c0a791aSdanielk1977 void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
651bc2ca9ebSdanielk1977   PCache *pCache = p->pCache;
6525fc3a8a3Sdrh   sqlite3_pcache_page *pOther;
653d491e1bfSdanielk1977   assert( p->nRef>0 );
654bc2ca9ebSdanielk1977   assert( newPgno>0 );
655a0f6b124Sdrh   assert( sqlite3PcachePageSanity(p) );
6565c8e0928Sdrh   pcacheTrace(("%p.MOVE %d -> %d\n",pCache,p->pgno,newPgno));
6575fc3a8a3Sdrh   pOther = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, newPgno, 0);
6585fc3a8a3Sdrh   if( pOther ){
659*a002cc17Sstephan     PgHdr *pXPage = (PgHdr*)pOther->pExtra;
660*a002cc17Sstephan     assert( pXPage->nRef==0 );
661*a002cc17Sstephan     pXPage->nRef++;
662*a002cc17Sstephan     pCache->nRefSum++;
663*a002cc17Sstephan     sqlite3PcacheDrop(pXPage);
6645fc3a8a3Sdrh   }
665*a002cc17Sstephan   sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno);
6668c0a791aSdanielk1977   p->pgno = newPgno;
667bc2ca9ebSdanielk1977   if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
668a8dcba91Sdrh     pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
669f0f025b3Sdrh     assert( sqlite3PcachePageSanity(p) );
670f599a199Sdanielk1977   }
6718c0a791aSdanielk1977 }
6728c0a791aSdanielk1977 
6738c0a791aSdanielk1977 /*
674bc2ca9ebSdanielk1977 ** Drop every cache entry whose page number is greater than "pgno". The
675bc2ca9ebSdanielk1977 ** caller must ensure that there are no outstanding references to any pages
676bc2ca9ebSdanielk1977 ** other than page 1 with a page number greater than pgno.
677bc2ca9ebSdanielk1977 **
678bc2ca9ebSdanielk1977 ** If there is a reference to page 1 and the pgno parameter passed to this
679bc2ca9ebSdanielk1977 ** function is 0, then the data area associated with page 1 is zeroed, but
680bc2ca9ebSdanielk1977 ** the page object is not dropped.
6818c0a791aSdanielk1977 */
sqlite3PcacheTruncate(PCache * pCache,Pgno pgno)6828c0a791aSdanielk1977 void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
683bc2ca9ebSdanielk1977   if( pCache->pCache ){
684062d4cb0Sdanielk1977     PgHdr *p;
685bc2ca9ebSdanielk1977     PgHdr *pNext;
6865c8e0928Sdrh     pcacheTrace(("%p.TRUNCATE %d\n",pCache,pgno));
687bc2ca9ebSdanielk1977     for(p=pCache->pDirty; p; p=pNext){
688bc2ca9ebSdanielk1977       pNext = p->pDirtyNext;
689f3609eebSdrh       /* This routine never gets call with a positive pgno except right
690f3609eebSdrh       ** after sqlite3PcacheCleanAll().  So if there are dirty pages,
691f3609eebSdrh       ** it must be that pgno==0.
692f3609eebSdrh       */
693f3609eebSdrh       assert( p->pgno>0 );
69441113b64Sdan       if( p->pgno>pgno ){
695bc2ca9ebSdanielk1977         assert( p->flags&PGHDR_DIRTY );
696bc2ca9ebSdanielk1977         sqlite3PcacheMakeClean(p);
697bc2ca9ebSdanielk1977       }
698bc2ca9ebSdanielk1977     }
69995a0b371Sdrh     if( pgno==0 && pCache->nRefSum ){
70039065c60Sdrh       sqlite3_pcache_page *pPage1;
70139065c60Sdrh       pPage1 = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache,1,0);
70239065c60Sdrh       if( ALWAYS(pPage1) ){  /* Page 1 is always available in cache, because
70395a0b371Sdrh                              ** pCache->nRefSum>0 */
70439065c60Sdrh         memset(pPage1->pBuf, 0, pCache->szPage);
705bc2ca9ebSdanielk1977         pgno = 1;
706bc2ca9ebSdanielk1977       }
70739065c60Sdrh     }
70822e21ff4Sdan     sqlite3GlobalConfig.pcache2.xTruncate(pCache->pCache, pgno+1);
709062d4cb0Sdanielk1977   }
710062d4cb0Sdanielk1977 }
7118c0a791aSdanielk1977 
7128c0a791aSdanielk1977 /*
7138c0a791aSdanielk1977 ** Close a cache.
7148c0a791aSdanielk1977 */
sqlite3PcacheClose(PCache * pCache)7158c0a791aSdanielk1977 void sqlite3PcacheClose(PCache *pCache){
716c3031c61Sdrh   assert( pCache->pCache!=0 );
7175c8e0928Sdrh   pcacheTrace(("%p.CLOSE\n",pCache));
71822e21ff4Sdan   sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
7198c0a791aSdanielk1977 }
7208c0a791aSdanielk1977 
7218c0a791aSdanielk1977 /*
7228c0a791aSdanielk1977 ** Discard the contents of the cache.
7238c0a791aSdanielk1977 */
sqlite3PcacheClear(PCache * pCache)724bea2a948Sdanielk1977 void sqlite3PcacheClear(PCache *pCache){
725bc2ca9ebSdanielk1977   sqlite3PcacheTruncate(pCache, 0);
7268c0a791aSdanielk1977 }
7278c0a791aSdanielk1977 
7288c0a791aSdanielk1977 /*
7298c0a791aSdanielk1977 ** Merge two lists of pages connected by pDirty and in pgno order.
7302380f3f1Smistachkin ** Do not bother fixing the pDirtyPrev pointers.
7318c0a791aSdanielk1977 */
pcacheMergeDirtyList(PgHdr * pA,PgHdr * pB)7328c0a791aSdanielk1977 static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){
7338c0a791aSdanielk1977   PgHdr result, *pTail;
7348c0a791aSdanielk1977   pTail = &result;
735b982bfeaSdrh   assert( pA!=0 && pB!=0 );
736b982bfeaSdrh   for(;;){
7378c0a791aSdanielk1977     if( pA->pgno<pB->pgno ){
7388c0a791aSdanielk1977       pTail->pDirty = pA;
7398c0a791aSdanielk1977       pTail = pA;
7408c0a791aSdanielk1977       pA = pA->pDirty;
741b982bfeaSdrh       if( pA==0 ){
742b982bfeaSdrh         pTail->pDirty = pB;
743b982bfeaSdrh         break;
744b982bfeaSdrh       }
7458c0a791aSdanielk1977     }else{
7468c0a791aSdanielk1977       pTail->pDirty = pB;
7478c0a791aSdanielk1977       pTail = pB;
7488c0a791aSdanielk1977       pB = pB->pDirty;
749b982bfeaSdrh       if( pB==0 ){
7508c0a791aSdanielk1977         pTail->pDirty = pA;
751b982bfeaSdrh         break;
752b982bfeaSdrh       }
753b982bfeaSdrh     }
7548c0a791aSdanielk1977   }
7558c0a791aSdanielk1977   return result.pDirty;
7568c0a791aSdanielk1977 }
7578c0a791aSdanielk1977 
7588c0a791aSdanielk1977 /*
7598c0a791aSdanielk1977 ** Sort the list of pages in accending order by pgno.  Pages are
760bc2ca9ebSdanielk1977 ** connected by pDirty pointers.  The pDirtyPrev pointers are
7618c0a791aSdanielk1977 ** corrupted by this sort.
762e64ca7baSdrh **
763e64ca7baSdrh ** Since there cannot be more than 2^31 distinct pages in a database,
764e64ca7baSdrh ** there cannot be more than 31 buckets required by the merge sorter.
765e64ca7baSdrh ** One extra bucket is added to catch overflow in case something
766e64ca7baSdrh ** ever changes to make the previous sentence incorrect.
7678c0a791aSdanielk1977 */
768e64ca7baSdrh #define N_SORT_BUCKET  32
pcacheSortDirtyList(PgHdr * pIn)7698c0a791aSdanielk1977 static PgHdr *pcacheSortDirtyList(PgHdr *pIn){
770e64ca7baSdrh   PgHdr *a[N_SORT_BUCKET], *p;
7718c0a791aSdanielk1977   int i;
7728c0a791aSdanielk1977   memset(a, 0, sizeof(a));
7738c0a791aSdanielk1977   while( pIn ){
7748c0a791aSdanielk1977     p = pIn;
7758c0a791aSdanielk1977     pIn = p->pDirty;
7768c0a791aSdanielk1977     p->pDirty = 0;
777e64ca7baSdrh     for(i=0; ALWAYS(i<N_SORT_BUCKET-1); i++){
7788c0a791aSdanielk1977       if( a[i]==0 ){
7798c0a791aSdanielk1977         a[i] = p;
7808c0a791aSdanielk1977         break;
7818c0a791aSdanielk1977       }else{
7828c0a791aSdanielk1977         p = pcacheMergeDirtyList(a[i], p);
7838c0a791aSdanielk1977         a[i] = 0;
7848c0a791aSdanielk1977       }
7858c0a791aSdanielk1977     }
786e64ca7baSdrh     if( NEVER(i==N_SORT_BUCKET-1) ){
787e64ca7baSdrh       /* To get here, there need to be 2^(N_SORT_BUCKET) elements in
788e64ca7baSdrh       ** the input list.  But that is impossible.
7898c0a791aSdanielk1977       */
7908c0a791aSdanielk1977       a[i] = pcacheMergeDirtyList(a[i], p);
7918c0a791aSdanielk1977     }
7928c0a791aSdanielk1977   }
7938c0a791aSdanielk1977   p = a[0];
7948c0a791aSdanielk1977   for(i=1; i<N_SORT_BUCKET; i++){
795b982bfeaSdrh     if( a[i]==0 ) continue;
796b982bfeaSdrh     p = p ? pcacheMergeDirtyList(p, a[i]) : a[i];
7978c0a791aSdanielk1977   }
7988c0a791aSdanielk1977   return p;
7998c0a791aSdanielk1977 }
8008c0a791aSdanielk1977 
8018c0a791aSdanielk1977 /*
8028c0a791aSdanielk1977 ** Return a list of all dirty pages in the cache, sorted by page number.
8038c0a791aSdanielk1977 */
sqlite3PcacheDirtyList(PCache * pCache)8048c0a791aSdanielk1977 PgHdr *sqlite3PcacheDirtyList(PCache *pCache){
8058c0a791aSdanielk1977   PgHdr *p;
806bc2ca9ebSdanielk1977   for(p=pCache->pDirty; p; p=p->pDirtyNext){
807bc2ca9ebSdanielk1977     p->pDirty = p->pDirtyNext;
8088c0a791aSdanielk1977   }
8098c0a791aSdanielk1977   return pcacheSortDirtyList(pCache->pDirty);
8108c0a791aSdanielk1977 }
8118c0a791aSdanielk1977 
8128c0a791aSdanielk1977 /*
81395a0b371Sdrh ** Return the total number of references to all pages held by the cache.
81495a0b371Sdrh **
81595a0b371Sdrh ** This is not the total number of pages referenced, but the sum of the
81695a0b371Sdrh ** reference count for all pages.
8178c0a791aSdanielk1977 */
sqlite3PcacheRefCount(PCache * pCache)8188c0a791aSdanielk1977 int sqlite3PcacheRefCount(PCache *pCache){
81995a0b371Sdrh   return pCache->nRefSum;
8208c0a791aSdanielk1977 }
8218c0a791aSdanielk1977 
822bc2ca9ebSdanielk1977 /*
823bc2ca9ebSdanielk1977 ** Return the number of references to the page supplied as an argument.
824bc2ca9ebSdanielk1977 */
sqlite3PcachePageRefcount(PgHdr * p)82571d5d2cdSdanielk1977 int sqlite3PcachePageRefcount(PgHdr *p){
82671d5d2cdSdanielk1977   return p->nRef;
82771d5d2cdSdanielk1977 }
82871d5d2cdSdanielk1977 
8298c0a791aSdanielk1977 /*
8308c0a791aSdanielk1977 ** Return the total number of pages in the cache.
8318c0a791aSdanielk1977 */
sqlite3PcachePagecount(PCache * pCache)8328c0a791aSdanielk1977 int sqlite3PcachePagecount(PCache *pCache){
833c3031c61Sdrh   assert( pCache->pCache!=0 );
834c3031c61Sdrh   return sqlite3GlobalConfig.pcache2.xPagecount(pCache->pCache);
835a858aa2eSdanielk1977 }
8368c0a791aSdanielk1977 
837f3d3c27aSdanielk1977 #ifdef SQLITE_TEST
8388c0a791aSdanielk1977 /*
839bc2ca9ebSdanielk1977 ** Get the suggested cache-size value.
8408c0a791aSdanielk1977 */
sqlite3PcacheGetCachesize(PCache * pCache)8418c0a791aSdanielk1977 int sqlite3PcacheGetCachesize(PCache *pCache){
8423b42abb3Sdrh   return numberOfCachePages(pCache);
8438c0a791aSdanielk1977 }
844f3d3c27aSdanielk1977 #endif
8458c0a791aSdanielk1977 
8468c0a791aSdanielk1977 /*
8478c0a791aSdanielk1977 ** Set the suggested cache-size value.
8488c0a791aSdanielk1977 */
sqlite3PcacheSetCachesize(PCache * pCache,int mxPage)8498c0a791aSdanielk1977 void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
850c3031c61Sdrh   assert( pCache->pCache!=0 );
8513b42abb3Sdrh   pCache->szCache = mxPage;
8523b42abb3Sdrh   sqlite3GlobalConfig.pcache2.xCachesize(pCache->pCache,
8533b42abb3Sdrh                                          numberOfCachePages(pCache));
854bc2ca9ebSdanielk1977 }
8558c0a791aSdanielk1977 
85609419b4bSdrh /*
8579b0cf34fSdrh ** Set the suggested cache-spill value.  Make no changes if if the
8589b0cf34fSdrh ** argument is zero.  Return the effective cache-spill size, which will
8599b0cf34fSdrh ** be the larger of the szSpill and szCache.
8609b0cf34fSdrh */
sqlite3PcacheSetSpillsize(PCache * p,int mxPage)8619b0cf34fSdrh int sqlite3PcacheSetSpillsize(PCache *p, int mxPage){
8629b0cf34fSdrh   int res;
8639b0cf34fSdrh   assert( p->pCache!=0 );
8649b0cf34fSdrh   if( mxPage ){
8659b0cf34fSdrh     if( mxPage<0 ){
8664f9c8ec6Sdrh       mxPage = (int)((-1024*(i64)mxPage)/(p->szPage+p->szExtra));
8679b0cf34fSdrh     }
8689b0cf34fSdrh     p->szSpill = mxPage;
8699b0cf34fSdrh   }
8709b0cf34fSdrh   res = numberOfCachePages(p);
8719b0cf34fSdrh   if( res<p->szSpill ) res = p->szSpill;
8729b0cf34fSdrh   return res;
8739b0cf34fSdrh }
8749b0cf34fSdrh 
8759b0cf34fSdrh /*
87609419b4bSdrh ** Free up as much memory as possible from the page cache.
87709419b4bSdrh */
sqlite3PcacheShrink(PCache * pCache)87809419b4bSdrh void sqlite3PcacheShrink(PCache *pCache){
879c3031c61Sdrh   assert( pCache->pCache!=0 );
88009419b4bSdrh   sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache);
88109419b4bSdrh }
88209419b4bSdrh 
883def6889dSdrh /*
884def6889dSdrh ** Return the size of the header added by this middleware layer
885def6889dSdrh ** in the page-cache hierarchy.
886def6889dSdrh */
sqlite3HeaderSizePcache(void)88737c057b8Sdrh int sqlite3HeaderSizePcache(void){ return ROUND8(sizeof(PgHdr)); }
888def6889dSdrh 
8890f52455aSdan /*
8900f52455aSdan ** Return the number of dirty pages currently in the cache, as a percentage
8910f52455aSdan ** of the configured cache size.
8920f52455aSdan */
sqlite3PCachePercentDirty(PCache * pCache)8930f52455aSdan int sqlite3PCachePercentDirty(PCache *pCache){
8940f52455aSdan   PgHdr *pDirty;
8950f52455aSdan   int nDirty = 0;
8960f52455aSdan   int nCache = numberOfCachePages(pCache);
8970f52455aSdan   for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext) nDirty++;
898b5895e50Sdrh   return nCache ? (int)(((i64)nDirty * 100) / nCache) : 0;
8990f52455aSdan }
900def6889dSdrh 
90109236755Sdan #ifdef SQLITE_DIRECT_OVERFLOW_READ
90209236755Sdan /*
90309236755Sdan ** Return true if there are one or more dirty pages in the cache. Else false.
90409236755Sdan */
sqlite3PCacheIsDirty(PCache * pCache)90509236755Sdan int sqlite3PCacheIsDirty(PCache *pCache){
90609236755Sdan   return (pCache->pDirty!=0);
90709236755Sdan }
90809236755Sdan #endif
90909236755Sdan 
910750e87dfSdanielk1977 #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
91167e3da7aSdanielk1977 /*
912bc2ca9ebSdanielk1977 ** For all dirty pages currently in the cache, invoke the specified
913bc2ca9ebSdanielk1977 ** callback. This is only used if the SQLITE_CHECK_PAGES macro is
914bc2ca9ebSdanielk1977 ** defined.
91567e3da7aSdanielk1977 */
sqlite3PcacheIterateDirty(PCache * pCache,void (* xIter)(PgHdr *))916bc2ca9ebSdanielk1977 void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)){
917bc2ca9ebSdanielk1977   PgHdr *pDirty;
918bc2ca9ebSdanielk1977   for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext){
919bc2ca9ebSdanielk1977     xIter(pDirty);
92067e3da7aSdanielk1977   }
921062d4cb0Sdanielk1977 }
922062d4cb0Sdanielk1977 #endif
923