Upgraded bundled sqlite lib to 3.2.2

This commit is contained in:
Ilia Alshanetsky 2005-06-30 20:58:36 +00:00
parent efc6ccaa01
commit 7d02c9dcb2
51 changed files with 5222 additions and 3790 deletions

View file

@ -20,6 +20,7 @@
**
** @(#) $Id$
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
#include "os.h"
#include "pager.h"
@ -171,7 +172,7 @@ struct PgHdr {
#ifdef SQLITE_CHECK_PAGES
u32 pageHash;
#endif
/* pPager->psAligned bytes of page data follow this header */
/* pPager->pageSize bytes of page data follow this header */
/* Pager.nExtra bytes of local data follow the page data */
};
@ -207,15 +208,22 @@ struct PgHistory {
*/
#define PGHDR_TO_DATA(P) ((void*)(&(P)[1]))
#define DATA_TO_PGHDR(D) (&((PgHdr*)(D))[-1])
#define PGHDR_TO_EXTRA(G,P) ((void*)&((char*)(&(G)[1]))[(P)->psAligned])
#define PGHDR_TO_EXTRA(G,P) ((void*)&((char*)(&(G)[1]))[(P)->pageSize])
#define PGHDR_TO_HIST(P,PGR) \
((PgHistory*)&((char*)(&(P)[1]))[(PGR)->psAligned+(PGR)->nExtra])
((PgHistory*)&((char*)(&(P)[1]))[(PGR)->pageSize+(PGR)->nExtra])
/*
** How big to make the hash table used for locating in-memory pages
** by page number.
** by page number. This macro looks a little silly, but is evaluated
** at compile-time, not run-time (at least for gcc this is true).
*/
#define N_PG_HASH 2048
#define N_PG_HASH (\
(MAX_PAGES>1024)?2048: \
(MAX_PAGES>512)?1024: \
(MAX_PAGES>256)?512: \
(MAX_PAGES>128)?256: \
(MAX_PAGES>64)?128:64 \
)
/*
** Hash a page number
@ -226,30 +234,6 @@ struct PgHistory {
** A open page cache is an instance of the following structure.
*/
struct Pager {
char *zFilename; /* Name of the database file */
char *zJournal; /* Name of the journal file */
char *zDirectory; /* Directory hold database and journal files */
OsFile fd, jfd; /* File descriptors for database and journal */
OsFile stfd; /* File descriptor for the statement subjournal*/
int dbSize; /* Number of pages in the file */
int origDbSize; /* dbSize before the current change */
int stmtSize; /* Size of database (in pages) at stmt_begin() */
i64 stmtJSize; /* Size of journal at stmt_begin() */
int nRec; /* Number of pages written to the journal */
u32 cksumInit; /* Quasi-random value added to every checksum */
int stmtNRec; /* Number of records in stmt subjournal */
int nExtra; /* Add this many bytes to each in-memory page */
void (*xDestructor)(void*,int); /* Call this routine when freeing pages */
void (*xReiniter)(void*,int); /* Call this routine when reloading pages */
int pageSize; /* Number of bytes in a page */
int psAligned; /* pageSize rounded up to a multiple of 8 */
int nPage; /* Total number of in-memory pages */
int nRef; /* Number of in-memory pages with PgHdr.nRef>0 */
int mxPage; /* Maximum number of pages to hold in cache */
int nHit, nMiss, nOvfl; /* Cache hits, missing, and LRU overflows */
int nRead,nWrite; /* Database pages read/written */
void (*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
void *pCodecArg; /* First argument to xCodec() */
u8 journalOpen; /* True if journal file descriptors is valid */
u8 journalStarted; /* True if header of journal is synced */
u8 useJournal; /* Use a rollback journal on this file */
@ -267,9 +251,26 @@ struct Pager {
u8 dirtyCache; /* True if cached pages have changed */
u8 alwaysRollback; /* Disable dont_rollback() for all pages */
u8 memDb; /* True to inhibit all file I/O */
u8 setMaster; /* True if a m-j name has been written to jrnl */
int dbSize; /* Number of pages in the file */
int origDbSize; /* dbSize before the current change */
int stmtSize; /* Size of database (in pages) at stmt_begin() */
int nRec; /* Number of pages written to the journal */
u32 cksumInit; /* Quasi-random value added to every checksum */
int stmtNRec; /* Number of records in stmt subjournal */
int nExtra; /* Add this many bytes to each in-memory page */
int pageSize; /* Number of bytes in a page */
int nPage; /* Total number of in-memory pages */
int nMaxPage; /* High water mark of nPage */
int nRef; /* Number of in-memory pages with PgHdr.nRef>0 */
int mxPage; /* Maximum number of pages to hold in cache */
u8 *aInJournal; /* One bit for each page in the database file */
u8 *aInStmt; /* One bit for each page in the database */
u8 setMaster; /* True if a m-j name has been written to jrnl */
char *zFilename; /* Name of the database file */
char *zJournal; /* Name of the journal file */
char *zDirectory; /* Directory hold database and journal files */
OsFile fd, jfd; /* File descriptors for database and journal */
OsFile stfd; /* File descriptor for the statement subjournal*/
BusyHandler *pBusyHandler; /* Pointer to sqlite.busyHandler */
PgHdr *pFirst, *pLast; /* List of free pages */
PgHdr *pFirstSynced; /* First free page with PgHdr.needSync==0 */
@ -279,10 +280,29 @@ struct Pager {
i64 journalHdr; /* Byte offset to previous journal header */
i64 stmtHdrOff; /* First journal header written this statement */
i64 stmtCksum; /* cksumInit when statement was started */
i64 stmtJSize; /* Size of journal at stmt_begin() */
int sectorSize; /* Assumed sector size during rollback */
#ifdef SQLITE_TEST
int nHit, nMiss, nOvfl; /* Cache hits, missing, and LRU overflows */
int nRead,nWrite; /* Database pages read/written */
#endif
void (*xDestructor)(void*,int); /* Call this routine when freeing pages */
void (*xReiniter)(void*,int); /* Call this routine when reloading pages */
void (*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
void *pCodecArg; /* First argument to xCodec() */
PgHdr *aHash[N_PG_HASH]; /* Hash table to map page number to PgHdr */
};
/*
** If SQLITE_TEST is defined then increment the variable given in
** the argument
*/
#ifdef SQLITE_TEST
# define TEST_INCR(x) x++
#else
# define TEST_INCR(x)
#endif
/*
** These are bits that can be set in Pager.errMask.
*/
@ -822,6 +842,7 @@ static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){
*/
static void pager_reset(Pager *pPager){
PgHdr *pPg, *pNext;
if( pPager->errMask ) return;
for(pPg=pPager->pAll; pPg; pPg=pNext){
pNext = pPg->pNextAll;
sqliteFree(pPg);
@ -842,6 +863,29 @@ static void pager_reset(Pager *pPager){
assert( pPager->journalOpen==0 );
}
/*
** This function is used to reset the pager after a malloc() failure. This
** doesn't work with in-memory databases. If a malloc() fails when an
** in-memory database is in use it is not possible to recover.
**
** If a transaction or statement transaction is active, it is rolled back.
**
** It is an error to call this function if any pages are in use.
*/
#ifndef SQLITE_OMIT_GLOBALRECOVER
int sqlite3pager_reset(Pager *pPager){
if( pPager ){
if( pPager->nRef || MEMDB ){
return SQLITE_ERROR;
}
pPager->errMask &= ~(PAGER_ERR_MEM);
pager_reset(pPager);
}
return SQLITE_OK;
}
#endif
/*
** When this routine is called, the pager has the journal file open and
** a RESERVED or EXCLUSIVE lock on the database. This routine releases
@ -881,6 +925,7 @@ static int pager_unwritelock(Pager *pPager){
pPager->dirtyCache = 0;
pPager->nRec = 0;
}else{
assert( pPager->aInJournal==0 );
assert( pPager->dirtyCache==0 || pPager->useJournal==0 );
}
rc = sqlite3OsUnlock(&pPager->fd, SHARED_LOCK);
@ -935,6 +980,12 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
u32 cksum; /* Checksum used for sanity checking */
u8 aData[SQLITE_MAX_PAGE_SIZE]; /* Temp storage for a page */
/* useCksum should be true for the main journal and false for
** statement journals. Verify that this is always the case
*/
assert( jfd == (useCksum ? &pPager->jfd : &pPager->stfd) );
rc = read32bits(jfd, &pgno);
if( rc!=SQLITE_OK ) return rc;
rc = sqlite3OsRead(jfd, &aData, pPager->pageSize);
@ -969,13 +1020,27 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
**
** If in EXCLUSIVE state, then we update the pager cache if it exists
** and the main file. The page is then marked not dirty.
**
** Ticket #1171: The statement journal might contain page content that is
** different from the page content at the start of the transaction.
** This occurs when a page is changed prior to the start of a statement
** then changed again within the statement. When rolling back such a
** statement we must not write to the original database unless we know
** for certain that original page contents are in the main rollback
** journal. Otherwise, if a full ROLLBACK occurs after the statement
** rollback the full ROLLBACK will not restore the page to its original
** content. Two conditions must be met before writing to the database
** files. (1) the database must be locked. (2) we know that the original
** page content is in the main journal either because the page is not in
** cache or else it is marked as needSync==0.
*/
pPg = pager_lookup(pPager, pgno);
assert( pPager->state>=PAGER_EXCLUSIVE || pPg );
assert( pPager->state>=PAGER_EXCLUSIVE || pPg!=0 );
TRACE3("PLAYBACK %d page %d\n", PAGERID(pPager), pgno);
if( pPager->state>=PAGER_EXCLUSIVE ){
if( pPager->state>=PAGER_EXCLUSIVE && (pPg==0 || pPg->needSync==0) ){
sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
rc = sqlite3OsWrite(&pPager->fd, aData, pPager->pageSize);
if( pPg ) pPg->dirty = 0;
}
if( pPg ){
/* No page should ever be explicitly rolled back that is in use, except
@ -991,13 +1056,9 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
if( pPager->xDestructor ){ /*** FIX ME: Should this be xReinit? ***/
pPager->xDestructor(pData, pPager->pageSize);
}
if( pPager->state>=PAGER_EXCLUSIVE ){
pPg->dirty = 0;
pPg->needSync = 0;
#ifdef SQLITE_CHECK_PAGES
pPg->pageHash = pager_pagehash(pPg);
pPg->pageHash = pager_pagehash(pPg);
#endif
}
CODEC(pPager, pData, pPg->pgno, 3);
}
return rc;
@ -1434,22 +1495,8 @@ end_stmt_playback:
/*
** Change the maximum number of in-memory pages that are allowed.
**
** The maximum number is the absolute value of the mxPage parameter.
** If mxPage is negative, the noSync flag is also set. noSync bypasses
** calls to sqlite3OsSync(). The pager runs much faster with noSync on,
** but if the operating system crashes or there is an abrupt power
** failure, the database file might be left in an inconsistent and
** unrepairable state.
*/
void sqlite3pager_set_cachesize(Pager *pPager, int mxPage){
if( mxPage>=0 ){
pPager->noSync = pPager->tempFile;
if( pPager->noSync ) pPager->needSync = 0;
}else{
pPager->noSync = 1;
mxPage = -mxPage;
}
if( mxPage>10 ){
pPager->mxPage = mxPage;
}else{
@ -1492,8 +1539,15 @@ void sqlite3pager_set_safety_level(Pager *pPager, int level){
#endif
/*
** Open a temporary file. Write the name of the file into zName
** (zName must be at least SQLITE_TEMPNAME_SIZE bytes long.) Write
** The following global variable is incremented whenever the library
** attempts to open a temporary file. This information is used for
** testing and analysis only.
*/
int sqlite3_opentemp_count = 0;
/*
** Open a temporary file. Write the name of the file into zFile
** (zFile must be at least SQLITE_TEMPNAME_SIZE bytes long.) Write
** the file descriptor into *fd. Return SQLITE_OK on success or some
** other error code if we fail.
**
@ -1503,6 +1557,7 @@ void sqlite3pager_set_safety_level(Pager *pPager, int level){
static int sqlite3pager_opentemp(char *zFile, OsFile *fd){
int cnt = 8;
int rc;
sqlite3_opentemp_count++; /* Used for testing and analysis only */
do{
cnt--;
sqlite3OsTempFileName(zFile);
@ -1610,10 +1665,10 @@ int sqlite3pager_open(
pPager->nRef = 0;
pPager->dbSize = memDb-1;
pPager->pageSize = SQLITE_DEFAULT_PAGE_SIZE;
pPager->psAligned = FORCE_ALIGNMENT(pPager->pageSize);
pPager->stmtSize = 0;
pPager->stmtJSize = 0;
pPager->nPage = 0;
pPager->nMaxPage = 0;
pPager->mxPage = 100;
pPager->state = PAGER_UNLOCK;
pPager->errMask = 0;
@ -1665,14 +1720,16 @@ void sqlite3pager_set_reiniter(Pager *pPager, void (*xReinit)(void*,int)){
}
/*
** Set the page size.
**
** The page size must only be changed when the cache is empty.
** Set the page size. Return the new size. If the suggest new page
** size is inappropriate, then an alternative page size is selected
** and returned.
*/
void sqlite3pager_set_pagesize(Pager *pPager, int pageSize){
int sqlite3pager_set_pagesize(Pager *pPager, int pageSize){
assert( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE );
pPager->pageSize = pageSize;
pPager->psAligned = FORCE_ALIGNMENT(pageSize);
if( !pPager->memDb ){
pPager->pageSize = pageSize;
}
return pPager->pageSize;
}
/*
@ -1824,12 +1881,12 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
rc = SQLITE_OK;
}else{
int busy = 1;
BusyHandler *pH;
do {
rc = sqlite3OsLock(&pPager->fd, locktype);
}while( rc==SQLITE_BUSY &&
pPager->pBusyHandler &&
pPager->pBusyHandler->xFunc &&
pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, busy++)
(pH = pPager->pBusyHandler)!=0 &&
pH->xFunc && pH->xFunc(pH->pArg, busy++)
);
if( rc==SQLITE_OK ){
pPager->state = locktype;
@ -1905,7 +1962,7 @@ int sqlite3pager_close(Pager *pPager){
if( !MEMDB ){
sqlite3OsUnlock(&pPager->fd, NO_LOCK);
}
assert( pPager->journalOpen==0 );
assert( pPager->errMask || pPager->journalOpen==0 );
break;
}
case PAGER_SHARED: {
@ -1932,8 +1989,15 @@ int sqlite3pager_close(Pager *pPager){
sqliteFree(pPg);
}
TRACE2("CLOSE %d\n", PAGERID(pPager));
assert( pPager->errMask || (pPager->journalOpen==0 && pPager->stmtOpen==0) );
if( pPager->journalOpen ){
sqlite3OsClose(&pPager->jfd);
}
sqliteFree(pPager->aInJournal);
if( pPager->stmtOpen ){
sqlite3OsClose(&pPager->stfd);
}
sqlite3OsClose(&pPager->fd);
assert( pPager->journalOpen==0 );
/* Temp files are automatically deleted by the OS
** if( pPager->tempFile ){
** sqlite3OsDelete(pPager->zFilename);
@ -2144,7 +2208,7 @@ static int pager_write_pagelist(PgHdr *pList){
TRACE3("STORE %d page %d\n", PAGERID(pPager), pList->pgno);
rc = sqlite3OsWrite(&pPager->fd, PGHDR_TO_DATA(pList), pPager->pageSize);
CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 0);
pPager->nWrite++;
TEST_INCR(pPager->nWrite);
}
#ifndef NDEBUG
else{
@ -2178,6 +2242,26 @@ static PgHdr *pager_get_all_dirty_pages(Pager *pPager){
return pList;
}
/*
** Return TRUE if there is a hot journal on the given pager.
** A hot journal is one that needs to be played back.
**
** If the current size of the database file is 0 but a journal file
** exists, that is probably an old journal left over from a prior
** database with the same name. Just delete the journal.
*/
static int hasHotJournal(Pager *pPager){
if( !pPager->useJournal ) return 0;
if( !sqlite3OsFileExists(pPager->zJournal) ) return 0;
if( sqlite3OsCheckReservedLock(&pPager->fd) ) return 0;
if( sqlite3pager_pagecount(pPager)==0 ){
sqlite3OsDelete(pPager->zJournal);
return 0;
}else{
return 1;
}
}
/*
** Acquire a page.
**
@ -2203,7 +2287,7 @@ static PgHdr *pager_get_all_dirty_pages(Pager *pPager){
*/
int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
PgHdr *pPg;
int rc, n;
int rc;
/* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page
** number greater than this, or zero, is requested.
@ -2234,10 +2318,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
/* If a journal file exists, and there is no RESERVED lock on the
** database file, then it either needs to be played back or deleted.
*/
if( pPager->useJournal &&
sqlite3OsFileExists(pPager->zJournal) &&
!sqlite3OsCheckReservedLock(&pPager->fd)
){
if( hasHotJournal(pPager) ){
int rc;
/* Get an EXCLUSIVE lock on the database file. At this point it is
@ -2298,16 +2379,13 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
if( pPg==0 ){
/* The requested page is not in the page cache. */
int h;
pPager->nMiss++;
TEST_INCR(pPager->nMiss);
if( pPager->nPage<pPager->mxPage || pPager->pFirst==0 || MEMDB ){
/* Create a new page */
pPg = sqliteMallocRaw( sizeof(*pPg) + pPager->psAligned
pPg = sqliteMallocRaw( sizeof(*pPg) + pPager->pageSize
+ sizeof(u32) + pPager->nExtra
+ MEMDB*sizeof(PgHistory) );
if( pPg==0 ){
if( !MEMDB ){
pager_unwritelock(pPager);
}
pPager->errMask |= PAGER_ERR_MEM;
return SQLITE_NOMEM;
}
@ -2319,6 +2397,10 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
pPg->pNextAll = pPager->pAll;
pPager->pAll = pPg;
pPager->nPage++;
if( pPager->nPage>pPager->nMaxPage ){
assert( pPager->nMaxPage==(pPager->nPage-1) );
pPager->nMaxPage++;
}
}else{
/* Find a page to recycle. Try to locate a page that does not
** require us to do an fsync() on the journal.
@ -2383,7 +2465,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
/* Unlink the old page from the free list and the hash table
*/
unlinkPage(pPg);
pPager->nOvfl++;
TEST_INCR(pPager->nOvfl);
}
pPg->pgno = pgno;
if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){
@ -2415,13 +2497,12 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
if( pPager->nExtra>0 ){
memset(PGHDR_TO_EXTRA(pPg, pPager), 0, pPager->nExtra);
}
n = sqlite3pager_pagecount(pPager);
if( pPager->errMask!=0 ){
sqlite3pager_unref(PGHDR_TO_DATA(pPg));
rc = pager_errcode(pPager);
return rc;
}
if( n<(int)pgno ){
if( sqlite3pager_pagecount(pPager)<(int)pgno ){
memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize);
}else{
int rc;
@ -2440,7 +2521,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize);
}
}else{
pPager->nRead++;
TEST_INCR(pPager->nRead);
}
}
#ifdef SQLITE_CHECK_PAGES
@ -2448,7 +2529,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
#endif
}else{
/* The requested page is in the page cache. */
pPager->nHit++;
TEST_INCR(pPager->nHit);
page_ref(pPg);
}
*ppPage = PGHDR_TO_DATA(pPg);
@ -2546,6 +2627,7 @@ static int pager_open_journal(Pager *pPager){
assert( pPager->state>=PAGER_RESERVED );
assert( pPager->journalOpen==0 );
assert( pPager->useJournal );
assert( pPager->aInJournal==0 );
sqlite3pager_pagecount(pPager);
pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 );
if( pPager->aInJournal==0 ){
@ -2559,6 +2641,8 @@ static int pager_open_journal(Pager *pPager){
if( rc!=SQLITE_OK ){
goto failed_to_open_journal;
}
SET_FULLSYNC(pPager->jfd, pPager->fullSync);
SET_FULLSYNC(pPager->fd, pPager->fullSync);
sqlite3OsOpenDirectory(pPager->zDirectory, &pPager->jfd);
pPager->journalOpen = 1;
pPager->journalStarted = 0;
@ -2567,7 +2651,7 @@ static int pager_open_journal(Pager *pPager){
pPager->nRec = 0;
if( pPager->errMask!=0 ){
rc = pager_errcode(pPager);
return rc;
goto failed_to_open_journal;
}
pPager->origDbSize = pPager->dbSize;
@ -2631,11 +2715,7 @@ int sqlite3pager_begin(void *pData, int exFlag){
pPager->state = PAGER_EXCLUSIVE;
pPager->origDbSize = pPager->dbSize;
}else{
if( SQLITE_BUSY_RESERVED_LOCK || exFlag ){
rc = pager_wait_on_lock(pPager, RESERVED_LOCK);
}else{
rc = sqlite3OsLock(&pPager->fd, RESERVED_LOCK);
}
rc = sqlite3OsLock(&pPager->fd, RESERVED_LOCK);
if( rc==SQLITE_OK ){
pPager->state = PAGER_RESERVED;
if( exFlag ){
@ -3118,11 +3198,13 @@ int *sqlite3pager_stats(Pager *pPager){
a[3] = pPager->dbSize;
a[4] = pPager->state;
a[5] = pPager->errMask;
#ifdef SQLITE_TEST
a[6] = pPager->nHit;
a[7] = pPager->nMiss;
a[8] = pPager->nOvfl;
a[9] = pPager->nRead;
a[10] = pPager->nWrite;
#endif
return a;
}
@ -3406,8 +3488,10 @@ sync_exit:
** meta-data associated with page pData (i.e. data stored in the nExtra bytes
** allocated along with the page) is the responsibility of the caller.
**
** A transaction must be active when this routine is called, however it is
** illegal to call this routine if a statment transaction is active.
** A transaction must be active when this routine is called. It used to be
** required that a statement transaction was not active, but this restriction
** has been removed (CREATE INDEX needs to move a page when a statement
** transaction is active).
*/
int sqlite3pager_movepage(Pager *pPager, void *pData, Pgno pgno){
PgHdr *pPg = DATA_TO_PGHDR(pData);
@ -3415,7 +3499,6 @@ int sqlite3pager_movepage(Pager *pPager, void *pData, Pgno pgno){
int h;
Pgno needSyncPgno = 0;
assert( !pPager->stmtInUse );
assert( pPg->nRef>0 );
TRACE5("MOVE %d page %d (needSync=%d) moves to %d\n",
@ -3517,3 +3600,5 @@ void sqlite3pager_refdump(Pager *pPager){
}
}
#endif
#endif /* SQLITE_OMIT_DISKIO */