SQLite

Check-in [a60104aa7e]
Login

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

Overview
Comment:Test that the correct number of padding frames are appended to the log file after committing a transaction in synchronous=FULL mode.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: a60104aa7e38e7d9f2ff2eae02687dc9c5dd5d77
User & Date: dan 2010-05-04 10:36:21.000
Context
2010-05-04
11:06
Fix a typo in walfault.test. (check-in: 232dbe8ece user: dan tags: trunk)
10:36
Test that the correct number of padding frames are appended to the log file after committing a transaction in synchronous=FULL mode. (check-in: a60104aa7e user: dan tags: trunk)
2010-05-03
19:20
Unset some global TCL variables prior to use in test where prior tests can have those same variables set to an array value. (check-in: 49bef00e5c user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/test2.c.
577
578
579
580
581
582
583

584
585
586
587
588
589
590
  const char **argv      /* Text of each argument */
){
  int pbyte;
  int rc;
  if( argc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
                     " PENDING-BYTE\"", (void*)0);

  }
  if( Tcl_GetInt(interp, argv[1], &pbyte) ) return TCL_ERROR;
  rc = sqlite3_test_control(SQLITE_TESTCTRL_PENDING_BYTE, pbyte);
  Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
  return TCL_OK;
}  








>







577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
  const char **argv      /* Text of each argument */
){
  int pbyte;
  int rc;
  if( argc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
                     " PENDING-BYTE\"", (void*)0);
    return TCL_ERROR;
  }
  if( Tcl_GetInt(interp, argv[1], &pbyte) ) return TCL_ERROR;
  rc = sqlite3_test_control(SQLITE_TESTCTRL_PENDING_BYTE, pbyte);
  Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
  return TCL_OK;
}  

Changes to src/wal.c.
910
911
912
913
914
915
916
917
918
919
920
921
922

