/ Check-in [9f6ea1de]
Login

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

Overview
Comment:Merge trunk updates with experimental branch. Also add tests to journal2.test.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | experimental
Files: files | file ages | folders
SHA1: 9f6ea1de5abab0ca28688e257ddf03c66413cf6e
User & Date: dan 2010-06-17 10:52:07
Original Comment: Merge trunk updates with experimental branch.
Context
2010-06-17
11:36
Fix bug in journal2.test. check-in: c1e04f1d user: dan tags: experimental
10:52
Merge trunk updates with experimental branch. Also add tests to journal2.test. check-in: 9f6ea1de user: dan tags: experimental
10:42
Do not delete the journal file in "PRAGMA journal_mode" commands. This fixes [fc62af4523]. check-in: 1ec74591 user: dan tags: trunk
06:19
Merge fix [f80c3f922a] with experimental changes. check-in: 20133e9c user: dan tags: experimental
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/pager.c.

  5894   5894       */
  5895   5895       if( isOpen(pPager->jfd) && eMode!=PAGER_JOURNALMODE_WAL ){
  5896   5896         sqlite3OsClose(pPager->jfd);
  5897   5897       }
  5898   5898   
  5899   5899       /* Change the journal mode. */
  5900   5900       pPager->journalMode = (u8)eMode;
  5901         -
  5902         -    /* When transistioning from TRUNCATE or PERSIST to any other journal
  5903         -    ** mode (and we are not in locking_mode=EXCLUSIVE) then delete the
  5904         -    ** journal file.
  5905         -    */
  5906         -    assert( (PAGER_JOURNALMODE_TRUNCATE & 5)==1 );
  5907         -    assert( (PAGER_JOURNALMODE_PERSIST & 5)==1 );
  5908         -    assert( (PAGER_JOURNALMODE_DELETE & 5)!=1 );
  5909         -    assert( (PAGER_JOURNALMODE_MEMORY & 5)!=1 );
  5910         -    assert( (PAGER_JOURNALMODE_OFF & 5)!=1 );
  5911         -    assert( (PAGER_JOURNALMODE_WAL & 5)!=1 );
  5912         -    if( (eOld & 5)==1 && (eMode & 5)!=1 && !pPager->exclusiveMode ){
  5913         -      sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
  5914         -    }
  5915   5901     }
  5916   5902   
  5917   5903     /* Return the new journal mode */
  5918   5904     return (int)pPager->journalMode;
  5919   5905   }
  5920   5906   
  5921   5907   /*

Changes to test/journal2.test.

    33     33   # Set up a hook so that each time a journal file is opened, closed or
    34     34   # deleted, the method name ("xOpen", "xClose" or "xDelete") and the final
    35     35   # segment of the journal file-name (i.e. "test.db-journal") are appended to
    36     36   # global list variable $::oplog.
    37     37   #
    38     38   tvfs filter {xOpen xClose xDelete}
    39     39   tvfs script journal_op_catcher
    40         -
    41     40   proc journal_op_catcher {method filename args} {
    42     41   
    43     42     # If global variable ::tvfs_error_on_write is defined, then return an
    44     43     # IO error to every attempt to modify the file-system. Otherwise, return
    45     44     # SQLITE_OK.
    46     45     #
    47     46     if {[info exists ::tvfs_error_on_write]} {
    48         -    if {$method == "xDelete" || $method == "xWrite" || $method == "xTruncate"} {
           47  +    if {[lsearch {xDelete xWrite xTruncate} $method]>=0} {
    49     48         return SQLITE_IOERR 
    50     49       }
    51     50       return SQLITE_OK
    52     51     }
    53     52   
    54         -  if {[string match *journal* $filename]==0} return
    55         -
           53  +  # The rest of this command only deals with xOpen(), xClose() and xDelete()
           54  +  # operations on journal files. If this invocation does not represent such
           55  +  # an operation, return with no further ado.
           56  +  #
    56     57     set f [file tail $filename]
           58  +  if {[string match *journal $f]==0} return
           59  +  if {[lsearch {xOpen xDelete xClose} $method]<0} return
           60  +
           61  +  # Append a record of this operation to global list variable $::oplog.
           62  +  #
    57     63     lappend ::oplog $method $f
    58     64   
           65  +  # If this is an attempt to delete a journal file for which there exists
           66  +  # one ore more open handles, return an error. The code in test_vfs.c
           67  +  # will not invoke the xDelete method of the "real" VFS in this case.
           68  +  #
    59     69     if {[info exists ::open_journals($f)]==0} { set ::open_journals($f) 0 }
    60     70     switch -- $method {
    61         -    xOpen {
    62         -      incr ::open_journals($f) +1
    63         -    }
    64         -    xClose {
    65         -      incr ::open_journals($f) -1
    66         -    }
    67         -    xDelete {
    68         -      if {$::open_journals($f)>0} { return SQLITE_IOERR }
    69         -    }
           71  +    xOpen   { incr ::open_journals($f) +1 }
           72  +    xClose  { incr ::open_journals($f) -1 }
           73  +    xDelete { if {$::open_journals($f)>0} { puts EEE;return SQLITE_IOERR } }
    70     74     }
    71     75   
    72         -  return
           76  +  return ""
    73     77   }
    74     78   
    75     79   
    76     80   do_test journal2-1.1 {
    77     81     set ::oplog [list]
    78     82     sqlite3 db test.db
    79     83     execsql { CREATE TABLE t1(a, b) }
................................................................................
   108    112   do_test journal2-1.7 { execsql { SELECT * FROM t1 } } {1 2 3 4}
   109    113   do_test journal2-1.8 {
   110    114     execsql { PRAGMA journal_mode = truncate } db2
   111    115     execsql { INSERT INTO t1 VALUES(5, 6)  } db2
   112    116   } {}
   113    117   do_test journal2-1.9 { execsql { SELECT * FROM t1 } } {1 2 3 4 5 6}
   114    118   
   115         -# Grow the database until it is reasonably large. Then, from a 
   116         -# journal_mode=DELETE connection, attempt to commit a large transaction (one
   117         -# that involves upgrading to an exclusive lock and writing the database
   118         -# before the transaction is committed).
          119  +# Grow the database until it is reasonably large.
   119    120   #
   120    121   do_test journal2-1.10 {
   121    122     db2 close
   122    123     db func a_string a_string
   123    124     execsql {
   124    125       CREATE TABLE t2(a UNIQUE, b UNIQUE);
   125    126       INSERT INTO t2 VALUES(a_string(200), a_string(300));
................................................................................
   133    134     file size test.db-journal
   134    135   } {0}
   135    136   do_test journal2-1.11 {
   136    137     set sz [expr [file size test.db] / 1024]
   137    138     expr {$sz>120 && $sz<200}
   138    139   } 1
   139    140   
          141  +# Using new connection [db2] (with journal_mode=DELETE), write a lot of
          142  +# data to the database. So that many pages within the database file are
          143  +# modified before the transaction is committed.
          144  +#
          145  +# Then, enable simulated IO errors in all calls to xDelete, xWrite
          146  +# and xTruncate before committing the transaction and closing the 
          147  +# database file. From the point of view of other file-system users, it
          148  +# appears as if the process hosting [db2] unexpectedly exited.
          149  +# 
   140    150   do_test journal2-1.12 {
   141    151     sqlite3 db2 test.db
   142    152     execsql {
   143    153       PRAGMA cache_size = 10;
   144    154       BEGIN;
   145    155         INSERT INTO t2 SELECT randomblob(200), randomblob(300) FROM t2;  -- 128
   146    156     } db2
................................................................................
   177    187   do_test journal2-1.20 {
   178    188     sqlite3 db2 testX.db
   179    189     expr {[catchsql { PRAGMA integrity_check } db2] == "0 ok"}
   180    190   } {0}
   181    191   do_test journal2-1.21 {
   182    192     db2 close
   183    193   } {}
   184         -
   185    194   db close
          195  +
          196  +#-------------------------------------------------------------------------
          197  +# Test that it is possible to switch from journal_mode=truncate to
          198  +# journal_mode=WAL on a SAFE_DELETE file-system. SQLite should close and
          199  +# delete the journal file when committing the transaction that switches
          200  +# the system to WAL mode.
          201  +#
          202  +ifcapable wal {
          203  +  do_test journal2-2.1 {
          204  +    faultsim_delete_and_reopen
          205  +    set ::oplog [list]
          206  +    execsql { PRAGMA journal_mode = persist }
          207  +    set ::oplog
          208  +  } {}
          209  +  do_test journal2-2.2 {
          210  +    execsql { 
          211  +      CREATE TABLE t1(x);
          212  +      INSERT INTO t1 VALUES(3.14159);
          213  +    }
          214  +    set ::oplog
          215  +  } {xOpen test.db-journal}
          216  +  do_test journal2-2.3 {
          217  +    expr {[file size test.db-journal] > 512}
          218  +  } {1}
          219  +  do_test journal2-2.3 {
          220  +    set ::oplog [list]
          221  +    execsql { PRAGMA journal_mode = WAL }
          222  +    set ::oplog
          223  +  } {xClose test.db-journal xDelete test.db-journal}
          224  +  db close
          225  +}
          226  +
   186    227   tvfs delete
   187    228   finish_test
   188    229   

Changes to test/jrnlmode.test.

   480    480       do_test jrnlmode-6.5 {
   481    481         execsql {
   482    482           PRAGMA journal_mode = MEMORY;
   483    483           BEGIN;
   484    484             INSERT INTO t4 VALUES(3, 4);
   485    485         }
   486    486         file exists test.db-journal
   487         -    } {0}
          487  +    } {1}
   488    488       do_test jrnlmode-6.7 {
   489    489         execsql {
   490    490           COMMIT;
   491    491           SELECT * FROM t4;
   492    492         }
   493    493       } {1 2 3 4}
   494    494       do_test jrnlmode-6.8 {
   495    495         file exists test.db-journal
   496         -    } {0}
          496  +    } {1}
   497    497       do_test jrnlmode-6.9 {
   498    498         execsql {
   499    499           PRAGMA journal_mode = DELETE;
   500    500           BEGIN IMMEDIATE; INSERT INTO t4 VALUES(1,2); COMMIT;
   501    501         }
   502    502         file exists test.db-journal
   503    503       } {0}
   504    504     }
   505    505   }
   506    506   
   507    507   finish_test

Added test/tkt-fc62af4523.test.

            1  +# 2010 June 16
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +# This file implements regression tests for SQLite library. Specifically,
           12  +# it tests that ticket [fc62af4523] has been resolved.
           13  +#
           14  +
           15  +set testdir [file dirname $argv0]
           16  +source $testdir/tester.tcl
           17  +source $testdir/lock_common.tcl
           18  +source $testdir/malloc_common.tcl
           19  +
           20  +do_test tkt-fc62af4523.1 {
           21  +  execsql {
           22  +    PRAGMA cache_size = 10;
           23  +    PRAGMA journal_mode = persist;
           24  +    CREATE TABLE t1(a UNIQUE, b UNIQUE);
           25  +    INSERT INTO t1 SELECT randomblob(200), randomblob(300);
           26  +    INSERT INTO t1 SELECT randomblob(200), randomblob(300) FROM t1; --  2
           27  +    INSERT INTO t1 SELECT randomblob(200), randomblob(300) FROM t1; --  4
           28  +    INSERT INTO t1 SELECT randomblob(200), randomblob(300) FROM t1; --  8
           29  +    INSERT INTO t1 SELECT randomblob(200), randomblob(300) FROM t1; -- 16
           30  +    INSERT INTO t1 SELECT randomblob(200), randomblob(300) FROM t1; -- 32
           31  +    INSERT INTO t1 SELECT randomblob(200), randomblob(300) FROM t1; -- 64
           32  +  }
           33  +  execsql {
           34  +    PRAGMA integrity_check;
           35  +    SELECT count(*) FROM t1;
           36  +  }
           37  +} {ok 64}
           38  +
           39  +# Launch an external process. Have it write (but not commit) a large
           40  +# transaction to the database.
           41  +#
           42  +set ::chan [launch_testfixture]
           43  +proc buddy {code} { testfixture $::chan $code }
           44  +do_test tkt-fc62af4523.2 {
           45  +  testfixture $::chan {
           46  +    sqlite3 db test.db
           47  +    db eval {
           48  +      PRAGMA cache_size = 10;
           49  +      BEGIN;
           50  +        UPDATE t1 SET b = randomblob(400);
           51  +        UPDATE t1 SET a = randomblob(200);
           52  +    }
           53  +  }
           54  +  file exists test.db-journal
           55  +} {1}
           56  +
           57  +# Now do "PRAGMA journal_mode = DELETE" in this process. At one point
           58  +# this was causing SQLite to delete the journal file from the file-system,
           59  +# even though the external process is currently using it.
           60  +#
           61  +do_test tkt-fc62af4523.3 { execsql { PRAGMA journal_mode = DELETE } } {delete}
           62  +do_test tkt-fc62af4523.4 { file exists test.db-journal } {1}
           63  +
           64  +# Cause the external process to crash. Since it has already written 
           65  +# uncommitted data into the database file, the next reader will have
           66  +# to do a hot-journal rollback to recover the database.
           67  +#
           68  +# Or, if this test is run in a version with the bug present, the journal
           69  +# file has already been deleted. In this case we are left with a corrupt
           70  +# database file and no hot-journal to fix it with.
           71  +#
           72  +do_test tkt-fc62af4523.5 {
           73  +  testfixture $::chan sqlite_abort
           74  +} {ERROR: Child process hung up}
           75  +after 200
           76  +do_test tkt-fc62af4523.6 {
           77  +  execsql {
           78  +    PRAGMA integrity_check;
           79  +    SELECT count(*) FROM t1;
           80  +  }
           81  +} {ok 64}
           82  +
           83  +catch { close $::chan }
           84  +finish_test
           85  +