Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(77)

Side by Side Diff: third_party/sqlite/src/src/pcache.c

Issue 901033002: Import SQLite 3.8.7.4. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Apply patches to SQLite. Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 ** 2008 August 05 2 ** 2008 August 05
3 ** 3 **
4 ** The author disclaims copyright to this source code. In place of 4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing: 5 ** a legal notice, here is a blessing:
6 ** 6 **
7 ** May you do good and not evil. 7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others. 8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give. 9 ** May you share freely, never taking more than you give.
10 ** 10 **
11 ************************************************************************* 11 *************************************************************************
12 ** This file implements that page cache. 12 ** This file implements that page cache.
13 */ 13 */
14 #include "sqliteInt.h" 14 #include "sqliteInt.h"
15 15
16 /* 16 /*
17 ** A complete page cache is an instance of this structure. 17 ** A complete page cache is an instance of this structure.
18 */ 18 */
19 struct PCache { 19 struct PCache {
20 PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */ 20 PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */
21 PgHdr *pSynced; /* Last synced page in dirty page list */ 21 PgHdr *pSynced; /* Last synced page in dirty page list */
22 int nRef; /* Number of referenced pages */ 22 int nRef; /* Number of referenced pages */
23 int nMax; /* Configured cache size */ 23 int szCache; /* Configured cache size */
24 int szPage; /* Size of every page in this cache */ 24 int szPage; /* Size of every page in this cache */
25 int szExtra; /* Size of extra space for each page */ 25 int szExtra; /* Size of extra space for each page */
26 int bPurgeable; /* True if pages are on backing store */ 26 u8 bPurgeable; /* True if pages are on backing store */
27 u8 eCreate; /* eCreate value for for xFetch() */
27 int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */ 28 int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */
28 void *pStress; /* Argument to xStress */ 29 void *pStress; /* Argument to xStress */
29 sqlite3_pcache *pCache; /* Pluggable cache module */ 30 sqlite3_pcache *pCache; /* Pluggable cache module */
30 PgHdr *pPage1; /* Reference to page 1 */ 31 PgHdr *pPage1; /* Reference to page 1 */
31 }; 32 };
32 33
33 /* 34 /*
34 ** Some of the assert() macros in this code are too expensive to run 35 ** Some of the assert() macros in this code are too expensive to run
35 ** even during normal debugging. Use them only rarely on long-running 36 ** even during normal debugging. Use them only rarely on long-running
36 ** tests. Enable the expensive asserts using the 37 ** tests. Enable the expensive asserts using the
37 ** -DSQLITE_ENABLE_EXPENSIVE_ASSERT=1 compile-time option. 38 ** -DSQLITE_ENABLE_EXPENSIVE_ASSERT=1 compile-time option.
38 */ 39 */
39 #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT 40 #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
40 # define expensive_assert(X) assert(X) 41 # define expensive_assert(X) assert(X)
41 #else 42 #else
42 # define expensive_assert(X) 43 # define expensive_assert(X)
43 #endif 44 #endif
44 45
45 /********************************** Linked List Management ********************/ 46 /********************************** Linked List Management ********************/
46 47
47 #if !defined(NDEBUG) && defined(SQLITE_ENABLE_EXPENSIVE_ASSERT) 48 /* Allowed values for second argument to pcacheManageDirtyList() */
48 /* 49 #define PCACHE_DIRTYLIST_REMOVE 1 /* Remove pPage from dirty list */
49 ** Check that the pCache->pSynced variable is set correctly. If it 50 #define PCACHE_DIRTYLIST_ADD 2 /* Add pPage to the dirty list */
50 ** is not, either fail an assert or return zero. Otherwise, return 51 #define PCACHE_DIRTYLIST_FRONT 3 /* Move pPage to the front of the list */
51 ** non-zero. This is only used in debugging builds, as follows:
52 **
53 ** expensive_assert( pcacheCheckSynced(pCache) );
54 */
55 static int pcacheCheckSynced(PCache *pCache){
56 PgHdr *p;
57 for(p=pCache->pDirtyTail; p!=pCache->pSynced; p=p->pDirtyPrev){
58 assert( p->nRef || (p->flags&PGHDR_NEED_SYNC) );
59 }
60 return (p==0 || p->nRef || (p->flags&PGHDR_NEED_SYNC)==0);
61 }
62 #endif /* !NDEBUG && SQLITE_ENABLE_EXPENSIVE_ASSERT */
63 52
64 /* 53 /*
65 ** Remove page pPage from the list of dirty pages. 54 ** Manage pPage's participation on the dirty list. Bits of the addRemove
55 ** argument determines what operation to do. The 0x01 bit means first
56 ** remove pPage from the dirty list. The 0x02 means add pPage back to
57 ** the dirty list. Doing both moves pPage to the front of the dirty list.
66 */ 58 */
67 static void pcacheRemoveFromDirtyList(PgHdr *pPage){ 59 static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
68 PCache *p = pPage->pCache; 60 PCache *p = pPage->pCache;
69 61
70 assert( pPage->pDirtyNext || pPage==p->pDirtyTail ); 62 if( addRemove & PCACHE_DIRTYLIST_REMOVE ){
71 assert( pPage->pDirtyPrev || pPage==p->pDirty ); 63 assert( pPage->pDirtyNext || pPage==p->pDirtyTail );
72 64 assert( pPage->pDirtyPrev || pPage==p->pDirty );
73 /* Update the PCache1.pSynced variable if necessary. */ 65
74 if( p->pSynced==pPage ){ 66 /* Update the PCache1.pSynced variable if necessary. */
75 PgHdr *pSynced = pPage->pDirtyPrev; 67 if( p->pSynced==pPage ){
76 while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){ 68 PgHdr *pSynced = pPage->pDirtyPrev;
77 pSynced = pSynced->pDirtyPrev; 69 while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){
70 pSynced = pSynced->pDirtyPrev;
71 }
72 p->pSynced = pSynced;
78 } 73 }
79 p->pSynced = pSynced; 74
75 if( pPage->pDirtyNext ){
76 pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev;
77 }else{
78 assert( pPage==p->pDirtyTail );
79 p->pDirtyTail = pPage->pDirtyPrev;
80 }
81 if( pPage->pDirtyPrev ){
82 pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext;
83 }else{
84 assert( pPage==p->pDirty );
85 p->pDirty = pPage->pDirtyNext;
86 if( p->pDirty==0 && p->bPurgeable ){
87 assert( p->eCreate==1 );
88 p->eCreate = 2;
89 }
90 }
91 pPage->pDirtyNext = 0;
92 pPage->pDirtyPrev = 0;
80 } 93 }
81 94 if( addRemove & PCACHE_DIRTYLIST_ADD ){
82 if( pPage->pDirtyNext ){ 95 assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage );
83 pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev; 96
84 }else{ 97 pPage->pDirtyNext = p->pDirty;
85 assert( pPage==p->pDirtyTail ); 98 if( pPage->pDirtyNext ){
86 p->pDirtyTail = pPage->pDirtyPrev; 99 assert( pPage->pDirtyNext->pDirtyPrev==0 );
100 pPage->pDirtyNext->pDirtyPrev = pPage;
101 }else{
102 p->pDirtyTail = pPage;
103 if( p->bPurgeable ){
104 assert( p->eCreate==2 );
105 p->eCreate = 1;
106 }
107 }
108 p->pDirty = pPage;
109 if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){
110 p->pSynced = pPage;
111 }
87 } 112 }
88 if( pPage->pDirtyPrev ){
89 pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext;
90 }else{
91 assert( pPage==p->pDirty );
92 p->pDirty = pPage->pDirtyNext;
93 }
94 pPage->pDirtyNext = 0;
95 pPage->pDirtyPrev = 0;
96
97 expensive_assert( pcacheCheckSynced(p) );
98 } 113 }
99 114
100 /* 115 /*
101 ** Add page pPage to the head of the dirty list (PCache1.pDirty is set to
102 ** pPage).
103 */
104 static void pcacheAddToDirtyList(PgHdr *pPage){
105 PCache *p = pPage->pCache;
106
107 assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage );
108
109 pPage->pDirtyNext = p->pDirty;
110 if( pPage->pDirtyNext ){
111 assert( pPage->pDirtyNext->pDirtyPrev==0 );
112 pPage->pDirtyNext->pDirtyPrev = pPage;
113 }
114 p->pDirty = pPage;
115 if( !p->pDirtyTail ){
116 p->pDirtyTail = pPage;
117 }
118 if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){
119 p->pSynced = pPage;
120 }
121 expensive_assert( pcacheCheckSynced(p) );
122 }
123
124 /*
125 ** Wrapper around the pluggable caches xUnpin method. If the cache is 116 ** Wrapper around the pluggable caches xUnpin method. If the cache is
126 ** being used for an in-memory database, this function is a no-op. 117 ** being used for an in-memory database, this function is a no-op.
127 */ 118 */
128 static void pcacheUnpin(PgHdr *p){ 119 static void pcacheUnpin(PgHdr *p){
129 PCache *pCache = p->pCache; 120 if( p->pCache->bPurgeable ){
130 if( pCache->bPurgeable ){
131 if( p->pgno==1 ){ 121 if( p->pgno==1 ){
132 pCache->pPage1 = 0; 122 p->pCache->pPage1 = 0;
133 } 123 }
134 sqlite3GlobalConfig.pcache.xUnpin(pCache->pCache, p, 0); 124 sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 0);
135 } 125 }
136 } 126 }
137 127
128 /*
129 ** Compute the number of pages of cache requested.
130 */
131 static int numberOfCachePages(PCache *p){
132 if( p->szCache>=0 ){
133 return p->szCache;
134 }else{
135 return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra));
136 }
137 }
138
138 /*************************************************** General Interfaces ****** 139 /*************************************************** General Interfaces ******
139 ** 140 **
140 ** Initialize and shutdown the page cache subsystem. Neither of these 141 ** Initialize and shutdown the page cache subsystem. Neither of these
141 ** functions are threadsafe. 142 ** functions are threadsafe.
142 */ 143 */
143 int sqlite3PcacheInitialize(void){ 144 int sqlite3PcacheInitialize(void){
144 if( sqlite3GlobalConfig.pcache.xInit==0 ){ 145 if( sqlite3GlobalConfig.pcache2.xInit==0 ){
145 /* IMPLEMENTATION-OF: R-26801-64137 If the xInit() method is NULL, then the 146 /* IMPLEMENTATION-OF: R-26801-64137 If the xInit() method is NULL, then the
146 ** built-in default page cache is used instead of the application defined 147 ** built-in default page cache is used instead of the application defined
147 ** page cache. */ 148 ** page cache. */
148 sqlite3PCacheSetDefault(); 149 sqlite3PCacheSetDefault();
149 } 150 }
150 return sqlite3GlobalConfig.pcache.xInit(sqlite3GlobalConfig.pcache.pArg); 151 return sqlite3GlobalConfig.pcache2.xInit(sqlite3GlobalConfig.pcache2.pArg);
151 } 152 }
152 void sqlite3PcacheShutdown(void){ 153 void sqlite3PcacheShutdown(void){
153 if( sqlite3GlobalConfig.pcache.xShutdown ){ 154 if( sqlite3GlobalConfig.pcache2.xShutdown ){
154 /* IMPLEMENTATION-OF: R-26000-56589 The xShutdown() method may be NULL. */ 155 /* IMPLEMENTATION-OF: R-26000-56589 The xShutdown() method may be NULL. */
155 sqlite3GlobalConfig.pcache.xShutdown(sqlite3GlobalConfig.pcache.pArg); 156 sqlite3GlobalConfig.pcache2.xShutdown(sqlite3GlobalConfig.pcache2.pArg);
156 } 157 }
157 } 158 }
158 159
159 /* 160 /*
160 ** Return the size in bytes of a PCache object. 161 ** Return the size in bytes of a PCache object.
161 */ 162 */
162 int sqlite3PcacheSize(void){ return sizeof(PCache); } 163 int sqlite3PcacheSize(void){ return sizeof(PCache); }
163 164
164 /* 165 /*
165 ** Create a new PCache object. Storage space to hold the object 166 ** Create a new PCache object. Storage space to hold the object
166 ** has already been allocated and is passed in as the p pointer. 167 ** has already been allocated and is passed in as the p pointer.
167 ** The caller discovers how much space needs to be allocated by 168 ** The caller discovers how much space needs to be allocated by
168 ** calling sqlite3PcacheSize(). 169 ** calling sqlite3PcacheSize().
169 */ 170 */
170 void sqlite3PcacheOpen( 171 int sqlite3PcacheOpen(
171 int szPage, /* Size of every page */ 172 int szPage, /* Size of every page */
172 int szExtra, /* Extra space associated with each page */ 173 int szExtra, /* Extra space associated with each page */
173 int bPurgeable, /* True if pages are on backing store */ 174 int bPurgeable, /* True if pages are on backing store */
174 int (*xStress)(void*,PgHdr*),/* Call to try to make pages clean */ 175 int (*xStress)(void*,PgHdr*),/* Call to try to make pages clean */
175 void *pStress, /* Argument to xStress */ 176 void *pStress, /* Argument to xStress */
176 PCache *p /* Preallocated space for the PCache */ 177 PCache *p /* Preallocated space for the PCache */
177 ){ 178 ){
178 memset(p, 0, sizeof(PCache)); 179 memset(p, 0, sizeof(PCache));
179 p->szPage = szPage; 180 p->szPage = 1;
180 p->szExtra = szExtra; 181 p->szExtra = szExtra;
181 p->bPurgeable = bPurgeable; 182 p->bPurgeable = bPurgeable;
183 p->eCreate = 2;
182 p->xStress = xStress; 184 p->xStress = xStress;
183 p->pStress = pStress; 185 p->pStress = pStress;
184 p->nMax = 100; 186 p->szCache = 100;
187 return sqlite3PcacheSetPageSize(p, szPage);
185 } 188 }
186 189
187 /* 190 /*
188 ** Change the page size for PCache object. The caller must ensure that there 191 ** Change the page size for PCache object. The caller must ensure that there
189 ** are no outstanding page references when this function is called. 192 ** are no outstanding page references when this function is called.
190 */ 193 */
191 void sqlite3PcacheSetPageSize(PCache *pCache, int szPage){ 194 int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
192 assert( pCache->nRef==0 && pCache->pDirty==0 ); 195 assert( pCache->nRef==0 && pCache->pDirty==0 );
193 if( pCache->pCache ){ 196 if( pCache->szPage ){
194 sqlite3GlobalConfig.pcache.xDestroy(pCache->pCache); 197 sqlite3_pcache *pNew;
195 pCache->pCache = 0; 198 pNew = sqlite3GlobalConfig.pcache2.xCreate(
199 szPage, pCache->szExtra + sizeof(PgHdr), pCache->bPurgeable
200 );
201 if( pNew==0 ) return SQLITE_NOMEM;
202 sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache));
203 if( pCache->pCache ){
204 sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
205 }
206 pCache->pCache = pNew;
196 pCache->pPage1 = 0; 207 pCache->pPage1 = 0;
197 } 208 pCache->szPage = szPage;
198 pCache->szPage = szPage; 209 }
210 return SQLITE_OK;
199 } 211 }
200 212
201 /* 213 /*
202 ** Try to obtain a page from the cache. 214 ** Try to obtain a page from the cache.
203 */ 215 **
204 int sqlite3PcacheFetch( 216 ** This routine returns a pointer to an sqlite3_pcache_page object if
217 ** such an object is already in cache, or if a new one is created.
218 ** This routine returns a NULL pointer if the object was not in cache
219 ** and could not be created.
220 **
221 ** The createFlags should be 0 to check for existing pages and should
222 ** be 3 (not 1, but 3) to try to create a new page.
223 **
224 ** If the createFlag is 0, then NULL is always returned if the page
225 ** is not already in the cache. If createFlag is 1, then a new page
226 ** is created only if that can be done without spilling dirty pages
227 ** and without exceeding the cache size limit.
228 **
229 ** The caller needs to invoke sqlite3PcacheFetchFinish() to properly
230 ** initialize the sqlite3_pcache_page object and convert it into a
231 ** PgHdr object. The sqlite3PcacheFetch() and sqlite3PcacheFetchFinish()
232 ** routines are split this way for performance reasons. When separated
233 ** they can both (usually) operate without having to push values to
234 ** the stack on entry and pop them back off on exit, which saves a
235 ** lot of pushing and popping.
236 */
237 sqlite3_pcache_page *sqlite3PcacheFetch(
205 PCache *pCache, /* Obtain the page from this cache */ 238 PCache *pCache, /* Obtain the page from this cache */
206 Pgno pgno, /* Page number to obtain */ 239 Pgno pgno, /* Page number to obtain */
207 int createFlag, /* If true, create page if it does not exist already */ 240 int createFlag /* If true, create page if it does not exist already */
208 PgHdr **ppPage /* Write the page here */ 241 ){
209 ){
210 PgHdr *pPage = 0;
211 int eCreate; 242 int eCreate;
212 243
213 assert( pCache!=0 ); 244 assert( pCache!=0 );
214 assert( createFlag==1 || createFlag==0 ); 245 assert( pCache->pCache!=0 );
246 assert( createFlag==3 || createFlag==0 );
215 assert( pgno>0 ); 247 assert( pgno>0 );
216 248
217 /* If the pluggable cache (sqlite3_pcache*) has not been allocated, 249 /* eCreate defines what to do if the page does not exist.
218 ** allocate it now. 250 ** 0 Do not allocate a new page. (createFlag==0)
251 ** 1 Allocate a new page if doing so is inexpensive.
252 ** (createFlag==1 AND bPurgeable AND pDirty)
253 ** 2 Allocate a new page even it doing so is difficult.
254 ** (createFlag==1 AND !(bPurgeable AND pDirty)
219 */ 255 */
220 if( !pCache->pCache && createFlag ){ 256 eCreate = createFlag & pCache->eCreate;
221 sqlite3_pcache *p; 257 assert( eCreate==0 || eCreate==1 || eCreate==2 );
222 int nByte; 258 assert( createFlag==0 || pCache->eCreate==eCreate );
223 nByte = pCache->szPage + pCache->szExtra + sizeof(PgHdr); 259 assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) );
224 p = sqlite3GlobalConfig.pcache.xCreate(nByte, pCache->bPurgeable); 260 return sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
225 if( !p ){ 261 }
226 return SQLITE_NOMEM; 262
263 /*
264 ** If the sqlite3PcacheFetch() routine is unable to allocate a new
265 ** page because new clean pages are available for reuse and the cache
266 ** size limit has been reached, then this routine can be invoked to
267 ** try harder to allocate a page. This routine might invoke the stress
268 ** callback to spill dirty pages to the journal. It will then try to
269 ** allocate the new page and will only fail to allocate a new page on
270 ** an OOM error.
271 **
272 ** This routine should be invoked only after sqlite3PcacheFetch() fails.
273 */
274 int sqlite3PcacheFetchStress(
275 PCache *pCache, /* Obtain the page from this cache */
276 Pgno pgno, /* Page number to obtain */
277 sqlite3_pcache_page **ppPage /* Write result here */
278 ){
279 PgHdr *pPg;
280 if( pCache->eCreate==2 ) return 0;
281
282
283 /* Find a dirty page to write-out and recycle. First try to find a
284 ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
285 ** cleared), but if that is not possible settle for any other
286 ** unreferenced dirty page.
287 */
288 for(pPg=pCache->pSynced;
289 pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC));
290 pPg=pPg->pDirtyPrev
291 );
292 pCache->pSynced = pPg;
293 if( !pPg ){
294 for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev);
295 }
296 if( pPg ){
297 int rc;
298 #ifdef SQLITE_LOG_CACHE_SPILL
299 sqlite3_log(SQLITE_FULL,
300 "spill page %d making room for %d - cache used: %d/%d",
301 pPg->pgno, pgno,
302 sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache),
303 numberOfCachePages(pCache));
304 #endif
305 rc = pCache->xStress(pCache->pStress, pPg);
306 if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
307 return rc;
227 } 308 }
228 sqlite3GlobalConfig.pcache.xCachesize(p, pCache->nMax); 309 }
229 pCache->pCache = p; 310 *ppPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2);
230 } 311 return *ppPage==0 ? SQLITE_NOMEM : SQLITE_OK;
231 312 }
232 eCreate = createFlag * (1 + (!pCache->bPurgeable || !pCache->pDirty)); 313
233 if( pCache->pCache ){ 314 /*
234 pPage = sqlite3GlobalConfig.pcache.xFetch(pCache->pCache, pgno, eCreate); 315 ** This is a helper routine for sqlite3PcacheFetchFinish()
235 } 316 **
236 317 ** In the uncommon case where the page being fetched has not been
237 if( !pPage && eCreate==1 ){ 318 ** initialized, this routine is invoked to do the initialization.
238 PgHdr *pPg; 319 ** This routine is broken out into a separate function since it
239 320 ** requires extra stack manipulation that can be avoided in the common
240 /* Find a dirty page to write-out and recycle. First try to find a 321 ** case.
241 ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC 322 */
242 ** cleared), but if that is not possible settle for any other 323 static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit(
243 ** unreferenced dirty page. 324 PCache *pCache, /* Obtain the page from this cache */
244 */ 325 Pgno pgno, /* Page number obtained */
245 expensive_assert( pcacheCheckSynced(pCache) ); 326 sqlite3_pcache_page *pPage /* Page obtained by prior PcacheFetch() call */
246 for(pPg=pCache->pSynced; 327 ){
247 pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); 328 PgHdr *pPgHdr;
248 pPg=pPg->pDirtyPrev 329 assert( pPage!=0 );
249 ); 330 pPgHdr = (PgHdr*)pPage->pExtra;
250 pCache->pSynced = pPg; 331 assert( pPgHdr->pPage==0 );
251 if( !pPg ){ 332 memset(pPgHdr, 0, sizeof(PgHdr));
252 for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev); 333 pPgHdr->pPage = pPage;
253 } 334 pPgHdr->pData = pPage->pBuf;
254 if( pPg ){ 335 pPgHdr->pExtra = (void *)&pPgHdr[1];
255 int rc; 336 memset(pPgHdr->pExtra, 0, pCache->szExtra);
256 rc = pCache->xStress(pCache->pStress, pPg); 337 pPgHdr->pCache = pCache;
257 if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ 338 pPgHdr->pgno = pgno;
258 return rc; 339 return sqlite3PcacheFetchFinish(pCache,pgno,pPage);
259 } 340 }
260 } 341
261 342 /*
262 pPage = sqlite3GlobalConfig.pcache.xFetch(pCache->pCache, pgno, 2); 343 ** This routine converts the sqlite3_pcache_page object returned by
263 } 344 ** sqlite3PcacheFetch() into an initialized PgHdr object. This routine
264 345 ** must be called after sqlite3PcacheFetch() in order to get a usable
265 if( pPage ){ 346 ** result.
266 if( !pPage->pData ){ 347 */
267 memset(pPage, 0, sizeof(PgHdr)); 348 PgHdr *sqlite3PcacheFetchFinish(
268 pPage->pData = (void *)&pPage[1]; 349 PCache *pCache, /* Obtain the page from this cache */
269 pPage->pExtra = (void*)&((char *)pPage->pData)[pCache->szPage]; 350 Pgno pgno, /* Page number obtained */
270 memset(pPage->pExtra, 0, pCache->szExtra); 351 sqlite3_pcache_page *pPage /* Page obtained by prior PcacheFetch() call */
271 pPage->pCache = pCache; 352 ){
272 pPage->pgno = pgno; 353 PgHdr *pPgHdr;
273 } 354
274 assert( pPage->pCache==pCache ); 355 if( pPage==0 ) return 0;
275 assert( pPage->pgno==pgno ); 356 pPgHdr = (PgHdr *)pPage->pExtra;
276 assert( pPage->pData==(void *)&pPage[1] ); 357
277 assert( pPage->pExtra==(void *)&((char *)&pPage[1])[pCache->szPage] ); 358 if( !pPgHdr->pPage ){
278 359 return pcacheFetchFinishWithInit(pCache, pgno, pPage);
279 if( 0==pPage->nRef ){ 360 }
280 pCache->nRef++; 361 if( 0==pPgHdr->nRef ){
281 } 362 pCache->nRef++;
282 pPage->nRef++; 363 }
283 if( pgno==1 ){ 364 pPgHdr->nRef++;
284 pCache->pPage1 = pPage; 365 if( pgno==1 ){
285 } 366 pCache->pPage1 = pPgHdr;
286 } 367 }
287 *ppPage = pPage; 368 return pPgHdr;
288 return (pPage==0 && eCreate) ? SQLITE_NOMEM : SQLITE_OK;
289 } 369 }
290 370
291 /* 371 /*
292 ** Decrement the reference count on a page. If the page is clean and the 372 ** Decrement the reference count on a page. If the page is clean and the
293 ** reference count drops to 0, then it is made elible for recycling. 373 ** reference count drops to 0, then it is made eligible for recycling.
294 */ 374 */
295 void sqlite3PcacheRelease(PgHdr *p){ 375 void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
296 assert( p->nRef>0 ); 376 assert( p->nRef>0 );
297 p->nRef--; 377 p->nRef--;
298 if( p->nRef==0 ){ 378 if( p->nRef==0 ){
299 PCache *pCache = p->pCache; 379 p->pCache->nRef--;
300 pCache->nRef--;
301 if( (p->flags&PGHDR_DIRTY)==0 ){ 380 if( (p->flags&PGHDR_DIRTY)==0 ){
302 pcacheUnpin(p); 381 pcacheUnpin(p);
303 }else{ 382 }else if( p->pDirtyPrev!=0 ){
304 /* Move the page to the head of the dirty list. */ 383 /* Move the page to the head of the dirty list. */
305 pcacheRemoveFromDirtyList(p); 384 pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
306 pcacheAddToDirtyList(p);
307 } 385 }
308 } 386 }
309 } 387 }
310 388
311 /* 389 /*
312 ** Increase the reference count of a supplied page by 1. 390 ** Increase the reference count of a supplied page by 1.
313 */ 391 */
314 void sqlite3PcacheRef(PgHdr *p){ 392 void sqlite3PcacheRef(PgHdr *p){
315 assert(p->nRef>0); 393 assert(p->nRef>0);
316 p->nRef++; 394 p->nRef++;
317 } 395 }
318 396
319 /* 397 /*
320 ** Drop a page from the cache. There must be exactly one reference to the 398 ** Drop a page from the cache. There must be exactly one reference to the
321 ** page. This function deletes that reference, so after it returns the 399 ** page. This function deletes that reference, so after it returns the
322 ** page pointed to by p is invalid. 400 ** page pointed to by p is invalid.
323 */ 401 */
324 void sqlite3PcacheDrop(PgHdr *p){ 402 void sqlite3PcacheDrop(PgHdr *p){
325 PCache *pCache;
326 assert( p->nRef==1 ); 403 assert( p->nRef==1 );
327 if( p->flags&PGHDR_DIRTY ){ 404 if( p->flags&PGHDR_DIRTY ){
328 pcacheRemoveFromDirtyList(p); 405 pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
329 } 406 }
330 pCache = p->pCache; 407 p->pCache->nRef--;
331 pCache->nRef--;
332 if( p->pgno==1 ){ 408 if( p->pgno==1 ){
333 pCache->pPage1 = 0; 409 p->pCache->pPage1 = 0;
334 } 410 }
335 sqlite3GlobalConfig.pcache.xUnpin(pCache->pCache, p, 1); 411 sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 1);
336 } 412 }
337 413
338 /* 414 /*
339 ** Make sure the page is marked as dirty. If it isn't dirty already, 415 ** Make sure the page is marked as dirty. If it isn't dirty already,
340 ** make it so. 416 ** make it so.
341 */ 417 */
342 void sqlite3PcacheMakeDirty(PgHdr *p){ 418 void sqlite3PcacheMakeDirty(PgHdr *p){
343 p->flags &= ~PGHDR_DONT_WRITE; 419 p->flags &= ~PGHDR_DONT_WRITE;
344 assert( p->nRef>0 ); 420 assert( p->nRef>0 );
345 if( 0==(p->flags & PGHDR_DIRTY) ){ 421 if( 0==(p->flags & PGHDR_DIRTY) ){
346 p->flags |= PGHDR_DIRTY; 422 p->flags |= PGHDR_DIRTY;
347 pcacheAddToDirtyList( p); 423 pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD);
348 } 424 }
349 } 425 }
350 426
351 /* 427 /*
352 ** Make sure the page is marked as clean. If it isn't clean already, 428 ** Make sure the page is marked as clean. If it isn't clean already,
353 ** make it so. 429 ** make it so.
354 */ 430 */
355 void sqlite3PcacheMakeClean(PgHdr *p){ 431 void sqlite3PcacheMakeClean(PgHdr *p){
356 if( (p->flags & PGHDR_DIRTY) ){ 432 if( (p->flags & PGHDR_DIRTY) ){
357 pcacheRemoveFromDirtyList(p); 433 pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
358 p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC); 434 p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC);
359 if( p->nRef==0 ){ 435 if( p->nRef==0 ){
360 pcacheUnpin(p); 436 pcacheUnpin(p);
361 } 437 }
362 } 438 }
363 } 439 }
364 440
365 /* 441 /*
366 ** Make every page in the cache clean. 442 ** Make every page in the cache clean.
367 */ 443 */
(...skipping 15 matching lines...) Expand all
383 pCache->pSynced = pCache->pDirtyTail; 459 pCache->pSynced = pCache->pDirtyTail;
384 } 460 }
385 461
386 /* 462 /*
387 ** Change the page number of page p to newPgno. 463 ** Change the page number of page p to newPgno.
388 */ 464 */
389 void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){ 465 void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
390 PCache *pCache = p->pCache; 466 PCache *pCache = p->pCache;
391 assert( p->nRef>0 ); 467 assert( p->nRef>0 );
392 assert( newPgno>0 ); 468 assert( newPgno>0 );
393 sqlite3GlobalConfig.pcache.xRekey(pCache->pCache, p, p->pgno, newPgno); 469 sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno);
394 p->pgno = newPgno; 470 p->pgno = newPgno;
395 if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){ 471 if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
396 pcacheRemoveFromDirtyList(p); 472 pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
397 pcacheAddToDirtyList(p);
398 } 473 }
399 } 474 }
400 475
401 /* 476 /*
402 ** Drop every cache entry whose page number is greater than "pgno". The 477 ** Drop every cache entry whose page number is greater than "pgno". The
403 ** caller must ensure that there are no outstanding references to any pages 478 ** caller must ensure that there are no outstanding references to any pages
404 ** other than page 1 with a page number greater than pgno. 479 ** other than page 1 with a page number greater than pgno.
405 ** 480 **
406 ** If there is a reference to page 1 and the pgno parameter passed to this 481 ** If there is a reference to page 1 and the pgno parameter passed to this
407 ** function is 0, then the data area associated with page 1 is zeroed, but 482 ** function is 0, then the data area associated with page 1 is zeroed, but
(...skipping 12 matching lines...) Expand all
420 assert( p->pgno>0 ); 495 assert( p->pgno>0 );
421 if( ALWAYS(p->pgno>pgno) ){ 496 if( ALWAYS(p->pgno>pgno) ){
422 assert( p->flags&PGHDR_DIRTY ); 497 assert( p->flags&PGHDR_DIRTY );
423 sqlite3PcacheMakeClean(p); 498 sqlite3PcacheMakeClean(p);
424 } 499 }
425 } 500 }
426 if( pgno==0 && pCache->pPage1 ){ 501 if( pgno==0 && pCache->pPage1 ){
427 memset(pCache->pPage1->pData, 0, pCache->szPage); 502 memset(pCache->pPage1->pData, 0, pCache->szPage);
428 pgno = 1; 503 pgno = 1;
429 } 504 }
430 sqlite3GlobalConfig.pcache.xTruncate(pCache->pCache, pgno+1); 505 sqlite3GlobalConfig.pcache2.xTruncate(pCache->pCache, pgno+1);
431 } 506 }
432 } 507 }
433 508
434 /* 509 /*
435 ** Close a cache. 510 ** Close a cache.
436 */ 511 */
437 void sqlite3PcacheClose(PCache *pCache){ 512 void sqlite3PcacheClose(PCache *pCache){
438 if( pCache->pCache ){ 513 assert( pCache->pCache!=0 );
439 sqlite3GlobalConfig.pcache.xDestroy(pCache->pCache); 514 sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
440 }
441 } 515 }
442 516
443 /* 517 /*
444 ** Discard the contents of the cache. 518 ** Discard the contents of the cache.
445 */ 519 */
446 void sqlite3PcacheClear(PCache *pCache){ 520 void sqlite3PcacheClear(PCache *pCache){
447 sqlite3PcacheTruncate(pCache, 0); 521 sqlite3PcacheTruncate(pCache, 0);
448 } 522 }
449 523
450 /* 524 /*
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
539 ** Return the number of references to the page supplied as an argument. 613 ** Return the number of references to the page supplied as an argument.
540 */ 614 */
541 int sqlite3PcachePageRefcount(PgHdr *p){ 615 int sqlite3PcachePageRefcount(PgHdr *p){
542 return p->nRef; 616 return p->nRef;
543 } 617 }
544 618
545 /* 619 /*
546 ** Return the total number of pages in the cache. 620 ** Return the total number of pages in the cache.
547 */ 621 */
548 int sqlite3PcachePagecount(PCache *pCache){ 622 int sqlite3PcachePagecount(PCache *pCache){
549 int nPage = 0; 623 assert( pCache->pCache!=0 );
550 if( pCache->pCache ){ 624 return sqlite3GlobalConfig.pcache2.xPagecount(pCache->pCache);
551 nPage = sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache);
552 }
553 return nPage;
554 } 625 }
555 626
556 #ifdef SQLITE_TEST 627 #ifdef SQLITE_TEST
557 /* 628 /*
558 ** Get the suggested cache-size value. 629 ** Get the suggested cache-size value.
559 */ 630 */
560 int sqlite3PcacheGetCachesize(PCache *pCache){ 631 int sqlite3PcacheGetCachesize(PCache *pCache){
561 return pCache->nMax; 632 return numberOfCachePages(pCache);
562 } 633 }
563 #endif 634 #endif
564 635
565 /* 636 /*
566 ** Set the suggested cache-size value. 637 ** Set the suggested cache-size value.
567 */ 638 */
568 void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){ 639 void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
569 pCache->nMax = mxPage; 640 assert( pCache->pCache!=0 );
570 if( pCache->pCache ){ 641 pCache->szCache = mxPage;
571 sqlite3GlobalConfig.pcache.xCachesize(pCache->pCache, mxPage); 642 sqlite3GlobalConfig.pcache2.xCachesize(pCache->pCache,
572 } 643 numberOfCachePages(pCache));
644 }
645
646 /*
647 ** Free up as much memory as possible from the page cache.
648 */
649 void sqlite3PcacheShrink(PCache *pCache){
650 assert( pCache->pCache!=0 );
651 sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache);
573 } 652 }
574 653
575 #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG) 654 #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
576 /* 655 /*
577 ** For all dirty pages currently in the cache, invoke the specified 656 ** For all dirty pages currently in the cache, invoke the specified
578 ** callback. This is only used if the SQLITE_CHECK_PAGES macro is 657 ** callback. This is only used if the SQLITE_CHECK_PAGES macro is
579 ** defined. 658 ** defined.
580 */ 659 */
581 void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)){ 660 void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)){
582 PgHdr *pDirty; 661 PgHdr *pDirty;
583 for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext){ 662 for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext){
584 xIter(pDirty); 663 xIter(pDirty);
585 } 664 }
586 } 665 }
587 #endif 666 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698