]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix a problem with OTA updates in the presence of database readers.
authordan <dan@noemail.net>
Wed, 18 Feb 2015 17:40:05 +0000 (17:40 +0000)
committerdan <dan@noemail.net>
Wed, 18 Feb 2015 17:40:05 +0000 (17:40 +0000)
FossilOrigin-Name: 144bb29ffcbfe96dc10c0224113e73a80e89314b

ext/ota/ota3.test
ext/ota/ota6.test
ext/ota/otafault.test
ext/ota/sqlite3ota.c
manifest
manifest.uuid

index da29454b9a87354f927217aaf43b63fe92a47dcd..6e1645edda8ebb270871e54434b531aff618b0ff 100644 (file)
@@ -26,6 +26,10 @@ proc run_ota {target ota} {
 }
 
 forcedelete test.db-oal ota.db
+db close
+sqlite3_shutdown
+sqlite3_config_uri 1
+reset_db
 
 #--------------------------------------------------------------------
 # Test that for an OTA to be applied, no corruption results if the
@@ -127,7 +131,6 @@ do_test 2.4 {
     INSERT INTO data_x2 VALUES(1, 'a', 2, 3, 0);
   }
   db2 close
-  breakpoint
   list [catch { run_ota test.db ota.db } msg] $msg
 } {1 SQLITE_ERROR}
 
@@ -153,5 +156,20 @@ do_test 3.2 {
   sqlite3ota_destroy_vfs win32
 } {}
 
+#-------------------------------------------------------------------------
+# Test that it is an error to specify an explicit VFS that does not 
+# include ota VFS functionality.
+#
+do_test 4.1 {
+  testvfs tvfs
+  sqlite3ota ota file:test.db?vfs=tvfs ota.db 
+  list [catch { ota step } msg] $msg
+} {0 SQLITE_ERROR}
+do_test 4.2 {
+  list [catch { ota close } msg] $msg
+} {1 {SQLITE_ERROR - ota vfs not found}}
+tvfs delete
+
 finish_test
 
