SQLite

Check-in [1cb675e539]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Improve tests for resuming ota updates following power failures. Fix a problem revealed by the same.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | ota-update
Files: files | file ages | folders
SHA1: 1cb675e5392f179516d8e7a52760922a6c7df4d0
User & Date: dan 2015-02-23 12:22:55.407
Context
2015-02-23
15:02
Update the sqlite3ota_db() API to account for the fact that each OTA handle now uses two SQLite database handles. (check-in: ef08ecceb7 user: dan tags: ota-update)
12:22
Improve tests for resuming ota updates following power failures. Fix a problem revealed by the same. (check-in: 1cb675e539 user: dan tags: ota-update)
2015-02-21
20:08
Fix some problems with resuming ota updates if saving the state is interrupted by a power failure or system crash. (check-in: 6d5ed70d0d user: dan tags: ota-update)
Changes
Unified Diff Ignore Whitespace Patch
Changes to ext/ota/otacrash.test.
32
33
34
35
36
37
38












39




40
41









42
43


44

















45


46


47

48






49
50

51

52

53



54



55
56
57
58
59
60
61
62
63
64

65
66
67







68
69
70
71
  INSERT INTO data_t1 VALUES(13, 14, 15, 0);
  INSERT INTO data_t1 VALUES(4, NULL, NULL, 1);
  INSERT INTO data_t1 VALUES(1, NULL, 100, '..x');
}
db_save_and_close














for {set i 0} {$i < 10} {incr i} {




  forcedelete test.db2 test.db2-journal test.db test.db-oal test.db-wal
  db_restore









  do_test 2.$i.1 {
    crashsql -file test.db2 -delay 3 -tclbody {




















      sqlite3ota ota test.db file:test.db2?vfs=crash


      ota step


      ota close








      sqlite3ota ota test.db file:test.db2?vfs=crash
      ota step

      ota step

      ota close

    } {}



  } {1 {child process exited abnormally}}




  do_test 2.$i.2 {
    sqlite3ota ota test.db test.db2
    while {[ota step]=="SQLITE_OK"} {}
    ota close
  } {SQLITE_DONE}

  sqlite3 db test.db
  do_execsql_test 2.$i.3 {
    SELECT * FROM t1;

  } {1 2 100  7 8 9  10 11 12  13 14 15}
  do_execsql_test 2.$i.4 { PRAGMA integrity_check } {ok}
  db close







}

finish_test








>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
|

>
>
>
>
>
>
>
>
>
|
|
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
|
>
>
|
>

>
>
>
>
>
>
|
|
>
|
>

>
|
>
>
>
|
>
>
>
|
|



<

|
|
|
>
|
<
|
>
>
>
>
>
>
>




32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123

124
125
126
127
128
129

130
131
132
133
134
135
136
137
138
139
140
141
  INSERT INTO data_t1 VALUES(13, 14, 15, 0);
  INSERT INTO data_t1 VALUES(4, NULL, NULL, 1);
  INSERT INTO data_t1 VALUES(1, NULL, 100, '..x');
}
db_save_and_close


# Determine the number of steps in applying the ota update to the test
# target database created above. Set $::ota_num_steps accordingly
#
# Check that the same number of steps are required to apply the ota
# update using many calls to sqlite3ota_step() on a single ota handle
# as required to apply it using a series of ota handles, on each of 
# which sqlite3ota_step() is called once.
#
do_test 1.1 {
  db_restore
  sqlite3ota ota test.db test.db2
  breakpoint
  set nStep 0
  while {[ota step]=="SQLITE_OK"} { incr nStep }
  ota close
} {SQLITE_DONE}
set ota_num_steps $nStep
do_test 1.2 {
  db_restore
  set nStep 0
  while {1} {
    sqlite3ota ota test.db test.db2
    ota step
    if {[ota close]=="SQLITE_DONE"} break
    incr nStep
  }
  set nStep
} $ota_num_steps


