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