If a page is made eligible for recycling when more than the configured maximum number of pages are allocated, free it immediately instead of adding it to the LRU list. (CVS 5638)

FossilOrigin-Name: 4b12922dcb4547bf3a7276d0542b2e1d12ad338d
This commit is contained in:
danielk1977 2008-08-29 09:10:02 +00:00
parent 8b213899e8
commit 062d4cb0ae
6 changed files with 234 additions and 15 deletions

View File

@ -1,5 +1,5 @@
C Avoid\sreevaluating\sWHERE\sand\sORDER\sBY\sexpressions\sthat\salias\sterms\sin\sthe\nresult\sset.\s\sTicket\s#3343.\s\sNote\sthat\saliased\sGROUP\sBY\sexpressions\sare\sstill\nevaluated\stwice.\s(CVS\s5637)
D 2008-08-29T02:14:03
C If\sa\spage\sis\smade\seligible\sfor\srecycling\swhen\smore\sthan\sthe\sconfigured\smaximum\snumber\sof\spages\sare\sallocated,\sfree\sit\simmediately\sinstead\sof\sadding\sit\sto\sthe\sLRU\slist.\s(CVS\s5638)
D 2008-08-29T09:10:03
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in 689e14735f862a5553bceef206d8c13e29504e44
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@ -137,8 +137,8 @@ F src/os_win.c aefe9ee26430678a19a058a874e4e2bd91398142
F src/pager.c 032d11049af4ec49bdbaa3584e7ce9887098b66a
F src/pager.h 914103bb62dbcc3d8e9f14baec812d027264d457
F src/parse.y d0f76d2cb8d6883d5600dc20beb961a6022b94b8
F src/pcache.c 4853068cb21ae742507186f8780b2eba33b734ff
F src/pcache.h bd373ee3e4db310d6bbe7fa6d8d971de9678edd8
F src/pcache.c e1cb0e77d2a299cfa4aa95d2e3307cc6900d2007
F src/pcache.h 53730c33310cdf7a5c94e8333c853d59a3b30226
F src/pragma.c f5b271b090af7fcedd308d7c5807a5503f7a853d
F src/prepare.c c197041e0c4770672cda75e6bfe10242f885e510
F src/printf.c 785f87120589c1db672e37c6eb1087c456e6f84d
@ -153,7 +153,7 @@ F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8
F src/status.c 8caa772cd9310bc297280f7cf0ede4d69ed5b801
F src/table.c 22744786199c9195720c15a7a42cb97b2e2728d8
F src/tclsqlite.c 420c7936d71f8318ea23b254c0d2cfc365135403
F src/test1.c bca7922b1eb9e8ca6042651a6974f0e2ad022df7
F src/test1.c e5781c664321fc10092dda13d6c3d02ae844566f
F src/test2.c eaa77124786649eedf47d3c5e94d8070c0da228f
F src/test3.c e85b7ce5c28c3ce7fbdbf7f98e1467b19786c62b
F src/test4.c 41056378671e7b00e6305fa9ac6fa27e6f96f406
@ -445,6 +445,7 @@ F test/pager2.test 070983b89a308adaba525a2f9c1ba0592c72fa3d
F test/pager3.test 2323bf27fd5bd887b580247e5bce500ceee994b4
F test/pageropt.test 3ee6578891baaca967f0bd349e4abfa736229e1a
F test/pagesize.test 0d9ff3fedfce6e5ffe8fa7aca9b6d3433a2e843b
F test/pcache.test a0fc9e965d039c4de24f9af929f9a25eb8be8539
F test/permutations.test e16bbd8cf443dd637317d9085b67bbdf91f21a1c
F test/pragma.test b55931bbd5dd543e56fd942dbf4b7439619b09a6
F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
@ -626,7 +627,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
P 83e6a75e7d70b4b01f0892924d7a8a49d5ef6bf2
R f7b963f31369c623d2a04efc9a423904
U drh
Z 9a20437031aab1a22d3ddda0e55ea04f
P ab0292caa5887cc1bdc0e8c9d3f3502b83975440
R b8688b362830896e075bddc5ac84e1a4
U danielk1977
Z e3ebfdb580a05ecf955ac9f707aeb447

View File

@ -1 +1 @@
ab0292caa5887cc1bdc0e8c9d3f3502b83975440
4b12922dcb4547bf3a7276d0542b2e1d12ad338d

View File