# Run one or more tests using the target (test.db) and ota (test.db2)
# databases created above. As follows:
#
#   1. This process starts the ota update and calls sqlite3ota_step()
#      $nPre times. Then closes the ota update handle.
#
#   2. A second process resumes the ota update and attempts to call 
#      sqlite3ota_step() $nStep times before closing the handle. A
#      crash is simulated during each xSync() of file test.db2.
#
#   3. This process attempts to resume the ota update from whatever
#      state it was left in by step (2). Test that it is successful
#      in doing so and that the final target database is as expected.
#
# In total (nSync+1) tests are run, where nSync is the number of times
# xSync() is called on test.db2.
#
proc do_ota_crash_test {tn nPre nStep} {

  set script [subst -nocommands {
    sqlite3ota ota test.db file:test.db2?vfs=crash
    set i 0
    while {[set i] < $nStep} {
      if {[ota step]!="SQLITE_OK"} break
      incr i
    }
    ota close
  }]

  set bDone 0
  for {set iDelay 1} {$bDone==0} {incr iDelay} {
    forcedelete test.db2 test.db2-journal test.db test.db-oal test.db-wal
    db_restore

    if {$nPre>0} {
      sqlite3ota ota test.db file:test.db2
      set i 0
      for {set i 0} {$i < $nPre} {incr i} { 
        if {[ota step]!="SQLITE_OK"} break
      }
      ota close
    }

    set res [crashsql -file test.db2 -delay $iDelay -tclbody $script {}]

    set bDone 1
    if {$res == "1 {child process exited abnormally}"} {
      set bDone 0
    } elseif {$res != "0 {}"} {
      error "unexected catchsql result: $res"
    }

    sqlite3ota ota test.db test.db2
    while {[ota step]=="SQLITE_OK"} {}
    ota close


    sqlite3 db test.db
    do_execsql_test $tn.delay=$iDelay {
      SELECT * FROM t1;
      PRAGMA integrity_check;
    } {1 2 100  7 8 9  10 11 12  13 14 15  ok}

    db close
  }
}

for {set nPre 0} {$nPre < $ota_num_steps} {incr nPre} {
  for {set is 1} {$is <= ($ota_num_steps - $nPre)} {incr is} {
    do_ota_crash_test 2.pre=$nPre.step=$is $nPre $is
  }
}

finish_test

Changes to ext/ota/sqlite3ota.c.
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597



2598
2599





2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
        }
        p->nProgress = pState->nProgress;
        p->iOalSz = pState->iOalSz;
      }
    }
    assert( p->rc!=SQLITE_OK || p->eStage!=0 );

    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");



      }






      /* 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");
      }
    }

    if( p->rc==SQLITE_OK ){
      if( p->eStage==OTA_STAGE_OAL ){

        /* Open transactions both databases. The *-oal file is opened or
        ** created at this point. */







|
|
<
<
<
<


>
>
>

|
>
>
>
>
>




<
|
|
<







2583
2584
2585
2586
2587
2588
2589
2590
2591




2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607

2608
2609

2610
2611
2612
2613
2614
2615
2616
        }
        p->nProgress = pState->nProgress;
        p->iOalSz = pState->iOalSz;
      }
    }
    assert( p->rc!=SQLITE_OK || p->eStage!=0 );

    if( p->rc==SQLITE_OK && p->pTargetFd->pWalFd ){
      if( p->eStage==OTA_STAGE_OAL ){




        p->rc = SQLITE_ERROR;
        p->zErrmsg = sqlite3_mprintf("cannot update wal mode database");
      }else if( p->eStage==OTA_STAGE_MOVE ){
        p->eStage = OTA_STAGE_CKPT;
        p->nStep = 0;
      }
    }

    if( p->rc==SQLITE_OK
     && (p->eStage==OTA_STAGE_OAL || p->eStage==OTA_STAGE_MOVE)
     && pState->eStage!=0 && p->pTargetFd->iCookie!=pState->iCookie
    ){   
      /* 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. */

      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 transactions both databases. The *-oal file is opened or
        ** created at this point. */