Annotation of embedaddon/sqlite3/test/wal5.test, revision 1.1

1.1     ! misho       1: # 2010 April 13
        !             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.  The
        !            12: # focus of this file is testing the operation of "blocking-checkpoint"
        !            13: # operations.
        !            14: #
        !            15: 
        !            16: set testdir [file dirname $argv0]
        !            17: source $testdir/tester.tcl
        !            18: source $testdir/lock_common.tcl
        !            19: source $testdir/wal_common.tcl
        !            20: ifcapable !wal {finish_test ; return }
        !            21: 
        !            22: set testprefix wal5
        !            23: 
        !            24: proc db_page_count  {{file test.db}} { expr [file size $file] / 1024 }
        !            25: proc wal_page_count {{file test.db}} { wal_frame_count ${file}-wal 1024 }
        !            26: 
        !            27: 
        !            28: # A checkpoint may be requested either using the C API or by executing
        !            29: # an SQL PRAGMA command. To test both methods, all tests in this file are 
        !            30: # run twice - once using each method to request checkpoints.
        !            31: #
        !            32: foreach {testprefix do_wal_checkpoint} {
        !            33: 
        !            34:   wal5-pragma {
        !            35:     proc do_wal_checkpoint { dbhandle args } {
        !            36:       array set a $args
        !            37:       foreach key [array names a] {
        !            38:         if {[lsearch {-mode -db} $key]<0} { error "unknown switch: $key" }
        !            39:       }
        !            40: 
        !            41:       set sql "PRAGMA "
        !            42:       if {[info exists a(-db)]} { append sql "$a(-db)." }
        !            43:       append sql "wal_checkpoint"
        !            44:       if {[info exists a(-mode)]} { append sql " = $a(-mode)" }
        !            45: 
        !            46:       uplevel [list $dbhandle eval $sql]
        !            47:     }
        !            48:   }
        !            49: 
        !            50:   wal5-capi {
        !            51:     proc do_wal_checkpoint { dbhandle args } {
        !            52:       set a(-mode) passive
        !            53:       array set a $args
        !            54:       foreach key [array names a] {
        !            55:         if {[lsearch {-mode -db} $key]<0} { error "unknown switch: $key" }
        !            56:       }
        !            57: 
        !            58:       if {$a(-mode)!="restart" && $a(-mode)!="full"} { set a(-mode) passive }
        !            59: 
        !            60:       set cmd [list sqlite3_wal_checkpoint_v2 $dbhandle $a(-mode)]
        !            61:       if {[info exists a(-db)]} { lappend sql $a(-db) }
        !            62: 
        !            63:       uplevel $cmd
        !            64:     }
        !            65:   }
        !            66: } {
        !            67: 
        !            68:   eval $do_wal_checkpoint
        !            69: 
        !            70:   do_multiclient_test tn {
        !            71: 
        !            72:     set ::nBusyHandler 0
        !            73:     set ::busy_handler_script ""
        !            74:     proc busyhandler {n} {
        !            75:       incr ::nBusyHandler 
        !            76:       eval $::busy_handler_script
        !            77:       return 0
        !            78:     }
        !            79: 
        !            80:     proc reopen_all {} {
        !            81:       code1 {db close}
        !            82:       code2 {db2 close}
        !            83:       code3 {db3 close}
        !            84: 
        !            85:       code1 {sqlite3 db test.db}
        !            86:       code2 {sqlite3 db2 test.db}
        !            87:       code3 {sqlite3 db3 test.db}
        !            88: 
        !            89:       sql1  { PRAGMA synchronous = NORMAL }
        !            90:       code1 { db busy busyhandler }
        !            91:     }
        !            92: 
        !            93:     do_test 1.$tn.1 {
        !            94:       reopen_all
        !            95:       sql1 {
        !            96:         PRAGMA page_size = 1024;
        !            97:         PRAGMA auto_vacuum = 0;
        !            98:         CREATE TABLE t1(x, y);
        !            99:         PRAGMA journal_mode = WAL;
        !           100:         INSERT INTO t1 VALUES(1, zeroblob(1200));
        !           101:         INSERT INTO t1 VALUES(2, zeroblob(1200));
        !           102:         INSERT INTO t1 VALUES(3, zeroblob(1200));
        !           103:       }
        !           104:       expr [file size test.db] / 1024
        !           105:     } {2}
        !           106: 
        !           107:     # Have connection 2 grab a read-lock on the current snapshot.
        !           108:     do_test 1.$tn.2 { sql2 { BEGIN; SELECT x FROM t1 } } {1 2 3}
        !           109: 
        !           110:     # Attempt a checkpoint.
        !           111:     do_test 1.$tn.3 {
        !           112:       code1 { do_wal_checkpoint db }
        !           113:       list [db_page_count] [wal_page_count]
        !           114:     } {5 9}
        !           115: 
        !           116:     # Write to the db again. The log cannot wrap because of the lock still
        !           117:     # held by connection 2. The busy-handler has not yet been invoked.
        !           118:     do_test 1.$tn.4 {
        !           119:       sql1 { INSERT INTO t1 VALUES(4, zeroblob(1200)) }
        !           120:       list [db_page_count] [wal_page_count] $::nBusyHandler
        !           121:     } {5 12 0}
        !           122: 
        !           123:     # Now do a blocking-checkpoint. Set the busy-handler up so that connection
        !           124:     # 2 releases its lock on the 6th invocation. The checkpointer should then
        !           125:     # proceed to checkpoint the entire log file. Next write should go to the 
        !           126:     # start of the log file.
        !           127:     #
        !           128:     set ::busy_handler_script { if {$n==5} { sql2 COMMIT } }
        !           129:     do_test 1.$tn.5 {
        !           130:       code1 { do_wal_checkpoint db -mode restart }
        !           131:       list [db_page_count] [wal_page_count] $::nBusyHandler
        !           132:     } {6 12 6}
        !           133:     do_test 1.$tn.6 {
        !           134:       set ::nBusyHandler 0
        !           135:       sql1 { INSERT INTO t1 VALUES(5, zeroblob(1200)) }
        !           136:       list [db_page_count] [wal_page_count] $::nBusyHandler
        !           137:     } {6 12 0}
        !           138: 
        !           139:     do_test 1.$tn.7 {
        !           140:       reopen_all
        !           141:       list [db_page_count] [wal_page_count] $::nBusyHandler
        !           142:     } {7 0 0}
        !           143: 
        !           144:     do_test 1.$tn.8  { sql2 { BEGIN ; SELECT x FROM t1 } } {1 2 3 4 5}
        !           145:     do_test 1.$tn.9  {
        !           146:       sql1 { INSERT INTO t1 VALUES(6, zeroblob(1200)) }
        !           147:       list [db_page_count] [wal_page_count] $::nBusyHandler
        !           148:     } {7 5 0}
        !           149:     do_test 1.$tn.10 { sql3 { BEGIN ; SELECT x FROM t1 } } {1 2 3 4 5 6}
        !           150: 
        !           151:     set ::busy_handler_script { 
        !           152:       if {$n==5} { sql2 COMMIT } 
        !           153:       if {$n==6} { set ::db_file_size [db_page_count] }
        !           154:       if {$n==7} { sql3 COMMIT }
        !           155:     }
        !           156:     do_test 1.$tn.11 {
        !           157:       code1 { do_wal_checkpoint db -mode restart }
        !           158:       list [db_page_count] [wal_page_count] $::nBusyHandler
        !           159:     } {10 5 8}
        !           160:     do_test 1.$tn.12 { set ::db_file_size } 10
        !           161:   }
        !           162: 
        !           163:   #-------------------------------------------------------------------------
        !           164:   # This block of tests explores checkpoint operations on more than one 
        !           165:   # database file.
        !           166:   #
        !           167:   proc setup_and_attach_aux {} {
        !           168:     sql1 { ATTACH 'test.db2' AS aux }
        !           169:     sql2 { ATTACH 'test.db2' AS aux }
        !           170:     sql3 { ATTACH 'test.db2' AS aux }
        !           171:     sql1 {
        !           172:       PRAGMA aux.auto_vacuum = 0;
        !           173:       PRAGMA main.auto_vacuum = 0;
        !           174:       PRAGMA main.page_size=1024; PRAGMA main.journal_mode=WAL;
        !           175:       PRAGMA aux.page_size=1024;  PRAGMA aux.journal_mode=WAL;
        !           176:     }
        !           177:   }
        !           178: 
        !           179:   proc file_page_counts {} {
        !           180:     list [db_page_count  test.db ] \
        !           181:          [wal_page_count test.db ] \
        !           182:          [db_page_count  test.db2] \
        !           183:          [wal_page_count test.db2]
        !           184:   }
        !           185: 
        !           186:   # Test that executing "PRAGMA wal_checkpoint" checkpoints all attached
        !           187:   # databases, not just the main db.  In capi mode, check that this is
        !           188:   # true if a NULL pointer is passed to wal_checkpoint_v2() in place of a 
        !           189:   # database name.
        !           190:   do_multiclient_test tn {
        !           191:     setup_and_attach_aux
        !           192:     do_test 2.1.$tn.1 {
        !           193:       sql1 {
        !           194:         CREATE TABLE t1(a, b);
        !           195:         INSERT INTO t1 VALUES(1, 2);
        !           196:         CREATE TABLE aux.t2(a, b);
        !           197:         INSERT INTO t2 VALUES(1, 2);
        !           198:       }
        !           199:     } {}
        !           200:     do_test 2.2.$tn.2 { file_page_counts } {1 3 1 3}
        !           201:     do_test 2.1.$tn.3 { code1 { do_wal_checkpoint db } } {0 3 3}
        !           202:     do_test 2.1.$tn.4 { file_page_counts } {2 3 2 3}
        !           203:   }
        !           204: 
        !           205:   do_multiclient_test tn {
        !           206:     setup_and_attach_aux
        !           207:     do_test 2.2.$tn.1 {
        !           208:       execsql {
        !           209:         CREATE TABLE t1(a, b);
        !           210:         INSERT INTO t1 VALUES(1, 2);
        !           211:         CREATE TABLE aux.t2(a, b);
        !           212:         INSERT INTO t2 VALUES(1, 2);
        !           213:         INSERT INTO t2 VALUES(3, 4);
        !           214:       }
        !           215:     } {}
        !           216:     do_test 2.2.$tn.2 { file_page_counts } {1 3 1 4}
        !           217:     do_test 2.2.$tn.3 { sql2 { BEGIN; SELECT * FROM t1 } } {1 2}
        !           218:     do_test 2.2.$tn.4 { code1 { do_wal_checkpoint db -mode restart } } {1 3 3}
        !           219:     do_test 2.2.$tn.5 { file_page_counts } {2 3 2 4}
        !           220:   }
        !           221: 
        !           222:   do_multiclient_test tn {
        !           223:     setup_and_attach_aux
        !           224:     do_test 2.3.$tn.1 {
        !           225:       execsql {
        !           226:         CREATE TABLE t1(a, b);
        !           227:         INSERT INTO t1 VALUES(1, 2);
        !           228:         CREATE TABLE aux.t2(a, b);
        !           229:         INSERT INTO t2 VALUES(1, 2);
        !           230:       }
        !           231:     } {}
        !           232:     do_test 2.3.$tn.2 { file_page_counts } {1 3 1 3}
        !           233:     do_test 2.3.$tn.3 { sql2 { BEGIN; SELECT * FROM t1 } } {1 2}
        !           234:     do_test 2.3.$tn.4 { sql1 { INSERT INTO t1 VALUES(3, 4) } } {}
        !           235:     do_test 2.3.$tn.5 { sql1 { INSERT INTO t2 VALUES(3, 4) } } {}
        !           236:     do_test 2.3.$tn.6 { file_page_counts } {1 4 1 4}
        !           237:     do_test 2.3.$tn.7 { code1 { do_wal_checkpoint db -mode full } } {1 4 3}
        !           238:     do_test 2.3.$tn.8 { file_page_counts } {1 4 2 4}
        !           239:   }
        !           240: 
        !           241:   # Check that checkpoints block on the correct locks. And respond correctly
        !           242:   # if they cannot obtain those locks. There are three locks that a checkpoint
        !           243:   # may block on (in the following order):
        !           244:   #
        !           245:   #   1. The writer lock: FULL and RESTART checkpoints block until any writer
        !           246:   #      process releases its lock.
        !           247:   #
        !           248:   #   2. Readers using part of the log file. FULL and RESTART checkpoints block
        !           249:   #      until readers using part (but not all) of the log file have finished.
        !           250:   #
        !           251:   #   3. Readers using any of the log file. After copying data into the
        !           252:   #      database file, RESTART checkpoints block until readers using any part
        !           253:   #      of the log file have finished.
        !           254:   #
        !           255:   # This test case involves running a checkpoint while there exist other 
        !           256:   # processes holding all three types of locks.
        !           257:   #
        !           258:   foreach {tn1 checkpoint busy_on ckpt_expected expected} {
        !           259:     1   PASSIVE   -   {0 3 3}   -
        !           260:     2   TYPO      -   {0 3 3}   -
        !           261: 
        !           262:     3   FULL      -   {0 4 4}   2
        !           263:     4   FULL      1   {1 3 3}   1
        !           264:     5   FULL      2   {1 4 3}   2
        !           265:     6   FULL      3   {0 4 4}   2
        !           266: 
        !           267:     7   RESTART   -   {0 4 4}   3
        !           268:     8   RESTART   1   {1 3 3}   1
        !           269:     9   RESTART   2   {1 4 3}   2
        !           270:     10  RESTART   3   {1 4 4}   3
        !           271: 
        !           272:   } {
        !           273:     do_multiclient_test tn {
        !           274:       setup_and_attach_aux
        !           275: 
        !           276:       proc busyhandler {x} {
        !           277:         set ::max_busyhandler $x
        !           278:         if {$::busy_on!="-" && $x==$::busy_on} { return 1 }
        !           279:         switch -- $x {
        !           280:           1 { sql2 "COMMIT ; BEGIN ; SELECT * FROM t1" }
        !           281:           2 { sql3 "COMMIT" }
        !           282:           3 { sql2 "COMMIT" }
        !           283:         }
        !           284:         return 0
        !           285:       }
        !           286:       set ::max_busyhandler -
        !           287: 
        !           288:       do_test 2.4.$tn1.$tn.1 {
        !           289:         sql1 {
        !           290:           CREATE TABLE t1(a, b);
        !           291:           INSERT INTO t1 VALUES(1, 2);
        !           292:         }
        !           293:         sql2 { BEGIN; INSERT INTO t1 VALUES(3, 4) }
        !           294:         sql3 { BEGIN; SELECT * FROM t1 }
        !           295:       } {1 2}
        !           296: 
        !           297:       do_test 2.4.$tn1.$tn.2 {
        !           298:         code1 { db busy busyhandler }
        !           299:         code1 { do_wal_checkpoint db -mode [string tolower $checkpoint] }
        !           300:       } $ckpt_expected
        !           301:       do_test 2.4.$tn1.$tn.3 { set ::max_busyhandler } $expected
        !           302:     }
        !           303:   }
        !           304: 
        !           305: 
        !           306:   do_multiclient_test tn {
        !           307: 
        !           308:     code1 $do_wal_checkpoint
        !           309:     code2 $do_wal_checkpoint
        !           310:     code3 $do_wal_checkpoint
        !           311:     
        !           312:     do_test 3.$tn.1 {
        !           313:       sql1 {
        !           314:         PRAGMA auto_vacuum = 0;
        !           315:         PRAGMA journal_mode = WAL;
        !           316:         PRAGMA synchronous = normal;
        !           317:         CREATE TABLE t1(x, y);
        !           318:       }
        !           319: 
        !           320:       sql2 { PRAGMA journal_mode }
        !           321:       sql3 { PRAGMA journal_mode }
        !           322:     } {wal}
        !           323: 
        !           324:     do_test 3.$tn.2 { code2 { do_wal_checkpoint db2 } } {0 2 2}
        !           325: 
        !           326:     do_test 3.$tn.3 { code2 { do_wal_checkpoint db2 } } {0 2 2}
        !           327: 
        !           328:     do_test 3.$tn.4 { code3 { do_wal_checkpoint db3 } } {0 2 2}
        !           329: 
        !           330:     code1 {db  close}
        !           331:     code2 {db2 close}
        !           332:     code3 {db3 close}
        !           333: 
        !           334:     code1 {sqlite3 db  test.db}
        !           335:     code2 {sqlite3 db2 test.db}
        !           336:     code3 {sqlite3 db3 test.db}
        !           337: 
        !           338:     do_test 3.$tn.5 { sql3 { PRAGMA journal_mode } } {wal}
        !           339: 
        !           340:     do_test 3.$tn.6 { code3 { do_wal_checkpoint db3 } } {0 0 0}
        !           341:   }
        !           342: }
        !           343: 
        !           344: 
        !           345: finish_test
        !           346: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>