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

Add an API to support custom page cache implementations. (CVS 5899)

FossilOrigin-Name: 47866d6708e9b69e367937fd85f93580fd025447
This commit is contained in:
danielk1977
2008-11-13 14:28:28 +00:00
parent 0d0654119f
commit bc2ca9eb39
12 changed files with 1166 additions and 935 deletions

View File

@@ -167,8 +167,8 @@ OBJS0 = alter.lo analyze.lo attach.lo auth.lo bitvec.lo btmutex.lo \
memjournal.lo \
mutex.lo mutex_noop.lo mutex_os2.lo mutex_unix.lo mutex_w32.lo \
opcodes.lo os.lo os_unix.lo os_win.lo os_os2.lo \
pager.lo parse.lo pcache.lo pragma.lo prepare.lo printf.lo random.lo \
resolve.lo select.lo status.lo \
pager.lo parse.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \
random.lo resolve.lo select.lo status.lo \
table.lo tokenize.lo trigger.lo update.lo \
util.lo vacuum.lo \
vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbefifo.lo vdbemem.lo \
@@ -237,6 +237,7 @@ SRC = \
$(TOP)/src/parse.y \
$(TOP)/src/pcache.c \
$(TOP)/src/pcache.h \
$(TOP)/src/pcache1.c \
$(TOP)/src/pragma.c \
$(TOP)/src/prepare.c \
$(TOP)/src/printf.c \
@@ -335,6 +336,7 @@ TESTSRC2 = \
$(TOP)/src/os_win.c \
$(TOP)/src/pager.c \
$(TOP)/src/pcache.c \
$(TOP)/src/pcache1.c \
$(TOP)/src/pragma.c \
$(TOP)/src/prepare.c \
$(TOP)/src/printf.c \
@@ -596,6 +598,9 @@ pager.lo: $(TOP)/src/pager.c $(HDR) $(TOP)/src/pager.h
pcache.lo: $(TOP)/src/pcache.c $(HDR) $(TOP)/src/pcache.h
$(LTCOMPILE) -c $(TOP)/src/pcache.c
pcache1.lo: $(TOP)/src/pcache1.c $(HDR) $(TOP)/src/pcache.h
$(LTCOMPILE) -c $(TOP)/src/pcache1.c
opcodes.lo: opcodes.c
$(LTCOMPILE) -c opcodes.c

View File

@@ -60,7 +60,7 @@ LIBOBJ+= alter.o analyze.o attach.o auth.o \
memjournal.o \
mutex.o mutex_noop.o mutex_os2.o mutex_unix.o mutex_w32.o \
opcodes.o os.o os_os2.o os_unix.o os_win.o \
pager.o parse.o pcache.o pragma.o prepare.o printf.o \
pager.o parse.o pcache.o pcache1.o pragma.o prepare.o printf.o \
random.o resolve.o rtree.o select.o status.o \
table.o tokenize.o trigger.o \
update.o util.o vacuum.o \
@@ -122,6 +122,7 @@ SRC = \
$(TOP)/src/parse.y \
$(TOP)/src/pcache.c \
$(TOP)/src/pcache.h \
$(TOP)/src/pcache1.c \
$(TOP)/src/pragma.c \
$(TOP)/src/prepare.c \
$(TOP)/src/printf.c \
@@ -242,7 +243,7 @@ TESTSRC2 = \
$(TOP)/src/os_os2.c $(TOP)/src/os_unix.c $(TOP)/src/os_win.c \
$(TOP)/src/pager.c $(TOP)/src/pragma.c $(TOP)/src/prepare.c \
$(TOP)/src/printf.c $(TOP)/src/random.c $(TOP)/src/pcache.c \
$(TOP)/src/select.c $(TOP)/src/tokenize.c \
$(TOP)/src/pcache1.c $(TOP)/src/select.c $(TOP)/src/tokenize.c \
$(TOP)/src/utf.c $(TOP)/src/util.c $(TOP)/src/vdbeapi.c $(TOP)/src/vdbeaux.c \
$(TOP)/src/vdbe.c $(TOP)/src/vdbemem.c $(TOP)/src/where.c parse.c \
$(TOP)/ext/fts3/fts3.c $(TOP)/ext/fts3/fts3_tokenizer.c

View File

