]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Change the way the "incremental checkpoint" function of OTA works in order to reduce...
authordan <dan@noemail.net>
Sat, 14 Feb 2015 18:58:22 +0000 (18:58 +0000)
committerdan <dan@noemail.net>
Sat, 14 Feb 2015 18:58:22 +0000 (18:58 +0000)
FossilOrigin-Name: b64a11a754dc56f3406d3b703531ebe9e4af4908

ext/ota/ota1.test
ext/ota/ota6.test
ext/ota/sqlite3ota.c
manifest
manifest.uuid
src/main.c
src/pager.c
src/pager.h
src/sqlite.h.in
src/wal.c
src/wal.h

index dec5f14a99959724d9c20524206bd446c11d5005..addcde94462ad90fc4237c2072637d514f611f84 100644 (file)
@@ -198,7 +198,6 @@ foreach {tn3 create_vfs destroy_vfs} {
 
       do_test $tn3.1.$tn2.$tn.1 {
         create_ota1 ota.db
-        breakpoint
         $cmd test.db ota.db
       } {SQLITE_DONE}
 
@@ -475,6 +474,7 @@ foreach {tn3 create_vfs destroy_vfs} {
     }
   }
 
+  catch { db close }
   eval $destroy_vfs
 }
 
index 8027f36c5f19fb17de8deec56e8ffd33610d1841..3b794ee77c571f66f37cc60f99b585e47a686ad1 100644 (file)
@@ -68,34 +68,12 @@ for {set nStep 1} {$nStep < 7} {incr nStep} {
   } {1 {SQLITE_BUSY - database modified during ota update}}
 }
 
-for {set nStep 7} {$nStep < 8} {incr nStep} {
-  do_test 1.$nStep.1 {
-    setup_test
-    sqlite3ota ota test.db ota.db
-    for {set i 0} {$i<$nStep} {incr i} {ota step}
-    ota close
-    sqlite3 db test.db
-    execsql { INSERT INTO t1 VALUES(5, 'hello') }
-    sqlite3ota ota test.db ota.db
-    ota step
-  } {SQLITE_OK}
-  do_test 1.$nStep.2 {
-    ota step
-  } {SQLITE_OK}
-  do_test 1.$nStep.3 {
-    list [file exists test.db-oal] [file exists test.db-wal]
-  } {0 1}
-  do_test 1.$nStep.4 {
-    list [catch { ota close } msg] $msg
-  } {0 SQLITE_OK}
-}
-
 
 # Test the outcome of some other client writing the db after the *-oal
 # file has been copied to the *-wal path. Once this has happened, any
 # other client writing to the db causes OTA to consider its job finished.
 #