923
924
925
926
927
928
929
** If this call obtains a new read-lock and the database contents have been
** modified since the most recent call to WalCloseSnapshot() on this Wal
** connection, then *pChanged is set to 1 before returning. Otherwise, it 
** is left unmodified. This is used by the pager layer to determine whether 
** or not any cached pages may be safely reused.
*/
int sqlite3WalOpenSnapshot(Wal *pWal, int *pChanged){
  int rc;

  rc = walSetLock(pWal, SQLITE_SHM_READ);
  if( rc==SQLITE_OK ){
    pWal->lockState = SQLITE_SHM_READ;


    rc = walIndexReadHdr(pWal, pChanged);
    if( rc!=SQLITE_OK ){
      /* An error occured while attempting log recovery. */
      sqlite3WalCloseSnapshot(pWal);
    }else{
      /* Check if the mapping needs to grow. */
      if( pWal->hdr.iLastPg 







|


<
|

>







910
911
912
913
914
915
916
917
918
919

920
921
922
923
924
925
926
927
928
929
** If this call obtains a new read-lock and the database contents have been
** modified since the most recent call to WalCloseSnapshot() on this Wal
** connection, then *pChanged is set to 1 before returning. Otherwise, it 
** is left unmodified. This is used by the pager layer to determine whether 
** or not any cached pages may be safely reused.
*/
int sqlite3WalOpenSnapshot(Wal *pWal, int *pChanged){
  int rc;                         /* Return code */

  rc = walSetLock(pWal, SQLITE_SHM_READ);

  assert( rc!=SQLITE_OK || pWal->lockState==SQLITE_SHM_READ );

  if( rc==SQLITE_OK ){
    rc = walIndexReadHdr(pWal, pChanged);
    if( rc!=SQLITE_OK ){
      /* An error occured while attempting log recovery. */
      sqlite3WalCloseSnapshot(pWal);
    }else{
      /* Check if the mapping needs to grow. */
      if( pWal->hdr.iLastPg 
938
939
940
941
942
943
944
945
946

947
948
949
950
951
952
953
954
955
  return rc;
}

/*
** Unlock the current snapshot.
*/
void sqlite3WalCloseSnapshot(Wal *pWal){
  if( pWal->lockState!=SQLITE_SHM_UNLOCK ){
    assert( pWal->lockState==SQLITE_SHM_READ );

    walSetLock(pWal, SQLITE_SHM_UNLOCK);
  }
}

/*
** Read a page from the log, if it is present. 
*/
int sqlite3WalRead(Wal *pWal, Pgno pgno, int *pInWal, u8 *pOut){
  u32 iRead = 0;







|
|
>
|
<







938
939
940
941
942
943
944
945
946
947
948

949
950
951
952
953
954
955
  return rc;
}

/*
** Unlock the current snapshot.
*/
void sqlite3WalCloseSnapshot(Wal *pWal){
  assert( pWal->lockState==SQLITE_SHM_READ
       || pWal->lockState==SQLITE_SHM_UNLOCK
  );
  walSetLock(pWal, SQLITE_SHM_UNLOCK);

}

/*
** Read a page from the log, if it is present. 
*/
int sqlite3WalRead(Wal *pWal, Pgno pgno, int *pInWal, u8 *pOut){
  u32 iRead = 0;
Changes to test/wal.test.
846
847
848
849
850
851
852






















853
854
855
856
857
858
859
860
861
862
863
864
865
866
867

868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
} {B 2}
db2 close
db close

#-------------------------------------------------------------------------
# Test large log summaries.
#






















do_test wal-13.1.1 {
  list [file exists test.db] [file exists test.db-wal]
} {1 0}
do_test wal-13.1.2 {
  set fd [open test.db-wal w]
  seek $fd [expr 200*1024*1024]
  puts $fd ""
  close $fd
  sqlite3 db test.db
  execsql { SELECT * FROM t2 }
} {B 2}
do_test wal-13.1.3 {
  db close
  file exists test.db-wal
} {0}

do_test wal-13.1.4 {
  sqlite3 db test.db
  execsql { SELECT count(*) FROM t2 }
} {1}
do_test wal-13.1.5 {
  for {set i 0} {$i < 6} {incr i} {
    execsql { INSERT INTO t2 SELECT randomblob(400), randomblob(400) FROM t2 }
  }
  execsql { SELECT count(*) FROM t2 }
} [expr int(pow(2, 6))]
do_test wal-13.1.6 {
  file size test.db-wal
} [log_file_size 80 1024]

foreach code [list {
  set tn 2
  proc buddy {tcl} { uplevel #0 $tcl }
} {
  set tn 3
  set ::buddy [launch_testfixture]
  proc buddy {tcl} { testfixture $::buddy $tcl }
}] {

  eval $code
  reopen_db

  do_test wal-13.$tn.0 {
    buddy { sqlite3 db2 test.db }
    execsql {
      PRAGMA journal_mode = WAL;
      CREATE TABLE t1(x);
      INSERT INTO t1 SELECT randomblob(400);
    }
    execsql { SELECT count(*) FROM t1 }
  } {1}

  for {set ii 1} {$ii<16} {incr ii} {
    do_test wal-13.$tn.$ii.a {
      buddy { db2 eval { INSERT INTO t1 SELECT randomblob(400) FROM t1 } }
      buddy { db2 eval { SELECT count(*) FROM t1 } }
    } [expr (1<<$ii)]
    do_test wal-13.$tn.$ii.b {
      db eval { SELECT count(*) FROM t1 }
    } [expr (1<<$ii)]
    do_test wal-13.$tn.$ii.c {
      db eval { SELECT count(*) FROM t1 }







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>















>
|



|
|



|
|

|


|


|












|






|







846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
} {B 2}
db2 close
db close

#-------------------------------------------------------------------------
# Test large log summaries.
#
# In this case "large" usually means a log file that requires a wal-index
# mapping larger than 64KB (the default initial allocation). A 64KB wal-index
# is large enough for a log file that contains approximately 13100 frames.
# So the following tests create logs containing at least this many frames.
#
# wal-13.1.*: This test case creates a very large log file within the
#             file-system (around 200MB). The log file does not contain
#             any valid frames. Test that the database file can still be
#             opened and queried, and that the invalid log file causes no 
#             problems.
#
# wal-13.2.*: Test that a process may create a large log file and query
#             the database (including the log file that it itself created).
#
# wal-13.3.*: Test that if a very large log file is created, and then a
#             second connection is opened on the database file, it is possible
#             to query the database (and the very large log) using the
#             second connection.
#
# wal-13.4.*: Same test as wal-13.3.*. Except in this case the second
#             connection is opened by an external process.
#
do_test wal-13.1.1 {
  list [file exists test.db] [file exists test.db-wal]
} {1 0}
do_test wal-13.1.2 {
  set fd [open test.db-wal w]
  seek $fd [expr 200*1024*1024]
  puts $fd ""
  close $fd
  sqlite3 db test.db
  execsql { SELECT * FROM t2 }
} {B 2}
do_test wal-13.1.3 {
  db close
  file exists test.db-wal
} {0}

do_test wal-13.2.1 {
  sqlite3 db test.db
  execsql { SELECT count(*) FROM t2 }
} {1}
do_test wal-13.2.2 {
  for {set i 0} {$i < 16} {incr i} {
    execsql { INSERT INTO t2 SELECT randomblob(400), randomblob(400) FROM t2 }
  }
  execsql { SELECT count(*) FROM t2 }
} [expr int(pow(2, 16))]
do_test wal-13.2.1 {
  file size test.db-wal
} [log_file_size 33123 1024]

foreach code [list {
  set tn 3
  proc buddy {tcl} { uplevel #0 $tcl }
} {
  set tn 4
  set ::buddy [launch_testfixture]
  proc buddy {tcl} { testfixture $::buddy $tcl }
}] {

  eval $code
  reopen_db

  do_test wal-13.$tn.0 {
    buddy { sqlite3 db2 test.db }
    execsql {
      PRAGMA journal_mode = WAL;
      CREATE TABLE t1(x);
      INSERT INTO t1 SELECT randomblob(800);
    }
    execsql { SELECT count(*) FROM t1 }
  } {1}

  for {set ii 1} {$ii<16} {incr ii} {
    do_test wal-13.$tn.$ii.a {
      buddy { db2 eval { INSERT INTO t1 SELECT randomblob(800) FROM t1 } }
      buddy { db2 eval { SELECT count(*) FROM t1 } }
    } [expr (1<<$ii)]
    do_test wal-13.$tn.$ii.b {
      db eval { SELECT count(*) FROM t1 }
    } [expr (1<<$ii)]
    do_test wal-13.$tn.$ii.c {
      db eval { SELECT count(*) FROM t1 }
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
# Check a fun corruption case has been fixed.
#
# The problem was that after performing a checkpoint using a connection
# that had an out-of-date pager-cache, the next time the connection was
# used it did not realize the cache was out-of-date and proceeded to
# operate with an inconsistent cache. Leading to corruption.
#

catch { db close }
catch { db2 close }
catch { db3 close }
file delete -force test.db test.db-wal
sqlite3 db test.db
sqlite3 db2 test.db

do_test wal-14 {
  execsql {
    PRAGMA journal_mode = WAL;
    CREATE TABLE t1(a PRIMARY KEY, b);
    INSERT INTO t1 VALUES(randomblob(10), randomblob(100));
    INSERT INTO t1 SELECT randomblob(10), randomblob(100) FROM t1;
    INSERT INTO t1 SELECT randomblob(10), randomblob(100) FROM t1;







<






<







949
950
951
952
953
954
955

956
957
958
959
960
961

962
963
964
965
966
967
968
# Check a fun corruption case has been fixed.
#
# The problem was that after performing a checkpoint using a connection
# that had an out-of-date pager-cache, the next time the connection was
# used it did not realize the cache was out-of-date and proceeded to
# operate with an inconsistent cache. Leading to corruption.
#

catch { db close }
catch { db2 close }
catch { db3 close }
file delete -force test.db test.db-wal
sqlite3 db test.db
sqlite3 db2 test.db

do_test wal-14 {
  execsql {
    PRAGMA journal_mode = WAL;
    CREATE TABLE t1(a PRIMARY KEY, b);
    INSERT INTO t1 VALUES(randomblob(10), randomblob(100));
    INSERT INTO t1 SELECT randomblob(10), randomblob(100) FROM t1;
    INSERT INTO t1 SELECT randomblob(10), randomblob(100) FROM t1;
1103
1104
1105
1106
1107
1108
1109
1110
































































1111
1112
1113
1114
1115

  do_test wal-16.$tn.6 {
    list [file size test2.db] [file size test2.db-wal]
  } [list [expr ($ckpt_aux ? 7 : 1)*1024] [log_file_size 16 1024]]

  catch { db close }
}

































































catch { db2 close }
catch { db close }
finish_test










>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200

  do_test wal-16.$tn.6 {
    list [file size test2.db] [file size test2.db-wal]
  } [list [expr ($ckpt_aux ? 7 : 1)*1024] [log_file_size 16 1024]]

  catch { db close }
}

#-------------------------------------------------------------------------
# The following tests - wal-17.* - attempt to verify that the correct
# number of "padding" frames are appended to the log file when a transaction
# is committed in synchronous=FULL mode.
# 
# Do this by creating a database that uses 512 byte pages. Then writing
# a transaction that modifies 171 pages. In synchronous=NORMAL mode, this
# produces a log file of:
#
#   12 + (16+512)*171 = 90300 bytes.
#
# Slightly larger than 11*8192 = 90112 bytes.
#
# Run the test using various different sector-sizes. In each case, the
# WAL code should write the 90300 bytes of log file containing the 
# transaction, then append as may frames as are required to extend the
# log file so that no part of the next transaction will be written into
# a disk-sector used by transaction just committed.
#
set old_pending_byte [sqlite3_test_control_pending_byte 0x10000000]
catch { db close }
foreach {tn sectorsize logsize} {
  1   128  90828
  2   256  90828
  3   512  90828 
  4  1024  91356
  5  2048  92412
  6  4096  94524
  7  8192  98748
} {
  file delete -force test.db test.db-wal test.db-journal
  sqlite3_simulate_device -sectorsize $sectorsize
  sqlite3 db test.db -vfs devsym

  do_test wal-17.$tn.1 {
    execsql {
      PRAGMA auto_vacuum = 0;
      PRAGMA page_size = 512;
      PRAGMA journal_mode = WAL;
      PRAGMA synchronous = FULL;
    }
    execsql {
      BEGIN;
      CREATE TABLE t(x);
    }
    for {set i 0} {$i<166} {incr i} {
      execsql { INSERT INTO t VALUES(randomblob(400)) }
    }
    execsql COMMIT

    file size test.db-wal
  } $logsize

  do_test wal-17.$tn.2 {
    file size test.db
  } 512

  do_test wal-17.$tn.3 {
    db close
    file size test.db
  } [expr 512*171]
}
sqlite3_test_control_pending_byte $old_pending_byte

catch { db2 close }
catch { db close }
finish_test