|
1 /* |
|
2 ** 2008 August 05 |
|
3 ** |
|
4 ** The author disclaims copyright to this source code. In place of |
|
5 ** a legal notice, here is a blessing: |
|
6 ** |
|
7 ** May you do good and not evil. |
|
8 ** May you find forgiveness for yourself and forgive others. |
|
9 ** May you share freely, never taking more than you give. |
|
10 ** |
|
11 ************************************************************************* |
|
12 ** This file implements that page cache. |
|
13 ** |
|
14 ** @(#) $Id: pcache.c,v 1.33 2008/09/29 11:49:48 danielk1977 Exp $ |
|
15 */ |
|
16 #include "sqliteInt.h" |
|
17 |
|
18 /* |
|
19 ** A complete page cache is an instance of this structure. |
|
20 ** |
|
21 ** A cache may only be deleted by its owner and while holding the |
|
22 ** SQLITE_MUTEX_STATUS_LRU mutex. |
|
23 */ |
|
24 struct PCache { |
|
25 /********************************************************************* |
|
26 ** The first group of elements may be read or written at any time by |
|
27 ** the cache owner without holding the mutex. No thread other than the |
|
28 ** cache owner is permitted to access these elements at any time. |
|
29 */ |
|
30 PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */ |
|
31 PgHdr *pSynced; /* Last synced page in dirty page list */ |
|
32 int nRef; /* Number of pinned pages */ |
|
33 int nPinned; /* Number of pinned and/or dirty pages */ |
|
34 int nMax; /* Configured cache size */ |
|
35 int nMin; /* Configured minimum cache size */ |
|
36 /********************************************************************** |
|
37 ** The next group of elements are fixed when the cache is created and |
|
38 ** may not be changed afterwards. These elements can read at any time by |
|
39 ** the cache owner or by any thread holding the the mutex. Non-owner |
|
40 ** threads must hold the mutex when reading these elements to prevent |
|
41 ** the entire PCache object from being deleted during the read. |
|
42 */ |
|
43 int szPage; /* Size of every page in this cache */ |
|
44 int szExtra; /* Size of extra space for each page */ |
|
45 int bPurgeable; /* True if pages are on backing store */ |
|
46 int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */ |
|
47 void *pStress; /* Argument to xStress */ |
|
48 /********************************************************************** |
|
49 ** The final group of elements can only be accessed while holding the |
|
50 ** mutex. Both the cache owner and any other thread must hold the mutex |
|
51 ** to read or write any of these elements. |
|
52 */ |
|
53 int nPage; /* Total number of pages in apHash */ |
|
54 int nHash; /* Number of slots in apHash[] */ |
|
55 PgHdr **apHash; /* Hash table for fast lookup by pgno */ |
|
56 PgHdr *pClean; /* List of clean pages in use */ |
|
57 }; |
|
58 |
|
59 /* |
|
60 ** Free slots in the page block allocator |
|
61 */ |
|
62 typedef struct PgFreeslot PgFreeslot; |
|
63 struct PgFreeslot { |
|
64 PgFreeslot *pNext; /* Next free slot */ |
|
65 }; |
|
66 |
|
67 /* |
|
68 ** Global data for the page cache. |
|
69 */ |
|
70 static SQLITE_WSD struct PCacheGlobal { |
|
71 int isInit; /* True when initialized */ |
|
72 sqlite3_mutex *mutex; /* static mutex MUTEX_STATIC_LRU */ |
|
73 |
|
74 int nMaxPage; /* Sum of nMaxPage for purgeable caches */ |
|
75 int nMinPage; /* Sum of nMinPage for purgeable caches */ |
|
76 int nCurrentPage; /* Number of purgeable pages allocated */ |
|
77 PgHdr *pLruHead, *pLruTail; /* LRU list of unused clean pgs */ |
|
78 |
|
79 /* Variables related to SQLITE_CONFIG_PAGECACHE settings. */ |
|
80 int szSlot; /* Size of each free slot */ |
|
81 void *pStart, *pEnd; /* Bounds of pagecache malloc range */ |
|
82 PgFreeslot *pFree; /* Free page blocks */ |
|
83 } pcache = {0}; |
|
84 |
|
85 /* |
|
86 ** All code in this file should access the global pcache structure via the |
|
87 ** alias "pcache_g". This ensures that the WSD emulation is used when |
|
88 ** compiling for systems that do not support real WSD. |
|
89 */ |
|
90 #define pcache_g (GLOBAL(struct PCacheGlobal, pcache)) |
|
91 |
|
92 /* |
|
93 ** All global variables used by this module (all of which are grouped |
|
94 ** together in global structure "pcache" above) are protected by the static |
|
95 ** SQLITE_MUTEX_STATIC_LRU mutex. A pointer to this mutex is stored in |
|
96 ** variable "pcache.mutex". |
|
97 ** |
|
98 ** Some elements of the PCache and PgHdr structures are protected by the |
|
99 ** SQLITE_MUTEX_STATUS_LRU mutex and other are not. The protected |
|
100 ** elements are grouped at the end of the structures and are clearly |
|
101 ** marked. |
|
102 ** |
|
103 ** Use the following macros must surround all access (read or write) |
|
104 ** of protected elements. The mutex is not recursive and may not be |
|
105 ** entered more than once. The pcacheMutexHeld() macro should only be |
|
106 ** used within an assert() to verify that the mutex is being held. |
|
107 */ |
|
108 #define pcacheEnterMutex() sqlite3_mutex_enter(pcache_g.mutex) |
|
109 #define pcacheExitMutex() sqlite3_mutex_leave(pcache_g.mutex) |
|
110 #define pcacheMutexHeld() sqlite3_mutex_held(pcache_g.mutex) |
|
111 |
|
112 /* |
|
113 ** Some of the assert() macros in this code are too expensive to run |
|
114 ** even during normal debugging. Use them only rarely on long-running |
|
115 ** tests. Enable the expensive asserts using the |
|
116 ** -DSQLITE_ENABLE_EXPENSIVE_ASSERT=1 compile-time option. |
|
117 */ |
|
118 #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT |
|
119 # define expensive_assert(X) assert(X) |
|
120 #else |
|
121 # define expensive_assert(X) |
|
122 #endif |
|
123 |
|
124 /********************************** Linked List Management ********************/ |
|
125 |
|
126 #if !defined(NDEBUG) && defined(SQLITE_ENABLE_EXPENSIVE_ASSERT) |
|
127 /* |
|
128 ** This routine verifies that the number of entries in the hash table |
|
129 ** is pCache->nPage. This routine is used within assert() statements |
|
130 ** only and is therefore disabled during production builds. |
|
131 */ |
|
132 static int pcacheCheckHashCount(PCache *pCache){ |
|
133 int i; |
|
134 int nPage = 0; |
|
135 for(i=0; i<pCache->nHash; i++){ |
|
136 PgHdr *p; |
|
137 for(p=pCache->apHash[i]; p; p=p->pNextHash){ |
|
138 nPage++; |
|
139 } |
|
140 } |
|
141 assert( nPage==pCache->nPage ); |
|
142 return 1; |
|
143 } |
|
144 #endif /* !NDEBUG && SQLITE_ENABLE_EXPENSIVE_ASSERT */ |
|
145 |
|
146 |
|
147 #if !defined(NDEBUG) && defined(SQLITE_ENABLE_EXPENSIVE_ASSERT) |
|
148 /* |
|
149 ** Based on the current value of PCache.nRef and the contents of the |
|
150 ** PCache.pDirty list, return the expected value of the PCache.nPinned |
|
151 ** counter. This is only used in debugging builds, as follows: |
|
152 ** |
|
153 ** expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) ); |
|
154 */ |
|
155 static int pcachePinnedCount(PCache *pCache){ |
|
156 PgHdr *p; |
|
157 int nPinned = pCache->nRef; |
|
158 for(p=pCache->pDirty; p; p=p->pNext){ |
|
159 if( p->nRef==0 ){ |
|
160 nPinned++; |
|
161 } |
|
162 } |
|
163 return nPinned; |
|
164 } |
|
165 #endif /* !NDEBUG && SQLITE_ENABLE_EXPENSIVE_ASSERT */ |
|
166 |
|
167 |
|
168 #if !defined(NDEBUG) && defined(SQLITE_ENABLE_EXPENSIVE_ASSERT) |
|
169 /* |
|
170 ** Check that the pCache->pSynced variable is set correctly. If it |
|
171 ** is not, either fail an assert or return zero. Otherwise, return |
|
172 ** non-zero. This is only used in debugging builds, as follows: |
|
173 ** |
|
174 ** expensive_assert( pcacheCheckSynced(pCache) ); |
|
175 */ |
|
176 static int pcacheCheckSynced(PCache *pCache){ |
|
177 PgHdr *p = pCache->pDirtyTail; |
|
178 for(p=pCache->pDirtyTail; p!=pCache->pSynced; p=p->pPrev){ |
|
179 assert( p->nRef || (p->flags&PGHDR_NEED_SYNC) ); |
|
180 } |
|
181 return (p==0 || p->nRef || (p->flags&PGHDR_NEED_SYNC)==0); |
|
182 } |
|
183 #endif /* !NDEBUG && SQLITE_ENABLE_EXPENSIVE_ASSERT */ |
|
184 |
|
185 |
|
186 |
|
187 /* |
|
188 ** Remove a page from its hash table (PCache.apHash[]). |
|
189 */ |
|
190 static void pcacheRemoveFromHash(PgHdr *pPage){ |
|
191 assert( pcacheMutexHeld() ); |
|
192 if( pPage->pPrevHash ){ |
|
193 pPage->pPrevHash->pNextHash = pPage->pNextHash; |
|
194 }else{ |
|
195 PCache *pCache = pPage->pCache; |
|
196 u32 h = pPage->pgno % pCache->nHash; |
|
197 assert( pCache->apHash[h]==pPage ); |
|
198 pCache->apHash[h] = pPage->pNextHash; |
|
199 } |
|
200 if( pPage->pNextHash ){ |
|
201 pPage->pNextHash->pPrevHash = pPage->pPrevHash; |
|
202 } |
|
203 pPage->pCache->nPage--; |
|
204 expensive_assert( pcacheCheckHashCount(pPage->pCache) ); |
|
205 } |
|
206 |
|
207 /* |
|
208 ** Insert a page into the hash table |
|
209 ** |
|
210 ** The mutex must be held by the caller. |
|
211 */ |
|
212 static void pcacheAddToHash(PgHdr *pPage){ |
|
213 PCache *pCache = pPage->pCache; |
|
214 u32 h = pPage->pgno % pCache->nHash; |
|
215 assert( pcacheMutexHeld() ); |
|
216 pPage->pNextHash = pCache->apHash[h]; |
|
217 pPage->pPrevHash = 0; |
|
218 if( pCache->apHash[h] ){ |
|
219 pCache->apHash[h]->pPrevHash = pPage; |
|
220 } |
|
221 pCache->apHash[h] = pPage; |
|
222 pCache->nPage++; |
|
223 expensive_assert( pcacheCheckHashCount(pCache) ); |
|
224 } |
|
225 |
|
226 /* |
|
227 ** Attempt to increase the size the hash table to contain |
|
228 ** at least nHash buckets. |
|
229 */ |
|
230 static int pcacheResizeHash(PCache *pCache, int nHash){ |
|
231 PgHdr *p; |
|
232 PgHdr **pNew; |
|
233 assert( pcacheMutexHeld() ); |
|
234 #ifdef SQLITE_MALLOC_SOFT_LIMIT |
|
235 if( nHash*sizeof(PgHdr*)>SQLITE_MALLOC_SOFT_LIMIT ){ |
|
236 nHash = SQLITE_MALLOC_SOFT_LIMIT/sizeof(PgHdr *); |
|
237 } |
|
238 #endif |
|
239 pcacheExitMutex(); |
|
240 pNew = (PgHdr **)sqlite3Malloc(sizeof(PgHdr*)*nHash); |
|
241 pcacheEnterMutex(); |
|
242 if( !pNew ){ |
|
243 return SQLITE_NOMEM; |
|
244 } |
|
245 memset(pNew, 0, sizeof(PgHdr *)*nHash); |
|
246 sqlite3_free(pCache->apHash); |
|
247 pCache->apHash = pNew; |
|
248 pCache->nHash = nHash; |
|
249 pCache->nPage = 0; |
|
250 |
|
251 for(p=pCache->pClean; p; p=p->pNext){ |
|
252 pcacheAddToHash(p); |
|
253 } |
|
254 for(p=pCache->pDirty; p; p=p->pNext){ |
|
255 pcacheAddToHash(p); |
|
256 } |
|
257 return SQLITE_OK; |
|
258 } |
|
259 |
|
260 /* |
|
261 ** Remove a page from a linked list that is headed by *ppHead. |
|
262 ** *ppHead is either PCache.pClean or PCache.pDirty. |
|
263 */ |
|
264 static void pcacheRemoveFromList(PgHdr **ppHead, PgHdr *pPage){ |
|
265 int isDirtyList = (ppHead==&pPage->pCache->pDirty); |
|
266 assert( ppHead==&pPage->pCache->pClean || ppHead==&pPage->pCache->pDirty ); |
|
267 assert( pcacheMutexHeld() || ppHead!=&pPage->pCache->pClean ); |
|
268 |
|
269 if( pPage->pPrev ){ |
|
270 pPage->pPrev->pNext = pPage->pNext; |
|
271 }else{ |
|
272 assert( *ppHead==pPage ); |
|
273 *ppHead = pPage->pNext; |
|
274 } |
|
275 if( pPage->pNext ){ |
|
276 pPage->pNext->pPrev = pPage->pPrev; |
|
277 } |
|
278 |
|
279 if( isDirtyList ){ |
|
280 PCache *pCache = pPage->pCache; |
|
281 assert( pPage->pNext || pCache->pDirtyTail==pPage ); |
|
282 if( !pPage->pNext ){ |
|
283 pCache->pDirtyTail = pPage->pPrev; |
|
284 } |
|
285 if( pCache->pSynced==pPage ){ |
|
286 PgHdr *pSynced = pPage->pPrev; |
|
287 while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){ |
|
288 pSynced = pSynced->pPrev; |
|
289 } |
|
290 pCache->pSynced = pSynced; |
|
291 } |
|
292 } |
|
293 } |
|
294 |
|
295 /* |
|
296 ** Add a page from a linked list that is headed by *ppHead. |
|
297 ** *ppHead is either PCache.pClean or PCache.pDirty. |
|
298 */ |
|
299 static void pcacheAddToList(PgHdr **ppHead, PgHdr *pPage){ |
|
300 int isDirtyList = (ppHead==&pPage->pCache->pDirty); |
|
301 assert( ppHead==&pPage->pCache->pClean || ppHead==&pPage->pCache->pDirty ); |
|
302 |
|
303 if( (*ppHead) ){ |
|
304 (*ppHead)->pPrev = pPage; |
|
305 } |
|
306 pPage->pNext = *ppHead; |
|
307 pPage->pPrev = 0; |
|
308 *ppHead = pPage; |
|
309 |
|
310 if( isDirtyList ){ |
|
311 PCache *pCache = pPage->pCache; |
|
312 if( !pCache->pDirtyTail ){ |
|
313 assert( pPage->pNext==0 ); |
|
314 pCache->pDirtyTail = pPage; |
|
315 } |
|
316 if( !pCache->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){ |
|
317 pCache->pSynced = pPage; |
|
318 } |
|
319 } |
|
320 } |
|
321 |
|
322 /* |
|
323 ** Remove a page from the global LRU list |
|
324 */ |
|
325 static void pcacheRemoveFromLruList(PgHdr *pPage){ |
|
326 assert( sqlite3_mutex_held(pcache_g.mutex) ); |
|
327 assert( (pPage->flags&PGHDR_DIRTY)==0 ); |
|
328 if( pPage->pCache->bPurgeable==0 ) return; |
|
329 if( pPage->pNextLru ){ |
|
330 assert( pcache_g.pLruTail!=pPage ); |
|
331 pPage->pNextLru->pPrevLru = pPage->pPrevLru; |
|
332 }else{ |
|
333 assert( pcache_g.pLruTail==pPage ); |
|
334 pcache_g.pLruTail = pPage->pPrevLru; |
|
335 } |
|
336 if( pPage->pPrevLru ){ |
|
337 assert( pcache_g.pLruHead!=pPage ); |
|
338 pPage->pPrevLru->pNextLru = pPage->pNextLru; |
|
339 }else{ |
|
340 assert( pcache_g.pLruHead==pPage ); |
|
341 pcache_g.pLruHead = pPage->pNextLru; |
|
342 } |
|
343 } |
|
344 |
|
345 /* |
|
346 ** Add a page to the global LRU list. The page is normally added |
|
347 ** to the front of the list so that it will be the last page recycled. |
|
348 ** However, if the PGHDR_REUSE_UNLIKELY bit is set, the page is added |
|
349 ** to the end of the LRU list so that it will be the next to be recycled. |
|
350 */ |
|
351 static void pcacheAddToLruList(PgHdr *pPage){ |
|
352 assert( sqlite3_mutex_held(pcache_g.mutex) ); |
|
353 assert( (pPage->flags&PGHDR_DIRTY)==0 ); |
|
354 if( pPage->pCache->bPurgeable==0 ) return; |
|
355 if( pcache_g.pLruTail && (pPage->flags & PGHDR_REUSE_UNLIKELY)!=0 ){ |
|
356 /* If reuse is unlikely. Put the page at the end of the LRU list |
|
357 ** where it will be recycled sooner rather than later. |
|
358 */ |
|
359 assert( pcache_g.pLruHead ); |
|
360 pPage->pNextLru = 0; |
|
361 pPage->pPrevLru = pcache_g.pLruTail; |
|
362 pcache_g.pLruTail->pNextLru = pPage; |
|
363 pcache_g.pLruTail = pPage; |
|
364 pPage->flags &= ~PGHDR_REUSE_UNLIKELY; |
|
365 }else{ |
|
366 /* If reuse is possible. the page goes at the beginning of the LRU |
|
367 ** list so that it will be the last to be recycled. |
|
368 */ |
|
369 if( pcache_g.pLruHead ){ |
|
370 pcache_g.pLruHead->pPrevLru = pPage; |
|
371 } |
|
372 pPage->pNextLru = pcache_g.pLruHead; |
|
373 pcache_g.pLruHead = pPage; |
|
374 pPage->pPrevLru = 0; |
|
375 if( pcache_g.pLruTail==0 ){ |
|
376 pcache_g.pLruTail = pPage; |
|
377 } |
|
378 } |
|
379 } |
|
380 |
|
381 /*********************************************** Memory Allocation *********** |
|
382 ** |
|
383 ** Initialize the page cache memory pool. |
|
384 ** |
|
385 ** This must be called at start-time when no page cache lines are |
|
386 ** checked out. This function is not threadsafe. |
|
387 */ |
|
388 void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){ |
|
389 PgFreeslot *p; |
|
390 sz &= ~7; |
|
391 pcache_g.szSlot = sz; |
|
392 pcache_g.pStart = pBuf; |
|
393 pcache_g.pFree = 0; |
|
394 while( n-- ){ |
|
395 p = (PgFreeslot*)pBuf; |
|
396 p->pNext = pcache_g.pFree; |
|
397 pcache_g.pFree = p; |
|
398 pBuf = (void*)&((char*)pBuf)[sz]; |
|
399 } |
|
400 pcache_g.pEnd = pBuf; |
|
401 } |
|
402 |
|
403 /* |
|
404 ** Allocate a page cache line. Look in the page cache memory pool first |
|
405 ** and use an element from it first if available. If nothing is available |
|
406 ** in the page cache memory pool, go to the general purpose memory allocator. |
|
407 */ |
|
408 static void *pcacheMalloc(int sz, PCache *pCache){ |
|
409 assert( sqlite3_mutex_held(pcache_g.mutex) ); |
|
410 if( sz<=pcache_g.szSlot && pcache_g.pFree ){ |
|
411 PgFreeslot *p = pcache_g.pFree; |
|
412 pcache_g.pFree = p->pNext; |
|
413 sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, sz); |
|
414 sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, 1); |
|
415 return (void*)p; |
|
416 }else{ |
|
417 void *p; |
|
418 |
|
419 /* Allocate a new buffer using sqlite3Malloc. Before doing so, exit the |
|
420 ** global pcache mutex and unlock the pager-cache object pCache. This is |
|
421 ** so that if the attempt to allocate a new buffer causes the the |
|
422 ** configured soft-heap-limit to be breached, it will be possible to |
|
423 ** reclaim memory from this pager-cache. |
|
424 */ |
|
425 pcacheExitMutex(); |
|
426 p = sqlite3Malloc(sz); |
|
427 pcacheEnterMutex(); |
|
428 |
|
429 if( p ){ |
|
430 sz = sqlite3MallocSize(p); |
|
431 sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz); |
|
432 } |
|
433 return p; |
|
434 } |
|
435 } |
|
436 void *sqlite3PageMalloc(int sz){ |
|
437 void *p; |
|
438 pcacheEnterMutex(); |
|
439 p = pcacheMalloc(sz, 0); |
|
440 pcacheExitMutex(); |
|
441 return p; |
|
442 } |
|
443 |
|
444 /* |
|
445 ** Release a pager memory allocation |
|
446 */ |
|
447 static void pcacheFree(void *p){ |
|
448 assert( sqlite3_mutex_held(pcache_g.mutex) ); |
|
449 if( p==0 ) return; |
|
450 if( p>=pcache_g.pStart && p<pcache_g.pEnd ){ |
|
451 PgFreeslot *pSlot; |
|
452 sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, -1); |
|
453 pSlot = (PgFreeslot*)p; |
|
454 pSlot->pNext = pcache_g.pFree; |
|
455 pcache_g.pFree = pSlot; |
|
456 }else{ |
|
457 int iSize = sqlite3MallocSize(p); |
|
458 sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -iSize); |
|
459 sqlite3_free(p); |
|
460 } |
|
461 } |
|
462 void sqlite3PageFree(void *p){ |
|
463 pcacheEnterMutex(); |
|
464 pcacheFree(p); |
|
465 pcacheExitMutex(); |
|
466 } |
|
467 |
|
468 /* |
|
469 ** Allocate a new page. |
|
470 */ |
|
471 static PgHdr *pcachePageAlloc(PCache *pCache){ |
|
472 PgHdr *p; |
|
473 int sz = sizeof(*p) + pCache->szPage + pCache->szExtra; |
|
474 assert( sqlite3_mutex_held(pcache_g.mutex) ); |
|
475 p = pcacheMalloc(sz, pCache); |
|
476 if( p==0 ) return 0; |
|
477 memset(p, 0, sizeof(PgHdr)); |
|
478 p->pData = (void*)&p[1]; |
|
479 p->pExtra = (void*)&((char*)p->pData)[pCache->szPage]; |
|
480 if( pCache->bPurgeable ){ |
|
481 pcache_g.nCurrentPage++; |
|
482 } |
|
483 return p; |
|
484 } |
|
485 |
|
486 /* |
|
487 ** Deallocate a page |
|
488 */ |
|
489 static void pcachePageFree(PgHdr *p){ |
|
490 assert( sqlite3_mutex_held(pcache_g.mutex) ); |
|
491 if( p->pCache->bPurgeable ){ |
|
492 pcache_g.nCurrentPage--; |
|
493 } |
|
494 pcacheFree(p->apSave[0]); |
|
495 pcacheFree(p->apSave[1]); |
|
496 pcacheFree(p); |
|
497 } |
|
498 |
|
499 #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT |
|
500 /* |
|
501 ** Return the number of bytes that will be returned to the heap when |
|
502 ** the argument is passed to pcachePageFree(). |
|
503 */ |
|
504 static int pcachePageSize(PgHdr *p){ |
|
505 assert( sqlite3_mutex_held(pcache_g.mutex) ); |
|
506 assert( !pcache_g.pStart ); |
|
507 assert( p->apSave[0]==0 ); |
|
508 assert( p->apSave[1]==0 ); |
|
509 assert( p && p->pCache ); |
|
510 return sqlite3MallocSize(p); |
|
511 } |
|
512 #endif |
|
513 |
|
514 /* |
|
515 ** Attempt to 'recycle' a page from the global LRU list. Only clean, |
|
516 ** unreferenced pages from purgeable caches are eligible for recycling. |
|
517 ** |
|
518 ** This function removes page pcache.pLruTail from the global LRU list, |
|
519 ** and from the hash-table and PCache.pClean list of the owner pcache. |
|
520 ** There should be no other references to the page. |
|
521 ** |
|
522 ** A pointer to the recycled page is returned, or NULL if no page is |
|
523 ** eligible for recycling. |
|
524 */ |
|
525 static PgHdr *pcacheRecyclePage(void){ |
|
526 PgHdr *p = 0; |
|
527 assert( sqlite3_mutex_held(pcache_g.mutex) ); |
|
528 |
|
529 if( (p=pcache_g.pLruTail) ){ |
|
530 assert( (p->flags&PGHDR_DIRTY)==0 ); |
|
531 pcacheRemoveFromLruList(p); |
|
532 pcacheRemoveFromHash(p); |
|
533 pcacheRemoveFromList(&p->pCache->pClean, p); |
|
534 } |
|
535 |
|
536 return p; |
|
537 } |
|
538 |
|
539 /* |
|
540 ** Obtain space for a page. Try to recycle an old page if the limit on the |
|
541 ** number of pages has been reached. If the limit has not been reached or |
|
542 ** there are no pages eligible for recycling, allocate a new page. |
|
543 ** |
|
544 ** Return a pointer to the new page, or NULL if an OOM condition occurs. |
|
545 */ |
|
546 static int pcacheRecycleOrAlloc(PCache *pCache, PgHdr **ppPage){ |
|
547 PgHdr *p = 0; |
|
548 |
|
549 int szPage = pCache->szPage; |
|
550 int szExtra = pCache->szExtra; |
|
551 |
|
552 assert( pcache_g.isInit ); |
|
553 assert( sqlite3_mutex_held(pcache_g.mutex) ); |
|
554 |
|
555 *ppPage = 0; |
|
556 |
|
557 /* If we have reached either the global or the local limit for |
|
558 ** pinned+dirty pages, and there is at least one dirty page, |
|
559 ** invoke the xStress callback to cause a page to become clean. |
|
560 */ |
|
561 expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) ); |
|
562 expensive_assert( pcacheCheckSynced(pCache) ); |
|
563 if( pCache->xStress |
|
564 && pCache->pDirty |
|
565 && (pCache->nPinned>=(pcache_g.nMaxPage+pCache->nMin-pcache_g.nMinPage) |
|
566 || pCache->nPinned>=pCache->nMax) |
|
567 ){ |
|
568 PgHdr *pPg; |
|
569 assert(pCache->pDirtyTail); |
|
570 |
|
571 for(pPg=pCache->pSynced; |
|
572 pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); |
|
573 pPg=pPg->pPrev |
|
574 ); |
|
575 if( !pPg ){ |
|
576 for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pPrev); |
|
577 } |
|
578 if( pPg ){ |
|
579 int rc; |
|
580 pcacheExitMutex(); |
|
581 rc = pCache->xStress(pCache->pStress, pPg); |
|
582 pcacheEnterMutex(); |
|
583 if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ |
|
584 return rc; |
|
585 } |
|
586 } |
|
587 } |
|
588 |
|
589 /* If either the local or the global page limit has been reached, |
|
590 ** try to recycle a page. |
|
591 */ |
|
592 if( pCache->bPurgeable && (pCache->nPage>=pCache->nMax-1 || |
|
593 pcache_g.nCurrentPage>=pcache_g.nMaxPage) ){ |
|
594 p = pcacheRecyclePage(); |
|
595 } |
|
596 |
|
597 /* If a page has been recycled but it is the wrong size, free it. */ |
|
598 if( p && (p->pCache->szPage!=szPage || p->pCache->szPage!=szExtra) ){ |
|
599 pcachePageFree(p); |
|
600 p = 0; |
|
601 } |
|
602 |
|
603 if( !p ){ |
|
604 p = pcachePageAlloc(pCache); |
|
605 } |
|
606 |
|
607 *ppPage = p; |
|
608 return (p?SQLITE_OK:SQLITE_NOMEM); |
|
609 } |
|
610 |
|
611 /*************************************************** General Interfaces ****** |
|
612 ** |
|
613 ** Initialize and shutdown the page cache subsystem. Neither of these |
|
614 ** functions are threadsafe. |
|
615 */ |
|
616 int sqlite3PcacheInitialize(void){ |
|
617 assert( pcache_g.isInit==0 ); |
|
618 memset(&pcache_g, 0, sizeof(pcache)); |
|
619 if( sqlite3GlobalConfig.bCoreMutex ){ |
|
620 /* No need to check the return value of sqlite3_mutex_alloc(). |
|
621 ** Allocating a static mutex cannot fail. |
|
622 */ |
|
623 pcache_g.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU); |
|
624 } |
|
625 pcache_g.isInit = 1; |
|
626 return SQLITE_OK; |
|
627 } |
|
628 void sqlite3PcacheShutdown(void){ |
|
629 memset(&pcache_g, 0, sizeof(pcache)); |
|
630 } |
|
631 |
|
632 /* |
|
633 ** Return the size in bytes of a PCache object. |
|
634 */ |
|
635 int sqlite3PcacheSize(void){ return sizeof(PCache); } |
|
636 |
|
637 /* |
|
638 ** Create a new PCache object. Storage space to hold the object |
|
639 ** has already been allocated and is passed in as the p pointer. |
|
640 */ |
|
641 void sqlite3PcacheOpen( |
|
642 int szPage, /* Size of every page */ |
|
643 int szExtra, /* Extra space associated with each page */ |
|
644 int bPurgeable, /* True if pages are on backing store */ |
|
645 int (*xStress)(void*,PgHdr*),/* Call to try to make pages clean */ |
|
646 void *pStress, /* Argument to xStress */ |
|
647 PCache *p /* Preallocated space for the PCache */ |
|
648 ){ |
|
649 assert( pcache_g.isInit ); |
|
650 memset(p, 0, sizeof(PCache)); |
|
651 p->szPage = szPage; |
|
652 p->szExtra = szExtra; |
|
653 p->bPurgeable = bPurgeable; |
|
654 p->xStress = xStress; |
|
655 p->pStress = pStress; |
|
656 p->nMax = 100; |
|
657 p->nMin = 10; |
|
658 |
|
659 pcacheEnterMutex(); |
|
660 if( bPurgeable ){ |
|
661 pcache_g.nMaxPage += p->nMax; |
|
662 pcache_g.nMinPage += p->nMin; |
|
663 } |
|
664 |
|
665 pcacheExitMutex(); |
|
666 } |
|
667 |
|
668 /* |
|
669 ** Change the page size for PCache object. This can only happen |
|
670 ** when the cache is empty. |
|
671 */ |
|
672 void sqlite3PcacheSetPageSize(PCache *pCache, int szPage){ |
|
673 assert(pCache->nPage==0); |
|
674 pCache->szPage = szPage; |
|
675 } |
|
676 |
|
677 /* |
|
678 ** Try to obtain a page from the cache. |
|
679 */ |
|
680 int sqlite3PcacheFetch( |
|
681 PCache *pCache, /* Obtain the page from this cache */ |
|
682 Pgno pgno, /* Page number to obtain */ |
|
683 int createFlag, /* If true, create page if it does not exist already */ |
|
684 PgHdr **ppPage /* Write the page here */ |
|
685 ){ |
|
686 int rc = SQLITE_OK; |
|
687 PgHdr *pPage = 0; |
|
688 |
|
689 assert( pcache_g.isInit ); |
|
690 assert( pCache!=0 ); |
|
691 assert( pgno>0 ); |
|
692 expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) ); |
|
693 |
|
694 pcacheEnterMutex(); |
|
695 |
|
696 /* Search the hash table for the requested page. Exit early if it is found. */ |
|
697 if( pCache->apHash ){ |
|
698 u32 h = pgno % pCache->nHash; |
|
699 for(pPage=pCache->apHash[h]; pPage; pPage=pPage->pNextHash){ |
|
700 if( pPage->pgno==pgno ){ |
|
701 if( pPage->nRef==0 ){ |
|
702 if( 0==(pPage->flags&PGHDR_DIRTY) ){ |
|
703 pcacheRemoveFromLruList(pPage); |
|
704 pCache->nPinned++; |
|
705 } |
|
706 pCache->nRef++; |
|
707 } |
|
708 pPage->nRef++; |
|
709 break; |
|
710 } |
|
711 } |
|
712 } |
|
713 |
|
714 if( !pPage && createFlag ){ |
|
715 if( pCache->nHash<=pCache->nPage ){ |
|
716 rc = pcacheResizeHash(pCache, pCache->nHash<256 ? 256 : pCache->nHash*2); |
|
717 } |
|
718 if( rc==SQLITE_OK ){ |
|
719 rc = pcacheRecycleOrAlloc(pCache, &pPage); |
|
720 } |
|
721 if( rc==SQLITE_OK ){ |
|
722 pPage->pPager = 0; |
|
723 pPage->flags = 0; |
|
724 pPage->pDirty = 0; |
|
725 pPage->pgno = pgno; |
|
726 pPage->pCache = pCache; |
|
727 pPage->nRef = 1; |
|
728 pCache->nRef++; |
|
729 pCache->nPinned++; |
|
730 pcacheAddToList(&pCache->pClean, pPage); |
|
731 pcacheAddToHash(pPage); |
|
732 } |
|
733 } |
|
734 |
|
735 pcacheExitMutex(); |
|
736 |
|
737 *ppPage = pPage; |
|
738 expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) ); |
|
739 assert( pPage || !createFlag || rc!=SQLITE_OK ); |
|
740 return rc; |
|
741 } |
|
742 |
|
743 /* |
|
744 ** Dereference a page. When the reference count reaches zero, |
|
745 ** move the page to the LRU list if it is clean. |
|
746 */ |
|
747 void sqlite3PcacheRelease(PgHdr *p){ |
|
748 assert( p->nRef>0 ); |
|
749 p->nRef--; |
|
750 if( p->nRef==0 ){ |
|
751 PCache *pCache = p->pCache; |
|
752 pCache->nRef--; |
|
753 if( (p->flags&PGHDR_DIRTY)==0 ){ |
|
754 pCache->nPinned--; |
|
755 pcacheEnterMutex(); |
|
756 if( pcache_g.nCurrentPage>pcache_g.nMaxPage ){ |
|
757 pcacheRemoveFromList(&pCache->pClean, p); |
|
758 pcacheRemoveFromHash(p); |
|
759 pcachePageFree(p); |
|
760 }else{ |
|
761 pcacheAddToLruList(p); |
|
762 } |
|
763 pcacheExitMutex(); |
|
764 }else{ |
|
765 /* Move the page to the head of the caches dirty list. */ |
|
766 pcacheRemoveFromList(&pCache->pDirty, p); |
|
767 pcacheAddToList(&pCache->pDirty, p); |
|
768 } |
|
769 } |
|
770 } |
|
771 |
|
772 void sqlite3PcacheRef(PgHdr *p){ |
|
773 assert(p->nRef>0); |
|
774 p->nRef++; |
|
775 } |
|
776 |
|
777 /* |
|
778 ** Drop a page from the cache. There must be exactly one reference to the |
|
779 ** page. This function deletes that reference, so after it returns the |
|
780 ** page pointed to by p is invalid. |
|
781 */ |
|
782 void sqlite3PcacheDrop(PgHdr *p){ |
|
783 PCache *pCache; |
|
784 assert( p->nRef==1 ); |
|
785 assert( 0==(p->flags&PGHDR_DIRTY) ); |
|
786 pCache = p->pCache; |
|
787 pCache->nRef--; |
|
788 pCache->nPinned--; |
|
789 pcacheEnterMutex(); |
|
790 pcacheRemoveFromList(&pCache->pClean, p); |
|
791 pcacheRemoveFromHash(p); |
|
792 pcachePageFree(p); |
|
793 pcacheExitMutex(); |
|
794 } |
|
795 |
|
796 /* |
|
797 ** Make sure the page is marked as dirty. If it isn't dirty already, |
|
798 ** make it so. |
|
799 */ |
|
800 void sqlite3PcacheMakeDirty(PgHdr *p){ |
|
801 PCache *pCache; |
|
802 p->flags &= ~PGHDR_DONT_WRITE; |
|
803 if( p->flags & PGHDR_DIRTY ) return; |
|
804 assert( (p->flags & PGHDR_DIRTY)==0 ); |
|
805 assert( p->nRef>0 ); |
|
806 pCache = p->pCache; |
|
807 pcacheEnterMutex(); |
|
808 pcacheRemoveFromList(&pCache->pClean, p); |
|
809 pcacheAddToList(&pCache->pDirty, p); |
|
810 pcacheExitMutex(); |
|
811 p->flags |= PGHDR_DIRTY; |
|
812 } |
|
813 |
|
814 static void pcacheMakeClean(PgHdr *p){ |
|
815 PCache *pCache = p->pCache; |
|
816 assert( p->apSave[0]==0 && p->apSave[1]==0 ); |
|
817 assert( p->flags & PGHDR_DIRTY ); |
|
818 pcacheRemoveFromList(&pCache->pDirty, p); |
|
819 pcacheAddToList(&pCache->pClean, p); |
|
820 p->flags &= ~PGHDR_DIRTY; |
|
821 if( p->nRef==0 ){ |
|
822 pcacheAddToLruList(p); |
|
823 pCache->nPinned--; |
|
824 } |
|
825 expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) ); |
|
826 } |
|
827 |
|
828 /* |
|
829 ** Make sure the page is marked as clean. If it isn't clean already, |
|
830 ** make it so. |
|
831 */ |
|
832 void sqlite3PcacheMakeClean(PgHdr *p){ |
|
833 if( (p->flags & PGHDR_DIRTY) ){ |
|
834 pcacheEnterMutex(); |
|
835 pcacheMakeClean(p); |
|
836 pcacheExitMutex(); |
|
837 } |
|
838 } |
|
839 |
|
840 /* |
|
841 ** Make every page in the cache clean. |
|
842 */ |
|
843 void sqlite3PcacheCleanAll(PCache *pCache){ |
|
844 PgHdr *p; |
|
845 pcacheEnterMutex(); |
|
846 while( (p = pCache->pDirty)!=0 ){ |
|
847 assert( p->apSave[0]==0 && p->apSave[1]==0 ); |
|
848 pcacheRemoveFromList(&pCache->pDirty, p); |
|
849 p->flags &= ~PGHDR_DIRTY; |
|
850 pcacheAddToList(&pCache->pClean, p); |
|
851 if( p->nRef==0 ){ |
|
852 pcacheAddToLruList(p); |
|
853 pCache->nPinned--; |
|
854 } |
|
855 } |
|
856 sqlite3PcacheAssertFlags(pCache, 0, PGHDR_DIRTY); |
|
857 expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) ); |
|
858 pcacheExitMutex(); |
|
859 } |
|
860 |
|
861 /* |
|
862 ** Change the page number of page p to newPgno. If newPgno is 0, then the |
|
863 ** page object is added to the clean-list and the PGHDR_REUSE_UNLIKELY |
|
864 ** flag set. |
|
865 */ |
|
866 void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){ |
|
867 assert( p->nRef>0 ); |
|
868 pcacheEnterMutex(); |
|
869 pcacheRemoveFromHash(p); |
|
870 p->pgno = newPgno; |
|
871 if( newPgno==0 ){ |
|
872 pcacheFree(p->apSave[0]); |
|
873 pcacheFree(p->apSave[1]); |
|
874 p->apSave[0] = 0; |
|
875 p->apSave[1] = 0; |
|
876 if( (p->flags & PGHDR_DIRTY) ){ |
|
877 pcacheMakeClean(p); |
|
878 } |
|
879 p->flags = PGHDR_REUSE_UNLIKELY; |
|
880 } |
|
881 pcacheAddToHash(p); |
|
882 pcacheExitMutex(); |
|
883 } |
|
884 |
|
885 /* |
|
886 ** Remove all content from a page cache |
|
887 */ |
|
888 static void pcacheClear(PCache *pCache){ |
|
889 PgHdr *p, *pNext; |
|
890 assert( sqlite3_mutex_held(pcache_g.mutex) ); |
|
891 for(p=pCache->pClean; p; p=pNext){ |
|
892 pNext = p->pNext; |
|
893 pcacheRemoveFromLruList(p); |
|
894 pcachePageFree(p); |
|
895 } |
|
896 for(p=pCache->pDirty; p; p=pNext){ |
|
897 pNext = p->pNext; |
|
898 pcachePageFree(p); |
|
899 } |
|
900 pCache->pClean = 0; |
|
901 pCache->pDirty = 0; |
|
902 pCache->pDirtyTail = 0; |
|
903 pCache->nPage = 0; |
|
904 pCache->nPinned = 0; |
|
905 memset(pCache->apHash, 0, pCache->nHash*sizeof(pCache->apHash[0])); |
|
906 } |
|
907 |
|
908 |
|
909 /* |
|
910 ** Drop every cache entry whose page number is greater than "pgno". |
|
911 */ |
|
912 void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){ |
|
913 PgHdr *p, *pNext; |
|
914 PgHdr *pDirty = pCache->pDirty; |
|
915 pcacheEnterMutex(); |
|
916 for(p=pCache->pClean; p||pDirty; p=pNext){ |
|
917 if( !p ){ |
|
918 p = pDirty; |
|
919 pDirty = 0; |
|
920 } |
|
921 pNext = p->pNext; |
|
922 if( p->pgno>pgno ){ |
|
923 if( p->nRef==0 ){ |
|
924 pcacheRemoveFromHash(p); |
|
925 if( p->flags&PGHDR_DIRTY ){ |
|
926 pcacheRemoveFromList(&pCache->pDirty, p); |
|
927 pCache->nPinned--; |
|
928 }else{ |
|
929 pcacheRemoveFromList(&pCache->pClean, p); |
|
930 pcacheRemoveFromLruList(p); |
|
931 } |
|
932 pcachePageFree(p); |
|
933 }else{ |
|
934 /* If there are references to the page, it cannot be freed. In this |
|
935 ** case, zero the page content instead. |
|
936 */ |
|
937 memset(p->pData, 0, pCache->szPage); |
|
938 } |
|
939 } |
|
940 } |
|
941 pcacheExitMutex(); |
|
942 } |
|
943 |
|
944 /* |
|
945 ** If there are currently more than pcache.nMaxPage pages allocated, try |
|
946 ** to recycle pages to reduce the number allocated to pcache.nMaxPage. |
|
947 */ |
|
948 static void pcacheEnforceMaxPage(void){ |
|
949 PgHdr *p; |
|
950 assert( sqlite3_mutex_held(pcache_g.mutex) ); |
|
951 while( pcache_g.nCurrentPage>pcache_g.nMaxPage && (p = pcacheRecyclePage()) ){ |
|
952 pcachePageFree(p); |
|
953 } |
|
954 } |
|
955 |
|
956 /* |
|
957 ** Close a cache. |
|
958 */ |
|
959 void sqlite3PcacheClose(PCache *pCache){ |
|
960 pcacheEnterMutex(); |
|
961 |
|
962 /* Free all the pages used by this pager and remove them from the LRU list. */ |
|
963 pcacheClear(pCache); |
|
964 if( pCache->bPurgeable ){ |
|
965 pcache_g.nMaxPage -= pCache->nMax; |
|
966 pcache_g.nMinPage -= pCache->nMin; |
|
967 pcacheEnforceMaxPage(); |
|
968 } |
|
969 sqlite3_free(pCache->apHash); |
|
970 pcacheExitMutex(); |
|
971 } |
|
972 |
|
973 /* |
|
974 ** Preserve the content of the page. It is assumed that the content |
|
975 ** has not been preserved already. |
|
976 ** |
|
977 ** If idJournal==0 then this is for the overall transaction. |
|
978 ** If idJournal==1 then this is for the statement journal. |
|
979 ** |
|
980 ** This routine is used for in-memory databases only. |
|
981 ** |
|
982 ** Return SQLITE_OK or SQLITE_NOMEM if a memory allocation fails. |
|
983 */ |
|
984 int sqlite3PcachePreserve(PgHdr *p, int idJournal){ |
|
985 void *x; |
|
986 int sz; |
|
987 assert( p->pCache->bPurgeable==0 ); |
|
988 assert( p->apSave[idJournal]==0 ); |
|
989 sz = p->pCache->szPage; |
|
990 p->apSave[idJournal] = x = sqlite3PageMalloc( sz ); |
|
991 if( x==0 ) return SQLITE_NOMEM; |
|
992 memcpy(x, p->pData, sz); |
|
993 return SQLITE_OK; |
|
994 } |
|
995 |
|
996 /* |
|
997 ** Commit a change previously preserved. |
|
998 */ |
|
999 void sqlite3PcacheCommit(PCache *pCache, int idJournal){ |
|
1000 PgHdr *p; |
|
1001 int mask = idJournal==0 ? ~PGHDR_IN_JOURNAL : 0xffffff; |
|
1002 pcacheEnterMutex(); /* Mutex is required to call pcacheFree() */ |
|
1003 for(p=pCache->pDirty; p; p=p->pNext){ |
|
1004 if( p->apSave[idJournal] ){ |
|
1005 pcacheFree(p->apSave[idJournal]); |
|
1006 p->apSave[idJournal] = 0; |
|
1007 } |
|
1008 p->flags &= mask; |
|
1009 } |
|
1010 pcacheExitMutex(); |
|
1011 } |
|
1012 |
|
1013 /* |
|
1014 ** Rollback a change previously preserved. |
|
1015 */ |
|
1016 void sqlite3PcacheRollback( |
|
1017 PCache *pCache, /* Pager cache */ |
|
1018 int idJournal, /* Which copy to rollback to */ |
|
1019 void (*xReiniter)(PgHdr*) /* Called on each rolled back page */ |
|
1020 ){ |
|
1021 PgHdr *p; |
|
1022 int sz; |
|
1023 int mask = idJournal==0 ? ~PGHDR_IN_JOURNAL : 0xffffff; |
|
1024 pcacheEnterMutex(); /* Mutex is required to call pcacheFree() */ |
|
1025 sz = pCache->szPage; |
|
1026 for(p=pCache->pDirty; p; p=p->pNext){ |
|
1027 if( p->apSave[idJournal] ){ |
|
1028 memcpy(p->pData, p->apSave[idJournal], sz); |
|
1029 pcacheFree(p->apSave[idJournal]); |
|
1030 p->apSave[idJournal] = 0; |
|
1031 if( xReiniter ){ |
|
1032 xReiniter(p); |
|
1033 } |
|
1034 } |
|
1035 p->flags &= mask; |
|
1036 } |
|
1037 pcacheExitMutex(); |
|
1038 } |
|
1039 |
|
1040 #ifndef NDEBUG |
|
1041 /* |
|
1042 ** Assert flags settings on all pages. Debugging only. |
|
1043 */ |
|
1044 void sqlite3PcacheAssertFlags(PCache *pCache, int trueMask, int falseMask){ |
|
1045 PgHdr *p; |
|
1046 for(p=pCache->pDirty; p; p=p->pNext){ |
|
1047 assert( (p->flags&trueMask)==trueMask ); |
|
1048 assert( (p->flags&falseMask)==0 ); |
|
1049 } |
|
1050 for(p=pCache->pClean; p; p=p->pNext){ |
|
1051 assert( (p->flags&trueMask)==trueMask ); |
|
1052 assert( (p->flags&falseMask)==0 ); |
|
1053 } |
|
1054 } |
|
1055 #endif |
|
1056 |
|
1057 /* |
|
1058 ** Discard the contents of the cache. |
|
1059 */ |
|
1060 int sqlite3PcacheClear(PCache *pCache){ |
|
1061 assert(pCache->nRef==0); |
|
1062 pcacheEnterMutex(); |
|
1063 pcacheClear(pCache); |
|
1064 pcacheExitMutex(); |
|
1065 return SQLITE_OK; |
|
1066 } |
|
1067 |
|
1068 /* |
|
1069 ** Merge two lists of pages connected by pDirty and in pgno order. |
|
1070 ** Do not both fixing the pPrevDirty pointers. |
|
1071 */ |
|
1072 static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){ |
|
1073 PgHdr result, *pTail; |
|
1074 pTail = &result; |
|
1075 while( pA && pB ){ |
|
1076 if( pA->pgno<pB->pgno ){ |
|
1077 pTail->pDirty = pA; |
|
1078 pTail = pA; |
|
1079 pA = pA->pDirty; |
|
1080 }else{ |
|
1081 pTail->pDirty = pB; |
|
1082 pTail = pB; |
|
1083 pB = pB->pDirty; |
|
1084 } |
|
1085 } |
|
1086 if( pA ){ |
|
1087 pTail->pDirty = pA; |
|
1088 }else if( pB ){ |
|
1089 pTail->pDirty = pB; |
|
1090 }else{ |
|
1091 pTail->pDirty = 0; |
|
1092 } |
|
1093 return result.pDirty; |
|
1094 } |
|
1095 |
|
1096 /* |
|
1097 ** Sort the list of pages in accending order by pgno. Pages are |
|
1098 ** connected by pDirty pointers. The pPrevDirty pointers are |
|
1099 ** corrupted by this sort. |
|
1100 */ |
|
1101 #define N_SORT_BUCKET_ALLOC 25 |
|
1102 #define N_SORT_BUCKET 25 |
|
1103 #ifdef SQLITE_TEST |
|
1104 int sqlite3_pager_n_sort_bucket = 0; |
|
1105 #undef N_SORT_BUCKET |
|
1106 #define N_SORT_BUCKET \ |
|
1107 (sqlite3_pager_n_sort_bucket?sqlite3_pager_n_sort_bucket:N_SORT_BUCKET_ALLOC) |
|
1108 #endif |
|
1109 static PgHdr *pcacheSortDirtyList(PgHdr *pIn){ |
|
1110 PgHdr *a[N_SORT_BUCKET_ALLOC], *p; |
|
1111 int i; |
|
1112 memset(a, 0, sizeof(a)); |
|
1113 while( pIn ){ |
|
1114 p = pIn; |
|
1115 pIn = p->pDirty; |
|
1116 p->pDirty = 0; |
|
1117 for(i=0; i<N_SORT_BUCKET-1; i++){ |
|
1118 if( a[i]==0 ){ |
|
1119 a[i] = p; |
|
1120 break; |
|
1121 }else{ |
|
1122 p = pcacheMergeDirtyList(a[i], p); |
|
1123 a[i] = 0; |
|
1124 } |
|
1125 } |
|
1126 if( i==N_SORT_BUCKET-1 ){ |
|
1127 /* Coverage: To get here, there need to be 2^(N_SORT_BUCKET) |
|
1128 ** elements in the input list. This is possible, but impractical. |
|
1129 ** Testing this line is the point of global variable |
|
1130 ** sqlite3_pager_n_sort_bucket. |
|
1131 */ |
|
1132 a[i] = pcacheMergeDirtyList(a[i], p); |
|
1133 } |
|
1134 } |
|
1135 p = a[0]; |
|
1136 for(i=1; i<N_SORT_BUCKET; i++){ |
|
1137 p = pcacheMergeDirtyList(p, a[i]); |
|
1138 } |
|
1139 return p; |
|
1140 } |
|
1141 |
|
1142 /* |
|
1143 ** Return a list of all dirty pages in the cache, sorted by page number. |
|
1144 */ |
|
1145 PgHdr *sqlite3PcacheDirtyList(PCache *pCache){ |
|
1146 PgHdr *p; |
|
1147 for(p=pCache->pDirty; p; p=p->pNext){ |
|
1148 p->pDirty = p->pNext; |
|
1149 } |
|
1150 return pcacheSortDirtyList(pCache->pDirty); |
|
1151 } |
|
1152 |
|
1153 /* |
|
1154 ** Return the total number of outstanding page references. |
|
1155 */ |
|
1156 int sqlite3PcacheRefCount(PCache *pCache){ |
|
1157 return pCache->nRef; |
|
1158 } |
|
1159 |
|
1160 int sqlite3PcachePageRefcount(PgHdr *p){ |
|
1161 return p->nRef; |
|
1162 } |
|
1163 |
|
1164 /* |
|
1165 ** Return the total number of pages in the cache. |
|
1166 */ |
|
1167 int sqlite3PcachePagecount(PCache *pCache){ |
|
1168 assert( pCache->nPage>=0 ); |
|
1169 return pCache->nPage; |
|
1170 } |
|
1171 |
|
1172 #ifdef SQLITE_CHECK_PAGES |
|
1173 /* |
|
1174 ** This function is used by the pager.c module to iterate through all |
|
1175 ** pages in the cache. At present, this is only required if the |
|
1176 ** SQLITE_CHECK_PAGES macro (used for debugging) is specified. |
|
1177 */ |
|
1178 void sqlite3PcacheIterate(PCache *pCache, void (*xIter)(PgHdr *)){ |
|
1179 PgHdr *p; |
|
1180 for(p=pCache->pClean; p; p=p->pNext){ |
|
1181 xIter(p); |
|
1182 } |
|
1183 for(p=pCache->pDirty; p; p=p->pNext){ |
|
1184 xIter(p); |
|
1185 } |
|
1186 } |
|
1187 #endif |
|
1188 |
|
1189 /* |
|
1190 ** Set flags on all pages in the page cache |
|
1191 */ |
|
1192 void sqlite3PcacheClearFlags(PCache *pCache, int mask){ |
|
1193 PgHdr *p; |
|
1194 |
|
1195 /* Obtain the global mutex before modifying any PgHdr.flags variables |
|
1196 ** or traversing the LRU list. |
|
1197 */ |
|
1198 pcacheEnterMutex(); |
|
1199 |
|
1200 mask = ~mask; |
|
1201 for(p=pCache->pDirty; p; p=p->pNext){ |
|
1202 p->flags &= mask; |
|
1203 } |
|
1204 for(p=pCache->pClean; p; p=p->pNext){ |
|
1205 p->flags &= mask; |
|
1206 } |
|
1207 |
|
1208 if( 0==(mask&PGHDR_NEED_SYNC) ){ |
|
1209 pCache->pSynced = pCache->pDirtyTail; |
|
1210 assert( !pCache->pSynced || (pCache->pSynced->flags&PGHDR_NEED_SYNC)==0 ); |
|
1211 } |
|
1212 |
|
1213 pcacheExitMutex(); |
|
1214 } |
|
1215 |
|
1216 /* |
|
1217 ** Set the suggested cache-size value. |
|
1218 */ |
|
1219 int sqlite3PcacheGetCachesize(PCache *pCache){ |
|
1220 return pCache->nMax; |
|
1221 } |
|
1222 |
|
1223 /* |
|
1224 ** Set the suggested cache-size value. |
|
1225 */ |
|
1226 void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){ |
|
1227 if( mxPage<10 ){ |
|
1228 mxPage = 10; |
|
1229 } |
|
1230 if( pCache->bPurgeable ){ |
|
1231 pcacheEnterMutex(); |
|
1232 pcache_g.nMaxPage -= pCache->nMax; |
|
1233 pcache_g.nMaxPage += mxPage; |
|
1234 pcacheEnforceMaxPage(); |
|
1235 pcacheExitMutex(); |
|
1236 } |
|
1237 pCache->nMax = mxPage; |
|
1238 } |
|
1239 |
|
1240 #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT |
|
1241 /* |
|
1242 ** This function is called to free superfluous dynamically allocated memory |
|
1243 ** held by the pager system. Memory in use by any SQLite pager allocated |
|
1244 ** by the current thread may be sqlite3_free()ed. |
|
1245 ** |
|
1246 ** nReq is the number of bytes of memory required. Once this much has |
|
1247 ** been released, the function returns. The return value is the total number |
|
1248 ** of bytes of memory released. |
|
1249 */ |
|
1250 int sqlite3PcacheReleaseMemory(int nReq){ |
|
1251 int nFree = 0; |
|
1252 if( pcache_g.pStart==0 ){ |
|
1253 PgHdr *p; |
|
1254 pcacheEnterMutex(); |
|
1255 while( (nReq<0 || nFree<nReq) && (p=pcacheRecyclePage()) ){ |
|
1256 nFree += pcachePageSize(p); |
|
1257 pcachePageFree(p); |
|
1258 } |
|
1259 pcacheExitMutex(); |
|
1260 } |
|
1261 return nFree; |
|
1262 } |
|
1263 #endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */ |
|
1264 |
|
1265 #ifdef SQLITE_TEST |
|
1266 void sqlite3PcacheStats( |
|
1267 int *pnCurrent, |
|
1268 int *pnMax, |
|
1269 int *pnMin, |
|
1270 int *pnRecyclable |
|
1271 ){ |
|
1272 PgHdr *p; |
|
1273 int nRecyclable = 0; |
|
1274 for(p=pcache_g.pLruHead; p; p=p->pNextLru){ |
|
1275 nRecyclable++; |
|
1276 } |
|
1277 |
|
1278 *pnCurrent = pcache_g.nCurrentPage; |
|
1279 *pnMax = pcache_g.nMaxPage; |
|
1280 *pnMin = pcache_g.nMinPage; |
|
1281 *pnRecyclable = nRecyclable; |
|
1282 } |
|
1283 #endif |