From: danielk1977 Date: Mon, 2 Apr 2007 05:07:47 +0000 (+0000) Subject: Fix a resource leak introduced by the change-counter optimisation. Also add some... X-Git-Tag: version-3.6.10~2380 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=241687280b7b059849532a5e818cd37d7738bb2d;p=thirdparty%2Fsqlite.git Fix a resource leak introduced by the change-counter optimisation. Also add some test coverage. (CVS 3790) FossilOrigin-Name: ba0538a4977aefd6645554f1989f0a98b540b9cd --- diff --git a/manifest b/manifest index ea08ab1421..d12160f432 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Update\sthe\sversion\snumber\sand\schange\scomments\sin\spreparation\sfor\sthe\nrelease\sof\s3.3.14.\s(CVS\s3789) -D 2007-04-02T00:53:19 +C Fix\sa\sresource\sleak\sintroduced\sby\sthe\schange-counter\soptimisation.\sAlso\sadd\ssome\stest\scoverage.\s(CVS\s3790) +D 2007-04-02T05:07:47 F Makefile.in 2f2c3bf69faf0ae7b8e8af4f94f1986849034530 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -58,7 +58,7 @@ F src/alter.c 2c79ec40f65e33deaf90ca493422c74586e481a3 F src/analyze.c 4bbf5ddf9680587c6d4917e02e378b6037be3651 F src/attach.c a16ada4a4654a0d126b8223ec9494ebb81bc5c3c F src/auth.c 902f4722661c796b97f007d9606bd7529c02597f -F src/btree.c 052d0306d66768ad4d5a54609d4464bdc2a17839 +F src/btree.c 48fa58f2d71edeab4a7d08157abe50a0b7a0e489 F src/btree.h 9b2cc0d113c0bc2d37d244b9a394d56948c9acbf F src/build.c ad3374b5409554e504300f77e1fbc6b4c106a57f F src/callback.c 31d22b4919c7645cbcbb1591ce2453e8c677c558 @@ -86,7 +86,7 @@ F src/os_unix.c ccb003fb9fadc032924d3efb3fa8cc69fd9e176b F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e F src/os_win.c c9a99524d6b2bdec636264cad1b67553925e3309 F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b -F src/pager.c 84072e9b5f370752176e5f7575557496bf239bc3 +F src/pager.c a73e3b06cf315bfa70d34d9d311d3395693eef87 F src/pager.h e79a24cf200b8771366217f5bca414f5b7823f42 F src/parse.y 207ab04273ae13aa4a729b96008d294d5f334ab3 F src/pragma.c 3b992b5b2640d6ae25cef05aa6a42cd1d6c43234 @@ -102,7 +102,7 @@ F src/sqliteInt.h 09384eb30d6740e3e9d0c9379432e254fdb390d9 F src/table.c 6d0da66dde26ee75614ed8f584a1996467088d06 F src/tclsqlite.c a8d1166319db5d505b25ac6a9820162afe63fc8a F src/test1.c 0f94df69cd8832799aafaf58f7e28b4527225a3e -F src/test2.c 710a7252e22a8c690136a2b609e90fdad2697f35 +F src/test2.c 24458b17ab2f3c90cbc1c8446bd7ffe69be62f88 F src/test3.c 65f92247cf8592854e9bf5115b3fb711f8b33280 F src/test4.c 8b784cd82de158a2317cb4ac4bc86f91ad315e25 F src/test5.c 7162f8526affb771c4ed256826eee7bb9eca265f @@ -168,6 +168,7 @@ F test/btree6.test a5ede6bfbbb2ec8b27e62813612c0f28e8f3e027 F test/btree7.test a6d3b842db22af97dd14b989e90a2fd96066b72f F test/btree8.test fadc112bcbd6a0c622d34c813fc8a648eacf8804 F test/busy.test 0271c854738e23ad76e10d4096a698e5af29d211 +F test/cache.test 02cd1d1b0e7ad59cf24b85d49d77705e33aa5224 F test/capi2.test 7ecc9b342cc9ec27b53bbf95724cf2e5874fd496 F test/capi3.test 1675323145d128e5942a9faffcfd5cf4e219a33f F test/capi3b.test 5f0bc94b104e11086b1103b20277e1910f59c7f4 @@ -261,7 +262,7 @@ F test/malloc.test d868a6b98b07928b00bca3d9874daf6885c86150 F test/malloc2.test 4ed7d719542c4570dec9c2ebe2bbdf3a9f3b0d05 F test/malloc3.test e965954b6f808876a63d3101fd70370320b509a7 F test/malloc4.test 59cd02f71b363302a04c4e77b97c0a1572eaa210 -F test/malloc5.test 7425272e263325fda7d32cb55706e52b5c09e7e0 +F test/malloc5.test 17a32bd72073741d539bb2a1307d712a316b89da F test/malloc6.test 025ae0b78542e0ddd000d23f79d93e9be9ba0f15 F test/malloc7.test 1cf52834509eac7ebeb92105dacd4669f9ca9869 F test/manydb.test 8de36b8d33aab5ef295b11d9e95310aeded31af8 @@ -274,11 +275,11 @@ F test/misc3.test 7bd937e2c62bcc6be71939faf068d506467b1e03 F test/misc4.test b043a05dea037cca5989f3ae09552fa16119bc80 F test/misc5.test c7d2d2a5a20dc37d3605a8067f0df5af2240122e F test/misc6.test 3de55ec5cadf466ada587173faa5d6a4790a8bb7 -F test/misc7.test 8663e29f1a57c55321d4e6a8b2b9203d33254c69 +F test/misc7.test db026378fd83c9a318a9b5f5db5c17725db450d9 F test/misuse.test 30b3a458e5a70c31e74c291937b6c82204c59f33 F test/notnull.test 44d600f916b770def8b095a9962dbe3be5a70d82 F test/null.test 9503e1f63e959544c006d9f01709c5b5eab67d54 -F test/pager.test ceeef3caac4bf2046c6c06827f1a87dc1dec30f3 +F test/pager.test 3e12bef9c8512adb3f5db13d5745dc68fb4b92fc F test/pager2.test c025f91b75fe65e85febda64d9416428b8a5cab5 F test/pager3.test 2323bf27fd5bd887b580247e5bce500ceee994b4 F test/pagesize.test 05c74ea49f790734ec1e9ab765d9bf1cce79b8f2 @@ -447,7 +448,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513 -P 18aec1ddfb08b74f0ef9cf1215eac7af71449db3 -R 1ba2c076c76000f21aa292bb0a8f72c4 -U drh -Z ab035ae84bd6530ffbee25f61451be81 +P d9f6fdb72b29354921e6de40df5ed4f86b158a01 +R ac656430c79d0852aed9fac02cb5a8d8 +U danielk1977 +Z 6f28f4d19e867b11a92da6fb2f139223 diff --git a/manifest.uuid b/manifest.uuid index 91244695a9..32c12b0baa 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d9f6fdb72b29354921e6de40df5ed4f86b158a01 \ No newline at end of file +ba0538a4977aefd6645554f1989f0a98b540b9cd \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index a85d14ba58..2fa350a8ae 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.349 2007/03/31 02:36:44 drh Exp $ +** $Id: btree.c,v 1.350 2007/04/02 05:07:47 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -2280,8 +2280,13 @@ static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8); /* ** This routine is called prior to sqlite3PagerCommit when a transaction ** is commited for an auto-vacuum database. +** +** If SQLITE_OK is returned, then *pnTrunc is set to the number of pages +** the database file should be truncated to during the commit process. +** i.e. the database has been reorganized so that only the first *pnTrunc +** pages are in use. */ -static int autoVacuumCommit(BtShared *pBt, Pgno *nTrunc){ +static int autoVacuumCommit(BtShared *pBt, Pgno *pnTrunc){ Pager *pPager = pBt->pPager; Pgno nFreeList; /* Number of pages remaining on the free-list. */ int nPtrMap; /* Number of pointer-map pages deallocated */ @@ -2310,7 +2315,7 @@ static int autoVacuumCommit(BtShared *pBt, Pgno *nTrunc){ */ nFreeList = get4byte(&pBt->pPage1->aData[36]); if( nFreeList==0 ){ - *nTrunc = 0; + *pnTrunc = 0; return SQLITE_OK; } @@ -2401,7 +2406,7 @@ static int autoVacuumCommit(BtShared *pBt, Pgno *nTrunc){ if( rc!=SQLITE_OK ) goto autovacuum_out; put4byte(&pBt->pPage1->aData[32], 0); put4byte(&pBt->pPage1->aData[36], 0); - *nTrunc = finSize; + *pnTrunc = finSize; assert( finSize!=PENDING_BYTE_PAGE(pBt) ); autovacuum_out: diff --git a/src/pager.c b/src/pager.c index 18f737e541..e2514fdb42 100644 --- a/src/pager.c +++ b/src/pager.c @@ -18,7 +18,7 @@ ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.313 2007/04/01 23:49:52 drh Exp $ +** @(#) $Id: pager.c,v 1.314 2007/04/02 05:07:47 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" @@ -2389,9 +2389,16 @@ static PgHdr *merge_pagelist(PgHdr *pA, PgHdr *pB){ ** connected by pDirty pointers. The pPrevDirty pointers are ** corrupted by this sort. */ -#define N_SORT_BUCKET 25 +#define N_SORT_BUCKET_ALLOC 25 +#define N_SORT_BUCKET 25 +#ifdef SQLITE_TEST + int sqlite3_pager_n_sort_bucket = 0; + #undef N_SORT_BUCKET + #define N_SORT_BUCKET \ + (sqlite3_pager_n_sort_bucket?sqlite3_pager_n_sort_bucket:N_SORT_BUCKET_ALLOC) +#endif static PgHdr *sort_pagelist(PgHdr *pIn){ - PgHdr *a[N_SORT_BUCKET], *p; + PgHdr *a[N_SORT_BUCKET_ALLOC], *p; int i; memset(a, 0, sizeof(a)); while( pIn ){ @@ -2408,6 +2415,11 @@ static PgHdr *sort_pagelist(PgHdr *pIn){ } } if( i==N_SORT_BUCKET-1 ){ + /* Coverage: To get here, there need to be 2^(N_SORT_BUCKET) + ** elements in the input list. This is possible, but impractical. + ** Testing this line is the point of global variable + ** sqlite3_pager_n_sort_bucket. + */ a[i] = merge_pagelist(a[i], p); } } @@ -2591,7 +2603,9 @@ static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){ /* Unlink the old page from the free list and the hash table */ unlinkPage(pPg); - TEST_INCR(pPager->nOvfl); + if( pPg && pPg->pgno!=0 ){ + TEST_INCR(pPager->nOvfl); + } *ppPg = pPg; return SQLITE_OK; @@ -2771,9 +2785,32 @@ static int pagerSharedLock(Pager *pPager){ } if( pPager->pAll ){ + /* The shared-lock has just been acquired on the database file + ** and there are already pages in the cache (from a previous + ** read or write transaction). If the value of the change-counter + ** stored in Pager.iChangeCount matches that found on page 1 of + ** the database file, then no database changes have occured since + ** the cache was last valid and it is safe to retain the cached + ** pages. Otherwise, if Pager.iChangeCount does not match the + ** change-counter on page 1 of the file, the current cache contents + ** must be discarded. + */ + PgHdr *pPage1 = pager_lookup(pPager, 1); if( pPage1 ){ - unlinkHashChain(pPager, pPage1); + unlinkPage(pPage1); + + assert( pPager->pFirst==pPager->pFirstSynced ); + pPage1->pNextFree = pPager->pFirst; + if( pPager->pFirst ){ + pPager->pFirst->pPrevFree = pPage1; + }else{ + assert( !pPager->pLast ); + pPager->pLast = pPage1; + } + pPager->pFirst = pPage1; + pPager->pFirstSynced = pPage1; + } assert( !pager_lookup(pPager, 1) ); @@ -2802,6 +2839,60 @@ static int pagerSharedLock(Pager *pPager){ return rc; } +/* +** Allocate or recycle space for a single page. +*/ +static int pagerAllocatePage(Pager *pPager, PgHdr **ppPg){ + int rc = SQLITE_OK; + PgHdr *pPg; + + if( !(pPager->pFirstSynced && pPager->pFirstSynced->pgno==0) && ( + pPager->nPagemxPage || pPager->pFirst==0 || MEMDB || + (pPager->pFirstSynced==0 && pPager->doNotSync) + ) ){ + /* Create a new page */ + if( pPager->nPage>=pPager->nHash ){ + pager_resize_hash_table(pPager, + pPager->nHash<256 ? 256 : pPager->nHash*2); + if( pPager->nHash==0 ){ + rc = SQLITE_NOMEM; + goto pager_allocate_out; + } + } + pPg = sqliteMallocRaw( sizeof(*pPg) + pPager->pageSize + + sizeof(u32) + pPager->nExtra + + MEMDB*sizeof(PgHistory) ); + if( pPg==0 ){ + rc = SQLITE_NOMEM; + goto pager_allocate_out; + } + memset(pPg, 0, sizeof(*pPg)); + if( MEMDB ){ + memset(PGHDR_TO_HIST(pPg, pPager), 0, sizeof(PgHistory)); + } + pPg->pPager = pPager; + pPg->pNextAll = pPager->pAll; + pPager->pAll = pPg; + pPager->nPage++; + if( pPager->nPage>pPager->nMaxPage ){ + assert( pPager->nMaxPage==(pPager->nPage-1) ); + pPager->nMaxPage++; + } + }else{ + /* Recycle an existing page with a zero ref-count. */ + rc = pager_recycle(pPager, 1, &pPg); + if( rc!=SQLITE_OK ){ + goto pager_allocate_out; + } + assert( pPager->state>=SHARED_LOCK ); + assert(pPg); + } + *ppPg = pPg; + +pager_allocate_out: + return rc; +} + /* ** Acquire a page. ** @@ -2867,43 +2958,11 @@ int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag){ int nMax; int h; TEST_INCR(pPager->nMiss); - if( pPager->nPagemxPage || pPager->pFirst==0 || MEMDB || - (pPager->pFirstSynced==0 && pPager->doNotSync) - ){ - /* Create a new page */ - if( pPager->nPage>=pPager->nHash ){ - pager_resize_hash_table(pPager, - pPager->nHash<256 ? 256 : pPager->nHash*2); - if( pPager->nHash==0 ){ - return SQLITE_NOMEM; - } - } - pPg = sqliteMallocRaw( sizeof(*pPg) + pPager->pageSize - + sizeof(u32) + pPager->nExtra - + MEMDB*sizeof(PgHistory) ); - if( pPg==0 ){ - return SQLITE_NOMEM; - } - memset(pPg, 0, sizeof(*pPg)); - if( MEMDB ){ - memset(PGHDR_TO_HIST(pPg, pPager), 0, sizeof(PgHistory)); - } - pPg->pPager = pPager; - pPg->pNextAll = pPager->pAll; - pPager->pAll = pPg; - pPager->nPage++; - if( pPager->nPage>pPager->nMaxPage ){ - assert( pPager->nMaxPage==(pPager->nPage-1) ); - pPager->nMaxPage++; - } - }else{ - rc = pager_recycle(pPager, 1, &pPg); - if( rc!=SQLITE_OK ){ - return rc; - } - assert( pPager->state>=SHARED_LOCK ); - assert(pPg); + rc = pagerAllocatePage(pPager, &pPg); + if( rc!=SQLITE_OK ){ + return rc; } + pPg->pgno = pgno; if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){ sqlite3CheckMemory(pPager->aInJournal, pgno/8); diff --git a/src/test2.c b/src/test2.c index 00e05c0379..1398c18379 100644 --- a/src/test2.c +++ b/src/test2.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test2.c,v 1.42 2007/03/30 14:06:34 drh Exp $ +** $Id: test2.c,v 1.43 2007/04/02 05:07:47 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -570,6 +570,7 @@ int Sqlitetest2_Init(Tcl_Interp *interp){ extern int sqlite3_io_error_hit; extern int sqlite3_diskfull_pending; extern int sqlite3_diskfull; + extern int sqlite3_pager_n_sort_bucket; static struct { char *zName; Tcl_CmdProc *xProc; @@ -612,5 +613,7 @@ int Sqlitetest2_Init(Tcl_Interp *interp){ (char*)&sqlite3_pending_byte, TCL_LINK_INT); Tcl_LinkVar(interp, "pager_pagesize", (char*)&test_pagesize, TCL_LINK_INT); + Tcl_LinkVar(interp, "sqlite_pager_n_sort_bucket", + (char*)&sqlite3_pager_n_sort_bucket, TCL_LINK_INT); return TCL_OK; } diff --git a/test/cache.test b/test/cache.test new file mode 100644 index 0000000000..b1eca3829f --- /dev/null +++ b/test/cache.test @@ -0,0 +1,58 @@ +# 2007 March 24 +# +# 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. +# +#*********************************************************************** +# +# $Id: cache.test,v 1.1 2007/04/02 05:07:48 danielk1977 Exp $ + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +ifcapable {!pager_pragmas} { + finish_test + return +} + +proc pager_cache_size {db} { + set bt [btree_from_db $db] + array set stats [btree_pager_stats $bt] + return $stats(page) +} + +do_test cache-1.1 { + pager_cache_size db +} {0} + +do_test cache-1.2 { + execsql { + CREATE TABLE abc(a, b, c); + INSERT INTO abc VALUES(1, 2, 3); + } + pager_cache_size db +} {2} + +# At one point, repeatedly locking and unlocking the cache was causing +# a resource leak of one page per repetition. The page wasn't actually +# leaked, but would not be reused until the pager-cache was full (i.e. +# 2000 pages by default). +# +# This tests that once the pager-cache is initialised, it can be locked +# and unlocked repeatedly without internally allocating any new pages. +# +set cache_size [pager_cache_size db] +for {set ii 0} {$ii < 10} {incr ii} { + + do_test cache-1.3.$ii { + execsql {SELECT * FROM abc} + pager_cache_size db + } $::cache_size + +} + +finish_test diff --git a/test/malloc5.test b/test/malloc5.test index 50c1dda05b..0e5acd97eb 100644 --- a/test/malloc5.test +++ b/test/malloc5.test @@ -12,7 +12,7 @@ # This file contains test cases focused on the two memory-management APIs, # sqlite3_soft_heap_limit() and sqlite3_release_memory(). # -# $Id: malloc5.test,v 1.7 2006/01/19 08:43:32 danielk1977 Exp $ +# $Id: malloc5.test,v 1.8 2007/04/02 05:07:48 danielk1977 Exp $ #--------------------------------------------------------------------------- # NOTES ON EXPECTED BEHAVIOUR @@ -85,6 +85,7 @@ do_test malloc5-1.4 { do_test malloc5-1.5 { # Manipulate the cache so that it contains two unused pages. One requires # a journal-sync to free, the other does not. + db2 close execsql { SELECT * FROM abc; CREATE TABLE def(d, e, f); @@ -95,6 +96,7 @@ do_test malloc5-1.6 { # Database should not be locked this time. The above test case only # requested 500 bytes of memory, which can be obtained by freeing the page # that does not require an fsync(). + sqlite3 db2 test.db catchsql { SELECT * FROM abc; } db2 @@ -102,9 +104,11 @@ do_test malloc5-1.6 { do_test malloc5-1.7 { # Release another 500 bytes of memory. This time we require a sync(), # so the database file will be locked afterwards. + db2 close sqlite3_release_memory 500 } $::pgalloc do_test malloc5-1.8 { + sqlite3 db2 test.db catchsql { SELECT * FROM abc; } db2 diff --git a/test/misc7.test b/test/misc7.test index d07b3f08cb..4af1b9d7d0 100644 --- a/test/misc7.test +++ b/test/misc7.test @@ -10,7 +10,7 @@ #*********************************************************************** # This file implements regression tests for SQLite library. # -# $Id: misc7.test,v 1.9 2007/03/31 10:00:49 danielk1977 Exp $ +# $Id: misc7.test,v 1.10 2007/04/02 05:07:48 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -158,7 +158,8 @@ do_test misc7-7.2 { } } {} -# Test malloc failure whilst installing a foriegn key. +# Test the UTF-16 version of the "out of memory" message (used when +# malloc fails during sqlite3_open() ). # ifcapable utf16 { do_test misc7-8 { @@ -327,7 +328,15 @@ do_ioerr_test misc7-16 -sqlprep { } } - - +sqlite3 db test.db +set sqlite_pager_n_sort_bucket 4 +do_test misc7-17 { + execsql { + PRAGMA integrity_check; + VACUUM; + PRAGMA integrity_check; + } +} {ok ok} +set sqlite_pager_n_sort_bucket 0 finish_test diff --git a/test/pager.test b/test/pager.test index 176e00d7e6..0b1c850215 100644 --- a/test/pager.test +++ b/test/pager.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this script is page cache subsystem. # -# $Id: pager.test,v 1.26 2007/03/23 18:12:07 danielk1977 Exp $ +# $Id: pager.test,v 1.27 2007/04/02 05:07:48 danielk1977 Exp $ set testdir [file dirname $argv0] @@ -119,7 +119,7 @@ do_test pager-2.12 { } {1} do_test pager-2.13 { pager_stats $::p1 -} {ref 1 page 2 max 10 size 0 state 1 err 0 hit 1 miss 2 ovfl 0} +} {ref 1 page 1 max 10 size 0 state 1 err 0 hit 1 miss 2 ovfl 0} do_test pager-2.14 { set v [catch { page_write $::g1 "Page-One" @@ -128,7 +128,7 @@ do_test pager-2.14 { } {0 {}} do_test pager-2.15 { pager_stats $::p1 -} {ref 1 page 2 max 10 size 1 state 2 err 0 hit 1 miss 2 ovfl 0} +} {ref 1 page 1 max 10 size 1 state 2 err 0 hit 1 miss 2 ovfl 0} do_test pager-2.16 { page_read $::g1 } {Page-One} @@ -140,19 +140,19 @@ do_test pager-2.17 { } {0 {}} do_test pager-2.20 { pager_stats $::p1 -} {ref 1 page 2 max 10 size -1 state 1 err 0 hit 2 miss 2 ovfl 0} +} {ref 1 page 1 max 10 size -1 state 1 err 0 hit 2 miss 2 ovfl 0} do_test pager-2.19 { pager_pagecount $::p1 } {1} do_test pager-2.21 { pager_stats $::p1 -} {ref 1 page 2 max 10 size 1 state 1 err 0 hit 2 miss 2 ovfl 0} +} {ref 1 page 1 max 10 size 1 state 1 err 0 hit 2 miss 2 ovfl 0} do_test pager-2.22 { page_unref $::g1 } {} do_test pager-2.23 { pager_stats $::p1 -} {ref 0 page 2 max 10 size -1 state 0 err 0 hit 2 miss 2 ovfl 0} +} {ref 0 page 1 max 10 size -1 state 0 err 0 hit 2 miss 2 ovfl 0} do_test pager-2.24 { set v [catch { page_get $::p1 1