more TDB
This commit is contained in:
parent
031d84e76e
commit
3beef665c8
|
@ -22,16 +22,6 @@ target_link_libraries(
|
||||||
PUBLIC util
|
PUBLIC util
|
||||||
)
|
)
|
||||||
|
|
||||||
# for tdb_sqlite
|
|
||||||
add_library(tdb_sqlite "")
|
|
||||||
target_sources(tdb_sqlite
|
|
||||||
PRIVATE
|
|
||||||
"src/sqlite/pcache.c"
|
|
||||||
"src/sqlite/pcache1.c"
|
|
||||||
"src/sqlite/pager.c"
|
|
||||||
)
|
|
||||||
target_include_directories(tdb_sqlite PUBLIC "src/sqliteinc")
|
|
||||||
|
|
||||||
# for test
|
# for test
|
||||||
if(${BUILD_TEST})
|
if(${BUILD_TEST})
|
||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
|
|
|
@ -1,308 +0,0 @@
|
||||||
/*
|
|
||||||
** 2007 August 27
|
|
||||||
**
|
|
||||||
** 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 contains code used to implement mutexes on Btree objects.
|
|
||||||
** This code really belongs in btree.c. But btree.c is getting too
|
|
||||||
** big and we want to break it down some. This packaged seemed like
|
|
||||||
** a good breakout.
|
|
||||||
*/
|
|
||||||
#include "btreeInt.h"
|
|
||||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
|
||||||
#if SQLITE_THREADSAFE
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Obtain the BtShared mutex associated with B-Tree handle p. Also,
|
|
||||||
** set BtShared.db to the database handle associated with p and the
|
|
||||||
** p->locked boolean to true.
|
|
||||||
*/
|
|
||||||
static void lockBtreeMutex(Btree *p){
|
|
||||||
assert( p->locked==0 );
|
|
||||||
assert( sqlite3_mutex_notheld(p->pBt->mutex) );
|
|
||||||
assert( sqlite3_mutex_held(p->db->mutex) );
|
|
||||||
|
|
||||||
sqlite3_mutex_enter(p->pBt->mutex);
|
|
||||||
p->pBt->db = p->db;
|
|
||||||
p->locked = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Release the BtShared mutex associated with B-Tree handle p and
|
|
||||||
** clear the p->locked boolean.
|
|
||||||
*/
|
|
||||||
static void SQLITE_NOINLINE unlockBtreeMutex(Btree *p){
|
|
||||||
BtShared *pBt = p->pBt;
|
|
||||||
assert( p->locked==1 );
|
|
||||||
assert( sqlite3_mutex_held(pBt->mutex) );
|
|
||||||
assert( sqlite3_mutex_held(p->db->mutex) );
|
|
||||||
assert( p->db==pBt->db );
|
|
||||||
|
|
||||||
sqlite3_mutex_leave(pBt->mutex);
|
|
||||||
p->locked = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Forward reference */
|
|
||||||
static void SQLITE_NOINLINE btreeLockCarefully(Btree *p);
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Enter a mutex on the given BTree object.
|
|
||||||
**
|
|
||||||
** If the object is not sharable, then no mutex is ever required
|
|
||||||
** and this routine is a no-op. The underlying mutex is non-recursive.
|
|
||||||
** But we keep a reference count in Btree.wantToLock so the behavior
|
|
||||||
** of this interface is recursive.
|
|
||||||
**
|
|
||||||
** To avoid deadlocks, multiple Btrees are locked in the same order
|
|
||||||
** by all database connections. The p->pNext is a list of other
|
|
||||||
** Btrees belonging to the same database connection as the p Btree
|
|
||||||
** which need to be locked after p. If we cannot get a lock on
|
|
||||||
** p, then first unlock all of the others on p->pNext, then wait
|
|
||||||
** for the lock to become available on p, then relock all of the
|
|
||||||
** subsequent Btrees that desire a lock.
|
|
||||||
*/
|
|
||||||
void sqlite3BtreeEnter(Btree *p){
|
|
||||||
/* Some basic sanity checking on the Btree. The list of Btrees
|
|
||||||
** connected by pNext and pPrev should be in sorted order by
|
|
||||||
** Btree.pBt value. All elements of the list should belong to
|
|
||||||
** the same connection. Only shared Btrees are on the list. */
|
|
||||||
assert( p->pNext==0 || p->pNext->pBt>p->pBt );
|
|
||||||
assert( p->pPrev==0 || p->pPrev->pBt<p->pBt );
|
|
||||||
assert( p->pNext==0 || p->pNext->db==p->db );
|
|
||||||
assert( p->pPrev==0 || p->pPrev->db==p->db );
|
|
||||||
assert( p->sharable || (p->pNext==0 && p->pPrev==0) );
|
|
||||||
|
|
||||||
/* Check for locking consistency */
|
|
||||||
assert( !p->locked || p->wantToLock>0 );
|
|
||||||
assert( p->sharable || p->wantToLock==0 );
|
|
||||||
|
|
||||||
/* We should already hold a lock on the database connection */
|
|
||||||
assert( sqlite3_mutex_held(p->db->mutex) );
|
|
||||||
|
|
||||||
/* Unless the database is sharable and unlocked, then BtShared.db
|
|
||||||
** should already be set correctly. */
|
|
||||||
assert( (p->locked==0 && p->sharable) || p->pBt->db==p->db );
|
|
||||||
|
|
||||||
if( !p->sharable ) return;
|
|
||||||
p->wantToLock++;
|
|
||||||
if( p->locked ) return;
|
|
||||||
btreeLockCarefully(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is a helper function for sqlite3BtreeLock(). By moving
|
|
||||||
** complex, but seldom used logic, out of sqlite3BtreeLock() and
|
|
||||||
** into this routine, we avoid unnecessary stack pointer changes
|
|
||||||
** and thus help the sqlite3BtreeLock() routine to run much faster
|
|
||||||
** in the common case.
|
|
||||||
*/
|
|
||||||
static void SQLITE_NOINLINE btreeLockCarefully(Btree *p){
|
|
||||||
Btree *pLater;
|
|
||||||
|
|
||||||
/* In most cases, we should be able to acquire the lock we
|
|
||||||
** want without having to go through the ascending lock
|
|
||||||
** procedure that follows. Just be sure not to block.
|
|
||||||
*/
|
|
||||||
if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){
|
|
||||||
p->pBt->db = p->db;
|
|
||||||
p->locked = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* To avoid deadlock, first release all locks with a larger
|
|
||||||
** BtShared address. Then acquire our lock. Then reacquire
|
|
||||||
** the other BtShared locks that we used to hold in ascending
|
|
||||||
** order.
|
|
||||||
*/
|
|
||||||
for(pLater=p->pNext; pLater; pLater=pLater->pNext){
|
|
||||||
assert( pLater->sharable );
|
|
||||||
assert( pLater->pNext==0 || pLater->pNext->pBt>pLater->pBt );
|
|
||||||
assert( !pLater->locked || pLater->wantToLock>0 );
|
|
||||||
if( pLater->locked ){
|
|
||||||
unlockBtreeMutex(pLater);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lockBtreeMutex(p);
|
|
||||||
for(pLater=p->pNext; pLater; pLater=pLater->pNext){
|
|
||||||
if( pLater->wantToLock ){
|
|
||||||
lockBtreeMutex(pLater);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Exit the recursive mutex on a Btree.
|
|
||||||
*/
|
|
||||||
void sqlite3BtreeLeave(Btree *p){
|
|
||||||
assert( sqlite3_mutex_held(p->db->mutex) );
|
|
||||||
if( p->sharable ){
|
|
||||||
assert( p->wantToLock>0 );
|
|
||||||
p->wantToLock--;
|
|
||||||
if( p->wantToLock==0 ){
|
|
||||||
unlockBtreeMutex(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
/*
|
|
||||||
** Return true if the BtShared mutex is held on the btree, or if the
|
|
||||||
** B-Tree is not marked as sharable.
|
|
||||||
**
|
|
||||||
** This routine is used only from within assert() statements.
|
|
||||||
*/
|
|
||||||
int sqlite3BtreeHoldsMutex(Btree *p){
|
|
||||||
assert( p->sharable==0 || p->locked==0 || p->wantToLock>0 );
|
|
||||||
assert( p->sharable==0 || p->locked==0 || p->db==p->pBt->db );
|
|
||||||
assert( p->sharable==0 || p->locked==0 || sqlite3_mutex_held(p->pBt->mutex) );
|
|
||||||
assert( p->sharable==0 || p->locked==0 || sqlite3_mutex_held(p->db->mutex) );
|
|
||||||
|
|
||||||
return (p->sharable==0 || p->locked);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Enter the mutex on every Btree associated with a database
|
|
||||||
** connection. This is needed (for example) prior to parsing
|
|
||||||
** a statement since we will be comparing table and column names
|
|
||||||
** against all schemas and we do not want those schemas being
|
|
||||||
** reset out from under us.
|
|
||||||
**
|
|
||||||
** There is a corresponding leave-all procedures.
|
|
||||||
**
|
|
||||||
** Enter the mutexes in accending order by BtShared pointer address
|
|
||||||
** to avoid the possibility of deadlock when two threads with
|
|
||||||
** two or more btrees in common both try to lock all their btrees
|
|
||||||
** at the same instant.
|
|
||||||
*/
|
|
||||||
static void SQLITE_NOINLINE btreeEnterAll(sqlite3 *db){
|
|
||||||
int i;
|
|
||||||
int skipOk = 1;
|
|
||||||
Btree *p;
|
|
||||||
assert( sqlite3_mutex_held(db->mutex) );
|
|
||||||
for(i=0; i<db->nDb; i++){
|
|
||||||
p = db->aDb[i].pBt;
|
|
||||||
if( p && p->sharable ){
|
|
||||||
sqlite3BtreeEnter(p);
|
|
||||||
skipOk = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
db->noSharedCache = skipOk;
|
|
||||||
}
|
|
||||||
void sqlite3BtreeEnterAll(sqlite3 *db){
|
|
||||||
if( db->noSharedCache==0 ) btreeEnterAll(db);
|
|
||||||
}
|
|
||||||
static void SQLITE_NOINLINE btreeLeaveAll(sqlite3 *db){
|
|
||||||
int i;
|
|
||||||
Btree *p;
|
|
||||||
assert( sqlite3_mutex_held(db->mutex) );
|
|
||||||
for(i=0; i<db->nDb; i++){
|
|
||||||
p = db->aDb[i].pBt;
|
|
||||||
if( p ) sqlite3BtreeLeave(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void sqlite3BtreeLeaveAll(sqlite3 *db){
|
|
||||||
if( db->noSharedCache==0 ) btreeLeaveAll(db);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
/*
|
|
||||||
** Return true if the current thread holds the database connection
|
|
||||||
** mutex and all required BtShared mutexes.
|
|
||||||
**
|
|
||||||
** This routine is used inside assert() statements only.
|
|
||||||
*/
|
|
||||||
int sqlite3BtreeHoldsAllMutexes(sqlite3 *db){
|
|
||||||
int i;
|
|
||||||
if( !sqlite3_mutex_held(db->mutex) ){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
for(i=0; i<db->nDb; i++){
|
|
||||||
Btree *p;
|
|
||||||
p = db->aDb[i].pBt;
|
|
||||||
if( p && p->sharable &&
|
|
||||||
(p->wantToLock==0 || !sqlite3_mutex_held(p->pBt->mutex)) ){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif /* NDEBUG */
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
/*
|
|
||||||
** Return true if the correct mutexes are held for accessing the
|
|
||||||
** db->aDb[iDb].pSchema structure. The mutexes required for schema
|
|
||||||
** access are:
|
|
||||||
**
|
|
||||||
** (1) The mutex on db
|
|
||||||
** (2) if iDb!=1, then the mutex on db->aDb[iDb].pBt.
|
|
||||||
**
|
|
||||||
** If pSchema is not NULL, then iDb is computed from pSchema and
|
|
||||||
** db using sqlite3SchemaToIndex().
|
|
||||||
*/
|
|
||||||
int sqlite3SchemaMutexHeld(sqlite3 *db, int iDb, Schema *pSchema){
|
|
||||||
Btree *p;
|
|
||||||
assert( db!=0 );
|
|
||||||
if( pSchema ) iDb = sqlite3SchemaToIndex(db, pSchema);
|
|
||||||
assert( iDb>=0 && iDb<db->nDb );
|
|
||||||
if( !sqlite3_mutex_held(db->mutex) ) return 0;
|
|
||||||
if( iDb==1 ) return 1;
|
|
||||||
p = db->aDb[iDb].pBt;
|
|
||||||
assert( p!=0 );
|
|
||||||
return p->sharable==0 || p->locked==1;
|
|
||||||
}
|
|
||||||
#endif /* NDEBUG */
|
|
||||||
|
|
||||||
#else /* SQLITE_THREADSAFE>0 above. SQLITE_THREADSAFE==0 below */
|
|
||||||
/*
|
|
||||||
** The following are special cases for mutex enter routines for use
|
|
||||||
** in single threaded applications that use shared cache. Except for
|
|
||||||
** these two routines, all mutex operations are no-ops in that case and
|
|
||||||
** are null #defines in btree.h.
|
|
||||||
**
|
|
||||||
** If shared cache is disabled, then all btree mutex routines, including
|
|
||||||
** the ones below, are no-ops and are null #defines in btree.h.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void sqlite3BtreeEnter(Btree *p){
|
|
||||||
p->pBt->db = p->db;
|
|
||||||
}
|
|
||||||
void sqlite3BtreeEnterAll(sqlite3 *db){
|
|
||||||
int i;
|
|
||||||
for(i=0; i<db->nDb; i++){
|
|
||||||
Btree *p = db->aDb[i].pBt;
|
|
||||||
if( p ){
|
|
||||||
p->pBt->db = p->db;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* if SQLITE_THREADSAFE */
|
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_INCRBLOB
|
|
||||||
/*
|
|
||||||
** Enter a mutex on a Btree given a cursor owned by that Btree.
|
|
||||||
**
|
|
||||||
** These entry points are used by incremental I/O only. Enter() is required
|
|
||||||
** any time OMIT_SHARED_CACHE is not defined, regardless of whether or not
|
|
||||||
** the build is threadsafe. Leave() is only required by threadsafe builds.
|
|
||||||
*/
|
|
||||||
void sqlite3BtreeEnterCursor(BtCursor *pCur){
|
|
||||||
sqlite3BtreeEnter(pCur->pBtree);
|
|
||||||
}
|
|
||||||
# if SQLITE_THREADSAFE
|
|
||||||
void sqlite3BtreeLeaveCursor(BtCursor *pCur){
|
|
||||||
sqlite3BtreeLeave(pCur->pBtree);
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
#endif /* ifndef SQLITE_OMIT_INCRBLOB */
|
|
||||||
|
|
||||||
#endif /* ifndef SQLITE_OMIT_SHARED_CACHE */
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,851 +0,0 @@
|
||||||
/*
|
|
||||||
** 2008 August 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 that page cache.
|
|
||||||
*/
|
|
||||||
#include "sqliteInt.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
** A complete page cache is an instance of this structure. Every
|
|
||||||
** entry in the cache holds a single page of the database file. The
|
|
||||||
** btree layer only operates on the cached copy of the database pages.
|
|
||||||
**
|
|
||||||
** A page cache entry is "clean" if it exactly matches what is currently
|
|
||||||
** on disk. A page is "dirty" if it has been modified and needs to be
|
|
||||||
** persisted to disk.
|
|
||||||
**
|
|
||||||
** pDirty, pDirtyTail, pSynced:
|
|
||||||
** All dirty pages are linked into the doubly linked list using
|
|
||||||
** PgHdr.pDirtyNext and pDirtyPrev. The list is maintained in LRU order
|
|
||||||
** such that p was added to the list more recently than p->pDirtyNext.
|
|
||||||
** PCache.pDirty points to the first (newest) element in the list and
|
|
||||||
** pDirtyTail to the last (oldest).
|
|
||||||
**
|
|
||||||
** The PCache.pSynced variable is used to optimize searching for a dirty
|
|
||||||
** page to eject from the cache mid-transaction. It is better to eject
|
|
||||||
** a page that does not require a journal sync than one that does.
|
|
||||||
** Therefore, pSynced is maintained so that it *almost* always points
|
|
||||||
** to either the oldest page in the pDirty/pDirtyTail list that has a
|
|
||||||
** clear PGHDR_NEED_SYNC flag or to a page that is older than this one
|
|
||||||
** (so that the right page to eject can be found by following pDirtyPrev
|
|
||||||
** pointers).
|
|
||||||
*/
|
|
||||||
struct PCache {
|
|
||||||
PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */
|
|
||||||
PgHdr *pSynced; /* Last synced page in dirty page list */
|
|
||||||
int nRefSum; /* Sum of ref counts over all pages */
|
|
||||||
int szCache; /* Configured cache size */
|
|
||||||
int szSpill; /* Size before spilling occurs */
|
|
||||||
int szPage; /* Size of every page in this cache */
|
|
||||||
int szExtra; /* Size of extra space for each page */
|
|
||||||
u8 bPurgeable; /* True if pages are on backing store */
|
|
||||||
u8 eCreate; /* eCreate value for for xFetch() */
|
|
||||||
int (*xStress)(void *, PgHdr *); /* Call to try make a page clean */
|
|
||||||
void * pStress; /* Argument to xStress */
|
|
||||||
sqlite3_pcache *pCache; /* Pluggable cache module */
|
|
||||||
};
|
|
||||||
|
|
||||||
/********************************** Test and Debug Logic **********************/
|
|
||||||
/*
|
|
||||||
** Debug tracing macros. Enable by by changing the "0" to "1" and
|
|
||||||
** recompiling.
|
|
||||||
**
|
|
||||||
** When sqlite3PcacheTrace is 1, single line trace messages are issued.
|
|
||||||
** When sqlite3PcacheTrace is 2, a dump of the pcache showing all cache entries
|
|
||||||
** is displayed for many operations, resulting in a lot of output.
|
|
||||||
*/
|
|
||||||
#if defined(SQLITE_DEBUG) && 0
|
|
||||||
int sqlite3PcacheTrace = 2; /* 0: off 1: simple 2: cache dumps */
|
|
||||||
int sqlite3PcacheMxDump = 9999; /* Max cache entries for pcacheDump() */
|
|
||||||
#define pcacheTrace(X) \
|
|
||||||
if (sqlite3PcacheTrace) { \
|
|
||||||
sqlite3DebugPrintf X; \
|
|
||||||
}
|
|
||||||
void pcacheDump(PCache *pCache) {
|
|
||||||
int N;
|
|
||||||
int i, j;
|
|
||||||
sqlite3_pcache_page *pLower;
|
|
||||||
PgHdr * pPg;
|
|
||||||
unsigned char * a;
|
|
||||||
|
|
||||||
if (sqlite3PcacheTrace < 2) return;
|
|
||||||
if (pCache->pCache == 0) return;
|
|
||||||
N = sqlite3PcachePagecount(pCache);
|
|
||||||
if (N > sqlite3PcacheMxDump) N = sqlite3PcacheMxDump;
|
|
||||||
for (i = 1; i <= N; i++) {
|
|
||||||
pLower = pcache2.xFetch(pCache->pCache, i, 0);
|
|
||||||
if (pLower == 0) continue;
|
|
||||||
pPg = (PgHdr *)pLower->pExtra;
|
|
||||||
printf("%3d: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags);
|
|
||||||
a = (unsigned char *)pLower->pBuf;
|
|
||||||
for (j = 0; j < 12; j++) printf("%02x", a[j]);
|
|
||||||
printf("\n");
|
|
||||||
if (pPg->pPage == 0) {
|
|
||||||
pcache2.xUnpin(pCache->pCache, pLower, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define pcacheTrace(X)
|
|
||||||
#define pcacheDump(X)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// /*
|
|
||||||
// ** Check invariants on a PgHdr entry. Return true if everything is OK.
|
|
||||||
// ** Return false if any invariant is violated.
|
|
||||||
// **
|
|
||||||
// ** This routine is for use inside of assert() statements only. For
|
|
||||||
// ** example:
|
|
||||||
// **
|
|
||||||
// ** assert( sqlite3PcachePageSanity(pPg) );
|
|
||||||
// */
|
|
||||||
// #ifdef SQLITE_DEBUG
|
|
||||||
// int sqlite3PcachePageSanity(PgHdr *pPg) {
|
|
||||||
// PCache *pCache;
|
|
||||||
// assert(pPg != 0);
|
|
||||||
// assert(pPg->pgno > 0 || pPg->pPager == 0); /* Page number is 1 or more */
|
|
||||||
// pCache = pPg->pCache;
|
|
||||||
// assert(pCache != 0); /* Every page has an associated PCache */
|
|
||||||
// if (pPg->flags & PGHDR_CLEAN) {
|
|
||||||
// assert((pPg->flags & PGHDR_DIRTY) == 0); /* Cannot be both CLEAN and DIRTY */
|
|
||||||
// assert(pCache->pDirty != pPg); /* CLEAN pages not on dirty list */
|
|
||||||
// assert(pCache->pDirtyTail != pPg);
|
|
||||||
// }
|
|
||||||
// /* WRITEABLE pages must also be DIRTY */
|
|
||||||
// if (pPg->flags & PGHDR_WRITEABLE) {
|
|
||||||
// assert(pPg->flags & PGHDR_DIRTY); /* WRITEABLE implies DIRTY */
|
|
||||||
// }
|
|
||||||
// /* NEED_SYNC can be set independently of WRITEABLE. This can happen,
|
|
||||||
// ** for example, when using the sqlite3PagerDontWrite() optimization:
|
|
||||||
// ** (1) Page X is journalled, and gets WRITEABLE and NEED_SEEK.
|
|
||||||
// ** (2) Page X moved to freelist, WRITEABLE is cleared
|
|
||||||
// ** (3) Page X reused, WRITEABLE is set again
|
|
||||||
// ** If NEED_SYNC had been cleared in step 2, then it would not be reset
|
|
||||||
// ** in step 3, and page might be written into the database without first
|
|
||||||
// ** syncing the rollback journal, which might cause corruption on a power
|
|
||||||
// ** loss.
|
|
||||||
// **
|
|
||||||
// ** Another example is when the database page size is smaller than the
|
|
||||||
// ** disk sector size. When any page of a sector is journalled, all pages
|
|
||||||
// ** in that sector are marked NEED_SYNC even if they are still CLEAN, just
|
|
||||||
// ** in case they are later modified, since all pages in the same sector
|
|
||||||
// ** must be journalled and synced before any of those pages can be safely
|
|
||||||
// ** written.
|
|
||||||
// */
|
|
||||||
// return 1;
|
|
||||||
// }
|
|
||||||
// #endif /* SQLITE_DEBUG */
|
|
||||||
|
|
||||||
/********************************** Linked List Management ********************/
|
|
||||||
|
|
||||||
/* Allowed values for second argument to pcacheManageDirtyList() */
|
|
||||||
#define PCACHE_DIRTYLIST_REMOVE 1 /* Remove pPage from dirty list */
|
|
||||||
#define PCACHE_DIRTYLIST_ADD 2 /* Add pPage to the dirty list */
|
|
||||||
#define PCACHE_DIRTYLIST_FRONT 3 /* Move pPage to the front of the list */
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Manage pPage's participation on the dirty list. Bits of the addRemove
|
|
||||||
** argument determines what operation to do. The 0x01 bit means first
|
|
||||||
** remove pPage from the dirty list. The 0x02 means add pPage back to
|
|
||||||
** the dirty list. Doing both moves pPage to the front of the dirty list.
|
|
||||||
*/
|
|
||||||
static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove) {
|
|
||||||
PCache *p = pPage->pCache;
|
|
||||||
|
|
||||||
pcacheTrace(("%p.DIRTYLIST.%s %d\n", p, addRemove == 1 ? "REMOVE" : addRemove == 2 ? "ADD" : "FRONT", pPage->pgno));
|
|
||||||
if (addRemove & PCACHE_DIRTYLIST_REMOVE) {
|
|
||||||
assert(pPage->pDirtyNext || pPage == p->pDirtyTail);
|
|
||||||
assert(pPage->pDirtyPrev || pPage == p->pDirty);
|
|
||||||
|
|
||||||
/* Update the PCache1.pSynced variable if necessary. */
|
|
||||||
if (p->pSynced == pPage) {
|
|
||||||
p->pSynced = pPage->pDirtyPrev;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pPage->pDirtyNext) {
|
|
||||||
pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev;
|
|
||||||
} else {
|
|
||||||
assert(pPage == p->pDirtyTail);
|
|
||||||
p->pDirtyTail = pPage->pDirtyPrev;
|
|
||||||
}
|
|
||||||
if (pPage->pDirtyPrev) {
|
|
||||||
pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext;
|
|
||||||
} else {
|
|
||||||
/* If there are now no dirty pages in the cache, set eCreate to 2.
|
|
||||||
** This is an optimization that allows sqlite3PcacheFetch() to skip
|
|
||||||
** searching for a dirty page to eject from the cache when it might
|
|
||||||
** otherwise have to. */
|
|
||||||
assert(pPage == p->pDirty);
|
|
||||||
p->pDirty = pPage->pDirtyNext;
|
|
||||||
assert(p->bPurgeable || p->eCreate == 2);
|
|
||||||
if (p->pDirty == 0) { /*OPTIMIZATION-IF-TRUE*/
|
|
||||||
assert(p->bPurgeable == 0 || p->eCreate == 1);
|
|
||||||
p->eCreate = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (addRemove & PCACHE_DIRTYLIST_ADD) {
|
|
||||||
pPage->pDirtyPrev = 0;
|
|
||||||
pPage->pDirtyNext = p->pDirty;
|
|
||||||
if (pPage->pDirtyNext) {
|
|
||||||
assert(pPage->pDirtyNext->pDirtyPrev == 0);
|
|
||||||
pPage->pDirtyNext->pDirtyPrev = pPage;
|
|
||||||
} else {
|
|
||||||
p->pDirtyTail = pPage;
|
|
||||||
if (p->bPurgeable) {
|
|
||||||
assert(p->eCreate == 2);
|
|
||||||
p->eCreate = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p->pDirty = pPage;
|
|
||||||
|
|
||||||
/* If pSynced is NULL and this page has a clear NEED_SYNC flag, set
|
|
||||||
** pSynced to point to it. Checking the NEED_SYNC flag is an
|
|
||||||
** optimization, as if pSynced points to a page with the NEED_SYNC
|
|
||||||
** flag set sqlite3PcacheFetchStress() searches through all newer
|
|
||||||
** entries of the dirty-list for a page with NEED_SYNC clear anyway. */
|
|
||||||
if (!p->pSynced && 0 == (pPage->flags & PGHDR_NEED_SYNC) /*OPTIMIZATION-IF-FALSE*/
|
|
||||||
) {
|
|
||||||
p->pSynced = pPage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pcacheDump(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Wrapper around the pluggable caches xUnpin method. If the cache is
|
|
||||||
** being used for an in-memory database, this function is a no-op.
|
|
||||||
*/
|
|
||||||
static void pcacheUnpin(PgHdr *p) {
|
|
||||||
if (p->pCache->bPurgeable) {
|
|
||||||
pcacheTrace(("%p.UNPIN %d\n", p->pCache, p->pgno));
|
|
||||||
pcache2.xUnpin(p->pCache->pCache, p->pPage, 0);
|
|
||||||
pcacheDump(p->pCache);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Compute the number of pages of cache requested. p->szCache is the
|
|
||||||
** cache size requested by the "PRAGMA cache_size" statement.
|
|
||||||
*/
|
|
||||||
static int numberOfCachePages(PCache *p) {
|
|
||||||
if (p->szCache >= 0) {
|
|
||||||
/* IMPLEMENTATION-OF: R-42059-47211 If the argument N is positive then the
|
|
||||||
** suggested cache size is set to N. */
|
|
||||||
return p->szCache;
|
|
||||||
} else {
|
|
||||||
i64 n;
|
|
||||||
/* IMPLEMANTATION-OF: R-59858-46238 If the argument N is negative, then the
|
|
||||||
** number of cache pages is adjusted to be a number of pages that would
|
|
||||||
** use approximately abs(N*1024) bytes of memory based on the current
|
|
||||||
** page size. */
|
|
||||||
n = ((-1024 * (i64)p->szCache) / (p->szPage + p->szExtra));
|
|
||||||
if (n > 1000000000) n = 1000000000;
|
|
||||||
return (int)n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*************************************************** General Interfaces ******
|
|
||||||
**
|
|
||||||
** Initialize and shutdown the page cache subsystem. Neither of these
|
|
||||||
** functions are threadsafe.
|
|
||||||
*/
|
|
||||||
int sqlite3PcacheInitialize(void) { return pcache2.xInit(pcache2.pArg); }
|
|
||||||
void sqlite3PcacheShutdown(void) {
|
|
||||||
if (pcache2.xShutdown) {
|
|
||||||
/* IMPLEMENTATION-OF: R-26000-56589 The xShutdown() method may be NULL. */
|
|
||||||
pcache2.xShutdown(pcache2.pArg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Return the size in bytes of a PCache object.
|
|
||||||
*/
|
|
||||||
int sqlite3PcacheSize(void) { return sizeof(PCache); }
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Create a new PCache object. Storage space to hold the object
|
|
||||||
** has already been allocated and is passed in as the p pointer.
|
|
||||||
** The caller discovers how much space needs to be allocated by
|
|
||||||
** calling sqlite3PcacheSize().
|
|
||||||
**
|
|
||||||
** szExtra is some extra space allocated for each page. The first
|
|
||||||
** 8 bytes of the extra space will be zeroed as the page is allocated,
|
|
||||||
** but remaining content will be uninitialized. Though it is opaque
|
|
||||||
** to this module, the extra space really ends up being the MemPage
|
|
||||||
** structure in the pager.
|
|
||||||
*/
|
|
||||||
int sqlite3PcacheOpen(int szPage, /* Size of every page */
|
|
||||||
int szExtra, /* Extra space associated with each page */
|
|
||||||
int bPurgeable, /* True if pages are on backing store */
|
|
||||||
int (*xStress)(void *, PgHdr *), /* Call to try to make pages clean */
|
|
||||||
void * pStress, /* Argument to xStress */
|
|
||||||
PCache *p /* Preallocated space for the PCache */
|
|
||||||
) {
|
|
||||||
memset(p, 0, sizeof(PCache));
|
|
||||||
p->szPage = 1;
|
|
||||||
p->szExtra = szExtra;
|
|
||||||
assert(szExtra >= 8); /* First 8 bytes will be zeroed */
|
|
||||||
p->bPurgeable = bPurgeable;
|
|
||||||
p->eCreate = 2;
|
|
||||||
p->xStress = xStress;
|
|
||||||
p->pStress = pStress;
|
|
||||||
p->szCache = 100;
|
|
||||||
p->szSpill = 1;
|
|
||||||
pcacheTrace(("%p.OPEN szPage %d bPurgeable %d\n", p, szPage, bPurgeable));
|
|
||||||
return sqlite3PcacheSetPageSize(p, szPage);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Change the page size for PCache object. The caller must ensure that there
|
|
||||||
** are no outstanding page references when this function is called.
|
|
||||||
*/
|
|
||||||
int sqlite3PcacheSetPageSize(PCache *pCache, int szPage) {
|
|
||||||
assert(pCache->nRefSum == 0 && pCache->pDirty == 0);
|
|
||||||
if (pCache->szPage) {
|
|
||||||
sqlite3_pcache *pNew;
|
|
||||||
pNew = pcache2.xCreate(szPage, pCache->szExtra + ROUND8(sizeof(PgHdr)), pCache->bPurgeable);
|
|
||||||
if (pNew == 0) return SQLITE_NOMEM;
|
|
||||||
pcache2.xCachesize(pNew, numberOfCachePages(pCache));
|
|
||||||
if (pCache->pCache) {
|
|
||||||
pcache2.xDestroy(pCache->pCache);
|
|
||||||
}
|
|
||||||
pCache->pCache = pNew;
|
|
||||||
pCache->szPage = szPage;
|
|
||||||
pcacheTrace(("%p.PAGESIZE %d\n", pCache, szPage));
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Try to obtain a page from the cache.
|
|
||||||
**
|
|
||||||
** This routine returns a pointer to an sqlite3_pcache_page object if
|
|
||||||
** such an object is already in cache, or if a new one is created.
|
|
||||||
** This routine returns a NULL pointer if the object was not in cache
|
|
||||||
** and could not be created.
|
|
||||||
**
|
|
||||||
** The createFlags should be 0 to check for existing pages and should
|
|
||||||
** be 3 (not 1, but 3) to try to create a new page.
|
|
||||||
**
|
|
||||||
** If the createFlag is 0, then NULL is always returned if the page
|
|
||||||
** is not already in the cache. If createFlag is 1, then a new page
|
|
||||||
** is created only if that can be done without spilling dirty pages
|
|
||||||
** and without exceeding the cache size limit.
|
|
||||||
**
|
|
||||||
** The caller needs to invoke sqlite3PcacheFetchFinish() to properly
|
|
||||||
** initialize the sqlite3_pcache_page object and convert it into a
|
|
||||||
** PgHdr object. The sqlite3PcacheFetch() and sqlite3PcacheFetchFinish()
|
|
||||||
** routines are split this way for performance reasons. When separated
|
|
||||||
** they can both (usually) operate without having to push values to
|
|
||||||
** the stack on entry and pop them back off on exit, which saves a
|
|
||||||
** lot of pushing and popping.
|
|
||||||
*/
|
|
||||||
sqlite3_pcache_page *sqlite3PcacheFetch(PCache *pCache, /* Obtain the page from this cache */
|
|
||||||
Pgno pgno, /* Page number to obtain */
|
|
||||||
int createFlag /* If true, create page if it does not exist already */
|
|
||||||
) {
|
|
||||||
int eCreate;
|
|
||||||
sqlite3_pcache_page *pRes;
|
|
||||||
|
|
||||||
assert(pCache != 0);
|
|
||||||
assert(pCache->pCache != 0);
|
|
||||||
assert(createFlag == 3 || createFlag == 0);
|
|
||||||
assert(pCache->eCreate == ((pCache->bPurgeable && pCache->pDirty) ? 1 : 2));
|
|
||||||
|
|
||||||
/* eCreate defines what to do if the page does not exist.
|
|
||||||
** 0 Do not allocate a new page. (createFlag==0)
|
|
||||||
** 1 Allocate a new page if doing so is inexpensive.
|
|
||||||
** (createFlag==1 AND bPurgeable AND pDirty)
|
|
||||||
** 2 Allocate a new page even it doing so is difficult.
|
|
||||||
** (createFlag==1 AND !(bPurgeable AND pDirty)
|
|
||||||
*/
|
|
||||||
eCreate = createFlag & pCache->eCreate;
|
|
||||||
assert(eCreate == 0 || eCreate == 1 || eCreate == 2);
|
|
||||||
assert(createFlag == 0 || pCache->eCreate == eCreate);
|
|
||||||
assert(createFlag == 0 || eCreate == 1 + (!pCache->bPurgeable || !pCache->pDirty));
|
|
||||||
pRes = pcache2.xFetch(pCache->pCache, pgno, eCreate);
|
|
||||||
pcacheTrace(("%p.FETCH %d%s (result: %p)\n", pCache, pgno, createFlag ? " create" : "", pRes));
|
|
||||||
return pRes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** If the sqlite3PcacheFetch() routine is unable to allocate a new
|
|
||||||
** page because no clean pages are available for reuse and the cache
|
|
||||||
** size limit has been reached, then this routine can be invoked to
|
|
||||||
** try harder to allocate a page. This routine might invoke the stress
|
|
||||||
** callback to spill dirty pages to the journal. It will then try to
|
|
||||||
** allocate the new page and will only fail to allocate a new page on
|
|
||||||
** an OOM error.
|
|
||||||
**
|
|
||||||
** This routine should be invoked only after sqlite3PcacheFetch() fails.
|
|
||||||
*/
|
|
||||||
int sqlite3PcacheFetchStress(PCache * pCache, /* Obtain the page from this cache */
|
|
||||||
Pgno pgno, /* Page number to obtain */
|
|
||||||
sqlite3_pcache_page **ppPage /* Write result here */
|
|
||||||
) {
|
|
||||||
PgHdr *pPg;
|
|
||||||
if (pCache->eCreate == 2) return 0;
|
|
||||||
|
|
||||||
if (sqlite3PcachePagecount(pCache) > pCache->szSpill) {
|
|
||||||
/* Find a dirty page to write-out and recycle. First try to find a
|
|
||||||
** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
|
|
||||||
** cleared), but if that is not possible settle for any other
|
|
||||||
** unreferenced dirty page.
|
|
||||||
**
|
|
||||||
** If the LRU page in the dirty list that has a clear PGHDR_NEED_SYNC
|
|
||||||
** flag is currently referenced, then the following may leave pSynced
|
|
||||||
** set incorrectly (pointing to other than the LRU page with NEED_SYNC
|
|
||||||
** cleared). This is Ok, as pSynced is just an optimization. */
|
|
||||||
for (pPg = pCache->pSynced; pPg && (pPg->nRef || (pPg->flags & PGHDR_NEED_SYNC)); pPg = pPg->pDirtyPrev)
|
|
||||||
;
|
|
||||||
pCache->pSynced = pPg;
|
|
||||||
if (!pPg) {
|
|
||||||
for (pPg = pCache->pDirtyTail; pPg && pPg->nRef; pPg = pPg->pDirtyPrev)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
if (pPg) {
|
|
||||||
int rc;
|
|
||||||
#ifdef SQLITE_LOG_CACHE_SPILL
|
|
||||||
sqlite3_log(SQLITE_FULL, "spill page %d making room for %d - cache used: %d/%d", pPg->pgno, pgno,
|
|
||||||
pcache2.xPagecount(pCache->pCache), numberOfCachePages(pCache));
|
|
||||||
#endif
|
|
||||||
pcacheTrace(("%p.SPILL %d\n", pCache, pPg->pgno));
|
|
||||||
rc = pCache->xStress(pCache->pStress, pPg);
|
|
||||||
pcacheDump(pCache);
|
|
||||||
if (rc != 0 && rc != SQLITE_BUSY) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*ppPage = pcache2.xFetch(pCache->pCache, pgno, 2);
|
|
||||||
return *ppPage == 0 ? SQLITE_NOMEM : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** This is a helper routine for sqlite3PcacheFetchFinish()
|
|
||||||
**
|
|
||||||
** In the uncommon case where the page being fetched has not been
|
|
||||||
** initialized, this routine is invoked to do the initialization.
|
|
||||||
** This routine is broken out into a separate function since it
|
|
||||||
** requires extra stack manipulation that can be avoided in the common
|
|
||||||
** case.
|
|
||||||
*/
|
|
||||||
static PgHdr *pcacheFetchFinishWithInit(PCache * pCache, /* Obtain the page from this cache */
|
|
||||||
Pgno pgno, /* Page number obtained */
|
|
||||||
sqlite3_pcache_page *pPage /* Page obtained by prior PcacheFetch() call */
|
|
||||||
) {
|
|
||||||
PgHdr *pPgHdr;
|
|
||||||
assert(pPage != 0);
|
|
||||||
pPgHdr = (PgHdr *)pPage->pExtra;
|
|
||||||
assert(pPgHdr->pPage == 0);
|
|
||||||
memset(&pPgHdr->pDirty, 0, sizeof(PgHdr) - offsetof(PgHdr, pDirty));
|
|
||||||
pPgHdr->pPage = pPage;
|
|
||||||
pPgHdr->pData = pPage->pBuf;
|
|
||||||
pPgHdr->pExtra = (void *)&pPgHdr[1];
|
|
||||||
memset(pPgHdr->pExtra, 0, 8);
|
|
||||||
pPgHdr->pCache = pCache;
|
|
||||||
pPgHdr->pgno = pgno;
|
|
||||||
pPgHdr->flags = PGHDR_CLEAN;
|
|
||||||
return sqlite3PcacheFetchFinish(pCache, pgno, pPage);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** This routine converts the sqlite3_pcache_page object returned by
|
|
||||||
** sqlite3PcacheFetch() into an initialized PgHdr object. This routine
|
|
||||||
** must be called after sqlite3PcacheFetch() in order to get a usable
|
|
||||||
** result.
|
|
||||||
*/
|
|
||||||
PgHdr *sqlite3PcacheFetchFinish(PCache * pCache, /* Obtain the page from this cache */
|
|
||||||
Pgno pgno, /* Page number obtained */
|
|
||||||
sqlite3_pcache_page *pPage /* Page obtained by prior PcacheFetch() call */
|
|
||||||
) {
|
|
||||||
PgHdr *pPgHdr;
|
|
||||||
|
|
||||||
assert(pPage != 0);
|
|
||||||
pPgHdr = (PgHdr *)pPage->pExtra;
|
|
||||||
|
|
||||||
if (!pPgHdr->pPage) {
|
|
||||||
return pcacheFetchFinishWithInit(pCache, pgno, pPage);
|
|
||||||
}
|
|
||||||
pCache->nRefSum++;
|
|
||||||
pPgHdr->nRef++;
|
|
||||||
// assert(sqlite3PcachePageSanity(pPgHdr));
|
|
||||||
return pPgHdr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Decrement the reference count on a page. If the page is clean and the
|
|
||||||
** reference count drops to 0, then it is made eligible for recycling.
|
|
||||||
*/
|
|
||||||
void sqlite3PcacheRelease(PgHdr *p) {
|
|
||||||
assert(p->nRef > 0);
|
|
||||||
p->pCache->nRefSum--;
|
|
||||||
if ((--p->nRef) == 0) {
|
|
||||||
if (p->flags & PGHDR_CLEAN) {
|
|
||||||
pcacheUnpin(p);
|
|
||||||
} else {
|
|
||||||
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Increase the reference count of a supplied page by 1.
|
|
||||||
*/
|
|
||||||
void sqlite3PcacheRef(PgHdr *p) {
|
|
||||||
assert(p->nRef > 0);
|
|
||||||
// assert(sqlite3PcachePageSanity(p));
|
|
||||||
p->nRef++;
|
|
||||||
p->pCache->nRefSum++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Drop a page from the cache. There must be exactly one reference to the
|
|
||||||
** page. This function deletes that reference, so after it returns the
|
|
||||||
** page pointed to by p is invalid.
|
|
||||||
*/
|
|
||||||
void sqlite3PcacheDrop(PgHdr *p) {
|
|
||||||
assert(p->nRef == 1);
|
|
||||||
// assert(sqlite3PcachePageSanity(p));
|
|
||||||
if (p->flags & PGHDR_DIRTY) {
|
|
||||||
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
|
|
||||||
}
|
|
||||||
p->pCache->nRefSum--;
|
|
||||||
pcache2.xUnpin(p->pCache->pCache, p->pPage, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Make sure the page is marked as dirty. If it isn't dirty already,
|
|
||||||
** make it so.
|
|
||||||
*/
|
|
||||||
void sqlite3PcacheMakeDirty(PgHdr *p) {
|
|
||||||
assert(p->nRef > 0);
|
|
||||||
// assert(sqlite3PcachePageSanity(p));
|
|
||||||
if (p->flags & (PGHDR_CLEAN | PGHDR_DONT_WRITE)) { /*OPTIMIZATION-IF-FALSE*/
|
|
||||||
p->flags &= ~PGHDR_DONT_WRITE;
|
|
||||||
if (p->flags & PGHDR_CLEAN) {
|
|
||||||
p->flags ^= (PGHDR_DIRTY | PGHDR_CLEAN);
|
|
||||||
pcacheTrace(("%p.DIRTY %d\n", p->pCache, p->pgno));
|
|
||||||
assert((p->flags & (PGHDR_DIRTY | PGHDR_CLEAN)) == PGHDR_DIRTY);
|
|
||||||
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD);
|
|
||||||
}
|
|
||||||
// assert(sqlite3PcachePageSanity(p));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Make sure the page is marked as clean. If it isn't clean already,
|
|
||||||
** make it so.
|
|
||||||
*/
|
|
||||||
void sqlite3PcacheMakeClean(PgHdr *p) {
|
|
||||||
// assert(sqlite3PcachePageSanity(p));
|
|
||||||
assert((p->flags & PGHDR_DIRTY) != 0);
|
|
||||||
assert((p->flags & PGHDR_CLEAN) == 0);
|
|
||||||
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
|
|
||||||
p->flags &= ~(PGHDR_DIRTY | PGHDR_NEED_SYNC | PGHDR_WRITEABLE);
|
|
||||||
p->flags |= PGHDR_CLEAN;
|
|
||||||
pcacheTrace(("%p.CLEAN %d\n", p->pCache, p->pgno));
|
|
||||||
// assert(sqlite3PcachePageSanity(p));
|
|
||||||
if (p->nRef == 0) {
|
|
||||||
pcacheUnpin(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Make every page in the cache clean.
|
|
||||||
*/
|
|
||||||
void sqlite3PcacheCleanAll(PCache *pCache) {
|
|
||||||
PgHdr *p;
|
|
||||||
pcacheTrace(("%p.CLEAN-ALL\n", pCache));
|
|
||||||
while ((p = pCache->pDirty) != 0) {
|
|
||||||
sqlite3PcacheMakeClean(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Clear the PGHDR_NEED_SYNC and PGHDR_WRITEABLE flag from all dirty pages.
|
|
||||||
*/
|
|
||||||
void sqlite3PcacheClearWritable(PCache *pCache) {
|
|
||||||
PgHdr *p;
|
|
||||||
pcacheTrace(("%p.CLEAR-WRITEABLE\n", pCache));
|
|
||||||
for (p = pCache->pDirty; p; p = p->pDirtyNext) {
|
|
||||||
p->flags &= ~(PGHDR_NEED_SYNC | PGHDR_WRITEABLE);
|
|
||||||
}
|
|
||||||
pCache->pSynced = pCache->pDirtyTail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Clear the PGHDR_NEED_SYNC flag from all dirty pages.
|
|
||||||
*/
|
|
||||||
void sqlite3PcacheClearSyncFlags(PCache *pCache) {
|
|
||||||
PgHdr *p;
|
|
||||||
for (p = pCache->pDirty; p; p = p->pDirtyNext) {
|
|
||||||
p->flags &= ~PGHDR_NEED_SYNC;
|
|
||||||
}
|
|
||||||
pCache->pSynced = pCache->pDirtyTail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Change the page number of page p to newPgno.
|
|
||||||
*/
|
|
||||||
void sqlite3PcacheMove(PgHdr *p, Pgno newPgno) {
|
|
||||||
PCache *pCache = p->pCache;
|
|
||||||
assert(p->nRef > 0);
|
|
||||||
assert(newPgno > 0);
|
|
||||||
// assert(sqlite3PcachePageSanity(p));
|
|
||||||
pcacheTrace(("%p.MOVE %d -> %d\n", pCache, p->pgno, newPgno));
|
|
||||||
pcache2.xRekey(pCache->pCache, p->pPage, p->pgno, newPgno);
|
|
||||||
p->pgno = newPgno;
|
|
||||||
if ((p->flags & PGHDR_DIRTY) && (p->flags & PGHDR_NEED_SYNC)) {
|
|
||||||
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Drop every cache entry whose page number is greater than "pgno". The
|
|
||||||
** caller must ensure that there are no outstanding references to any pages
|
|
||||||
** other than page 1 with a page number greater than pgno.
|
|
||||||
**
|
|
||||||
** If there is a reference to page 1 and the pgno parameter passed to this
|
|
||||||
** function is 0, then the data area associated with page 1 is zeroed, but
|
|
||||||
** the page object is not dropped.
|
|
||||||
*/
|
|
||||||
void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno) {
|
|
||||||
if (pCache->pCache) {
|
|
||||||
PgHdr *p;
|
|
||||||
PgHdr *pNext;
|
|
||||||
pcacheTrace(("%p.TRUNCATE %d\n", pCache, pgno));
|
|
||||||
for (p = pCache->pDirty; p; p = pNext) {
|
|
||||||
pNext = p->pDirtyNext;
|
|
||||||
/* This routine never gets call with a positive pgno except right
|
|
||||||
** after sqlite3PcacheCleanAll(). So if there are dirty pages,
|
|
||||||
** it must be that pgno==0.
|
|
||||||
*/
|
|
||||||
assert(p->pgno > 0);
|
|
||||||
if (p->pgno > pgno) {
|
|
||||||
assert(p->flags & PGHDR_DIRTY);
|
|
||||||
sqlite3PcacheMakeClean(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pgno == 0 && pCache->nRefSum) {
|
|
||||||
sqlite3_pcache_page *pPage1;
|
|
||||||
pPage1 = pcache2.xFetch(pCache->pCache, 1, 0);
|
|
||||||
if (pPage1) { /* Page 1 is always available in cache, because
|
|
||||||
** pCache->nRefSum>0 */
|
|
||||||
memset(pPage1->pBuf, 0, pCache->szPage);
|
|
||||||
pgno = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pcache2.xTruncate(pCache->pCache, pgno + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Close a cache.
|
|
||||||
*/
|
|
||||||
void sqlite3PcacheClose(PCache *pCache) {
|
|
||||||
assert(pCache->pCache != 0);
|
|
||||||
pcacheTrace(("%p.CLOSE\n", pCache));
|
|
||||||
pcache2.xDestroy(pCache->pCache);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Discard the contents of the cache.
|
|
||||||
*/
|
|
||||||
void sqlite3PcacheClear(PCache *pCache) { sqlite3PcacheTruncate(pCache, 0); }
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Merge two lists of pages connected by pDirty and in pgno order.
|
|
||||||
** Do not bother fixing the pDirtyPrev pointers.
|
|
||||||
*/
|
|
||||||
static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB) {
|
|
||||||
PgHdr result, *pTail;
|
|
||||||
pTail = &result;
|
|
||||||
assert(pA != 0 && pB != 0);
|
|
||||||
for (;;) {
|
|
||||||
if (pA->pgno < pB->pgno) {
|
|
||||||
pTail->pDirty = pA;
|
|
||||||
pTail = pA;
|
|
||||||
pA = pA->pDirty;
|
|
||||||
if (pA == 0) {
|
|
||||||
pTail->pDirty = pB;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pTail->pDirty = pB;
|
|
||||||
pTail = pB;
|
|
||||||
pB = pB->pDirty;
|
|
||||||
if (pB == 0) {
|
|
||||||
pTail->pDirty = pA;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result.pDirty;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Sort the list of pages in accending order by pgno. Pages are
|
|
||||||
** connected by pDirty pointers. The pDirtyPrev pointers are
|
|
||||||
** corrupted by this sort.
|
|
||||||
**
|
|
||||||
** Since there cannot be more than 2^31 distinct pages in a database,
|
|
||||||
** there cannot be more than 31 buckets required by the merge sorter.
|
|
||||||
** One extra bucket is added to catch overflow in case something
|
|
||||||
** ever changes to make the previous sentence incorrect.
|
|
||||||
*/
|
|
||||||
#define N_SORT_BUCKET 32
|
|
||||||
static PgHdr *pcacheSortDirtyList(PgHdr *pIn) {
|
|
||||||
PgHdr *a[N_SORT_BUCKET], *p;
|
|
||||||
int i;
|
|
||||||
memset(a, 0, sizeof(a));
|
|
||||||
while (pIn) {
|
|
||||||
p = pIn;
|
|
||||||
pIn = p->pDirty;
|
|
||||||
p->pDirty = 0;
|
|
||||||
for (i = 0; i < N_SORT_BUCKET - 1; i++) {
|
|
||||||
if (a[i] == 0) {
|
|
||||||
a[i] = p;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
p = pcacheMergeDirtyList(a[i], p);
|
|
||||||
a[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i == N_SORT_BUCKET - 1) {
|
|
||||||
/* To get here, there need to be 2^(N_SORT_BUCKET) elements in
|
|
||||||
** the input list. But that is impossible.
|
|
||||||
*/
|
|
||||||
a[i] = pcacheMergeDirtyList(a[i], p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p = a[0];
|
|
||||||
for (i = 1; i < N_SORT_BUCKET; i++) {
|
|
||||||
if (a[i] == 0) continue;
|
|
||||||
p = p ? pcacheMergeDirtyList(p, a[i]) : a[i];
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Return a list of all dirty pages in the cache, sorted by page number.
|
|
||||||
*/
|
|
||||||
PgHdr *sqlite3PcacheDirtyList(PCache *pCache) {
|
|
||||||
PgHdr *p;
|
|
||||||
for (p = pCache->pDirty; p; p = p->pDirtyNext) {
|
|
||||||
p->pDirty = p->pDirtyNext;
|
|
||||||
}
|
|
||||||
return pcacheSortDirtyList(pCache->pDirty);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Return the total number of references to all pages held by the cache.
|
|
||||||
**
|
|
||||||
** This is not the total number of pages referenced, but the sum of the
|
|
||||||
** reference count for all pages.
|
|
||||||
*/
|
|
||||||
int sqlite3PcacheRefCount(PCache *pCache) { return pCache->nRefSum; }
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Return the number of references to the page supplied as an argument.
|
|
||||||
*/
|
|
||||||
int sqlite3PcachePageRefcount(PgHdr *p) { return p->nRef; }
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Return the total number of pages in the cache.
|
|
||||||
*/
|
|
||||||
int sqlite3PcachePagecount(PCache *pCache) {
|
|
||||||
assert(pCache->pCache != 0);
|
|
||||||
return pcache2.xPagecount(pCache->pCache);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef SQLITE_TEST
|
|
||||||
/*
|
|
||||||
** Get the suggested cache-size value.
|
|
||||||
*/
|
|
||||||
int sqlite3PcacheGetCachesize(PCache *pCache) { return numberOfCachePages(pCache); }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Set the suggested cache-size value.
|
|
||||||
*/
|
|
||||||
void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage) {
|
|
||||||
assert(pCache->pCache != 0);
|
|
||||||
pCache->szCache = mxPage;
|
|
||||||
pcache2.xCachesize(pCache->pCache, numberOfCachePages(pCache));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Set the suggested cache-spill value. Make no changes if if the
|
|
||||||
** argument is zero. Return the effective cache-spill size, which will
|
|
||||||
** be the larger of the szSpill and szCache.
|
|
||||||
*/
|
|
||||||
int sqlite3PcacheSetSpillsize(PCache *p, int mxPage) {
|
|
||||||
int res;
|
|
||||||
assert(p->pCache != 0);
|
|
||||||
if (mxPage) {
|
|
||||||
if (mxPage < 0) {
|
|
||||||
mxPage = (int)((-1024 * (i64)mxPage) / (p->szPage + p->szExtra));
|
|
||||||
}
|
|
||||||
p->szSpill = mxPage;
|
|
||||||
}
|
|
||||||
res = numberOfCachePages(p);
|
|
||||||
if (res < p->szSpill) res = p->szSpill;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Free up as much memory as possible from the page cache.
|
|
||||||
*/
|
|
||||||
void sqlite3PcacheShrink(PCache *pCache) {
|
|
||||||
assert(pCache->pCache != 0);
|
|
||||||
pcache2.xShrink(pCache->pCache);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Return the size of the header added by this middleware layer
|
|
||||||
** in the page-cache hierarchy.
|
|
||||||
*/
|
|
||||||
int sqlite3HeaderSizePcache(void) { return ROUND8(sizeof(PgHdr)); }
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Return the number of dirty pages currently in the cache, as a percentage
|
|
||||||
** of the configured cache size.
|
|
||||||
*/
|
|
||||||
int sqlite3PCachePercentDirty(PCache *pCache) {
|
|
||||||
PgHdr *pDirty;
|
|
||||||
int nDirty = 0;
|
|
||||||
int nCache = numberOfCachePages(pCache);
|
|
||||||
for (pDirty = pCache->pDirty; pDirty; pDirty = pDirty->pDirtyNext) nDirty++;
|
|
||||||
return nCache ? (int)(((i64)nDirty * 100) / nCache) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef SQLITE_DIRECT_OVERFLOW_READ
|
|
||||||
/*
|
|
||||||
** Return true if there are one or more dirty pages in the cache. Else false.
|
|
||||||
*/
|
|
||||||
int sqlite3PCacheIsDirty(PCache *pCache) { return (pCache->pDirty != 0); }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
|
|
||||||
/*
|
|
||||||
** For all dirty pages currently in the cache, invoke the specified
|
|
||||||
** callback. This is only used if the SQLITE_CHECK_PAGES macro is
|
|
||||||
** defined.
|
|
||||||
*/
|
|
||||||
void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)) {
|
|
||||||
PgHdr *pDirty;
|
|
||||||
for (pDirty = pCache->pDirty; pDirty; pDirty = pDirty->pDirtyNext) {
|
|
||||||
xIter(pDirty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,412 +0,0 @@
|
||||||
/*
|
|
||||||
** 2001 September 15
|
|
||||||
**
|
|
||||||
** 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 header file defines the interface that the sqlite B-Tree file
|
|
||||||
** subsystem. See comments in the source code for a detailed description
|
|
||||||
** of what each interface routine does.
|
|
||||||
*/
|
|
||||||
#ifndef SQLITE_BTREE_H
|
|
||||||
#define SQLITE_BTREE_H
|
|
||||||
|
|
||||||
/* TODO: This definition is just included so other modules compile. It
|
|
||||||
** needs to be revisited.
|
|
||||||
*/
|
|
||||||
#define SQLITE_N_BTREE_META 16
|
|
||||||
|
|
||||||
/*
|
|
||||||
** If defined as non-zero, auto-vacuum is enabled by default. Otherwise
|
|
||||||
** it must be turned on for each database using "PRAGMA auto_vacuum = 1".
|
|
||||||
*/
|
|
||||||
#ifndef SQLITE_DEFAULT_AUTOVACUUM
|
|
||||||
#define SQLITE_DEFAULT_AUTOVACUUM 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define BTREE_AUTOVACUUM_NONE 0 /* Do not do auto-vacuum */
|
|
||||||
#define BTREE_AUTOVACUUM_FULL 1 /* Do full auto-vacuum */
|
|
||||||
#define BTREE_AUTOVACUUM_INCR 2 /* Incremental vacuum */
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Forward declarations of structure
|
|
||||||
*/
|
|
||||||
typedef struct Btree Btree;
|
|
||||||
typedef struct BtCursor BtCursor;
|
|
||||||
typedef struct BtShared BtShared;
|
|
||||||
typedef struct BtreePayload BtreePayload;
|
|
||||||
|
|
||||||
|
|
||||||
int sqlite3BtreeOpen(
|
|
||||||
sqlite3_vfs *pVfs, /* VFS to use with this b-tree */
|
|
||||||
const char *zFilename, /* Name of database file to open */
|
|
||||||
sqlite3 *db, /* Associated database connection */
|
|
||||||
Btree **ppBtree, /* Return open Btree* here */
|
|
||||||
int flags, /* Flags */
|
|
||||||
int vfsFlags /* Flags passed through to VFS open */
|
|
||||||
);
|
|
||||||
|
|
||||||
/* The flags parameter to sqlite3BtreeOpen can be the bitwise or of the
|
|
||||||
** following values.
|
|
||||||
**
|
|
||||||
** NOTE: These values must match the corresponding PAGER_ values in
|
|
||||||
** pager.h.
|
|
||||||
*/
|
|
||||||
#define BTREE_OMIT_JOURNAL 1 /* Do not create or use a rollback journal */
|
|
||||||
#define BTREE_MEMORY 2 /* This is an in-memory DB */
|
|
||||||
#define BTREE_SINGLE 4 /* The file contains at most 1 b-tree */
|
|
||||||
#define BTREE_UNORDERED 8 /* Use of a hash implementation is OK */
|
|
||||||
|
|
||||||
int sqlite3BtreeClose(Btree*);
|
|
||||||
int sqlite3BtreeSetCacheSize(Btree*,int);
|
|
||||||
int sqlite3BtreeSetSpillSize(Btree*,int);
|
|
||||||
#if SQLITE_MAX_MMAP_SIZE>0
|
|
||||||
int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
|
|
||||||
#endif
|
|
||||||
int sqlite3BtreeSetPagerFlags(Btree*,unsigned);
|
|
||||||
int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
|
|
||||||
int sqlite3BtreeGetPageSize(Btree*);
|
|
||||||
Pgno sqlite3BtreeMaxPageCount(Btree*,Pgno);
|
|
||||||
Pgno sqlite3BtreeLastPage(Btree*);
|
|
||||||
int sqlite3BtreeSecureDelete(Btree*,int);
|
|
||||||
int sqlite3BtreeGetRequestedReserve(Btree*);
|
|
||||||
int sqlite3BtreeGetReserveNoMutex(Btree *p);
|
|
||||||
int sqlite3BtreeSetAutoVacuum(Btree *, int);
|
|
||||||
int sqlite3BtreeGetAutoVacuum(Btree *);
|
|
||||||
int sqlite3BtreeBeginTrans(Btree*,int,int*);
|
|
||||||
int sqlite3BtreeCommitPhaseOne(Btree*, const char*);
|
|
||||||
int sqlite3BtreeCommitPhaseTwo(Btree*, int);
|
|
||||||
int sqlite3BtreeCommit(Btree*);
|
|
||||||
int sqlite3BtreeRollback(Btree*,int,int);
|
|
||||||
int sqlite3BtreeBeginStmt(Btree*,int);
|
|
||||||
int sqlite3BtreeCreateTable(Btree*, Pgno*, int flags);
|
|
||||||
int sqlite3BtreeTxnState(Btree*);
|
|
||||||
int sqlite3BtreeIsInBackup(Btree*);
|
|
||||||
|
|
||||||
void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
|
|
||||||
int sqlite3BtreeSchemaLocked(Btree *pBtree);
|
|
||||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
|
||||||
int sqlite3BtreeLockTable(Btree *pBtree, int iTab, u8 isWriteLock);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Savepoints are named, nestable SQL transactions mostly implemented */
|
|
||||||
/* in vdbe.c and pager.c See https://sqlite.org/lang_savepoint.html */
|
|
||||||
int sqlite3BtreeSavepoint(Btree *, int, int);
|
|
||||||
|
|
||||||
/* "Checkpoint" only refers to WAL. See https://sqlite.org/wal.html#ckpt */
|
|
||||||
#ifndef SQLITE_OMIT_WAL
|
|
||||||
int sqlite3BtreeCheckpoint(Btree*, int, int *, int *);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const char *sqlite3BtreeGetFilename(Btree *);
|
|
||||||
const char *sqlite3BtreeGetJournalname(Btree *);
|
|
||||||
int sqlite3BtreeCopyFile(Btree *, Btree *);
|
|
||||||
|
|
||||||
int sqlite3BtreeIncrVacuum(Btree *);
|
|
||||||
|
|
||||||
/* The flags parameter to sqlite3BtreeCreateTable can be the bitwise OR
|
|
||||||
** of the flags shown below.
|
|
||||||
**
|
|
||||||
** Every SQLite table must have either BTREE_INTKEY or BTREE_BLOBKEY set.
|
|
||||||
** With BTREE_INTKEY, the table key is a 64-bit integer and arbitrary data
|
|
||||||
** is stored in the leaves. (BTREE_INTKEY is used for SQL tables.) With
|
|
||||||
** BTREE_BLOBKEY, the key is an arbitrary BLOB and no content is stored
|
|
||||||
** anywhere - the key is the content. (BTREE_BLOBKEY is used for SQL
|
|
||||||
** indices.)
|
|
||||||
*/
|
|
||||||
#define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */
|
|
||||||
#define BTREE_BLOBKEY 2 /* Table has keys only - no data */
|
|
||||||
|
|
||||||
int sqlite3BtreeDropTable(Btree*, int, int*);
|
|
||||||
int sqlite3BtreeClearTable(Btree*, int, i64*);
|
|
||||||
int sqlite3BtreeClearTableOfCursor(BtCursor*);
|
|
||||||
int sqlite3BtreeTripAllCursors(Btree*, int, int);
|
|
||||||
|
|
||||||
void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue);
|
|
||||||
int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
|
|
||||||
|
|
||||||
int sqlite3BtreeNewDb(Btree *p);
|
|
||||||
|
|
||||||
/*
|
|
||||||
** The second parameter to sqlite3BtreeGetMeta or sqlite3BtreeUpdateMeta
|
|
||||||
** should be one of the following values. The integer values are assigned
|
|
||||||
** to constants so that the offset of the corresponding field in an
|
|
||||||
** SQLite database header may be found using the following formula:
|
|
||||||
**
|
|
||||||
** offset = 36 + (idx * 4)
|
|
||||||
**
|
|
||||||
** For example, the free-page-count field is located at byte offset 36 of
|
|
||||||
** the database file header. The incr-vacuum-flag field is located at
|
|
||||||
** byte offset 64 (== 36+4*7).
|
|
||||||
**
|
|
||||||
** The BTREE_DATA_VERSION value is not really a value stored in the header.
|
|
||||||
** It is a read-only number computed by the pager. But we merge it with
|
|
||||||
** the header value access routines since its access pattern is the same.
|
|
||||||
** Call it a "virtual meta value".
|
|
||||||
*/
|
|
||||||
#define BTREE_FREE_PAGE_COUNT 0
|
|
||||||
#define BTREE_SCHEMA_VERSION 1
|
|
||||||
#define BTREE_FILE_FORMAT 2
|
|
||||||
#define BTREE_DEFAULT_CACHE_SIZE 3
|
|
||||||
#define BTREE_LARGEST_ROOT_PAGE 4
|
|
||||||
#define BTREE_TEXT_ENCODING 5
|
|
||||||
#define BTREE_USER_VERSION 6
|
|
||||||
#define BTREE_INCR_VACUUM 7
|
|
||||||
#define BTREE_APPLICATION_ID 8
|
|
||||||
#define BTREE_DATA_VERSION 15 /* A virtual meta-value */
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Kinds of hints that can be passed into the sqlite3BtreeCursorHint()
|
|
||||||
** interface.
|
|
||||||
**
|
|
||||||
** BTREE_HINT_RANGE (arguments: Expr*, Mem*)
|
|
||||||
**
|
|
||||||
** The first argument is an Expr* (which is guaranteed to be constant for
|
|
||||||
** the lifetime of the cursor) that defines constraints on which rows
|
|
||||||
** might be fetched with this cursor. The Expr* tree may contain
|
|
||||||
** TK_REGISTER nodes that refer to values stored in the array of registers
|
|
||||||
** passed as the second parameter. In other words, if Expr.op==TK_REGISTER
|
|
||||||
** then the value of the node is the value in Mem[pExpr.iTable]. Any
|
|
||||||
** TK_COLUMN node in the expression tree refers to the Expr.iColumn-th
|
|
||||||
** column of the b-tree of the cursor. The Expr tree will not contain
|
|
||||||
** any function calls nor subqueries nor references to b-trees other than
|
|
||||||
** the cursor being hinted.
|
|
||||||
**
|
|
||||||
** The design of the _RANGE hint is aid b-tree implementations that try
|
|
||||||
** to prefetch content from remote machines - to provide those
|
|
||||||
** implementations with limits on what needs to be prefetched and thereby
|
|
||||||
** reduce network bandwidth.
|
|
||||||
**
|
|
||||||
** Note that BTREE_HINT_FLAGS with BTREE_BULKLOAD is the only hint used by
|
|
||||||
** standard SQLite. The other hints are provided for extentions that use
|
|
||||||
** the SQLite parser and code generator but substitute their own storage
|
|
||||||
** engine.
|
|
||||||
*/
|
|
||||||
#define BTREE_HINT_RANGE 0 /* Range constraints on queries */
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Values that may be OR'd together to form the argument to the
|
|
||||||
** BTREE_HINT_FLAGS hint for sqlite3BtreeCursorHint():
|
|
||||||
**
|
|
||||||
** The BTREE_BULKLOAD flag is set on index cursors when the index is going
|
|
||||||
** to be filled with content that is already in sorted order.
|
|
||||||
**
|
|
||||||
** The BTREE_SEEK_EQ flag is set on cursors that will get OP_SeekGE or
|
|
||||||
** OP_SeekLE opcodes for a range search, but where the range of entries
|
|
||||||
** selected will all have the same key. In other words, the cursor will
|
|
||||||
** be used only for equality key searches.
|
|
||||||
**
|
|
||||||
*/
|
|
||||||
#define BTREE_BULKLOAD 0x00000001 /* Used to full index in sorted order */
|
|
||||||
#define BTREE_SEEK_EQ 0x00000002 /* EQ seeks only - no range seeks */
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Flags passed as the third argument to sqlite3BtreeCursor().
|
|
||||||
**
|
|
||||||
** For read-only cursors the wrFlag argument is always zero. For read-write
|
|
||||||
** cursors it may be set to either (BTREE_WRCSR|BTREE_FORDELETE) or just
|
|
||||||
** (BTREE_WRCSR). If the BTREE_FORDELETE bit is set, then the cursor will
|
|
||||||
** only be used by SQLite for the following:
|
|
||||||
**
|
|
||||||
** * to seek to and then delete specific entries, and/or
|
|
||||||
**
|
|
||||||
** * to read values that will be used to create keys that other
|
|
||||||
** BTREE_FORDELETE cursors will seek to and delete.
|
|
||||||
**
|
|
||||||
** The BTREE_FORDELETE flag is an optimization hint. It is not used by
|
|
||||||
** by this, the native b-tree engine of SQLite, but it is available to
|
|
||||||
** alternative storage engines that might be substituted in place of this
|
|
||||||
** b-tree system. For alternative storage engines in which a delete of
|
|
||||||
** the main table row automatically deletes corresponding index rows,
|
|
||||||
** the FORDELETE flag hint allows those alternative storage engines to
|
|
||||||
** skip a lot of work. Namely: FORDELETE cursors may treat all SEEK
|
|
||||||
** and DELETE operations as no-ops, and any READ operation against a
|
|
||||||
** FORDELETE cursor may return a null row: 0x01 0x00.
|
|
||||||
*/
|
|
||||||
#define BTREE_WRCSR 0x00000004 /* read-write cursor */
|
|
||||||
#define BTREE_FORDELETE 0x00000008 /* Cursor is for seek/delete only */
|
|
||||||
|
|
||||||
int sqlite3BtreeCursor(
|
|
||||||
Btree*, /* BTree containing table to open */
|
|
||||||
Pgno iTable, /* Index of root page */
|
|
||||||
int wrFlag, /* 1 for writing. 0 for read-only */
|
|
||||||
struct KeyInfo*, /* First argument to compare function */
|
|
||||||
BtCursor *pCursor /* Space to write cursor structure */
|
|
||||||
);
|
|
||||||
BtCursor *sqlite3BtreeFakeValidCursor(void);
|
|
||||||
int sqlite3BtreeCursorSize(void);
|
|
||||||
void sqlite3BtreeCursorZero(BtCursor*);
|
|
||||||
void sqlite3BtreeCursorHintFlags(BtCursor*, unsigned);
|
|
||||||
#ifdef SQLITE_ENABLE_CURSOR_HINTS
|
|
||||||
void sqlite3BtreeCursorHint(BtCursor*, int, ...);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int sqlite3BtreeCloseCursor(BtCursor*);
|
|
||||||
int sqlite3BtreeTableMoveto(
|
|
||||||
BtCursor*,
|
|
||||||
i64 intKey,
|
|
||||||
int bias,
|
|
||||||
int *pRes
|
|
||||||
);
|
|
||||||
int sqlite3BtreeIndexMoveto(
|
|
||||||
BtCursor*,
|
|
||||||
UnpackedRecord *pUnKey,
|
|
||||||
int *pRes
|
|
||||||
);
|
|
||||||
int sqlite3BtreeCursorHasMoved(BtCursor*);
|
|
||||||
int sqlite3BtreeCursorRestore(BtCursor*, int*);
|
|
||||||
int sqlite3BtreeDelete(BtCursor*, u8 flags);
|
|
||||||
|
|
||||||
/* Allowed flags for sqlite3BtreeDelete() and sqlite3BtreeInsert() */
|
|
||||||
#define BTREE_SAVEPOSITION 0x02 /* Leave cursor pointing at NEXT or PREV */
|
|
||||||
#define BTREE_AUXDELETE 0x04 /* not the primary delete operation */
|
|
||||||
#define BTREE_APPEND 0x08 /* Insert is likely an append */
|
|
||||||
#define BTREE_PREFORMAT 0x80 /* Inserted data is a preformated cell */
|
|
||||||
|
|
||||||
/* An instance of the BtreePayload object describes the content of a single
|
|
||||||
** entry in either an index or table btree.
|
|
||||||
**
|
|
||||||
** Index btrees (used for indexes and also WITHOUT ROWID tables) contain
|
|
||||||
** an arbitrary key and no data. These btrees have pKey,nKey set to the
|
|
||||||
** key and the pData,nData,nZero fields are uninitialized. The aMem,nMem
|
|
||||||
** fields give an array of Mem objects that are a decomposition of the key.
|
|
||||||
** The nMem field might be zero, indicating that no decomposition is available.
|
|
||||||
**
|
|
||||||
** Table btrees (used for rowid tables) contain an integer rowid used as
|
|
||||||
** the key and passed in the nKey field. The pKey field is zero.
|
|
||||||
** pData,nData hold the content of the new entry. nZero extra zero bytes
|
|
||||||
** are appended to the end of the content when constructing the entry.
|
|
||||||
** The aMem,nMem fields are uninitialized for table btrees.
|
|
||||||
**
|
|
||||||
** Field usage summary:
|
|
||||||
**
|
|
||||||
** Table BTrees Index Btrees
|
|
||||||
**
|
|
||||||
** pKey always NULL encoded key
|
|
||||||
** nKey the ROWID length of pKey
|
|
||||||
** pData data not used
|
|
||||||
** aMem not used decomposed key value
|
|
||||||
** nMem not used entries in aMem
|
|
||||||
** nData length of pData not used
|
|
||||||
** nZero extra zeros after pData not used
|
|
||||||
**
|
|
||||||
** This object is used to pass information into sqlite3BtreeInsert(). The
|
|
||||||
** same information used to be passed as five separate parameters. But placing
|
|
||||||
** the information into this object helps to keep the interface more
|
|
||||||
** organized and understandable, and it also helps the resulting code to
|
|
||||||
** run a little faster by using fewer registers for parameter passing.
|
|
||||||
*/
|
|
||||||
struct BtreePayload {
|
|
||||||
const void *pKey; /* Key content for indexes. NULL for tables */
|
|
||||||
sqlite3_int64 nKey; /* Size of pKey for indexes. PRIMARY KEY for tabs */
|
|
||||||
const void *pData; /* Data for tables. */
|
|
||||||
sqlite3_value *aMem; /* First of nMem value in the unpacked pKey */
|
|
||||||
u16 nMem; /* Number of aMem[] value. Might be zero */
|
|
||||||
int nData; /* Size of pData. 0 if none. */
|
|
||||||
int nZero; /* Extra zero data appended after pData,nData */
|
|
||||||
};
|
|
||||||
|
|
||||||
int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload,
|
|
||||||
int flags, int seekResult);
|
|
||||||
int sqlite3BtreeFirst(BtCursor*, int *pRes);
|
|
||||||
int sqlite3BtreeLast(BtCursor*, int *pRes);
|
|
||||||
int sqlite3BtreeNext(BtCursor*, int flags);
|
|
||||||
int sqlite3BtreeEof(BtCursor*);
|
|
||||||
int sqlite3BtreePrevious(BtCursor*, int flags);
|
|
||||||
i64 sqlite3BtreeIntegerKey(BtCursor*);
|
|
||||||
void sqlite3BtreeCursorPin(BtCursor*);
|
|
||||||
void sqlite3BtreeCursorUnpin(BtCursor*);
|
|
||||||
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
|
|
||||||
i64 sqlite3BtreeOffset(BtCursor*);
|
|
||||||
#endif
|
|
||||||
int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*);
|
|
||||||
const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
|
|
||||||
u32 sqlite3BtreePayloadSize(BtCursor*);
|
|
||||||
sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor*);
|
|
||||||
|
|
||||||
char *sqlite3BtreeIntegrityCheck(sqlite3*,Btree*,Pgno*aRoot,int nRoot,int,int*);
|
|
||||||
struct Pager *sqlite3BtreePager(Btree*);
|
|
||||||
i64 sqlite3BtreeRowCountEst(BtCursor*);
|
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_INCRBLOB
|
|
||||||
int sqlite3BtreePayloadChecked(BtCursor*, u32 offset, u32 amt, void*);
|
|
||||||
int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
|
|
||||||
void sqlite3BtreeIncrblobCursor(BtCursor *);
|
|
||||||
#endif
|
|
||||||
void sqlite3BtreeClearCursor(BtCursor *);
|
|
||||||
int sqlite3BtreeSetVersion(Btree *pBt, int iVersion);
|
|
||||||
int sqlite3BtreeCursorHasHint(BtCursor*, unsigned int mask);
|
|
||||||
int sqlite3BtreeIsReadonly(Btree *pBt);
|
|
||||||
int sqlite3HeaderSizeBtree(void);
|
|
||||||
|
|
||||||
#ifdef SQLITE_DEBUG
|
|
||||||
sqlite3_uint64 sqlite3BtreeSeekCount(Btree*);
|
|
||||||
#else
|
|
||||||
# define sqlite3BtreeSeekCount(X) 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
int sqlite3BtreeCursorIsValid(BtCursor*);
|
|
||||||
#endif
|
|
||||||
int sqlite3BtreeCursorIsValidNN(BtCursor*);
|
|
||||||
|
|
||||||
int sqlite3BtreeCount(sqlite3*, BtCursor*, i64*);
|
|
||||||
|
|
||||||
#ifdef SQLITE_TEST
|
|
||||||
int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
|
|
||||||
void sqlite3BtreeCursorList(Btree*);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_WAL
|
|
||||||
int sqlite3BtreeCheckpoint(Btree*, int, int *, int *);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int sqlite3BtreeTransferRow(BtCursor*, BtCursor*, i64);
|
|
||||||
|
|
||||||
/*
|
|
||||||
** If we are not using shared cache, then there is no need to
|
|
||||||
** use mutexes to access the BtShared structures. So make the
|
|
||||||
** Enter and Leave procedures no-ops.
|
|
||||||
*/
|
|
||||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
|
||||||
void sqlite3BtreeEnter(Btree*);
|
|
||||||
void sqlite3BtreeEnterAll(sqlite3*);
|
|
||||||
int sqlite3BtreeSharable(Btree*);
|
|
||||||
void sqlite3BtreeEnterCursor(BtCursor*);
|
|
||||||
int sqlite3BtreeConnectionCount(Btree*);
|
|
||||||
#else
|
|
||||||
# define sqlite3BtreeEnter(X)
|
|
||||||
# define sqlite3BtreeEnterAll(X)
|
|
||||||
# define sqlite3BtreeSharable(X) 0
|
|
||||||
# define sqlite3BtreeEnterCursor(X)
|
|
||||||
# define sqlite3BtreeConnectionCount(X) 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE
|
|
||||||
void sqlite3BtreeLeave(Btree*);
|
|
||||||
void sqlite3BtreeLeaveCursor(BtCursor*);
|
|
||||||
void sqlite3BtreeLeaveAll(sqlite3*);
|
|
||||||
#ifndef NDEBUG
|
|
||||||
/* These routines are used inside assert() statements only. */
|
|
||||||
int sqlite3BtreeHoldsMutex(Btree*);
|
|
||||||
int sqlite3BtreeHoldsAllMutexes(sqlite3*);
|
|
||||||
int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*);
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
|
|
||||||
# define sqlite3BtreeLeave(X)
|
|
||||||
# define sqlite3BtreeLeaveCursor(X)
|
|
||||||
# define sqlite3BtreeLeaveAll(X)
|
|
||||||
|
|
||||||
# define sqlite3BtreeHoldsMutex(X) 1
|
|
||||||
# define sqlite3BtreeHoldsAllMutexes(X) 1
|
|
||||||
# define sqlite3SchemaMutexHeld(X,Y,Z) 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* SQLITE_BTREE_H */
|
|
|
@ -1,729 +0,0 @@
|
||||||
/*
|
|
||||||
** 2004 April 6
|
|
||||||
**
|
|
||||||
** 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 an external (disk-based) database using BTrees.
|
|
||||||
** For a detailed discussion of BTrees, refer to
|
|
||||||
**
|
|
||||||
** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
|
|
||||||
** "Sorting And Searching", pages 473-480. Addison-Wesley
|
|
||||||
** Publishing Company, Reading, Massachusetts.
|
|
||||||
**
|
|
||||||
** The basic idea is that each page of the file contains N database
|
|
||||||
** entries and N+1 pointers to subpages.
|
|
||||||
**
|
|
||||||
** ----------------------------------------------------------------
|
|
||||||
** | Ptr(0) | Key(0) | Ptr(1) | Key(1) | ... | Key(N-1) | Ptr(N) |
|
|
||||||
** ----------------------------------------------------------------
|
|
||||||
**
|
|
||||||
** All of the keys on the page that Ptr(0) points to have values less
|
|
||||||
** than Key(0). All of the keys on page Ptr(1) and its subpages have
|
|
||||||
** values greater than Key(0) and less than Key(1). All of the keys
|
|
||||||
** on Ptr(N) and its subpages have values greater than Key(N-1). And
|
|
||||||
** so forth.
|
|
||||||
**
|
|
||||||
** Finding a particular key requires reading O(log(M)) pages from the
|
|
||||||
** disk where M is the number of entries in the tree.
|
|
||||||
**
|
|
||||||
** In this implementation, a single file can hold one or more separate
|
|
||||||
** BTrees. Each BTree is identified by the index of its root page. The
|
|
||||||
** key and data for any entry are combined to form the "payload". A
|
|
||||||
** fixed amount of payload can be carried directly on the database
|
|
||||||
** page. If the payload is larger than the preset amount then surplus
|
|
||||||
** bytes are stored on overflow pages. The payload for an entry
|
|
||||||
** and the preceding pointer are combined to form a "Cell". Each
|
|
||||||
** page has a small header which contains the Ptr(N) pointer and other
|
|
||||||
** information such as the size of key and data.
|
|
||||||
**
|
|
||||||
** FORMAT DETAILS
|
|
||||||
**
|
|
||||||
** The file is divided into pages. The first page is called page 1,
|
|
||||||
** the second is page 2, and so forth. A page number of zero indicates
|
|
||||||
** "no such page". The page size can be any power of 2 between 512 and 65536.
|
|
||||||
** Each page can be either a btree page, a freelist page, an overflow
|
|
||||||
** page, or a pointer-map page.
|
|
||||||
**
|
|
||||||
** The first page is always a btree page. The first 100 bytes of the first
|
|
||||||
** page contain a special header (the "file header") that describes the file.
|
|
||||||
** The format of the file header is as follows:
|
|
||||||
**
|
|
||||||
** OFFSET SIZE DESCRIPTION
|
|
||||||
** 0 16 Header string: "SQLite format 3\000"
|
|
||||||
** 16 2 Page size in bytes. (1 means 65536)
|
|
||||||
** 18 1 File format write version
|
|
||||||
** 19 1 File format read version
|
|
||||||
** 20 1 Bytes of unused space at the end of each page
|
|
||||||
** 21 1 Max embedded payload fraction (must be 64)
|
|
||||||
** 22 1 Min embedded payload fraction (must be 32)
|
|
||||||
** 23 1 Min leaf payload fraction (must be 32)
|
|
||||||
** 24 4 File change counter
|
|
||||||
** 28 4 Reserved for future use
|
|
||||||
** 32 4 First freelist page
|
|
||||||
** 36 4 Number of freelist pages in the file
|
|
||||||
** 40 60 15 4-byte meta values passed to higher layers
|
|
||||||
**
|
|
||||||
** 40 4 Schema cookie
|
|
||||||
** 44 4 File format of schema layer
|
|
||||||
** 48 4 Size of page cache
|
|
||||||
** 52 4 Largest root-page (auto/incr_vacuum)
|
|
||||||
** 56 4 1=UTF-8 2=UTF16le 3=UTF16be
|
|
||||||
** 60 4 User version
|
|
||||||
** 64 4 Incremental vacuum mode
|
|
||||||
** 68 4 Application-ID
|
|
||||||
** 72 20 unused
|
|
||||||
** 92 4 The version-valid-for number
|
|
||||||
** 96 4 SQLITE_VERSION_NUMBER
|
|
||||||
**
|
|
||||||
** All of the integer values are big-endian (most significant byte first).
|
|
||||||
**
|
|
||||||
** The file change counter is incremented when the database is changed
|
|
||||||
** This counter allows other processes to know when the file has changed
|
|
||||||
** and thus when they need to flush their cache.
|
|
||||||
**
|
|
||||||
** The max embedded payload fraction is the amount of the total usable
|
|
||||||
** space in a page that can be consumed by a single cell for standard
|
|
||||||
** B-tree (non-LEAFDATA) tables. A value of 255 means 100%. The default
|
|
||||||
** is to limit the maximum cell size so that at least 4 cells will fit
|
|
||||||
** on one page. Thus the default max embedded payload fraction is 64.
|
|
||||||
**
|
|
||||||
** If the payload for a cell is larger than the max payload, then extra
|
|
||||||
** payload is spilled to overflow pages. Once an overflow page is allocated,
|
|
||||||
** as many bytes as possible are moved into the overflow pages without letting
|
|
||||||
** the cell size drop below the min embedded payload fraction.
|
|
||||||
**
|
|
||||||
** The min leaf payload fraction is like the min embedded payload fraction
|
|
||||||
** except that it applies to leaf nodes in a LEAFDATA tree. The maximum
|
|
||||||
** payload fraction for a LEAFDATA tree is always 100% (or 255) and it
|
|
||||||
** not specified in the header.
|
|
||||||
**
|
|
||||||
** Each btree pages is divided into three sections: The header, the
|
|
||||||
** cell pointer array, and the cell content area. Page 1 also has a 100-byte
|
|
||||||
** file header that occurs before the page header.
|
|
||||||
**
|
|
||||||
** |----------------|
|
|
||||||
** | file header | 100 bytes. Page 1 only.
|
|
||||||
** |----------------|
|
|
||||||
** | page header | 8 bytes for leaves. 12 bytes for interior nodes
|
|
||||||
** |----------------|
|
|
||||||
** | cell pointer | | 2 bytes per cell. Sorted order.
|
|
||||||
** | array | | Grows downward
|
|
||||||
** | | v
|
|
||||||
** |----------------|
|
|
||||||
** | unallocated |
|
|
||||||
** | space |
|
|
||||||
** |----------------| ^ Grows upwards
|
|
||||||
** | cell content | | Arbitrary order interspersed with freeblocks.
|
|
||||||
** | area | | and free space fragments.
|
|
||||||
** |----------------|
|
|
||||||
**
|
|
||||||
** The page headers looks like this:
|
|
||||||
**
|
|
||||||
** OFFSET SIZE DESCRIPTION
|
|
||||||
** 0 1 Flags. 1: intkey, 2: zerodata, 4: leafdata, 8: leaf
|
|
||||||
** 1 2 byte offset to the first freeblock
|
|
||||||
** 3 2 number of cells on this page
|
|
||||||
** 5 2 first byte of the cell content area
|
|
||||||
** 7 1 number of fragmented free bytes
|
|
||||||
** 8 4 Right child (the Ptr(N) value). Omitted on leaves.
|
|
||||||
**
|
|
||||||
** The flags define the format of this btree page. The leaf flag means that
|
|
||||||
** this page has no children. The zerodata flag means that this page carries
|
|
||||||
** only keys and no data. The intkey flag means that the key is an integer
|
|
||||||
** which is stored in the key size entry of the cell header rather than in
|
|
||||||
** the payload area.
|
|
||||||
**
|
|
||||||
** The cell pointer array begins on the first byte after the page header.
|
|
||||||
** The cell pointer array contains zero or more 2-byte numbers which are
|
|
||||||
** offsets from the beginning of the page to the cell content in the cell
|
|
||||||
** content area. The cell pointers occur in sorted order. The system strives
|
|
||||||
** to keep free space after the last cell pointer so that new cells can
|
|
||||||
** be easily added without having to defragment the page.
|
|
||||||
**
|
|
||||||
** Cell content is stored at the very end of the page and grows toward the
|
|
||||||
** beginning of the page.
|
|
||||||
**
|
|
||||||
** Unused space within the cell content area is collected into a linked list of
|
|
||||||
** freeblocks. Each freeblock is at least 4 bytes in size. The byte offset
|
|
||||||
** to the first freeblock is given in the header. Freeblocks occur in
|
|
||||||
** increasing order. Because a freeblock must be at least 4 bytes in size,
|
|
||||||
** any group of 3 or fewer unused bytes in the cell content area cannot
|
|
||||||
** exist on the freeblock chain. A group of 3 or fewer free bytes is called
|
|
||||||
** a fragment. The total number of bytes in all fragments is recorded.
|
|
||||||
** in the page header at offset 7.
|
|
||||||
**
|
|
||||||
** SIZE DESCRIPTION
|
|
||||||
** 2 Byte offset of the next freeblock
|
|
||||||
** 2 Bytes in this freeblock
|
|
||||||
**
|
|
||||||
** Cells are of variable length. Cells are stored in the cell content area at
|
|
||||||
** the end of the page. Pointers to the cells are in the cell pointer array
|
|
||||||
** that immediately follows the page header. Cells is not necessarily
|
|
||||||
** contiguous or in order, but cell pointers are contiguous and in order.
|
|
||||||
**
|
|
||||||
** Cell content makes use of variable length integers. A variable
|
|
||||||
** length integer is 1 to 9 bytes where the lower 7 bits of each
|
|
||||||
** byte are used. The integer consists of all bytes that have bit 8 set and
|
|
||||||
** the first byte with bit 8 clear. The most significant byte of the integer
|
|
||||||
** appears first. A variable-length integer may not be more than 9 bytes long.
|
|
||||||
** As a special case, all 8 bytes of the 9th byte are used as data. This
|
|
||||||
** allows a 64-bit integer to be encoded in 9 bytes.
|
|
||||||
**
|
|
||||||
** 0x00 becomes 0x00000000
|
|
||||||
** 0x7f becomes 0x0000007f
|
|
||||||
** 0x81 0x00 becomes 0x00000080
|
|
||||||
** 0x82 0x00 becomes 0x00000100
|
|
||||||
** 0x80 0x7f becomes 0x0000007f
|
|
||||||
** 0x8a 0x91 0xd1 0xac 0x78 becomes 0x12345678
|
|
||||||
** 0x81 0x81 0x81 0x81 0x01 becomes 0x10204081
|
|
||||||
**
|
|
||||||
** Variable length integers are used for rowids and to hold the number of
|
|
||||||
** bytes of key and data in a btree cell.
|
|
||||||
**
|
|
||||||
** The content of a cell looks like this:
|
|
||||||
**
|
|
||||||
** SIZE DESCRIPTION
|
|
||||||
** 4 Page number of the left child. Omitted if leaf flag is set.
|
|
||||||
** var Number of bytes of data. Omitted if the zerodata flag is set.
|
|
||||||
** var Number of bytes of key. Or the key itself if intkey flag is set.
|
|
||||||
** * Payload
|
|
||||||
** 4 First page of the overflow chain. Omitted if no overflow
|
|
||||||
**
|
|
||||||
** Overflow pages form a linked list. Each page except the last is completely
|
|
||||||
** filled with data (pagesize - 4 bytes). The last page can have as little
|
|
||||||
** as 1 byte of data.
|
|
||||||
**
|
|
||||||
** SIZE DESCRIPTION
|
|
||||||
** 4 Page number of next overflow page
|
|
||||||
** * Data
|
|
||||||
**
|
|
||||||
** Freelist pages come in two subtypes: trunk pages and leaf pages. The
|
|
||||||
** file header points to the first in a linked list of trunk page. Each trunk
|
|
||||||
** page points to multiple leaf pages. The content of a leaf page is
|
|
||||||
** unspecified. A trunk page looks like this:
|
|
||||||
**
|
|
||||||
** SIZE DESCRIPTION
|
|
||||||
** 4 Page number of next trunk page
|
|
||||||
** 4 Number of leaf pointers on this page
|
|
||||||
** * zero or more pages numbers of leaves
|
|
||||||
*/
|
|
||||||
#include "sqliteInt.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* The following value is the maximum cell size assuming a maximum page
|
|
||||||
** size give above.
|
|
||||||
*/
|
|
||||||
#define MX_CELL_SIZE(pBt) ((int)(pBt->pageSize-8))
|
|
||||||
|
|
||||||
/* The maximum number of cells on a single page of the database. This
|
|
||||||
** assumes a minimum cell size of 6 bytes (4 bytes for the cell itself
|
|
||||||
** plus 2 bytes for the index to the cell in the page header). Such
|
|
||||||
** small cells will be rare, but they are possible.
|
|
||||||
*/
|
|
||||||
#define MX_CELL(pBt) ((pBt->pageSize-8)/6)
|
|
||||||
|
|
||||||
/* Forward declarations */
|
|
||||||
typedef struct MemPage MemPage;
|
|
||||||
typedef struct BtLock BtLock;
|
|
||||||
typedef struct CellInfo CellInfo;
|
|
||||||
|
|
||||||
/*
|
|
||||||
** This is a magic string that appears at the beginning of every
|
|
||||||
** SQLite database in order to identify the file as a real database.
|
|
||||||
**
|
|
||||||
** You can change this value at compile-time by specifying a
|
|
||||||
** -DSQLITE_FILE_HEADER="..." on the compiler command-line. The
|
|
||||||
** header must be exactly 16 bytes including the zero-terminator so
|
|
||||||
** the string itself should be 15 characters long. If you change
|
|
||||||
** the header, then your custom library will not be able to read
|
|
||||||
** databases generated by the standard tools and the standard tools
|
|
||||||
** will not be able to read databases created by your custom library.
|
|
||||||
*/
|
|
||||||
#ifndef SQLITE_FILE_HEADER /* 123456789 123456 */
|
|
||||||
# define SQLITE_FILE_HEADER "SQLite format 3"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Page type flags. An ORed combination of these flags appear as the
|
|
||||||
** first byte of on-disk image of every BTree page.
|
|
||||||
*/
|
|
||||||
#define PTF_INTKEY 0x01
|
|
||||||
#define PTF_ZERODATA 0x02
|
|
||||||
#define PTF_LEAFDATA 0x04
|
|
||||||
#define PTF_LEAF 0x08
|
|
||||||
|
|
||||||
/*
|
|
||||||
** An instance of this object stores information about each a single database
|
|
||||||
** page that has been loaded into memory. The information in this object
|
|
||||||
** is derived from the raw on-disk page content.
|
|
||||||
**
|
|
||||||
** As each database page is loaded into memory, the pager allocats an
|
|
||||||
** instance of this object and zeros the first 8 bytes. (This is the
|
|
||||||
** "extra" information associated with each page of the pager.)
|
|
||||||
**
|
|
||||||
** Access to all fields of this structure is controlled by the mutex
|
|
||||||
** stored in MemPage.pBt->mutex.
|
|
||||||
*/
|
|
||||||
struct MemPage {
|
|
||||||
u8 isInit; /* True if previously initialized. MUST BE FIRST! */
|
|
||||||
u8 intKey; /* True if table b-trees. False for index b-trees */
|
|
||||||
u8 intKeyLeaf; /* True if the leaf of an intKey table */
|
|
||||||
Pgno pgno; /* Page number for this page */
|
|
||||||
/* Only the first 8 bytes (above) are zeroed by pager.c when a new page
|
|
||||||
** is allocated. All fields that follow must be initialized before use */
|
|
||||||
u8 leaf; /* True if a leaf page */
|
|
||||||
u8 hdrOffset; /* 100 for page 1. 0 otherwise */
|
|
||||||
u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */
|
|
||||||
u8 max1bytePayload; /* min(maxLocal,127) */
|
|
||||||
u8 nOverflow; /* Number of overflow cell bodies in aCell[] */
|
|
||||||
u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
|
|
||||||
u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */
|
|
||||||
u16 cellOffset; /* Index in aData of first cell pointer */
|
|
||||||
int nFree; /* Number of free bytes on the page. -1 for unknown */
|
|
||||||
u16 nCell; /* Number of cells on this page, local and ovfl */
|
|
||||||
u16 maskPage; /* Mask for page offset */
|
|
||||||
u16 aiOvfl[4]; /* Insert the i-th overflow cell before the aiOvfl-th
|
|
||||||
** non-overflow cell */
|
|
||||||
u8 *apOvfl[4]; /* Pointers to the body of overflow cells */
|
|
||||||
BtShared *pBt; /* Pointer to BtShared that this page is part of */
|
|
||||||
u8 *aData; /* Pointer to disk image of the page data */
|
|
||||||
u8 *aDataEnd; /* One byte past the end of usable data */
|
|
||||||
u8 *aCellIdx; /* The cell index area */
|
|
||||||
u8 *aDataOfst; /* Same as aData for leaves. aData+4 for interior */
|
|
||||||
DbPage *pDbPage; /* Pager page handle */
|
|
||||||
u16 (*xCellSize)(MemPage*,u8*); /* cellSizePtr method */
|
|
||||||
void (*xParseCell)(MemPage*,u8*,CellInfo*); /* btreeParseCell method */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
** A linked list of the following structures is stored at BtShared.pLock.
|
|
||||||
** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor
|
|
||||||
** is opened on the table with root page BtShared.iTable. Locks are removed
|
|
||||||
** from this list when a transaction is committed or rolled back, or when
|
|
||||||
** a btree handle is closed.
|
|
||||||
*/
|
|
||||||
struct BtLock {
|
|
||||||
Btree *pBtree; /* Btree handle holding this lock */
|
|
||||||
Pgno iTable; /* Root page of table */
|
|
||||||
u8 eLock; /* READ_LOCK or WRITE_LOCK */
|
|
||||||
BtLock *pNext; /* Next in BtShared.pLock list */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Candidate values for BtLock.eLock */
|
|
||||||
#define READ_LOCK 1
|
|
||||||
#define WRITE_LOCK 2
|
|
||||||
|
|
||||||
/* A Btree handle
|
|
||||||
**
|
|
||||||
** A database connection contains a pointer to an instance of
|
|
||||||
** this object for every database file that it has open. This structure
|
|
||||||
** is opaque to the database connection. The database connection cannot
|
|
||||||
** see the internals of this structure and only deals with pointers to
|
|
||||||
** this structure.
|
|
||||||
**
|
|
||||||
** For some database files, the same underlying database cache might be
|
|
||||||
** shared between multiple connections. In that case, each connection
|
|
||||||
** has it own instance of this object. But each instance of this object
|
|
||||||
** points to the same BtShared object. The database cache and the
|
|
||||||
** schema associated with the database file are all contained within
|
|
||||||
** the BtShared object.
|
|
||||||
**
|
|
||||||
** All fields in this structure are accessed under sqlite3.mutex.
|
|
||||||
** The pBt pointer itself may not be changed while there exists cursors
|
|
||||||
** in the referenced BtShared that point back to this Btree since those
|
|
||||||
** cursors have to go through this Btree to find their BtShared and
|
|
||||||
** they often do so without holding sqlite3.mutex.
|
|
||||||
*/
|
|
||||||
struct Btree {
|
|
||||||
sqlite3 *db; /* The database connection holding this btree */
|
|
||||||
BtShared *pBt; /* Sharable content of this btree */
|
|
||||||
u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */
|
|
||||||
u8 sharable; /* True if we can share pBt with another db */
|
|
||||||
u8 locked; /* True if db currently has pBt locked */
|
|
||||||
u8 hasIncrblobCur; /* True if there are one or more Incrblob cursors */
|
|
||||||
int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */
|
|
||||||
int nBackup; /* Number of backup operations reading this btree */
|
|
||||||
u32 iBDataVersion; /* Combines with pBt->pPager->iDataVersion */
|
|
||||||
Btree *pNext; /* List of other sharable Btrees from the same db */
|
|
||||||
Btree *pPrev; /* Back pointer of the same list */
|
|
||||||
#ifdef SQLITE_DEBUG
|
|
||||||
u64 nSeek; /* Calls to sqlite3BtreeMovetoUnpacked() */
|
|
||||||
#endif
|
|
||||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
|
||||||
BtLock lock; /* Object used to lock page 1 */
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Btree.inTrans may take one of the following values.
|
|
||||||
**
|
|
||||||
** If the shared-data extension is enabled, there may be multiple users
|
|
||||||
** of the Btree structure. At most one of these may open a write transaction,
|
|
||||||
** but any number may have active read transactions.
|
|
||||||
**
|
|
||||||
** These values must match SQLITE_TXN_NONE, SQLITE_TXN_READ, and
|
|
||||||
** SQLITE_TXN_WRITE
|
|
||||||
*/
|
|
||||||
#define TRANS_NONE 0
|
|
||||||
#define TRANS_READ 1
|
|
||||||
#define TRANS_WRITE 2
|
|
||||||
|
|
||||||
#if TRANS_NONE!=SQLITE_TXN_NONE
|
|
||||||
# error wrong numeric code for no-transaction
|
|
||||||
#endif
|
|
||||||
#if TRANS_READ!=SQLITE_TXN_READ
|
|
||||||
# error wrong numeric code for read-transaction
|
|
||||||
#endif
|
|
||||||
#if TRANS_WRITE!=SQLITE_TXN_WRITE
|
|
||||||
# error wrong numeric code for write-transaction
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** An instance of this object represents a single database file.
|
|
||||||
**
|
|
||||||
** A single database file can be in use at the same time by two
|
|
||||||
** or more database connections. When two or more connections are
|
|
||||||
** sharing the same database file, each connection has it own
|
|
||||||
** private Btree object for the file and each of those Btrees points
|
|
||||||
** to this one BtShared object. BtShared.nRef is the number of
|
|
||||||
** connections currently sharing this database file.
|
|
||||||
**
|
|
||||||
** Fields in this structure are accessed under the BtShared.mutex
|
|
||||||
** mutex, except for nRef and pNext which are accessed under the
|
|
||||||
** global SQLITE_MUTEX_STATIC_MAIN mutex. The pPager field
|
|
||||||
** may not be modified once it is initially set as long as nRef>0.
|
|
||||||
** The pSchema field may be set once under BtShared.mutex and
|
|
||||||
** thereafter is unchanged as long as nRef>0.
|
|
||||||
**
|
|
||||||
** isPending:
|
|
||||||
**
|
|
||||||
** If a BtShared client fails to obtain a write-lock on a database
|
|
||||||
** table (because there exists one or more read-locks on the table),
|
|
||||||
** the shared-cache enters 'pending-lock' state and isPending is
|
|
||||||
** set to true.
|
|
||||||
**
|
|
||||||
** The shared-cache leaves the 'pending lock' state when either of
|
|
||||||
** the following occur:
|
|
||||||
**
|
|
||||||
** 1) The current writer (BtShared.pWriter) concludes its transaction, OR
|
|
||||||
** 2) The number of locks held by other connections drops to zero.
|
|
||||||
**
|
|
||||||
** while in the 'pending-lock' state, no connection may start a new
|
|
||||||
** transaction.
|
|
||||||
**
|
|
||||||
** This feature is included to help prevent writer-starvation.
|
|
||||||
*/
|
|
||||||
struct BtShared {
|
|
||||||
Pager *pPager; /* The page cache */
|
|
||||||
sqlite3 *db; /* Database connection currently using this Btree */
|
|
||||||
BtCursor *pCursor; /* A list of all open cursors */
|
|
||||||
MemPage *pPage1; /* First page of the database */
|
|
||||||
u8 openFlags; /* Flags to sqlite3BtreeOpen() */
|
|
||||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
|
||||||
u8 autoVacuum; /* True if auto-vacuum is enabled */
|
|
||||||
u8 incrVacuum; /* True if incr-vacuum is enabled */
|
|
||||||
u8 bDoTruncate; /* True to truncate db on commit */
|
|
||||||
#endif
|
|
||||||
u8 inTransaction; /* Transaction state */
|
|
||||||
u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
|
|
||||||
u8 nReserveWanted; /* Desired number of extra bytes per page */
|
|
||||||
u16 btsFlags; /* Boolean parameters. See BTS_* macros below */
|
|
||||||
u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
|
|
||||||
u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */
|
|
||||||
u16 maxLeaf; /* Maximum local payload in a LEAFDATA table */
|
|
||||||
u16 minLeaf; /* Minimum local payload in a LEAFDATA table */
|
|
||||||
u32 pageSize; /* Total number of bytes on a page */
|
|
||||||
u32 usableSize; /* Number of usable bytes on each page */
|
|
||||||
int nTransaction; /* Number of open transactions (read + write) */
|
|
||||||
u32 nPage; /* Number of pages in the database */
|
|
||||||
void *pSchema; /* Pointer to space allocated by sqlite3BtreeSchema() */
|
|
||||||
void (*xFreeSchema)(void*); /* Destructor for BtShared.pSchema */
|
|
||||||
sqlite3_mutex *mutex; /* Non-recursive mutex required to access this object */
|
|
||||||
Bitvec *pHasContent; /* Set of pages moved to free-list this transaction */
|
|
||||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
|
||||||
int nRef; /* Number of references to this structure */
|
|
||||||
BtShared *pNext; /* Next on a list of sharable BtShared structs */
|
|
||||||
BtLock *pLock; /* List of locks held on this shared-btree struct */
|
|
||||||
Btree *pWriter; /* Btree with currently open write transaction */
|
|
||||||
#endif
|
|
||||||
u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */
|
|
||||||
int nPreformatSize; /* Size of last cell written by TransferRow() */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Allowed values for BtShared.btsFlags
|
|
||||||
*/
|
|
||||||
#define BTS_READ_ONLY 0x0001 /* Underlying file is readonly */
|
|
||||||
#define BTS_PAGESIZE_FIXED 0x0002 /* Page size can no longer be changed */
|
|
||||||
#define BTS_SECURE_DELETE 0x0004 /* PRAGMA secure_delete is enabled */
|
|
||||||
#define BTS_OVERWRITE 0x0008 /* Overwrite deleted content with zeros */
|
|
||||||
#define BTS_FAST_SECURE 0x000c /* Combination of the previous two */
|
|
||||||
#define BTS_INITIALLY_EMPTY 0x0010 /* Database was empty at trans start */
|
|
||||||
#define BTS_NO_WAL 0x0020 /* Do not open write-ahead-log files */
|
|
||||||
#define BTS_EXCLUSIVE 0x0040 /* pWriter has an exclusive lock */
|
|
||||||
#define BTS_PENDING 0x0080 /* Waiting for read-locks to clear */
|
|
||||||
|
|
||||||
/*
|
|
||||||
** An instance of the following structure is used to hold information
|
|
||||||
** about a cell. The parseCellPtr() function fills in this structure
|
|
||||||
** based on information extract from the raw disk page.
|
|
||||||
*/
|
|
||||||
struct CellInfo {
|
|
||||||
i64 nKey; /* The key for INTKEY tables, or nPayload otherwise */
|
|
||||||
u8 *pPayload; /* Pointer to the start of payload */
|
|
||||||
u32 nPayload; /* Bytes of payload */
|
|
||||||
u16 nLocal; /* Amount of payload held locally, not on overflow */
|
|
||||||
u16 nSize; /* Size of the cell content on the main b-tree page */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Maximum depth of an SQLite B-Tree structure. Any B-Tree deeper than
|
|
||||||
** this will be declared corrupt. This value is calculated based on a
|
|
||||||
** maximum database size of 2^31 pages a minimum fanout of 2 for a
|
|
||||||
** root-node and 3 for all other internal nodes.
|
|
||||||
**
|
|
||||||
** If a tree that appears to be taller than this is encountered, it is
|
|
||||||
** assumed that the database is corrupt.
|
|
||||||
*/
|
|
||||||
#define BTCURSOR_MAX_DEPTH 20
|
|
||||||
|
|
||||||
/*
|
|
||||||
** A cursor is a pointer to a particular entry within a particular
|
|
||||||
** b-tree within a database file.
|
|
||||||
**
|
|
||||||
** The entry is identified by its MemPage and the index in
|
|
||||||
** MemPage.aCell[] of the entry.
|
|
||||||
**
|
|
||||||
** A single database file can be shared by two more database connections,
|
|
||||||
** but cursors cannot be shared. Each cursor is associated with a
|
|
||||||
** particular database connection identified BtCursor.pBtree.db.
|
|
||||||
**
|
|
||||||
** Fields in this structure are accessed under the BtShared.mutex
|
|
||||||
** found at self->pBt->mutex.
|
|
||||||
**
|
|
||||||
** skipNext meaning:
|
|
||||||
** The meaning of skipNext depends on the value of eState:
|
|
||||||
**
|
|
||||||
** eState Meaning of skipNext
|
|
||||||
** VALID skipNext is meaningless and is ignored
|
|
||||||
** INVALID skipNext is meaningless and is ignored
|
|
||||||
** SKIPNEXT sqlite3BtreeNext() is a no-op if skipNext>0 and
|
|
||||||
** sqlite3BtreePrevious() is no-op if skipNext<0.
|
|
||||||
** REQUIRESEEK restoreCursorPosition() restores the cursor to
|
|
||||||
** eState=SKIPNEXT if skipNext!=0
|
|
||||||
** FAULT skipNext holds the cursor fault error code.
|
|
||||||
*/
|
|
||||||
struct BtCursor {
|
|
||||||
u8 eState; /* One of the CURSOR_XXX constants (see below) */
|
|
||||||
u8 curFlags; /* zero or more BTCF_* flags defined below */
|
|
||||||
u8 curPagerFlags; /* Flags to send to sqlite3PagerGet() */
|
|
||||||
u8 hints; /* As configured by CursorSetHints() */
|
|
||||||
int skipNext; /* Prev() is noop if negative. Next() is noop if positive.
|
|
||||||
** Error code if eState==CURSOR_FAULT */
|
|
||||||
Btree *pBtree; /* The Btree to which this cursor belongs */
|
|
||||||
Pgno *aOverflow; /* Cache of overflow page locations */
|
|
||||||
void *pKey; /* Saved key that was cursor last known position */
|
|
||||||
/* All fields above are zeroed when the cursor is allocated. See
|
|
||||||
** sqlite3BtreeCursorZero(). Fields that follow must be manually
|
|
||||||
** initialized. */
|
|
||||||
#define BTCURSOR_FIRST_UNINIT pBt /* Name of first uninitialized field */
|
|
||||||
BtShared *pBt; /* The BtShared this cursor points to */
|
|
||||||
BtCursor *pNext; /* Forms a linked list of all cursors */
|
|
||||||
CellInfo info; /* A parse of the cell we are pointing at */
|
|
||||||
i64 nKey; /* Size of pKey, or last integer key */
|
|
||||||
Pgno pgnoRoot; /* The root page of this tree */
|
|
||||||
i8 iPage; /* Index of current page in apPage */
|
|
||||||
u8 curIntKey; /* Value of apPage[0]->intKey */
|
|
||||||
u16 ix; /* Current index for apPage[iPage] */
|
|
||||||
u16 aiIdx[BTCURSOR_MAX_DEPTH-1]; /* Current index in apPage[i] */
|
|
||||||
struct KeyInfo *pKeyInfo; /* Arg passed to comparison function */
|
|
||||||
MemPage *pPage; /* Current page */
|
|
||||||
MemPage *apPage[BTCURSOR_MAX_DEPTH-1]; /* Stack of parents of current page */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Legal values for BtCursor.curFlags
|
|
||||||
*/
|
|
||||||
#define BTCF_WriteFlag 0x01 /* True if a write cursor */
|
|
||||||
#define BTCF_ValidNKey 0x02 /* True if info.nKey is valid */
|
|
||||||
#define BTCF_ValidOvfl 0x04 /* True if aOverflow is valid */
|
|
||||||
#define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */
|
|
||||||
#define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */
|
|
||||||
#define BTCF_Multiple 0x20 /* Maybe another cursor on the same btree */
|
|
||||||
#define BTCF_Pinned 0x40 /* Cursor is busy and cannot be moved */
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Potential values for BtCursor.eState.
|
|
||||||
**
|
|
||||||
** CURSOR_INVALID:
|
|
||||||
** Cursor does not point to a valid entry. This can happen (for example)
|
|
||||||
** because the table is empty or because BtreeCursorFirst() has not been
|
|
||||||
** called.
|
|
||||||
**
|
|
||||||
** CURSOR_VALID:
|
|
||||||
** Cursor points to a valid entry. getPayload() etc. may be called.
|
|
||||||
**
|
|
||||||
** CURSOR_SKIPNEXT:
|
|
||||||
** Cursor is valid except that the Cursor.skipNext field is non-zero
|
|
||||||
** indicating that the next sqlite3BtreeNext() or sqlite3BtreePrevious()
|
|
||||||
** operation should be a no-op.
|
|
||||||
**
|
|
||||||
** CURSOR_REQUIRESEEK:
|
|
||||||
** The table that this cursor was opened on still exists, but has been
|
|
||||||
** modified since the cursor was last used. The cursor position is saved
|
|
||||||
** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in
|
|
||||||
** this state, restoreCursorPosition() can be called to attempt to
|
|
||||||
** seek the cursor to the saved position.
|
|
||||||
**
|
|
||||||
** CURSOR_FAULT:
|
|
||||||
** An unrecoverable error (an I/O error or a malloc failure) has occurred
|
|
||||||
** on a different connection that shares the BtShared cache with this
|
|
||||||
** cursor. The error has left the cache in an inconsistent state.
|
|
||||||
** Do nothing else with this cursor. Any attempt to use the cursor
|
|
||||||
** should return the error code stored in BtCursor.skipNext
|
|
||||||
*/
|
|
||||||
#define CURSOR_VALID 0
|
|
||||||
#define CURSOR_INVALID 1
|
|
||||||
#define CURSOR_SKIPNEXT 2
|
|
||||||
#define CURSOR_REQUIRESEEK 3
|
|
||||||
#define CURSOR_FAULT 4
|
|
||||||
|
|
||||||
/*
|
|
||||||
** The database page the PENDING_BYTE occupies. This page is never used.
|
|
||||||
*/
|
|
||||||
# define PENDING_BYTE_PAGE(pBt) PAGER_MJ_PGNO(pBt)
|
|
||||||
|
|
||||||
/*
|
|
||||||
** These macros define the location of the pointer-map entry for a
|
|
||||||
** database page. The first argument to each is the number of usable
|
|
||||||
** bytes on each page of the database (often 1024). The second is the
|
|
||||||
** page number to look up in the pointer map.
|
|
||||||
**
|
|
||||||
** PTRMAP_PAGENO returns the database page number of the pointer-map
|
|
||||||
** page that stores the required pointer. PTRMAP_PTROFFSET returns
|
|
||||||
** the offset of the requested map entry.
|
|
||||||
**
|
|
||||||
** If the pgno argument passed to PTRMAP_PAGENO is a pointer-map page,
|
|
||||||
** then pgno is returned. So (pgno==PTRMAP_PAGENO(pgsz, pgno)) can be
|
|
||||||
** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements
|
|
||||||
** this test.
|
|
||||||
*/
|
|
||||||
#define PTRMAP_PAGENO(pBt, pgno) ptrmapPageno(pBt, pgno)
|
|
||||||
#define PTRMAP_PTROFFSET(pgptrmap, pgno) (5*(pgno-pgptrmap-1))
|
|
||||||
#define PTRMAP_ISPAGE(pBt, pgno) (PTRMAP_PAGENO((pBt),(pgno))==(pgno))
|
|
||||||
|
|
||||||
/*
|
|
||||||
** The pointer map is a lookup table that identifies the parent page for
|
|
||||||
** each child page in the database file. The parent page is the page that
|
|
||||||
** contains a pointer to the child. Every page in the database contains
|
|
||||||
** 0 or 1 parent pages. (In this context 'database page' refers
|
|
||||||
** to any page that is not part of the pointer map itself.) Each pointer map
|
|
||||||
** entry consists of a single byte 'type' and a 4 byte parent page number.
|
|
||||||
** The PTRMAP_XXX identifiers below are the valid types.
|
|
||||||
**
|
|
||||||
** The purpose of the pointer map is to facility moving pages from one
|
|
||||||
** position in the file to another as part of autovacuum. When a page
|
|
||||||
** is moved, the pointer in its parent must be updated to point to the
|
|
||||||
** new location. The pointer map is used to locate the parent page quickly.
|
|
||||||
**
|
|
||||||
** PTRMAP_ROOTPAGE: The database page is a root-page. The page-number is not
|
|
||||||
** used in this case.
|
|
||||||
**
|
|
||||||
** PTRMAP_FREEPAGE: The database page is an unused (free) page. The page-number
|
|
||||||
** is not used in this case.
|
|
||||||
**
|
|
||||||
** PTRMAP_OVERFLOW1: The database page is the first page in a list of
|
|
||||||
** overflow pages. The page number identifies the page that
|
|
||||||
** contains the cell with a pointer to this overflow page.
|
|
||||||
**
|
|
||||||
** PTRMAP_OVERFLOW2: The database page is the second or later page in a list of
|
|
||||||
** overflow pages. The page-number identifies the previous
|
|
||||||
** page in the overflow page list.
|
|
||||||
**
|
|
||||||
** PTRMAP_BTREE: The database page is a non-root btree page. The page number
|
|
||||||
** identifies the parent page in the btree.
|
|
||||||
*/
|
|
||||||
#define PTRMAP_ROOTPAGE 1
|
|
||||||
#define PTRMAP_FREEPAGE 2
|
|
||||||
#define PTRMAP_OVERFLOW1 3
|
|
||||||
#define PTRMAP_OVERFLOW2 4
|
|
||||||
#define PTRMAP_BTREE 5
|
|
||||||
|
|
||||||
/* A bunch of assert() statements to check the transaction state variables
|
|
||||||
** of handle p (type Btree*) are internally consistent.
|
|
||||||
*/
|
|
||||||
#define btreeIntegrity(p) \
|
|
||||||
assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \
|
|
||||||
assert( p->pBt->inTransaction>=p->inTrans );
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** The ISAUTOVACUUM macro is used within balance_nonroot() to determine
|
|
||||||
** if the database supports auto-vacuum or not. Because it is used
|
|
||||||
** within an expression that is an argument to another macro
|
|
||||||
** (sqliteMallocRaw), it is not possible to use conditional compilation.
|
|
||||||
** So, this macro is defined instead.
|
|
||||||
*/
|
|
||||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
|
||||||
#define ISAUTOVACUUM (pBt->autoVacuum)
|
|
||||||
#else
|
|
||||||
#define ISAUTOVACUUM 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** This structure is passed around through all the sanity checking routines
|
|
||||||
** in order to keep track of some global state information.
|
|
||||||
**
|
|
||||||
** The aRef[] array is allocated so that there is 1 bit for each page in
|
|
||||||
** the database. As the integrity-check proceeds, for each page used in
|
|
||||||
** the database the corresponding bit is set. This allows integrity-check to
|
|
||||||
** detect pages that are used twice and orphaned pages (both of which
|
|
||||||
** indicate corruption).
|
|
||||||
*/
|
|
||||||
typedef struct IntegrityCk IntegrityCk;
|
|
||||||
struct IntegrityCk {
|
|
||||||
BtShared *pBt; /* The tree being checked out */
|
|
||||||
Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */
|
|
||||||
u8 *aPgRef; /* 1 bit per page in the db (see above) */
|
|
||||||
Pgno nPage; /* Number of pages in the database */
|
|
||||||
int mxErr; /* Stop accumulating errors when this reaches zero */
|
|
||||||
int nErr; /* Number of messages written to zErrMsg so far */
|
|
||||||
int bOomFault; /* A memory allocation error has occurred */
|
|
||||||
const char *zPfx; /* Error message prefix */
|
|
||||||
Pgno v1; /* Value for first %u substitution in zPfx */
|
|
||||||
int v2; /* Value for second %d substitution in zPfx */
|
|
||||||
StrAccum errMsg; /* Accumulate the error message text here */
|
|
||||||
u32 *heap; /* Min-heap used for analyzing cell coverage */
|
|
||||||
sqlite3 *db; /* Database connection running the check */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Routines to read or write a two- and four-byte big-endian integer values.
|
|
||||||
*/
|
|
||||||
#define get2byte(x) ((x)[0]<<8 | (x)[1])
|
|
||||||
#define put2byte(p,v) ((p)[0] = (u8)((v)>>8), (p)[1] = (u8)(v))
|
|
||||||
#define get4byte sqlite3Get4byte
|
|
||||||
#define put4byte sqlite3Put4byte
|
|
||||||
|
|
||||||
/*
|
|
||||||
** get2byteAligned(), unlike get2byte(), requires that its argument point to a
|
|
||||||
** two-byte aligned address. get2bytea() is only used for accessing the
|
|
||||||
** cell addresses in a btree header.
|
|
||||||
*/
|
|
||||||
#if SQLITE_BYTEORDER==4321
|
|
||||||
# define get2byteAligned(x) (*(u16*)(x))
|
|
||||||
#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4008000
|
|
||||||
# define get2byteAligned(x) __builtin_bswap16(*(u16*)(x))
|
|
||||||
#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
|
|
||||||
# define get2byteAligned(x) _byteswap_ushort(*(u16*)(x))
|
|
||||||
#else
|
|
||||||
# define get2byteAligned(x) ((x)[0]<<8 | (x)[1])
|
|
||||||
#endif
|
|
|
@ -1,241 +0,0 @@
|
||||||
/*
|
|
||||||
** 2001 September 15
|
|
||||||
**
|
|
||||||
** 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 header file defines the interface that the sqlite page cache
|
|
||||||
** subsystem. The page cache subsystem reads and writes a file a page
|
|
||||||
** at a time and provides a journal for rollback.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SQLITE_PAGER_H
|
|
||||||
#define SQLITE_PAGER_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Default maximum size for persistent journal files. A negative
|
|
||||||
** value means no limit. This value may be overridden using the
|
|
||||||
** sqlite3PagerJournalSizeLimit() API. See also "PRAGMA journal_size_limit".
|
|
||||||
*/
|
|
||||||
#ifndef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT
|
|
||||||
#define SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT -1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
** The type used to represent a page number. The first page in a file
|
|
||||||
** is called page 1. 0 is used to represent "not a page".
|
|
||||||
*/
|
|
||||||
typedef u32 Pgno;
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Each open file is managed by a separate instance of the "Pager" structure.
|
|
||||||
*/
|
|
||||||
typedef struct Pager Pager;
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Handle type for pages.
|
|
||||||
*/
|
|
||||||
typedef struct PgHdr DbPage;
|
|
||||||
|
|
||||||
// /*
|
|
||||||
// ** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is
|
|
||||||
// ** reserved for working around a windows/posix incompatibility). It is
|
|
||||||
// ** used in the journal to signify that the remainder of the journal file
|
|
||||||
// ** is devoted to storing a super-journal name - there are no more pages to
|
|
||||||
// ** roll back. See comments for function writeSuperJournal() in pager.c
|
|
||||||
// ** for details.
|
|
||||||
// */
|
|
||||||
// #define PAGER_MJ_PGNO(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1))
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Allowed values for the flags parameter to sqlite3PagerOpen().
|
|
||||||
**
|
|
||||||
** NOTE: These values must match the corresponding BTREE_ values in btree.h.
|
|
||||||
*/
|
|
||||||
#define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */
|
|
||||||
#define PAGER_MEMORY 0x0002 /* In-memory database */
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Valid values for the second argument to sqlite3PagerLockingMode().
|
|
||||||
*/
|
|
||||||
#define PAGER_LOCKINGMODE_QUERY -1
|
|
||||||
#define PAGER_LOCKINGMODE_NORMAL 0
|
|
||||||
#define PAGER_LOCKINGMODE_EXCLUSIVE 1
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Numeric constants that encode the journalmode.
|
|
||||||
**
|
|
||||||
** The numeric values encoded here (other than PAGER_JOURNALMODE_QUERY)
|
|
||||||
** are exposed in the API via the "PRAGMA journal_mode" command and
|
|
||||||
** therefore cannot be changed without a compatibility break.
|
|
||||||
*/
|
|
||||||
#define PAGER_JOURNALMODE_QUERY (-1) /* Query the value of journalmode */
|
|
||||||
#define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */
|
|
||||||
#define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */
|
|
||||||
#define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */
|
|
||||||
#define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */
|
|
||||||
#define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */
|
|
||||||
#define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Flags that make up the mask passed to sqlite3PagerGet().
|
|
||||||
*/
|
|
||||||
#define PAGER_GET_NOCONTENT 0x01 /* Do not load data from disk */
|
|
||||||
#define PAGER_GET_READONLY 0x02 /* Read-only page is acceptable */
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Flags for sqlite3PagerSetFlags()
|
|
||||||
**
|
|
||||||
** Value constraints (enforced via assert()):
|
|
||||||
** PAGER_FULLFSYNC == SQLITE_FullFSync
|
|
||||||
** PAGER_CKPT_FULLFSYNC == SQLITE_CkptFullFSync
|
|
||||||
** PAGER_CACHE_SPILL == SQLITE_CacheSpill
|
|
||||||
*/
|
|
||||||
#define PAGER_SYNCHRONOUS_OFF 0x01 /* PRAGMA synchronous=OFF */
|
|
||||||
#define PAGER_SYNCHRONOUS_NORMAL 0x02 /* PRAGMA synchronous=NORMAL */
|
|
||||||
#define PAGER_SYNCHRONOUS_FULL 0x03 /* PRAGMA synchronous=FULL */
|
|
||||||
#define PAGER_SYNCHRONOUS_EXTRA 0x04 /* PRAGMA synchronous=EXTRA */
|
|
||||||
#define PAGER_SYNCHRONOUS_MASK 0x07 /* Mask for four values above */
|
|
||||||
#define PAGER_FULLFSYNC 0x08 /* PRAGMA fullfsync=ON */
|
|
||||||
#define PAGER_CKPT_FULLFSYNC 0x10 /* PRAGMA checkpoint_fullfsync=ON */
|
|
||||||
#define PAGER_CACHESPILL 0x20 /* PRAGMA cache_spill=ON */
|
|
||||||
#define PAGER_FLAGS_MASK 0x38 /* All above except SYNCHRONOUS */
|
|
||||||
|
|
||||||
/*
|
|
||||||
** The remainder of this file contains the declarations of the functions
|
|
||||||
** that make up the Pager sub-system API. See source code comments for
|
|
||||||
** a detailed description of each routine.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Open and close a Pager connection. */
|
|
||||||
int sqlite3PagerOpen(
|
|
||||||
Pager **ppPager,
|
|
||||||
const char*,
|
|
||||||
int,
|
|
||||||
int,
|
|
||||||
int,
|
|
||||||
void(*)(DbPage*)
|
|
||||||
);
|
|
||||||
int sqlite3PagerClose(Pager *pPager, sqlite3*);
|
|
||||||
// int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
|
|
||||||
|
|
||||||
// /* Functions used to configure a Pager object. */
|
|
||||||
// void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *);
|
|
||||||
// int sqlite3PagerSetPagesize(Pager*, u32*, int);
|
|
||||||
// Pgno sqlite3PagerMaxPageCount(Pager*, Pgno);
|
|
||||||
// void sqlite3PagerSetCachesize(Pager*, int);
|
|
||||||
// int sqlite3PagerSetSpillsize(Pager*, int);
|
|
||||||
// void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64);
|
|
||||||
// void sqlite3PagerShrink(Pager*);
|
|
||||||
// void sqlite3PagerSetFlags(Pager*,unsigned);
|
|
||||||
// int sqlite3PagerLockingMode(Pager *, int);
|
|
||||||
// int sqlite3PagerSetJournalMode(Pager *, int);
|
|
||||||
// int sqlite3PagerGetJournalMode(Pager*);
|
|
||||||
// int sqlite3PagerOkToChangeJournalMode(Pager*);
|
|
||||||
// i64 sqlite3PagerJournalSizeLimit(Pager *, i64);
|
|
||||||
// sqlite3_backup **sqlite3PagerBackupPtr(Pager*);
|
|
||||||
// int sqlite3PagerFlush(Pager*);
|
|
||||||
|
|
||||||
// /* Functions used to obtain and release page references. */
|
|
||||||
// int sqlite3PagerGet(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag);
|
|
||||||
// DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno);
|
|
||||||
// void sqlite3PagerRef(DbPage*);
|
|
||||||
// void sqlite3PagerUnref(DbPage*);
|
|
||||||
// void sqlite3PagerUnrefNotNull(DbPage*);
|
|
||||||
// void sqlite3PagerUnrefPageOne(DbPage*);
|
|
||||||
|
|
||||||
// /* Operations on page references. */
|
|
||||||
// int sqlite3PagerWrite(DbPage*);
|
|
||||||
// void sqlite3PagerDontWrite(DbPage*);
|
|
||||||
// int sqlite3PagerMovepage(Pager*,DbPage*,Pgno,int);
|
|
||||||
// int sqlite3PagerPageRefcount(DbPage*);
|
|
||||||
// void *sqlite3PagerGetData(DbPage *);
|
|
||||||
// void *sqlite3PagerGetExtra(DbPage *);
|
|
||||||
|
|
||||||
// /* Functions used to manage pager transactions and savepoints. */
|
|
||||||
// void sqlite3PagerPagecount(Pager*, int*);
|
|
||||||
// int sqlite3PagerBegin(Pager*, int exFlag, int);
|
|
||||||
// int sqlite3PagerCommitPhaseOne(Pager*,const char *zSuper, int);
|
|
||||||
// int sqlite3PagerExclusiveLock(Pager*);
|
|
||||||
// int sqlite3PagerSync(Pager *pPager, const char *zSuper);
|
|
||||||
// int sqlite3PagerCommitPhaseTwo(Pager*);
|
|
||||||
// int sqlite3PagerRollback(Pager*);
|
|
||||||
// int sqlite3PagerOpenSavepoint(Pager *pPager, int n);
|
|
||||||
// int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
|
|
||||||
// int sqlite3PagerSharedLock(Pager *pPager);
|
|
||||||
|
|
||||||
// #ifndef SQLITE_OMIT_WAL
|
|
||||||
// int sqlite3PagerCheckpoint(Pager *pPager, sqlite3*, int, int*, int*);
|
|
||||||
// int sqlite3PagerWalSupported(Pager *pPager);
|
|
||||||
// int sqlite3PagerWalCallback(Pager *pPager);
|
|
||||||
// int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
|
|
||||||
// int sqlite3PagerCloseWal(Pager *pPager, sqlite3*);
|
|
||||||
// # ifdef SQLITE_ENABLE_SNAPSHOT
|
|
||||||
// int sqlite3PagerSnapshotGet(Pager*, sqlite3_snapshot **ppSnapshot);
|
|
||||||
// int sqlite3PagerSnapshotOpen(Pager*, sqlite3_snapshot *pSnapshot);
|
|
||||||
// int sqlite3PagerSnapshotRecover(Pager *pPager);
|
|
||||||
// int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot);
|
|
||||||
// void sqlite3PagerSnapshotUnlock(Pager *pPager);
|
|
||||||
// # endif
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #if !defined(SQLITE_OMIT_WAL) && defined(SQLITE_ENABLE_SETLK_TIMEOUT)
|
|
||||||
// int sqlite3PagerWalWriteLock(Pager*, int);
|
|
||||||
// void sqlite3PagerWalDb(Pager*, sqlite3*);
|
|
||||||
// #else
|
|
||||||
// # define sqlite3PagerWalWriteLock(y,z) SQLITE_OK
|
|
||||||
// # define sqlite3PagerWalDb(x,y)
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifdef SQLITE_DIRECT_OVERFLOW_READ
|
|
||||||
// int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno);
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifdef SQLITE_ENABLE_ZIPVFS
|
|
||||||
// int sqlite3PagerWalFramesize(Pager *pPager);
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// /* Functions used to query pager state and configuration. */
|
|
||||||
// u8 sqlite3PagerIsreadonly(Pager*);
|
|
||||||
// u32 sqlite3PagerDataVersion(Pager*);
|
|
||||||
// #ifdef SQLITE_DEBUG
|
|
||||||
// int sqlite3PagerRefcount(Pager*);
|
|
||||||
// #endif
|
|
||||||
// int sqlite3PagerMemUsed(Pager*);
|
|
||||||
// const char *sqlite3PagerFilename(const Pager*, int);
|
|
||||||
// sqlite3_vfs *sqlite3PagerVfs(Pager*);
|
|
||||||
// sqlite3_file *sqlite3PagerFile(Pager*);
|
|
||||||
// sqlite3_file *sqlite3PagerJrnlFile(Pager*);
|
|
||||||
// const char *sqlite3PagerJournalname(Pager*);
|
|
||||||
// void *sqlite3PagerTempSpace(Pager*);
|
|
||||||
// int sqlite3PagerIsMemdb(Pager*);
|
|
||||||
// void sqlite3PagerCacheStat(Pager *, int, int, int *);
|
|
||||||
// void sqlite3PagerClearCache(Pager*);
|
|
||||||
// int sqlite3SectorSize(sqlite3_file *);
|
|
||||||
|
|
||||||
// /* Functions used to truncate the database file. */
|
|
||||||
// void sqlite3PagerTruncateImage(Pager*,Pgno);
|
|
||||||
|
|
||||||
// void sqlite3PagerRekey(DbPage*, Pgno, u16);
|
|
||||||
|
|
||||||
// /* Functions to support testing and debugging. */
|
|
||||||
// #if !defined(NDEBUG) || defined(SQLITE_TEST)
|
|
||||||
// Pgno sqlite3PagerPagenumber(DbPage*);
|
|
||||||
// int sqlite3PagerIswriteable(DbPage*);
|
|
||||||
// #endif
|
|
||||||
// #ifdef SQLITE_TEST
|
|
||||||
// int *sqlite3PagerStats(Pager*);
|
|
||||||
// void sqlite3PagerRefdump(Pager*);
|
|
||||||
// void disable_simulated_io_errors(void);
|
|
||||||
// void enable_simulated_io_errors(void);
|
|
||||||
// #else
|
|
||||||
// # define disable_simulated_io_errors()
|
|
||||||
// # define enable_simulated_io_errors()
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
#endif /* SQLITE_PAGER_H */
|
|
|
@ -1,210 +0,0 @@
|
||||||
/*
|
|
||||||
** 2008 August 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 header file defines the interface that the sqlite page cache
|
|
||||||
** subsystem.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _PCACHE_H_
|
|
||||||
|
|
||||||
typedef struct PgHdr PgHdr;
|
|
||||||
typedef struct PCache PCache;
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Every page in the cache is controlled by an instance of the following
|
|
||||||
** structure.
|
|
||||||
*/
|
|
||||||
struct PgHdr {
|
|
||||||
sqlite3_pcache_page *pPage; /* Pcache object page handle */
|
|
||||||
void * pData; /* Page data */
|
|
||||||
void * pExtra; /* Extra content */
|
|
||||||
PCache * pCache; /* PRIVATE: Cache that owns this page */
|
|
||||||
PgHdr * pDirty; /* Transient list of dirty sorted by pgno */
|
|
||||||
Pager * pPager; /* The pager this page is part of */
|
|
||||||
Pgno pgno; /* Page number for this page */
|
|
||||||
#ifdef SQLITE_CHECK_PAGES
|
|
||||||
u32 pageHash; /* Hash of page content */
|
|
||||||
#endif
|
|
||||||
u16 flags; /* PGHDR flags defined below */
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
** Elements above, except pCache, are public. All that follow are
|
|
||||||
** private to pcache.c and should not be accessed by other modules.
|
|
||||||
** pCache is grouped with the public elements for efficiency.
|
|
||||||
*/
|
|
||||||
i16 nRef; /* Number of users of this page */
|
|
||||||
PgHdr *pDirtyNext; /* Next element in list of dirty pages */
|
|
||||||
PgHdr *pDirtyPrev; /* Previous element in list of dirty pages */
|
|
||||||
/* NB: pDirtyNext and pDirtyPrev are undefined if the
|
|
||||||
** PgHdr object is not dirty */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Bit values for PgHdr.flags */
|
|
||||||
#define PGHDR_CLEAN 0x001 /* Page not on the PCache.pDirty list */
|
|
||||||
#define PGHDR_DIRTY 0x002 /* Page is on the PCache.pDirty list */
|
|
||||||
#define PGHDR_WRITEABLE 0x004 /* Journaled and ready to modify */
|
|
||||||
#define PGHDR_NEED_SYNC \
|
|
||||||
0x008 /* Fsync the rollback journal before \
|
|
||||||
** writing this page to the database */
|
|
||||||
#define PGHDR_DONT_WRITE 0x010 /* Do not write content to disk */
|
|
||||||
#define PGHDR_MMAP 0x020 /* This is an mmap page object */
|
|
||||||
|
|
||||||
#define PGHDR_WAL_APPEND 0x040 /* Appended to wal file */
|
|
||||||
|
|
||||||
/* Initialize and shutdown the page cache subsystem */
|
|
||||||
int sqlite3PcacheInitialize(void);
|
|
||||||
void sqlite3PcacheShutdown(void);
|
|
||||||
|
|
||||||
/* Page cache buffer management:
|
|
||||||
** These routines implement SQLITE_CONFIG_PAGECACHE.
|
|
||||||
*/
|
|
||||||
void sqlite3PCacheBufferSetup(void *, int sz, int n);
|
|
||||||
|
|
||||||
/* Create a new pager cache.
|
|
||||||
** Under memory stress, invoke xStress to try to make pages clean.
|
|
||||||
** Only clean and unpinned pages can be reclaimed.
|
|
||||||
*/
|
|
||||||
int sqlite3PcacheOpen(int szPage, /* Size of every page */
|
|
||||||
int szExtra, /* Extra space associated with each page */
|
|
||||||
int bPurgeable, /* True if pages are on backing store */
|
|
||||||
int (*xStress)(void *, PgHdr *), /* Call to try to make pages clean */
|
|
||||||
void * pStress, /* Argument to xStress */
|
|
||||||
PCache *pToInit /* Preallocated space for the PCache */
|
|
||||||
);
|
|
||||||
|
|
||||||
/* Modify the page-size after the cache has been created. */
|
|
||||||
int sqlite3PcacheSetPageSize(PCache *, int);
|
|
||||||
|
|
||||||
/* Return the size in bytes of a PCache object. Used to preallocate
|
|
||||||
** storage space.
|
|
||||||
*/
|
|
||||||
int sqlite3PcacheSize(void);
|
|
||||||
|
|
||||||
/* One release per successful fetch. Page is pinned until released.
|
|
||||||
** Reference counted.
|
|
||||||
*/
|
|
||||||
sqlite3_pcache_page *sqlite3PcacheFetch(PCache *, Pgno, int createFlag);
|
|
||||||
int sqlite3PcacheFetchStress(PCache *, Pgno, sqlite3_pcache_page **);
|
|
||||||
PgHdr * sqlite3PcacheFetchFinish(PCache *, Pgno, sqlite3_pcache_page *pPage);
|
|
||||||
void sqlite3PcacheRelease(PgHdr *);
|
|
||||||
|
|
||||||
void sqlite3PcacheDrop(PgHdr *); /* Remove page from cache */
|
|
||||||
void sqlite3PcacheMakeDirty(PgHdr *); /* Make sure page is marked dirty */
|
|
||||||
void sqlite3PcacheMakeClean(PgHdr *); /* Mark a single page as clean */
|
|
||||||
void sqlite3PcacheCleanAll(PCache *); /* Mark all dirty list pages as clean */
|
|
||||||
void sqlite3PcacheClearWritable(PCache *);
|
|
||||||
|
|
||||||
/* Change a page number. Used by incr-vacuum. */
|
|
||||||
void sqlite3PcacheMove(PgHdr *, Pgno);
|
|
||||||
|
|
||||||
/* Remove all pages with pgno>x. Reset the cache if x==0 */
|
|
||||||
void sqlite3PcacheTruncate(PCache *, Pgno x);
|
|
||||||
|
|
||||||
/* Get a list of all dirty pages in the cache, sorted by page number */
|
|
||||||
PgHdr *sqlite3PcacheDirtyList(PCache *);
|
|
||||||
|
|
||||||
/* Reset and close the cache object */
|
|
||||||
void sqlite3PcacheClose(PCache *);
|
|
||||||
|
|
||||||
/* Clear flags from pages of the page cache */
|
|
||||||
void sqlite3PcacheClearSyncFlags(PCache *);
|
|
||||||
|
|
||||||
/* Discard the contents of the cache */
|
|
||||||
void sqlite3PcacheClear(PCache *);
|
|
||||||
|
|
||||||
/* Return the total number of outstanding page references */
|
|
||||||
int sqlite3PcacheRefCount(PCache *);
|
|
||||||
|
|
||||||
/* Increment the reference count of an existing page */
|
|
||||||
void sqlite3PcacheRef(PgHdr *);
|
|
||||||
|
|
||||||
int sqlite3PcachePageRefcount(PgHdr *);
|
|
||||||
|
|
||||||
/* Return the total number of pages stored in the cache */
|
|
||||||
int sqlite3PcachePagecount(PCache *);
|
|
||||||
|
|
||||||
#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
|
|
||||||
/* 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 sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(SQLITE_DEBUG)
|
|
||||||
/* Check invariants on a PgHdr object */
|
|
||||||
int sqlite3PcachePageSanity(PgHdr *);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Set and get the suggested cache-size for the specified pager-cache.
|
|
||||||
**
|
|
||||||
** 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
|
|
||||||
** of the suggested cache-sizes.
|
|
||||||
*/
|
|
||||||
void sqlite3PcacheSetCachesize(PCache *, int);
|
|
||||||
#ifdef SQLITE_TEST
|
|
||||||
int sqlite3PcacheGetCachesize(PCache *);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Set or get the suggested spill-size for the specified pager-cache.
|
|
||||||
**
|
|
||||||
** The spill-size is the minimum number of pages in cache before the cache
|
|
||||||
** will attempt to spill dirty pages by calling xStress.
|
|
||||||
*/
|
|
||||||
int sqlite3PcacheSetSpillsize(PCache *, int);
|
|
||||||
|
|
||||||
/* Free up as much memory as possible from the page cache */
|
|
||||||
void sqlite3PcacheShrink(PCache *);
|
|
||||||
|
|
||||||
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
|
||||||
/* Try to return memory used by the pcache module to the main memory heap */
|
|
||||||
int sqlite3PcacheReleaseMemory(int);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SQLITE_TEST
|
|
||||||
void sqlite3PcacheStats(int *, int *, int *, int *);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void sqlite3PCacheSetDefault(void);
|
|
||||||
|
|
||||||
/* Return the header size */
|
|
||||||
int sqlite3HeaderSizePcache(void);
|
|
||||||
int sqlite3HeaderSizePcache1(void);
|
|
||||||
|
|
||||||
/* Number of dirty pages as a percentage of the configured cache size */
|
|
||||||
int sqlite3PCachePercentDirty(PCache *);
|
|
||||||
|
|
||||||
#ifdef SQLITE_DIRECT_OVERFLOW_READ
|
|
||||||
int sqlite3PCacheIsDirty(PCache *pCache);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// For real implementation of sqlite3_pcache ========================================
|
|
||||||
typedef struct sqlite3_pcache sqlite3_pcache;
|
|
||||||
typedef struct sqlite3_pcache_methods2 {
|
|
||||||
int iVersion;
|
|
||||||
void *pArg;
|
|
||||||
int (*xInit)(void *);
|
|
||||||
void (*xShutdown)(void *);
|
|
||||||
sqlite3_pcache *(*xCreate)(int szPage, int szExtra, int bPurgeable);
|
|
||||||
void (*xCachesize)(sqlite3_pcache *, int nCachesize);
|
|
||||||
int (*xPagecount)(sqlite3_pcache *);
|
|
||||||
sqlite3_pcache_page *(*xFetch)(sqlite3_pcache *, unsigned key, int createFlag);
|
|
||||||
void (*xUnpin)(sqlite3_pcache *, sqlite3_pcache_page *, int discard);
|
|
||||||
void (*xRekey)(sqlite3_pcache *, sqlite3_pcache_page *, unsigned oldKey, unsigned newKey);
|
|
||||||
void (*xTruncate)(sqlite3_pcache *, unsigned iLimit);
|
|
||||||
void (*xDestroy)(sqlite3_pcache *);
|
|
||||||
void (*xShrink)(sqlite3_pcache *);
|
|
||||||
} sqlite3_pcache_methods2;
|
|
||||||
|
|
||||||
extern sqlite3_pcache_methods2 pcache2;
|
|
||||||
|
|
||||||
#endif /* _PCACHE_H_ */
|
|
|
@ -1,95 +0,0 @@
|
||||||
/*
|
|
||||||
** 2001-09-15
|
|
||||||
**
|
|
||||||
** 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 header file defines the interface that the SQLite library
|
|
||||||
** presents to client programs. If a C-function, structure, datatype,
|
|
||||||
** or constant definition does not appear in this file, then it is
|
|
||||||
** not a published API of SQLite, is subject to change without
|
|
||||||
** notice, and should not be referenced by programs that use SQLite.
|
|
||||||
**
|
|
||||||
** Some of the definitions that are in this file are marked as
|
|
||||||
** "experimental". Experimental interfaces are normally new
|
|
||||||
** features recently added to SQLite. We do not anticipate changes
|
|
||||||
** to experimental interfaces but reserve the right to make minor changes
|
|
||||||
** if experience from use "in the wild" suggest such changes are prudent.
|
|
||||||
**
|
|
||||||
** The official C-language API documentation for SQLite is derived
|
|
||||||
** from comments in this file. This file is the authoritative source
|
|
||||||
** on how SQLite interfaces are supposed to operate.
|
|
||||||
**
|
|
||||||
** The name of this file under configuration management is "sqlite.h.in".
|
|
||||||
** The makefile makes some minor changes to this file (such as inserting
|
|
||||||
** the version number) and changes its name to "sqlite3.h" as
|
|
||||||
** part of the build process.
|
|
||||||
*/
|
|
||||||
#ifndef SQLITE3_H
|
|
||||||
#define SQLITE3_H
|
|
||||||
#include <stdarg.h> /* Needed for the definition of va_list */
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Make sure we can call this stuff from C++.
|
|
||||||
*/
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
** CAPI3REF: Result Codes
|
|
||||||
** KEYWORDS: {result code definitions}
|
|
||||||
**
|
|
||||||
** Many SQLite functions return an integer result code from the set shown
|
|
||||||
** here in order to indicate success or failure.
|
|
||||||
**
|
|
||||||
** New error codes may be added in future versions of SQLite.
|
|
||||||
**
|
|
||||||
** See also: [extended result code definitions]
|
|
||||||
*/
|
|
||||||
#define SQLITE_OK 0 /* Successful result */
|
|
||||||
/* beginning-of-error-codes */
|
|
||||||
#define SQLITE_ERROR 1 /* Generic error */
|
|
||||||
#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */
|
|
||||||
#define SQLITE_PERM 3 /* Access permission denied */
|
|
||||||
#define SQLITE_ABORT 4 /* Callback routine requested an abort */
|
|
||||||
#define SQLITE_BUSY 5 /* The database file is locked */
|
|
||||||
#define SQLITE_LOCKED 6 /* A table in the database is locked */
|
|
||||||
#define SQLITE_NOMEM 7 /* A malloc() failed */
|
|
||||||
#define SQLITE_READONLY 8 /* Attempt to write a readonly database */
|
|
||||||
#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/
|
|
||||||
#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */
|
|
||||||
#define SQLITE_CORRUPT 11 /* The database disk image is malformed */
|
|
||||||
#define SQLITE_NOTFOUND 12 /* Unknown opcode in sqlite3_file_control() */
|
|
||||||
#define SQLITE_FULL 13 /* Insertion failed because database is full */
|
|
||||||
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
|
|
||||||
#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
|
|
||||||
#define SQLITE_EMPTY 16 /* Internal use only */
|
|
||||||
#define SQLITE_SCHEMA 17 /* The database schema changed */
|
|
||||||
#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */
|
|
||||||
#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */
|
|
||||||
#define SQLITE_MISMATCH 20 /* Data type mismatch */
|
|
||||||
#define SQLITE_MISUSE 21 /* Library used incorrectly */
|
|
||||||
#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
|
|
||||||
#define SQLITE_AUTH 23 /* Authorization denied */
|
|
||||||
#define SQLITE_FORMAT 24 /* Not used */
|
|
||||||
#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */
|
|
||||||
#define SQLITE_NOTADB 26 /* File opened that is not a database file */
|
|
||||||
#define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */
|
|
||||||
#define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */
|
|
||||||
#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */
|
|
||||||
#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
|
|
||||||
/* end-of-error-codes */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
} /* end of the 'extern "C"' block */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* _FTS5_H */
|
|
||||||
|
|
||||||
/******** End of fts5.h *********/
|
|
|
@ -1,58 +0,0 @@
|
||||||
/*
|
|
||||||
** 2001 September 15
|
|
||||||
**
|
|
||||||
** 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.
|
|
||||||
**
|
|
||||||
*************************************************************************
|
|
||||||
** Internal interface definitions for SQLite.
|
|
||||||
**
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#ifndef SQLITEINT_H
|
|
||||||
#define SQLITEINT_H
|
|
||||||
|
|
||||||
#include "sqlite3.h"
|
|
||||||
|
|
||||||
typedef int8_t i8;
|
|
||||||
typedef int16_t i16;
|
|
||||||
typedef int32_t i32;
|
|
||||||
typedef int64_t i64;
|
|
||||||
typedef uint8_t u8;
|
|
||||||
typedef uint16_t u16;
|
|
||||||
typedef uint32_t u32;
|
|
||||||
typedef uint64_t u64;
|
|
||||||
|
|
||||||
typedef struct sqlite3_pcache_page {
|
|
||||||
void *pBuf; /* The content of the page */
|
|
||||||
void *pExtra; /* Extra information associated with the page */
|
|
||||||
} sqlite3_pcache_page;
|
|
||||||
|
|
||||||
#define ROUNDDOWN8(x) ((x) & ~7)
|
|
||||||
|
|
||||||
#define ROUND8(x) (((x) + 7) & ~7)
|
|
||||||
|
|
||||||
typedef struct sqlite3_vfs sqlite3_vfs;
|
|
||||||
typedef struct sqlite3 sqlite3;
|
|
||||||
|
|
||||||
#define SQLITE_DEFAULT_PAGE_SIZE 4096
|
|
||||||
|
|
||||||
#include "pager.h"
|
|
||||||
|
|
||||||
#include "pcache.h"
|
|
||||||
|
|
||||||
#endif /* SQLITEINT_H */
|
|
|
@ -1,155 +0,0 @@
|
||||||
/*
|
|
||||||
** 2010 February 1
|
|
||||||
**
|
|
||||||
** 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 header file defines the interface to the write-ahead logging
|
|
||||||
** system. Refer to the comments below and the header comment attached to
|
|
||||||
** the implementation of each function in log.c for further details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SQLITE_WAL_H
|
|
||||||
#define SQLITE_WAL_H
|
|
||||||
|
|
||||||
#include "sqliteInt.h"
|
|
||||||
|
|
||||||
/* Macros for extracting appropriate sync flags for either transaction
|
|
||||||
** commits (WAL_SYNC_FLAGS(X)) or for checkpoint ops (CKPT_SYNC_FLAGS(X)):
|
|
||||||
*/
|
|
||||||
#define WAL_SYNC_FLAGS(X) ((X)&0x03)
|
|
||||||
#define CKPT_SYNC_FLAGS(X) (((X)>>2)&0x03)
|
|
||||||
|
|
||||||
#ifdef SQLITE_OMIT_WAL
|
|
||||||
# define sqlite3WalOpen(x,y,z) 0
|
|
||||||
# define sqlite3WalLimit(x,y)
|
|
||||||
# define sqlite3WalClose(v,w,x,y,z) 0
|
|
||||||
# define sqlite3WalBeginReadTransaction(y,z) 0
|
|
||||||
# define sqlite3WalEndReadTransaction(z)
|
|
||||||
# define sqlite3WalDbsize(y) 0
|
|
||||||
# define sqlite3WalBeginWriteTransaction(y) 0
|
|
||||||
# define sqlite3WalEndWriteTransaction(x) 0
|
|
||||||
# define sqlite3WalUndo(x,y,z) 0
|
|
||||||
# define sqlite3WalSavepoint(y,z)
|
|
||||||
# define sqlite3WalSavepointUndo(y,z) 0
|
|
||||||
# define sqlite3WalFrames(u,v,w,x,y,z) 0
|
|
||||||
# define sqlite3WalCheckpoint(q,r,s,t,u,v,w,x,y,z) 0
|
|
||||||
# define sqlite3WalCallback(z) 0
|
|
||||||
# define sqlite3WalExclusiveMode(y,z) 0
|
|
||||||
# define sqlite3WalHeapMemory(z) 0
|
|
||||||
# define sqlite3WalFramesize(z) 0
|
|
||||||
# define sqlite3WalFindFrame(x,y,z) 0
|
|
||||||
# define sqlite3WalFile(x) 0
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define WAL_SAVEPOINT_NDATA 4
|
|
||||||
|
|
||||||
/* Connection to a write-ahead log (WAL) file.
|
|
||||||
** There is one object of this type for each pager.
|
|
||||||
*/
|
|
||||||
typedef struct Wal Wal;
|
|
||||||
|
|
||||||
/* Open and close a connection to a write-ahead log. */
|
|
||||||
int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *, int, i64, Wal**);
|
|
||||||
int sqlite3WalClose(Wal *pWal, sqlite3*, int sync_flags, int, u8 *);
|
|
||||||
|
|
||||||
/* Set the limiting size of a WAL file. */
|
|
||||||
void sqlite3WalLimit(Wal*, i64);
|
|
||||||
|
|
||||||
/* Used by readers to open (lock) and close (unlock) a snapshot. A
|
|
||||||
** snapshot is like a read-transaction. It is the state of the database
|
|
||||||
** at an instant in time. sqlite3WalOpenSnapshot gets a read lock and
|
|
||||||
** preserves the current state even if the other threads or processes
|
|
||||||
** write to or checkpoint the WAL. sqlite3WalCloseSnapshot() closes the
|
|
||||||
** transaction and releases the lock.
|
|
||||||
*/
|
|
||||||
int sqlite3WalBeginReadTransaction(Wal *pWal, int *);
|
|
||||||
void sqlite3WalEndReadTransaction(Wal *pWal);
|
|
||||||
|
|
||||||
/* Read a page from the write-ahead log, if it is present. */
|
|
||||||
int sqlite3WalFindFrame(Wal *, Pgno, u32 *);
|
|
||||||
int sqlite3WalReadFrame(Wal *, u32, int, u8 *);
|
|
||||||
|
|
||||||
/* If the WAL is not empty, return the size of the database. */
|
|
||||||
Pgno sqlite3WalDbsize(Wal *pWal);
|
|
||||||
|
|
||||||
/* Obtain or release the WRITER lock. */
|
|
||||||
int sqlite3WalBeginWriteTransaction(Wal *pWal);
|
|
||||||
int sqlite3WalEndWriteTransaction(Wal *pWal);
|
|
||||||
|
|
||||||
/* Undo any frames written (but not committed) to the log */
|
|
||||||
int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx);
|
|
||||||
|
|
||||||
/* Return an integer that records the current (uncommitted) write
|
|
||||||
** position in the WAL */
|
|
||||||
void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData);
|
|
||||||
|
|
||||||
/* Move the write position of the WAL back to iFrame. Called in
|
|
||||||
** response to a ROLLBACK TO command. */
|
|
||||||
int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData);
|
|
||||||
|
|
||||||
/* Write a frame or frames to the log. */
|
|
||||||
int sqlite3WalFrames(Wal *pWal, int, PgHdr *, Pgno, int, int);
|
|
||||||
|
|
||||||
/* Copy pages from the log to the database file */
|
|
||||||
int sqlite3WalCheckpoint(
|
|
||||||
Wal *pWal, /* Write-ahead log connection */
|
|
||||||
sqlite3 *db, /* Check this handle's interrupt flag */
|
|
||||||
int eMode, /* One of PASSIVE, FULL and RESTART */
|
|
||||||
int (*xBusy)(void*), /* Function to call when busy */
|
|
||||||
void *pBusyArg, /* Context argument for xBusyHandler */
|
|
||||||
int sync_flags, /* Flags to sync db file with (or 0) */
|
|
||||||
int nBuf, /* Size of buffer nBuf */
|
|
||||||
u8 *zBuf, /* Temporary buffer to use */
|
|
||||||
int *pnLog, /* OUT: Number of frames in WAL */
|
|
||||||
int *pnCkpt /* OUT: Number of backfilled frames in WAL */
|
|
||||||
);
|
|
||||||
|
|
||||||
/* Return the value to pass to a sqlite3_wal_hook callback, the
|
|
||||||
** number of frames in the WAL at the point of the last commit since
|
|
||||||
** sqlite3WalCallback() was called. If no commits have occurred since
|
|
||||||
** the last call, then return 0.
|
|
||||||
*/
|
|
||||||
int sqlite3WalCallback(Wal *pWal);
|
|
||||||
|
|
||||||
/* Tell the wal layer that an EXCLUSIVE lock has been obtained (or released)
|
|
||||||
** by the pager layer on the database file.
|
|
||||||
*/
|
|
||||||
int sqlite3WalExclusiveMode(Wal *pWal, int op);
|
|
||||||
|
|
||||||
/* Return true if the argument is non-NULL and the WAL module is using
|
|
||||||
** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
|
|
||||||
** WAL module is using shared-memory, return false.
|
|
||||||
*/
|
|
||||||
int sqlite3WalHeapMemory(Wal *pWal);
|
|
||||||
|
|
||||||
#ifdef SQLITE_ENABLE_SNAPSHOT
|
|
||||||
int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot);
|
|
||||||
void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot);
|
|
||||||
int sqlite3WalSnapshotRecover(Wal *pWal);
|
|
||||||
int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot);
|
|
||||||
void sqlite3WalSnapshotUnlock(Wal *pWal);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SQLITE_ENABLE_ZIPVFS
|
|
||||||
/* If the WAL file is not empty, return the number of bytes of content
|
|
||||||
** stored in each frame (i.e. the db page-size when the WAL was created).
|
|
||||||
*/
|
|
||||||
int sqlite3WalFramesize(Wal *pWal);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Return the sqlite3_file object for the WAL file */
|
|
||||||
sqlite3_file *sqlite3WalFile(Wal *pWal);
|
|
||||||
|
|
||||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
||||||
int sqlite3WalWriteLock(Wal *pWal, int bLock);
|
|
||||||
void sqlite3WalDb(Wal *pWal, sqlite3 *db);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* ifndef SQLITE_OMIT_WAL */
|
|
||||||
#endif /* SQLITE_WAL_H */
|
|
Loading…
Reference in New Issue