1# See the file LICENSE for redistribution information. 2# 3# Copyright (c) 1996, 2013 Oracle and/or its affiliates. All rights reserved. 4# 5# $Id$ 6# 7# Options are: 8# -checkrec <checkpoint frequency" 9# -dir <dbhome directory> 10# -maxfilesize <maxsize of log file> 11proc archive { { inmem 0 } args } { 12 global alphabet 13 source ./include.tcl 14 15 # Set defaults 16 if { $inmem == 1 } { 17 set maxbsize [expr 8 * [expr 1024 * 1024]] 18 set desc "in-memory" 19 } else { 20 set maxbsize [expr 8 * 1024] 21 set desc "on-disk" 22 } 23 set maxfile [expr 32 * 1024] 24 set checkrec 500 25 for { set i 0 } { $i < [llength $args] } {incr i} { 26 switch -regexp -- [lindex $args $i] { 27 -c.* { incr i; set checkrec [lindex $args $i] } 28 -d.* { incr i; set testdir [lindex $args $i] } 29 -m.* { incr i; set maxfile [lindex $args $i] } 30 default { 31 puts "FAIL:[timestamp] archive usage" 32 puts "usage: archive -checkrec <checkpt freq> \ 33 -dir <directory> -maxfilesize <max size of log files>" 34 return 35 } 36 } 37 } 38 39 # Clean out old log if it existed 40 puts "Archive: Log archive test (using $desc logging)." 41 puts "Unlinking log: error message OK" 42 env_cleanup $testdir 43 44 # Now run the various functionality tests 45 if { $inmem == 0 } { 46 set eflags "-create -txn -home $testdir \ 47 -log_buffer $maxbsize -log_max $maxfile" 48 } else { 49 set eflags "-create -txn -home $testdir -log_inmemory \ 50 -log_buffer $maxbsize -log_max $maxfile" 51 } 52 set dbenv [eval {berkdb_env} $eflags] 53 error_check_good dbenv [is_valid_env $dbenv] TRUE 54 55 set logc [$dbenv log_cursor] 56 error_check_good log_cursor [is_valid_logc $logc $dbenv] TRUE 57 58 # The basic test structure here is that we write a lot of log 59 # records (enough to fill up 100 log files; each log file it 60 # small). We start with three txns and open a database in 61 # each transaction. Then, in a loop, we take periodic 62 # checkpoints. Between each pair of checkpoints, we end one 63 # transaction; when no transactions are left, we start up three 64 # new ones, letting them overlap checkpoints as well. 65 # 66 # The pattern that we create is: 67 # 1. Create TXN1, TXN2, TXN3 and open dbs within the txns. 68 # 2. Write a bunch of additional log records. 69 # 3. Checkpoint. 70 # 4. Archive, checking that we list the right files. 71 # 5. Commit one transaction. 72 # 6. If no txns left, start 3 new ones. 73 # 7. Until we've gone through enough records, return to step 2. 74 75 set baserec "1:$alphabet:2:$alphabet:3:$alphabet:4:$alphabet" 76 puts "\tArchive.a: Writing log records; checkpoint every $checkrec records" 77 set nrecs $maxfile 78 set rec 0:$baserec 79 80 # Begin 1st transaction and record current log file. Open 81 # a database in the transaction; the log file won't be 82 # removable until the transaction is aborted or committed. 83 set t1 [$dbenv txn] 84 error_check_good t1:txn_begin [is_valid_txn $t1 $dbenv] TRUE 85 86 set l1 [lindex [lindex [$logc get -last] 0] 0] 87 set lsnlist [list $l1] 88 89 set tdb1 [eval {berkdb_open -create -mode 0644} \ 90 -env $dbenv -txn $t1 -btree tdb1.db] 91 error_check_good dbopen [is_valid_db $tdb1] TRUE 92 93 # Do the same for a 2nd and 3rd transaction. 94 set t2 [$dbenv txn] 95 error_check_good t2:txn_begin [is_valid_txn $t2 $dbenv] TRUE 96 set l2 [lindex [lindex [$logc get -last] 0] 0] 97 lappend lsnlist $l2 98 set tdb2 [eval {berkdb_open -create -mode 0644} \ 99 -env $dbenv -txn $t2 -btree tdb2.db] 100 error_check_good dbopen [is_valid_db $tdb2] TRUE 101 102 set t3 [$dbenv txn] 103 error_check_good t3:txn_begin [is_valid_txn $t3 $dbenv] TRUE 104 set l3 [lindex [lindex [$logc get -last] 0] 0] 105 lappend lsnlist $l3 106 set tdb3 [eval {berkdb_open -create -mode 0644} \ 107 -env $dbenv -txn $t3 -btree tdb3.db] 108 error_check_good dbopen [is_valid_db $tdb3] TRUE 109 110 # Keep a list of active transactions and databases opened 111 # within those transactions. 112 set txnlist [list "$t1 $tdb1" "$t2 $tdb2" "$t3 $tdb3"] 113 114 # Loop through a large number of log records, checkpointing 115 # and checking db_archive periodically. 116 for { set i 1 } { $i <= $nrecs } { incr i } { 117 set rec $i:$baserec 118 set lsn [$dbenv log_put $rec] 119 error_check_bad log_put [llength $lsn] 0 120 if { [expr $i % $checkrec] == 0 } { 121 122 # Take a checkpoint 123 $dbenv txn_checkpoint 124 set ckp_file [lindex [lindex [$logc get -last] 0] 0] 125 catch { archive_command -h $testdir -a } res_log_full 126 if { [string first db_archive $res_log_full] == 0 } { 127 set res_log_full "" 128 } 129 catch { archive_command -h $testdir } res_log 130 if { [string first db_archive $res_log] == 0 } { 131 set res_log "" 132 } 133 catch { archive_command -h $testdir -l } res_alllog 134 catch { archive_command -h $testdir -a -s } \ 135 res_data_full 136 catch { archive_command -h $testdir -s } res_data 137 138 if { $inmem == 0 } { 139 error_check_good nlogfiles [llength $res_alllog] \ 140 [lindex [lindex [$logc get -last] 0] 0] 141 } else { 142 error_check_good nlogfiles [llength $res_alllog] 0 143 } 144 145 error_check_good logs_match [llength $res_log_full] \ 146 [llength $res_log] 147 error_check_good data_match [llength $res_data_full] \ 148 [llength $res_data] 149 150 # Check right number of log files 151 if { $inmem == 0 } { 152 set expected [min $ckp_file [expr [lindex $lsnlist 0] - 1]] 153 error_check_good nlogs [llength $res_log] $expected 154 } 155 156 # Check that the relative names are a subset of the 157 # full names 158 set n 0 159 foreach x $res_log { 160 error_check_bad log_name_match:$res_log \ 161 [string first $x \ 162 [lindex $res_log_full $n]] -1 163 incr n 164 } 165 166 set n 0 167 foreach x $res_data { 168 error_check_bad log_name_match:$res_data \ 169 [string first $x \ 170 [lindex $res_data_full $n]] -1 171 incr n 172 } 173 174 # Commit a transaction and close the associated db. 175 set t [lindex [lindex $txnlist 0] 0] 176 set tdb [lindex [lindex $txnlist 0] 1] 177 if { [string length $t] != 0 } { 178 error_check_good txn_commit:$t [$t commit] 0 179 error_check_good tdb_close:$tdb [$tdb close] 0 180 set txnlist [lrange $txnlist 1 end] 181 set lsnlist [lrange $lsnlist 1 end] 182 } 183 184 # If we're down to no transactions, start some new ones. 185 if { [llength $txnlist] == 0 } { 186 set t1 [$dbenv txn] 187 error_check_bad tx_begin $t1 NULL 188 error_check_good \ 189 tx_begin [is_substr $t1 $dbenv] 1 190 set tdb1 [eval {berkdb_open -create -mode 0644} \ 191 -env $dbenv -txn $t1 -btree tdb1.db] 192 error_check_good dbopen [is_valid_db $tdb1] TRUE 193 set l1 [lindex [lindex [$logc get -last] 0] 0] 194 lappend lsnlist $l1 195 196 set t2 [$dbenv txn] 197 error_check_bad tx_begin $t2 NULL 198 error_check_good \ 199 tx_begin [is_substr $t2 $dbenv] 1 200 set tdb2 [eval {berkdb_open -create -mode 0644} \ 201 -env $dbenv -txn $t2 -btree tdb2.db] 202 error_check_good dbopen [is_valid_db $tdb2] TRUE 203 set l2 [lindex [lindex [$logc get -last] 0] 0] 204 lappend lsnlist $l2 205 206 set t3 [$dbenv txn] 207 error_check_bad tx_begin $t3 NULL 208 error_check_good \ 209 tx_begin [is_substr $t3 $dbenv] 1 210 set tdb3 [eval {berkdb_open -create -mode 0644} \ 211 -env $dbenv -txn $t3 -btree tdb3.db] 212 error_check_good dbopen [is_valid_db $tdb3] TRUE 213 set l3 [lindex [lindex [$logc get -last] 0] 0] 214 lappend lsnlist $l3 215 216 set txnlist [list "$t1 $tdb1" "$t2 $tdb2" "$t3 $tdb3"] 217 } 218 } 219 } 220 # Commit any transactions still running. 221 puts "\tArchive.b: Commit any transactions still running." 222 foreach pair $txnlist { 223 set t [lindex $pair 0] 224 set tdb [lindex $pair 1] 225 error_check_good txn_commit:$t [$t commit] 0 226 error_check_good tdb_close:$tdb [$tdb close] 0 227 } 228 229 # Close and unlink the file 230 error_check_good log_cursor_close [$logc close] 0 231 reset_env $dbenv 232} 233 234proc archive_command { args } { 235 source ./include.tcl 236 237 # Catch a list of files output by db_archive. 238 catch { eval exec $util_path/db_archive $args } output 239 240 if { $is_windows_test == 1 || 1 } { 241 # On Windows, convert all filenames to use forward slashes. 242 regsub -all {[\\]} $output / output 243 } 244 245 # Output the [possibly-transformed] list. 246 return $output 247} 248 249proc min { a b } { 250 if {$a < $b} { 251 return $a 252 } else { 253 return $b 254 } 255} 256