1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Simplify the pcache module by only recycling clean pages from 'other' caches. This commit causes errors in test files ioerr5.test and malloc5.test because they test recycling dirty pages from other caches. (CVS 5615)

FossilOrigin-Name: 9e511e161bcb077450d31fca5dd20c2557f103b3
This commit is contained in:
danielk1977
2008-08-26 18:05:48 +00:00
parent 1a4e3162d9
commit d491e1bfd1
8 changed files with 227 additions and 351 deletions

View File

@@ -1,5 +1,5 @@
C Implement\sa\s"counter"\sSQL\sfunction\sthat\scan\sbe\sused\sto\sinsert\sa\ssequence\nnumber\seach\srow\sof\sa\sresult\sset.\s\sCurrently\sin\sthe\stest\sharness\sonly,\sbut\na\scandidate\sto\smove\sinto\sthe\score.\s(CVS\s5614) C Simplify\sthe\spcache\smodule\sby\sonly\srecycling\sclean\spages\sfrom\s'other'\scaches.\sThis\scommit\scauses\serrors\sin\stest\sfiles\sioerr5.test\sand\smalloc5.test\sbecause\sthey\stest\srecycling\sdirty\spages\sfrom\sother\scaches.\s(CVS\s5615)
D 2008-08-26T14:42:15 D 2008-08-26T18:05:48
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in 689e14735f862a5553bceef206d8c13e29504e44 F Makefile.in 689e14735f862a5553bceef206d8c13e29504e44
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -135,11 +135,11 @@ F src/os_common.h 24525d8b7bce66c374dfc1810a6c9043f3359b60
F src/os_os2.c e391fc95adc744bbdcefd4d11e3066998185a0a0 F src/os_os2.c e391fc95adc744bbdcefd4d11e3066998185a0a0
F src/os_unix.c 4665cef7639dd937893c3ea076f0e8a8f215bb32 F src/os_unix.c 4665cef7639dd937893c3ea076f0e8a8f215bb32
F src/os_win.c aefe9ee26430678a19a058a874e4e2bd91398142 F src/os_win.c aefe9ee26430678a19a058a874e4e2bd91398142
F src/pager.c 67d689efa33fbca2788d006e18dd7d1a7de22487 F src/pager.c 9dfaca6cd443228326b1837fbb712b9cbde9a0e0
F src/pager.h 3b9c138d2e744b9d6e61d4c2742301e3bf464864 F src/pager.h 3b9c138d2e744b9d6e61d4c2742301e3bf464864
F src/parse.y d0f76d2cb8d6883d5600dc20beb961a6022b94b8 F src/parse.y d0f76d2cb8d6883d5600dc20beb961a6022b94b8
F src/pcache.c 4883f3714503242057643a5dddbc74065def5157 F src/pcache.c 03c2ad23aa6f9cf008a6fe4ee68a07b3948d331f
F src/pcache.h f03fc3b8241da092bd929ba0eec15e84d9d2cca0 F src/pcache.h 3531f83e1771442af16f6ffeac68024ff8c8bb2d
F src/pragma.c f5b271b090af7fcedd308d7c5807a5503f7a853d F src/pragma.c f5b271b090af7fcedd308d7c5807a5503f7a853d
F src/prepare.c c197041e0c4770672cda75e6bfe10242f885e510 F src/prepare.c c197041e0c4770672cda75e6bfe10242f885e510
F src/printf.c 785f87120589c1db672e37c6eb1087c456e6f84d F src/printf.c 785f87120589c1db672e37c6eb1087c456e6f84d
@@ -155,7 +155,7 @@ F src/status.c 8caa772cd9310bc297280f7cf0ede4d69ed5b801
F src/table.c 22744786199c9195720c15a7a42cb97b2e2728d8 F src/table.c 22744786199c9195720c15a7a42cb97b2e2728d8
F src/tclsqlite.c ec46084184f033ba396a9ee7b5514b695083d0f3 F src/tclsqlite.c ec46084184f033ba396a9ee7b5514b695083d0f3
F src/test1.c f92039530f6a6253ec8d3bfeaa54205a0036bbb6 F src/test1.c f92039530f6a6253ec8d3bfeaa54205a0036bbb6
F src/test2.c 9601907ac0bab60f2f81695c3a6e9249621ae741 F src/test2.c eaa77124786649eedf47d3c5e94d8070c0da228f
F src/test3.c e85b7ce5c28c3ce7fbdbf7f98e1467b19786c62b F src/test3.c e85b7ce5c28c3ce7fbdbf7f98e1467b19786c62b
F src/test4.c 41056378671e7b00e6305fa9ac6fa27e6f96f406 F src/test4.c 41056378671e7b00e6305fa9ac6fa27e6f96f406
F src/test5.c 162a1cea2105a2c460a3f39fa6919617b562a288 F src/test5.c 162a1cea2105a2c460a3f39fa6919617b562a288
@@ -421,7 +421,7 @@ F test/malloc_common.tcl e082fe4791dad22b49d2ad3f7dcf1dcbee1a4cec
F test/manydb.test 8de36b8d33aab5ef295b11d9e95310aeded31af8 F test/manydb.test 8de36b8d33aab5ef295b11d9e95310aeded31af8
F test/memdb.test a67bda4ff90a38f2b19f6c7f95aa7289e051d893 F test/memdb.test a67bda4ff90a38f2b19f6c7f95aa7289e051d893
F test/memleak.test d2d2a1ff7105d32dc3fdf691458cf6cba58c7217 F test/memleak.test d2d2a1ff7105d32dc3fdf691458cf6cba58c7217
F test/memsubsys1.test bd578712272a3c327873b388396e351586d29e61 F test/memsubsys1.test c12d1e4ad7f0ec7a45b56b5c49fe7397fa8d6d8f
F test/memsubsys2.test 72a731225997ad5e8df89fdbeae9224616b6aecc F test/memsubsys2.test 72a731225997ad5e8df89fdbeae9224616b6aecc
F test/minmax.test 722d80816f7e096bf2c04f4111f1a6c1ba65453d F test/minmax.test 722d80816f7e096bf2c04f4111f1a6c1ba65453d
F test/minmax2.test 33504c01a03bd99226144e4b03f7631a274d66e0 F test/minmax2.test 33504c01a03bd99226144e4b03f7631a274d66e0
@@ -531,7 +531,7 @@ F test/tkt2285.test cca17be61cf600b397188e77e7143844d2b977e9
F test/tkt2332.test fc955609b958ca86dfa102832243370a0cc84070 F test/tkt2332.test fc955609b958ca86dfa102832243370a0cc84070
F test/tkt2339.test 73bd17818924cd2ac442e5fd9916b58565739450 F test/tkt2339.test 73bd17818924cd2ac442e5fd9916b58565739450
F test/tkt2391.test ab7a11be7402da8b51a5be603425367aa0684567 F test/tkt2391.test ab7a11be7402da8b51a5be603425367aa0684567
F test/tkt2409.test 695269f90bbd30285fb1dd1499e8cc0d827a647d F test/tkt2409.test c9599f296178eb764a7d6260c5403e1e921d9fef
F test/tkt2450.test 77ed94863f2049c1420288ddfea2d41e5e0971d6 F test/tkt2450.test 77ed94863f2049c1420288ddfea2d41e5e0971d6
F test/tkt2640.test 28134f5d1e05658ef182520cf0b680fa3de5211b F test/tkt2640.test 28134f5d1e05658ef182520cf0b680fa3de5211b
F test/tkt2643.test 3f3ebb743da00d4fed4fcf6daed92a0e18e57813 F test/tkt2643.test 3f3ebb743da00d4fed4fcf6daed92a0e18e57813
@@ -624,7 +624,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1 F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
P 4995a1d1c9530be9ce647d338169620cd95a72eb P c84d46c71233bbf869513f433b1d18cbd7f2a35e
R 53057febb14c48765135eac34d009c5b R 9db6a9b878af9d031aaa0c602a425d48
U drh U danielk1977
Z 0de0cfc7bacf48ec9c7d1199a1a02018 Z e27423cf6787772e11bb472965b58787

View File

@@ -1 +1 @@
c84d46c71233bbf869513f433b1d18cbd7f2a35e 9e511e161bcb077450d31fca5dd20c2557f103b3

View File

