diff --git a/manifest b/manifest index cda16b2cf7..39dc294cdc 100644 --- a/manifest +++ b/manifest @@ -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 diff --git a/manifest.uuid b/manifest.uuid index e6f959c8d4..e9f6d7b708 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ab0292caa5887cc1bdc0e8c9d3f3502b83975440 \ No newline at end of file +4b12922dcb4547bf3a7276d0542b2e1d12ad338d \ No newline at end of file diff --git a/src/pcache.c b/src/pcache.c index f0f5a964c6..552f6c772d 100644 --- a/src/pcache.c +++ b/src/pcache.c @@ -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 + diff --git a/src/pcache.h b/src/pcache.h index d3fd7a9331..f01e98b89c 100644 --- a/src/pcache.h +++ b/src/pcache.h @@ -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_ */ diff --git a/src/test1.c b/src/test1.c index 7680e29f30..e6bc2aa882 100644 --- a/src/test1.c +++ b/src/test1.c @@ -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; diff --git a/test/pcache.test b/test/pcache.test new file mode 100644 index 0000000000..1639823230 --- /dev/null +++ b/test/pcache.test @@ -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 +