summaryrefslogtreecommitdiff
path: root/ext/pdo_sqlite/sqlite/src/pager.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/pdo_sqlite/sqlite/src/pager.c')
-rw-r--r--ext/pdo_sqlite/sqlite/src/pager.c152
1 files changed, 71 insertions, 81 deletions
diff --git a/ext/pdo_sqlite/sqlite/src/pager.c b/ext/pdo_sqlite/sqlite/src/pager.c
index 7f4b6f952f..cb042cf329 100644
--- a/ext/pdo_sqlite/sqlite/src/pager.c
+++ b/ext/pdo_sqlite/sqlite/src/pager.c
@@ -31,6 +31,7 @@
** Macros for troubleshooting. Normally turned off
*/
#if 0
+#define sqlite3DebugPrintf printf
#define TRACE1(X) sqlite3DebugPrintf(X)
#define TRACE2(X,Y) sqlite3DebugPrintf(X,Y)
#define TRACE3(X,Y,Z) sqlite3DebugPrintf(X,Y,Z)
@@ -231,7 +232,6 @@ struct Pager {
u8 fullSync; /* Do extra syncs of the journal for robustness */
u8 full_fsync; /* Use F_FULLFSYNC when available */
u8 state; /* PAGER_UNLOCK, _SHARED, _RESERVED, etc. */
- u8 errCode; /* One of several kinds of errors */
u8 tempFile; /* zFilename is a temporary file */
u8 readOnly; /* True for a read-only database */
u8 needSync; /* True if an fsync() is needed on the journal */
@@ -239,6 +239,7 @@ struct Pager {
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 errCode; /* One of several kinds of errors */
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() */
@@ -350,7 +351,9 @@ static const unsigned char aJournalMagic[] = {
/*
** The default size of a disk sector
*/
-#define PAGER_SECTOR_SIZE 512
+#ifndef PAGER_SECTOR_SIZE
+# define PAGER_SECTOR_SIZE 512
+#endif
/*
** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is
@@ -376,8 +379,8 @@ static const unsigned char aJournalMagic[] = {
static int cnt = 0;
if( !pager3_refinfo_enable ) return;
sqlite3DebugPrintf(
- "REFCNT: %4d addr=%p nRef=%d\n",
- p->pgno, PGHDR_TO_DATA(p), p->nRef
+ "REFCNT: %4d addr=%p nRef=%-3d total=%d\n",
+ p->pgno, PGHDR_TO_DATA(p), p->nRef, p->pPager->nRef
);
cnt++; /* Something to set a breakpoint on */
}
@@ -476,12 +479,13 @@ static u32 retrieve32bits(PgHdr *p, int offset){
** will immediately return the same error code.
*/
static int pager_error(Pager *pPager, int rc){
+ int rc2 = rc & 0xff;
assert( pPager->errCode==SQLITE_FULL || pPager->errCode==SQLITE_OK );
if(
- rc==SQLITE_FULL ||
- rc==SQLITE_IOERR ||
- rc==SQLITE_CORRUPT ||
- rc==SQLITE_PROTOCOL
+ rc2==SQLITE_FULL ||
+ rc2==SQLITE_IOERR ||
+ rc2==SQLITE_CORRUPT ||
+ rc2==SQLITE_PROTOCOL
){
pPager->errCode = rc;
}
@@ -847,6 +851,23 @@ static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){
}
/*
+** Unlock the database file.
+**
+** Once all locks have been removed from the database file, other
+** processes or threads might change the file. So make sure all of
+** our internal cache is invalidated.
+*/
+static void pager_unlock(Pager *pPager){
+ if( !MEMDB ){
+ sqlite3OsUnlock(pPager->fd, NO_LOCK);
+ pPager->dbSize = -1;
+ }
+ pPager->state = PAGER_UNLOCK;
+ assert( pPager->pAll==0 );
+}
+
+
+/*
** Unlock the database and clear the in-memory cache. This routine
** sets the state of the pager back to what it was when it was first
** opened. Any outstanding pages are invalidated and subsequent attempts
@@ -870,11 +891,9 @@ static void pager_reset(Pager *pPager){
if( pPager->state>=PAGER_RESERVED ){
sqlite3pager_rollback(pPager);
}
- sqlite3OsUnlock(pPager->fd, NO_LOCK);
- pPager->state = PAGER_UNLOCK;
- pPager->dbSize = -1;
+ pager_unlock(pPager);
pPager->nRef = 0;
- assert( pPager->journalOpen==0 );
+ assert( pPager->errCode || (pPager->journalOpen==0 && pPager->stmtOpen==0) );
}
/*
@@ -926,6 +945,7 @@ static int pager_unwritelock(Pager *pPager){
pPager->setMaster = 0;
pPager->needSync = 0;
pPager->pFirstSynced = pPager->pFirst;
+ pPager->dbSize = -1;
return rc;
}
@@ -1340,6 +1360,10 @@ static int pager_playback(Pager *pPager){
pPager->journalOff = szJ;
break;
}else{
+ /* If we are unable to rollback a hot journal, then the database
+ ** is probably not recoverable. Return CORRUPT.
+ */
+ rc = SQLITE_CORRUPT;
goto end_playback;
}
}
@@ -1416,6 +1440,7 @@ static int pager_stmt_playback(Pager *pPager){
if( pPager->state>=PAGER_EXCLUSIVE ){
rc = pager_truncate(pPager, pPager->stmtSize);
}
+ assert( pPager->state>=PAGER_SHARED );
pPager->dbSize = pPager->stmtSize;
/* Figure out how many records are in the statement journal.
@@ -1793,14 +1818,19 @@ void enable_simulated_io_errors(void){
** response is to zero the memory at pDest and continue. A real IO error
** will presumably recur and be picked up later (Todo: Think about this).
*/
-void sqlite3pager_read_fileheader(Pager *pPager, int N, unsigned char *pDest){
+int sqlite3pager_read_fileheader(Pager *pPager, int N, unsigned char *pDest){
+ int rc = SQLITE_OK;
memset(pDest, 0, N);
if( MEMDB==0 ){
disable_simulated_io_errors();
sqlite3OsSeek(pPager->fd, 0);
- sqlite3OsRead(pPager->fd, pDest, N);
enable_simulated_io_errors();
+ rc = sqlite3OsRead(pPager->fd, pDest, N);
+ if( rc==SQLITE_IOERR_SHORT_READ ){
+ rc = SQLITE_OK;
+ }
}
+ return rc;
}
/*
@@ -1814,12 +1844,13 @@ void sqlite3pager_read_fileheader(Pager *pPager, int N, unsigned char *pDest){
*/
int sqlite3pager_pagecount(Pager *pPager){
i64 n;
+ int rc;
assert( pPager!=0 );
if( pPager->dbSize>=0 ){
n = pPager->dbSize;
} else {
- if( sqlite3OsFileSize(pPager->fd, &n)!=SQLITE_OK ){
- pager_error(pPager, SQLITE_IOERR);
+ if( (rc = sqlite3OsFileSize(pPager->fd, &n))!=SQLITE_OK ){
+ pager_error(pPager, rc);
return 0;
}
if( n>0 && n<pPager->pageSize ){
@@ -1959,9 +1990,15 @@ static void memoryTruncate(Pager *pPager){
*/
static int pager_wait_on_lock(Pager *pPager, int locktype){
int rc;
+
+ /* The OS lock values must be the same as the Pager lock values */
assert( PAGER_SHARED==SHARED_LOCK );
assert( PAGER_RESERVED==RESERVED_LOCK );
assert( PAGER_EXCLUSIVE==EXCLUSIVE_LOCK );
+
+ /* If the file is currently unlocked then the size must be unknown */
+ assert( pPager->state>=PAGER_SHARED || pPager->dbSize<0 || MEMDB );
+
if( pPager->state>=locktype ){
rc = SQLITE_OK;
}else{
@@ -1980,6 +2017,7 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
*/
int sqlite3pager_truncate(Pager *pPager, Pgno nPage){
int rc;
+ assert( pPager->state>=PAGER_SHARED || MEMDB );
sqlite3pager_pagecount(pPager);
if( pPager->errCode ){
rc = pPager->errCode;
@@ -2026,7 +2064,6 @@ int sqlite3pager_truncate(Pager *pPager, Pgno nPage){
** to the caller.
*/
int sqlite3pager_close(Pager *pPager){
- PgHdr *pPg, *pNext;
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
/* A malloc() cannot fail in sqlite3ThreadData() as one or more calls to
** malloc() must have already been made by this thread before it gets
@@ -2038,46 +2075,10 @@ int sqlite3pager_close(Pager *pPager){
assert( pTsd && pTsd->nAlloc );
#endif
- switch( pPager->state ){
- case PAGER_RESERVED:
- case PAGER_SYNCED:
- case PAGER_EXCLUSIVE: {
- /* We ignore any IO errors that occur during the rollback
- ** operation. So disable IO error simulation so that testing
- ** works more easily.
- */
- disable_simulated_io_errors();
- sqlite3pager_rollback(pPager);
- enable_simulated_io_errors();
- if( !MEMDB ){
- sqlite3OsUnlock(pPager->fd, NO_LOCK);
- }
- assert( pPager->errCode || pPager->journalOpen==0 );
- break;
- }
- case PAGER_SHARED: {
- if( !MEMDB ){
- sqlite3OsUnlock(pPager->fd, NO_LOCK);
- }
- break;
- }
- default: {
- /* Do nothing */
- break;
- }
- }
- for(pPg=pPager->pAll; pPg; pPg=pNext){
-#ifndef NDEBUG
- if( MEMDB ){
- PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
- assert( !pPg->alwaysRollback );
- assert( !pHist->pOrig );
- assert( !pHist->pStmt );
- }
-#endif
- pNext = pPg->pNextAll;
- sqliteFree(pPg);
- }
+ disable_simulated_io_errors();
+ pPager->errCode = 0;
+ pager_reset(pPager);
+ enable_simulated_io_errors();
TRACE2("CLOSE %d\n", PAGERID(pPager));
assert( pPager->errCode || (pPager->journalOpen==0 && pPager->stmtOpen==0) );
if( pPager->journalOpen ){
@@ -2578,7 +2579,7 @@ int sqlite3pager_release_memory(int nReq){
** The error will be returned to the user (or users, in the case
** of a shared pager cache) of the pager for which the error occured.
*/
- assert( rc==SQLITE_IOERR || rc==SQLITE_FULL );
+ assert( (rc&0xff)==SQLITE_IOERR || rc==SQLITE_FULL );
assert( p->state>=PAGER_RESERVED );
pager_error(p, rc);
}
@@ -2659,8 +2660,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
*/
rc = sqlite3OsLock(pPager->fd, EXCLUSIVE_LOCK);
if( rc!=SQLITE_OK ){
- sqlite3OsUnlock(pPager->fd, NO_LOCK);
- pPager->state = PAGER_UNLOCK;
+ pager_unlock(pPager);
return pager_error(pPager, rc);
}
pPager->state = PAGER_EXCLUSIVE;
@@ -2675,8 +2675,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
*/
rc = sqlite3OsOpenReadOnly(pPager->zJournal, &pPager->jfd);
if( rc!=SQLITE_OK ){
- sqlite3OsUnlock(pPager->fd, NO_LOCK);
- pPager->state = PAGER_UNLOCK;
+ pager_unlock(pPager);
return SQLITE_BUSY;
}
pPager->journalOpen = 1;
@@ -2783,19 +2782,10 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
}
TRACE3("FETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
CODEC1(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
- if( rc!=SQLITE_OK ){
- i64 fileSize;
- int rc2 = sqlite3OsFileSize(pPager->fd, &fileSize);
- if( rc2!=SQLITE_OK || fileSize>=pgno*pPager->pageSize ){
- /* An IO error occured in one of the the sqlite3OsSeek() or
- ** sqlite3OsRead() calls above. */
- pPg->pgno = 0;
- sqlite3pager_unref(PGHDR_TO_DATA(pPg));
- return rc;
- }else{
- clear_simulated_io_error();
- memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize);
- }
+ if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
+ pPg->pgno = 0;
+ sqlite3pager_unref(PGHDR_TO_DATA(pPg));
+ return rc;
}else{
TEST_INCR(pPager->nRead);
}
@@ -2967,8 +2957,7 @@ failed_to_open_journal:
*/
sqlite3OsDelete(pPager->zJournal);
}else{
- sqlite3OsUnlock(pPager->fd, NO_LOCK);
- pPager->state = PAGER_UNLOCK;
+ pager_reset(pPager);
}
return rc;
}
@@ -3227,6 +3216,7 @@ int sqlite3pager_write(void *pData){
/* Update the database size and return.
*/
+ assert( pPager->state>=PAGER_SHARED );
if( pPager->dbSize<(int)pPg->pgno ){
pPager->dbSize = pPg->pgno;
if( !MEMDB && pPager->dbSize==PENDING_BYTE/pPager->pageSize ){
@@ -3302,6 +3292,7 @@ void sqlite3pager_dont_write(Pager *pPager, Pgno pgno){
assert( pPg!=0 ); /* We never call _dont_write unless the page is in mem */
pPg->alwaysRollback = 1;
if( pPg->dirty && !pPager->stmtInUse ){
+ assert( pPager->state>=PAGER_SHARED );
if( pPager->dbSize==(int)pPg->pgno && pPager->origDbSize<pPager->dbSize ){
/* If this pages is the last page in the file and the file has grown
** during the current transaction, then do NOT mark the page as clean.
@@ -3331,7 +3322,8 @@ void sqlite3pager_dont_rollback(void *pData){
PgHdr *pPg = DATA_TO_PGHDR(pData);
Pager *pPager = pPg->pPager;
- if( pPager->state!=PAGER_EXCLUSIVE || pPager->journalOpen==0 ) return;
+ assert( pPager->state>=PAGER_RESERVED );
+ if( pPager->journalOpen==0 ) return;
if( pPg->alwaysRollback || pPager->alwaysRollback || MEMDB ) return;
if( !pPg->inJournal && (int)pPg->pgno <= pPager->origDbSize ){
assert( pPager->aInJournal!=0 );
@@ -3399,14 +3391,12 @@ int sqlite3pager_commit(Pager *pPager){
** if there have been no changes to the database file. */
assert( pPager->needSync==0 );
rc = pager_unwritelock(pPager);
- pPager->dbSize = -1;
return rc;
}
assert( pPager->journalOpen );
rc = sqlite3pager_sync(pPager, 0, 0);
if( rc==SQLITE_OK ){
rc = pager_unwritelock(pPager);
- pPager->dbSize = -1;
}
return rc;
}
@@ -3464,7 +3454,6 @@ int sqlite3pager_rollback(Pager *pPager){
if( !pPager->dirtyCache || !pPager->journalOpen ){
rc = pager_unwritelock(pPager);
- pPager->dbSize = -1;
return rc;
}
@@ -3540,6 +3529,7 @@ int sqlite3pager_stmt_begin(Pager *pPager){
int rc;
char zTemp[SQLITE_TEMPNAME_SIZE];
assert( !pPager->stmtInUse );
+ assert( pPager->state>=PAGER_SHARED );
assert( pPager->dbSize>=0 );
TRACE2("STMT-BEGIN %d\n", PAGERID(pPager));
if( MEMDB ){