/ Check-in [197d00d6]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Activate test cases for new journal format. (CVS 1687)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 197d00d6a6a440848a0b4710157272558868221c
User & Date: danielk1977 2004-06-25 06:23:23
Context
2004-06-25
07:21
Add a comment on the implementation of sqlite3OsLock(). No code changes. (CVS 1688) check-in: 084f3fff user: danielk1977 tags: trunk
06:23
Activate test cases for new journal format. (CVS 1687) check-in: 197d00d6 user: danielk1977 tags: trunk
02:38
Modifications to the journal format to make it more robust. (CVS 1686) check-in: 504246a1 user: danielk1977 tags: trunk
Changes
Hide Diffs Unified Diffs Show Whitespace Changes Patch

Changes to src/os_test.c.

208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
...
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
    if( p ){
      int skip = 0;
      int trash = 0;
      if( crash ){
        char random;
        sqlite3Randomness(1, &random);
        if( random & 0x01 ){
          if( 0 && random & 0x02 ){
            trash = 1;
#ifdef TRACE_WRITECACHE
printf("Trashing block %d of %s\n", i, pFile->zName); 
#endif
          }else{
            skip = 1;
#ifdef TRACE_WRITECACHE
................................................................................
*/
static int writeCache(OsTestFile *pFile){
  if( pFile->apBlk ){
    int c = crashRequired(pFile->zName);
    if( c ){
      OsTestFile *p;
#ifdef TRACE_WRITECACHE
      printf("Crash during sync of %s\n", pFile->zName);
#endif
      for(p=pAllFiles; p; p=p->pNext){
        writeCache2(p, 1);
      }
      exit(-1);
    }else{
      return writeCache2(pFile, 0);







|







 







|







208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
...
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
    if( p ){
      int skip = 0;
      int trash = 0;
      if( crash ){
        char random;
        sqlite3Randomness(1, &random);
        if( random & 0x01 ){
          if( random & 0x02 ){
            trash = 1;
#ifdef TRACE_WRITECACHE
printf("Trashing block %d of %s\n", i, pFile->zName); 
#endif
          }else{
            skip = 1;
#ifdef TRACE_WRITECACHE
................................................................................
*/
static int writeCache(OsTestFile *pFile){
  if( pFile->apBlk ){
    int c = crashRequired(pFile->zName);
    if( c ){
      OsTestFile *p;
#ifdef TRACE_WRITECACHE
      printf("\nCrash during sync of %s\n", pFile->zName);
#endif
      for(p=pAllFiles; p; p=p->pNext){
        writeCache2(p, 1);
      }
      exit(-1);
    }else{
      return writeCache2(pFile, 0);

Changes to src/pager.c.

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
....
2042
2043
2044
2045
2046
2047
2048

2049
2050
2051
2052
2053
2054
2055
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.138 2004/06/25 02:38:55 danielk1977 Exp $
*/
#include "os.h"         /* Must be first to enable large file support */
#include "sqliteInt.h"
#include "pager.h"
#include <assert.h>
#include <string.h>

................................................................................
          /* If in full-sync mode, write a new journal header into the
	  ** journal file. This is done to avoid ever modifying a journal
	  ** header that is involved in the rollback of pages that have
	  ** already been written to the database (in case the header is
	  ** trashed when the nRec field is updated).
          */
          pPager->nRec = 0;

          rc = writeJournalHdr(pPager);
          if( rc!=0 ){
            sqlite3pager_rollback(pPager);
            return SQLITE_IOERR;
          }
        }
        pPg = pPager->pFirst;







|







 







>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
....
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.139 2004/06/25 06:23:23 danielk1977 Exp $
*/
#include "os.h"         /* Must be first to enable large file support */
#include "sqliteInt.h"
#include "pager.h"
#include <assert.h>
#include <string.h>

................................................................................
          /* If in full-sync mode, write a new journal header into the
	  ** journal file. This is done to avoid ever modifying a journal
	  ** header that is involved in the rollback of pages that have
	  ** already been written to the database (in case the header is
	  ** trashed when the nRec field is updated).
          */
          pPager->nRec = 0;
          assert( pPager->journalOff > 0 );
          rc = writeJournalHdr(pPager);
          if( rc!=0 ){
            sqlite3pager_rollback(pPager);
            return SQLITE_IOERR;
          }
        }
        pPg = pPager->pFirst;

Changes to test/crash.test.

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
..
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
..
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
...
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
...
222
223
224
225
226
227
228

229


230
231
232
233
234
235
236
...
298
299
300
301
302
303
304
305
306
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# $Id: crash.test,v 1.3 2004/06/23 10:43:15 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

set repeats 100
# set repeats 5

# This proc execs a seperate process that crashes midway through executing
# the SQL script $sql on database test.db.
#
# The crash occurs during a sync() of file $crashfile. When the crash
# occurs a random subset of all unsynced writes made by the process are
# written into the files on disk. Argument $crashdelay indicates the
................................................................................
# occured.
proc crashsql {crashdelay crashfile sql} {
  set cfile [file join [pwd] $crashfile]

  set f [open crash.tcl w]
  puts $f "sqlite3_crashparams $crashdelay $cfile"
  puts $f "sqlite3 db test.db"

  puts $f "db eval {pragma full_synchronous = 1}"
  puts $f "db eval {"
  puts $f   "$sql"
  puts $f "}"
  close $f

  set r [catch {
    exec [file join . crashtest] crash.tcl
  } msg]
  lappend r $msg
}

# The following procedure computes a "signature" for table "abc".  If
# abc changes in any way, the signature should change.  
proc signature {} {
  return [db eval {SELECT count(*), md5sum(a), md5sum(b), md5sum(c) FROM abc}]
}
proc signature2 {} {
  return [db eval {SELECT count(*), md5sum(a), md5sum(b), md5sum(c) FROM abc2}]
}

# Use a small pager-cache for these tests.
do_test crash-0.1 {
  execsql { pragma default_cache_size = 10 }
} {}

#--------------------------------------------------------------------------
# Simple crash test:
#
# crash-1.1: Create a database with a table with two rows.
# crash-1.2: Run a 'DELETE FROM abc WHERE a = 1' that crashes during
#            the first journal-sync.
# crash-1.3: Ensure the database is in the same state as after crash-1.1.
# crash-1.4: Run a 'DELETE FROM abc WHERE a = 1' that crashes during
#            the first database-sync.
# crash-1.5: Ensure the database is in the same state as after crash-1.1.



#
# Tests 1.6 through 1.9 are the same as 1.2 through 1.5, except the crash
# is requested on the second sync of each file. This doesn't happen in


# such a small test case, so these tests are just to verify that the
# test infrastructure operates as expected.
#
do_test crash-1.1 {
  execsql {
    CREATE TABLE abc(a, b, c);
    INSERT INTO abc VALUES(1, 2, 3);
    INSERT INTO abc VALUES(4, 5, 6);
  }
................................................................................
  expr 0
} {0}
do_test crash-1.2 {
  crashsql 1 test.db-journal {
    DELETE FROM abc WHERE a = 1;
  }
} {1 {child process exited abnormally}}

# exit

do_test crash-1.3 {
  signature
} $::sig
do_test crash-1.4 {
  crashsql 1 test.db {
    DELETE FROM abc WHERE a = 1;
  }
................................................................................
do_test crash-1.5 {
  signature
} $::sig
do_test crash-1.6 {
  crashsql 2 test.db-journal {
    DELETE FROM abc WHERE a = 1;
  }
} {0 {}}
do_test crash-1.7 {
  catchsql {
    SELECT * FROM abc;
  }











} {0 {4 5 6}}
do_test crash-1.8 {
  crashsql 2 test.db {
    DELETE FROM abc WHERE a = 4;
  }
} {0 {}}
do_test crash-1.9 {
  catchsql {
    SELECT * FROM abc;
  }
} {0 {}}

#--------------------------------------------------------------------------
# The following tests test recovery when both the database file and the the
................................................................................
# crash-4.3.*: Test recovery when crash occurs during sync() of the master
#              journal file. 
#
do_test crash-4.0 {
  file delete -force test2.db
  file delete -force test2.db-journal
  sqlite3 db2 test2.db

  execsql {pragma default_cache_size = 10} db2


  db2 close
  execsql {
    ATTACH 'test2.db' AS aux;
    CREATE TABLE aux.abc2 AS SELECT 2*a as a, 2*b as b, 2*c as c FROM abc;
  }
  expr [file size test2.db] / 1024
} {559}
................................................................................
    signature
  } $sig
  do_test crash-4.3.$i.3 {
    signature2
  } $sig2
}

finish_test








|





|







 







>
|






|













<
<
<
<
<










>
>
>

<
<
>
>
|
|







 







<
<
<







 







|




>
>
>
>
>
>
>
>
>
>
>

|




|







 







>
|
>
>







 







<

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
..
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
..
88
89
90
91
92
93
94



95
96
97
98
99
100
101
...
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
...
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
...
308
309
310
311
312
313
314

315
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# $Id: crash.test,v 1.4 2004/06/25 06:23:23 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

set repeats 100
# set repeats 10

# This proc execs a seperate process that crashes midway through executing
# the SQL script $sql on database test.db.
#
# The crash occurs during a sync() of file $crashfile. When the crash
# occurs a random subset of all unsynced writes made by the process are
# written into the files on disk. Argument $crashdelay indicates the
................................................................................
# occured.
proc crashsql {crashdelay crashfile sql} {
  set cfile [file join [pwd] $crashfile]

  set f [open crash.tcl w]
  puts $f "sqlite3_crashparams $crashdelay $cfile"
  puts $f "sqlite3 db test.db"
  puts $f "db eval {pragma synchronous = full}"
  puts $f "db eval {pragma cache_size = 10}"
  puts $f "db eval {"
  puts $f   "$sql"
  puts $f "}"
  close $f

  set r [catch {
    exec [file join . crashtest] crash.tcl >@stdout
  } msg]
  lappend r $msg
}

# The following procedure computes a "signature" for table "abc".  If
# abc changes in any way, the signature should change.  
proc signature {} {
  return [db eval {SELECT count(*), md5sum(a), md5sum(b), md5sum(c) FROM abc}]
}
proc signature2 {} {
  return [db eval {SELECT count(*), md5sum(a), md5sum(b), md5sum(c) FROM abc2}]
}






#--------------------------------------------------------------------------
# Simple crash test:
#
# crash-1.1: Create a database with a table with two rows.
# crash-1.2: Run a 'DELETE FROM abc WHERE a = 1' that crashes during
#            the first journal-sync.
# crash-1.3: Ensure the database is in the same state as after crash-1.1.
# crash-1.4: Run a 'DELETE FROM abc WHERE a = 1' that crashes during
#            the first database-sync.
# crash-1.5: Ensure the database is in the same state as after crash-1.1.
# crash-1.6: Run a 'DELETE FROM abc WHERE a = 1' that crashes during
#            the second journal-sync.
# crash-1.7: Ensure the database is in the same state as after crash-1.1.
#


# Tests 1.8 through 1.11 test for crashes on the third journal sync and
# second database sync.  Neither of these is required in such a small test
# case, so these tests are just to verify that the test infrastructure
# operates as expected.
#
do_test crash-1.1 {
  execsql {
    CREATE TABLE abc(a, b, c);
    INSERT INTO abc VALUES(1, 2, 3);
    INSERT INTO abc VALUES(4, 5, 6);
  }
................................................................................
  expr 0
} {0}
do_test crash-1.2 {
  crashsql 1 test.db-journal {
    DELETE FROM abc WHERE a = 1;
  }
} {1 {child process exited abnormally}}



do_test crash-1.3 {
  signature
} $::sig
do_test crash-1.4 {
  crashsql 1 test.db {
    DELETE FROM abc WHERE a = 1;
  }
................................................................................
do_test crash-1.5 {
  signature
} $::sig
do_test crash-1.6 {
  crashsql 2 test.db-journal {
    DELETE FROM abc WHERE a = 1;
  }
} {1 {child process exited abnormally}}
do_test crash-1.7 {
  catchsql {
    SELECT * FROM abc;
  }
} {0 {1 2 3 4 5 6}}

do_test crash-1.8 {
  crashsql 3 test.db-journal {
    DELETE FROM abc WHERE a = 1;
  }
} {0 {}}
do_test crash-1.9 {
  catchsql {
    SELECT * FROM abc;
  }
} {0 {4 5 6}}
do_test crash-1.10 {
  crashsql 2 test.db {
    DELETE FROM abc WHERE a = 4;
  }
} {0 {}}
do_test crash-1.11 {
  catchsql {
    SELECT * FROM abc;
  }
} {0 {}}

#--------------------------------------------------------------------------
# The following tests test recovery when both the database file and the the
................................................................................
# crash-4.3.*: Test recovery when crash occurs during sync() of the master
#              journal file. 
#
do_test crash-4.0 {
  file delete -force test2.db
  file delete -force test2.db-journal
  sqlite3 db2 test2.db
  execsql {
    pragma default_cache_size = 10;
    pragma default_synchronous = full;
  } db2
  db2 close
  execsql {
    ATTACH 'test2.db' AS aux;
    CREATE TABLE aux.abc2 AS SELECT 2*a as a, 2*b as b, 2*c as c FROM abc;
  }
  expr [file size test2.db] / 1024
} {559}
................................................................................
    signature
  } $sig
  do_test crash-4.3.$i.3 {
    signature2
  } $sig2
}