@@ -1,7 +1,7 @@
C Avoid\ssome\sbuffer\soverreads\sdetected\sby\svalgrind\swhile\srunning\scorruptC.test.\s(CVS\s5898)
D 2008-11-12T18:21:36
C Add\san\sAPI\sto\ssupport\scustom\spage\scache\simplementations.\s(CVS\s5899)
D 2008-11-13T14:28:29
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in 48172b58e444a9725ec482e0c022a564749acab4
F Makefile.in 6cbc7db84c23804c368bc7ffe51367412212d7b2
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
F README b974cdc3f9f12b87e851b04e75996d720ebf81ac
F VERSION 4eb06187e9b9f72fdf3ba27c407e24665d0bb513
@@ -79,7 +79,7 @@ F ext/rtree/tkt3363.test 6662237ea75bb431cd5d262dfc9535e1023315fc
F ext/rtree/viewrtree.tcl 09526398dae87a5a87c5aac2b3854dbaf8376869
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
F ltmain.sh 09fe5815427dc7d0abb188bbcdf0e34896577210
F main.mk 187bbff650073ffad5e8313795665ea64f36c0d5
F main.mk 2da751f09754965bcbc8b3fde56c8c71e67ebdb5
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac
@@ -99,7 +99,7 @@ F src/attach.c 208881c87160d9e2c73a46cf86116c5a6d66f9d7
F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627
F src/bitvec.c 9e922b2577b7e46d8f95349bca6a52f7674d7582
F src/btmutex.c 3a90096c3080b9057dc570b8e16e46511e1c788a
F src/btree.c 7c06d81faa3a44116968987a5189b4a2f6a37962
F src/btree.c be3e0aa63755b094941f9c4298a987fe93df0f22
F src/btree.h 179c3ea813780df78a289a8f5130db18e6d4616e
F src/btreeInt.h e38e9b2b285f40f5bc0a6664f630d4a141622f16
F src/build.c 98a6884d47c3cc12faeb2e9a926018d3a7382133
@@ -118,7 +118,7 @@ F src/insert.c d61998cb8d934bd42b77bd362f94cc3368c5d5f7
F src/journal.c cffd2cd214e58c0e99c3ff632b3bee6c7cbb260e
F src/legacy.c aac57bd984e666059011ea01ec4383892a253be3
F src/loadext.c 3872457afdf25bb174fd383cb4e3e0d2a9e60552
F src/main.c cdc0fa9b11254d7e9f15c67b22a3981cb5090119
F src/main.c fd93666b883dbe976f8fb9a5b87784bde2eca43d
F src/malloc.c a213fb461b8df08aed7606f6a1e1d3452e089000
F src/mem0.c f2f84062d1f35814d6535c9f9e33de3bfb3b132c
F src/mem1.c 2091081d1c6bcd4516738f37cd84d42e814cf9a2
@@ -138,11 +138,12 @@ F src/os_common.h 24525d8b7bce66c374dfc1810a6c9043f3359b60
F src/os_os2.c 63be0987dbeb42e9b08c831863d2a315953b86e1
F src/os_unix.c af390f03ebe339e63911aec2d4ccd1e53fde581e
F src/os_win.c e208cbbceac63c1dd881d0909de5a4679a2c6992
F src/pager.c 6b6f8eb4938d184d6612ea89631185dbace246b3
F src/pager.c c3f46fcb60a9049dd2f3039dfcde60fbbb83b41b
F src/pager.h 4a57b219c0765fe1870238064e3f46e4eb2cf5af
F src/parse.y 2c4758b4c5ead6de8cf7112f5a7cce7561d313fe
F src/pcache.c 3d547c392145113336d44b901e048b86ee6a4774
F src/pcache.h 2caf2deb6cbaa75c423b8b96fc1411069ee77c75
F src/pcache.c 439bcf164f10dd0595cbd63f7472881d46dcbb61
F src/pcache.h b6feb183dea39ede8336bb47c5969403d26fa5c0
F src/pcache1.c 7612a5d850ba48b4f0230a6937469f55a7cee43d
F src/pragma.c 5d4333a27ef4f770fc69ca4f138419d3b462c554
F src/prepare.c ae49b8298eca79acdbc964679962e089b943ec94
F src/printf.c 785f87120589c1db672e37c6eb1087c456e6f84d
@@ -150,9 +151,9 @@ F src/random.c a87afbd598aa877e23ac676ee92fd8ee5c786a51
F src/resolve.c 266bb03d2b456fe68f5df2dd5687e7e88ff8088d
F src/select.c b03c6fe474ded7bd110ca7b551bf0236133c12da
F src/shell.c 01835f435d2e42be95480f7d7cce48e9b255652e
F src/sqlite.h.in b73e17f40b0dcfc4b17f5ef18ba90bca8d1e8bc5
F src/sqlite.h.in 85e159e1d634c84ddbf87481293d5b1d26e2d27b
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
F src/sqliteInt.h f2b50cd40d847ccf2d9baf5a622e744a05f136e3
F src/sqliteInt.h 024f3e7722860905c50b59669127e1ac5e520b99
F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
F src/table.c 22744786199c9195720c15a7a42cb97b2e2728d8
@@ -656,7 +657,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
P 369f74983bb1b6a6426260148018cdc084fc2b49
R 1f4429807d31bf0a13a5939ab83fd57a
P faa6bd7b615837c920b5b3b027115caa2f56ec15
R d0a03787d9cbd01ae9ab954f29497939
U danielk1977
Z ced029dc2e076de2b81cab7ea9f2d078
Z 6ca197766dcdc265d028d54cbf94409d

View File

@@ -1 +1 @@
faa6bd7b615837c920b5b3b027115caa2f56ec15
47866d6708e9b69e367937fd85f93580fd025447

View File

