15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 2008 November 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)**
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This file implements the default page cache implementation (the
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** sqlite3_pcache interface). It also contains part of the implementation
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** of the SQLITE_CONFIG_PAGECACHE and sqlite3_release_memory() features.
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** If the default page cache implementation is overriden, then neither of
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** these two features are available.
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sqliteInt.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct PCache1 PCache1;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct PgHdr1 PgHdr1;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct PgFreeslot PgFreeslot;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct PGroup PGroup;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Each page cache (or PCache) belongs to a PGroup.  A PGroup is a set
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** of one or more PCaches that are able to recycle each others unpinned
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** pages when they are under memory pressure.  A PGroup is an instance of
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** the following object.
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This page cache implementation works in one of two modes:
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**   (1)  Every PCache is the sole member of its own PGroup.  There is
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**        one PGroup per PCache.
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**   (2)  There is a single global PGroup that all PCaches are a member
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**        of.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Mode 1 uses more memory (since PCache instances are not able to rob
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** unused pages from other PCaches) but it also operates without a mutex,
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** and is therefore often faster.  Mode 2 requires a mutex in order to be
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** threadsafe, but is able recycle pages more efficient.
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** For mode (1), PGroup.mutex is NULL.  For mode (2) there is only a single
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** PGroup which is the pcache1.grp global variable and its mutex is
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** SQLITE_MUTEX_STATIC_LRU.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct PGroup {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_mutex *mutex;          /* MUTEX_STATIC_LRU or NULL */
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nMaxPage;                  /* Sum of nMax for purgeable caches */
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nMinPage;                  /* Sum of nMin for purgeable caches */
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int mxPinned;                  /* nMaxpage + 10 - nMinPage */
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nCurrentPage;              /* Number of purgeable pages allocated */
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgHdr1 *pLruHead, *pLruTail;   /* LRU list of unpinned pages */
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Each page cache is an instance of the following object.  Every
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** open database file (including each in-memory database and each
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** temporary or transient database) has a single page cache which
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** is an instance of this object.
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Pointers to structures of this type are cast and returned as
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** opaque sqlite3_pcache* handles.
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct PCache1 {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Cache configuration parameters. Page size (szPage) and the purgeable
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** flag (bPurgeable) are set when the cache is created. nMax may be
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** modified at any time by a call to the pcache1CacheSize() method.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** The PGroup mutex must be held when accessing nMax.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  */
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PGroup *pGroup;                     /* PGroup this cache belongs to */
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int szPage;                         /* Size of allocated pages in bytes */
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int bPurgeable;                     /* True if cache is purgeable */
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int nMin;                  /* Minimum number of pages reserved */
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int nMax;                  /* Configured "cache_size" value */
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int n90pct;                /* nMax*9/10 */
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Hash table of all pages. The following variables may only be accessed
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** when the accessor is holding the PGroup mutex.
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  */
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int nRecyclable;           /* Number of pages in the LRU list */
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int nPage;                 /* Total number of pages in apHash */
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int nHash;                 /* Number of slots in apHash[] */
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgHdr1 **apHash;                    /* Hash table for fast lookup by key */
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int iMaxKey;               /* Largest key seen since xTruncate() */
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Each cache entry is represented by an instance of the following
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** structure. A buffer of PgHdr1.pCache->szPage bytes is allocated
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** directly before this structure in memory (see the PGHDR1_TO_PAGE()
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** macro below).
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct PgHdr1 {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int iKey;             /* Key value (page number) */
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgHdr1 *pNext;                 /* Next in hash table chain */
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PCache1 *pCache;               /* Cache that currently owns this page */
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgHdr1 *pLruNext;              /* Next in LRU list of unpinned pages */
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgHdr1 *pLruPrev;              /* Previous in LRU list of unpinned pages */
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Free slots in the allocator used to divide up the buffer provided using
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** the SQLITE_CONFIG_PAGECACHE mechanism.
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct PgFreeslot {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgFreeslot *pNext;  /* Next free slot */
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Global data used by this cache.
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static SQLITE_WSD struct PCacheGlobal {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PGroup grp;                    /* The global PGroup for mode (2) */
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Variables related to SQLITE_CONFIG_PAGECACHE settings.  The
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** szSlot, nSlot, pStart, pEnd, nReserve, and isInit values are all
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** fixed at sqlite3_initialize() time and do not require mutex protection.
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** The nFreeSlot and pFree values do require mutex protection.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  */
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int isInit;                    /* True if initialized */
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int szSlot;                    /* Size of each free slot */
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nSlot;                     /* The number of pcache slots */
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nReserve;                  /* Try to keep nFreeSlot above this */
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void *pStart, *pEnd;           /* Bounds of pagecache malloc range */
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Above requires no mutex.  Use mutex below for variable that follow. */
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_mutex *mutex;          /* Mutex for accessing the following: */
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nFreeSlot;                 /* Number of unused pcache slots */
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgFreeslot *pFree;             /* Free page blocks */
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* The following value requires a mutex to change.  We skip the mutex on
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** reading because (1) most platforms read a 32-bit integer atomically and
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** (2) even if an incorrect value is read, no great harm is done since this
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** is really just an optimization. */
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int bUnderPressure;            /* True if low on PAGECACHE memory */
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} pcache1_g;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** All code in this file should access the global structure above via the
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** alias "pcache1". This ensures that the WSD emulation is used when
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** compiling for systems that do not support real WSD.
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define pcache1 (GLOBAL(struct PCacheGlobal, pcache1_g))
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** When a PgHdr1 structure is allocated, the associated PCache1.szPage
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** bytes of data are located directly before it in memory (i.e. the total
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** size of the allocation is sizeof(PgHdr1)+PCache1.szPage byte). The
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** PGHDR1_TO_PAGE() macro takes a pointer to a PgHdr1 structure as
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** an argument and returns a pointer to the associated block of szPage
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** bytes. The PAGE_TO_PGHDR1() macro does the opposite: its argument is
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** a pointer to a block of szPage bytes of data and the return value is
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** a pointer to the associated PgHdr1 structure.
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**   assert( PGHDR1_TO_PAGE(PAGE_TO_PGHDR1(pCache, X))==X );
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define PGHDR1_TO_PAGE(p)    (void*)(((char*)p) - p->pCache->szPage)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define PAGE_TO_PGHDR1(c, p) (PgHdr1*)(((char*)p) + c->szPage)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Macros to enter and leave the PCache LRU mutex.
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define pcache1EnterMutex(X) sqlite3_mutex_enter((X)->mutex)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define pcache1LeaveMutex(X) sqlite3_mutex_leave((X)->mutex)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/******************************************************************************/
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/******** Page Allocation/SQLITE_CONFIG_PCACHE Related Functions **************/
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This function is called during initialization if a static buffer is
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** supplied to use for the page-cache by passing the SQLITE_CONFIG_PAGECACHE
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** verb to sqlite3_config(). Parameter pBuf points to an allocation large
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** enough to contain 'n' buffers of 'sz' bytes each.
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This routine is called from sqlite3_initialize() and so it is guaranteed
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** to be serialized already.  There is no need for further mutexing.
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pcache1.isInit ){
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PgFreeslot *p;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sz = ROUNDDOWN8(sz);
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1.szSlot = sz;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1.nSlot = pcache1.nFreeSlot = n;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1.nReserve = n>90 ? 10 : (n/10 + 1);
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1.pStart = pBuf;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1.pFree = 0;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1.bUnderPressure = 0;
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while( n-- ){
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      p = (PgFreeslot*)pBuf;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      p->pNext = pcache1.pFree;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pcache1.pFree = p;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pBuf = (void*)&((char*)pBuf)[sz];
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1.pEnd = pBuf;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Malloc function used within this file to allocate space from the buffer
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** configured using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** such buffer exists or there is no space left in it, this function falls
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** back to sqlite3Malloc().
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Multiple threads can run this routine at the same time.  Global variables
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** in pcache1 need to be protected via mutex.
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void *pcache1Alloc(int nByte){
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void *p = 0;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( nByte<=pcache1.szSlot ){
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_mutex_enter(pcache1.mutex);
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p = (PgHdr1 *)pcache1.pFree;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( p ){
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pcache1.pFree = pcache1.pFree->pNext;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pcache1.nFreeSlot--;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pcache1.bUnderPressure = pcache1.nFreeSlot<pcache1.nReserve;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert( pcache1.nFreeSlot>=0 );
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, 1);
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_mutex_leave(pcache1.mutex);
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( p==0 ){
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* Memory is not available in the SQLITE_CONFIG_PAGECACHE pool.  Get
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ** it from sqlite3Malloc instead.
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    */
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p = sqlite3Malloc(nByte);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( p ){
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int sz = sqlite3MallocSize(p);
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sqlite3_mutex_enter(pcache1.mutex);
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sqlite3_mutex_leave(pcache1.mutex);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3MemdebugSetType(p, MEMTYPE_PCACHE);
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return p;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Free an allocated buffer obtained from pcache1Alloc().
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void pcache1Free(void *p){
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( p==0 ) return;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( p>=pcache1.pStart && p<pcache1.pEnd ){
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PgFreeslot *pSlot;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_mutex_enter(pcache1.mutex);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, -1);
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pSlot = (PgFreeslot*)p;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pSlot->pNext = pcache1.pFree;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1.pFree = pSlot;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1.nFreeSlot++;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1.bUnderPressure = pcache1.nFreeSlot<pcache1.nReserve;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert( pcache1.nFreeSlot<=pcache1.nSlot );
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_mutex_leave(pcache1.mutex);
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int iSize;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    iSize = sqlite3MallocSize(p);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_mutex_enter(pcache1.mutex);
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -iSize);
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_mutex_leave(pcache1.mutex);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_free(p);
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Return the size of a pcache allocation
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pcache1MemSize(void *p){
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( p>=pcache1.pStart && p<pcache1.pEnd ){
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return pcache1.szSlot;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int iSize;
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    iSize = sqlite3MallocSize(p);
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3MemdebugSetType(p, MEMTYPE_PCACHE);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return iSize;
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Allocate a new page object initially associated with cache pCache.
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nByte = sizeof(PgHdr1) + pCache->szPage;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void *pPg = pcache1Alloc(nByte);
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgHdr1 *p;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pPg ){
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p = PAGE_TO_PGHDR1(pCache, pPg);
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pCache->bPurgeable ){
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pCache->pGroup->nCurrentPage++;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p = 0;
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return p;
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Free a page object allocated by pcache1AllocPage().
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The pointer is allowed to be NULL, which is prudent.  But it turns out
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** that the current implementation happens to never call this routine
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** with a NULL pointer, so we mark the NULL test with ALWAYS().
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void pcache1FreePage(PgHdr1 *p){
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( ALWAYS(p) ){
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PCache1 *pCache = p->pCache;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pCache->bPurgeable ){
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pCache->pGroup->nCurrentPage--;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1Free(PGHDR1_TO_PAGE(p));
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Malloc function used by SQLite to obtain space from the buffer configured
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no such buffer
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** exists, this function falls back to sqlite3Malloc().
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void *sqlite3PageMalloc(int sz){
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pcache1Alloc(sz);
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Free an allocated buffer obtained from sqlite3PageMalloc().
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void sqlite3PageFree(void *p){
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pcache1Free(p);
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Return true if it desirable to avoid allocating a new page cache
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** entry.
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** If memory was allocated specifically to the page cache using
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** SQLITE_CONFIG_PAGECACHE but that memory has all been used, then
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** it is desirable to avoid allocating a new page cache entry because
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** presumably SQLITE_CONFIG_PAGECACHE was suppose to be sufficient
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** for all page cache needs and we should not need to spill the
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** allocation onto the heap.
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Or, the heap is used for all page cache memory put the heap is
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** under memory pressure, then again it is desirable to avoid
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** allocating a new page cache entry in order to avoid stressing
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** the heap even further.
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pcache1UnderMemoryPressure(PCache1 *pCache){
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pcache1.nSlot && pCache->szPage<=pcache1.szSlot ){
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return pcache1.bUnderPressure;
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return sqlite3HeapNearlyFull();
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/******************************************************************************/
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/******** General Implementation Functions ************************************/
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This function is used to resize the hash table used by the cache passed
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** as the first argument.
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The PCache mutex must be held when this function is called.
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pcache1ResizeHash(PCache1 *p){
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgHdr1 **apNew;
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int nNew;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int i;
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( sqlite3_mutex_held(p->pGroup->mutex) );
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  nNew = p->nHash*2;
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( nNew<256 ){
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nNew = 256;
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pcache1LeaveMutex(p->pGroup);
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( p->nHash ){ sqlite3BeginBenignMalloc(); }
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  apNew = (PgHdr1 **)sqlite3_malloc(sizeof(PgHdr1 *)*nNew);
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( p->nHash ){ sqlite3EndBenignMalloc(); }
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pcache1EnterMutex(p->pGroup);
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( apNew ){
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(apNew, 0, sizeof(PgHdr1 *)*nNew);
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for(i=0; i<p->nHash; i++){
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PgHdr1 *pPage;
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PgHdr1 *pNext = p->apHash[i];
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while( (pPage = pNext)!=0 ){
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unsigned int h = pPage->iKey % nNew;
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pNext = pPage->pNext;
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pPage->pNext = apNew[h];
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        apNew[h] = pPage;
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_free(p->apHash);
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p->apHash = apNew;
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p->nHash = nNew;
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (p->apHash ? SQLITE_OK : SQLITE_NOMEM);
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This function is used internally to remove the page pPage from the
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** PGroup LRU list, if is part of it. If pPage is not part of the PGroup
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** LRU list, then this function is a no-op.
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The PGroup mutex must be held when this function is called.
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** If pPage is NULL then this routine is a no-op.
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void pcache1PinPage(PgHdr1 *pPage){
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PCache1 *pCache;
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PGroup *pGroup;
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pPage==0 ) return;
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCache = pPage->pCache;
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pGroup = pCache->pGroup;
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( sqlite3_mutex_held(pGroup->mutex) );
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pPage->pLruNext || pPage==pGroup->pLruTail ){
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pPage->pLruPrev ){
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pPage->pLruPrev->pLruNext = pPage->pLruNext;
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pPage->pLruNext ){
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pPage->pLruNext->pLruPrev = pPage->pLruPrev;
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pGroup->pLruHead==pPage ){
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pGroup->pLruHead = pPage->pLruNext;
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pGroup->pLruTail==pPage ){
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pGroup->pLruTail = pPage->pLruPrev;
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pPage->pLruNext = 0;
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pPage->pLruPrev = 0;
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pPage->pCache->nRecyclable--;
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Remove the page supplied as an argument from the hash table
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** (PCache1.apHash structure) that it is currently stored in.
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The PGroup mutex must be held when this function is called.
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void pcache1RemoveFromHash(PgHdr1 *pPage){
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int h;
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PCache1 *pCache = pPage->pCache;
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgHdr1 **pp;
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  h = pPage->iKey % pCache->nHash;
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(pp=&pCache->apHash[h]; (*pp)!=pPage; pp=&(*pp)->pNext);
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *pp = (*pp)->pNext;
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCache->nPage--;
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** If there are currently more than nMaxPage pages allocated, try
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** to recycle pages to reduce the number allocated to nMaxPage.
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void pcache1EnforceMaxPage(PGroup *pGroup){
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( sqlite3_mutex_held(pGroup->mutex) );
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while( pGroup->nCurrentPage>pGroup->nMaxPage && pGroup->pLruTail ){
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PgHdr1 *p = pGroup->pLruTail;
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert( p->pCache->pGroup==pGroup );
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1PinPage(p);
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1RemoveFromHash(p);
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1FreePage(p);
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Discard all pages from cache pCache with a page number (key value)
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** greater than or equal to iLimit. Any pinned pages that meet this
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** criteria are unpinned before they are discarded.
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The PCache mutex must be held when this function is called.
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void pcache1TruncateUnsafe(
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PCache1 *pCache,             /* The cache to truncate */
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int iLimit          /* Drop pages with this pgno or larger */
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TESTONLY( unsigned int nPage = 0; )  /* To assert pCache->nPage is correct */
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int h;
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(h=0; h<pCache->nHash; h++){
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PgHdr1 **pp = &pCache->apHash[h];
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PgHdr1 *pPage;
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while( (pPage = *pp)!=0 ){
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( pPage->iKey>=iLimit ){
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pCache->nPage--;
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *pp = pPage->pNext;
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pcache1PinPage(pPage);
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pcache1FreePage(pPage);
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }else{
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pp = &pPage->pNext;
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        TESTONLY( nPage++; )
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pCache->nPage==nPage );
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/******************************************************************************/
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/******** sqlite3_pcache Methods **********************************************/
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Implementation of the sqlite3_pcache.xInit method.
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pcache1Init(void *NotUsed){
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UNUSED_PARAMETER(NotUsed);
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pcache1.isInit==0 );
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&pcache1, 0, sizeof(pcache1));
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( sqlite3GlobalConfig.bCoreMutex ){
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1.grp.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PMEM);
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pcache1.grp.mxPinned = 10;
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pcache1.isInit = 1;
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SQLITE_OK;
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Implementation of the sqlite3_pcache.xShutdown method.
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Note that the static mutex allocated in xInit does
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** not need to be freed.
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void pcache1Shutdown(void *NotUsed){
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UNUSED_PARAMETER(NotUsed);
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pcache1.isInit!=0 );
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&pcache1, 0, sizeof(pcache1));
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Implementation of the sqlite3_pcache.xCreate method.
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Allocate a new cache.
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static sqlite3_pcache *pcache1Create(int szPage, int bPurgeable){
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PCache1 *pCache;      /* The newly created page cache */
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PGroup *pGroup;       /* The group the new page cache will belong to */
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int sz;               /* Bytes of memory required to allocate the new cache */
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /*
552eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ** The separateCache variable is true if each PCache has its own private
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** PGroup.  In other words, separateCache is true for mode (1) where no
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** mutexing is required.
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  **
556eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  **   *  Always use separate caches (mode-1) if SQLITE_SEPARATE_CACHE_POOLS
557eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  **
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  **   *  Always use a unified cache (mode-2) if ENABLE_MEMORY_MANAGEMENT
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  **
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  **   *  Always use a unified cache in single-threaded applications
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  **
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  **   *  Otherwise (if multi-threaded and ENABLE_MEMORY_MANAGEMENT is off)
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  **      use separate caches (mode-1)
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  */
565eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#ifdef SQLITE_SEPARATE_CACHE_POOLS
566eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const int separateCache = 1;
567eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#elif defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) || SQLITE_THREADSAFE==0
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int separateCache = 0;
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int separateCache = sqlite3GlobalConfig.bCoreMutex>0;
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sz = sizeof(PCache1) + sizeof(PGroup)*separateCache;
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCache = (PCache1 *)sqlite3_malloc(sz);
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pCache ){
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(pCache, 0, sz);
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( separateCache ){
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pGroup = (PGroup*)&pCache[1];
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pGroup->mxPinned = 10;
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }else{
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pGroup = &pcache1_g.grp;
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pCache->pGroup = pGroup;
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pCache->szPage = szPage;
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pCache->bPurgeable = (bPurgeable ? 1 : 0);
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( bPurgeable ){
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pCache->nMin = 10;
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pcache1EnterMutex(pGroup);
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pGroup->nMinPage += pCache->nMin;
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pcache1LeaveMutex(pGroup);
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (sqlite3_pcache *)pCache;
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Implementation of the sqlite3_pcache.xCachesize method.
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Configure the cache_size limit for a cache.
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void pcache1Cachesize(sqlite3_pcache *p, int nMax){
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PCache1 *pCache = (PCache1 *)p;
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pCache->bPurgeable ){
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PGroup *pGroup = pCache->pGroup;
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1EnterMutex(pGroup);
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pGroup->nMaxPage += (nMax - pCache->nMax);
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pCache->nMax = nMax;
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pCache->n90pct = pCache->nMax*9/10;
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1EnforceMaxPage(pGroup);
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1LeaveMutex(pGroup);
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Implementation of the sqlite3_pcache.xPagecount method.
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pcache1Pagecount(sqlite3_pcache *p){
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int n;
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PCache1 *pCache = (PCache1*)p;
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pcache1EnterMutex(pCache->pGroup);
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  n = pCache->nPage;
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pcache1LeaveMutex(pCache->pGroup);
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return n;
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Implementation of the sqlite3_pcache.xFetch method.
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Fetch a page by key value.
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Whether or not a new page may be allocated by this function depends on
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** the value of the createFlag argument.  0 means do not allocate a new
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** page.  1 means allocate a new page if space is easily available.  2
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** means to try really hard to allocate a new page.
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** For a non-purgeable cache (a cache used as the storage for an in-memory
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** database) there is really no difference between createFlag 1 and 2.  So
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** the calling function (pcache.c) will never have a createFlag of 1 on
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** a non-purgable cache.
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** There are three different approaches to obtaining space for a page,
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** depending on the value of parameter createFlag (which may be 0, 1 or 2).
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**   1. Regardless of the value of createFlag, the cache is searched for a
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**      copy of the requested page. If one is found, it is returned.
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**   2. If createFlag==0 and the page is not already in the cache, NULL is
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**      returned.
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**   3. If createFlag is 1, and the page is not already in the cache, then
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**      return NULL (do not allocate a new page) if any of the following
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**      conditions are true:
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**       (a) the number of pages pinned by the cache is greater than
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**           PCache1.nMax, or
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**       (b) the number of pages pinned by the cache is greater than
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**           the sum of nMax for all purgeable caches, less the sum of
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**           nMin for all other purgeable caches, or
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**   4. If none of the first three conditions apply and the cache is marked
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**      as purgeable, and if one of the following is true:
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**       (a) The number of pages allocated for the cache is already
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**           PCache1.nMax, or
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**       (b) The number of pages allocated for all purgeable caches is
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**           already equal to or greater than the sum of nMax for all
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**           purgeable caches,
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**       (c) The system is under memory pressure and wants to avoid
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**           unnecessary pages cache entry allocations
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**      then attempt to recycle a page from the LRU list. If it is the right
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**      size, return the recycled buffer. Otherwise, free the buffer and
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**      proceed to step 5.
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**   5. Otherwise, allocate and return a new page buffer.
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nPinned;
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PCache1 *pCache = (PCache1 *)p;
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PGroup *pGroup;
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgHdr1 *pPage = 0;
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pCache->bPurgeable || createFlag!=1 );
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pCache->bPurgeable || pCache->nMin==0 );
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pCache->bPurgeable==0 || pCache->nMin==10 );
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pCache->nMin==0 || pCache->bPurgeable );
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pcache1EnterMutex(pGroup = pCache->pGroup);
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Step 1: Search the hash table for an existing entry. */
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pCache->nHash>0 ){
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned int h = iKey % pCache->nHash;
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for(pPage=pCache->apHash[h]; pPage&&pPage->iKey!=iKey; pPage=pPage->pNext);
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Step 2: Abort if no existing page is found and createFlag is 0 */
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pPage || createFlag==0 ){
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1PinPage(pPage);
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    goto fetch_out;
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* The pGroup local variable will normally be initialized by the
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** pcache1EnterMutex() macro above.  But if SQLITE_MUTEX_OMIT is defined,
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** then pcache1EnterMutex() is a no-op, so we have to initialize the
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** local variable here.  Delaying the initialization of pGroup is an
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** optimization:  The common case is to exit the module before reaching
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** this point.
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  */
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef SQLITE_MUTEX_OMIT
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pGroup = pCache->pGroup;
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Step 3: Abort if createFlag is 1 but the cache is nearly full */
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  nPinned = pCache->nPage - pCache->nRecyclable;
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( nPinned>=0 );
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage );
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pCache->n90pct == pCache->nMax*9/10 );
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( createFlag==1 && (
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        nPinned>=pGroup->mxPinned
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     || nPinned>=(int)pCache->n90pct
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     || pcache1UnderMemoryPressure(pCache)
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  )){
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    goto fetch_out;
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pCache->nPage>=pCache->nHash && pcache1ResizeHash(pCache) ){
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    goto fetch_out;
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Step 4. Try to recycle a page. */
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pCache->bPurgeable && pGroup->pLruTail && (
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         (pCache->nPage+1>=pCache->nMax)
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      || pGroup->nCurrentPage>=pGroup->nMaxPage
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      || pcache1UnderMemoryPressure(pCache)
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  )){
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PCache1 *pOtherCache;
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pPage = pGroup->pLruTail;
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1RemoveFromHash(pPage);
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1PinPage(pPage);
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( (pOtherCache = pPage->pCache)->szPage!=pCache->szPage ){
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pcache1FreePage(pPage);
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pPage = 0;
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }else{
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pGroup->nCurrentPage -=
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               (pOtherCache->bPurgeable - pCache->bPurgeable);
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Step 5. If a usable page buffer has still not been found,
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** attempt to allocate a new one.
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  */
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( !pPage ){
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( createFlag==1 ) sqlite3BeginBenignMalloc();
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1LeaveMutex(pGroup);
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pPage = pcache1AllocPage(pCache);
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1EnterMutex(pGroup);
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( createFlag==1 ) sqlite3EndBenignMalloc();
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pPage ){
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned int h = iKey % pCache->nHash;
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pCache->nPage++;
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pPage->iKey = iKey;
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pPage->pNext = pCache->apHash[h];
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pPage->pCache = pCache;
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pPage->pLruPrev = 0;
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pPage->pLruNext = 0;
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *(void **)(PGHDR1_TO_PAGE(pPage)) = 0;
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pCache->apHash[h] = pPage;
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)fetch_out:
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pPage && iKey>pCache->iMaxKey ){
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pCache->iMaxKey = iKey;
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pcache1LeaveMutex(pGroup);
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (pPage ? PGHDR1_TO_PAGE(pPage) : 0);
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Implementation of the sqlite3_pcache.xUnpin method.
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Mark a page as unpinned (eligible for asynchronous recycling).
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void pcache1Unpin(sqlite3_pcache *p, void *pPg, int reuseUnlikely){
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PCache1 *pCache = (PCache1 *)p;
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgHdr1 *pPage = PAGE_TO_PGHDR1(pCache, pPg);
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PGroup *pGroup = pCache->pGroup;
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pPage->pCache==pCache );
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pcache1EnterMutex(pGroup);
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* It is an error to call this function if the page is already
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** part of the PGroup LRU list.
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  */
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pPage->pLruPrev==0 && pPage->pLruNext==0 );
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pGroup->pLruHead!=pPage && pGroup->pLruTail!=pPage );
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( reuseUnlikely || pGroup->nCurrentPage>pGroup->nMaxPage ){
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1RemoveFromHash(pPage);
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1FreePage(pPage);
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* Add the page to the PGroup LRU list. */
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pGroup->pLruHead ){
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pGroup->pLruHead->pLruPrev = pPage;
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pPage->pLruNext = pGroup->pLruHead;
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pGroup->pLruHead = pPage;
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }else{
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pGroup->pLruTail = pPage;
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pGroup->pLruHead = pPage;
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pCache->nRecyclable++;
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pcache1LeaveMutex(pCache->pGroup);
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Implementation of the sqlite3_pcache.xRekey method.
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void pcache1Rekey(
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_pcache *p,
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void *pPg,
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int iOld,
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int iNew
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PCache1 *pCache = (PCache1 *)p;
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgHdr1 *pPage = PAGE_TO_PGHDR1(pCache, pPg);
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgHdr1 **pp;
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int h;
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pPage->iKey==iOld );
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pPage->pCache==pCache );
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pcache1EnterMutex(pCache->pGroup);
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  h = iOld%pCache->nHash;
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp = &pCache->apHash[h];
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while( (*pp)!=pPage ){
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pp = &(*pp)->pNext;
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *pp = pPage->pNext;
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  h = iNew%pCache->nHash;
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pPage->iKey = iNew;
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pPage->pNext = pCache->apHash[h];
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCache->apHash[h] = pPage;
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( iNew>pCache->iMaxKey ){
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pCache->iMaxKey = iNew;
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pcache1LeaveMutex(pCache->pGroup);
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Implementation of the sqlite3_pcache.xTruncate method.
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Discard all unpinned pages in the cache with a page number equal to
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** or greater than parameter iLimit. Any pinned pages with a page number
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** equal to or greater than iLimit are implicitly unpinned.
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void pcache1Truncate(sqlite3_pcache *p, unsigned int iLimit){
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PCache1 *pCache = (PCache1 *)p;
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pcache1EnterMutex(pCache->pGroup);
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( iLimit<=pCache->iMaxKey ){
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1TruncateUnsafe(pCache, iLimit);
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pCache->iMaxKey = iLimit-1;
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pcache1LeaveMutex(pCache->pGroup);
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Implementation of the sqlite3_pcache.xDestroy method.
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Destroy a cache allocated using pcache1Create().
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void pcache1Destroy(sqlite3_pcache *p){
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PCache1 *pCache = (PCache1 *)p;
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PGroup *pGroup = pCache->pGroup;
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pCache->bPurgeable || (pCache->nMax==0 && pCache->nMin==0) );
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pcache1EnterMutex(pGroup);
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pcache1TruncateUnsafe(pCache, 0);
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pGroup->nMaxPage -= pCache->nMax;
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pGroup->nMinPage -= pCache->nMin;
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pcache1EnforceMaxPage(pGroup);
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pcache1LeaveMutex(pGroup);
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_free(pCache->apHash);
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_free(pCache);
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This function is called during initialization (sqlite3_initialize()) to
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** install the default pluggable cache module, assuming the user has not
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** already provided an alternative.
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void sqlite3PCacheSetDefault(void){
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const sqlite3_pcache_methods defaultMethods = {
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    0,                       /* pArg */
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1Init,             /* xInit */
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1Shutdown,         /* xShutdown */
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1Create,           /* xCreate */
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1Cachesize,        /* xCachesize */
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1Pagecount,        /* xPagecount */
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1Fetch,            /* xFetch */
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1Unpin,            /* xUnpin */
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1Rekey,            /* xRekey */
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1Truncate,         /* xTruncate */
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1Destroy           /* xDestroy */
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_config(SQLITE_CONFIG_PCACHE, &defaultMethods);
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This function is called to free superfluous dynamically allocated memory
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** held by the pager system. Memory in use by any SQLite pager allocated
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** by the current thread may be sqlite3_free()ed.
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** nReq is the number of bytes of memory required. Once this much has
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** been released, the function returns. The return value is the total number
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** of bytes of memory released.
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int sqlite3PcacheReleaseMemory(int nReq){
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nFree = 0;
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( sqlite3_mutex_notheld(pcache1.mutex) );
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pcache1.pStart==0 ){
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PgHdr1 *p;
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1EnterMutex(&pcache1.grp);
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while( (nReq<0 || nFree<nReq) && ((p=pcache1.grp.pLruTail)!=0) ){
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      nFree += pcache1MemSize(PGHDR1_TO_PAGE(p));
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pcache1PinPage(p);
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pcache1RemoveFromHash(p);
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pcache1FreePage(p);
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pcache1LeaveMutex(&pcache1.grp);
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return nFree;
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef SQLITE_TEST
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This function is used by test procedures to inspect the internal state
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** of the global cache.
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void sqlite3PcacheStats(
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int *pnCurrent,      /* OUT: Total number of pages cached */
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int *pnMax,          /* OUT: Global maximum cache size */
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int *pnMin,          /* OUT: Sum of PCache1.nMin for purgeable caches */
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int *pnRecyclable    /* OUT: Total number of pages available for recycling */
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PgHdr1 *p;
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nRecyclable = 0;
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(p=pcache1.grp.pLruHead; p; p=p->pLruNext){
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nRecyclable++;
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *pnCurrent = pcache1.grp.nCurrentPage;
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *pnMax = pcache1.grp.nMaxPage;
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *pnMin = pcache1.grp.nMinPage;
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *pnRecyclable = nRecyclable;
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
970