blob: b513e275c14679dba336a32e4a42128f7f72af09 [file] [log] [blame]
danielk19778c0a7912008-08-20 14:49:23 +00001/*
2** 2008 August 05
3**
4** The author disclaims copyright to this source code. In place of
5** a legal notice, here is a blessing:
6**
7** May you do good and not evil.
8** May you find forgiveness for yourself and forgive others.
9** May you share freely, never taking more than you give.
10**
11*************************************************************************
12** This file implements that page cache.
13**
drh3d4501e2008-12-04 20:40:10 +000014** @(#) $Id: pcache.c,v 1.39 2008/12/04 20:40:10 drh Exp $
danielk19778c0a7912008-08-20 14:49:23 +000015*/
16#include "sqliteInt.h"
17
18/*
19** A complete page cache is an instance of this structure.
20*/
21struct PCache {
danielk1977d491e1b2008-08-26 18:05:48 +000022 PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */
23 PgHdr *pSynced; /* Last synced page in dirty page list */
danielk1977bc2ca9e2008-11-13 14:28:28 +000024 int nRef; /* Number of referenced pages */
drha85f7e32008-08-28 02:26:07 +000025 int nMax; /* Configured cache size */
26 int nMin; /* Configured minimum cache size */
drha85f7e32008-08-28 02:26:07 +000027 int szPage; /* Size of every page in this cache */
28 int szExtra; /* Size of extra space for each page */
29 int bPurgeable; /* True if pages are on backing store */
drha85f7e32008-08-28 02:26:07 +000030 int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */
31 void *pStress; /* Argument to xStress */
danielk1977bc2ca9e2008-11-13 14:28:28 +000032 sqlite3_pcache *pCache; /* Pluggable cache module */
33 PgHdr *pPage1;
danielk19778c0a7912008-08-20 14:49:23 +000034};
35
36/*
drha85f7e32008-08-28 02:26:07 +000037** Some of the assert() macros in this code are too expensive to run
38** even during normal debugging. Use them only rarely on long-running
39** tests. Enable the expensive asserts using the
40** -DSQLITE_ENABLE_EXPENSIVE_ASSERT=1 compile-time option.
41*/
42#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
43# define expensive_assert(X) assert(X)
44#else
45# define expensive_assert(X)
46#endif
danielk19778c0a7912008-08-20 14:49:23 +000047
danielk19778c0a7912008-08-20 14:49:23 +000048/********************************** Linked List Management ********************/
49
drha85f7e32008-08-28 02:26:07 +000050#if !defined(NDEBUG) && defined(SQLITE_ENABLE_EXPENSIVE_ASSERT)
drh41d30272008-08-20 21:47:45 +000051/*
danielk1977d491e1b2008-08-26 18:05:48 +000052** Check that the pCache->pSynced variable is set correctly. If it
53** is not, either fail an assert or return zero. Otherwise, return
54** non-zero. This is only used in debugging builds, as follows:
55**
drha85f7e32008-08-28 02:26:07 +000056** expensive_assert( pcacheCheckSynced(pCache) );
danielk1977d491e1b2008-08-26 18:05:48 +000057*/
58static int pcacheCheckSynced(PCache *pCache){
danielk1977bc2ca9e2008-11-13 14:28:28 +000059 PgHdr *p;
60 for(p=pCache->pDirtyTail; p!=pCache->pSynced; p=p->pDirtyPrev){
danielk1977d491e1b2008-08-26 18:05:48 +000061 assert( p->nRef || (p->flags&PGHDR_NEED_SYNC) );
62 }
63 return (p==0 || p->nRef || (p->flags&PGHDR_NEED_SYNC)==0);
64}
drha85f7e32008-08-28 02:26:07 +000065#endif /* !NDEBUG && SQLITE_ENABLE_EXPENSIVE_ASSERT */
danielk1977d491e1b2008-08-26 18:05:48 +000066
danielk19778c0a7912008-08-20 14:49:23 +000067/*
danielk1977bc2ca9e2008-11-13 14:28:28 +000068** Remove page pPage from the list of dirty pages.
danielk19778c0a7912008-08-20 14:49:23 +000069*/
danielk1977bc2ca9e2008-11-13 14:28:28 +000070static void pcacheRemoveFromDirtyList(PgHdr *pPage){
71 PCache *p = pPage->pCache;
danielk19778c0a7912008-08-20 14:49:23 +000072
danielk1977bc2ca9e2008-11-13 14:28:28 +000073 assert( pPage->pDirtyNext || pPage==p->pDirtyTail );
74 assert( pPage->pDirtyPrev || pPage==p->pDirty );
danielk19778c0a7912008-08-20 14:49:23 +000075
danielk1977bc2ca9e2008-11-13 14:28:28 +000076 /* Update the PCache1.pSynced variable if necessary. */
77 if( p->pSynced==pPage ){
78 PgHdr *pSynced = pPage->pDirtyPrev;
79 while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){
80 pSynced = pSynced->pDirtyPrev;
danielk1977d491e1b2008-08-26 18:05:48 +000081 }
danielk1977bc2ca9e2008-11-13 14:28:28 +000082 p->pSynced = pSynced;
danielk1977d491e1b2008-08-26 18:05:48 +000083 }
danielk19778c0a7912008-08-20 14:49:23 +000084
danielk1977bc2ca9e2008-11-13 14:28:28 +000085 if( pPage->pDirtyNext ){
86 pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev;
danielk19778c0a7912008-08-20 14:49:23 +000087 }else{
danielk1977bc2ca9e2008-11-13 14:28:28 +000088 assert( pPage==p->pDirtyTail );
89 p->pDirtyTail = pPage->pDirtyPrev;
danielk19778c0a7912008-08-20 14:49:23 +000090 }
danielk1977bc2ca9e2008-11-13 14:28:28 +000091 if( pPage->pDirtyPrev ){
92 pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext;
danielk19778c0a7912008-08-20 14:49:23 +000093 }else{
danielk1977bc2ca9e2008-11-13 14:28:28 +000094 assert( pPage==p->pDirty );
95 p->pDirty = pPage->pDirtyNext;
danielk19778c0a7912008-08-20 14:49:23 +000096 }
danielk1977bc2ca9e2008-11-13 14:28:28 +000097 pPage->pDirtyNext = 0;
98 pPage->pDirtyPrev = 0;
99
100 expensive_assert( pcacheCheckSynced(p) );
danielk19778c0a7912008-08-20 14:49:23 +0000101}
102
103/*
danielk1977bc2ca9e2008-11-13 14:28:28 +0000104** Add page pPage to the head of the dirty list (PCache1.pDirty is set to
105** pPage).
danielk19778c0a7912008-08-20 14:49:23 +0000106*/
danielk1977bc2ca9e2008-11-13 14:28:28 +0000107static void pcacheAddToDirtyList(PgHdr *pPage){
108 PCache *p = pPage->pCache;
danielk19778c0a7912008-08-20 14:49:23 +0000109
danielk1977bc2ca9e2008-11-13 14:28:28 +0000110 assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage );
111
112 pPage->pDirtyNext = p->pDirty;
113 if( pPage->pDirtyNext ){
114 assert( pPage->pDirtyNext->pDirtyPrev==0 );
115 pPage->pDirtyNext->pDirtyPrev = pPage;
danielk19778c0a7912008-08-20 14:49:23 +0000116 }
danielk1977bc2ca9e2008-11-13 14:28:28 +0000117 p->pDirty = pPage;
118 if( !p->pDirtyTail ){
119 p->pDirtyTail = pPage;
120 }
121 if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){
122 p->pSynced = pPage;
123 }
124 expensive_assert( pcacheCheckSynced(p) );
danielk19778c0a7912008-08-20 14:49:23 +0000125}
126
127/*
danielk1977bc2ca9e2008-11-13 14:28:28 +0000128** Wrapper around the pluggable caches xUnpin method. If the cache is
129** being used for an in-memory database, this function is a no-op.
danielk19778c0a7912008-08-20 14:49:23 +0000130*/
danielk1977bc2ca9e2008-11-13 14:28:28 +0000131static void pcacheUnpin(PgHdr *p){
132 PCache *pCache = p->pCache;
danielk1977801880f2008-08-21 15:54:01 +0000133 if( pCache->bPurgeable ){
danielk1977bc2ca9e2008-11-13 14:28:28 +0000134 if( p->pgno==1 ){
135 pCache->pPage1 = 0;
danielk1977d491e1b2008-08-26 18:05:48 +0000136 }
danielk1977bc2ca9e2008-11-13 14:28:28 +0000137 sqlite3GlobalConfig.pcache.xUnpin(pCache->pCache, p, 0);
danielk19778c0a7912008-08-20 14:49:23 +0000138 }
danielk19778c0a7912008-08-20 14:49:23 +0000139}
140
141/*************************************************** General Interfaces ******
142**
143** Initialize and shutdown the page cache subsystem. Neither of these
144** functions are threadsafe.
145*/
146int sqlite3PcacheInitialize(void){
danielk1977bc2ca9e2008-11-13 14:28:28 +0000147 if( sqlite3GlobalConfig.pcache.xInit==0 ){
148 sqlite3PCacheSetDefault();
danielk19778c0a7912008-08-20 14:49:23 +0000149 }
danielk1977bc2ca9e2008-11-13 14:28:28 +0000150 return sqlite3GlobalConfig.pcache.xInit(sqlite3GlobalConfig.pcache.pArg);
danielk19778c0a7912008-08-20 14:49:23 +0000151}
152void sqlite3PcacheShutdown(void){
danielk1977bc2ca9e2008-11-13 14:28:28 +0000153 if( sqlite3GlobalConfig.pcache.xShutdown ){
154 sqlite3GlobalConfig.pcache.xShutdown(sqlite3GlobalConfig.pcache.pArg);
155 }
danielk19778c0a7912008-08-20 14:49:23 +0000156}
157
158/*
159** Return the size in bytes of a PCache object.
160*/
161int sqlite3PcacheSize(void){ return sizeof(PCache); }
162
163/*
danielk1977bc2ca9e2008-11-13 14:28:28 +0000164** Create a new PCache object. Storage space to hold the object
165** has already been allocated and is passed in as the p pointer.
166** The caller discovers how much space needs to be allocated by
167** calling sqlite3PcacheSize().
danielk19778c0a7912008-08-20 14:49:23 +0000168*/
169void sqlite3PcacheOpen(
170 int szPage, /* Size of every page */
171 int szExtra, /* Extra space associated with each page */
172 int bPurgeable, /* True if pages are on backing store */
danielk1977a858aa22008-08-22 16:22:17 +0000173 int (*xStress)(void*,PgHdr*),/* Call to try to make pages clean */
danielk19778c0a7912008-08-20 14:49:23 +0000174 void *pStress, /* Argument to xStress */
175 PCache *p /* Preallocated space for the PCache */
176){
danielk19778c0a7912008-08-20 14:49:23 +0000177 memset(p, 0, sizeof(PCache));
178 p->szPage = szPage;
179 p->szExtra = szExtra;
180 p->bPurgeable = bPurgeable;
danielk19778c0a7912008-08-20 14:49:23 +0000181 p->xStress = xStress;
182 p->pStress = pStress;
183 p->nMax = 100;
danielk1977468c82b2008-08-27 16:38:56 +0000184 p->nMin = 10;
danielk19778c0a7912008-08-20 14:49:23 +0000185}
186
drh41d30272008-08-20 21:47:45 +0000187/*
danielk1977bc2ca9e2008-11-13 14:28:28 +0000188** Change the page size for PCache object. The caller must ensure that there
189** are no outstanding page references when this function is called.
drh41d30272008-08-20 21:47:45 +0000190*/
danielk19778c0a7912008-08-20 14:49:23 +0000191void sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
danielk1977bc2ca9e2008-11-13 14:28:28 +0000192 assert( pCache->nRef==0 && pCache->pDirty==0 );
193 if( pCache->pCache ){
194 sqlite3GlobalConfig.pcache.xDestroy(pCache->pCache);
195 pCache->pCache = 0;
196 }
danielk19778c0a7912008-08-20 14:49:23 +0000197 pCache->szPage = szPage;
198}
199
200/*
201** Try to obtain a page from the cache.
202*/
203int sqlite3PcacheFetch(
204 PCache *pCache, /* Obtain the page from this cache */
205 Pgno pgno, /* Page number to obtain */
206 int createFlag, /* If true, create page if it does not exist already */
207 PgHdr **ppPage /* Write the page here */
208){
danielk1977f599a192008-08-28 10:21:16 +0000209 PgHdr *pPage = 0;
danielk1977bc2ca9e2008-11-13 14:28:28 +0000210 int eCreate;
danielk1977f599a192008-08-28 10:21:16 +0000211
danielk19778c0a7912008-08-20 14:49:23 +0000212 assert( pCache!=0 );
213 assert( pgno>0 );
danielk19778c0a7912008-08-20 14:49:23 +0000214
danielk1977bc2ca9e2008-11-13 14:28:28 +0000215 /* If the pluggable cache (sqlite3_pcache*) has not been allocated,
216 ** allocate it now.
217 */
218 if( !pCache->pCache && createFlag ){
219 sqlite3_pcache *p;
220 int nByte;
221 nByte = pCache->szPage + pCache->szExtra + sizeof(PgHdr);
222 p = sqlite3GlobalConfig.pcache.xCreate(nByte, pCache->bPurgeable);
223 if( !p ){
224 return SQLITE_NOMEM;
225 }
226 sqlite3GlobalConfig.pcache.xCachesize(p, pCache->nMax);
227 pCache->pCache = p;
228 }
danielk1977f599a192008-08-28 10:21:16 +0000229
danielk1977bc2ca9e2008-11-13 14:28:28 +0000230 eCreate = createFlag ? 1 : 0;
231 if( eCreate && (!pCache->bPurgeable || !pCache->pDirty) ){
232 eCreate = 2;
233 }
234 if( pCache->pCache ){
235 pPage = sqlite3GlobalConfig.pcache.xFetch(pCache->pCache, pgno, eCreate);
236 }
237
238 if( !pPage && eCreate==1 ){
239 PgHdr *pPg;
240
241 /* Find a dirty page to write-out and recycle. First try to find a
242 ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
243 ** cleared), but if that is not possible settle for any other
244 ** unreferenced dirty page.
245 */
246 expensive_assert( pcacheCheckSynced(pCache) );
247 for(pPg=pCache->pSynced;
248 pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC));
249 pPg=pPg->pDirtyPrev
250 );
251 if( !pPg ){
252 for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev);
253 }
254 if( pPg ){
255 int rc;
256 rc = pCache->xStress(pCache->pStress, pPg);
257 if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
258 return rc;
danielk19778c0a7912008-08-20 14:49:23 +0000259 }
260 }
danielk1977bc2ca9e2008-11-13 14:28:28 +0000261
262 pPage = sqlite3GlobalConfig.pcache.xFetch(pCache->pCache, pgno, 2);
danielk19778c0a7912008-08-20 14:49:23 +0000263 }
264
danielk1977bc2ca9e2008-11-13 14:28:28 +0000265 if( pPage ){
266 if( 0==pPage->nRef ){
danielk1977f599a192008-08-28 10:21:16 +0000267 pCache->nRef++;
danielk1977bc2ca9e2008-11-13 14:28:28 +0000268 }
269 pPage->nRef++;
270 pPage->pData = (void*)&pPage[1];
271 pPage->pExtra = (void*)&((char*)pPage->pData)[pCache->szPage];
272 pPage->pCache = pCache;
273 pPage->pgno = pgno;
274 if( pgno==1 ){
275 pCache->pPage1 = pPage;
danielk1977f599a192008-08-28 10:21:16 +0000276 }
danielk19778c0a7912008-08-20 14:49:23 +0000277 }
danielk1977f599a192008-08-28 10:21:16 +0000278 *ppPage = pPage;
danielk1977bc2ca9e2008-11-13 14:28:28 +0000279 return (pPage==0 && eCreate) ? SQLITE_NOMEM : SQLITE_OK;
danielk19778c0a7912008-08-20 14:49:23 +0000280}
281
282/*
danielk1977bc2ca9e2008-11-13 14:28:28 +0000283** Decrement the reference count on a page. If the page is clean and the
284** reference count drops to 0, then it is made elible for recycling.
danielk19778c0a7912008-08-20 14:49:23 +0000285*/
286void sqlite3PcacheRelease(PgHdr *p){
287 assert( p->nRef>0 );
danielk1977502b7432008-08-25 14:49:42 +0000288 p->nRef--;
289 if( p->nRef==0 ){
290 PCache *pCache = p->pCache;
danielk1977d491e1b2008-08-26 18:05:48 +0000291 pCache->nRef--;
292 if( (p->flags&PGHDR_DIRTY)==0 ){
danielk1977bc2ca9e2008-11-13 14:28:28 +0000293 pcacheUnpin(p);
danielk1977d491e1b2008-08-26 18:05:48 +0000294 }else{
danielk1977bc2ca9e2008-11-13 14:28:28 +0000295 /* Move the page to the head of the dirty list. */
296 pcacheRemoveFromDirtyList(p);
297 pcacheAddToDirtyList(p);
danielk1977d491e1b2008-08-26 18:05:48 +0000298 }
danielk1977502b7432008-08-25 14:49:42 +0000299 }
danielk19778c0a7912008-08-20 14:49:23 +0000300}
301
danielk1977bc2ca9e2008-11-13 14:28:28 +0000302/*
303** Increase the reference count of a supplied page by 1.
304*/
danielk19778c0a7912008-08-20 14:49:23 +0000305void sqlite3PcacheRef(PgHdr *p){
danielk1977502b7432008-08-25 14:49:42 +0000306 assert(p->nRef>0);
307 p->nRef++;
danielk19778c0a7912008-08-20 14:49:23 +0000308}
309
310/*
danielk19774abdfa42008-08-27 09:44:39 +0000311** Drop a page from the cache. There must be exactly one reference to the
312** page. This function deletes that reference, so after it returns the
313** page pointed to by p is invalid.
danielk19778c0a7912008-08-20 14:49:23 +0000314*/
315void sqlite3PcacheDrop(PgHdr *p){
316 PCache *pCache;
danielk19778c0a7912008-08-20 14:49:23 +0000317 assert( p->nRef==1 );
danielk1977bc2ca9e2008-11-13 14:28:28 +0000318 if( p->flags&PGHDR_DIRTY ){
319 pcacheRemoveFromDirtyList(p);
320 }
danielk19778c0a7912008-08-20 14:49:23 +0000321 pCache = p->pCache;
322 pCache->nRef--;
danielk1977bc2ca9e2008-11-13 14:28:28 +0000323 if( p->pgno==1 ){
324 pCache->pPage1 = 0;
325 }
326 sqlite3GlobalConfig.pcache.xUnpin(pCache->pCache, p, 1);
danielk19778c0a7912008-08-20 14:49:23 +0000327}
328
329/*
danielk1977bc2ca9e2008-11-13 14:28:28 +0000330** Make sure the page is marked as dirty. If it isn't dirty already,
danielk19778c0a7912008-08-20 14:49:23 +0000331** make it so.
332*/
333void sqlite3PcacheMakeDirty(PgHdr *p){
334 PCache *pCache;
danielk197733e32162008-08-23 18:53:08 +0000335 p->flags &= ~PGHDR_DONT_WRITE;
danielk19778c0a7912008-08-20 14:49:23 +0000336 assert( p->nRef>0 );
danielk1977bc2ca9e2008-11-13 14:28:28 +0000337 if( 0==(p->flags & PGHDR_DIRTY) ){
338 pCache = p->pCache;
339 p->flags |= PGHDR_DIRTY;
340 pcacheAddToDirtyList( p);
danielk1977d491e1b2008-08-26 18:05:48 +0000341 }
danielk1977f599a192008-08-28 10:21:16 +0000342}
343
344/*
danielk1977bc2ca9e2008-11-13 14:28:28 +0000345** Make sure the page is marked as clean. If it isn't clean already,
danielk1977f599a192008-08-28 10:21:16 +0000346** make it so.
347*/
348void sqlite3PcacheMakeClean(PgHdr *p){
349 if( (p->flags & PGHDR_DIRTY) ){
danielk1977bc2ca9e2008-11-13 14:28:28 +0000350 pcacheRemoveFromDirtyList(p);
351 p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC);
352 if( p->nRef==0 ){
353 pcacheUnpin(p);
354 }
danielk1977f599a192008-08-28 10:21:16 +0000355 }
danielk19778c0a7912008-08-20 14:49:23 +0000356}
357
358/*
359** Make every page in the cache clean.
360*/
361void sqlite3PcacheCleanAll(PCache *pCache){
362 PgHdr *p;
danielk19778c0a7912008-08-20 14:49:23 +0000363 while( (p = pCache->pDirty)!=0 ){
danielk1977bc2ca9e2008-11-13 14:28:28 +0000364 sqlite3PcacheMakeClean(p);
danielk19778c0a7912008-08-20 14:49:23 +0000365 }
366}
367
368/*
danielk1977bc2ca9e2008-11-13 14:28:28 +0000369** Clear the PGHDR_NEED_SYNC flag from all dirty pages.
370*/
371void sqlite3PcacheClearSyncFlags(PCache *pCache){
372 PgHdr *p;
373 for(p=pCache->pDirty; p; p=p->pDirtyNext){
374 p->flags &= ~PGHDR_NEED_SYNC;
375 }
376 pCache->pSynced = pCache->pDirtyTail;
377}
378
379/*
380** Change the page number of page p to newPgno.
danielk19778c0a7912008-08-20 14:49:23 +0000381*/
382void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
danielk1977bc2ca9e2008-11-13 14:28:28 +0000383 PCache *pCache = p->pCache;
danielk1977d491e1b2008-08-26 18:05:48 +0000384 assert( p->nRef>0 );
danielk1977bc2ca9e2008-11-13 14:28:28 +0000385 assert( newPgno>0 );
386 sqlite3GlobalConfig.pcache.xRekey(pCache->pCache, p, p->pgno, newPgno);
danielk19778c0a7912008-08-20 14:49:23 +0000387 p->pgno = newPgno;
danielk1977bc2ca9e2008-11-13 14:28:28 +0000388 if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
389 pcacheRemoveFromDirtyList(p);
390 pcacheAddToDirtyList(p);
danielk19778c0a7912008-08-20 14:49:23 +0000391 }
danielk19778c0a7912008-08-20 14:49:23 +0000392}
393
394/*
danielk1977bc2ca9e2008-11-13 14:28:28 +0000395** Drop every cache entry whose page number is greater than "pgno". The
396** caller must ensure that there are no outstanding references to any pages
397** other than page 1 with a page number greater than pgno.
398**
399** If there is a reference to page 1 and the pgno parameter passed to this
400** function is 0, then the data area associated with page 1 is zeroed, but
401** the page object is not dropped.
danielk19778c0a7912008-08-20 14:49:23 +0000402*/
403void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
danielk1977bc2ca9e2008-11-13 14:28:28 +0000404 if( pCache->pCache ){
405 PgHdr *p;
406 PgHdr *pNext;
407 for(p=pCache->pDirty; p; p=pNext){
408 pNext = p->pDirtyNext;
409 if( p->pgno>pgno ){
410 assert( p->flags&PGHDR_DIRTY );
411 sqlite3PcacheMakeClean(p);
danielk19778c0a7912008-08-20 14:49:23 +0000412 }
413 }
danielk1977bc2ca9e2008-11-13 14:28:28 +0000414 if( pgno==0 && pCache->pPage1 ){
415 memset(pCache->pPage1->pData, 0, pCache->szPage);
416 pgno = 1;
417 }
418 sqlite3GlobalConfig.pcache.xTruncate(pCache->pCache, pgno+1);
danielk1977062d4cb2008-08-29 09:10:02 +0000419 }
420}
danielk19778c0a7912008-08-20 14:49:23 +0000421
422/*
423** Close a cache.
424*/
425void sqlite3PcacheClose(PCache *pCache){
danielk1977bc2ca9e2008-11-13 14:28:28 +0000426 if( pCache->pCache ){
427 sqlite3GlobalConfig.pcache.xDestroy(pCache->pCache);
danielk19778c0a7912008-08-20 14:49:23 +0000428 }
429}
430
431/*
432** Discard the contents of the cache.
433*/
434int sqlite3PcacheClear(PCache *pCache){
danielk1977bc2ca9e2008-11-13 14:28:28 +0000435 sqlite3PcacheTruncate(pCache, 0);
danielk19778c0a7912008-08-20 14:49:23 +0000436 return SQLITE_OK;
437}
438
439/*
440** Merge two lists of pages connected by pDirty and in pgno order.
danielk1977bc2ca9e2008-11-13 14:28:28 +0000441** Do not both fixing the pDirtyPrev pointers.
danielk19778c0a7912008-08-20 14:49:23 +0000442*/
443static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){
444 PgHdr result, *pTail;
445 pTail = &result;
446 while( pA && pB ){
447 if( pA->pgno<pB->pgno ){
448 pTail->pDirty = pA;
449 pTail = pA;
450 pA = pA->pDirty;
451 }else{
452 pTail->pDirty = pB;
453 pTail = pB;
454 pB = pB->pDirty;
455 }
456 }
457 if( pA ){
458 pTail->pDirty = pA;
459 }else if( pB ){
460 pTail->pDirty = pB;
461 }else{
462 pTail->pDirty = 0;
463 }
464 return result.pDirty;
465}
466
467/*
468** Sort the list of pages in accending order by pgno. Pages are
danielk1977bc2ca9e2008-11-13 14:28:28 +0000469** connected by pDirty pointers. The pDirtyPrev pointers are
danielk19778c0a7912008-08-20 14:49:23 +0000470** corrupted by this sort.
471*/
472#define N_SORT_BUCKET_ALLOC 25
473#define N_SORT_BUCKET 25
474#ifdef SQLITE_TEST
475 int sqlite3_pager_n_sort_bucket = 0;
476 #undef N_SORT_BUCKET
477 #define N_SORT_BUCKET \
478 (sqlite3_pager_n_sort_bucket?sqlite3_pager_n_sort_bucket:N_SORT_BUCKET_ALLOC)
479#endif
480static PgHdr *pcacheSortDirtyList(PgHdr *pIn){
481 PgHdr *a[N_SORT_BUCKET_ALLOC], *p;
482 int i;
483 memset(a, 0, sizeof(a));
484 while( pIn ){
485 p = pIn;
486 pIn = p->pDirty;
487 p->pDirty = 0;
488 for(i=0; i<N_SORT_BUCKET-1; i++){
489 if( a[i]==0 ){
490 a[i] = p;
491 break;
492 }else{
493 p = pcacheMergeDirtyList(a[i], p);
494 a[i] = 0;
495 }
496 }
497 if( i==N_SORT_BUCKET-1 ){
498 /* Coverage: To get here, there need to be 2^(N_SORT_BUCKET)
499 ** elements in the input list. This is possible, but impractical.
500 ** Testing this line is the point of global variable
501 ** sqlite3_pager_n_sort_bucket.
502 */
503 a[i] = pcacheMergeDirtyList(a[i], p);
504 }
505 }
506 p = a[0];
507 for(i=1; i<N_SORT_BUCKET; i++){
508 p = pcacheMergeDirtyList(p, a[i]);
509 }
510 return p;
511}
512
513/*
514** Return a list of all dirty pages in the cache, sorted by page number.
515*/
516PgHdr *sqlite3PcacheDirtyList(PCache *pCache){
517 PgHdr *p;
danielk1977bc2ca9e2008-11-13 14:28:28 +0000518 for(p=pCache->pDirty; p; p=p->pDirtyNext){
519 p->pDirty = p->pDirtyNext;
danielk19778c0a7912008-08-20 14:49:23 +0000520 }
521 return pcacheSortDirtyList(pCache->pDirty);
522}
523
danielk19778c0a7912008-08-20 14:49:23 +0000524/*
danielk1977bc2ca9e2008-11-13 14:28:28 +0000525** Return the total number of referenced pages held by the cache.
danielk19778c0a7912008-08-20 14:49:23 +0000526*/
527int sqlite3PcacheRefCount(PCache *pCache){
528 return pCache->nRef;
529}
530
danielk1977bc2ca9e2008-11-13 14:28:28 +0000531/*
532** Return the number of references to the page supplied as an argument.
533*/
danielk197771d5d2c2008-09-29 11:49:47 +0000534int sqlite3PcachePageRefcount(PgHdr *p){
535 return p->nRef;
536}
537
danielk19778c0a7912008-08-20 14:49:23 +0000538/*
539** Return the total number of pages in the cache.
540*/
541int sqlite3PcachePagecount(PCache *pCache){
danielk1977bc2ca9e2008-11-13 14:28:28 +0000542 int nPage = 0;
543 if( pCache->pCache ){
544 nPage = sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache);
danielk19778c0a7912008-08-20 14:49:23 +0000545 }
danielk1977bc2ca9e2008-11-13 14:28:28 +0000546 return nPage;
danielk19778c0a7912008-08-20 14:49:23 +0000547}
548
danielk1977f3d3c272008-11-19 16:52:44 +0000549#ifdef SQLITE_TEST
danielk19778c0a7912008-08-20 14:49:23 +0000550/*
danielk1977bc2ca9e2008-11-13 14:28:28 +0000551** Get the suggested cache-size value.
danielk19778c0a7912008-08-20 14:49:23 +0000552*/
553int sqlite3PcacheGetCachesize(PCache *pCache){
554 return pCache->nMax;
555}
danielk1977f3d3c272008-11-19 16:52:44 +0000556#endif
danielk19778c0a7912008-08-20 14:49:23 +0000557
558/*
559** Set the suggested cache-size value.
560*/
561void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
danielk19778c0a7912008-08-20 14:49:23 +0000562 pCache->nMax = mxPage;
danielk1977bc2ca9e2008-11-13 14:28:28 +0000563 if( pCache->pCache ){
564 sqlite3GlobalConfig.pcache.xCachesize(pCache->pCache, mxPage);
565 }
danielk19778c0a7912008-08-20 14:49:23 +0000566}
567
danielk1977bc2ca9e2008-11-13 14:28:28 +0000568#ifdef SQLITE_CHECK_PAGES
danielk197767e3da72008-08-21 12:19:44 +0000569/*
danielk1977bc2ca9e2008-11-13 14:28:28 +0000570** For all dirty pages currently in the cache, invoke the specified
571** callback. This is only used if the SQLITE_CHECK_PAGES macro is
572** defined.
danielk197767e3da72008-08-21 12:19:44 +0000573*/
danielk1977bc2ca9e2008-11-13 14:28:28 +0000574void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)){
575 PgHdr *pDirty;
576 for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext){
577 xIter(pDirty);
danielk197767e3da72008-08-21 12:19:44 +0000578 }
danielk1977062d4cb2008-08-29 09:10:02 +0000579}
580#endif