+
index 3b794ee77c571f66f37cc60f99b585e47a686ad1..4fe14950b40693f16226f262f6da047d12f0851a 100644 (file)
@@ -45,7 +45,7 @@ proc setup_test {} {
 # file is being generated. Once this has happened, the update cannot be
 # progressed.
 #
-for {set nStep 1} {$nStep < 7} {incr nStep} {
+for {set nStep 1} {$nStep < 8} {incr nStep} {
   do_test 1.$nStep.1 {
     setup_test
     sqlite3ota ota test.db ota.db
@@ -68,12 +68,11 @@ for {set nStep 1} {$nStep < 7} {incr nStep} {
   } {1 {SQLITE_BUSY - database modified during ota update}}
 }
 
-
 # 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 7} {$nStep < 20} {incr nStep} {
+for {set nStep 8} {$nStep < 20} {incr nStep} {
   do_test 1.$nStep.1 {
     setup_test
     sqlite3ota ota test.db ota.db
index efc66673d615c250265915982fcb76bd24852a9d..d49f9d58f3f140ee1fe4b3db19b8b38fdbb4acfb 100644 (file)
@@ -37,7 +37,9 @@ foreach {tn2 setup sql expect} {
     INSERT INTO data_t1 VALUES(2, NULL, NULL, 1);
     INSERT INTO data_t1 VALUES(3, 'three', NULL, '.x.');
     INSERT INTO data_t1 VALUES(4, 4, 4, 0);
-  } {SELECT * FROM t1} {1 1 1   3 three 3   4 4 4}
+  } {
+    SELECT * FROM t1
+  } {1 1 1   3 three 3   4 4 4}
 
   2 {
     CREATE TABLE t2(a PRIMARY KEY, b, c) WITHOUT ROWID;
@@ -50,7 +52,9 @@ foreach {tn2 setup sql expect} {
     INSERT INTO data_t2 VALUES('b', NULL, NULL, 1);
     INSERT INTO data_t2 VALUES('c', 'see', NULL, '.x.');
     INSERT INTO data_t2 VALUES('d', 'd', 'd', 0);
-  } {SELECT * FROM t2} {a a a   c see c     d d d}
+  } {
+    SELECT * FROM t2
+  } {a a a   c see c     d d d}
 
   3 {
     CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
@@ -62,7 +66,23 @@ foreach {tn2 setup sql expect} {
     CREATE TABLE ota.data_t2(a, b, c, ota_control);
     INSERT INTO data_t1 VALUES(1, 2, 3, 0);
     INSERT INTO data_t2 VALUES(4, 5, 6, 0);
-  } {SELECT * FROM t1 UNION ALL SELECT * FROM t2} {1 2 3 4 5 6}
+  } {
+    SELECT * FROM t1 UNION ALL SELECT * FROM t2
+  } {1 2 3 4 5 6}
+
+  4 {
+    CREATE TABLE t1(a PRIMARY KEY, b, c);
+    CREATE INDEX t1c ON t1(c);
+    INSERT INTO t1 VALUES('A', 'B', 'C');
+    INSERT INTO t1 VALUES('D', 'E', 'F');
+
+    CREATE TABLE ota.data_t1(a, b, c, ota_control);
+    INSERT INTO data_t1 VALUES('D', NULL, NULL, 1);
+    INSERT INTO data_t1 VALUES('A', 'Z', NULL, '.x.');
+    INSERT INTO data_t1 VALUES('G', 'H', 'I', 0);
+  } {
+    SELECT * FROM t1 ORDER BY a;
+  } {A Z C G H I}
 
 } {
   catch {db close}
@@ -137,47 +157,59 @@ foreach {tn2 setup sql expect} {
     autoinstall_test_functions
 
 
-  }
-
-  for {set iStep 0} {$iStep<=21} {incr iStep} {
-  
-    forcedelete test.db-journal test.db-wal ota.db-journal ota.db-wal
-  
-    copy_if_exists test.db.bak test.db
-    copy_if_exists ota.db.bak ota.db
-  
-    sqlite3ota ota test.db ota.db
-    for {set x 0} {$x < $::iStep} {incr x} { ota step }
-    ota close
-  
-    copy_if_exists test.db test.db.bak.2
-    copy_if_exists test.db-wal test.db.bak.2-wal
-    copy_if_exists test.db-oal test.db.bak.2-oal
-    copy_if_exists ota.db ota.db.bak.2
-  
-    do_faultsim_test 3.$tn.$iStep -faults $::f -prep {
-      catch { db close }
+    for {set iStep 0} {$iStep<=21} {incr iStep} {
+    
       forcedelete test.db-journal test.db-wal ota.db-journal ota.db-wal
-      copy_if_exists test.db.bak.2 test.db
-      copy_if_exists test.db.bak.2-wal test.db-wal
-      copy_if_exists test.db.bak.2-oal test.db-oal
-      copy_if_exists ota.db.bak.2  ota.db
-    } -body {
+    
+      copy_if_exists test.db.bak test.db
+      copy_if_exists ota.db.bak ota.db
+    
       sqlite3ota ota test.db ota.db
-      while {[ota step] == "SQLITE_OK"} {}
+      for {set x 0} {$x < $::iStep} {incr x} { ota step }
       ota close
-    } -test {
-      faultsim_test_result {*}$::reslist
+  
+# sqlite3 x ota.db ; puts "XYZ [x eval { SELECT * FROM ota_state } ]" ; x close
     
-      if {$testrc==0} {
-        sqlite3 db test.db
-        faultsim_integrity_check
-        set res [db eval $::sql]
-        if {$res != [list {*}$::expect]} {
-          puts ""
-          puts "res: $res"
-          puts "exp: $expected"
-          error "data not as expected!"
+      copy_if_exists test.db     test.db.bak.2
+      copy_if_exists test.db-wal test.db.bak.2-wal
+      copy_if_exists test.db-oal test.db.bak.2-oal
+      copy_if_exists ota.db      ota.db.bak.2
+    
+      do_faultsim_test 3.$tn.$iStep -faults $::f -prep {
+        catch { db close }
+        forcedelete test.db-journal test.db-wal ota.db-journal ota.db-wal
+        copy_if_exists test.db.bak.2 test.db
+        copy_if_exists test.db.bak.2-wal test.db-wal
+        copy_if_exists test.db.bak.2-oal test.db-oal
+        copy_if_exists ota.db.bak.2  ota.db
+      } -body {
+        sqlite3ota ota test.db ota.db
+        ota step
+        ota close
+      } -test {
+
+        if {$testresult=="SQLITE_OK"} {set testresult "SQLITE_DONE"}
+        faultsim_test_result {*}$::reslist
+      
+        if {$testrc==0} {
+          # No error occurred. If the OTA has not already been fully applied,
+          # apply the rest of it now. Then ensure that the final state of the
+          # target db is as expected. And that "PRAGMA integrity_check"
+          # passes.
+          sqlite3ota ota test.db ota.db
+          while {[ota step] == "SQLITE_OK"} {}
+          ota close
+
+          sqlite3 db test.db
+          faultsim_integrity_check
+
+          set res [db eval $::sql]
+          if {$res != [list {*}$::expect]} {
+            puts ""
+            puts "res: $res"
+            puts "exp: $::expect"
+            error "data not as expected!"
+          }
         }
       }
     }
index b4a475bc0a07f475afa30c268d65f9a72ec376c4..0ef195481169e46f09aa29f57cf8dfc20529a02d 100644 (file)
 #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
+#define OTA_STAGE_MOVE        2
+#define OTA_STAGE_CAPTURE     3
+#define OTA_STAGE_CKPT        4
+#define OTA_STAGE_DONE        5
 
 
 #define OTA_CREATE_STATE "CREATE TABLE IF NOT EXISTS ota.ota_state"        \
@@ -949,7 +950,7 @@ static char *otaObjIterGetOldlist(
 
     /* For a table with implicit rowids, append "old._rowid_" to the list. */
     if( pIter->eType==OTA_PK_EXTERNAL || pIter->eType==OTA_PK_NONE ){
-      zList = sqlite3_mprintf("%z, %s._rowid_", zList, zObj);
+      zList = otaMPrintf(p, "%z, %s._rowid_", zList, zObj);
     }
   }
   return zList;
@@ -1116,6 +1117,11 @@ static char *otaWithoutRowidPK(sqlite3ota *p, OtaObjIter *pIter){
   return z;
 }
 
+static void otaFinalize(sqlite3ota *p, sqlite3_stmt *pStmt){
+  int rc = sqlite3_finalize(pStmt);
+  if( p->rc==SQLITE_OK ) p->rc = rc;
+}
+
 /*
 ** This function creates the second imposter table used when writing to
 ** a table b-tree where the table has an external primary key. If the
@@ -1160,18 +1166,13 @@ static void otaCreateImposterTable2(sqlite3ota *p, OtaObjIter *pIter){
       if( SQLITE_ROW==sqlite3_step(pQuery) ){
         zIdx = (const char*)sqlite3_column_text(pQuery, 0);
       }
-      if( zIdx==0 ){
-        p->rc = SQLITE_CORRUPT;
-      }
     }
-    assert( (zIdx==0)==(p->rc!=SQLITE_OK) );
-
-    if( p->rc==SQLITE_OK ){
+    if( zIdx ){
       p->rc = prepareFreeAndCollectError(p->db, &pXInfo, &p->zErrmsg,
           sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx)
       );
     }
-    sqlite3_finalize(pQuery);
+    otaFinalize(p, pQuery);
 
     while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){
       int bKey = sqlite3_column_int(pXInfo, 5);
@@ -1680,6 +1681,20 @@ static void otaCheckpointFrame(sqlite3ota *p, OtaFrame *pFrame){
   }
 }
 
+
+/*
+** Take an EXCLUSIVE lock on the database file.
+*/
+static void otaLockDatabase(sqlite3ota *p){
+  if( p->rc==SQLITE_OK ){
+    sqlite3_file *pReal = p->pTargetFd->pReal;
+    p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_SHARED);
+    if( p->rc==SQLITE_OK ){
+      p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_EXCLUSIVE);
+    }
+  }
+}
+
 /*
 ** 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,
@@ -1693,24 +1708,31 @@ static void otaMoveOalFile(sqlite3ota *p){
   char *zWal = sqlite3_mprintf("%s-wal", zBase);
   char *zOal = sqlite3_mprintf("%s-oal", zBase);
 
-  assert( p->eStage==OTA_STAGE_OAL );
+  assert( p->eStage==OTA_STAGE_MOVE );
   assert( p->rc==SQLITE_OK && p->zErrmsg==0 );
   if( zWal==0 || zOal==0 ){
     p->rc = SQLITE_NOMEM;
   }else{
     /* Move the *-oal file to *-wal. At this point connection p->db is
     ** holding a SHARED lock on the target database file (because it is
-    ** in WAL mode). So no other connection may be writing the db.  */
-    otaFileSuffix3(zBase, zWal);
-    otaFileSuffix3(zBase, zOal);
-    rename(zOal, zWal);
-
-    /* Re-open the databases. */
-    otaObjIterFinalize(&p->objiter);
-    sqlite3_close(p->db);
-    p->db = 0;
-    otaOpenDatabase(p);
-    otaSetupCheckpoint(p, 0);
+    ** in WAL mode). So no other connection may be writing the db. 
+    **
+    ** In order to ensure that there are no database readers, an EXCLUSIVE
+    ** lock is obtained here before the *-oal is moved to *-wal.
+    */
+    otaLockDatabase(p);
+    if( p->rc==SQLITE_OK ){
+      otaFileSuffix3(zBase, zWal);
+      otaFileSuffix3(zBase, zOal);
+      rename(zOal, zWal);
+
+      /* Re-open the databases. */
+      otaObjIterFinalize(&p->objiter);
+      sqlite3_close(p->db);
+      p->db = 0;
+      otaOpenDatabase(p);
+      otaSetupCheckpoint(p, 0);
+    }
   }
 
   sqlite3_free(zWal);
@@ -1904,24 +1926,66 @@ static int otaStep(sqlite3ota *p){
 ** Increment the schema cookie of the main database opened by p->db.
 */
 static void otaIncrSchemaCookie(sqlite3ota *p){
-  int iCookie = 1000000;
-  sqlite3_stmt *pStmt;
-
-  assert( p->rc==SQLITE_OK && p->zErrmsg==0 );
-  p->rc = prepareAndCollectError(p->db, &pStmt, &p->zErrmsg, 
-      "PRAGMA schema_version"
-  );
   if( p->rc==SQLITE_OK ){
-    if( SQLITE_ROW==sqlite3_step(pStmt) ){
-      iCookie = sqlite3_column_int(pStmt, 0);
+    int iCookie = 1000000;
+    sqlite3_stmt *pStmt;
+
+    p->rc = prepareAndCollectError(p->db, &pStmt, &p->zErrmsg, 
+        "PRAGMA schema_version"
+    );
+    if( p->rc==SQLITE_OK ){
+      if( SQLITE_ROW==sqlite3_step(pStmt) ){
+        iCookie = sqlite3_column_int(pStmt, 0);
+      }
+      p->rc = sqlite3_finalize(pStmt);
+    }
+    if( p->rc==SQLITE_OK ){
+      otaMPrintfExec(p, "PRAGMA schema_version = %d", iCookie+1);
     }
-    p->rc = sqlite3_finalize(pStmt);
   }
-  if( p->rc==SQLITE_OK ){
-    otaMPrintfExec(p, "PRAGMA schema_version = %d", iCookie+1);
+}
+
+static void otaSaveState(sqlite3ota *p, int eStage){
+  if( p->rc==SQLITE_OK || p->rc==SQLITE_DONE ){
+    sqlite3_stmt *pInsert = 0;
+    int rc;
+
+    assert( p->zErrmsg==0 );
+    rc = prepareFreeAndCollectError(p->db, &pInsert, &p->zErrmsg, 
+        sqlite3_mprintf(
+          "INSERT OR REPLACE INTO ota.ota_state(k, v) VALUES "
+          "(%d, %d), "
+          "(%d, %Q), "
+          "(%d, %Q), "
+          "(%d, %d), "
+          "(%d, %lld), "
+          "(%d, %lld), "
+          "(%d, %lld) ",
+          OTA_STATE_STAGE, 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, p->iWalCksum,
+          OTA_STATE_COOKIE, (i64)p->pTargetFd->iCookie
+          )
+        );
+    assert( pInsert==0 || rc==SQLITE_OK );
+
+    if( rc==SQLITE_OK ){
+      sqlite3_step(pInsert);
+      rc = sqlite3_finalize(pInsert);
+    }else{
+      sqlite3_finalize(pInsert);
+    }
+
+    if( rc!=SQLITE_OK ){
+      p->rc = rc;
+    }
   }
 }
 
+
 /*
 ** Step the OTA object.
 */
@@ -1959,14 +2023,20 @@ int sqlite3ota_step(sqlite3ota *p){
         }
 
         if( p->rc==SQLITE_OK && pIter->zTbl==0 ){
-          p->nProgress++;
+          otaSaveState(p, OTA_STAGE_MOVE);
           otaIncrSchemaCookie(p);
           if( p->rc==SQLITE_OK ){
             p->rc = sqlite3_exec(p->db, "COMMIT", 0, 0, &p->zErrmsg);
           }
-          if( p->rc==SQLITE_OK ){
-            otaMoveOalFile(p);
-          }
+          p->eStage = OTA_STAGE_MOVE;
+        }
+        break;
+      }
+
+      case OTA_STAGE_MOVE: {
+        if( p->rc==SQLITE_OK ){
+          otaMoveOalFile(p);
+          p->nProgress++;
         }
         break;
       }
@@ -2010,44 +2080,6 @@ int sqlite3ota_step(sqlite3ota *p){
   }
 }
 
-static void otaSaveState(sqlite3ota *p){
-  sqlite3_stmt *pInsert;
-  int rc;
-
-  assert( (p->rc==SQLITE_OK || p->rc==SQLITE_DONE) && p->zErrmsg==0 );
-  rc = prepareFreeAndCollectError(p->db, &pInsert, &p->zErrmsg, 
-      sqlite3_mprintf(
-        "INSERT OR REPLACE INTO ota.ota_state(k, v) VALUES "
-        "(%d, %d), "
-        "(%d, %Q), "
-        "(%d, %Q), "
-        "(%d, %d), "
-        "(%d, %lld), "
-        "(%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, p->iWalCksum,
-        OTA_STATE_COOKIE, (i64)p->pTargetFd->iCookie
-      )
-  );
-  assert( pInsert==0 || rc==SQLITE_OK );
-
-  if( rc==SQLITE_OK ){
-    sqlite3_step(pInsert);
-    rc = sqlite3_finalize(pInsert);
-  }else{
-    sqlite3_finalize(pInsert);
-  }
-
-  if( rc!=SQLITE_OK ){
-    p->rc = rc;
-  }
-}
-
 static void otaFreeState(OtaState *p){
   if( p ){
     sqlite3_free(p->zTbl);
@@ -2081,6 +2113,7 @@ static OtaState *otaLoadState(sqlite3ota *p){
       case OTA_STATE_STAGE:
         pRet->eStage = sqlite3_column_int(pStmt, 1);
         if( pRet->eStage!=OTA_STAGE_OAL
+         && pRet->eStage!=OTA_STAGE_MOVE
          && pRet->eStage!=OTA_STAGE_CKPT
         ){
           p->rc = SQLITE_CORRUPT;
@@ -2236,26 +2269,28 @@ sqlite3ota *sqlite3ota_open(const char *zTarget, const char *zOta){
     }
     assert( p->rc!=SQLITE_OK || p->eStage!=0 );
 
-    if( p->rc==SQLITE_OK ){
-      if( p->eStage==OTA_STAGE_OAL ){
+    if( p->rc==SQLITE_OK 
+     && (p->eStage==OTA_STAGE_OAL || p->eStage==OTA_STAGE_MOVE)
+    ){   
+      /* Check that this is not a wal mode database. If it is, it cannot 
+      ** be updated.  */
+      if( p->pTargetFd->pWalFd ){
+        p->rc = SQLITE_ERROR;
+        p->zErrmsg = sqlite3_mprintf("cannot update wal mode database");
+      }
 
-        /* Check that this is not a wal mode database. If it is, it cannot 
-        ** be updated.  */
-        if( p->pTargetFd->pWalFd ){
-          p->rc = SQLITE_ERROR;
-          p->zErrmsg = sqlite3_mprintf("cannot update wal mode database");
-        }
+      /* At this point (pTargetFd->iCookie) contains the value of the
+      ** change-counter cookie (the thing that gets incremented when a 
+      ** transaction is committed in rollback mode) currently stored on 
+      ** page 1 of the database file. */
+      else if( pState->eStage!=0 && p->pTargetFd->iCookie!=pState->iCookie ){
+        p->rc = SQLITE_BUSY;
+        p->zErrmsg = sqlite3_mprintf("database modified during ota update");
+      }
+    }
 
-        /* At this point (pTargetFd->iCookie) contains the value of the
-        ** change-counter cookie (the thing that gets incremented when a 
-        ** transaction is committed in rollback mode) currently stored on 
-        ** page 1 of the database file. */
-        else if( pState->eStage==OTA_STAGE_OAL 
-         && p->pTargetFd->iCookie!=pState->iCookie 
-        ){
-          p->rc = SQLITE_BUSY;
-          p->zErrmsg = sqlite3_mprintf("database modified during ota update");
-        }
+    if( p->rc==SQLITE_OK ){
+      if( p->eStage==OTA_STAGE_OAL ){
 
         /* Open the transaction */
         if( p->rc==SQLITE_OK ){
@@ -2270,6 +2305,8 @@ sqlite3ota *sqlite3ota_open(const char *zTarget, const char *zOta){
         if( p->rc==SQLITE_OK ){
           otaLoadTransactionState(p, pState);
         }
+      }else if( p->eStage==OTA_STAGE_MOVE ){
+        /* no-op */
       }else if( p->eStage==OTA_STAGE_CKPT ){
         otaSetupCheckpoint(p, pState);
         p->nStep = pState->nRow;
@@ -2325,10 +2362,7 @@ int sqlite3ota_close(sqlite3ota *p, char **pzErrmsg){
     ** the ota db. If successful, this call also commits the open 
     ** transaction on the ota db. */
     assert( p->rc!=SQLITE_ROW );
-    if( p->rc==SQLITE_OK || p->rc==SQLITE_DONE ){
-      assert( p->zErrmsg==0 );
-      otaSaveState(p);
-    }
+    otaSaveState(p, p->eStage);
 
     /* Close any open statement handles. */
     otaObjIterFinalize(&p->objiter);
@@ -2627,7 +2661,7 @@ static int otaVfsShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
 #endif
 
   assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
-  if( pOta && pOta->eStage==OTA_STAGE_OAL ){
+  if( pOta && (pOta->eStage==OTA_STAGE_OAL || pOta->eStage==OTA_STAGE_MOVE) ){
     /* 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 
@@ -2636,7 +2670,7 @@ static int otaVfsShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
   }else{
     int bCapture = 0;
     if( n==1 && (flags & SQLITE_SHM_EXCLUSIVE)
-     && p->pOta && p->pOta->eStage==OTA_STAGE_CAPTURE
+     && pOta && pOta->eStage==OTA_STAGE_CAPTURE
      && (ofst==WAL_LOCK_WRITE || ofst==WAL_LOCK_CKPT || ofst==WAL_LOCK_READ0)
     ){
       bCapture = 1;
@@ -2645,7 +2679,7 @@ static int otaVfsShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
     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);
+        pOta->mLock |= (1 << ofst);
       }
     }
   }
@@ -2662,12 +2696,13 @@ static int otaVfsShmMap(
 ){
   ota_file *p = (ota_file*)pFile;
   int rc = SQLITE_OK;
+  int eStage = (p->pOta ? p->pOta->eStage : 0);
 
   /* 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( eStage==OTA_STAGE_OAL || eStage==OTA_STAGE_MOVE ){
     if( iRegion<=p->nShm ){
       int nByte = (iRegion+1) * sizeof(char*);
       char **apNew = (char**)sqlite3_realloc(p->apShm, nByte);
@@ -2714,9 +2749,10 @@ static void otaVfsShmBarrier(sqlite3_file *pFile){
 static int otaVfsShmUnmap(sqlite3_file *pFile, int delFlag){
   ota_file *p = (ota_file*)pFile;
   int rc = SQLITE_OK;
+  int eStage = (p->pOta ? p->pOta->eStage : 0);
 
   assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
-  if( p->pOta && p->pOta->eStage==OTA_STAGE_OAL ){
+  if( eStage==OTA_STAGE_OAL || eStage==OTA_STAGE_MOVE ){
     /* no-op */
   }else{
     rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag);
index 66b0b3d8291b488048e87757c595f6b60ad9f5c6..48056fe9f66b26d13c0bfc4f67cc37105ad7725a 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Improve\stest\scoverage\sof\sota\scode\sa\sbit.
-D 2015-02-17T20:49:42.756
+C Fix\sa\sproblem\swith\sOTA\supdates\sin\sthe\spresence\sof\sdatabase\sreaders.
+D 2015-02-18T17:40:05.856
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 6b9e7677829aa94b9f30949656e27312aefb9a46
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -128,15 +128,15 @@ F ext/ota/ota.c c11a85af71dccc45976622fe7a51169a481caa91
 F ext/ota/ota1.test 88a47987dc12780c23d9efbeb0e9416c838eb1f6
 F ext/ota/ota10.test 85e0f6e7964db5007590c1b299e75211ed4240d4
 F ext/ota/ota11.test 0a0c56b9474f82097018a8f399172417737c64c9
-F ext/ota/ota3.test cd654ef16fc6b3d3596894ee3f3b8fd821b969f5
+F ext/ota/ota3.test 59fc88cf9749156c8a0b3ed9210b72a6af3f29d0
 F ext/ota/ota5.test ad0799daf8923ddebffe75ae8c5504ca90b7fadb
-F ext/ota/ota6.test 40996b7716dee72a6c5d28c3bee436717a438d3d
+F ext/ota/ota6.test 3bde7f69a894748b27206b6753462ec3b75b6bb6
 F ext/ota/ota7.test 1fe2c5761705374530e29f70c39693076028221a
 F ext/ota/ota8.test cd70e63a0c29c45c0906692827deafa34638feda
 F ext/ota/ota9.test d3eee95dd836824d07a22e5efcdb7bf6e869358b
 F ext/ota/otaA.test ef4bfa8cfd4ed814ae86f7457b64aa2f18c90171
-F ext/ota/otafault.test 0c7565f69e5e379a5ebdcaea4056f0c69da1becf
-F ext/ota/sqlite3ota.c 0c6cb4cea1a9231bc488e9c84da201b796437af6
+F ext/ota/otafault.test c17e0297b4d2b83115fa733b614cf4883cd826f2
+F ext/ota/sqlite3ota.c f04e79519f275ae932ad3573a089e2ef08552a78
 F ext/ota/sqlite3ota.h 1cc7201086fe65a36957740381485a24738c4077
 F ext/ota/test_ota.c 5dd58e4e6eb3ae7b471566616d44b701971bce88
 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
@@ -1256,7 +1256,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 e0b7151962fedbcac975f2216fd6b33b995a8945
-R 13b826f0fe6f2960ec7719bf830cc36a
+P a438fa6c9ad2fb1d78ac747172d07455d6381387
+R 4b928e3e4481330de038aee8bbb8f63e
 U dan
-Z 295fff9fbb7cdd54355b757b10496bab
+Z 71e8a5928d01f269472bf7adff7d46be
index 3de9df01220d1ae443c101ff9f907f7beb922bf6..4a97b0bd4d4828d66fa2c3bdb9bfd9cc9af6e6a3 100644 (file)
@@ -1 +1 @@
-a438fa6c9ad2fb1d78ac747172d07455d6381387
\ No newline at end of file
+144bb29ffcbfe96dc10c0224113e73a80e89314b
\ No newline at end of file