15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 2008 November 18
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 contains code used for testing the SQLite system.
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** None of the code in this file goes into a deliverable build.
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This file contains an application-defined pager cache
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** implementation that can be plugged in in place of the
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** default pcache.  This alternative pager cache will throw
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** some errors that the default cache does not.
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This pagecache implementation is designed for simplicity
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** not speed.
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sqlite3.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <assert.h>
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Global data used by this test implementation.  There is no
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** mutexing, which means this page cache will not work in a
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** multi-threaded test.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct testpcacheGlobalType testpcacheGlobalType;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct testpcacheGlobalType {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void *pDummy;             /* Dummy allocation to simulate failures */
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nInstance;            /* Number of current instances */
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned discardChance;   /* Chance of discarding on an unpin (0-100) */
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned prngSeed;        /* Seed for the PRNG */
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned highStress;      /* Call xStress agressively */
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static testpcacheGlobalType testpcacheGlobal;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Initializer.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Verify that the initializer is only called when the system is
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** uninitialized.  Allocate some memory and report SQLITE_NOMEM if
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** the allocation fails.  This provides a means to test the recovery
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** from a failed initialization attempt.  It also verifies that the
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** the destructor always gets call - otherwise there would be a
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** memory leak.
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int testpcacheInit(void *pArg){
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pArg==(void*)&testpcacheGlobal );
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( testpcacheGlobal.pDummy==0 );
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( testpcacheGlobal.nInstance==0 );
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  testpcacheGlobal.pDummy = sqlite3_malloc(10);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return testpcacheGlobal.pDummy==0 ? SQLITE_NOMEM : SQLITE_OK;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Destructor
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Verify that this is only called after initialization.
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Free the memory allocated by the initializer.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void testpcacheShutdown(void *pArg){
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( pArg==(void*)&testpcacheGlobal );
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( testpcacheGlobal.pDummy!=0 );
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( testpcacheGlobal.nInstance==0 );
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_free( testpcacheGlobal.pDummy );
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  testpcacheGlobal.pDummy = 0;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Number of pages in a cache.
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The number of pages is a hard upper bound in this test module.
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** If more pages are requested, sqlite3PcacheFetch() returns NULL.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** If testing with in-memory temp tables, provide a larger pcache.
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Some of the test cases need this.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(SQLITE_TEMP_STORE) && SQLITE_TEMP_STORE>=2
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# define TESTPCACHE_NPAGE    499
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# define TESTPCACHE_NPAGE    217
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TESTPCACHE_RESERVE   17
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Magic numbers used to determine validity of the page cache.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TESTPCACHE_VALID  0x364585fd
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TESTPCACHE_CLEAR  0xd42670d4
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Private implementation of a page cache.
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct testpcache testpcache;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct testpcache {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int szPage;               /* Size of each page.  Multiple of 8. */
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int bPurgeable;           /* True if the page cache is purgeable */
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nFree;                /* Number of unused slots in a[] */
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nPinned;              /* Number of pinned slots in a[] */
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned iRand;           /* State of the PRNG */
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned iMagic;          /* Magic number for sanity checking */
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct testpcachePage {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned key;              /* The key for this page. 0 means unallocated */
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int isPinned;              /* True if the page is pinned */
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void *pData;               /* Data for this page */
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } a[TESTPCACHE_NPAGE];    /* All pages in the cache */
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Get a random number using the PRNG in the given page cache.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static unsigned testpcacheRandom(testpcache *p){
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned x = 0;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(i=0; i<4; i++){
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p->iRand = (p->iRand*69069 + 5);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    x = (x<<8) | ((p->iRand>>16)&0xff);
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return x;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Allocate a new page cache instance.
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static sqlite3_pcache *testpcacheCreate(int szPage, int bPurgeable){
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nMem;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char *x;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  testpcache *p;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( testpcacheGlobal.pDummy!=0 );
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  szPage = (szPage+7)&~7;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  nMem = sizeof(testpcache) + TESTPCACHE_NPAGE*szPage;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p = sqlite3_malloc( nMem );
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( p==0 ) return 0;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  x = (char*)&p[1];
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->szPage = szPage;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->nFree = TESTPCACHE_NPAGE;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->nPinned = 0;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->iRand = testpcacheGlobal.prngSeed;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->bPurgeable = bPurgeable;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->iMagic = TESTPCACHE_VALID;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(i=0; i<TESTPCACHE_NPAGE; i++, x += szPage){
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p->a[i].key = 0;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p->a[i].isPinned = 0;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p->a[i].pData = (void*)x;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  testpcacheGlobal.nInstance++;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (sqlite3_pcache*)p;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Set the cache size
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void testpcacheCachesize(sqlite3_pcache *pCache, int newSize){
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  testpcache *p = (testpcache*)pCache;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( p->iMagic==TESTPCACHE_VALID );
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( newSize>=1 );
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( testpcacheGlobal.pDummy!=0 );
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( testpcacheGlobal.nInstance>0 );
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Return the number of pages in the cache that are being used.
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This includes both pinned and unpinned pages.
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int testpcachePagecount(sqlite3_pcache *pCache){
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  testpcache *p = (testpcache*)pCache;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( p->iMagic==TESTPCACHE_VALID );
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( testpcacheGlobal.pDummy!=0 );
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( testpcacheGlobal.nInstance>0 );
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TESTPCACHE_NPAGE - p->nFree;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Fetch a page.
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void *testpcacheFetch(
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_pcache *pCache,
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned key,
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int createFlag
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  testpcache *p = (testpcache*)pCache;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i, j;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( p->iMagic==TESTPCACHE_VALID );
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( testpcacheGlobal.pDummy!=0 );
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( testpcacheGlobal.nInstance>0 );
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* See if the page is already in cache.  Return immediately if it is */
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(i=0; i<TESTPCACHE_NPAGE; i++){
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( p->a[i].key==key ){
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( !p->a[i].isPinned ){
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        p->nPinned++;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        assert( p->nPinned <= TESTPCACHE_NPAGE - p->nFree );
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        p->a[i].isPinned = 1;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return p->a[i].pData;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* If createFlag is 0, never allocate a new page */
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( createFlag==0 ){
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* If no pages are available, always fail */
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( p->nPinned==TESTPCACHE_NPAGE ){
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Do not allocate the last TESTPCACHE_RESERVE pages unless createFlag is 2 */
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( p->nPinned>=TESTPCACHE_NPAGE-TESTPCACHE_RESERVE && createFlag<2 ){
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Do not allocate if highStress is enabled and createFlag is not 2.
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  **
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** The highStress setting causes pagerStress() to be called much more
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** often, which exercises the pager logic more intensely.
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  */
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( testpcacheGlobal.highStress && createFlag<2 ){
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Find a free page to allocate if there are any free pages.
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** Withhold TESTPCACHE_RESERVE free pages until createFlag is 2.
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  */
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( p->nFree>TESTPCACHE_RESERVE || (createFlag==2 && p->nFree>0) ){
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    j = testpcacheRandom(p) % TESTPCACHE_NPAGE;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for(i=0; i<TESTPCACHE_NPAGE; i++, j = (j+1)%TESTPCACHE_NPAGE){
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( p->a[j].key==0 ){
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        p->a[j].key = key;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        p->a[j].isPinned = 1;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        memset(p->a[j].pData, 0, p->szPage);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        p->nPinned++;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        p->nFree--;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        assert( p->nPinned <= TESTPCACHE_NPAGE - p->nFree );
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return p->a[j].pData;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* The prior loop always finds a freepage to allocate */
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert( 0 );
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* If this cache is not purgeable then we have to fail.
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  */
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( p->bPurgeable==0 ){
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* If there are no free pages, recycle a page.  The page to
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** recycle is selected at random from all unpinned pages.
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  */
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  j = testpcacheRandom(p) % TESTPCACHE_NPAGE;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(i=0; i<TESTPCACHE_NPAGE; i++, j = (j+1)%TESTPCACHE_NPAGE){
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( p->a[j].key>0 && p->a[j].isPinned==0 ){
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      p->a[j].key = key;
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      p->a[j].isPinned = 1;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      memset(p->a[j].pData, 0, p->szPage);
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      p->nPinned++;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert( p->nPinned <= TESTPCACHE_NPAGE - p->nFree );
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return p->a[j].pData;
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* The previous loop always finds a page to recycle. */
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert(0);
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Unpin a page.
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void testpcacheUnpin(
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_pcache *pCache,
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void *pOldPage,
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int discard
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  testpcache *p = (testpcache*)pCache;
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( p->iMagic==TESTPCACHE_VALID );
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( testpcacheGlobal.pDummy!=0 );
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( testpcacheGlobal.nInstance>0 );
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Randomly discard pages as they are unpinned according to the
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** discardChance setting.  If discardChance is 0, the random discard
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** never happens.  If discardChance is 100, it always happens.
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  */
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( p->bPurgeable
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  && (100-testpcacheGlobal.discardChance) <= (testpcacheRandom(p)%100)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ){
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    discard = 1;
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(i=0; i<TESTPCACHE_NPAGE; i++){
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( p->a[i].pData==pOldPage ){
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* The pOldPage pointer always points to a pinned page */
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert( p->a[i].isPinned );
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      p->a[i].isPinned = 0;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      p->nPinned--;
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert( p->nPinned>=0 );
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( discard ){
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        p->a[i].key = 0;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        p->nFree++;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        assert( p->nFree<=TESTPCACHE_NPAGE );
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* The pOldPage pointer always points to a valid page */
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( 0 );
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Rekey a single page.
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void testpcacheRekey(
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_pcache *pCache,
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void *pOldPage,
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned oldKey,
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned newKey
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  testpcache *p = (testpcache*)pCache;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i;
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( p->iMagic==TESTPCACHE_VALID );
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( testpcacheGlobal.pDummy!=0 );
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( testpcacheGlobal.nInstance>0 );
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* If there already exists another page at newKey, verify that
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** the other page is unpinned and discard it.
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  */
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(i=0; i<TESTPCACHE_NPAGE; i++){
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( p->a[i].key==newKey ){
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* The new key is never a page that is already pinned */
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert( p->a[i].isPinned==0 );
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      p->a[i].key = 0;
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      p->nFree++;
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert( p->nFree<=TESTPCACHE_NPAGE );
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Find the page to be rekeyed and rekey it.
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  */
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(i=0; i<TESTPCACHE_NPAGE; i++){
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( p->a[i].key==oldKey ){
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* The oldKey and pOldPage parameters match */
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert( p->a[i].pData==pOldPage );
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* Page to be rekeyed must be pinned */
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert( p->a[i].isPinned );
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      p->a[i].key = newKey;
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Rekey is always given a valid page to work with */
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( 0 );
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Truncate the page cache.  Every page with a key of iLimit or larger
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** is discarded.
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void testpcacheTruncate(sqlite3_pcache *pCache, unsigned iLimit){
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  testpcache *p = (testpcache*)pCache;
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int i;
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( p->iMagic==TESTPCACHE_VALID );
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( testpcacheGlobal.pDummy!=0 );
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( testpcacheGlobal.nInstance>0 );
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(i=0; i<TESTPCACHE_NPAGE; i++){
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( p->a[i].key>=iLimit ){
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      p->a[i].key = 0;
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( p->a[i].isPinned ){
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        p->nPinned--;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        assert( p->nPinned>=0 );
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      p->nFree++;
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert( p->nFree<=TESTPCACHE_NPAGE );
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Destroy a page cache.
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void testpcacheDestroy(sqlite3_pcache *pCache){
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  testpcache *p = (testpcache*)pCache;
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( p->iMagic==TESTPCACHE_VALID );
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( testpcacheGlobal.pDummy!=0 );
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( testpcacheGlobal.nInstance>0 );
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->iMagic = TESTPCACHE_CLEAR;
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_free(p);
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  testpcacheGlobal.nInstance--;
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Invoke this routine to register or unregister the testing pager cache
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** implemented by this file.
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Install the test pager cache if installFlag is 1 and uninstall it if
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** installFlag is 0.
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** When installing, discardChance is a number between 0 and 100 that
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** indicates the probability of discarding a page when unpinning the
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** page.  0 means never discard (unless the discard flag is set).
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 100 means always discard.
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void installTestPCache(
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int installFlag,            /* True to install.  False to uninstall. */
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned discardChance,     /* 0-100.  Chance to discard on unpin */
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned prngSeed,          /* Seed for the PRNG */
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned highStress         /* Call xStress agressively */
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const sqlite3_pcache_methods testPcache = {
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (void*)&testpcacheGlobal,
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    testpcacheInit,
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    testpcacheShutdown,
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    testpcacheCreate,
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    testpcacheCachesize,
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    testpcachePagecount,
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    testpcacheFetch,
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    testpcacheUnpin,
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    testpcacheRekey,
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    testpcacheTruncate,
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    testpcacheDestroy,
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static sqlite3_pcache_methods defaultPcache;
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int isInstalled = 0;
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( testpcacheGlobal.nInstance==0 );
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( testpcacheGlobal.pDummy==0 );
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( discardChance<=100 );
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  testpcacheGlobal.discardChance = discardChance;
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  testpcacheGlobal.prngSeed = prngSeed ^ (prngSeed<<16);
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  testpcacheGlobal.highStress = highStress;
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( installFlag!=isInstalled ){
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( installFlag ){
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sqlite3_config(SQLITE_CONFIG_GETPCACHE, &defaultPcache);
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert( defaultPcache.xCreate!=testpcacheCreate );
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sqlite3_config(SQLITE_CONFIG_PCACHE, &testPcache);
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }else{
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert( defaultPcache.xCreate!=0 );
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sqlite3_config(SQLITE_CONFIG_PCACHE, &defaultPcache);
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    isInstalled = installFlag;
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
459