Add an alternative application-defined pcache implementation and add test
cases to permutations.test to invoke it. Added the SQLITE_CONFIG_GETPCACHE method to sqlite3_config(). (CVS 5920) FossilOrigin-Name: 16f1e6ec2ad92f68c0079a0c2b5ca08a3b4af816
This commit is contained in:
parent
4c6517848f
commit
b232c23297
@ -376,6 +376,7 @@ TESTSRC = \
|
||||
$(TOP)/src/test_mutex.c \
|
||||
$(TOP)/src/test_onefile.c \
|
||||
$(TOP)/src/test_osinst.c \
|
||||
$(TOP)/src/test_pcache.c \
|
||||
$(TOP)/src/test_schema.c \
|
||||
$(TOP)/src/test_server.c \
|
||||
$(TOP)/src/test_tclvar.c \
|
||||
|
1
main.mk
1
main.mk
@ -228,6 +228,7 @@ TESTSRC = \
|
||||
$(TOP)/src/test_mutex.c \
|
||||
$(TOP)/src/test_onefile.c \
|
||||
$(TOP)/src/test_osinst.c \
|
||||
$(TOP)/src/test_pcache.c \
|
||||
$(TOP)/src/test_schema.c \
|
||||
$(TOP)/src/test_server.c \
|
||||
$(TOP)/src/test_tclvar.c \
|
||||
|
23
manifest
23
manifest
@ -1,7 +1,7 @@
|
||||
C Fix\sto\sthe\slemon\sparser\stemplate\swhen\sYYSTACKSIZE\sis\s0\s(dynamically\nallocated\sstack\sspace).\s(CVS\s5919)
|
||||
D 2008-11-18T23:25:55
|
||||
C Add\san\salternative\sapplication-defined\spcache\simplementation\sand\sadd\stest\ncases\sto\spermutations.test\sto\sinvoke\sit.\s\sAdded\sthe\sSQLITE_CONFIG_GETPCACHE\nmethod\sto\ssqlite3_config().\s(CVS\s5920)
|
||||
D 2008-11-19T01:20:26
|
||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||
F Makefile.in 6cbc7db84c23804c368bc7ffe51367412212d7b2
|
||||
F Makefile.in 0aa7bbe3be6acc4045706e3bb3fd0b8f38f4a3b5
|
||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||
F Makefile.vxwSH4 d53b4be86491060d498b22148951b6d765884cab
|
||||
F README b974cdc3f9f12b87e851b04e75996d720ebf81ac
|
||||
@ -80,7 +80,7 @@ F ext/rtree/tkt3363.test 6662237ea75bb431cd5d262dfc9535e1023315fc
|
||||
F ext/rtree/viewrtree.tcl 09526398dae87a5a87c5aac2b3854dbaf8376869
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
|
||||
F ltmain.sh 09fe5815427dc7d0abb188bbcdf0e34896577210
|
||||
F main.mk 2da751f09754965bcbc8b3fde56c8c71e67ebdb5
|
||||
F main.mk 87a73e91a3d0827dc796a249260866335e38a36e
|
||||
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
|
||||
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
|
||||
F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac
|
||||
@ -119,7 +119,7 @@ F src/insert.c 47d2c27396724d5050a5f7d6a54ce44ec163e473
|
||||
F src/journal.c cffd2cd214e58c0e99c3ff632b3bee6c7cbb260e
|
||||
F src/legacy.c aac57bd984e666059011ea01ec4383892a253be3
|
||||
F src/loadext.c 3872457afdf25bb174fd383cb4e3e0d2a9e60552
|
||||
F src/main.c fd93666b883dbe976f8fb9a5b87784bde2eca43d
|
||||
F src/main.c 3b99ff818efa18a772b4fceb8bc72081aa9b1517
|
||||
F src/malloc.c 00532787dc7f0dbf4e2487aa823946e1d0524ef1
|
||||
F src/mem0.c f2f84062d1f35814d6535c9f9e33de3bfb3b132c
|
||||
F src/mem1.c 2091081d1c6bcd4516738f37cd84d42e814cf9a2
|
||||
@ -152,7 +152,7 @@ F src/random.c a87afbd598aa877e23ac676ee92fd8ee5c786a51
|
||||
F src/resolve.c 4af5391d2b4c1d6c583a6805ac6660181de4545b
|
||||
F src/select.c 18c6d96f4f8c6e43cb35201a1245ff02be8c9378
|
||||
F src/shell.c 650d1a87408682280d0e9d014d0d328c59c84b38
|
||||
F src/sqlite.h.in 4d05b9195e9489dc62857d9dd3334b0139715101
|
||||
F src/sqlite.h.in e9a0aa2502dfe01bf166956051528f28871474c3
|
||||
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
|
||||
F src/sqliteInt.h d48bb0ecc2d1c25d47ea144560d7a8e6864fbabe
|
||||
F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8
|
||||
@ -176,11 +176,12 @@ F src/test_devsym.c 802d10e65b4217208cb47059b84adf46318bcdf4
|
||||
F src/test_func.c a55c4d5479ff2eb5c0a22d4d88e9528ab59c953b
|
||||
F src/test_hexio.c 2f1122aa3f012fa0142ee3c36ce5c902a70cd12f
|
||||
F src/test_loadext.c 97dc8800e46a46ed002c2968572656f37e9c0dd9
|
||||
F src/test_malloc.c e2f6e6774308f531a3d12475dd2a5211dd31b7eb
|
||||
F src/test_malloc.c 5127337c9fb4c851a7f604c0170e0e5ca1fbfe33
|
||||
F src/test_md5.c 28209a4e2068711b5443c33104fe41f21d160071
|
||||
F src/test_mutex.c 66c4ab4e0396a440ddb17cd9b58a05305144f05d
|
||||
F src/test_onefile.c 243157b10275251c5dc2d6619aee2ff9ae22379c
|
||||
F src/test_osinst.c ae29e9c09485622a157849508302dd9ffe44f21f
|
||||
F src/test_pcache.c 0008968cc36558c8253585e5d321eccba44edb80
|
||||
F src/test_schema.c 4b4bf7bb329326458c491b0e6facd4c8c4c5b479
|
||||
F src/test_server.c f0a403b5f699c09bd2b1236b6f69830fd6221f6b
|
||||
F src/test_tclvar.c 9e42fa59d3d2f064b7ab8628e7ab2dc8a9fe93d4
|
||||
@ -461,7 +462,7 @@ F test/pageropt.test 3ee6578891baaca967f0bd349e4abfa736229e1a
|
||||
F test/pagesize.test 0d9ff3fedfce6e5ffe8fa7aca9b6d3433a2e843b
|
||||
F test/pcache.test 515b4c26e9f57660357dfff5b6b697acac1abc5f
|
||||
F test/pcache2.test 46efd980a89f737847b99327bda19e08fe11e402
|
||||
F test/permutations.test 6f2952820e43568d7b869d54f4c7140bc695a5f0
|
||||
F test/permutations.test 5308a94878efc81a8e8ce133926dfb2c53d19133
|
||||
F test/pragma.test 165372b62391d233715cde82d99f34d306f9257f
|
||||
F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
|
||||
F test/printf.test 262a5acd3158f788e9bdf7f18d718f3af32ff6ef
|
||||
@ -658,7 +659,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
|
||||
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
P 2990b5b8e7bd8f91af24e5a606666077855ae283
|
||||
R d14041d00b154aef89232b6b6d2d34f2
|
||||
P 00ccc5967f8912961029a3513445c5e2ac713560
|
||||
R 073d299d61cca110cab93939ee191b26
|
||||
U drh
|
||||
Z 887cd197809b3ccb7d5ef687ab5d5c82
|
||||
Z 897c512f710f8b2c13194a810c1ac26d
|
||||
|
@ -1 +1 @@
|
||||
00ccc5967f8912961029a3513445c5e2ac713560
|
||||
16f1e6ec2ad92f68c0079a0c2b5ca08a3b4af816
|
10
src/main.c
10
src/main.c
@ -14,7 +14,7 @@
|
||||
** other files are for internal use by SQLite and should not be
|
||||
** accessed by users of the library.
|
||||
**
|
||||
** $Id: main.c,v 1.512 2008/11/13 14:28:29 danielk1977 Exp $
|
||||
** $Id: main.c,v 1.513 2008/11/19 01:20:26 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -315,6 +315,14 @@ int sqlite3_config(int op, ...){
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLITE_CONFIG_GETPCACHE: {
|
||||
if( sqlite3GlobalConfig.pcache.xInit==0 ){
|
||||
sqlite3PCacheSetDefault();
|
||||
}
|
||||
*va_arg(ap, sqlite3_pcache_methods*) = sqlite3GlobalConfig.pcache;
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
|
||||
case SQLITE_CONFIG_HEAP: {
|
||||
/* Designate a buffer for heap memory space */
|
||||
|
@ -30,7 +30,7 @@
|
||||
** the version number) and changes its name to "sqlite3.h" as
|
||||
** part of the build process.
|
||||
**
|
||||
** @(#) $Id: sqlite.h.in,v 1.414 2008/11/18 19:18:09 drh Exp $
|
||||
** @(#) $Id: sqlite.h.in,v 1.415 2008/11/19 01:20:26 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITE3_H_
|
||||
#define _SQLITE3_H_
|
||||
@ -6683,8 +6683,9 @@ typedef struct sqlite3_pcache sqlite3_pcache;
|
||||
**
|
||||
** The xRekey() method is used to change the key value associated with the
|
||||
** page passed as the second argument from oldKey to newKey. If the cache
|
||||
** contains an entry associated with oldKey, it should be discarded. Any
|
||||
** cache entry associated with oldKey is guaranteed not to be pinned.
|
||||
** previously contains an entry associated with newKey, it should be
|
||||
** discarded. Any prior cache entry associated with newKey is guaranteed not
|
||||
** to be pinned.
|
||||
**
|
||||
** When SQLite calls the xTruncate() method, the cache must discard all
|
||||
** existing cache entries with page numbers (keys) greater than or equal
|
||||
|
@ -13,7 +13,7 @@
|
||||
** This file contains code used to implement test interfaces to the
|
||||
** memory allocation subsystem.
|
||||
**
|
||||
** $Id: test_malloc.c,v 1.50 2008/11/10 18:05:36 shane Exp $
|
||||
** $Id: test_malloc.c,v 1.51 2008/11/19 01:20:26 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "tcl.h"
|
||||
@ -945,6 +945,42 @@ static int test_config_pagecache(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_config_alt_pcache INSTALL_FLAG DISCARD_CHANCE PRNG_SEED
|
||||
**
|
||||
** Set up the alternative test page cache. Install if INSTALL_FLAG is
|
||||
** true and uninstall (reverting to the default page cache) if INSTALL_FLAG
|
||||
** is false. DISCARD_CHANGE is an integer between 0 and 100 inclusive
|
||||
** which determines the chance of discarding a page when unpinned. 100
|
||||
** is certainty. 0 is never. PRNG_SEED is the pseudo-random number generator
|
||||
** seed.
|
||||
*/
|
||||
static int test_alt_pcache(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
int installFlag;
|
||||
int discardChance;
|
||||
int prngSeed;
|
||||
extern void installTestPCache(int,unsigned,unsigned);
|
||||
if( objc!=4 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "INSTALLFLAG DISCARDCHANCE PRNGSEEED");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetIntFromObj(interp, objv[1], &installFlag) ) return TCL_ERROR;
|
||||
if( Tcl_GetIntFromObj(interp, objv[2], &discardChance) ) return TCL_ERROR;
|
||||
if( Tcl_GetIntFromObj(interp, objv[3], &prngSeed) ) return TCL_ERROR;
|
||||
if( discardChance<0 || discardChance>100 ){
|
||||
Tcl_AppendResult(interp, "discard-chance should be between 0 and 100",
|
||||
(char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
installTestPCache(installFlag, (unsigned)discardChance, (unsigned)prngSeed);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_config_memstatus BOOLEAN
|
||||
**
|
||||
@ -1312,6 +1348,7 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_memdebug_log", test_memdebug_log ,0 },
|
||||
{ "sqlite3_config_scratch", test_config_scratch ,0 },
|
||||
{ "sqlite3_config_pagecache", test_config_pagecache ,0 },
|
||||
{ "sqlite3_config_alt_pcache", test_alt_pcache ,0 },
|
||||
{ "sqlite3_status", test_status ,0 },
|
||||
{ "sqlite3_db_status", test_db_status ,0 },
|
||||
{ "install_malloc_faultsim", test_install_malloc_faultsim ,0 },
|
||||
@ -1321,7 +1358,7 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_config_error", test_config_error ,0 },
|
||||
{ "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 },
|
||||
{ "sqlite3_dump_memsys3", test_dump_memsys3 ,3 },
|
||||
{ "sqlite3_dump_memsys5", test_dump_memsys3 ,5 }
|
||||
{ "sqlite3_dump_memsys5", test_dump_memsys3 ,5 },
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
|
||||
|
438
src/test_pcache.c
Normal file
438
src/test_pcache.c
Normal file
@ -0,0 +1,438 @@
|
||||
/*
|
||||
** 2008 November 18
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This file contains code used for testing the SQLite system.
|
||||
** None of the code in this file goes into a deliverable build.
|
||||
**
|
||||
** This file contains an application-defined pager cache
|
||||
** implementation that can be plugged in in place of the
|
||||
** default pcache. This alternative pager cache will throw
|
||||
** some errors that the default cache does not.
|
||||
**
|
||||
** This pagecache implementation is designed for simplicity
|
||||
** not speed.
|
||||
**
|
||||
** $Id: test_pcache.c,v 1.1 2008/11/19 01:20:26 drh Exp $
|
||||
*/
|
||||
#include "sqlite3.h"
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
** Global data used by this test implementation. There is no
|
||||
** mutexing, which means this page cache will not work in a
|
||||
** multi-threaded test.
|
||||
*/
|
||||
typedef struct testpcacheGlobalType testpcacheGlobalType;
|
||||
struct testpcacheGlobalType {
|
||||
void *pDummy; /* Dummy allocation to simulate failures */
|
||||
int nInstance; /* Number of current instances */
|
||||
unsigned discardChance; /* Chance of discarding on an unpin */
|
||||
unsigned prngSeed; /* Seed for the PRNG */
|
||||
};
|
||||
static testpcacheGlobalType testpcacheGlobal;
|
||||
|
||||
/*
|
||||
** Initializer.
|
||||
**
|
||||
** Verify that the initializer is only called when the system is
|
||||
** uninitialized. Allocate some memory and report SQLITE_NOMEM if
|
||||
** the allocation fails. This provides a means to test the recovery
|
||||
** from a failed initialization attempt. It also verifies that the
|
||||
** the destructor always gets call - otherwise there would be a
|
||||
** memory leak.
|
||||
*/
|
||||
static int testpcacheInit(void *pArg){
|
||||
assert( pArg==(void*)&testpcacheGlobal );
|
||||
assert( testpcacheGlobal.pDummy==0 );
|
||||
assert( testpcacheGlobal.nInstance==0 );
|
||||
testpcacheGlobal.pDummy = sqlite3_malloc(10);
|
||||
return testpcacheGlobal.pDummy==0 ? SQLITE_NOMEM : SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Destructor
|
||||
**
|
||||
** Verify that this is only called after initialization.
|
||||
** Free the memory allocated by the initializer.
|
||||
*/
|
||||
static void testpcacheShutdown(void *pArg){
|
||||
assert( pArg==(void*)&testpcacheGlobal );
|
||||
assert( testpcacheGlobal.pDummy!=0 );
|
||||
assert( testpcacheGlobal.nInstance==0 );
|
||||
sqlite3_free( testpcacheGlobal.pDummy );
|
||||
testpcacheGlobal.pDummy = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Number of pages in a cache
|
||||
*/
|
||||
#define TESTPCACHE_NPAGE 217
|
||||
#define TESTPCACHE_RESERVE 17
|
||||
|
||||
/*
|
||||
** Magic numbers used to determine validity of the page cache.
|
||||
*/
|
||||
#define TESTPCACHE_VALID 0x364585fd
|
||||
#define TESTPCACHE_CLEAR 0xd42670d4
|
||||
|
||||
/*
|
||||
** Private implementation of a page cache.
|
||||
*/
|
||||
typedef struct testpcache testpcache;
|
||||
struct testpcache {
|
||||
int szPage; /* Size of each page. Multiple of 8. */
|
||||
int bPurgeable; /* True if the page cache is purgeable */
|
||||
int nFree; /* Number of unused slots in a[] */
|
||||
int nPinned; /* Number of pinned slots in a[] */
|
||||
unsigned iRand; /* State of the PRNG */
|
||||
unsigned iMagic; /* Magic number for sanity checking */
|
||||
struct testpcachePage {
|
||||
unsigned key; /* The key for this page. 0 means unallocated */
|
||||
int isPinned; /* True if the page is pinned */
|
||||
void *pData; /* Data for this page */
|
||||
} a[TESTPCACHE_NPAGE]; /* All pages in the cache */
|
||||
};
|
||||
|
||||
/*
|
||||
** Get a random number using the PRNG in the given page cache.
|
||||
*/
|
||||
static unsigned testpcacheRandom(testpcache *p){
|
||||
unsigned x = 0;
|
||||
int i;
|
||||
for(i=0; i<4; i++){
|
||||
p->iRand = (p->iRand*69069 + 5);
|
||||
x = (x<<8) | ((p->iRand>>16)&0xff);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Allocate a new page cache instance.
|
||||
*/
|
||||
static sqlite3_pcache *testpcacheCreate(int szPage, int bPurgeable){
|
||||
int nMem;
|
||||
char *x;
|
||||
testpcache *p;
|
||||
int i;
|
||||
assert( testpcacheGlobal.pDummy!=0 );
|
||||
szPage = (szPage+7)&~7;
|
||||
nMem = sizeof(testpcache) + TESTPCACHE_NPAGE*szPage;
|
||||
p = sqlite3_malloc( nMem );
|
||||
if( p==0 ) return 0;
|
||||
x = (char*)&p[1];
|
||||
p->szPage = szPage;
|
||||
p->nFree = TESTPCACHE_NPAGE;
|
||||
p->nPinned = 0;
|
||||
p->iRand = testpcacheGlobal.prngSeed;
|
||||
p->bPurgeable = bPurgeable;
|
||||
p->iMagic = TESTPCACHE_VALID;
|
||||
for(i=0; i<TESTPCACHE_NPAGE; i++, x += szPage){
|
||||
p->a[i].key = 0;
|
||||
p->a[i].isPinned = 0;
|
||||
p->a[i].pData = (void*)x;
|
||||
}
|
||||
testpcacheGlobal.nInstance++;
|
||||
return (sqlite3_pcache*)p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the cache size
|
||||
*/
|
||||
static void testpcacheCachesize(sqlite3_pcache *pCache, int newSize){
|
||||
testpcache *p = (testpcache*)pCache;
|
||||
assert( p->iMagic==TESTPCACHE_VALID );
|
||||
assert( newSize>=1 );
|
||||
assert( testpcacheGlobal.pDummy!=0 );
|
||||
assert( testpcacheGlobal.nInstance>0 );
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of pages in the cache that are being used.
|
||||
** This includes both pinned and unpinned pages.
|
||||
*/
|
||||
static int testpcachePagecount(sqlite3_pcache *pCache){
|
||||
testpcache *p = (testpcache*)pCache;
|
||||
assert( p->iMagic==TESTPCACHE_VALID );
|
||||
assert( testpcacheGlobal.pDummy!=0 );
|
||||
assert( testpcacheGlobal.nInstance>0 );
|
||||
return TESTPCACHE_NPAGE - p->nFree;
|
||||
}
|
||||
|
||||
/*
|
||||
** Fetch a page.
|
||||
*/
|
||||
static void *testpcacheFetch(
|
||||
sqlite3_pcache *pCache,
|
||||
unsigned key,
|
||||
int createFlag
|
||||
){
|
||||
testpcache *p = (testpcache*)pCache;
|
||||
int i, j;
|
||||
assert( p->iMagic==TESTPCACHE_VALID );
|
||||
assert( testpcacheGlobal.pDummy!=0 );
|
||||
assert( testpcacheGlobal.nInstance>0 );
|
||||
|
||||
/* See if the page is already in cache. Return immediately if it is */
|
||||
for(i=0; i<TESTPCACHE_NPAGE; i++){
|
||||
if( p->a[i].key==key ){
|
||||
if( !p->a[i].isPinned ){
|
||||
p->nPinned++;
|
||||
assert( p->nPinned <= TESTPCACHE_NPAGE - p->nFree );
|
||||
p->a[i].isPinned = 1;
|
||||
}
|
||||
return p->a[i].pData;
|
||||
}
|
||||
}
|
||||
|
||||
/* If createFlag is 0, never allocate a new page */
|
||||
if( createFlag==0 ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If no pages are available, always fail */
|
||||
if( p->nPinned==TESTPCACHE_NPAGE ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Do not allocate the last TESTPCACHE_RESERVE pages unless createFlag is 2 */
|
||||
if( p->nPinned>=TESTPCACHE_NPAGE-TESTPCACHE_RESERVE && createFlag<2 ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Find a free page to allocate if there are any free pages.
|
||||
** Withhold TESTPCACHE_RESERVE free pages until createFlag is 2.
|
||||
*/
|
||||
if( p->nFree>TESTPCACHE_RESERVE || (createFlag==2 && p->nFree>0) ){
|
||||
j = testpcacheRandom(p) % TESTPCACHE_NPAGE;
|
||||
for(i=0; i<TESTPCACHE_NPAGE; i++, j = (j+1)%TESTPCACHE_NPAGE){
|
||||
if( p->a[j].key==0 ){
|
||||
p->a[j].key = key;
|
||||
p->a[j].isPinned = 1;
|
||||
memset(p->a[j].pData, 0, p->szPage);
|
||||
p->nPinned++;
|
||||
p->nFree--;
|
||||
assert( p->nPinned <= TESTPCACHE_NPAGE - p->nFree );
|
||||
return p->a[j].pData;
|
||||
}
|
||||
}
|
||||
|
||||
/* The prior loop always finds a freepage to allocate */
|
||||
assert( 0 );
|
||||
}
|
||||
|
||||
/* If this cache is not purgeable then we have to fail.
|
||||
*/
|
||||
if( p->bPurgeable==0 ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If there are no free pages, recycle a page. The page to
|
||||
** recycle is selected at random from all unpinned pages.
|
||||
*/
|
||||
j = testpcacheRandom(p) % TESTPCACHE_NPAGE;
|
||||
for(i=0; i<TESTPCACHE_NPAGE; i++, j = (j+1)%TESTPCACHE_NPAGE){
|
||||
if( p->a[j].key>0 && p->a[j].isPinned==0 ){
|
||||
p->a[j].key = key;
|
||||
p->a[j].isPinned = 1;
|
||||
memset(p->a[j].pData, 0, p->szPage);
|
||||
p->nPinned++;
|
||||
assert( p->nPinned <= TESTPCACHE_NPAGE - p->nFree );
|
||||
return p->a[j].pData;
|
||||
}
|
||||
}
|
||||
|
||||
/* The previous loop always finds a page to recycle. */
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Unpin a page.
|
||||
*/
|
||||
static void testpcacheUnpin(
|
||||
sqlite3_pcache *pCache,
|
||||
void *pOldPage,
|
||||
int discard
|
||||
){
|
||||
testpcache *p = (testpcache*)pCache;
|
||||
int i;
|
||||
assert( p->iMagic==TESTPCACHE_VALID );
|
||||
assert( testpcacheGlobal.pDummy!=0 );
|
||||
assert( testpcacheGlobal.nInstance>0 );
|
||||
|
||||
/* Randomly discard pages as they are unpinned according to the
|
||||
** discardChance setting. If discardChance is 0, the random discard
|
||||
** never happens. If discardChance is 100, it always happens.
|
||||
*/
|
||||
if( p->bPurgeable
|
||||
&& (100-testpcacheGlobal.discardChance) <= (testpcacheRandom(p)%100)
|
||||
){
|
||||
discard = 1;
|
||||
}
|
||||
|
||||
for(i=0; i<TESTPCACHE_NPAGE; i++){
|
||||
if( p->a[i].pData==pOldPage ){
|
||||
/* The pOldPage pointer always points to a pinned page */
|
||||
assert( p->a[i].isPinned );
|
||||
p->a[i].isPinned = 0;
|
||||
p->nPinned--;
|
||||
assert( p->nPinned>=0 );
|
||||
if( discard ){
|
||||
p->a[i].key = 0;
|
||||
p->nFree++;
|
||||
assert( p->nFree<=TESTPCACHE_NPAGE );
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* The pOldPage pointer always points to a valid page */
|
||||
assert( 0 );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Rekey a single page.
|
||||
*/
|
||||
static void testpcacheRekey(
|
||||
sqlite3_pcache *pCache,
|
||||
void *pOldPage,
|
||||
unsigned oldKey,
|
||||
unsigned newKey
|
||||
){
|
||||
testpcache *p = (testpcache*)pCache;
|
||||
int i;
|
||||
assert( p->iMagic==TESTPCACHE_VALID );
|
||||
assert( testpcacheGlobal.pDummy!=0 );
|
||||
assert( testpcacheGlobal.nInstance>0 );
|
||||
|
||||
/* If there already exists another page at newKey, verify that
|
||||
** the other page is unpinned and discard it.
|
||||
*/
|
||||
for(i=0; i<TESTPCACHE_NPAGE; i++){
|
||||
if( p->a[i].key==newKey ){
|
||||
/* The new key is never a page that is already pinned */
|
||||
assert( p->a[i].isPinned==0 );
|
||||
p->a[i].key = 0;
|
||||
p->nFree++;
|
||||
assert( p->nFree<=TESTPCACHE_NPAGE );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find the page to be rekeyed and rekey it.
|
||||
*/
|
||||
for(i=0; i<TESTPCACHE_NPAGE; i++){
|
||||
if( p->a[i].key==oldKey ){
|
||||
/* The oldKey and pOldPage parameters match */
|
||||
assert( p->a[i].pData==pOldPage );
|
||||
/* Page to be rekeyed must be pinned */
|
||||
assert( p->a[i].isPinned );
|
||||
p->a[i].key = newKey;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Rekey is always given a valid page to work with */
|
||||
assert( 0 );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Truncate the page cache. Every page with a key of iLimit or larger
|
||||
** is discarded.
|
||||
*/
|
||||
static void testpcacheTruncate(sqlite3_pcache *pCache, unsigned iLimit){
|
||||
testpcache *p = (testpcache*)pCache;
|
||||
unsigned int i;
|
||||
assert( p->iMagic==TESTPCACHE_VALID );
|
||||
assert( testpcacheGlobal.pDummy!=0 );
|
||||
assert( testpcacheGlobal.nInstance>0 );
|
||||
for(i=0; i<TESTPCACHE_NPAGE; i++){
|
||||
if( p->a[i].key>=iLimit ){
|
||||
p->a[i].key = 0;
|
||||
if( p->a[i].isPinned ){
|
||||
p->nPinned--;
|
||||
assert( p->nPinned>=0 );
|
||||
}
|
||||
p->nFree++;
|
||||
assert( p->nFree<=TESTPCACHE_NPAGE );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Destroy a page cache.
|
||||
*/
|
||||
static void testpcacheDestroy(sqlite3_pcache *pCache){
|
||||
testpcache *p = (testpcache*)pCache;
|
||||
assert( p->iMagic==TESTPCACHE_VALID );
|
||||
assert( testpcacheGlobal.pDummy!=0 );
|
||||
assert( testpcacheGlobal.nInstance>0 );
|
||||
p->iMagic = TESTPCACHE_CLEAR;
|
||||
sqlite3_free(p);
|
||||
testpcacheGlobal.nInstance--;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Invoke this routine to register or unregister the testing pager cache
|
||||
** implemented by this file.
|
||||
**
|
||||
** Install the test pager cache if installFlag is 1 and uninstall it if
|
||||
** installFlag is 0.
|
||||
**
|
||||
** When installing, discardChance is a number between 0 and 100 that
|
||||
** indicates the probability of discarding a page when unpinning the
|
||||
** page. 0 means never discard (unless the discard flag is set).
|
||||
** 100 means always discard.
|
||||
*/
|
||||
void installTestPCache(
|
||||
int installFlag, /* True to install. False to uninstall. */
|
||||
unsigned discardChance, /* 0-100. Chance to discard on unpin */
|
||||
unsigned prngSeed /* Seed for the PRNG */
|
||||
){
|
||||
static const sqlite3_pcache_methods testPcache = {
|
||||
(void*)&testpcacheGlobal,
|
||||
testpcacheInit,
|
||||
testpcacheShutdown,
|
||||
testpcacheCreate,
|
||||
testpcacheCachesize,
|
||||
testpcachePagecount,
|
||||
testpcacheFetch,
|
||||
testpcacheUnpin,
|
||||
testpcacheRekey,
|
||||
testpcacheTruncate,
|
||||
testpcacheDestroy,
|
||||
};
|
||||
static sqlite3_pcache_methods defaultPcache;
|
||||
static int isInstalled = 0;
|
||||
|
||||
assert( testpcacheGlobal.nInstance==0 );
|
||||
assert( testpcacheGlobal.pDummy==0 );
|
||||
assert( discardChance<=100 );
|
||||
testpcacheGlobal.discardChance = discardChance;
|
||||
testpcacheGlobal.prngSeed = prngSeed ^ (prngSeed<<16);
|
||||
if( installFlag!=isInstalled ){
|
||||
if( installFlag ){
|
||||
sqlite3_config(SQLITE_CONFIG_GETPCACHE, &defaultPcache);
|
||||
assert( defaultPcache.xCreate!=testpcacheCreate );
|
||||
sqlite3_config(SQLITE_CONFIG_PCACHE, &testPcache);
|
||||
}else{
|
||||
assert( defaultPcache.xCreate!=0 );
|
||||
sqlite3_config(SQLITE_CONFIG_PCACHE, &defaultPcache);
|
||||
}
|
||||
isInstalled = installFlag;
|
||||
}
|
||||
}
|
@ -9,7 +9,7 @@
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# $Id: permutations.test,v 1.38 2008/11/13 16:21:50 danielk1977 Exp $
|
||||
# $Id: permutations.test,v 1.39 2008/11/19 01:20:26 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -604,6 +604,106 @@ run_tests "safe_append" -description {
|
||||
} -include [lsort [concat shared_err.test $ALLTESTS]] \
|
||||
-exclude async3.test
|
||||
|
||||
# The set of tests to run on the alternative-pcache
|
||||
set perm-alt-pcache-testset {
|
||||
async.test
|
||||
attach.test
|
||||
delete.test delete2.test
|
||||
index.test
|
||||
insert.test insert2.test
|
||||
join.test join2.test
|
||||
rollback.test
|
||||
select1.test select2.test
|
||||
trans.test
|
||||
update.test
|
||||
}
|
||||
|
||||
run_tests "pcache0" -description {
|
||||
Alternative pcache implementation without random discard
|
||||
} -initialize {
|
||||
catch {db close}
|
||||
sqlite3_reset_auto_extension
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_alt_pcache 1 0 1
|
||||
sqlite3_initialize
|
||||
autoinstall_test_functions
|
||||
} -shutdown {
|
||||
catch {db close}
|
||||
sqlite3_reset_auto_extension
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_alt_pcache 0 0 0
|
||||
sqlite3_config_lookaside 100 500
|
||||
install_malloc_faultsim 1
|
||||
sqlite3_initialize
|
||||
} -include ${perm-alt-pcache-testset}
|
||||
|
||||
run_tests "pcache10" -description {
|
||||
Alternative pcache implementation without 10% random discard
|
||||
} -initialize {
|
||||
catch {db close}
|
||||
sqlite3_reset_auto_extension
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_alt_pcache 1 50 1
|
||||
sqlite3_initialize
|
||||
autoinstall_test_functions
|
||||
} -shutdown {
|
||||
catch {db close}
|
||||
sqlite3_reset_auto_extension
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_alt_pcache 0 0 0
|
||||
sqlite3_initialize
|
||||
} -include ${perm-alt-pcache-testset}
|
||||
|
||||
run_tests "pcache50" -description {
|
||||
Alternative pcache implementation without 50% random discard
|
||||
} -initialize {
|
||||
catch {db close}
|
||||
sqlite3_reset_auto_extension
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_alt_pcache 1 50 1
|
||||
sqlite3_initialize
|
||||
autoinstall_test_functions
|
||||
} -shutdown {
|
||||
catch {db close}
|
||||
sqlite3_reset_auto_extension
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_alt_pcache 0 0 0
|
||||
sqlite3_initialize
|
||||
} -include ${perm-alt-pcache-testset}
|
||||
|
||||
run_tests "pcache90" -description {
|
||||
Alternative pcache implementation without 90% random discard
|
||||
} -initialize {
|
||||
catch {db close}
|
||||
sqlite3_reset_auto_extension
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_alt_pcache 1 50 1
|
||||
sqlite3_initialize
|
||||
autoinstall_test_functions
|
||||
} -shutdown {
|
||||
catch {db close}
|
||||
sqlite3_reset_auto_extension
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_alt_pcache 0 0 0
|
||||
sqlite3_initialize
|
||||
} -include ${perm-alt-pcache-testset}
|
||||
|
||||
run_tests "pcache100" -description {
|
||||
Alternative pcache implementation that always discards when unpinning
|
||||
} -initialize {
|
||||
catch {db close}
|
||||
sqlite3_reset_auto_extension
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_alt_pcache 1 100 1
|
||||
sqlite3_initialize
|
||||
autoinstall_test_functions
|
||||
} -shutdown {
|
||||
catch {db close}
|
||||
sqlite3_reset_auto_extension
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_alt_pcache 0 0 0
|
||||
sqlite3_initialize
|
||||
} -include ${perm-alt-pcache-testset}
|
||||
|
||||
# End of tests
|
||||
#############################################################################
|
||||
|
Loading…
x
Reference in New Issue
Block a user