@ -11,7 +11,7 @@
*************************************************************************
** This file implements that page cache.
**
** @(#) $Id: pcache.c,v 1.23 2008/08/28 17:46:19 drh Exp $
** @(#) $Id: pcache.c,v 1.24 2008/08/29 09:10:03 danielk1977 Exp $
*/
#include "sqliteInt.h"
@ -748,7 +748,13 @@ void sqlite3PcacheRelease(PgHdr *p){
if( (p->flags&PGHDR_DIRTY)==0 ){
pCache->nPinned--;
pcacheEnterMutex();
pcacheAddToLruList(p);
if( pcache.nCurrentPage>pcache.nMaxPage ){
pcacheRemoveFromList(&pCache->pClean, p);
pcacheRemoveFromHash(p);
pcachePageFree(p);
}else{
pcacheAddToLruList(p);
}
pcacheExitMutex();
}else{
/* Move the page to the head of the caches dirty list. */
@ -930,6 +936,17 @@ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
pcacheExitMutex();
}
/*
** If there are currently more than pcache.nMaxPage pages allocated, try
** to recycle pages to reduce the number allocated to pcache.nMaxPage.
*/
static void pcacheEnforceMaxPage(){
PgHdr *p;
assert( sqlite3_mutex_held(pcache.mutex) );
while( pcache.nCurrentPage>pcache.nMaxPage && (p = pcacheRecyclePage()) ){
pcachePageFree(p);
}
}
/*
** Close a cache.
@ -942,9 +959,9 @@ void sqlite3PcacheClose(PCache *pCache){
if( pCache->bPurgeable ){
pcache.nMaxPage -= pCache->nMax;
pcache.nMinPage -= pCache->nMin;
pcacheEnforceMaxPage();
}
sqlite3_free(pCache->apHash);
pcacheExitMutex();
}
@ -1193,6 +1210,7 @@ void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
pcacheEnterMutex();
pcache.nMaxPage -= pCache->nMax;
pcache.nMaxPage += mxPage;
pcacheEnforceMaxPage();
pcacheExitMutex();
}
pCache->nMax = mxPage;
@ -1222,3 +1240,24 @@ int sqlite3PcacheReleaseMemory(int nReq){
return nFree;
}
#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */
#ifdef SQLITE_TEST
void sqlite3PcacheStats(
int *pnCurrent,
int *pnMax,
int *pnMin,
int *pnRecyclable
){
PgHdr *p;
int nRecyclable = 0;
for(p=pcache.pLruHead; p; p=p->pNextLru){
nRecyclable++;
}
*pnCurrent = pcache.nCurrentPage;
*pnMax = pcache.nMaxPage;
*pnMin = pcache.nMinPage;
*pnRecyclable = nRecyclable;
}
#endif

View File

@ -12,7 +12,7 @@
** This header file defines the interface that the sqlite page cache
** subsystem.
**
** @(#) $Id: pcache.h,v 1.8 2008/08/28 02:26:07 drh Exp $
** @(#) $Id: pcache.h,v 1.9 2008/08/29 09:10:03 danielk1977 Exp $
*/
#ifndef _PCACHE_H_
@ -161,4 +161,6 @@ void sqlite3PcacheSetCachesize(PCache *, int);
/* Try to return memory used by the pcache module to the main memory heap */
int sqlite3PcacheReleaseMemory(int);
void sqlite3PcacheStats(int*,int*,int*,int*);
#endif /* _PCACHE_H_ */

View File

@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.320 2008/08/27 15:21:34 drh Exp $
** $Id: test1.c,v 1.321 2008/08/29 09:10:03 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@ -4501,6 +4501,38 @@ static int reset_prng_state(
return TCL_OK;
}
/*
** tclcmd: pcache_stats
*/
static int test_pcache_stats(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj *CONST objv[] /* Command arguments */
){
int nMin;
int nMax;
int nCurrent;
int nRecyclable;
Tcl_Obj *pRet;
sqlite3PcacheStats(&nCurrent, &nMax, &nMin, &nRecyclable);
pRet = Tcl_NewObj();
Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("current", -1));
Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nCurrent));
Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("max", -1));
Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nMax));
Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("min", -1));
Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nMin));
Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("recyclable", -1));
Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nRecyclable));
Tcl_SetObjResult(interp, pRet);
return TCL_OK;
}
/*
** Register commands with the TCL interpreter.
@ -4675,6 +4707,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_blob_read", test_blob_read, 0 },
{ "sqlite3_blob_write", test_blob_write, 0 },
#endif
{ "pcache_stats", test_pcache_stats, 0 },
};
static int bitmask_size = sizeof(Bitmask)*8;
int i;

144
test/pcache.test Normal file
View File

@ -0,0 +1,144 @@
# 2008 August 29
#
# 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 is focused on testing the pcache module.
#
# $Id: pcache.test,v 1.1 2008/08/29 09:10:03 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# The pcache module limits the number of pages available to purgeable
# caches to the sum of the 'cache_size' values for the set of open
# caches. This block of tests, pcache-1.*, test that the library behaves
# corrctly when it is forced to exceed this limit.
#
do_test pcache-1.1 {
db close
pcache_stats
} {current 0 max 0 min 0 recyclable 0}
do_test pcache-1.2 {
sqlite3 db test.db
execsql "PRAGMA cache_size=10"
pcache_stats
} {current 1 max 10 min 10 recyclable 1}
do_test pcache-1.3 {
execsql {
BEGIN;
CREATE TABLE t1(a, b, c);
CREATE TABLE t2(a, b, c);
CREATE TABLE t3(a, b, c);
CREATE TABLE t4(a, b, c);
CREATE TABLE t5(a, b, c);
}
pcache_stats
} {current 6 max 10 min 10 recyclable 0}
do_test pcache-1.4 {
execsql {
CREATE TABLE t6(a, b, c);
CREATE TABLE t7(a, b, c);
CREATE TABLE t8(a, b, c);
CREATE TABLE t9(a, b, c);
}
pcache_stats
} {current 10 max 10 min 10 recyclable 0}
do_test pcache-1.5 {
sqlite3 db2 test.db
execsql "PRAGMA cache_size=10" db2
pcache_stats
} {current 11 max 20 min 20 recyclable 1}
do_test pcache-1.6 {
execsql {
BEGIN;
SELECT * FROM sqlite_master;
} db2
pcache_stats
} {current 11 max 20 min 20 recyclable 0}
# At this point connection db2 has a read lock on the database file and a
# single pinned page in its cache. Connection [db] is holding 10 dirty
# pages. It cannot recycle them because of the read lock held by db2.
#
do_test pcache-1.6 {
execsql {
CREATE INDEX i1 ON t1(a, b);
CREATE INDEX i2 ON t2(a, b);
CREATE INDEX i3 ON t3(a, b);
CREATE INDEX i4 ON t4(a, b);
CREATE INDEX i5 ON t5(a, b);
CREATE INDEX i6 ON t6(a, b);
CREATE INDEX i7 ON t7(a, b);
CREATE INDEX i8 ON t8(a, b);
CREATE INDEX i9 ON t9(a, b);
}
pcache_stats
} {current 20 max 20 min 20 recyclable 0}
do_test pcache-1.7 {
execsql {
CREATE TABLE t10(a, b, c);
}
pcache_stats
} {current 21 max 20 min 20 recyclable 0}
# Rolling back the transaction held by db2 at this point releases a pinned
# page. Because the number of allocated pages is greater than the
# configured maximum, this page should be freed immediately instead of
# recycled.
#
do_test pcache-1.8 {
execsql {ROLLBACK} db2
pcache_stats
} {current 20 max 20 min 20 recyclable 0}
do_test pcache-1.9 {
execsql COMMIT
pcache_stats
} {current 20 max 20 min 20 recyclable 20}
do_test pcache-1.10 {
db2 close
pcache_stats
} {current 10 max 10 min 10 recyclable 10}
do_test pcache-1.11 {
execsql { PRAGMA cache_size = 20 }
pcache_stats
} {current 10 max 20 min 10 recyclable 10}
do_test pcache-1.12 {
execsql {
SELECT * FROM t1 ORDER BY a; SELECT * FROM t1;
SELECT * FROM t2 ORDER BY a; SELECT * FROM t2;
SELECT * FROM t3 ORDER BY a; SELECT * FROM t3;
SELECT * FROM t4 ORDER BY a; SELECT * FROM t4;
SELECT * FROM t5 ORDER BY a; SELECT * FROM t5;
SELECT * FROM t6 ORDER BY a; SELECT * FROM t6;
SELECT * FROM t7 ORDER BY a; SELECT * FROM t7;
SELECT * FROM t8 ORDER BY a; SELECT * FROM t8;
SELECT * FROM t9 ORDER BY a; SELECT * FROM t9;
}
pcache_stats
} {current 19 max 20 min 10 recyclable 19}
do_test pcache-1.13 {
execsql { PRAGMA cache_size = 15 }
pcache_stats
} {current 15 max 15 min 10 recyclable 15}
finish_test