-for {set nStep 8} {$nStep < 20} {incr nStep} {
+for {set nStep 7} {$nStep < 20} {incr nStep} {
   do_test 1.$nStep.1 {
     setup_test
     sqlite3ota ota test.db ota.db
index de7f1250c5425d757670d863a8d1fd5426b9023f..652c21a5f56bd59299117e04b77bf16815787814 100644 (file)
@@ -75,6 +75,7 @@
 #define OTA_STATE_COOKIE      7
 
 #define OTA_STAGE_OAL         1
+#define OTA_STAGE_CAPTURE     2
 #define OTA_STAGE_CKPT        3
 #define OTA_STAGE_DONE        4
 
@@ -87,6 +88,21 @@ typedef struct OtaObjIter OtaObjIter;
 typedef struct ota_vfs ota_vfs;
 typedef struct ota_file ota_file;
 
+#if !defined(SQLITE_AMALGAMATION)
+typedef unsigned int u32;
+typedef unsigned char u8;
+typedef sqlite3_int64 i64;
+#endif
+
+/*
+** These values must match the values defined in wal.c for the equivalent
+** locks. These are not magic numbers as they are part of the SQLite file
+** format.
+*/
+#define WAL_LOCK_WRITE  0
+#define WAL_LOCK_CKPT   1
+#define WAL_LOCK_READ0  3
+
 /*
 ** A structure to store values read from the ota_state table in memory.
 */
@@ -94,10 +110,9 @@ struct OtaState {
   int eStage;
   char *zTbl;
   char *zIdx;
-  unsigned char *pCkptState;
-  int nCkptState;
+  i64 iWalCksum;
   int nRow;
-  sqlite3_int64 nProgress;
+  i64 nProgress;
 };
 
 /*
@@ -116,8 +131,8 @@ struct OtaObjIter {
   char **azTblCol;                /* Array of unquoted target column names */
   char **azTblType;               /* Array of target column types */
   int *aiSrcOrder;                /* src table col -> target table col */
-  unsigned char *abTblPk;         /* Array of flags, set on target PK columns */
-  unsigned char *abNotNull;       /* Array of flags, set on NOT NULL columns */
+  u8 *abTblPk;                    /* Array of flags, set on target PK columns */
+  u8 *abNotNull;                  /* Array of flags, set on NOT NULL columns */
   int eType;                      /* Table type - an OTA_PK_XXX value */
 
   /* Output variables. zTbl==0 implies EOF. */
@@ -158,6 +173,12 @@ struct OtaObjIter {
 #define OTA_PK_VTAB           5
 
 
+typedef struct OtaFrame OtaFrame;
+struct OtaFrame {
+  u32 iDbPage;
+  u32 iWalFrame;
+};
+
 /*
 ** OTA handle.
 */
@@ -171,16 +192,27 @@ struct sqlite3ota {
   int nStep;                      /* Rows processed for current object */
   int nProgress;                  /* Rows processed for all objects */
   OtaObjIter objiter;             /* Iterator for skipping through tbl/idx */
-  sqlite3_ckpt *pCkpt;            /* Incr-checkpoint handle */
-  ota_file *pTargetFd;            /* File handle open on target db */
   const char *zVfsName;           /* Name of automatically created ota vfs */
+  ota_file *pTargetFd;            /* File handle open on target db */
+
+  /* The following state variables are used as part of the incremental
+  ** checkpoint stage (eStage==OTA_STAGE_CKPT). See function otaSetupCkpt()
+  ** for details.  */
+  u32 iMaxFrame;                  /* Largest iWalFrame value in aFrame[] */
+  u32 mLock;
+  int nFrame;                     /* Entries in aFrame[] array */
+  int nFrameAlloc;                /* Allocated size of aFrame[] array */
+  OtaFrame *aFrame;
+  int pgsz;
+  u8 *aBuf;
+  i64 iWalCksum;
 };
 
 struct ota_vfs {
-  sqlite3_vfs base;             /* ota VFS shim methods */
-  sqlite3_vfs *pRealVfs;        /* Underlying VFS */
-  sqlite3_mutex *mutex;
-  const char *zOtaWal;
+  sqlite3_vfs base;               /* ota VFS shim methods */
+  sqlite3_vfs *pRealVfs;          /* Underlying VFS */
+  sqlite3_mutex *mutex;           /* Mutex to protect pMain */
+  ota_file *pMain;                /* Linked list of main db files */
 };
 
 struct ota_file {
@@ -190,13 +222,16 @@ struct ota_file {
   sqlite3ota *pOta;               /* Pointer to ota object (ota target only) */
 
   int openFlags;                  /* Flags this file was opened with */
-  unsigned int iCookie;           /* Cookie value for main db files */
-  unsigned char iWriteVer;        /* "write-version" value for main db files */
+  u32 iCookie;                    /* Cookie value for main db files */
+  u8 iWriteVer;                   /* "write-version" value for main db files */
 
   int nShm;                       /* Number of entries in apShm[] array */
   char **apShm;                   /* Array of mmap'd *-shm regions */
-  const char *zWal;               /* Wal filename for this db file */
   char *zDel;                     /* Delete this when closing file */
+
+  const char *zWal;               /* Wal filename for this main db file */
+  ota_file *pWalFd;               /* Wal file descriptor for this main db */
+  ota_file *pMainNext;            /* Next MAIN_DB file */
 };
 
 
@@ -468,7 +503,7 @@ static void *otaMalloc(sqlite3ota *p, int nByte){
 ** error code in the OTA handle passed as the first argument.
 */
 static void otaAllocateIterArrays(sqlite3ota *p, OtaObjIter *pIter, int nCol){
-  int nByte = (2*sizeof(char*) + sizeof(int) + 2*sizeof(unsigned char)) * nCol;
+  int nByte = (2*sizeof(char*) + sizeof(int) + 2*sizeof(u8)) * nCol;
   char **azNew;
 
   azNew = (char**)otaMalloc(p, nByte);
@@ -476,8 +511,8 @@ static void otaAllocateIterArrays(sqlite3ota *p, OtaObjIter *pIter, int nCol){
     pIter->azTblCol = azNew;
     pIter->azTblType = &azNew[nCol];
     pIter->aiSrcOrder = (int*)&pIter->azTblType[nCol];
-    pIter->abTblPk = (unsigned char*)&pIter->aiSrcOrder[nCol];
-    pIter->abNotNull = (unsigned char*)&pIter->abTblPk[nCol];
+    pIter->abTblPk = (u8*)&pIter->aiSrcOrder[nCol];
+    pIter->abNotNull = (u8*)&pIter->abTblPk[nCol];
   }
 }
 
@@ -576,7 +611,7 @@ static int otaTableType(
   zSql = 0;
   if( pStmt==0 ) goto otaTableType_end;
   while( sqlite3_step(pStmt)==SQLITE_ROW ){
-    const unsigned char *zOrig = sqlite3_column_text(pStmt,3);
+    const u8 *zOrig = sqlite3_column_text(pStmt,3);
     if( zOrig && zOrig[0]=='p' ){
       zSql = sqlite3_mprintf("SELECT rootpage FROM main.sqlite_master"
                              " WHERE name=%Q", sqlite3_column_text(pStmt,1));
@@ -713,7 +748,7 @@ static int otaObjIterCacheTableInfo(sqlite3ota *p, OtaObjIter *pIter){
 
         pIter->azTblType[iOrder] = otaStrndup(zType, -1, &p->rc);
         pIter->abTblPk[iOrder] = (iPk!=0);
-        pIter->abNotNull[iOrder] = (unsigned char)bNotNull || (iPk!=0);
+        pIter->abNotNull[iOrder] = (u8)bNotNull || (iPk!=0);
         iOrder++;
       }
     }
@@ -1480,21 +1515,26 @@ static void otaOpenDatabase(sqlite3ota *p){
   assert( p->rc==SQLITE_OK );
   assert( p->db==0 );
 
+  p->eStage = 0;
   p->rc = sqlite3_open_v2(p->zTarget, &p->db, flags, p->zVfsName);
   if( p->rc ){
     p->zErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->db));
   }else{
-    otaMPrintfExec(p, "ATTACH %Q AS ota", p->zOta);
+    p->rc = sqlite3_file_control(p->db, "main", SQLITE_FCNTL_OTA, (void*)p);
+    if( p->rc==SQLITE_OK ){
+      otaMPrintfExec(p, "ATTACH %Q AS ota", p->zOta);
+    }
 
     /* Mark the database file just opened as an OTA target database. If 
     ** this call returns SQLITE_NOTFOUND, then the OTA vfs is not in use.
     ** This is an error.  */
     if( p->rc==SQLITE_OK ){
       p->rc = sqlite3_file_control(p->db, "main", SQLITE_FCNTL_OTA, (void*)p);
-      if( p->rc==SQLITE_NOTFOUND ){
-        p->rc = SQLITE_ERROR;
-        p->zErrmsg = sqlite3_mprintf("ota vfs not found");
-      }
+    }
+
+    if( p->rc==SQLITE_NOTFOUND ){
+      p->rc = SQLITE_ERROR;
+      p->zErrmsg = sqlite3_mprintf("ota vfs not found");
     }
   }
 }
@@ -1533,6 +1573,101 @@ static void otaFileSuffix3(const char *zBase, char *z){
 #endif
 }
 
+/*
+** Return the current wal-index header checksum for the target database 
+** as a 64-bit integer.
+**
+** The checksum is store in the first page of xShmMap memory as an 8-byte 
+** blob starting at byte offset 40.
+*/
+static i64 otaShmChecksum(sqlite3ota *p){
+  i64 iRet;
+  if( p->rc==SQLITE_OK ){
+    sqlite3_file *pDb = p->pTargetFd->pReal;
+    u32 volatile *ptr;
+    p->rc = pDb->pMethods->xShmMap(pDb, 0, 32*1024, 0, (void volatile**)&ptr);
+    if( p->rc==SQLITE_OK ){
+      iRet = ((i64)ptr[10] << 32) + ptr[11];
+    }
+  }
+  return iRet;
+}
+
+static void otaSetupCheckpoint(sqlite3ota *p, OtaState *pState){
+
+  if( pState==0 ){
+    p->eStage = 0;
+    if( p->rc==SQLITE_OK ){
+      p->rc = sqlite3_exec(p->db, "SELECT * FROM sqlite_master", 0, 0, 0);
+    }
+  }
+
+  if( p->rc==SQLITE_OK ){
+    int rc2;
+    p->eStage = OTA_STAGE_CAPTURE;
+    rc2 = sqlite3_exec(p->db, "PRAGMA main.wal_checkpoint=restart", 0, 0, 0);
+    if( rc2!=SQLITE_INTERNAL ) p->rc = rc2;
+  }
+
+  if( p->rc==SQLITE_OK ){
+    p->eStage = OTA_STAGE_CKPT;
+    p->nStep = 0;
+    p->aBuf = otaMalloc(p, p->pgsz);
+    p->iWalCksum = otaShmChecksum(p);
+  }
+
+  if( p->rc==SQLITE_OK && pState && pState->iWalCksum!=p->iWalCksum ){
+    p->rc = SQLITE_DONE;
+    p->eStage = OTA_STAGE_DONE;
+  }
+}
+
+static int otaCaptureWalRead(sqlite3ota *pOta, i64 iOff, int iAmt){
+  const u32 mReq = (1<<WAL_LOCK_WRITE)|(1<<WAL_LOCK_CKPT)|(1<<WAL_LOCK_READ0);
+  u32 iFrame;
+
+  if( pOta->mLock!=mReq ){
+    return SQLITE_BUSY;
+  }
+
+  pOta->pgsz = iAmt;
+  if( pOta->nFrame==pOta->nFrameAlloc ){
+    int nNew = (pOta->nFrameAlloc ? pOta->nFrameAlloc : 64) * 2;
+    OtaFrame *aNew;
+    aNew = (OtaFrame*)sqlite3_realloc(pOta->aFrame, nNew * sizeof(OtaFrame));
+    if( aNew==0 ) return SQLITE_NOMEM;
+    pOta->aFrame = aNew;
+    pOta->nFrameAlloc = nNew;
+  }
+
+  iFrame = (u32)((iOff-32) / (i64)(iAmt+24)) + 1;
+  if( pOta->iMaxFrame<iFrame ) pOta->iMaxFrame = iFrame;
+  pOta->aFrame[pOta->nFrame].iWalFrame = iFrame;
+  pOta->aFrame[pOta->nFrame].iDbPage = 0;
+  pOta->nFrame++;
+  return SQLITE_OK;
+}
+
+static int otaCaptureDbWrite(sqlite3ota *pOta, i64 iOff){
+  pOta->aFrame[pOta->nFrame-1].iDbPage = (u32)(iOff / pOta->pgsz) + 1;
+  return SQLITE_OK;
+}
+
+static void otaCheckpointFrame(sqlite3ota *p, OtaFrame *pFrame){
+  if( p->rc==SQLITE_OK ){
+    sqlite3_file *pWal = p->pTargetFd->pWalFd->pReal;
+    sqlite3_file *pDb = p->pTargetFd->pReal;
+    i64 iOff;
+
+    iOff = (i64)(pFrame->iWalFrame-1) * (p->pgsz + 24) + 32 + 24;
+    p->rc = pWal->pMethods->xRead(pWal, p->aBuf, p->pgsz, iOff);
+    if( p->rc ) return;
+
+    iOff = (i64)(pFrame->iDbPage-1) * p->pgsz;
+    p->rc = pDb->pMethods->xWrite(pDb, p->aBuf, p->pgsz, iOff);
+  }
+}
+
 /*
 ** The OTA handle is currently in OTA_STAGE_OAL state, with a SHARED lock
 ** on the database file. This proc moves the *-oal file to the *-wal path,
@@ -1562,8 +1697,8 @@ static void otaMoveOalFile(sqlite3ota *p){
     otaObjIterFinalize(&p->objiter);
     sqlite3_close(p->db);
     p->db = 0;
-    p->eStage = OTA_STAGE_CKPT;
     otaOpenDatabase(p);
+    otaSetupCheckpoint(p, 0);
   }
 
   sqlite3_free(zWal);
@@ -1807,25 +1942,32 @@ int sqlite3ota_step(sqlite3ota *p){
       }
 
       case OTA_STAGE_CKPT: {
+        if( p->nStep>=p->nFrame ){
+          sqlite3_file *pDb = p->pTargetFd->pReal;
 
-        if( p->rc==SQLITE_OK && p->pCkpt==0 ){
-          p->rc = sqlite3_ckpt_open(p->db, 0, 0, &p->pCkpt);
-        }
-        if( p->rc==SQLITE_OK ){
-          if( p->pCkpt==0 ){
-            p->eStage = OTA_STAGE_DONE;
-            p->rc = SQLITE_DONE;
-          }else if( SQLITE_OK!=sqlite3_ckpt_step(p->pCkpt) ){
-            p->rc = sqlite3_ckpt_close(p->pCkpt, 0, 0);
-            p->pCkpt = 0;
+          /* Sync the db file */
+          p->rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);
+
+          /* Update nBackfill */
+          if( p->rc==SQLITE_OK ){
+            void volatile *ptr;
+            p->rc = pDb->pMethods->xShmMap(pDb, 0, 32*1024, 0, &ptr);
             if( p->rc==SQLITE_OK ){
-              p->eStage = OTA_STAGE_DONE;
-              p->rc = SQLITE_DONE;
+              ((u32*)ptr)[12] = p->iMaxFrame;
             }
           }
-          p->nProgress++;
+
+          if( p->rc==SQLITE_OK ){
+            p->eStage = OTA_STAGE_DONE;
+            p->rc = SQLITE_DONE;
+          }
+        }else{
+          OtaFrame *pFrame = &p->aFrame[p->nStep];
+          otaCheckpointFrame(p, pFrame);
+          p->nStep++;
         }
 
+        p->nProgress++;
         break;
       }
 
@@ -1838,7 +1980,7 @@ int sqlite3ota_step(sqlite3ota *p){
   }
 }
 
-static void otaSaveTransactionState(sqlite3ota *p){
+static void otaSaveState(sqlite3ota *p){
   sqlite3_stmt *pInsert;
   int rc;
 
@@ -1851,28 +1993,19 @@ static void otaSaveTransactionState(sqlite3ota *p){
         "(%d, %Q), "
         "(%d, %d), "
         "(%d, %lld), "
-        "(%d, ?), "
+        "(%d, %lld), "
         "(%d, %lld) ",
         OTA_STATE_STAGE, p->eStage,
         OTA_STATE_TBL, p->objiter.zTbl, 
         OTA_STATE_IDX, p->objiter.zIdx, 
         OTA_STATE_ROW, p->nStep, 
         OTA_STATE_PROGRESS, p->nProgress,
-        OTA_STATE_CKPT,
-        OTA_STATE_COOKIE, (sqlite3_int64)p->pTargetFd->iCookie
+        OTA_STATE_CKPT, p->iWalCksum,
+        OTA_STATE_COOKIE, (i64)p->pTargetFd->iCookie
       )
   );
   assert( pInsert==0 || rc==SQLITE_OK );
-  if( rc==SQLITE_OK ){
-    if( p->pCkpt ){
-      unsigned char *pCkptState = 0;
-      int nCkptState = 0;
-      rc = sqlite3_ckpt_close(p->pCkpt, &pCkptState, &nCkptState);
-      p->pCkpt = 0;
-      sqlite3_bind_blob(pInsert, 1, pCkptState, nCkptState, SQLITE_TRANSIENT);
-      sqlite3_free(pCkptState);
-    }
-  }
+
   if( rc==SQLITE_OK ){
     sqlite3_step(pInsert);
     rc = sqlite3_finalize(pInsert);
@@ -1889,7 +2022,6 @@ static void otaFreeState(OtaState *p){
   if( p ){
     sqlite3_free(p->zTbl);
     sqlite3_free(p->zIdx);
-    sqlite3_free(p->pCkptState);
     sqlite3_free(p);
   }
 }
@@ -1947,10 +2079,7 @@ static OtaState *otaLoadState(sqlite3ota *p){
         break;
 
       case OTA_STATE_CKPT:
-        pRet->nCkptState = sqlite3_column_bytes(pStmt, 1);
-        pRet->pCkptState = (unsigned char*)otaStrndup(
-            (char*)sqlite3_column_blob(pStmt, 1), pRet->nCkptState, &rc
-        );
+        pRet->iWalCksum = sqlite3_column_int64(pStmt, 1);
         break;
 
       case OTA_STATE_COOKIE:
@@ -1959,7 +2088,7 @@ static OtaState *otaLoadState(sqlite3ota *p){
         ** committed in rollback mode) currently stored on page 1 of the 
         ** database file. */
         if( pRet->eStage==OTA_STAGE_OAL 
-         && p->pTargetFd->iCookie!=(unsigned int)sqlite3_column_int64(pStmt, 1) 
+         && p->pTargetFd->iCookie!=(u32)sqlite3_column_int64(pStmt, 1) 
         ){
           rc = SQLITE_BUSY;
           p->zErrmsg = sqlite3_mprintf("database modified during ota update");
@@ -2035,7 +2164,7 @@ sqlite3ota *sqlite3ota_open(const char *zTarget, const char *zOta){
   if( p ){
     OtaState *pState = 0;
 
-    /* Create the custom VFS */
+    /* Create the custom VFS. */
     memset(p, 0, sizeof(sqlite3ota));
     otaCreateVfs(p, 0);
 
@@ -2053,6 +2182,11 @@ sqlite3ota *sqlite3ota_open(const char *zTarget, const char *zOta){
       p->rc = sqlite3_exec(p->db, OTA_CREATE_STATE, 0, 0, &p->zErrmsg);
     }
 
+    /* Check that this is not a wal mode database. If it is, it cannot be
+    ** updated. There is also a check for a live *-wal file in otaVfsAccess()
+    ** function, on the off chance that the target is a wal database for
+    ** which the first page of the db file has been overwritten by garbage
+    ** during an earlier failed checkpoint.  */
     if( p->rc==SQLITE_OK && p->pTargetFd->iWriteVer>1 ){
       p->rc = SQLITE_ERROR;
       p->zErrmsg = sqlite3_mprintf("cannot update wal mode database");
@@ -2064,7 +2198,7 @@ sqlite3ota *sqlite3ota_open(const char *zTarget, const char *zOta){
       if( p->rc==SQLITE_OK ){
         if( pState->eStage==0 ){ 
           otaDeleteOalFile(p);
-          p->eStage = 1;
+          p->eStage = OTA_STAGE_OAL;
         }else{
           p->eStage = pState->eStage;
         }
@@ -2075,14 +2209,11 @@ sqlite3ota *sqlite3ota_open(const char *zTarget, const char *zOta){
 
     if( p->rc==SQLITE_OK ){
       if( p->eStage==OTA_STAGE_OAL ){
-        ota_vfs *pOtaVfs = p->pTargetFd->pOtaVfs;
-
-        sqlite3_mutex_enter(pOtaVfs->mutex);
-        assert( pOtaVfs->zOtaWal==0 );
-        pOtaVfs->zOtaWal = p->pTargetFd->zWal;
-        p->rc = sqlite3_exec(p->db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
-        pOtaVfs->zOtaWal = 0;
-        sqlite3_mutex_leave(pOtaVfs->mutex);
+
+        /* Open the transaction */
+        if( p->rc==SQLITE_OK ){
+          p->rc = sqlite3_exec(p->db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
+        }
   
         /* Point the object iterator at the first object */
         if( p->rc==SQLITE_OK ){
@@ -2093,13 +2224,8 @@ sqlite3ota *sqlite3ota_open(const char *zTarget, const char *zOta){
           otaLoadTransactionState(p, pState);
         }
       }else if( p->eStage==OTA_STAGE_CKPT ){
-        p->rc = sqlite3_ckpt_open(
-            p->db, pState->pCkptState, pState->nCkptState, &p->pCkpt
-        );
-        if( p->rc==SQLITE_MISMATCH || (p->rc==SQLITE_OK && p->pCkpt==0) ){
-          p->eStage = OTA_STAGE_DONE;
-          p->rc = SQLITE_DONE;
-        }
+        otaSetupCheckpoint(p, pState);
+        p->nStep = pState->nRow;
       }else if( p->eStage==OTA_STAGE_DONE ){
         p->rc = SQLITE_DONE;
       }
@@ -2152,7 +2278,7 @@ int sqlite3ota_close(sqlite3ota *p, char **pzErrmsg){
     assert( p->rc!=SQLITE_ROW );
     if( p->rc==SQLITE_OK || p->rc==SQLITE_DONE ){
       assert( p->zErrmsg==0 );
-      otaSaveTransactionState(p);
+      otaSaveState(p);
     }
 
     /* Close any open statement handles. */
@@ -2164,9 +2290,10 @@ int sqlite3ota_close(sqlite3ota *p, char **pzErrmsg){
     }
 
     /* Close the open database handle and VFS object. */
-    if( p->pCkpt ) sqlite3_ckpt_close(p->pCkpt, 0, 0);
     sqlite3_close(p->db);
     otaDeleteVfs(p);
+    sqlite3_free(p->aBuf);
+    sqlite3_free(p->aFrame);
 
     otaEditErrmsg(p);
     rc = p->rc;
@@ -2238,6 +2365,14 @@ static int otaVfsClose(sqlite3_file *pFile){
   p->apShm = 0;
   sqlite3_free(p->zDel);
 
+  if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
+    ota_file **pp;
+    sqlite3_mutex_enter(p->pOtaVfs->mutex);
+    for(pp=&p->pOtaVfs->pMain; *pp!=p; pp=&((*pp)->pMainNext));
+    *pp = p->pMainNext;
+    sqlite3_mutex_leave(p->pOtaVfs->mutex);
+  }
+
   /* Close the underlying file handle */
   rc = p->pReal->pMethods->xClose(p->pReal);
   return rc;
@@ -2248,11 +2383,11 @@ static int otaVfsClose(sqlite3_file *pFile){
 ** Read and return an unsigned 32-bit big-endian integer from the buffer 
 ** passed as the only argument.
 */
-static unsigned int otaGetU32(unsigned char *aBuf){
-  return ((unsigned int)aBuf[0] << 24)
-       + ((unsigned int)aBuf[1] << 16)
-       + ((unsigned int)aBuf[2] <<  8)
-       + ((unsigned int)aBuf[3]);
+static u32 otaGetU32(u8 *aBuf){
+  return ((u32)aBuf[0] << 24)
+       + ((u32)aBuf[1] << 16)
+       + ((u32)aBuf[2] <<  8)
+       + ((u32)aBuf[3]);
 }
 
 /*
@@ -2265,13 +2400,22 @@ static int otaVfsRead(
   sqlite_int64 iOfst
 ){
   ota_file *p = (ota_file*)pFile;
-  int rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
-  if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){
-    /* These look like magic numbers. But they are stable, as they are part
-    ** of the definition of the SQLite file format, which may not change. */
-    unsigned char *pBuf = (unsigned char*)zBuf;
-    p->iCookie = otaGetU32(&pBuf[24]);
-    p->iWriteVer = pBuf[19];
+  int rc;
+
+  if( p->pOta 
+   && p->pOta->eStage==OTA_STAGE_CAPTURE
+   && (p->openFlags & SQLITE_OPEN_WAL) 
+  ){
+    rc = otaCaptureWalRead(p->pOta, iOfst, iAmt);
+  }else{
+    rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
+    if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){
+      /* These look like magic numbers. But they are stable, as they are part
+       ** of the definition of the SQLite file format, which may not change. */
+      u8 *pBuf = (u8*)zBuf;
+      p->iCookie = otaGetU32(&pBuf[24]);
+      p->iWriteVer = pBuf[19];
+    }
   }
   return rc;
 }
@@ -2286,13 +2430,21 @@ static int otaVfsWrite(
   sqlite_int64 iOfst
 ){
   ota_file *p = (ota_file*)pFile;
-  int rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
-  if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){
-    /* These look like magic numbers. But they are stable, as they are part
-    ** of the definition of the SQLite file format, which may not change. */
-    unsigned char *pBuf = (unsigned char*)zBuf;
-    p->iCookie = otaGetU32(&pBuf[24]);
-    p->iWriteVer = pBuf[19];
+  int rc;
+  if( p->pOta 
+   && p->pOta->eStage==OTA_STAGE_CAPTURE
+   && (p->openFlags & SQLITE_OPEN_MAIN_DB)
+  ){
+    rc = otaCaptureDbWrite(p->pOta, iOfst);
+  }else{
+    rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
+    if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){
+      /* These look like magic numbers. But they are stable, as they are part
+      ** of the definition of the SQLite file format, which may not change. */
+      u8 *pBuf = (u8*)zBuf;
+      p->iCookie = otaGetU32(&pBuf[24]);
+      p->iWriteVer = pBuf[19];
+    }
   }
   return rc;
 }
@@ -2310,6 +2462,12 @@ static int otaVfsTruncate(sqlite3_file *pFile, sqlite_int64 size){
 */
 static int otaVfsSync(sqlite3_file *pFile, int flags){
   ota_file *p = (ota_file *)pFile;
+  if( p->pOta && p->pOta->eStage==OTA_STAGE_CAPTURE ){
+    if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
+      return SQLITE_INTERNAL;
+    }
+    return SQLITE_OK;
+  }
   return p->pReal->pMethods->xSync(p->pReal, flags);
 }
 
@@ -2329,9 +2487,8 @@ static int otaVfsLock(sqlite3_file *pFile, int eLock){
   sqlite3ota *pOta = p->pOta;
   int rc = SQLITE_OK;
 
-  if( pOta && eLock==SQLITE_LOCK_EXCLUSIVE
-   && (pOta->eStage==OTA_STAGE_OAL || pOta->eStage==OTA_STAGE_CKPT) 
-  ){
+  assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
+  if( pOta && eLock==SQLITE_LOCK_EXCLUSIVE && pOta->eStage!=OTA_STAGE_DONE ){
     /* Do not allow EXCLUSIVE locks. Preventing SQLite from taking this 
     ** prevents it from checkpointing the database from sqlite3_close(). */
     rc = SQLITE_BUSY;
@@ -2365,6 +2522,7 @@ static int otaVfsFileControl(sqlite3_file *pFile, int op, void *pArg){
   ota_file *p = (ota_file *)pFile;
   int (*xControl)(sqlite3_file*,int,void*) = p->pReal->pMethods->xFileControl;
 
+  assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
   if( op==SQLITE_FCNTL_OTA ){
     int rc;
     sqlite3ota *pOta = (sqlite3ota*)pArg;
@@ -2385,6 +2543,7 @@ static int otaVfsFileControl(sqlite3_file *pFile, int op, void *pArg){
       }else if( rc==SQLITE_NOTFOUND ){
         pOta->pTargetFd = p;
         p->pOta = pOta;
+        if( p->pWalFd ) p->pWalFd->pOta = pOta;
         rc = SQLITE_OK;
       }
     }
@@ -2414,21 +2573,35 @@ static int otaVfsDeviceCharacteristics(sqlite3_file *pFile){
 */
 static int otaVfsShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
   ota_file *p = (ota_file*)pFile;
+  sqlite3ota *pOta = p->pOta;
   int rc = SQLITE_OK;
 
 #ifdef SQLITE_AMALGAMATION
     assert( WAL_CKPT_LOCK==1 );
 #endif
 
-  if( p->pOta && p->pOta->eStage==OTA_STAGE_OAL ){
+  assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
+  if( pOta && pOta->eStage==OTA_STAGE_OAL ){
     /* Magic number 1 is the WAL_CKPT_LOCK lock. Preventing SQLite from
     ** taking this lock also prevents any checkpoints from occurring. 
     ** todo: really, it's not clear why this might occur, as 
     ** wal_autocheckpoint ought to be turned off.  */
-    if( ofst==1 && n==1 ) rc = SQLITE_BUSY;
+    if( ofst==WAL_LOCK_CKPT && n==1 ) rc = SQLITE_BUSY;
   }else{
-    assert( p->nShm==0 );
-    rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
+    int bCapture = 0;
+    if( n==1 && (flags & SQLITE_SHM_EXCLUSIVE)
+     && p->pOta && p->pOta->eStage==OTA_STAGE_CAPTURE
+     && (ofst==WAL_LOCK_WRITE || ofst==WAL_LOCK_CKPT || ofst==WAL_LOCK_READ0)
+    ){
+      bCapture = 1;
+    }
+
+    if( bCapture==0 || 0==(flags & SQLITE_SHM_UNLOCK) ){
+      rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
+      if( bCapture && rc==SQLITE_OK ){
+        p->pOta->mLock |= (1 << ofst);
+      }
+    }
   }
 
   return rc;
@@ -2447,6 +2620,7 @@ static int otaVfsShmMap(
   /* If not in OTA_STAGE_OAL, allow this call to pass through. Or, if this
   ** ota is in the OTA_STAGE_OAL state, use heap memory for *-shm space 
   ** instead of a file on disk.  */
+  assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
   if( p->pOta && p->pOta->eStage==OTA_STAGE_OAL ){
     if( iRegion<=p->nShm ){
       int nByte = (iRegion+1) * sizeof(char*);
@@ -2495,6 +2669,7 @@ static int otaVfsShmUnmap(sqlite3_file *pFile, int delFlag){
   ota_file *p = (ota_file*)pFile;
   int rc = SQLITE_OK;
 
+  assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
   if( p->pOta && p->pOta->eStage==OTA_STAGE_OAL ){
     /* no-op */
   }else{
@@ -2503,6 +2678,14 @@ static int otaVfsShmUnmap(sqlite3_file *pFile, int delFlag){
   return rc;
 }
 
+static ota_file *otaFindMaindb(ota_vfs *pOtaVfs, const char *zWal){
+  ota_file *pDb;
+  sqlite3_mutex_enter(pOtaVfs->mutex);
+  for(pDb=pOtaVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext);
+  sqlite3_mutex_leave(pOtaVfs->mutex);
+  return pDb;
+}
+
 /*
 ** Open an ota file handle.
 */
@@ -2567,12 +2750,19 @@ static int otaVfsOpen(
       z += (n + 8 + 1);
       pFd->zWal = z;
     }
-    else if( (flags & SQLITE_OPEN_WAL) && zName==pOtaVfs->zOtaWal ){
-      char *zCopy = otaStrndup(zName, -1, &rc);
-      if( zCopy ){
-        int nCopy = strlen(zCopy);
-        zCopy[nCopy-3] = 'o';
-        zOpen = (const char*)(pFd->zDel = zCopy);
+    else if( flags & SQLITE_OPEN_WAL ){
+      ota_file *pDb = otaFindMaindb(pOtaVfs, zName);
+      if( pDb ){
+        if( pDb->pOta && pDb->pOta->eStage==OTA_STAGE_OAL ){
+          char *zCopy = otaStrndup(zName, -1, &rc);
+          if( zCopy ){
+            int nCopy = strlen(zCopy);
+            zCopy[nCopy-3] = 'o';
+            zOpen = (const char*)(pFd->zDel = zCopy);
+          }
+          pFd->pOta = pDb->pOta;
+        }
+        pDb->pWalFd = pFd;
       }
     }
   }
@@ -2581,7 +2771,16 @@ static int otaVfsOpen(
     rc = pRealVfs->xOpen(pRealVfs, zOpen, pFd->pReal, flags, pOutFlags);
   }
   if( pFd->pReal->pMethods ){
+    /* The xOpen() operation has succeeded. Set the sqlite3_file.pMethods
+    ** pointer and, if the file is a main database file, link it into the
+    ** mutex protected linked list of all such files.  */
     pFile->pMethods = &otavfs_io_methods;
+    if( flags & SQLITE_OPEN_MAIN_DB ){
+      sqlite3_mutex_enter(pOtaVfs->mutex);
+      pFd->pMainNext = pOtaVfs->pMain;
+      pOtaVfs->pMain = pFd;
+      sqlite3_mutex_leave(pOtaVfs->mutex);
+    }
   }
 
   return rc;
@@ -2611,11 +2810,28 @@ static int otaVfsAccess(
 
   rc = pRealVfs->xAccess(pRealVfs, zPath, flags, pResOut);
 
-  if( rc==SQLITE_OK && flags==SQLITE_ACCESS_EXISTS && pOtaVfs->zOtaWal==zPath ){
-    if( *pResOut ){
-      rc = SQLITE_CANTOPEN;
-    }else{
-      *pResOut = 1;
+  /* If this call is to check if a *-wal file associated with an OTA target
+  ** database connection exists, and the OTA update is in OTA_STAGE_OAL,
+  ** the following special handling is activated:
+  **
+  **   a) if the *-wal file does exist, return SQLITE_CANTOPEN. This
+  **      ensures that the OTA extension never tries to update a database
+  **      in wal mode, even if the first page of the database file has
+  **      been damaged. 
+  **
+  **   b) if the *-wal file does not exist, claim that it does anyway,
+  **      causing SQLite to call xOpen() to open it. This call will also
+  **      be intercepted (see the otaVfsOpen() function) and the *-oal
+  **      file opened instead.
+  */
+  if( rc==SQLITE_OK && flags==SQLITE_ACCESS_EXISTS ){
+    ota_file *pDb = otaFindMaindb(pOtaVfs, zPath);
+    if( pDb && pDb->pOta && pDb->pOta->eStage==OTA_STAGE_OAL ){
+      if( *pResOut ){
+        rc = SQLITE_CANTOPEN;
+      }else{
+        *pResOut = 1;
+      }
     }
   }
 
index 630a43ce13c822bb65ffb9fc34fa791147c07dfe..435ebc95adc10a43143d647cb733a4c2bd032476 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Merge\sthe\sota-update-no-pager_ota_mode\sbranch\sinto\sthis\sone.
-D 2015-02-11T17:05:17.871
+C Change\sthe\sway\sthe\s"incremental\scheckpoint"\sfunction\sof\sOTA\sworks\sin\sorder\sto\sreduce\sthe\seffect\son\sthe\sSQLite\score\scode.
+D 2015-02-14T18:58:22.415
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 6b9e7677829aa94b9f30949656e27312aefb9a46
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -125,17 +125,17 @@ F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e
 F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
 F ext/ota/README.txt 2ce4ffbb0aaa6731b041c27a7359f9a5f1c69152
 F ext/ota/ota.c c11a85af71dccc45976622fe7a51169a481caa91
-F ext/ota/ota1.test d50ba4ded2edeba99740bc7dd0b7284c1894127c
+F ext/ota/ota1.test dee5b852353642a243e0bf414d332b1bccd5324f
 F ext/ota/ota10.test 85e0f6e7964db5007590c1b299e75211ed4240d4
 F ext/ota/ota3.test a77efbce7723332eb688d2b28bf18204fc9614d7
 F ext/ota/ota5.test ad0799daf8923ddebffe75ae8c5504ca90b7fadb
-F ext/ota/ota6.test 1fbba5fd46e3e0bfa5ae1d0caf9da27d15cb7cdf
+F ext/ota/ota6.test 40996b7716dee72a6c5d28c3bee436717a438d3d
 F ext/ota/ota7.test 1fe2c5761705374530e29f70c39693076028221a
 F ext/ota/ota8.test cd70e63a0c29c45c0906692827deafa34638feda
 F ext/ota/ota9.test d3eee95dd836824d07a22e5efcdb7bf6e869358b
 F ext/ota/otaA.test 95566a8d193113867b960eadf85b310937f2fe03
 F ext/ota/otafault.test 508ba87c83d632670ac0f94371a465d4bb4d49dd
-F ext/ota/sqlite3ota.c 466546d41d9b09136216349db98647d0afd77816
+F ext/ota/sqlite3ota.c 0cf2a1b5ac7009050159a39d938f1334ce7072b8
 F ext/ota/sqlite3ota.h 1cc7201086fe65a36957740381485a24738c4077
 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
 F ext/rtree/rtree.c 14e6239434d4e3f65d3e90320713f26aa24e167f
@@ -209,7 +209,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
 F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e
 F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770
 F src/loadext.c 86bd4e2fccd520b748cba52492ab60c4a770f660
-F src/main.c c4cb192ebf0bcc975648ae05ac40bc1f40018c52
+F src/main.c 17e3a37374f3c13e27311773c30720b61584f5b9
 F src/malloc.c 740db54387204c9a2eb67c6d98e68b08e9ef4eab
 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
 F src/mem1.c abe6ee469b6c5a35c7f22bfeb9c9bac664a1c987
@@ -231,8 +231,8 @@ F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa
 F src/os_unix.c aefeaf915aaef9f81aa2645e0d5d06fa1bd83beb
 F src/os_win.c 8223e7db5b7c4a81d8b161098ac3959400434cdb
 F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca
-F src/pager.c 9d29fb3dfd99d16896d839a511b467784d72f4da
-F src/pager.h 20954a3fa1bbf05d39063d94e789ad9efd15e5d1
+F src/pager.c 4120a49ecd37697e28f5ed807f470b9c0b88410c
+F src/pager.h c3476e7c89cdf1c6914e50a11f3714e30b4e0a77
 F src/parse.y 0f8e7d60f0ab3cb53d270adef69259ac307d83a8
 F src/pcache.c d210cf90d04365a74f85d21374dded65af67b0cb
 F src/pcache.h b44658c9c932d203510279439d891a2a83e12ba8
@@ -246,7 +246,7 @@ F src/resolve.c f4d79e31ffa5820c2e3d1740baa5e9b190425f2b
 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
 F src/select.c e46cef4c224549b439384c88fc7f57ba064dad54
 F src/shell.c 82c25508dac802b32198af6f5256ca1597c6a1af
-F src/sqlite.h.in c49acd2daa6e54110ab0cc607eb73ff32720a269
+F src/sqlite.h.in ad5cdebfdd8bcef2534f93de6b8466b4c455a032
 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
 F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d
 F src/sqliteInt.h 57a405ae6d2ed10fff52de376d18f21e04d96609
@@ -317,8 +317,8 @@ F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f
 F src/vdbesort.c 6d64c5448b64851b99931ede980addc3af70d5e2
 F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010
 F src/vtab.c c08ec66f45919eaa726bf88aa53eb08379d607f9
-F src/wal.c 7a8a4e7a40d693d44dbfc4d1f2bcb7e2b620f530
-F src/wal.h 0d3ba0c3f1b4c25796cb213568a84b9f9063f465
+F src/wal.c 39303f2c9db02a4e422cd8eb2c8760420c6a51fe
+F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804
 F src/where.c d46de821bc604a4fd36fa3928c086950e91aafb1
 F src/whereInt.h d3633e9b592103241b74b0ec76185f3e5b8b62e0
@@ -1254,7 +1254,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P c3931db560ab4a2601c7f7318fb02c8d5e6862b1 0b63e8dcbaec5043e353734e684c2a46552a3409
-R f20bdc7a7c21af7b4cb60f763acf418a
+P 71887cd9b38def398d48eaf0ec34eeac3c7c5177
+R 9f9fcb7ec94597bb519ead7cc6d77d1b
 U dan
-Z 0a34d9bc8960589f0668f7402b31b0ce
+Z b1cfeba62f30a42f6b3ffd27f7078fc0
index f1db10b5fb8268bd23dfde82d544458e5aac079b..9b9576f034ca03c1a93009b4dea9fd5a2cb1bd21 100644 (file)
@@ -1 +1 @@
-71887cd9b38def398d48eaf0ec34eeac3c7c5177
\ No newline at end of file
+b64a11a754dc56f3406d3b703531ebe9e4af4908
\ No newline at end of file
index 7bca1e57773be4d5bc59a8b2f173e6e112e40fad..fa87a19cf71a399ed9c4e04e8116d75dfa3f905f 100644 (file)
@@ -1976,33 +1976,6 @@ int sqlite3_wal_checkpoint_v2(
 #endif
 }
 
-#ifdef SQLITE_ENABLE_OTA
-/*
-** Open an incremental checkpoint handle.
-*/
-int sqlite3_ckpt_open(
-  sqlite3 *db, 
-  unsigned char *a, int n, 
-  sqlite3_ckpt **ppCkpt
-){
-  Pager *pPager = 0;
-  int rc;
-
-  *ppCkpt = 0;
-  sqlite3_mutex_enter(db->mutex);
-
-  /* Find the Pager object. */
-  rc = sqlite3_file_control(db,"main",SQLITE_FCNTL_ZIPVFS_PAGER,(void*)&pPager);
-  if( rc!=SQLITE_OK ){
-    pPager = sqlite3BtreePager(db->aDb[0].pBt);
-  }
-
-  rc = sqlite3PagerWalCheckpointStart(db, pPager, a, n, ppCkpt);
-  sqlite3_mutex_leave(db->mutex);
-  return rc;
-}
-#endif /* SQLITE_ENABLE_OTA */
-
 
 /*
 ** Checkpoint database zDb. If zDb is NULL, or if the buffer zDb points
index 959f135b1d41d2247c9e6ea18a7f4586c21a7def..2230174e5cb211ad99fd37a66e4318f4f7176252 100644 (file)
@@ -5181,7 +5181,6 @@ int sqlite3PagerSharedLock(Pager *pPager){
     ** mode. Otherwise, the following function call is a no-op.
     */
     rc = pagerOpenWalIfPresent(pPager);
-
 #ifndef SQLITE_OMIT_WAL
     assert( pPager->pWal==0 || rc==SQLITE_OK );
 #endif
@@ -7269,27 +7268,5 @@ int sqlite3PagerWalFramesize(Pager *pPager){
 }
 #endif
 
-#ifdef SQLITE_ENABLE_OTA
-
-/*
-** Open an incremental checkpoint handle.
-*/
-int sqlite3PagerWalCheckpointStart(
-  sqlite3 *db, 
-  Pager *pPager,
-  u8 *a, int n, 
-  sqlite3_ckpt **ppCkpt
-){
-  if( pPager->pWal==0 ){
-    *ppCkpt = 0;
-    return SQLITE_OK;
-  }else{
-    return sqlite3WalCheckpointStart(db, pPager->pWal, a, n,
-        pPager->xBusyHandler, pPager->pBusyHandlerArg,
-        pPager->ckptSyncFlags, ppCkpt
-    );
-  }
-}
-#endif /* !SQLITE_ENABLE_OTA */
 
 #endif /* SQLITE_OMIT_DISKIO */
index 10df8e0deb4f43712e57f224073069dab14b7587..e07fa88fc5fe6cfcc7ff525a1dec6ef085e4c0a3 100644 (file)
@@ -210,6 +210,4 @@ void *sqlite3PagerCodec(DbPage *);
 # define enable_simulated_io_errors()
 #endif
 
-int sqlite3PagerWalCheckpointStart(sqlite3*, Pager*, u8*, int, sqlite3_ckpt**);
-
 #endif /* _PAGER_H_ */
index 23681cc6f355dbde9260ffbca3666595f252db0e..095ee73f89353a4cc1789ea4818740a7c18ef962 100644 (file)
@@ -7586,43 +7586,6 @@ SQLITE_EXPERIMENTAL int sqlite3_stmt_scanstatus(
 */
 SQLITE_EXPERIMENTAL void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
 
-/*
-** Incremental checkpoint API.
-**
-** An incremental checkpoint handle is opened using the sqlite3_ckpt_open()
-** API. To begin a new checkpoint, the second and third arguments should both
-** be passed zero. To resume an earlier checkpoint, the second and third
-** arguments should specify a buffer returned by an earlier call to
-** sqlite3_ckpt_close(). When resuming a checkpoint, if the database or WAL 
-** file has been modified since the checkpoint was suspended, the 
-** sqlite3_ckpt_open() call fails with SQLITE_MISMATCH.
-**
-** Each time sqlite3_ckpt_step() is called on an open checkpoint handle, a
-** single page is copied from the WAL file to the database. If no error 
-** occurs, but the checkpoint is not finished, SQLITE_OK is returned. If the
-** checkpoint has been finished (and so sqlite3_ckpt_step() should not be
-** called again), SQLITE_DONE is returned. Otherwise, if an error occurs,
-** some other SQLite error code is returned.
-**
-** Calling sqlite3_ckpt_close() closes an open checkpoint handle. If the
-** checkpoint has finished and no error has occurred, SQLITE_OK is returned
-** and the two output parameters zeroed. Or, if an error has occurred, an
-** error code is returned and the two output parameters are zeroed. Finally,
-** if the checkpoint is not finished but no error has occurred, SQLITE_OK is
-** returned and the first output variable set to point to a buffer allocated 
-** using sqlite3_malloc() containing the serialized state of the checkpoint. 
-** The contents of this buffer may be passed to a later call to
-** sqlite3_ckpt_open() to restart the checkpoint. The second output variable 
-** is set to the size of the buffer in bytes.
-**
-** These APIs are only available if SQLITE_ENABLE_OTA is defined at compile
-** time. They are intended for use by the OTA extension only. As such, they 
-** are subject to change or removal at any point.
-*/
-typedef struct sqlite3_ckpt sqlite3_ckpt;
-int sqlite3_ckpt_open(sqlite3*, unsigned char*, int n, sqlite3_ckpt **ppCkpt);
-int sqlite3_ckpt_step(sqlite3_ckpt*);
-int sqlite3_ckpt_close(sqlite3_ckpt*, unsigned char **pa, int *pn);
 
 /*
 ** Undo the hack that converts floating point types to integer for
index fb51ac9fd284ead099f7968d174602c0a18cb500..71f4a3d452fc2d4c28a33e8ec8b70014bb224d80 100644 (file)
--- a/src/wal.c
+++ b/src/wal.c
@@ -482,31 +482,6 @@ struct WalIterator {
   } aSegment[1];                  /* One for every 32KB page in the wal-index */
 };
 
-/*
-** An object of the following type is used to store state information for
-** an ongoing checkpoint operation. For normal checkpoints, the instance 
-** is allocated on the stack by the walCheckpoint() function. For the special
-** incremental checkpoints performed by OTA clients, it is allocated in
-** heap memory by sqlite3WalCheckpointStart().
-**
-** See the implementations of walCheckpointStart(), walCheckpointStep() and 
-** walCheckpointFinalize() for further details.
-*/
-typedef struct WalCkpt WalCkpt;
-struct WalCkpt {
-  sqlite3 *db;                    /* Database pointer (incremental only) */
-  int szPage;                     /* Database page-size */
-  int sync_flags;                 /* Flags for OsSync() (or 0) */
-  u32 mxSafeFrame;                /* Max frame that can be backfilled */
-  u32 mxPage;                     /* Max database page to write */
-  volatile WalCkptInfo *pInfo;    /* The checkpoint status information */
-  WalIterator *pIter;             /* Wal iterator context */
-  Wal *pWal;                      /* Pointer to owner object */                 
-  u8 *aBuf;                       /* Temporary page-sized buffer to use */
-  int rc;                         /* Error code. SQLITE_DONE -> finished */
-  int nStep;                      /* Number of times pIter has been stepped */
-};
-
 /*
 ** Define the parameters of the hash tables in the wal-index file. There
 ** is a hash-table following every HASHTABLE_NPAGE page numbers in the
@@ -1615,7 +1590,6 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){
 
   if( rc!=SQLITE_OK ){
     walIteratorFree(p);
-    p = 0;
   }
   *pp = p;
   return rc;
@@ -1649,188 +1623,6 @@ static int walPagesize(Wal *pWal){
   return (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
 }
 
-/*
-** Initialize the contents of the WalCkpt object indicated by the final
-** argument and begin a checkpoint operation. The CKPT lock must already
-** be held when this function is called.
-**
-** Return SQLITE_OK if successful or an error code otherwise.
-*/
-static int walCheckpointStart(
-  Wal *pWal,                      /* Wal connection */
-  u8 *aBuf,                       /* Page-sized temporary buffer */
-  int nBuf,                       /* Size of aBuf[] in bytes */
-  int (*xBusy)(void*),            /* Function to call when busy (or NULL) */
-  void *pBusyArg,                 /* Context argument for xBusyHandler */
-  int sync_flags,                 /* Flags for OsSync() (or 0) */
-  WalCkpt *p                      /* Allocated object to populate */
-){
-  int rc;                         /* Return code */
-  int i;                          /* Iterator variable */
-
-  memset(p, 0, sizeof(WalCkpt));
-  if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
-    return SQLITE_CORRUPT_BKPT;
-  }
-
-  p->szPage = walPagesize(pWal);
-  p->pWal = pWal;
-  p->aBuf = aBuf;
-  p->sync_flags = sync_flags;
-  testcase( p->szPage<=32768 );
-  testcase( p->szPage>=65536 );
-  p->pInfo = walCkptInfo(pWal);
-  if( p->pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK;
-
-  /* Allocate the iterator */
-  rc = walIteratorInit(pWal, &p->pIter);
-  if( rc!=SQLITE_OK ) return rc;
-  assert( p->pIter );
-
-  /* Compute in mxSafeFrame the index of the last frame of the WAL that is
-  ** safe to write into the database.  Frames beyond mxSafeFrame might
-  ** overwrite database pages that are in use by active readers and thus
-  ** cannot be backfilled from the WAL.
-  */
-  p->mxSafeFrame = pWal->hdr.mxFrame;
-  p->mxPage = pWal->hdr.nPage;
-  for(i=1; i<WAL_NREADER; i++){
-    u32 y = p->pInfo->aReadMark[i];
-    if( p->mxSafeFrame>y ){
-      assert( y<=pWal->hdr.mxFrame );
-      rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
-      if( rc==SQLITE_OK ){
-        p->pInfo->aReadMark[i] = (i==1 ? p->mxSafeFrame : READMARK_NOT_USED);
-        walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
-      }else if( rc==SQLITE_BUSY ){
-        p->mxSafeFrame = y;
-        xBusy = 0;
-      }else{
-        walIteratorFree(p->pIter);
-        p->pIter = 0;
-        return rc;
-      }
-    }
-  }
-
-  if( p->pInfo->nBackfill>=p->mxSafeFrame
-   || (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0), 1))!=SQLITE_OK
-  ){
-    walIteratorFree(p->pIter);
-    p->pIter = 0;
-  }
-  if( rc==SQLITE_BUSY ) rc = SQLITE_OK;
-
-  if( rc==SQLITE_OK && p->pIter ){
-    /* Sync the WAL to disk */
-    if( sync_flags ){
-      rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
-    }
-
-    /* If the database may grow as a result of this checkpoint, hint
-    ** about the eventual size of the db file to the VFS layer.  */
-    if( rc==SQLITE_OK ){
-      i64 nSize;                  /* Current size of database file */
-      i64 nReq = ((i64)p->mxPage * p->szPage);
-      rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
-      if( rc==SQLITE_OK && nSize<nReq ){
-        sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
-      }
-    }
-  }
-
-  return rc;
-}
-
-/*
-** Attempt to copy the next frame from the wal file to the database file. If
-** there are no more frames to copy to the database file return SQLITE_DONE.
-** If the frame is successfully copied, return SQLITE_OK. Or, if an error
-** occurs, return an SQLite error code.
-*/
-static int walCheckpointStep(WalCkpt *p){
-  u32 iDbpage = 0;                /* Next database page to write */
-  u32 iFrame = 0;                 /* Wal frame containing data for iDbpage */
-  int rc = SQLITE_DONE;
-
-  assert( p->rc==SQLITE_OK );
-  while( p->pIter && 0==walIteratorNext(p->pIter, &iDbpage, &iFrame) ){
-    i64 iOffset;
-    assert( walFramePgno(p->pWal, iFrame)==iDbpage );
-    p->nStep++;
-    if( iFrame<=p->pInfo->nBackfill 
-     || iFrame>p->mxSafeFrame 
-     || iDbpage>p->mxPage 
-    ){
-      continue;
-    }
-
-    iOffset = walFrameOffset(iFrame, p->szPage) + WAL_FRAME_HDRSIZE;
-    /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
-    rc = sqlite3OsRead(p->pWal->pWalFd, p->aBuf, p->szPage, iOffset);
-    if( rc!=SQLITE_OK ) break;
-    iOffset = (iDbpage-1)*(i64)p->szPage;
-    testcase( IS_BIG_INT(iOffset) );
-    rc = sqlite3OsWrite(p->pWal->pDbFd, p->aBuf, p->szPage, iOffset);
-    break;
-  }
-
-  p->rc = rc;
-  return rc;
-}
-
-/*
-** The current round of checkpointing work using the object indicated by
-** the only argument is now finished. If no error occcurred, this function
-** saves the results to shared memory (i.e. updates the WalCkptInfo.nBackfill
-** variable), and truncates and syncs the database file as required.
-**
-** All dynamic resources currently held by the WalCkpt object are released. 
-** It is the responsibility of the caller to delete the WalCkpt itself if
-** required.
-*/
-static int walCheckpointFinalize(WalCkpt *p){
-  if( p->pIter ){
-    int rc = p->rc;
-    Wal *pWal = p->pWal;
-
-    if( rc==SQLITE_DONE ){
-      /* If work was completed */
-      rc = SQLITE_OK;
-      if( p->mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
-        i64 szDb = pWal->hdr.nPage*(i64)p->szPage;
-        testcase( IS_BIG_INT(szDb) );
-        rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
-        if( rc==SQLITE_OK && p->sync_flags ){
-          rc = sqlite3OsSync(pWal->pDbFd, p->sync_flags);
-        }
-      }
-      if( rc==SQLITE_OK ){
-        p->pInfo->nBackfill = p->mxSafeFrame;
-      }
-      p->rc = rc;
-    }else{
-#ifdef SQLITE_ENABLE_OTA
-      if( rc==SQLITE_OK && p->sync_flags ){
-        /* If work was not completed, but no error has occured. */
-        p->rc = sqlite3OsSync(pWal->pDbFd, p->sync_flags);
-      }
-#else
-      assert( rc!=SQLITE_OK );
-#endif
-    }
-
-    /* Release the reader lock held while backfilling */
-    walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
-    walIteratorFree(p->pIter);
-    p->pIter = 0;
-  }else if( p->rc==SQLITE_DONE ){
-    p->rc = SQLITE_OK;
-  }
-
-  return p->rc;
-}
-
 /*
 ** The following is guaranteed when this function is called:
 **
@@ -1900,23 +1692,124 @@ static int walCheckpoint(
   int (*xBusy)(void*),            /* Function to call when busy */
   void *pBusyArg,                 /* Context argument for xBusyHandler */
   int sync_flags,                 /* Flags for OsSync() (or 0) */
-  u8 *zBuf,                       /* Temporary buffer to use */
-  int nBuf                        /* Size of zBuf in bytes */
+  u8 *zBuf                        /* Temporary buffer to use */
 ){
-  int rc;                         /* Return code */
-  WalCkpt sC;
+  int rc = SQLITE_OK;             /* Return code */
+  int szPage;                     /* Database page-size */
+  WalIterator *pIter = 0;         /* Wal iterator context */
+  u32 iDbpage = 0;                /* Next database page to write */
+  u32 iFrame = 0;                 /* Wal frame containing data for iDbpage */
+  u32 mxSafeFrame;                /* Max frame that can be backfilled */
+  u32 mxPage;                     /* Max database page to write */
+  int i;                          /* Loop counter */
+  volatile WalCkptInfo *pInfo;    /* The checkpoint status information */
 
-  /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
-  ** in the SQLITE_CHECKPOINT_PASSIVE mode. */
-  assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
+  szPage = walPagesize(pWal);
+  testcase( szPage<=32768 );
+  testcase( szPage>=65536 );
+  pInfo = walCkptInfo(pWal);
+  if( pInfo->nBackfill<pWal->hdr.mxFrame ){
+
+    /* Allocate the iterator */
+    rc = walIteratorInit(pWal, &pIter);
+    if( rc!=SQLITE_OK ){
+      return rc;
+    }
+    assert( pIter );
+
+    /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
+    ** in the SQLITE_CHECKPOINT_PASSIVE mode. */
+    assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
+
+    /* Compute in mxSafeFrame the index of the last frame of the WAL that is
+    ** safe to write into the database.  Frames beyond mxSafeFrame might
+    ** overwrite database pages that are in use by active readers and thus
+    ** cannot be backfilled from the WAL.
+    */
+    mxSafeFrame = pWal->hdr.mxFrame;
+    mxPage = pWal->hdr.nPage;
+    for(i=1; i<WAL_NREADER; i++){
+      u32 y = pInfo->aReadMark[i];
+      if( mxSafeFrame>y ){
+        assert( y<=pWal->hdr.mxFrame );
+        rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
+        if( rc==SQLITE_OK ){
+          pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
+          walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
+        }else if( rc==SQLITE_BUSY ){
+          mxSafeFrame = y;
+          xBusy = 0;
+        }else{
+          goto walcheckpoint_out;
+        }
+      }
+    }
+
+    if( pInfo->nBackfill<mxSafeFrame
+     && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0),1))==SQLITE_OK
+    ){
+      i64 nSize;                    /* Current size of database file */
+      u32 nBackfill = pInfo->nBackfill;
+
+      /* Sync the WAL to disk */
+      if( sync_flags ){
+        rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
+      }
+
+      /* If the database may grow as a result of this checkpoint, hint
+      ** about the eventual size of the db file to the VFS layer.
+      */
+      if( rc==SQLITE_OK ){
+        i64 nReq = ((i64)mxPage * szPage);
+        rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
+        if( rc==SQLITE_OK && nSize<nReq ){
+          sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
+        }
+      }
 
-  rc = walCheckpointStart(pWal, zBuf, nBuf, xBusy, pBusyArg, sync_flags, &sC);
-  if( rc!=SQLITE_OK ) goto walcheckpoint_out;
 
-  /* Step the checkpoint object until it reports something other than 
-  ** SQLITE_OK.  */
-  while( SQLITE_OK==(rc = walCheckpointStep(&sC)) );
-  rc = walCheckpointFinalize(&sC);
+      /* Iterate through the contents of the WAL, copying data to the db file */
+      while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
+        i64 iOffset;
+        assert( walFramePgno(pWal, iFrame)==iDbpage );
+        if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){
+          continue;
+        }
+        iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
+        /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
+        rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
+        if( rc!=SQLITE_OK ) break;
+        iOffset = (iDbpage-1)*(i64)szPage;
+        testcase( IS_BIG_INT(iOffset) );
+        rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
+        if( rc!=SQLITE_OK ) break;
+      }
+
+      /* If work was actually accomplished... */
+      if( rc==SQLITE_OK ){
+        if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
+          i64 szDb = pWal->hdr.nPage*(i64)szPage;
+          testcase( IS_BIG_INT(szDb) );
+          rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
+          if( rc==SQLITE_OK && sync_flags ){
+            rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
+          }
+        }
+        if( rc==SQLITE_OK ){
+          pInfo->nBackfill = mxSafeFrame;
+        }
+      }
+
+      /* Release the reader lock held while backfilling */
+      walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
+    }
+
+    if( rc==SQLITE_BUSY ){
+      /* Reset the return code so as not to report a checkpoint failure
+      ** just because there are active readers.  */
+      rc = SQLITE_OK;
+    }
+  }
 
   /* If this is an SQLITE_CHECKPOINT_RESTART or TRUNCATE operation, and the
   ** entire wal file has been copied into the database file, then block 
@@ -1925,12 +1818,12 @@ static int walCheckpoint(
   */
   if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){
     assert( pWal->writeLock );
-    if( sC.pInfo->nBackfill<pWal->hdr.mxFrame ){
+    if( pInfo->nBackfill<pWal->hdr.mxFrame ){
       rc = SQLITE_BUSY;
     }else if( eMode>=SQLITE_CHECKPOINT_RESTART ){
       u32 salt1;
       sqlite3_randomness(4, &salt1);
-      assert( sC.pInfo->nBackfill==pWal->hdr.mxFrame );
+      assert( pInfo->nBackfill==pWal->hdr.mxFrame );
       rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1);
       if( rc==SQLITE_OK ){
         if( eMode==SQLITE_CHECKPOINT_TRUNCATE ){
@@ -1956,7 +1849,7 @@ static int walCheckpoint(
   }
 
  walcheckpoint_out:
-  walIteratorFree(sC.pIter);
+  walIteratorFree(pIter);
   return rc;
 }
 
@@ -1980,9 +1873,6 @@ static void walLimitSize(Wal *pWal, i64 nMax){
 
 /*
 ** Close a connection to a log file.
-**
-** If parameter zBuf is not NULL, also attempt to obtain an exclusive 
-** lock and run a checkpoint.
 */
 int sqlite3WalClose(
   Wal *pWal,                      /* Wal to close */
@@ -2002,37 +1892,32 @@ int sqlite3WalClose(
     **
     ** The EXCLUSIVE lock is not released before returning.
     */
-#ifdef SQLITE_ENABLE_OTA
-    if( zBuf )          /* In non-OTA builds, zBuf is always non-NULL */
-#endif
-    {
-      rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
+    rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
+    if( rc==SQLITE_OK ){
+      if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
+        pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
+      }
+      rc = sqlite3WalCheckpoint(
+          pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
+      );
       if( rc==SQLITE_OK ){
-        if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
-          pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
-        }
-        rc = sqlite3WalCheckpoint(
-            pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
+        int bPersist = -1;
+        sqlite3OsFileControlHint(
+            pWal->pDbFd, SQLITE_FCNTL_PERSIST_WAL, &bPersist
         );
-        if( rc==SQLITE_OK ){
-          int bPersist = -1;
-          sqlite3OsFileControlHint(
-              pWal->pDbFd, SQLITE_FCNTL_PERSIST_WAL, &bPersist
-          );
-          if( bPersist!=1 ){
-            /* Try to delete the WAL file if the checkpoint completed and
-            ** fsyned (rc==SQLITE_OK) and if we are not in persistent-wal
-            ** mode (!bPersist) */
-            isDelete = 1;
-          }else if( pWal->mxWalSize>=0 ){
-            /* Try to truncate the WAL file to zero bytes if the checkpoint
-            ** completed and fsynced (rc==SQLITE_OK) and we are in persistent
-            ** WAL mode (bPersist) and if the PRAGMA journal_size_limit is a
-            ** non-negative value (pWal->mxWalSize>=0).  Note that we truncate
-            ** to zero bytes as truncating to the journal_size_limit might
-            ** leave a corrupt WAL file on disk. */
-            walLimitSize(pWal, 0);
-          }
+        if( bPersist!=1 ){
+          /* Try to delete the WAL file if the checkpoint completed and
+          ** fsyned (rc==SQLITE_OK) and if we are not in persistent-wal
+          ** mode (!bPersist) */
+          isDelete = 1;
+        }else if( pWal->mxWalSize>=0 ){
+          /* Try to truncate the WAL file to zero bytes if the checkpoint
+          ** completed and fsynced (rc==SQLITE_OK) and we are in persistent
+          ** WAL mode (bPersist) and if the PRAGMA journal_size_limit is a
+          ** non-negative value (pWal->mxWalSize>=0).  Note that we truncate
+          ** to zero bytes as truncating to the journal_size_limit might
+          ** leave a corrupt WAL file on disk. */
+          walLimitSize(pWal, 0);
         }
       }
     }
@@ -3134,7 +3019,11 @@ int sqlite3WalCheckpoint(
 
   /* Copy data from the log to the database file. */
   if( rc==SQLITE_OK ){
-    rc = walCheckpoint(pWal, eMode2, xBusy2, pBusyArg, sync_flags, zBuf, nBuf);
+    if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
+      rc = SQLITE_CORRUPT_BKPT;
+    }else{
+      rc = walCheckpoint(pWal, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
+    }
 
     /* If no error occurred, set the output variables. */
     if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
@@ -3161,159 +3050,6 @@ int sqlite3WalCheckpoint(
   return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : rc);
 }
 
-#ifdef SQLITE_ENABLE_OTA
-
-/*
-** Step the checkpoint object passed as the first argument.
-*/
-int sqlite3_ckpt_step(sqlite3_ckpt *pCkpt){
-  int rc;
-  WalCkpt *p = (WalCkpt*)pCkpt;
-  sqlite3_mutex_enter(p->db->mutex);
-  rc = walCheckpointStep(p);
-  sqlite3_mutex_leave(p->db->mutex);
-  return rc;
-}
-
-/*
-** Close the checkpoint object passed as the first argument. If the checkpoint
-** was completed, zero the two output variables. Otherwise, set *paState to
-** point to a buffer containing data that may be passed to a subsequent 
-** call to ckpt_open() to resume the checkpoint. In this case *pnState is
-** set to the size of the buffer in bytes. The buffer should be eventually
-** freed by the caller using sqlite3_free().
-*/
-int sqlite3_ckpt_close(sqlite3_ckpt *pCkpt, u8 **paState, int *pnState){
-  int rc;
-  WalCkpt *p = (WalCkpt*)pCkpt;
-  sqlite3 *db = p->db;
-  Wal *pWal = p->pWal;
-  sqlite3_mutex_enter(db->mutex);
-  if( paState ){
-    *paState = 0;
-    *pnState = 0;
-    if( p->rc==SQLITE_OK ){
-      u8 *aState = sqlite3_malloc(sizeof(u32) * 3);
-      if( aState==0 ){
-        p->rc = SQLITE_NOMEM;
-      }else{
-        *pnState = sizeof(u32)*3;
-        sqlite3Put4byte(&aState[0], p->nStep);
-        sqlite3Put4byte(&aState[4], p->pWal->hdr.aCksum[0]);
-        sqlite3Put4byte(&aState[8], p->pWal->hdr.aCksum[1]);
-        *paState = aState;
-      }
-    }
-  }
-  rc = walCheckpointFinalize(p);
-  walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
-  pWal->ckptLock = 0;
-  sqlite3_free(p);
-  memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
-  sqlite3_mutex_leave(db->mutex);
-  return rc;
-}
-
-/*
-** Open an incremental checkpoint handle.
-*/
-int sqlite3WalCheckpointStart(
-  sqlite3 *db,                    /* Database connection */
-  Wal *pWal,                      /* Wal connection */
-  u8 *aState, int nState,         /* Checkpoint state to restore */
-  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) */
-  sqlite3_ckpt **ppCkpt           /* OUT: Incremental checkpoint object */
-){
-  WalCkpt *p = 0;
-  int isChanged = 0;
-  int rc;
-  int pgsz;
-
-  *ppCkpt = 0;
-  if( pWal->readOnly ) return SQLITE_READONLY;
-  WALTRACE(("WAL%p: checkpoint begins\n", pWal));
-  rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
-  if( rc ){
-    /* Usually this is SQLITE_BUSY meaning that another thread or process
-    ** is already running a checkpoint, or maybe a recovery.  But it might
-    ** also be SQLITE_IOERR. */
-    return rc;
-  }
-  pWal->ckptLock = 1;
-
-  /* Read the wal-index header. */
-  rc = walIndexReadHdr(pWal, &isChanged);
-  if( rc!=SQLITE_OK ) goto ckptstart_out;
-  if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
-    sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
-  }
-
-  pgsz = walPagesize(pWal);
-  p = sqlite3_malloc(sizeof(WalCkpt) + pgsz);
-  if( p==0 ){
-    rc = SQLITE_NOMEM;
-    goto ckptstart_out;
-  }
-
-  rc = walCheckpointStart(
-      pWal, (u8*)&p[1], pgsz, xBusy, pBusyArg, sync_flags, p
-  );
-  p->db = db;
-
-  if( rc==SQLITE_OK && aState ){
-    if( nState!=sizeof(u32)*3 ){
-      rc = SQLITE_CORRUPT_BKPT;
-    }else{
-      int i;
-      if( pWal->hdr.aCksum[0]!=sqlite3Get4byte(&aState[4])
-       || pWal->hdr.aCksum[1]!=sqlite3Get4byte(&aState[8])
-      ){
-        rc = SQLITE_MISMATCH;
-      }else{
-        p->nStep = (int)sqlite3Get4byte(aState);
-        sqlite3Put4byte(&aState[4], pWal->hdr.aCksum[0]);
-        sqlite3Put4byte(&aState[8], pWal->hdr.aCksum[1]);
-        for(i=0; rc==SQLITE_OK && i<p->nStep; i++){
-          u32 dummy1, dummy2; 
-          rc = walIteratorNext(p->pIter, &dummy1, &dummy2);
-        }
-      }
-    }
-  }
-
- ckptstart_out:
-  if( rc!=SQLITE_OK ){
-    if( p ) walIteratorFree(p->pIter);
-    walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
-    pWal->ckptLock = 0;
-    sqlite3_free(p);
-    p = 0;
-  }
-  *ppCkpt = (sqlite3_ckpt*)p;
-  return rc;
-}
-#endif /* SQLITE_ENABLE_OTA */
-
-/*
-** Unless the wal file is empty, check that the 8 bytes of salt stored in
-** the wal header are identical to those in the buffer indicated by the
-** second argument. If they are not, return SQLITE_BUSY_SNAPSHOT. Otherwise,
-** if the buffers match or the WAL file is empty, return SQLITE_OK.
-*/
-int sqlite3WalCheckSalt(Wal *pWal, sqlite3_file *pFd){
-  int rc = SQLITE_OK;
-  if( pWal->hdr.mxFrame>0 ){
-    u8 aData[16];
-    rc = sqlite3OsRead(pFd, aData, sizeof(aData), 24);
-    if( rc==SQLITE_OK && memcmp(pWal->hdr.aSalt, aData, 8) ){
-      rc = SQLITE_BUSY_SNAPSHOT;
-    }
-  }
-  return rc;
-}
-
 /* 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
index 748b6bc2771ef8ba36aacb959dfd22e73b99ed29..092546354b34c0ab3d20056a7f8a8a52e4d0b5f5 100644 (file)
--- a/src/wal.h
+++ b/src/wal.h
@@ -126,17 +126,6 @@ int sqlite3WalExclusiveMode(Wal *pWal, int op);
 */
 int sqlite3WalHeapMemory(Wal *pWal);
 
-int sqlite3WalCheckSalt(Wal *pWal, sqlite3_file*);
-
-int sqlite3WalCheckpointStart(sqlite3 *,
-  Wal *pWal,                      /* Wal connection */
-  u8 *aState, int nState,         /* Checkpoint state to restore */
-  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) */
-  sqlite3_ckpt **ppCkpt           /* OUT: Incremental checkpoint object */
-);
-
 #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).