@@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btree.c,v 1.534 2008/11/12 18:21:36 danielk1977 Exp $
** $Id: btree.c,v 1.535 2008/11/13 14:28:29 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** See the header comment on "btreeInt.h" for additional information.
@@ -2603,9 +2603,14 @@ void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode){
BtCursor *p;
sqlite3BtreeEnter(pBtree);
for(p=pBtree->pBt->pCursor; p; p=p->pNext){
int i;
sqlite3BtreeClearCursor(p);
p->eState = CURSOR_FAULT;
p->skip = errCode;
for(i=0; i<=p->iPage; i++){
releasePage(p->apPage[i]);
p->apPage[i] = 0;
}
}
sqlite3BtreeLeave(pBtree);
}
@@ -5616,6 +5621,7 @@ static int balance_deeper(BtCursor *pCur){
memcpy(cdata, &data[hdr], pPage->cellOffset+2*pPage->nCell-hdr);
memcpy(&cdata[cbrk], &data[cbrk], usableSize-cbrk);
assert( pChild->isInit==0 );
rc = sqlite3BtreeInitPage(pChild);
if( rc==SQLITE_OK ){
int nCopy = pPage->nOverflow*sizeof(pPage->aOvfl[0]);

View File

@@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.511 2008/11/10 18:05:36 shane Exp $
** $Id: main.c,v 1.512 2008/11/13 14:28:29 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -309,6 +309,12 @@ int sqlite3_config(int op, ...){
break;
}
case SQLITE_CONFIG_PCACHE: {
/* Specify an alternative malloc implementation */
sqlite3GlobalConfig.pcache = *va_arg(ap, sqlite3_pcache_methods*);
break;
}
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
case SQLITE_CONFIG_HEAP: {
/* Designate a buffer for heap memory space */

View File

@@ -18,7 +18,7 @@
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.502 2008/11/07 00:24:54 drh Exp $
** @(#) $Id: pager.c,v 1.503 2008/11/13 14:28:29 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
@@ -312,6 +312,10 @@ static int pageInStatement(PgHdr *pPg){
return sqlite3BitvecTest(pPager->pInStmt, pPg->pgno);
}
static int pageInJournal(PgHdr *pPg){
return sqlite3BitvecTest(pPg->pPager->pInJournal, pPg->pgno);
}
/*
** Read a 32-bit integer from the given file descriptor. Store the integer
** that is read in *pRes. Return SQLITE_OK if everything worked, or an
@@ -454,7 +458,7 @@ static u32 pager_datahash(int nByte, unsigned char *pData){
static u32 pager_pagehash(PgHdr *pPage){
return pager_datahash(pPage->pPager->pageSize, (unsigned char *)pPage->pData);
}
static u32 pager_set_pagehash(PgHdr *pPage){
static void pager_set_pagehash(PgHdr *pPage){
pPage->pageHash = pager_pagehash(pPage);
}
@@ -997,13 +1001,10 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){
pPager->pInJournal = 0;
sqlite3BitvecDestroy(pPager->pAlwaysRollback);
pPager->pAlwaysRollback = 0;
sqlite3PcacheCleanAll(pPager->pPCache);
#ifdef SQLITE_CHECK_PAGES
sqlite3PcacheIterate(pPager->pPCache, pager_set_pagehash);
sqlite3PcacheIterateDirty(pPager->pPCache, pager_set_pagehash);
#endif
sqlite3PcacheClearFlags(pPager->pPCache,
PGHDR_IN_JOURNAL | PGHDR_NEED_SYNC
);
sqlite3PcacheCleanAll(pPager->pPCache);
pPager->dirtyCache = 0;
pPager->nRec = 0;
}else{
@@ -2339,19 +2340,9 @@ static int syncJournal(Pager *pPager){
/* Erase the needSync flag from every page.
*/
sqlite3PcacheClearFlags(pPager->pPCache, PGHDR_NEED_SYNC);
sqlite3PcacheClearSyncFlags(pPager->pPCache);
}
#ifndef NDEBUG
/* If the Pager.needSync flag is clear then the PgHdr.needSync
** flag must also be clear for all pages. Verify that this
** invariant is true.
*/
else{
sqlite3PcacheAssertFlags(pPager->pPCache, 0, PGHDR_NEED_SYNC);
}
#endif
return rc;
}
@@ -2852,9 +2843,6 @@ int sqlite3PagerAcquire(
int nMax;
PAGER_INCR(pPager->nMiss);
pPg->pPager = pPager;
if( sqlite3BitvecTest(pPager->pInJournal, pgno) ){
pPg->flags |= PGHDR_IN_JOURNAL;
}
memset(pPg->pExtra, 0, pPager->nExtra);
rc = sqlite3PagerPagecount(pPager, &nMax);
@@ -3058,7 +3046,6 @@ int sqlite3PagerBegin(DbPage *pPg, int exFlag){
if( pPager->state==PAGER_SHARED ){
assert( pPager->pInJournal==0 );
assert( !MEMDB );
sqlite3PcacheAssertFlags(pPager->pPCache, 0, PGHDR_IN_JOURNAL);
rc = sqlite3OsLock(pPager->fd, RESERVED_LOCK);
if( rc==SQLITE_OK ){
pPager->state = PAGER_RESERVED;
@@ -3167,9 +3154,7 @@ static int pager_write(PgHdr *pPg){
** to the journal then we can return right away.
*/
makeDirty(pPg);
if( (pPg->flags&PGHDR_IN_JOURNAL)
&& (pageInStatement(pPg) || pPager->stmtInUse==0)
){
if( pageInJournal(pPg) && (pageInStatement(pPg) || pPager->stmtInUse==0) ){
pPager->dirtyCache = 1;
pPager->dbModified = 1;
}else{
@@ -3199,7 +3184,7 @@ static int pager_write(PgHdr *pPg){
** EXCLUSIVE lock on the main database file. Write the current page to
** the transaction journal if it is not there already.
*/
if( !(pPg->flags&PGHDR_IN_JOURNAL) && pPager->journalOpen ){
if( !pageInJournal(pPg) && pPager->journalOpen ){
if( (int)pPg->pgno <= pPager->origDbSize ){
u32 cksum;
char *pData2;
@@ -3254,7 +3239,6 @@ static int pager_write(PgHdr *pPg){
if( pPg->flags&PGHDR_NEED_SYNC ){
pPager->needSync = 1;
}
pPg->flags |= PGHDR_IN_JOURNAL;
}
/* If the statement journal is open and the page is not in it,
@@ -3268,8 +3252,7 @@ static int pager_write(PgHdr *pPg){
){
i64 offset = pPager->stmtNRec*(4+pPager->pageSize);
char *pData2 = CODEC2(pPager, pData, pPg->pgno, 7);
assert( (pPg->flags&PGHDR_IN_JOURNAL)
|| (int)pPg->pgno>pPager->origDbSize );
assert( pageInJournal(pPg) || (int)pPg->pgno>pPager->origDbSize );
rc = write32bits(pPager->stfd, offset, pPg->pgno);
if( rc==SQLITE_OK ){
rc = sqlite3OsWrite(pPager->stfd, pData2, pPager->pageSize, offset+4);
@@ -3515,7 +3498,6 @@ void sqlite3PagerDontRollback(DbPage *pPg){
assert( pPager->pInJournal!=0 );
sqlite3BitvecSet(pPager->pInJournal, pPg->pgno);
pPg->flags |= PGHDR_IN_JOURNAL;
pPg->flags &= ~PGHDR_NEED_READ;
if( pPager->stmtInUse ){
assert( pPager->stmtSize >= pPager->origDbSize );
@@ -4077,7 +4059,7 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
*/
if( (pPg->flags&PGHDR_NEED_SYNC) && !isCommit ){
needSyncPgno = pPg->pgno;
assert( (pPg->flags&PGHDR_IN_JOURNAL) || (int)pgno>pPager->origDbSize );
assert( pageInJournal(pPg) || (int)pgno>pPager->origDbSize );
assert( pPg->flags&PGHDR_DIRTY );
assert( pPager->needSync );
}
@@ -4087,20 +4069,16 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
** page pgno before the 'move' operation, it needs to be retained
** for the page moved there.
*/
pPg->flags &= ~(PGHDR_NEED_SYNC|PGHDR_IN_JOURNAL);
pPg->flags &= ~PGHDR_NEED_SYNC;
pPgOld = pager_lookup(pPager, pgno);
assert( !pPgOld || pPgOld->nRef==1 );
if( pPgOld ){
pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC);
}
if( sqlite3BitvecTest(pPager->pInJournal, pgno) ){
pPg->flags |= PGHDR_IN_JOURNAL;
}
sqlite3PcacheMove(pPg, pgno);
if( pPgOld ){
sqlite3PcacheMove(pPgOld, 0);
sqlite3PcacheRelease(pPgOld);
sqlite3PcacheDrop(pPgOld);
}
makeDirty(pPg);
@@ -4138,7 +4116,6 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
pPager->needSync = 1;
assert( pPager->noSync==0 && !MEMDB );
pPgHdr->flags |= PGHDR_NEED_SYNC;
pPgHdr->flags |= PGHDR_IN_JOURNAL;
makeDirty(pPgHdr);
sqlite3PagerUnref(pPgHdr);
}

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,7 @@
** This header file defines the interface that the sqlite page cache
** subsystem.
**
** @(#) $Id: pcache.h,v 1.14 2008/10/17 18:51:53 danielk1977 Exp $
** @(#) $Id: pcache.h,v 1.15 2008/11/13 14:28:29 danielk1977 Exp $
*/
#ifndef _PCACHE_H_
@@ -34,6 +34,7 @@ struct PgHdr {
u32 pageHash; /* Hash of page content */
#endif
u16 flags; /* PGHDR flags defined below */
/**********************************************************************
** Elements above are public. All that follows is private to pcache.c
** and should not be accessed by other modules.
@@ -41,18 +42,11 @@ struct PgHdr {
i16 nRef; /* Number of users of this page */
PCache *pCache; /* Cache that owns this page */
/**********************************************************************
** Elements above are accessible at any time by the owner of the cache
** without the need for a mutex. The elements that follow can only be
** accessed while holding the SQLITE_MUTEX_STATIC_LRU mutex.
*/
PgHdr *pNextHash, *pPrevHash; /* Hash collision chain for PgHdr.pgno */
PgHdr *pNext, *pPrev; /* List of clean or dirty pages */
PgHdr *pNextLru, *pPrevLru; /* Part of global LRU list */
PgHdr *pDirtyNext; /* Next element in list of dirty pages */
PgHdr *pDirtyPrev; /* Previous element in list of dirty pages */
};
/* Bit values for PgHdr.flags */
#define PGHDR_IN_JOURNAL 0x001 /* Page is in rollback journal */
#define PGHDR_DIRTY 0x002 /* Page has changed */
#define PGHDR_NEED_SYNC 0x004 /* Fsync the rollback journal before
** writing this page to the database */
@@ -116,14 +110,7 @@ PgHdr *sqlite3PcacheDirtyList(PCache*);
void sqlite3PcacheClose(PCache*);
/* Clear flags from pages of the page cache */
void sqlite3PcacheClearFlags(PCache*, int mask);
/* Assert flags settings on all pages. Debugging only */
#ifndef NDEBUG
void sqlite3PcacheAssertFlags(PCache*, int trueMask, int falseMask);
#else
# define sqlite3PcacheAssertFlags(A,B,C)
#endif
void sqlite3PcacheClearSyncFlags(PCache *);
/* Return true if the number of dirty pages is 0 or 1 */
int sqlite3PcacheZeroOrOneDirtyPages(PCache*);
@@ -143,11 +130,11 @@ int sqlite3PcachePageRefcount(PgHdr*);
int sqlite3PcachePagecount(PCache*);
#ifdef SQLITE_CHECK_PAGES
/* Iterate through all pages currently stored in the cache. This interface
** is only available if SQLITE_CHECK_PAGES is defined when the library is
** built.
/* Iterate through all dirty pages currently stored in the cache. This
** interface is only available if SQLITE_CHECK_PAGES is defined when the
** library is built.
*/
void sqlite3PcacheIterate(PCache *pCache, void (*xIter)(PgHdr *));
void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *));
#endif
/* Set and get the suggested cache-size for the specified pager-cache.
@@ -168,4 +155,6 @@ int sqlite3PcacheReleaseMemory(int);
void sqlite3PcacheStats(int*,int*,int*,int*);
#endif
void sqlite3PCacheSetDefault(void);
#endif /* _PCACHE_H_ */

735
src/pcache1.c Normal file
View File

@@ -0,0 +1,735 @@
/*
** 2008 November 05
**
** 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 implements the default page cache implementation (the
** sqlite3_pcache interface). It also contains part of the implementation
** of the SQLITE_CONFIG_PAGECACHE and sqlite3_release_memory() features.
** If the default page cache implementation is overriden, then neither of
** these two features are available.
**
** @(#) $Id: pcache1.c,v 1.1 2008/11/13 14:28:29 danielk1977 Exp $
*/
#include "sqliteInt.h"
typedef struct PCache1 PCache1;
typedef struct PgHdr1 PgHdr1;
typedef struct PgFreeslot PgFreeslot;
/* Pointers to structures of this type are cast and returned as
** opaque sqlite3_pcache* handles
*/
struct PCache1 {
/* Cache configuration parameters. Page size (szPage) and the purgeable
** flag (bPurgeable) are set when the cache is created. nMax may be
** modified at any time by a call to the pcache1CacheSize() method.
** The global mutex must be held when accessing nMax.
*/
int szPage; /* Size of allocated pages in bytes */
int bPurgeable; /* True if cache is purgeable */
int nMin; /* Minimum number of pages reserved */
int nMax; /* Configured "cache_size" value */
/* Hash table of all pages. The following variables may only be accessed
** when the accessor is holding the global mutex (see pcache1EnterMutex()
** and pcache1LeaveMutex()).
*/
int nRecyclable; /* Number of pages in the LRU list */
int nPage; /* Total number of pages in apHash */
int nHash; /* Number of slots in apHash[] */
PgHdr1 **apHash; /* Hash table for fast lookup by key */
};
/*
** Each cache entry is represented by an instance of the following
** structure. A buffer of PgHdr1.pCache->szPage bytes is allocated
** directly after the structure in memory (see the PGHDR1_TO_PAGE()
** macro below).
*/
struct PgHdr1 {
unsigned int iKey; /* Key value (page number) */
PgHdr1 *pNext; /* Next in hash table chain */
PCache1 *pCache; /* Cache that currently owns this page */
PgHdr1 *pLruNext; /* Next in LRU list of unpinned pages */
PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */
};
/*
** Free slots in the allocator used to divide up the buffer provided using
** the SQLITE_CONFIG_PAGECACHE mechanism.
*/
struct PgFreeslot {
PgFreeslot *pNext; /* Next free slot */
};
/*
** Global data used by this cache.
*/
static SQLITE_WSD struct PCacheGlobal {
sqlite3_mutex *mutex; /* static mutex MUTEX_STATIC_LRU */
int nMaxPage; /* Sum of nMaxPage for purgeable caches */
int nMinPage; /* Sum of nMinPage for purgeable caches */
int nCurrentPage; /* Number of purgeable pages allocated */
PgHdr1 *pLruHead, *pLruTail; /* LRU list of unpinned pages */
/* Variables related to SQLITE_CONFIG_PAGECACHE settings. */
int szSlot; /* Size of each free slot */
void *pStart, *pEnd; /* Bounds of pagecache malloc range */
PgFreeslot *pFree; /* Free page blocks */
} pcache1_g = {0};
/*
** All code in this file should access the global structure above via the
** alias "pcache1". This ensures that the WSD emulation is used when
** compiling for systems that do not support real WSD.
*/
#define pcache1 (GLOBAL(struct PCacheGlobal, pcache1_g))
/*
** When a PgHdr1 structure is allocated, the associated PCache1.szPage
** bytes of data are located directly after it in memory (i.e. the total
** size of the allocation is sizeof(PgHdr1)+PCache1.szPage byte). The
** PGHDR1_TO_PAGE() macro takes a pointer to a PgHdr1 structure as
** an argument and returns a pointer to the associated block of szPage
** bytes. The PAGE_TO_PGHDR1() macro does the opposite: its argument is
** a pointer to a block of szPage bytes of data and the return value is
** a pointer to the associated PgHdr1 structure.
**
** assert( PGHDR1_TO_PAGE(PAGE_TO_PGHDR1(X))==X );
*/
#define PGHDR1_TO_PAGE(p) (void *)(&((unsigned char *)p)[sizeof(PgHdr1)])
#define PAGE_TO_PGHDR1(p) (PgHdr1 *)(&((unsigned char *)p)[-1*sizeof(PgHdr1)])
/*
** Macros to enter and leave the global LRU mutex.
*/
#define pcache1EnterMutex() sqlite3_mutex_enter(pcache1.mutex)
#define pcache1LeaveMutex() sqlite3_mutex_leave(pcache1.mutex)
/******************************************************************************/
/******** Page Allocation/SQLITE_CONFIG_PCACHE Related Functions **************/
/*
** This function is called during initialization if a static buffer is
** supplied to use for the page-cache by passing the SQLITE_CONFIG_PAGECACHE
** verb to sqlite3_config(). Parameter pBuf points to an allocation large
** enough to contain 'n' buffers of 'sz' bytes each.
*/
void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
PgFreeslot *p;
sz &= ~7;
pcache1.szSlot = sz;
pcache1.pStart = pBuf;
pcache1.pFree = 0;
while( n-- ){
p = (PgFreeslot*)pBuf;
p->pNext = pcache1.pFree;
pcache1.pFree = p;
pBuf = (void*)&((char*)pBuf)[sz];
}
pcache1.pEnd = pBuf;
}
/*
** Malloc function used within this file to allocate space from the buffer
** configured using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no
** such buffer exists or there is no space left in it, this function falls
** back to sqlite3Malloc().
*/
static void *pcache1Alloc(int nByte){
void *p;
assert( sqlite3_mutex_held(pcache1.mutex) );
if( nByte<=pcache1.szSlot && pcache1.pFree ){
p = (PgHdr1 *)pcache1.pFree;
pcache1.pFree = pcache1.pFree->pNext;
sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, 1);
}else{
/* Allocate a new buffer using sqlite3Malloc. Before doing so, exit the
** global pcache mutex and unlock the pager-cache object pCache. This is
** so that if the attempt to allocate a new buffer causes the the
** configured soft-heap-limit to be breached, it will be possible to
** reclaim memory from this pager-cache.
*/
pcache1LeaveMutex();
p = sqlite3Malloc(nByte);
pcache1EnterMutex();
if( p ){
int sz = sqlite3MallocSize(p);
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
}
}
return p;
}
/*
** Free an allocated buffer obtained from pcache1Alloc().
*/
static void pcache1Free(void *p){
assert( sqlite3_mutex_held(pcache1.mutex) );
if( p==0 ) return;
if( p>=pcache1.pStart && p<pcache1.pEnd ){
PgFreeslot *pSlot;
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, -1);
pSlot = (PgFreeslot*)p;
pSlot->pNext = pcache1.pFree;
pcache1.pFree = pSlot;
}else{
int iSize = sqlite3MallocSize(p);
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -iSize);
sqlite3_free(p);
}
}
/*
** Allocate a new page object initially associated with cache pCache.
*/
static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
int nByte = sizeof(PgHdr1) + pCache->szPage;
PgHdr1 *p = (PgHdr1 *)pcache1Alloc(nByte);
if( p ){
memset(p, 0, nByte);
if( pCache->bPurgeable ){
pcache1.nCurrentPage++;
}
}
return p;
}
/*
** Free a page object allocated by pcache1AllocPage().
*/
static void pcache1FreePage(PgHdr1 *p){
if( p ){
if( p->pCache->bPurgeable ){
pcache1.nCurrentPage--;
}
pcache1Free(p);
}
}
/*
** Malloc function used by SQLite to obtain space from the buffer configured
** using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no such buffer
** exists, this function falls back to sqlite3Malloc().
*/
void *sqlite3PageMalloc(int sz){
void *p;
pcache1EnterMutex();
p = pcache1Alloc(sz);
pcache1LeaveMutex();
return p;
}
/*
** Free an allocated buffer obtained from sqlite3PageMalloc().
*/
void sqlite3PageFree(void *p){
pcache1EnterMutex();
pcache1Free(p);
pcache1LeaveMutex();
}
/******************************************************************************/
/******** General Implementation Functions ************************************/
/*
** This function is used to resize the hash table used by the cache passed
** as the first argument.
**
** The global mutex must be held when this function is called.
*/
static int pcache1ResizeHash(PCache1 *p){
PgHdr1 **apNew;
int nNew;
unsigned int i;
assert( sqlite3_mutex_held(pcache1.mutex) );
nNew = p->nHash*2;
if( nNew<256 ){
nNew = 256;
}
pcache1LeaveMutex();
apNew = (PgHdr1 **)sqlite3_malloc(sizeof(PgHdr1 *)*nNew);
pcache1EnterMutex();
if( apNew ){
memset(apNew, 0, sizeof(PgHdr1 *)*nNew);
for(i=0; i<p->nHash; i++){
PgHdr1 *pPage;
PgHdr1 *pNext = p->apHash[i];
while( (pPage = pNext) ){
unsigned int h = pPage->iKey % nNew;
pNext = pPage->pNext;
pPage->pNext = apNew[h];
apNew[h] = pPage;
}
}
sqlite3_free(p->apHash);
p->apHash = apNew;
p->nHash = nNew;
}
return (p->apHash ? SQLITE_OK : SQLITE_NOMEM);
}
/*
** This function is used internally to remove the page pPage from the
** global LRU list, if is part of it. If pPage is not part of the global
** LRU list, then this function is a no-op.
**
** The global mutex must be held when this function is called.
*/
static void pcache1PinPage(PgHdr1 *pPage){
assert( sqlite3_mutex_held(pcache1.mutex) );
if( pPage && (pPage->pLruNext || pPage==pcache1.pLruTail) ){
if( pPage->pLruPrev ){
pPage->pLruPrev->pLruNext = pPage->pLruNext;
}
if( pPage->pLruNext ){
pPage->pLruNext->pLruPrev = pPage->pLruPrev;
}
if( pcache1.pLruHead==pPage ){
pcache1.pLruHead = pPage->pLruNext;
}
if( pcache1.pLruTail==pPage ){
pcache1.pLruTail = pPage->pLruPrev;
}
pPage->pLruNext = 0;
pPage->pLruPrev = 0;
pPage->pCache->nRecyclable--;
}
}
/*
** Remove the page supplied as an argument from the hash table
** (PCache1.apHash structure) that it is currently stored in.
**
** The global mutex must be held when this function is called.
*/
static void pcache1RemoveFromHash(PgHdr1 *pPage){
unsigned int h;
PCache1 *pCache = pPage->pCache;
PgHdr1 **pp;
h = pPage->iKey % pCache->nHash;
for(pp=&pCache->apHash[h]; (*pp)!=pPage; pp=&(*pp)->pNext);
*pp = (*pp)->pNext;
pCache->nPage--;
}
/*
** If there are currently more than pcache.nMaxPage pages allocated, try
** to recycle pages to reduce the number allocated to pcache.nMaxPage.
*/
static void pcache1EnforceMaxPage(void){
assert( sqlite3_mutex_held(pcache1.mutex) );
while( pcache1.nCurrentPage>pcache1.nMaxPage && pcache1.pLruTail ){
PgHdr1 *p = pcache1.pLruTail;
pcache1PinPage(p);
pcache1RemoveFromHash(p);
pcache1FreePage(p);
}
}
/*
** Discard all pages from cache pCache with a page number (key value)
** greater than or equal to iLimit. Any pinned pages that meet this
** criteria are unpinned before they are discarded.
**
** The global mutex must be held when this function is called.
*/
static void pcache1TruncateUnsafe(
PCache1 *pCache,
unsigned int iLimit
){
unsigned int h;
assert( sqlite3_mutex_held(pcache1.mutex) );
for(h=0; h<pCache->nHash; h++){
PgHdr1 **pp = &pCache->apHash[h];
PgHdr1 *pPage;
while( (pPage = *pp) ){
if( pPage->iKey>=iLimit ){
pcache1PinPage(pPage);
*pp = pPage->pNext;
pcache1FreePage(pPage);
}else{
pp = &pPage->pNext;
}
}
}
}
/******************************************************************************/
/******** sqlite3_pcache Methods **********************************************/
/*
** Implementation of the sqlite3_pcache.xInit method.
*/
static int pcache1Init(void *pUnused){
memset(&pcache1, 0, sizeof(pcache1));
if( sqlite3GlobalConfig.bCoreMutex ){
pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
}
return SQLITE_OK;
}
/*
** Implementation of the sqlite3_pcache.xShutdown method.
*/
static void pcache1Shutdown(void *pUnused){
/* no-op */
}
/*
** Implementation of the sqlite3_pcache.xCreate method.
**
** Allocate a new cache.
*/
static sqlite3_pcache *pcache1Create(int szPage, int bPurgeable){
PCache1 *pCache;
pCache = (PCache1 *)sqlite3_malloc(sizeof(PCache1));
if( pCache ){
memset(pCache, 0, sizeof(PCache1));
pCache->szPage = szPage;
pCache->bPurgeable = (bPurgeable ? 1 : 0);
if( bPurgeable ){
pCache->nMin = 10;
pcache1EnterMutex();
pcache1.nMinPage += pCache->nMin;
pcache1LeaveMutex();
}
}
return (sqlite3_pcache *)pCache;
}
/*
** Implementation of the sqlite3_pcache.xCachesize method.
**
** Configure the cache_size limit for a cache.
*/
static void pcache1Cachesize(sqlite3_pcache *p, int nMax){
PCache1 *pCache = (PCache1 *)p;
if( pCache->bPurgeable ){
pcache1EnterMutex();
pcache1.nMaxPage += (nMax - pCache->nMax);
pCache->nMax = nMax;
pcache1EnforceMaxPage();
pcache1LeaveMutex();
}
}
/*
** Implementation of the sqlite3_pcache.xPagecount method.
*/
static int pcache1Pagecount(sqlite3_pcache *p){
int n;
pcache1EnterMutex();
n = ((PCache1 *)p)->nPage;
pcache1LeaveMutex();
return n;
}
/*
** Implementation of the sqlite3_pcache.xFetch method.
**
** Fetch a page by key value.
**
** Whether or not a new page may be allocated by this function depends on
** the value of the createFlag argument.
**
** There are three different approaches to obtaining space for a page,
** depending on the value of parameter createFlag (which may be 0, 1 or 2).
**
** 1. Regardless of the value of createFlag, the cache is searched for a
** copy of the requested page. If one is found, it is returned.
**
** 2. If createFlag==0 and the page is not already in the cache, NULL is
** returned.
**
** 3. If createFlag is 1, the cache is marked as purgeable and the page is
** not already in the cache, and if either of the following are true,
** return NULL:
**
** (a) the number of pages pinned by the cache is greater than
** PCache1.nMax, or
** (b) the number of pages pinned by the cache is greater than
** the sum of nMax for all purgeable caches, less the sum of
** nMin for all other purgeable caches.
**
** 4. If none of the first three conditions apply and the cache is marked
** as purgeable, and if one of the following is true:
**
** (a) The number of pages allocated for the cache is already
** PCache1.nMax, or
**
** (b) The number of pages allocated for all purgeable caches is
** already equal to or greater than the sum of nMax for all
** purgeable caches,
**
** then attempt to recycle a page from the LRU list. If it is the right
** size, return the recycled buffer. Otherwise, free the buffer and
** proceed to step 5.
**
** 5. Otherwise, allocate and return a new page buffer.
*/
static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
int nPinned;
PCache1 *pCache = (PCache1 *)p;
PgHdr1 *pPage = 0;
pcache1EnterMutex();
if( createFlag==1 ) sqlite3BeginBenignMalloc();
/* Search the hash table for an existing entry. */
if( pCache->nHash>0 ){
unsigned int h = iKey % pCache->nHash;
for(pPage=pCache->apHash[h]; pPage&&pPage->iKey!=iKey; pPage=pPage->pNext);
}
if( pPage || createFlag==0 ){
pcache1PinPage(pPage);
goto fetch_out;
}
/* Step 3 of header comment. */
nPinned = pCache->nPage - pCache->nRecyclable;
if( createFlag==1 && pCache->bPurgeable && (
nPinned>=(pcache1.nMaxPage+pCache->nMin-pcache1.nMinPage)
|| nPinned>=(pCache->nMax)
)){
goto fetch_out;
}
if( pCache->nPage>=pCache->nHash && pcache1ResizeHash(pCache) ){
goto fetch_out;
}
/* Step 4. Try to recycle a page buffer if appropriate. */
if( pCache->bPurgeable && pcache1.pLruTail && (
pCache->nPage>=pCache->nMax-1 || pcache1.nCurrentPage>=pcache1.nMaxPage
)){
pPage = pcache1.pLruTail;
pcache1RemoveFromHash(pPage);
pcache1PinPage(pPage);
if( pPage->pCache->szPage!=pCache->szPage ){
pcache1FreePage(pPage);
pPage = 0;
}else{
pcache1.nCurrentPage -= (pPage->pCache->bPurgeable - pCache->bPurgeable);
}
}
/* Step 5. If a usable page buffer has still not been found,
** attempt to allocate a new one.
*/
if( !pPage ){
pPage = pcache1AllocPage(pCache);
}
if( pPage ){
unsigned int h = iKey % pCache->nHash;
memset(pPage, 0, pCache->szPage + sizeof(PgHdr1));
pCache->nPage++;
pPage->iKey = iKey;
pPage->pNext = pCache->apHash[h];
pPage->pCache = pCache;
pCache->apHash[h] = pPage;
}
fetch_out:
if( createFlag==1 ) sqlite3EndBenignMalloc();
pcache1LeaveMutex();
return (pPage ? PGHDR1_TO_PAGE(pPage) : 0);
}
/*
** Implementation of the sqlite3_pcache.xUnpin method.
**
** Mark a page as unpinned (eligible for asynchronous recycling).
*/
static void pcache1Unpin(sqlite3_pcache *p, void *pPg, int reuseUnlikely){
PCache1 *pCache = (PCache1 *)p;
PgHdr1 *pPage = PAGE_TO_PGHDR1(pPg);
pcache1EnterMutex();
/* It is an error to call this function if the page is already
** part of the global LRU list.
*/
assert( pPage->pLruPrev==0 && pPage->pLruNext==0 );
assert( pcache1.pLruHead!=pPage && pcache1.pLruTail!=pPage );
if( reuseUnlikely || pcache1.nCurrentPage>pcache1.nMaxPage ){
pcache1RemoveFromHash(pPage);
pcache1FreePage(pPage);
}else{
/* Add the page to the global LRU list. Normally, the page is added to
** the head of the list (last page to be recycled). However, if the
** reuseUnlikely flag passed to this function is true, the page is added
** to the tail of the list (first page to be recycled).
*/
if( pcache1.pLruHead ){
pcache1.pLruHead->pLruPrev = pPage;
pPage->pLruNext = pcache1.pLruHead;
pcache1.pLruHead = pPage;
}else{
pcache1.pLruTail = pPage;
pcache1.pLruHead = pPage;
}
pCache->nRecyclable++;
}
pcache1LeaveMutex();
}
/*
** Implementation of the sqlite3_pcache.xRekey method.
*/
static void pcache1Rekey(
sqlite3_pcache *p,
void *pPg,
unsigned int iOld,
unsigned int iNew
){
PCache1 *pCache = (PCache1 *)p;
PgHdr1 *pPage = PAGE_TO_PGHDR1(pPg);
PgHdr1 **pp;
unsigned int h;
assert( pPage->iKey==iOld );
pcache1EnterMutex();
h = iOld%pCache->nHash;
pp = &pCache->apHash[h];
while( (*pp)!=pPage ){
pp = &(*pp)->pNext;
}
*pp = pPage->pNext;
h = iNew%pCache->nHash;
pPage->iKey = iNew;
pPage->pNext = pCache->apHash[h];
pCache->apHash[h] = pPage;
pcache1LeaveMutex();
}
/*
** Implementation of the sqlite3_pcache.xTruncate method.
**
** Discard all unpinned pages in the cache with a page number equal to
** or greater than parameter iLimit. Any pinned pages with a page number
** equal to or greater than iLimit are implicitly unpinned.
*/
static void pcache1Truncate(sqlite3_pcache *p, unsigned int iLimit){
PCache1 *pCache = (PCache1 *)p;
pcache1EnterMutex();
pcache1TruncateUnsafe(pCache, iLimit);
pcache1LeaveMutex();
}
/*
** Implementation of the sqlite3_pcache.xDestroy method.
**
** Destroy a cache allocated using pcache1Create().
*/
static void pcache1Destroy(sqlite3_pcache *p){
PCache1 *pCache = (PCache1 *)p;
pcache1EnterMutex();
pcache1TruncateUnsafe(pCache, 0);
pcache1.nMaxPage -= pCache->nMax;
pcache1.nMinPage -= pCache->nMin;
pcache1EnforceMaxPage();
pcache1LeaveMutex();
sqlite3_free(pCache->apHash);
sqlite3_free(pCache);
}
/*
** This function is called during initialization (sqlite3_initialize()) to
** install the default pluggable cache module, assuming the user has not
** already provided an alternative.
*/
void sqlite3PCacheSetDefault(void){
static sqlite3_pcache_methods defaultMethods = {
0, /* pArg */
pcache1Init, /* xInit */
pcache1Shutdown, /* xShutdown */
pcache1Create, /* xCreate */
pcache1Cachesize, /* xCachesize */
pcache1Pagecount, /* xPagecount */
pcache1Fetch, /* xFetch */
pcache1Unpin, /* xUnpin */
pcache1Rekey, /* xRekey */
pcache1Truncate, /* xTruncate */
pcache1Destroy /* xDestroy */
};
sqlite3_config(SQLITE_CONFIG_PCACHE, &defaultMethods);
}
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
/*
** This function is called to free superfluous dynamically allocated memory
** held by the pager system. Memory in use by any SQLite pager allocated
** by the current thread may be sqlite3_free()ed.
**
** nReq is the number of bytes of memory required. Once this much has
** been released, the function returns. The return value is the total number
** of bytes of memory released.
*/
int sqlite3PcacheReleaseMemory(int nReq){
int nFree = 0;
if( pcache1.pStart==0 ){
PgHdr1 *p;
pcache1EnterMutex();
while( (nReq<0 || nFree<nReq) && (p=pcache1.pLruTail) ){
nFree += sqlite3MallocSize(p);
pcache1PinPage(p);
pcache1RemoveFromHash(p);
pcache1FreePage(p);
}
pcache1LeaveMutex();
}
return nFree;
}
#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */
#ifdef SQLITE_TEST
/*
** This function is used by test procedures to inspect the internal state
** of the global cache.
*/
void sqlite3PcacheStats(
int *pnCurrent, /* OUT: Total number of pages cached */
int *pnMax, /* OUT: Global maximum cache size */
int *pnMin, /* OUT: Sum of PCache1.nMin for purgeable caches */
int *pnRecyclable /* OUT: Total number of pages available for recycling */
){
PgHdr1 *p;
int nRecyclable = 0;
for(p=pcache1.pLruHead; p; p=p->pLruNext){
nRecyclable++;
}
*pnCurrent = pcache1.nCurrentPage;
*pnMax = pcache1.nMaxPage;
*pnMin = pcache1.nMinPage;
*pnRecyclable = nRecyclable;
}
#endif

View File

@@ -30,7 +30,7 @@
** the version number) and changes its name to "sqlite3.h" as
** part of the build process.
**
** @(#) $Id: sqlite.h.in,v 1.412 2008/11/10 23:54:06 drh Exp $
** @(#) $Id: sqlite.h.in,v 1.413 2008/11/13 14:28:29 danielk1977 Exp $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
@@ -1334,6 +1334,8 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */
/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
#define SQLITE_CONFIG_PCACHE 14 /* sqlite3_pcache_methods* */
#define SQLITE_CONFIG_GETPCACHE 15 /* sqlite3_pcache_methods* */
/*
** CAPI3REF: Configuration Options {H10170} <S20000>
@@ -6555,6 +6557,143 @@ SQLITE_EXPERIMENTAL int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
#define SQLITE_STMTSTATUS_FULLSCAN_STEP 1
#define SQLITE_STMTSTATUS_SORT 2
/*
** The sqlite3_pcache type is opaque. It is implemented by
** the pluggable module. The SQLite core has no knowledge of
** its size or internal structure and never deals with the
** sqlite3_pcache object except by holding and passing pointers
** to the object.
*/
typedef struct sqlite3_pcache sqlite3_pcache;
/*
** CAPI3REF: Custom Page Cache API.
** EXPERIMENTAL
**
** The sqlite3_config(SQLITE_CONFIG_SET_PCACHE, ...) interface can
** register an alternative page cache implementation by passing in an
** instance of the sqlite3_pcache_methods structure. The majority of the
** heap memory used by sqlite is used by the page cache to cache data read
** from, or ready to be written to, the database file. By implementing a
** custom page cache using this API, an application can control more
** precisely the amount of memory consumed by sqlite, the way in which
** said memory is allocated and released, and the policies used to
** determine exactly which parts of a database file are cached and for
** how long.
**
** The contents of the structure are copied to an internal buffer by sqlite
** within the call to [sqlite3_config].
**
** The xInit() method is called once for each call to sqlite3_initialize()
** (usually only once during the lifetime of the process). It is passed
** a copy of the sqlite3_pcache_methods.pArg value. It can be used to set
** up global structures and mutexes required by the custom page cache
** implementation. The xShutdown() method is called from within
** sqlite3_shutdown(), if the application invokes this API. It can be used
** to clean up any outstanding resources before process shutdown, if required.
**
** The xCreate() method is used to construct a new cache instance. The
** first parameter, szPage, is the size in bytes of the pages that must
** be allocated by the cache. szPage will not be a power of two. The
** second argument, bPurgeable, is true if the cache being created will
** be used to cache database pages read from a file stored on disk, or
** false if it is used for an in-memory database. The cache implementation
** does not have to do anything special based on the value of bPurgeable,
** it is purely advisory.
**
** The xCachesize() method may be called at any time by SQLite to set the
** suggested maximum cache-size (number of pages stored by) the cache
** instance passed as the first argument. This is the value configured using
** the SQLite "PRAGMA cache_size" command. As with the bPurgeable parameter,
** the implementation is not required to do anything special with this
** value, it is advisory only.
**
** The xPagecount() method should return the number of pages currently
** stored in the cache supplied as an argument.
**
** The xFetch() method is used to fetch a page and return a pointer to it.
** A 'page', in this context, is a buffer of szPage bytes aligned at an
** 8-byte boundary. The page to be fetched is determined by the key. The
** mimimum key value is 1. After it has been retrieved using xFetch, the page
** is considered to be pinned.
**
** If the requested page is already in the page cache, then a pointer to
** the cached buffer should be returned with its contents intact. If the
** page is not already in the cache, then the expected behaviour of the
** cache is determined by the value of the createFlag parameter passed
** to xFetch, according to the following table:
**
** <table border=1 width=85% align=center>
** <tr><th>createFlag<th>Expected Behaviour
** <tr><td>0<td>NULL should be returned. No new cache entry is created.
** <tr><td>1<td>If createFlag is set to 1, this indicates that
** SQLite is holding pinned pages that can be unpinned
** by writing their contents to the database file (a
** relatively expensive operation). In this situation the
** cache implementation has two choices: it can return NULL,
** in which case SQLite will attempt to unpin one or more
** pages before re-requesting the same page, or it can
** allocate a new page and return a pointer to it. If a new
** page is allocated, then it must be completely zeroed before
** it is returned.
** <tr><td>2<td>If createFlag is set to 2, then SQLite is not holding any
** pinned pages associated with the specific cache passed
** as the first argument to xFetch() that can be unpinned. The
** cache implementation should attempt to allocate a new
** cache entry and return a pointer to it. Again, the new
** page should be zeroed before it is returned. If the xFetch()
** method returns NULL when createFlag==2, SQLite assumes that
** a memory allocation failed and returns SQLITE_NOMEM to the
** user.
** </table>
**
** xUnpin() is called by SQLite with a pointer to a currently pinned page
** as its second argument. If the third parameter, discard, is non-zero,
** then the page should be evicted from the cache. In this case SQLite
** assumes that the next time the page is retrieved from the cache using
** the xFetch() method, it will be zeroed. If the discard parameter is
** zero, then the page is considered to be unpinned. The cache implementation
** may choose to reclaim (free or recycle) unpinned pages at any time.
** SQLite assumes that next time the page is retrieved from the cache
** it will either be zeroed, or contain the same data that it did when it
** was unpinned.
**
** The cache is not required to perform any reference counting. A single
** call to xUnpin() unpins the page regardless of the number of prior calls
** to xFetch().
**
** The xRekey() method is used to change the key value associated with the
** page passed as the second argument from oldKey to newKey. If the cache
** contains an entry associated with oldKey, it should be discarded. Any
** cache entry associated with oldKey is guaranteed not to be pinned.
**
** When SQLite calls the xTruncate() method, the cache must discard all
** existing cache entries with page numbers (keys) greater than or equal
** to the value of the iLimit parameter passed to xTruncate(). If any
** of these pages are pinned, they are implicitly unpinned, meaning that
** they can be safely discarded.
**
** The xDestroy() method is used to delete a cache allocated by xCreate().
** All resources associated with the specified cache should be freed. After
** calling the xDestroy() method, SQLite considers the sqlite3_pcache*
** handle invalid, and will not use it with any other sqlite3_pcache_methods
** functions.
*/
typedef struct sqlite3_pcache_methods sqlite3_pcache_methods;
struct sqlite3_pcache_methods {
void *pArg;
int (*xInit)(void*);
void (*xShutdown)(void*);
sqlite3_pcache *(*xCreate)(int szPage, int bPurgeable);
void (*xCachesize)(sqlite3_pcache*, int nCachesize);
int (*xPagecount)(sqlite3_pcache*);
void *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag);
void (*xUnpin)(sqlite3_pcache*, void*, int discard);
void (*xRekey)(sqlite3_pcache*, void*, unsigned oldKey, unsigned newKey);
void (*xTruncate)(sqlite3_pcache*, unsigned iLimit);
void (*xDestroy)(sqlite3_pcache*);
};
/*
** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support.

View File

@@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.790 2008/11/11 18:29:00 drh Exp $
** @(#) $Id: sqliteInt.h,v 1.791 2008/11/13 14:28:30 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@@ -1958,6 +1958,7 @@ struct Sqlite3Config {
int nLookaside; /* Default lookaside buffer count */
sqlite3_mem_methods m; /* Low-level memory allocation interface */
sqlite3_mutex_methods mutex; /* Low-level mutex interface */
sqlite3_pcache_methods pcache; /* Low-level page-cache interface */
void *pHeap; /* Heap storage space */
int nHeap; /* Size of pHeap[] */
int mnReq, mxReq; /* Min and max heap requests sizes */