@@ -18,7 +18,7 @@
** file simultaneously, or one process from reading the database while ** file simultaneously, or one process from reading the database while
** another is writing. ** another is writing.
** **
** @(#) $Id: pager.c,v 1.479 2008/08/25 17:23:29 drh Exp $ ** @(#) $Id: pager.c,v 1.480 2008/08/26 18:05:48 danielk1977 Exp $
*/ */
#ifndef SQLITE_OMIT_DISKIO #ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h" #include "sqliteInt.h"
@@ -302,18 +302,6 @@ static const unsigned char aJournalMagic[] = {
*/ */
#define PAGER_MAX_PGNO 2147483647 #define PAGER_MAX_PGNO 2147483647
/*
** The following two macros act as a type of recursive mutex. Their
** only purpose is to provide mutual exclusion between the "normal"
** users of a pager object (the btree.c module) and the user of the
** pagerStress() function (the pcache.c module). While the mutex
** obtained using pagerEnter() is held, the pcache module guarantees
** that the pagerStress() callback will not be invoked from a thread
** other than the holder of the mutex.
*/
#define pagerEnter(p) (sqlite3PcacheLock(p->pPCache))
#define pagerLeave(p) (sqlite3PcacheUnlock(p->pPCache))
/* /*
** Return true if page *pPg has already been written to the statement ** Return true if page *pPg has already been written to the statement
** journal (or statement snapshot has been created, if *pPg is part ** journal (or statement snapshot has been created, if *pPg is part
@@ -1956,7 +1944,6 @@ int sqlite3PagerSetPagesize(Pager *pPager, u16 *pPageSize){
int rc = SQLITE_OK; int rc = SQLITE_OK;
u16 pageSize = *pPageSize; u16 pageSize = *pPageSize;
assert( pageSize==0 || (pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE) ); assert( pageSize==0 || (pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE) );
pagerEnter(pPager);
if( pageSize && pageSize!=pPager->pageSize if( pageSize && pageSize!=pPager->pageSize
&& !pPager->memDb && sqlite3PcacheRefCount(pPager->pPCache)==0 && !pPager->memDb && sqlite3PcacheRefCount(pPager->pPCache)==0
){ ){
@@ -1973,7 +1960,6 @@ int sqlite3PagerSetPagesize(Pager *pPager, u16 *pPageSize){
} }
} }
*pPageSize = pPager->pageSize; *pPageSize = pPager->pageSize;
pagerLeave(pPager);
return rc; return rc;
} }
@@ -2042,7 +2028,6 @@ int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned char *pDest){
int rc = SQLITE_OK; int rc = SQLITE_OK;
memset(pDest, 0, N); memset(pDest, 0, N);
assert(MEMDB||pPager->fd->pMethods||pPager->tempFile); assert(MEMDB||pPager->fd->pMethods||pPager->tempFile);
pagerEnter(pPager);
if( pPager->fd->pMethods ){ if( pPager->fd->pMethods ){
IOTRACE(("DBHDR %p 0 %d\n", pPager, N)) IOTRACE(("DBHDR %p 0 %d\n", pPager, N))
rc = sqlite3OsRead(pPager->fd, pDest, N, 0); rc = sqlite3OsRead(pPager->fd, pDest, N, 0);
@@ -2050,7 +2035,6 @@ int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned char *pDest){
rc = SQLITE_OK; rc = SQLITE_OK;
} }
} }
pagerLeave(pPager);
return rc; return rc;
} }
@@ -2067,10 +2051,8 @@ int sqlite3PagerPagecount(Pager *pPager, int *pnPage){
i64 n = 0; i64 n = 0;
int rc; int rc;
assert( pPager!=0 ); assert( pPager!=0 );
pagerEnter(pPager);
if( pPager->errCode ){ if( pPager->errCode ){
rc = pPager->errCode; rc = pPager->errCode;
pagerLeave(pPager);
return rc; return rc;
} }
if( pPager->dbSize>=0 ){ if( pPager->dbSize>=0 ){
@@ -2080,7 +2062,6 @@ int sqlite3PagerPagecount(Pager *pPager, int *pnPage){
if( (pPager->fd->pMethods) if( (pPager->fd->pMethods)
&& (rc = sqlite3OsFileSize(pPager->fd, &n))!=SQLITE_OK ){ && (rc = sqlite3OsFileSize(pPager->fd, &n))!=SQLITE_OK ){
pager_error(pPager, rc); pager_error(pPager, rc);
pagerLeave(pPager);
return rc; return rc;
} }
if( n>0 && n<pPager->pageSize ){ if( n>0 && n<pPager->pageSize ){
@@ -2101,7 +2082,6 @@ int sqlite3PagerPagecount(Pager *pPager, int *pnPage){
if( pnPage ){ if( pnPage ){
*pnPage = n; *pnPage = n;
} }
pagerLeave(pPager);
return SQLITE_OK; return SQLITE_OK;
} }
@@ -2167,7 +2147,6 @@ int sqlite3PagerTruncate(Pager *pPager, Pgno nPage){
int rc = SQLITE_OK; int rc = SQLITE_OK;
assert( pPager->state>=PAGER_SHARED || MEMDB ); assert( pPager->state>=PAGER_SHARED || MEMDB );
pagerEnter(pPager);
sqlite3PagerPagecount(pPager, 0); sqlite3PagerPagecount(pPager, 0);
if( pPager->errCode ){ if( pPager->errCode ){
@@ -2188,7 +2167,6 @@ int sqlite3PagerTruncate(Pager *pPager, Pgno nPage){
} }
} }
pagerLeave(pPager);
return rc; return rc;
} }
@@ -2207,7 +2185,6 @@ int sqlite3PagerTruncate(Pager *pPager, Pgno nPage){
** to the caller. ** to the caller.
*/ */
int sqlite3PagerClose(Pager *pPager){ int sqlite3PagerClose(Pager *pPager){
pagerEnter(pPager);
disable_simulated_io_errors(); disable_simulated_io_errors();
sqlite3BeginBenignMalloc(); sqlite3BeginBenignMalloc();
@@ -2253,9 +2230,7 @@ Pgno sqlite3PagerPagenumber(DbPage *p){
** a reference to the page data. ** a reference to the page data.
*/ */
int sqlite3PagerRef(DbPage *pPg){ int sqlite3PagerRef(DbPage *pPg){
pagerEnter(pPg->pPager);
sqlite3PcacheRef(pPg); sqlite3PcacheRef(pPg);
pagerLeave(pPg->pPager);
return SQLITE_OK; return SQLITE_OK;
} }
@@ -2916,9 +2891,7 @@ int sqlite3PagerAcquire(
int noContent /* Do not bother reading content from disk if true */ int noContent /* Do not bother reading content from disk if true */
){ ){
int rc; int rc;
pagerEnter(pPager);
rc = pagerAcquire(pPager, pgno, ppPage, noContent); rc = pagerAcquire(pPager, pgno, ppPage, noContent);
pagerLeave(pPager);
return rc; return rc;
} }
@@ -2939,13 +2912,11 @@ DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
assert( pPager!=0 ); assert( pPager!=0 );
assert( pgno!=0 ); assert( pgno!=0 );
pagerEnter(pPager);
if( (pPager->state!=PAGER_UNLOCK) if( (pPager->state!=PAGER_UNLOCK)
&& (pPager->errCode==SQLITE_OK || pPager->errCode==SQLITE_FULL) && (pPager->errCode==SQLITE_OK || pPager->errCode==SQLITE_FULL)
){ ){
sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &pPg); sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &pPg);
} }
pagerLeave(pPager);
return pPg; return pPg;
} }
@@ -2961,10 +2932,8 @@ DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
int sqlite3PagerUnref(DbPage *pPg){ int sqlite3PagerUnref(DbPage *pPg){
if( pPg ){ if( pPg ){
Pager *pPager = pPg->pPager; Pager *pPager = pPg->pPager;
pagerEnter(pPager);
sqlite3PcacheRelease(pPg); sqlite3PcacheRelease(pPg);
pagerUnlockIfUnused(pPager); pagerUnlockIfUnused(pPager);
pagerLeave(pPager);
} }
return SQLITE_OK; return SQLITE_OK;
} }
@@ -2986,9 +2955,7 @@ static int pager_open_journal(Pager *pPager){
assert( pPager->useJournal ); assert( pPager->useJournal );
assert( pPager->pInJournal==0 ); assert( pPager->pInJournal==0 );
sqlite3PagerPagecount(pPager, 0); sqlite3PagerPagecount(pPager, 0);
pagerLeave(pPager);
pPager->pInJournal = sqlite3BitvecCreate(pPager->dbSize); pPager->pInJournal = sqlite3BitvecCreate(pPager->dbSize);
pagerEnter(pPager);
if( pPager->pInJournal==0 ){ if( pPager->pInJournal==0 ){
rc = SQLITE_NOMEM; rc = SQLITE_NOMEM;
goto failed_to_open_journal; goto failed_to_open_journal;
@@ -3078,7 +3045,6 @@ failed_to_open_journal:
int sqlite3PagerBegin(DbPage *pPg, int exFlag){ int sqlite3PagerBegin(DbPage *pPg, int exFlag){
Pager *pPager = pPg->pPager; Pager *pPager = pPg->pPager;
int rc = SQLITE_OK; int rc = SQLITE_OK;
pagerEnter(pPager);
assert( pPg->nRef>0 ); assert( pPg->nRef>0 );
assert( pPager->state!=PAGER_UNLOCK ); assert( pPager->state!=PAGER_UNLOCK );
if( pPager->state==PAGER_SHARED ){ if( pPager->state==PAGER_SHARED ){
@@ -3096,7 +3062,6 @@ int sqlite3PagerBegin(DbPage *pPg, int exFlag){
} }
} }
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
pagerLeave(pPager);
return rc; return rc;
} }
pPager->dirtyCache = 0; pPager->dirtyCache = 0;
@@ -3126,7 +3091,6 @@ int sqlite3PagerBegin(DbPage *pPg, int exFlag){
} }
} }
assert( !pPager->journalOpen || pPager->journalOff>0 || rc!=SQLITE_OK ); assert( !pPager->journalOpen || pPager->journalOff>0 || rc!=SQLITE_OK );
pagerLeave(pPager);
return rc; return rc;
} }
@@ -3362,7 +3326,6 @@ int sqlite3PagerWrite(DbPage *pDbPage){
Pager *pPager = pPg->pPager; Pager *pPager = pPg->pPager;
Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize); Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize);
pagerEnter(pPager);
if( !MEMDB && nPagePerSector>1 ){ if( !MEMDB && nPagePerSector>1 ){
Pgno nPageCount; /* Total number of pages in database file */ Pgno nPageCount; /* Total number of pages in database file */
Pgno pg1; /* First page of the sector pPg is located on. */ Pgno pg1; /* First page of the sector pPg is located on. */
@@ -3436,7 +3399,6 @@ int sqlite3PagerWrite(DbPage *pDbPage){
}else{ }else{
rc = pager_write(pDbPage); rc = pager_write(pDbPage);
} }
pagerLeave(pPager);
return rc; return rc;
} }
@@ -3480,7 +3442,6 @@ void sqlite3PagerDontWrite(DbPage *pDbPage){
Pager *pPager = pPg->pPager; Pager *pPager = pPg->pPager;
if( MEMDB ) return; if( MEMDB ) return;
pagerEnter(pPager);
pPg->flags |= PGHDR_ALWAYS_ROLLBACK; pPg->flags |= PGHDR_ALWAYS_ROLLBACK;
if( (pPg->flags&PGHDR_DIRTY) && !pPager->stmtInUse ){ if( (pPg->flags&PGHDR_DIRTY) && !pPager->stmtInUse ){
assert( pPager->state>=PAGER_SHARED ); assert( pPager->state>=PAGER_SHARED );
@@ -3502,7 +3463,6 @@ void sqlite3PagerDontWrite(DbPage *pDbPage){
#endif #endif
} }
} }
pagerLeave(pPager);
} }
/* /*
@@ -3519,7 +3479,6 @@ void sqlite3PagerDontWrite(DbPage *pDbPage){
void sqlite3PagerDontRollback(DbPage *pPg){ void sqlite3PagerDontRollback(DbPage *pPg){
Pager *pPager = pPg->pPager; Pager *pPager = pPg->pPager;
pagerEnter(pPager);
assert( pPager->state>=PAGER_RESERVED ); assert( pPager->state>=PAGER_RESERVED );
/* If the journal file is not open, or DontWrite() has been called on /* If the journal file is not open, or DontWrite() has been called on
@@ -3529,14 +3488,12 @@ void sqlite3PagerDontRollback(DbPage *pPg){
if( pPager->journalOpen==0 || (pPg->flags&PGHDR_ALWAYS_ROLLBACK) if( pPager->journalOpen==0 || (pPg->flags&PGHDR_ALWAYS_ROLLBACK)
|| pPager->alwaysRollback || pPager->alwaysRollback
){ ){
pagerLeave(pPager);
return; return;
} }
assert( !MEMDB ); /* For a memdb, pPager->journalOpen is always 0 */ assert( !MEMDB ); /* For a memdb, pPager->journalOpen is always 0 */
#ifdef SQLITE_SECURE_DELETE #ifdef SQLITE_SECURE_DELETE
if( pPg->inJournal || (int)pPg->pgno > pPager->origDbSize ){ if( pPg->inJournal || (int)pPg->pgno > pPager->origDbSize ){
pagerLeave(pPager);
return; return;
} }
#endif #endif
@@ -3563,7 +3520,6 @@ void sqlite3PagerDontRollback(DbPage *pPg){
} }
PAGERTRACE3("DONT_ROLLBACK page %d of %d\n", pPg->pgno, PAGERID(pPager)); PAGERTRACE3("DONT_ROLLBACK page %d of %d\n", pPg->pgno, PAGERID(pPager));
IOTRACE(("GARBAGE %p %d\n", pPager, pPg->pgno)) IOTRACE(("GARBAGE %p %d\n", pPager, pPg->pgno))
pagerLeave(pPager);
} }
@@ -3616,9 +3572,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirect){
*/ */
int sqlite3PagerSync(Pager *pPager){ int sqlite3PagerSync(Pager *pPager){
int rc; int rc;
pagerEnter(pPager);
rc = sqlite3OsSync(pPager->fd, pPager->sync_flags); rc = sqlite3OsSync(pPager->fd, pPager->sync_flags);
pagerLeave(pPager);
return rc; return rc;
} }
@@ -3667,7 +3621,6 @@ int sqlite3PagerCommitPhaseOne(
PAGERTRACE4("DATABASE SYNC: File=%s zMaster=%s nTrunc=%d\n", PAGERTRACE4("DATABASE SYNC: File=%s zMaster=%s nTrunc=%d\n",
pPager->zFilename, zMaster, nTrunc); pPager->zFilename, zMaster, nTrunc);
pagerEnter(pPager);
/* If this is an in-memory db, or no pages have been written to, or this /* If this is an in-memory db, or no pages have been written to, or this
** function has already been called, it is a no-op. ** function has already been called, it is a no-op.
@@ -3797,7 +3750,6 @@ sync_exit:
*/ */
rc = SQLITE_BUSY; rc = SQLITE_BUSY;
} }
pagerLeave(pPager);
return rc; return rc;
} }
@@ -3824,7 +3776,6 @@ int sqlite3PagerCommitPhaseTwo(Pager *pPager){
assert( pPager->dirtyCache==0 || pPager->journalOpen==0 ); assert( pPager->dirtyCache==0 || pPager->journalOpen==0 );
return SQLITE_OK; return SQLITE_OK;
} }
pagerEnter(pPager);
PAGERTRACE2("COMMIT %d\n", PAGERID(pPager)); PAGERTRACE2("COMMIT %d\n", PAGERID(pPager));
if( MEMDB ){ if( MEMDB ){
sqlite3PcacheCommit(pPager->pPCache, 0); sqlite3PcacheCommit(pPager->pPCache, 0);
@@ -3838,7 +3789,6 @@ int sqlite3PagerCommitPhaseTwo(Pager *pPager){
rc = pager_end_transaction(pPager, pPager->setMaster); rc = pager_end_transaction(pPager, pPager->setMaster);
rc = pager_error(pPager, rc); rc = pager_error(pPager, rc);
} }
pagerLeave(pPager);
return rc; return rc;
} }
@@ -3857,7 +3807,6 @@ int sqlite3PagerCommitPhaseTwo(Pager *pPager){
int sqlite3PagerRollback(Pager *pPager){ int sqlite3PagerRollback(Pager *pPager){
int rc = SQLITE_OK; int rc = SQLITE_OK;
PAGERTRACE2("ROLLBACK %d\n", PAGERID(pPager)); PAGERTRACE2("ROLLBACK %d\n", PAGERID(pPager));
pagerEnter(pPager);
if( MEMDB ){ if( MEMDB ){
sqlite3PcacheRollback(pPager->pPCache, 1); sqlite3PcacheRollback(pPager->pPCache, 1);
sqlite3PcacheRollback(pPager->pPCache, 0); sqlite3PcacheRollback(pPager->pPCache, 0);
@@ -3896,7 +3845,6 @@ int sqlite3PagerRollback(Pager *pPager){
*/ */
rc = pager_error(pPager, rc); rc = pager_error(pPager, rc);
} }
pagerLeave(pPager);
return rc; return rc;
} }
@@ -3921,7 +3869,6 @@ int sqlite3PagerRefcount(Pager *pPager){
*/ */
int *sqlite3PagerStats(Pager *pPager){ int *sqlite3PagerStats(Pager *pPager){
static int a[11]; static int a[11];
pagerEnter(pPager);
a[0] = sqlite3PcacheRefCount(pPager->pPCache); a[0] = sqlite3PcacheRefCount(pPager->pPCache);
a[1] = sqlite3PcachePagecount(pPager->pPCache); a[1] = sqlite3PcachePagecount(pPager->pPCache);
a[2] = sqlite3PcacheGetCachesize(pPager->pPCache); a[2] = sqlite3PcacheGetCachesize(pPager->pPCache);
@@ -3933,7 +3880,6 @@ int *sqlite3PagerStats(Pager *pPager){
a[8] = 0; /* Used to be pPager->nOvfl */ a[8] = 0; /* Used to be pPager->nOvfl */
a[9] = pPager->nRead; a[9] = pPager->nRead;
a[10] = pPager->nWrite; a[10] = pPager->nWrite;
pagerLeave(pPager);
return a; return a;
} }
int sqlite3PagerIsMemdb(Pager *pPager){ int sqlite3PagerIsMemdb(Pager *pPager){
@@ -3994,9 +3940,7 @@ stmt_begin_failed:
} }
int sqlite3PagerStmtBegin(Pager *pPager){ int sqlite3PagerStmtBegin(Pager *pPager){
int rc; int rc;
pagerEnter(pPager);
rc = pagerStmtBegin(pPager); rc = pagerStmtBegin(pPager);
pagerLeave(pPager);
return rc; return rc;
} }
@@ -4004,7 +3948,6 @@ int sqlite3PagerStmtBegin(Pager *pPager){
** Commit a statement. ** Commit a statement.
*/ */
int sqlite3PagerStmtCommit(Pager *pPager){ int sqlite3PagerStmtCommit(Pager *pPager){
pagerEnter(pPager);
if( pPager->stmtInUse ){ if( pPager->stmtInUse ){
PAGERTRACE2("STMT-COMMIT %d\n", PAGERID(pPager)); PAGERTRACE2("STMT-COMMIT %d\n", PAGERID(pPager));
if( !MEMDB ){ if( !MEMDB ){
@@ -4018,7 +3961,6 @@ int sqlite3PagerStmtCommit(Pager *pPager){
pPager->stmtInUse = 0; pPager->stmtInUse = 0;
} }
pPager->stmtAutoopen = 0; pPager->stmtAutoopen = 0;
pagerLeave(pPager);
return SQLITE_OK; return SQLITE_OK;
} }
@@ -4027,7 +3969,6 @@ int sqlite3PagerStmtCommit(Pager *pPager){
*/ */
int sqlite3PagerStmtRollback(Pager *pPager){ int sqlite3PagerStmtRollback(Pager *pPager){
int rc; int rc;
pagerEnter(pPager);
if( pPager->stmtInUse ){ if( pPager->stmtInUse ){
PAGERTRACE2("STMT-ROLLBACK %d\n", PAGERID(pPager)); PAGERTRACE2("STMT-ROLLBACK %d\n", PAGERID(pPager));
if( MEMDB ){ if( MEMDB ){
@@ -4043,7 +3984,6 @@ int sqlite3PagerStmtRollback(Pager *pPager){
rc = SQLITE_OK; rc = SQLITE_OK;
} }
pPager->stmtAutoopen = 0; pPager->stmtAutoopen = 0;
pagerLeave(pPager);
return rc; return rc;
} }
@@ -4139,8 +4079,6 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
PAGERID(pPager), pPg->pgno, (pPg->flags&PGHDR_NEED_SYNC)?1:0, pgno); PAGERID(pPager), pPg->pgno, (pPg->flags&PGHDR_NEED_SYNC)?1:0, pgno);
IOTRACE(("MOVE %p %d %d\n", pPager, pPg->pgno, pgno)) IOTRACE(("MOVE %p %d %d\n", pPager, pPg->pgno, pgno))
pagerEnter(pPager);
pager_get_content(pPg); pager_get_content(pPg);
/* If the journal needs to be sync()ed before page pPg->pgno can /* If the journal needs to be sync()ed before page pPg->pgno can
@@ -4208,7 +4146,6 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
if( pPager->pInJournal && (int)needSyncPgno<=pPager->origDbSize ){ if( pPager->pInJournal && (int)needSyncPgno<=pPager->origDbSize ){
sqlite3BitvecClear(pPager->pInJournal, needSyncPgno); sqlite3BitvecClear(pPager->pInJournal, needSyncPgno);
} }
pagerLeave(pPager);
return rc; return rc;
} }
pPager->needSync = 1; pPager->needSync = 1;
@@ -4218,7 +4155,6 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
sqlite3PagerUnref(pPgHdr); sqlite3PagerUnref(pPgHdr);
} }
pagerLeave(pPager);
return SQLITE_OK; return SQLITE_OK;
} }
#endif #endif

View File

@@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** This file implements that page cache. ** This file implements that page cache.
** **
** @(#) $Id: pcache.c,v 1.13 2008/08/25 14:49:42 danielk1977 Exp $ ** @(#) $Id: pcache.c,v 1.14 2008/08/26 18:05:48 danielk1977 Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@@ -19,23 +19,22 @@
** A complete page cache is an instance of this structure. ** A complete page cache is an instance of this structure.
*/ */
struct PCache { struct PCache {
PCache *pNextAll, *pPrevAll; /* List of all page caches */
int szPage; /* Size of every page in this cache */ int szPage; /* Size of every page in this cache */
int szExtra; /* Size of extra space for each page */ int szExtra; /* Size of extra space for each page */
int nHash; /* Number of slots in apHash[] */ int nHash; /* Number of slots in apHash[] */
int nPage; /* Total number of pages in apHash */ int nPage; /* Total number of pages in apHash */
int nMax; /* Configured cache size */ int nMax; /* Configured cache size */
int nMin; /* Configured minimum cache size */
PgHdr **apHash; /* Hash table for fast lookup by pgno */ PgHdr **apHash; /* Hash table for fast lookup by pgno */
int bPurgeable; /* True if pages are on backing store */ int bPurgeable; /* True if pages are on backing store */
void (*xDestroy)(PgHdr*); /* Called when refcnt goes 1->0 */ void (*xDestroy)(PgHdr*); /* Called when refcnt goes 1->0 */
int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */ int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */
void *pStress; /* Argument to xStress */ void *pStress; /* Argument to xStress */
PgHdr *pClean; /* List of clean pages in use */ PgHdr *pClean; /* List of clean pages in use */
PgHdr *pDirty; /* List of dirty pages */ PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */
int nRef; /* Number of outstanding page refs */ PgHdr *pSynced; /* Last synced page in dirty page list */
int nRef; /* Number of pinned pages */
int iInUseMM; int nPinned; /* Number of pinned and/or dirty pages */
int iInUseDB;
}; };
/* /*
@@ -59,23 +58,18 @@ struct PgFreeslot {
** pages held by purgable caches to mxPagePurgeable. ** pages held by purgable caches to mxPagePurgeable.
** **
** The doubly-linked list that runs between pcache.pLruHead and ** The doubly-linked list that runs between pcache.pLruHead and
** pcache.pLruTail contains all pages in the system with a zero ** pcache.pLruTail contains all clean purgable pages in the system
** reference count. The pcache.pLruSynced variable points to the last ** with a zero reference count. pcache.pLruTail is the next page to
** (closest to pcache.pLruTail) entry in this list that does not have ** be recycled.
** the PGHDR_NEED_SYNC flag set. This is the page that the pcacheRecycle()
** function will try to recycle.
*/ */
static struct PCacheGlobal { static struct PCacheGlobal {
int isInit; /* True when initialized */ int isInit; /* True when initialized */
sqlite3_mutex *mutex_mem2; /* static mutex MUTEX_STATIC_MEM2 */ sqlite3_mutex *mutex; /* static mutex MUTEX_STATIC_LRU */
sqlite3_mutex *mutex_lru; /* static mutex MUTEX_STATIC_LRU */
PCache *pAll; /* list of all page caches */ int nMaxPage; /* Sum of nMaxPage for purgeable caches */
int nPage; /* Number of pages */ int nMinPage; /* Sum of nMinPage for purgeable caches */
int nPurgeable; /* Number of pages in purgable caches */ int nCurrentPage; /* Number of purgeable pages allocated */
int mxPage; /* Globally configured page maximum */ PgHdr *pLruHead, *pLruTail; /* LRU list of unused clean pgs */
int mxPagePurgeable; /* Purgeable page maximum */
PgHdr *pLruHead, *pLruTail; /* Global LRU list of unused pages */
PgHdr *pLruSynced; /* Last synced entry in LRU list */
/* Variables related to SQLITE_CONFIG_PAGECACHE settings. */ /* Variables related to SQLITE_CONFIG_PAGECACHE settings. */
int szSlot; /* Size of each free slot */ int szSlot; /* Size of each free slot */
@@ -85,31 +79,17 @@ static struct PCacheGlobal {
/* /*
** All global variables used by this module (most of which are grouped ** All global variables used by this module (most of which are grouped
** together in global structure "pcache" above) except the list of all ** together in global structure "pcache" above) are protected by the static
** pager-caches starting with pcache.pAll, are protected by the static
** SQLITE_MUTEX_STATIC_LRU mutex. A pointer to this mutex is stored in ** SQLITE_MUTEX_STATIC_LRU mutex. A pointer to this mutex is stored in
** variable "pcache.mutex_lru". ** variable "pcache.mutex".
** **
** Access to the contents of the individual PCache structures is not ** Access to the contents of the individual PCache structures is not
** protected. It is the job of the caller to ensure that these structures ** protected. It is the job of the caller to ensure that these structures
** are accessed in a thread-safe manner. However, this module provides the ** are accessed in a thread-safe manner.
** functions sqlite3PcacheLock() and sqlite3PcacheUnlock() that may be used
** by the caller to increment/decrement a lock-count on an individual
** pager-cache object. This module guarantees that the xStress() callback
** will not be invoked on a pager-cache with a non-zero lock-count except
** from within a call to sqlite3PcacheFetch() on the same pager. A call
** to sqlite3PcacheLock() may block if such an xStress() call is currently
** underway.
**
** Before the xStress callback of a pager-cache (PCache) is invoked, the
** SQLITE_MUTEX_STATIC_MEM2 mutex is obtained.
**
** Deadlock within the module is avoided by never blocking on the MEM2
** mutex while the LRU mutex is held.
*/ */
#define pcacheEnterGlobal() sqlite3_mutex_enter(pcache.mutex_lru) #define pcacheEnterGlobal() sqlite3_mutex_enter(pcache.mutex)
#define pcacheExitGlobal() sqlite3_mutex_leave(pcache.mutex_lru) #define pcacheExitGlobal() sqlite3_mutex_leave(pcache.mutex)
/********************************** Linked List Management ********************/ /********************************** Linked List Management ********************/
@@ -131,6 +111,40 @@ static int pcacheCheckHashCount(PCache *pCache){
assert( nPage==pCache->nPage ); assert( nPage==pCache->nPage );
return 1; return 1;
} }
/*
** Based on the current value of PCache.nRef and the contents of the
** PCache.pDirty list, return the expected value of the PCache.nPinned
** counter. This is only used in debugging builds, as follows:
**
** assert( pCache->nPinned==pcachePinnedCount(pCache) );
*/
static int pcachePinnedCount(PCache *pCache){
PgHdr *p;
int nPinned = pCache->nRef;
for(p=pCache->pDirty; p; p=p->pNext){
if( p->nRef==0 ){
nPinned++;
}
}
return nPinned;
}
/*
** Check that the pCache->pSynced variable is set correctly. If it
** is not, either fail an assert or return zero. Otherwise, return
** non-zero. This is only used in debugging builds, as follows:
**
** assert( pcacheCheckSynced(pCache) );
*/
static int pcacheCheckSynced(PCache *pCache){
PgHdr *p = pCache->pDirtyTail;
for(p=pCache->pDirtyTail; p!=pCache->pSynced; p=p->pPrev){
assert( p->nRef || (p->flags&PGHDR_NEED_SYNC) );
}
return (p==0 || p->nRef || (p->flags&PGHDR_NEED_SYNC)==0);
}
#endif #endif
/* /*
@@ -205,6 +219,9 @@ static int pcacheResizeHash(PCache *pCache, int nHash){
** *ppHead is either PCache.pClean or PCache.pDirty. ** *ppHead is either PCache.pClean or PCache.pDirty.
*/ */
static void pcacheRemoveFromList(PgHdr **ppHead, PgHdr *pPage){ static void pcacheRemoveFromList(PgHdr **ppHead, PgHdr *pPage){
int isDirtyList = (ppHead==&pPage->pCache->pDirty);
assert( ppHead==&pPage->pCache->pClean || ppHead==&pPage->pCache->pDirty );
if( pPage->pPrev ){ if( pPage->pPrev ){
pPage->pPrev->pNext = pPage->pNext; pPage->pPrev->pNext = pPage->pNext;
}else{ }else{
@@ -214,6 +231,21 @@ static void pcacheRemoveFromList(PgHdr **ppHead, PgHdr *pPage){
if( pPage->pNext ){ if( pPage->pNext ){
pPage->pNext->pPrev = pPage->pPrev; pPage->pNext->pPrev = pPage->pPrev;
} }
if( isDirtyList ){
PCache *pCache = pPage->pCache;
assert( pPage->pNext || pCache->pDirtyTail==pPage );
if( !pPage->pNext ){
pCache->pDirtyTail = pPage->pPrev;
}
if( pCache->pSynced==pPage ){
PgHdr *pSynced = pPage->pPrev;
while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){
pSynced = pSynced->pPrev;
}
pCache->pSynced = pSynced;
}
}
} }
/* /*
@@ -221,32 +253,44 @@ static void pcacheRemoveFromList(PgHdr **ppHead, PgHdr *pPage){
** *ppHead is either PCache.pClean or PCache.pDirty. ** *ppHead is either PCache.pClean or PCache.pDirty.
*/ */
static void pcacheAddToList(PgHdr **ppHead, PgHdr *pPage){ static void pcacheAddToList(PgHdr **ppHead, PgHdr *pPage){
int isDirtyList = (ppHead==&pPage->pCache->pDirty);
assert( ppHead==&pPage->pCache->pClean || ppHead==&pPage->pCache->pDirty );
if( (*ppHead) ){ if( (*ppHead) ){
(*ppHead)->pPrev = pPage; (*ppHead)->pPrev = pPage;
} }
pPage->pNext = *ppHead; pPage->pNext = *ppHead;
pPage->pPrev = 0; pPage->pPrev = 0;
*ppHead = pPage; *ppHead = pPage;
if( isDirtyList ){
PCache *pCache = pPage->pCache;
if( !pCache->pDirtyTail ){
assert( pPage->pNext==0 );
pCache->pDirtyTail = pPage;
}
if( !pCache->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){
pCache->pSynced = pPage;
}
}
} }
/* /*
** Remove a page from the global LRU list ** Remove a page from the global LRU list
*/ */
static void pcacheRemoveFromLruList(PgHdr *pPage){ static void pcacheRemoveFromLruList(PgHdr *pPage){
assert( sqlite3_mutex_held(pcache.mutex_lru) ); assert( sqlite3_mutex_held(pcache.mutex) );
assert( (pPage->flags&PGHDR_DIRTY)==0 );
if( pPage->pCache->bPurgeable==0 ) return; if( pPage->pCache->bPurgeable==0 ) return;
if( pPage==pcache.pLruSynced ){
PgHdr *p;
for(p=pPage->pPrevLru; p && (p->flags&PGHDR_NEED_SYNC); p=p->pPrevLru);
pcache.pLruSynced = p;
}
if( pPage->pNextLru ){ if( pPage->pNextLru ){
assert( pcache.pLruTail!=pPage );
pPage->pNextLru->pPrevLru = pPage->pPrevLru; pPage->pNextLru->pPrevLru = pPage->pPrevLru;
}else{ }else{
assert( pcache.pLruTail==pPage ); assert( pcache.pLruTail==pPage );
pcache.pLruTail = pPage->pPrevLru; pcache.pLruTail = pPage->pPrevLru;
} }
if( pPage->pPrevLru ){ if( pPage->pPrevLru ){
assert( pcache.pLruHead!=pPage );
pPage->pPrevLru->pNextLru = pPage->pNextLru; pPage->pPrevLru->pNextLru = pPage->pNextLru;
}else{ }else{
assert( pcache.pLruHead==pPage ); assert( pcache.pLruHead==pPage );
@@ -261,7 +305,8 @@ static void pcacheRemoveFromLruList(PgHdr *pPage){
** to the end of the LRU list so that it will be the next to be recycled. ** to the end of the LRU list so that it will be the next to be recycled.
*/ */
static void pcacheAddToLruList(PgHdr *pPage){ static void pcacheAddToLruList(PgHdr *pPage){
assert( sqlite3_mutex_held(pcache.mutex_lru) ); assert( sqlite3_mutex_held(pcache.mutex) );
assert( (pPage->flags&PGHDR_DIRTY)==0 );
if( pPage->pCache->bPurgeable==0 ) return; if( pPage->pCache->bPurgeable==0 ) return;
if( pcache.pLruTail && (pPage->flags & PGHDR_REUSE_UNLIKELY)!=0 ){ if( pcache.pLruTail && (pPage->flags & PGHDR_REUSE_UNLIKELY)!=0 ){
/* If reuse is unlikely. Put the page at the end of the LRU list /* If reuse is unlikely. Put the page at the end of the LRU list
@@ -273,9 +318,6 @@ static void pcacheAddToLruList(PgHdr *pPage){
pcache.pLruTail->pNextLru = pPage; pcache.pLruTail->pNextLru = pPage;
pcache.pLruTail = pPage; pcache.pLruTail = pPage;
pPage->flags &= ~PGHDR_REUSE_UNLIKELY; pPage->flags &= ~PGHDR_REUSE_UNLIKELY;
if( 0==(pPage->flags&PGHDR_NEED_SYNC) ){
pcache.pLruSynced = pPage;
}
}else{ }else{
/* If reuse is possible. the page goes at the beginning of the LRU /* If reuse is possible. the page goes at the beginning of the LRU
** list so that it will be the last to be recycled. ** list so that it will be the last to be recycled.
@@ -289,9 +331,6 @@ static void pcacheAddToLruList(PgHdr *pPage){
if( pcache.pLruTail==0 ){ if( pcache.pLruTail==0 ){
pcache.pLruTail = pPage; pcache.pLruTail = pPage;
} }
if( pcache.pLruSynced==0 && 0==(pPage->flags&PGHDR_NEED_SYNC) ){
pcache.pLruSynced = pPage;
}
} }
} }
@@ -323,7 +362,7 @@ void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
** in the page cache memory pool, go to the general purpose memory allocator. ** in the page cache memory pool, go to the general purpose memory allocator.
*/ */
void *pcacheMalloc(int sz, PCache *pCache){ void *pcacheMalloc(int sz, PCache *pCache){
assert( sqlite3_mutex_held(pcache.mutex_lru) ); assert( sqlite3_mutex_held(pcache.mutex) );
if( sz<=pcache.szSlot && pcache.pFree ){ if( sz<=pcache.szSlot && pcache.pFree ){
PgFreeslot *p = pcache.pFree; PgFreeslot *p = pcache.pFree;
pcache.pFree = p->pNext; pcache.pFree = p->pNext;
@@ -342,9 +381,7 @@ void *pcacheMalloc(int sz, PCache *pCache){
** the global LRU mutex. ** the global LRU mutex.
*/ */
pcacheExitGlobal(); pcacheExitGlobal();
sqlite3PcacheUnlock(pCache);
p = sqlite3Malloc(sz); p = sqlite3Malloc(sz);
sqlite3PcacheLock(pCache);
pcacheEnterGlobal(); pcacheEnterGlobal();
if( p ){ if( p ){
@@ -366,7 +403,7 @@ void *sqlite3PageMalloc(sz){
** Release a pager memory allocation ** Release a pager memory allocation
*/ */
void pcacheFree(void *p){ void pcacheFree(void *p){
assert( sqlite3_mutex_held(pcache.mutex_lru) ); assert( sqlite3_mutex_held(pcache.mutex) );
if( p==0 ) return; if( p==0 ) return;
if( p>=pcache.pStart && p<pcache.pEnd ){ if( p>=pcache.pStart && p<pcache.pEnd ){
PgFreeslot *pSlot; PgFreeslot *pSlot;
@@ -392,17 +429,15 @@ void sqlite3PageFree(void *p){
static PgHdr *pcachePageAlloc(PCache *pCache){ static PgHdr *pcachePageAlloc(PCache *pCache){
PgHdr *p; PgHdr *p;
int sz = sizeof(*p) + pCache->szPage + pCache->szExtra; int sz = sizeof(*p) + pCache->szPage + pCache->szExtra;
assert( sqlite3_mutex_held(pcache.mutex_lru) ); assert( sqlite3_mutex_held(pcache.mutex) );
p = pcacheMalloc(sz, pCache); p = pcacheMalloc(sz, pCache);
if( p==0 ) return 0; if( p==0 ) return 0;
memset(p, 0, sizeof(PgHdr)); memset(p, 0, sizeof(PgHdr));
p->pData = (void*)&p[1]; p->pData = (void*)&p[1];
p->pExtra = (void*)&((char*)p->pData)[pCache->szPage]; p->pExtra = (void*)&((char*)p->pData)[pCache->szPage];
pcache.nPage++;
if( pCache->bPurgeable ){ if( pCache->bPurgeable ){
pcache.nPurgeable++; pcache.nCurrentPage++;
} }
return p; return p;
} }
@@ -410,10 +445,9 @@ static PgHdr *pcachePageAlloc(PCache *pCache){
** Deallocate a page ** Deallocate a page
*/ */
static void pcachePageFree(PgHdr *p){ static void pcachePageFree(PgHdr *p){
assert( sqlite3_mutex_held(pcache.mutex_lru) ); assert( sqlite3_mutex_held(pcache.mutex) );
pcache.nPage--;
if( p->pCache->bPurgeable ){ if( p->pCache->bPurgeable ){
pcache.nPurgeable--; pcache.nCurrentPage--;
} }
pcacheFree(p->apSave[0]); pcacheFree(p->apSave[0]);
pcacheFree(p->apSave[1]); pcacheFree(p->apSave[1]);
@@ -426,7 +460,7 @@ static void pcachePageFree(PgHdr *p){
** the argument is passed to pcachePageFree(). ** the argument is passed to pcachePageFree().
*/ */
static int pcachePageSize(PgHdr *p){ static int pcachePageSize(PgHdr *p){
assert( sqlite3_mutex_held(pcache.mutex_lru) ); assert( sqlite3_mutex_held(pcache.mutex) );
assert( !pcache.pStart ); assert( !pcache.pStart );
assert( p->apSave[0]==0 ); assert( p->apSave[0]==0 );
assert( p->apSave[1]==0 ); assert( p->apSave[1]==0 );
@@ -435,58 +469,30 @@ static int pcachePageSize(PgHdr *p){
} }
#endif #endif
static int pcacheRecyclePage(PgHdr *p, PCache *pCache){
assert( sqlite3_mutex_held(pcache.mutex_lru) );
assert( sqlite3_mutex_held(pcache.mutex_mem2) );
PCache *pC = p->pCache;
assert( pC->iInUseMM==0 );
pC->iInUseMM = 1;
if( pC->xStress && (pC->iInUseDB==0 || pC==pCache) ){
pcacheExitGlobal();
pC->xStress(pC->pStress, p);
pcacheEnterGlobal();
}
pC->iInUseMM = 0;
return (p->flags&PGHDR_DIRTY);
}
/* /*
** Recycle a page from the global LRU list. If no page can be recycled, ** Attempt to 'recycle' a page from the global LRU list. Only clean,
** return NULL. Otherwise, the pointer returned points to a PgHdr ** unreferenced pages from purgeable caches are eligible for recycling.
** object that has been removed from all lists and hash tables in **
** which is was referenced. The caller may reuse the allocation directly ** This function removes page pcache.pLruTail from the global LRU list,
** or may pass it to pcachePageFree() to return the memory to the heap ** and from the hash-table and PCache.pClean list of the owner pcache.
** (or pcache.pFree list). ** There should be no other references to the page.
*/ **
static PgHdr *pcacheRecycle(PCache *pCache){ ** A pointer to the recycled page is returned, or NULL if no page is
** eligible for recycling.
*/
static PgHdr *pcacheRecyclePage(){
PgHdr *p = 0; PgHdr *p = 0;
assert( sqlite3_mutex_held(pcache.mutex) );
assert( pcache.isInit ); if( (p=pcache.pLruTail) ){
assert( sqlite3_mutex_held(pcache.mutex_lru) ); assert( (p->flags&PGHDR_DIRTY)==0 );
if( SQLITE_OK==sqlite3_mutex_try(pcache.mutex_mem2) ){
p = pcache.pLruSynced;
while( p && (p->flags&PGHDR_DIRTY) && pcacheRecyclePage(p, pCache) ){
do { p = p->pPrevLru; } while( p && (p->flags&PGHDR_NEED_SYNC) );
}
if( !p ){
p = pcache.pLruTail;
while( p && (p->flags&PGHDR_DIRTY) && pcacheRecyclePage(p, pCache) ){
do { p = p->pPrevLru; } while( p && 0==(p->flags&PGHDR_NEED_SYNC) );
}
}
sqlite3_mutex_leave(pcache.mutex_mem2);
}
if( p ){
pcacheRemoveFromLruList(p); pcacheRemoveFromLruList(p);
pcacheRemoveFromHash(p); pcacheRemoveFromHash(p);
pcacheRemoveFromList(&p->pCache->pClean, p); pcacheRemoveFromList(&p->pCache->pClean, p);
/* If the always-rollback flag is set on the page being recycled, set /* If the always-rollback flag is set on the page being recycled, set
** the always-rollback flag on the corresponding pager. ** the always-rollback flag on the corresponding pager. TODO: This is
** a thread-safety problem.
*/ */
if( p->flags&PGHDR_ALWAYS_ROLLBACK ){ if( p->flags&PGHDR_ALWAYS_ROLLBACK ){
assert(p->pPager); assert(p->pPager);
@@ -509,21 +515,45 @@ static PgHdr *pcacheRecycleOrAlloc(PCache *pCache){
int szPage = pCache->szPage; int szPage = pCache->szPage;
int szExtra = pCache->szExtra; int szExtra = pCache->szExtra;
int bPurg = pCache->bPurgeable;
assert( pcache.isInit ); assert( pcache.isInit );
assert( sqlite3_mutex_notheld(pcache.mutex_lru) ); assert( sqlite3_mutex_notheld(pcache.mutex) );
pcacheEnterGlobal(); pcacheEnterGlobal();
if( (pcache.mxPage && pcache.nPage>=pcache.mxPage) /* If we have reached the limit for pinned/dirty pages, and there is at
|| (!pcache.mxPage && bPurg && pcache.nPurgeable>=pcache.mxPagePurgeable) ** least one dirty page, invoke the xStress callback to cause a page to
** become clean.
*/
assert( pCache->nPinned==pcachePinnedCount(pCache) );
assert( pcacheCheckSynced(pCache) );
if( pCache->xStress
&& pCache->pDirty
&& pCache->nPinned>=(pcache.nMaxPage+pCache->nMin-pcache.nMinPage)
){ ){
/* If the above test succeeds, then try to obtain a buffer by recycling PgHdr *pPg;
** an existing page. */ assert(pCache->pDirtyTail);
p = pcacheRecycle(pCache);
for(pPg=pCache->pSynced;
pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC));
pPg=pPg->pPrev
);
if( !pPg ){
for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pPrev);
}
if( pPg ){
pcacheExitGlobal();
pCache->xStress(pCache->pStress, pPg);
pcacheEnterGlobal();
}
} }
/* If the global page limit has been reached, try to recycle a page. */
if( pcache.nCurrentPage>=pcache.nMaxPage ){
p = pcacheRecyclePage();
}
/* If a page has been recycled but it is the wrong size, free it. */
if( p && (p->pCache->szPage!=szPage || p->pCache->szExtra!=szExtra) ){ if( p && (p->pCache->szPage!=szPage || p->pCache->szExtra!=szExtra) ){
pcachePageFree(p); pcachePageFree(p);
p = 0; p = 0;
@@ -546,9 +576,8 @@ int sqlite3PcacheInitialize(void){
assert( pcache.isInit==0 ); assert( pcache.isInit==0 );
memset(&pcache, 0, sizeof(pcache)); memset(&pcache, 0, sizeof(pcache));
if( sqlite3Config.bCoreMutex ){ if( sqlite3Config.bCoreMutex ){
pcache.mutex_lru = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU); pcache.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
pcache.mutex_mem2 = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM2); if( pcache.mutex==0 ){
if( pcache.mutex_lru==0 || pcache.mutex_mem2==0 ){
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
} }
@@ -586,21 +615,14 @@ void sqlite3PcacheOpen(
p->xStress = xStress; p->xStress = xStress;
p->pStress = pStress; p->pStress = pStress;
p->nMax = 100; p->nMax = 100;
p->nMin = 20;
if( bPurgeable ){
pcacheEnterGlobal();
pcache.mxPagePurgeable += p->nMax;
pcacheExitGlobal();
}
/* Add the new pager-cache to the list of caches starting at pcache.pAll */
pcacheEnterGlobal(); pcacheEnterGlobal();
p->pNextAll = pcache.pAll; if( bPurgeable ){
if( pcache.pAll ){ pcache.nMaxPage += p->nMax;
pcache.pAll->pPrevAll = p; pcache.nMinPage += p->nMin;
} }
p->pPrevAll = 0;
pcache.pAll = p;
pcacheExitGlobal(); pcacheExitGlobal();
} }
@@ -626,21 +648,23 @@ int sqlite3PcacheFetch(
assert( pcache.isInit ); assert( pcache.isInit );
assert( pCache!=0 ); assert( pCache!=0 );
assert( pgno>0 ); assert( pgno>0 );
assert( pCache->iInUseDB || pCache->iInUseMM ); assert( pCache->nPinned==pcachePinnedCount(pCache) );
/* Search the hash table for the requested page. Exit early if it is found. */ /* Search the hash table for the requested page. Exit early if it is found. */
if( pCache->apHash ){ if( pCache->apHash ){
u32 h = pgno % pCache->nHash; u32 h = pgno % pCache->nHash;
for(pPage=pCache->apHash[h]; pPage; pPage=pPage->pNextHash){ for(pPage=pCache->apHash[h]; pPage; pPage=pPage->pNextHash){
if( pPage->pgno==pgno ){ if( pPage->pgno==pgno ){
if( pPage->nRef==0 /* && (pPage->flags & PGHDR_DIRTY)==0 */ ){ if( pPage->nRef==0 ){
pcacheEnterGlobal(); if( 0==(pPage->flags&PGHDR_DIRTY) ){
pcacheRemoveFromLruList(pPage); pcacheEnterGlobal();
pcacheExitGlobal(); pcacheRemoveFromLruList(pPage);
} pcacheExitGlobal();
if( (pPage->nRef++)==0 ){ pCache->nPinned++;
}
pCache->nRef++; pCache->nRef++;
} }
pPage->nRef++;
*ppPage = pPage; *ppPage = pPage;
return SQLITE_OK; return SQLITE_OK;
} }
@@ -668,12 +692,14 @@ int sqlite3PcacheFetch(
pPage->pCache = pCache; pPage->pCache = pCache;
pPage->nRef = 1; pPage->nRef = 1;
pCache->nRef++; pCache->nRef++;
pCache->nPinned++;
pcacheAddToList(&pCache->pClean, pPage); pcacheAddToList(&pCache->pClean, pPage);
pcacheAddToHash(pPage); pcacheAddToHash(pPage);
}else{ }else{
*ppPage = 0; *ppPage = 0;
} }
assert( pCache->nPinned==pcachePinnedCount(pCache) );
return SQLITE_OK; return SQLITE_OK;
} }
@@ -683,20 +709,23 @@ int sqlite3PcacheFetch(
*/ */
void sqlite3PcacheRelease(PgHdr *p){ void sqlite3PcacheRelease(PgHdr *p){
assert( p->nRef>0 ); assert( p->nRef>0 );
assert( p->pCache->iInUseDB || p->pCache->iInUseMM );
p->nRef--; p->nRef--;
if( p->nRef==0 ){ if( p->nRef==0 ){
PCache *pCache = p->pCache; PCache *pCache = p->pCache;
pCache->nRef--;
if( p->pCache->xDestroy ){ if( p->pCache->xDestroy ){
p->pCache->xDestroy(p); p->pCache->xDestroy(p);
} }
#if 0 pCache->nRef--;
if( (p->flags & PGHDR_DIRTY)!=0 ) return; if( (p->flags&PGHDR_DIRTY)==0 ){
#endif pCache->nPinned--;
pcacheEnterGlobal(); pcacheEnterGlobal();
pcacheAddToLruList(p); pcacheAddToLruList(p);
pcacheExitGlobal(); pcacheExitGlobal();
}else{
/* Move the page to the head of the caches dirty list. */
pcacheRemoveFromList(&pCache->pDirty, p);
pcacheAddToList(&pCache->pDirty, p);
}
} }
} }
@@ -711,10 +740,10 @@ void sqlite3PcacheRef(PgHdr *p){
*/ */
void sqlite3PcacheDrop(PgHdr *p){ void sqlite3PcacheDrop(PgHdr *p){
PCache *pCache; PCache *pCache;
assert( p->pCache->iInUseDB );
assert( p->nRef==1 ); assert( p->nRef==1 );
pCache = p->pCache; pCache = p->pCache;
pCache->nRef--; pCache->nRef--;
pCache->nPinned--;
if( p->flags & PGHDR_DIRTY ){ if( p->flags & PGHDR_DIRTY ){
pcacheRemoveFromList(&pCache->pDirty, p); pcacheRemoveFromList(&pCache->pDirty, p);
}else{ }else{
@@ -732,7 +761,6 @@ void sqlite3PcacheDrop(PgHdr *p){
*/ */
void sqlite3PcacheMakeDirty(PgHdr *p){ void sqlite3PcacheMakeDirty(PgHdr *p){
PCache *pCache; PCache *pCache;
assert( p->pCache->iInUseDB );
p->flags &= ~PGHDR_DONT_WRITE; p->flags &= ~PGHDR_DONT_WRITE;
if( p->flags & PGHDR_DIRTY ) return; if( p->flags & PGHDR_DIRTY ) return;
assert( (p->flags & PGHDR_DIRTY)==0 ); assert( (p->flags & PGHDR_DIRTY)==0 );
@@ -749,14 +777,20 @@ void sqlite3PcacheMakeDirty(PgHdr *p){
*/ */
void sqlite3PcacheMakeClean(PgHdr *p){ void sqlite3PcacheMakeClean(PgHdr *p){
PCache *pCache; PCache *pCache;
assert( p->pCache->iInUseDB || p->pCache->iInUseMM );
if( (p->flags & PGHDR_DIRTY)==0 ) return; if( (p->flags & PGHDR_DIRTY)==0 ) return;
assert( p->apSave[0]==0 && p->apSave[1]==0 ); assert( p->apSave[0]==0 && p->apSave[1]==0 );
assert( p->flags & PGHDR_DIRTY ); assert( p->flags & PGHDR_DIRTY );
pCache = p->pCache; pCache = p->pCache;
pcacheRemoveFromList(&pCache->pDirty, p); pcacheRemoveFromList(&pCache->pDirty, p);
pcacheEnterGlobal();
pcacheAddToList(&pCache->pClean, p); pcacheAddToList(&pCache->pClean, p);
p->flags &= ~PGHDR_DIRTY; p->flags &= ~PGHDR_DIRTY;
if( p->nRef==0 ){
pcacheAddToLruList(p);
pCache->nPinned--;
}
assert( pCache->nPinned==pcachePinnedCount(pCache) );
pcacheExitGlobal();
} }
/* /*
@@ -764,15 +798,19 @@ void sqlite3PcacheMakeClean(PgHdr *p){
*/ */
void sqlite3PcacheCleanAll(PCache *pCache){ void sqlite3PcacheCleanAll(PCache *pCache){
PgHdr *p; PgHdr *p;
assert( pCache->iInUseDB );
pcacheEnterGlobal(); pcacheEnterGlobal();
while( (p = pCache->pDirty)!=0 ){ while( (p = pCache->pDirty)!=0 ){
assert( p->apSave[0]==0 && p->apSave[1]==0 ); assert( p->apSave[0]==0 && p->apSave[1]==0 );
pcacheRemoveFromList(&pCache->pDirty, p); pcacheRemoveFromList(&pCache->pDirty, p);
pcacheAddToList(&pCache->pClean, p);
p->flags &= ~PGHDR_DIRTY; p->flags &= ~PGHDR_DIRTY;
pcacheAddToList(&pCache->pClean, p);
if( p->nRef==0 ){
pcacheAddToLruList(p);
pCache->nPinned--;
}
} }
sqlite3PcacheAssertFlags(pCache, 0, PGHDR_DIRTY); sqlite3PcacheAssertFlags(pCache, 0, PGHDR_DIRTY);
assert( pCache->nPinned==pcachePinnedCount(pCache) );
pcacheExitGlobal(); pcacheExitGlobal();
} }
@@ -782,7 +820,7 @@ void sqlite3PcacheCleanAll(PCache *pCache){
** flag set. ** flag set.
*/ */
void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){ void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
assert( p->pCache->iInUseDB ); assert( p->nRef>0 );
pcacheRemoveFromHash(p); pcacheRemoveFromHash(p);
p->pgno = newPgno; p->pgno = newPgno;
if( newPgno==0 ){ if( newPgno==0 ){
@@ -798,21 +836,12 @@ void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
pcacheAddToHash(p); pcacheAddToHash(p);
} }
/*
** Set the global maximum number of pages. Return the previous value.
*/
void sqlite3PcacheGlobalMax(int mx){
pcacheEnterGlobal();
pcache.mxPage = mx;
pcacheExitGlobal();
}
/* /*
** Remove all content from a page cache ** Remove all content from a page cache
*/ */
void pcacheClear(PCache *pCache){ void pcacheClear(PCache *pCache){
PgHdr *p, *pNext; PgHdr *p, *pNext;
assert( sqlite3_mutex_held(pcache.mutex_lru) ); assert( sqlite3_mutex_held(pcache.mutex) );
for(p=pCache->pClean; p; p=pNext){ for(p=pCache->pClean; p; p=pNext){
pNext = p->pNext; pNext = p->pNext;
pcacheRemoveFromLruList(p); pcacheRemoveFromLruList(p);
@@ -820,12 +849,13 @@ void pcacheClear(PCache *pCache){
} }
for(p=pCache->pDirty; p; p=pNext){ for(p=pCache->pDirty; p; p=pNext){
pNext = p->pNext; pNext = p->pNext;
pcacheRemoveFromLruList(p);
pcachePageFree(p); pcachePageFree(p);
} }
pCache->pClean = 0; pCache->pClean = 0;
pCache->pDirty = 0; pCache->pDirty = 0;
pCache->pDirtyTail = 0;
pCache->nPage = 0; pCache->nPage = 0;
pCache->nPinned = 0;
memset(pCache->apHash, 0, pCache->nHash*sizeof(pCache->apHash[0])); memset(pCache->apHash, 0, pCache->nHash*sizeof(pCache->apHash[0]));
} }
@@ -836,7 +866,6 @@ void pcacheClear(PCache *pCache){
void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
PgHdr *p, *pNext; PgHdr *p, *pNext;
PgHdr *pDirty = pCache->pDirty; PgHdr *pDirty = pCache->pDirty;
assert( pCache->iInUseDB );
pcacheEnterGlobal(); pcacheEnterGlobal();
for(p=pCache->pClean; p||pDirty; p=pNext){ for(p=pCache->pClean; p||pDirty; p=pNext){
if( !p ){ if( !p ){
@@ -849,10 +878,11 @@ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
pcacheRemoveFromHash(p); pcacheRemoveFromHash(p);
if( p->flags&PGHDR_DIRTY ){ if( p->flags&PGHDR_DIRTY ){
pcacheRemoveFromList(&pCache->pDirty, p); pcacheRemoveFromList(&pCache->pDirty, p);
pCache->nPinned--;
}else{ }else{
pcacheRemoveFromList(&pCache->pClean, p); pcacheRemoveFromList(&pCache->pClean, p);
pcacheRemoveFromLruList(p);
} }
pcacheRemoveFromLruList(p);
pcachePageFree(p); pcachePageFree(p);
}else{ }else{
/* If there are references to the page, it cannot be freed. In this /* If there are references to the page, it cannot be freed. In this
@@ -870,31 +900,16 @@ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
** Close a cache. ** Close a cache.
*/ */
void sqlite3PcacheClose(PCache *pCache){ void sqlite3PcacheClose(PCache *pCache){
assert( pCache->iInUseDB==1 );
pcacheEnterGlobal(); pcacheEnterGlobal();
/* Free all the pages used by this pager and remove them from the LRU list. */ /* Free all the pages used by this pager and remove them from the LRU list. */
pcacheClear(pCache); pcacheClear(pCache);
if( pCache->bPurgeable ){ if( pCache->bPurgeable ){
pcache.mxPagePurgeable -= pCache->nMax; pcache.nMaxPage -= pCache->nMax;
pcache.nMinPage -= pCache->nMin;
} }
sqlite3_free(pCache->apHash); sqlite3_free(pCache->apHash);
/* Now remove the pager-cache structure itself from the list of
** all such structures headed by pcache.pAll.
*/
assert(pCache==pcache.pAll || pCache->pPrevAll);
assert(pCache->pNextAll==0 || pCache->pNextAll->pPrevAll==pCache);
assert(pCache->pPrevAll==0 || pCache->pPrevAll->pNextAll==pCache);
if( pCache->pPrevAll ){
pCache->pPrevAll->pNextAll = pCache->pNextAll;
}else{
pcache.pAll = pCache->pNextAll;
}
if( pCache->pNextAll ){
pCache->pNextAll->pPrevAll = pCache->pPrevAll;
}
pcacheExitGlobal(); pcacheExitGlobal();
} }
@@ -910,7 +925,6 @@ void sqlite3PcacheClose(PCache *pCache){
int sqlite3PcachePreserve(PgHdr *p, int idJournal){ int sqlite3PcachePreserve(PgHdr *p, int idJournal){
void *x; void *x;
int sz; int sz;
assert( p->pCache->iInUseDB );
assert( p->pCache->bPurgeable==0 ); assert( p->pCache->bPurgeable==0 );
if( !p->apSave[idJournal] ){ if( !p->apSave[idJournal] ){
sz = p->pCache->szPage; sz = p->pCache->szPage;
@@ -926,7 +940,6 @@ int sqlite3PcachePreserve(PgHdr *p, int idJournal){
*/ */
void sqlite3PcacheCommit(PCache *pCache, int idJournal){ void sqlite3PcacheCommit(PCache *pCache, int idJournal){
PgHdr *p; PgHdr *p;
assert( pCache->iInUseDB );
pcacheEnterGlobal(); /* Mutex is required to call pcacheFree() */ pcacheEnterGlobal(); /* Mutex is required to call pcacheFree() */
for(p=pCache->pDirty; p; p=p->pNext){ for(p=pCache->pDirty; p; p=p->pNext){
if( p->apSave[idJournal] ){ if( p->apSave[idJournal] ){
@@ -943,7 +956,6 @@ void sqlite3PcacheCommit(PCache *pCache, int idJournal){
void sqlite3PcacheRollback(PCache *pCache, int idJournal){ void sqlite3PcacheRollback(PCache *pCache, int idJournal){
PgHdr *p; PgHdr *p;
int sz; int sz;
assert( pCache->iInUseDB );
pcacheEnterGlobal(); /* Mutex is required to call pcacheFree() */ pcacheEnterGlobal(); /* Mutex is required to call pcacheFree() */
sz = pCache->szPage; sz = pCache->szPage;
for(p=pCache->pDirty; p; p=p->pNext){ for(p=pCache->pDirty; p; p=p->pNext){
@@ -961,7 +973,6 @@ void sqlite3PcacheRollback(PCache *pCache, int idJournal){
*/ */
void sqlite3PcacheAssertFlags(PCache *pCache, int trueMask, int falseMask){ void sqlite3PcacheAssertFlags(PCache *pCache, int trueMask, int falseMask){
PgHdr *p; PgHdr *p;
assert( pCache->iInUseDB || pCache->iInUseMM );
for(p=pCache->pDirty; p; p=p->pNext){ for(p=pCache->pDirty; p; p=p->pNext){
assert( (p->flags&trueMask)==trueMask ); assert( (p->flags&trueMask)==trueMask );
assert( (p->flags&falseMask)==0 ); assert( (p->flags&falseMask)==0 );
@@ -976,7 +987,6 @@ void sqlite3PcacheAssertFlags(PCache *pCache, int trueMask, int falseMask){
** Discard the contents of the cache. ** Discard the contents of the cache.
*/ */
int sqlite3PcacheClear(PCache *pCache){ int sqlite3PcacheClear(PCache *pCache){
assert( pCache->iInUseDB );
assert(pCache->nRef==0); assert(pCache->nRef==0);
pcacheEnterGlobal(); pcacheEnterGlobal();
pcacheClear(pCache); pcacheClear(pCache);
@@ -1063,7 +1073,6 @@ static PgHdr *pcacheSortDirtyList(PgHdr *pIn){
*/ */
PgHdr *sqlite3PcacheDirtyList(PCache *pCache){ PgHdr *sqlite3PcacheDirtyList(PCache *pCache){
PgHdr *p; PgHdr *p;
assert( pCache->iInUseDB );
for(p=pCache->pDirty; p; p=p->pNext){ for(p=pCache->pDirty; p; p=p->pNext){
p->pDirty = p->pNext; p->pDirty = p->pNext;
} }
@@ -1081,7 +1090,6 @@ int sqlite3PcacheRefCount(PCache *pCache){
** Return the total number of pages in the cache. ** Return the total number of pages in the cache.
*/ */
int sqlite3PcachePagecount(PCache *pCache){ int sqlite3PcachePagecount(PCache *pCache){
assert( pCache->iInUseDB || pCache->iInUseMM );
assert( pCache->nPage>=0 ); assert( pCache->nPage>=0 );
return pCache->nPage; return pCache->nPage;
} }
@@ -1094,7 +1102,6 @@ int sqlite3PcachePagecount(PCache *pCache){
*/ */
void sqlite3PcacheIterate(PCache *pCache, void (*xIter)(PgHdr *)){ void sqlite3PcacheIterate(PCache *pCache, void (*xIter)(PgHdr *)){
PgHdr *p; PgHdr *p;
assert( pCache->iInUseDB || pCache->iInUseMM );
for(p=pCache->pClean; p; p=p->pNext){ for(p=pCache->pClean; p; p=p->pNext){
xIter(p); xIter(p);
} }
@@ -1111,13 +1118,11 @@ void sqlite3PcacheSetFlags(PCache *pCache, int andMask, int orMask){
PgHdr *p; PgHdr *p;
assert( (orMask&PGHDR_NEED_SYNC)==0 ); assert( (orMask&PGHDR_NEED_SYNC)==0 );
assert( pCache->iInUseDB || pCache->iInUseMM );
/* Obtain the global mutex before modifying any PgHdr.flags variables /* Obtain the global mutex before modifying any PgHdr.flags variables
** or traversing the LRU list. ** or traversing the LRU list.
*/ */
pcacheEnterGlobal(); pcacheEnterGlobal();
assert( sqlite3_mutex_held(pcache.mutex_lru) );
for(p=pCache->pDirty; p; p=p->pNext){ for(p=pCache->pDirty; p; p=p->pNext){
p->flags = (p->flags&andMask)|orMask; p->flags = (p->flags&andMask)|orMask;
@@ -1127,8 +1132,11 @@ void sqlite3PcacheSetFlags(PCache *pCache, int andMask, int orMask){
} }
if( 0==(andMask&PGHDR_NEED_SYNC) ){ if( 0==(andMask&PGHDR_NEED_SYNC) ){
for(p=pcache.pLruTail; p && (p->flags&PGHDR_NEED_SYNC); p=p->pPrevLru); PgHdr *pSynced = pCache->pDirtyTail;
pcache.pLruSynced = p; while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){
pSynced = pSynced->pPrev;
}
pCache->pSynced = pSynced;
} }
pcacheExitGlobal(); pcacheExitGlobal();
@@ -1150,40 +1158,13 @@ void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
} }
if( pCache->bPurgeable ){ if( pCache->bPurgeable ){
pcacheEnterGlobal(); pcacheEnterGlobal();
pcache.mxPagePurgeable -= pCache->nMax; pcache.nMaxPage -= pCache->nMax;
pcache.mxPagePurgeable += mxPage; pcache.nMaxPage += mxPage;
pcacheExitGlobal(); pcacheExitGlobal();
} }
pCache->nMax = mxPage; pCache->nMax = mxPage;
} }
/*
** Lock a pager-cache.
*/
void sqlite3PcacheLock(PCache *pCache){
if( pCache ){
assert( sqlite3_mutex_notheld(pcache.mutex_lru) );
pCache->iInUseDB++;
if( pCache->iInUseMM && pCache->iInUseDB==1 ){
pCache->iInUseDB = 0;
sqlite3_mutex_enter(pcache.mutex_mem2);
assert( pCache->iInUseMM==0 && pCache->iInUseDB==0 );
pCache->iInUseDB = 1;
sqlite3_mutex_leave(pcache.mutex_mem2);
}
}
}
/*
** Unlock a pager-cache.
*/
void sqlite3PcacheUnlock(PCache *pCache){
if( pCache ){
pCache->iInUseDB--;
assert( pCache->iInUseDB>=0 );
}
}
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
/* /*
** This function is called to free superfluous dynamically allocated memory ** This function is called to free superfluous dynamically allocated memory
@@ -1199,7 +1180,7 @@ int sqlite3PcacheReleaseMemory(int nReq){
if( pcache.pStart==0 ){ if( pcache.pStart==0 ){
PgHdr *p; PgHdr *p;
pcacheEnterGlobal(); pcacheEnterGlobal();
while( (nReq<0 || nFree<nReq) && (p=pcacheRecycle(0)) ){ while( (nReq<0 || nFree<nReq) && (p=pcacheRecyclePage()) ){
nFree += pcachePageSize(p); nFree += pcachePageSize(p);
pcachePageFree(p); pcachePageFree(p);
} }

View File

@@ -12,7 +12,7 @@
** This header file defines the interface that the sqlite page cache ** This header file defines the interface that the sqlite page cache
** subsystem. ** subsystem.
** **
** @(#) $Id: pcache.h,v 1.5 2008/08/23 18:53:08 danielk1977 Exp $ ** @(#) $Id: pcache.h,v 1.6 2008/08/26 18:05:48 danielk1977 Exp $
*/ */
#ifndef _PCACHE_H_ #ifndef _PCACHE_H_
@@ -101,12 +101,6 @@ void sqlite3PcacheCleanAll(PCache*); /* Mark all dirty list pages as clean */
/* Change a page number. Used by incr-vacuum. */ /* Change a page number. Used by incr-vacuum. */
void sqlite3PcacheMove(PgHdr*, Pgno); void sqlite3PcacheMove(PgHdr*, Pgno);
/* Set a global maximum page count for all page caches.
** If the sum of individual cache maxes exceed the global max, the
** individuals are scaled down proportionally.
*/
void sqlite3PcacheGlobalMax(int N);
/* Remove all pages with pgno>x. Reset the cache if x==0 */ /* Remove all pages with pgno>x. Reset the cache if x==0 */
void sqlite3PcacheTruncate(PCache*, Pgno x); void sqlite3PcacheTruncate(PCache*, Pgno x);
@@ -148,10 +142,7 @@ int sqlite3PcachePagecount(PCache*);
*/ */
void sqlite3PcacheIterate(PCache *pCache, void (*xIter)(PgHdr *)); void sqlite3PcacheIterate(PCache *pCache, void (*xIter)(PgHdr *));
/* Set and get the suggested cache-size for the specified pager-cache. If /* Set and get the suggested cache-size for the specified pager-cache.
** a global maximum on the number of pages cached by the system is
** configured via the sqlite3PcacheGlobalMax() API, then the suggested
** cache-sizes are not used at all.
** **
** If no global maximum is configured, then the system attempts to limit ** If no global maximum is configured, then the system attempts to limit
** the total number of pages cached by purgeable pager-caches to the sum ** the total number of pages cached by purgeable pager-caches to the sum
@@ -160,14 +151,7 @@ void sqlite3PcacheIterate(PCache *pCache, void (*xIter)(PgHdr *));
int sqlite3PcacheGetCachesize(PCache *); int sqlite3PcacheGetCachesize(PCache *);
void sqlite3PcacheSetCachesize(PCache *, int); void sqlite3PcacheSetCachesize(PCache *, int);
/* Lock and unlock a pager-cache object. The PcacheLock() function may /* Try to return memory used by the pcache module to the main memory heap */
** block if the lock is temporarily available. While a pager-cache is locked,
** the system guarantees that any configured xStress() callback will not
** be invoked by any thread other than the one holding the lock.
*/
void sqlite3PcacheLock(PCache *);
void sqlite3PcacheUnlock(PCache *);
int sqlite3PcacheReleaseMemory(int); int sqlite3PcacheReleaseMemory(int);
#endif /* _PCACHE_H_ */ #endif /* _PCACHE_H_ */

View File

@@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated ** is not included in the SQLite library. It is used for automated
** testing of the SQLite library. ** testing of the SQLite library.
** **
** $Id: test2.c,v 1.60 2008/08/20 14:49:25 danielk1977 Exp $ ** $Id: test2.c,v 1.61 2008/08/26 18:05:48 danielk1977 Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "tcl.h" #include "tcl.h"
@@ -382,26 +382,6 @@ static int page_lookup(
return TCL_OK; return TCL_OK;
} }
/*
** Usage: pcache_global_max NPAGE
*/
static int pcache_global_max(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
int nPage;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" NPAGE\"", 0);
return TCL_ERROR;
}
if( Tcl_GetInt(interp, argv[1], &nPage) ) return TCL_ERROR;
sqlite3PcacheGlobalMax(nPage);
return TCL_OK;
}
/* /*
** Usage: pager_truncate ID PGNO ** Usage: pager_truncate ID PGNO
*/ */
@@ -650,7 +630,6 @@ int Sqlitetest2_Init(Tcl_Interp *interp){
{ "page_write", (Tcl_CmdProc*)page_write }, { "page_write", (Tcl_CmdProc*)page_write },
{ "page_number", (Tcl_CmdProc*)page_number }, { "page_number", (Tcl_CmdProc*)page_number },
{ "pager_truncate", (Tcl_CmdProc*)pager_truncate }, { "pager_truncate", (Tcl_CmdProc*)pager_truncate },
{ "pcache_global_max", (Tcl_CmdProc*)pcache_global_max },
#ifndef SQLITE_OMIT_DISKIO #ifndef SQLITE_OMIT_DISKIO
{ "fake_big_file", (Tcl_CmdProc*)fake_big_file }, { "fake_big_file", (Tcl_CmdProc*)fake_big_file },
#endif #endif

View File

@@ -11,7 +11,7 @@
# #
# This file contains tests of the memory allocation subsystem # This file contains tests of the memory allocation subsystem
# #
# $Id: memsubsys1.test,v 1.10 2008/08/20 14:49:25 danielk1977 Exp $ # $Id: memsubsys1.test,v 1.11 2008/08/26 18:05:48 danielk1977 Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@@ -228,10 +228,11 @@ sqlite3_shutdown
sqlite3_config_pagecache [expr 4096+$xtra_size] 24 sqlite3_config_pagecache [expr 4096+$xtra_size] 24
sqlite3_config_scratch 25000 1 sqlite3_config_scratch 25000 1
sqlite3_initialize sqlite3_initialize
pcache_global_max 15
reset_highwater_marks reset_highwater_marks
build_test_db memsubsys1-7 { build_test_db memsubsys1-7 {
PRAGMA page_size=4096; PRAGMA page_size=4096;
PRAGMA cache_size=10;
PRAGMA temp_store=memory;
} }
#show_memstats #show_memstats
do_test memsubsys1-7.3 { do_test memsubsys1-7.3 {
@@ -251,7 +252,6 @@ do_test memsubsys1-7.6 {
do_test memsubsys1-7.7 { do_test memsubsys1-7.7 {
set s_ovfl [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_OVERFLOW 0] 2] set s_ovfl [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_OVERFLOW 0] 2]
} 0 } 0
pcache_global_max 0
db close db close
sqlite3_shutdown sqlite3_shutdown

View File

@@ -16,7 +16,7 @@
# any statement other than a COMMIT, an I/O error is returned instead # any statement other than a COMMIT, an I/O error is returned instead
# of SQLITE_BUSY. # of SQLITE_BUSY.
# #
# $Id: tkt2409.test,v 1.4 2008/08/20 14:49:25 danielk1977 Exp $ # $Id: tkt2409.test,v 1.5 2008/08/26 18:05:48 danielk1977 Exp $
# Test Outline: # Test Outline:
# #
@@ -79,8 +79,6 @@ proc unread_lock_db {} {
} }
} }
pcache_global_max 10
# Open the db handle used by [read_lock_db]. # Open the db handle used by [read_lock_db].
# #
sqlite3 db2 test.db sqlite3 db2 test.db
@@ -223,8 +221,6 @@ do_test tkt2409-4.4 {
catchsql { ROLLBACK } catchsql { ROLLBACK }
} {0 {}} } {0 {}}
pcache_global_max 0
unread_lock_db unread_lock_db
db2 close db2 close
unset -nocomplain t1 unset -nocomplain t1