recd020.tcl 5.3 KB
Newer Older
unknown's avatar
unknown committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 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 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 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 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
# See the file LICENSE for redistribution information.
#
# Copyright (c) 1996-2002
#	Sleepycat Software.  All rights reserved.
#
# $Id: recd020.tcl,v 11.8 2002/08/08 15:38:08 bostic Exp $
#
# TEST	recd020
# TEST	Test recovery after checksum error.
proc recd020 { method args} {
	global fixed_len
	global log_log_record_types
	global datastr
	source ./include.tcl

	set pgindex [lsearch -exact $args "-pagesize"]
	if { $pgindex != -1 } {
		puts "Recd020: skipping for specific pagesizes"
		return
	}
	if { [is_queueext $method] == 1 } {
		puts "Recd020: skipping for method $method"
		return
	}

	puts "Recd020: $method recovery after checksum error"

	# Create the database and environment.
	env_cleanup $testdir

	set testfile recd020.db
	set flags "-create -txn -home $testdir"

	puts "\tRecd020.a: creating environment"
	set env_cmd "berkdb_env $flags"
	set dbenv [eval $env_cmd]
	error_check_good dbenv [is_valid_env $dbenv] TRUE

	set pgsize 512
	set orig_fixed_len $fixed_len
	set fixed_len [expr $pgsize / 4]
	set opts [convert_args $method $args]
	set omethod [convert_method $method]
	set oflags "-create $omethod -mode 0644 \
	    -auto_commit -chksum -pagesize $pgsize $opts $testfile"
	set db [eval {berkdb_open} -env $dbenv $oflags]

	#
	# Put some data.
	#
	set nument 50
	puts "\tRecd020.b: Put some data"
	for { set i 1 } { $i <= $nument } { incr i } {
		# Use 'i' as key so method doesn't matter
		set key $i
		set data $i$datastr

		# Put, in a txn.
		set txn [$dbenv txn]
		error_check_good txn_begin [is_valid_txn $txn $dbenv] TRUE
		error_check_good db_put \
		    [$db put -txn $txn $key [chop_data $method $data]] 0
		error_check_good txn_commit [$txn commit] 0
	}
	error_check_good db_close [$db close] 0
	error_check_good env_close [$dbenv close] 0
	#
	# We need to remove the env so that we don't get cached
	# pages.
	#
	error_check_good env_remove [berkdb envremove -home $testdir] 0

	puts "\tRecd020.c: Overwrite part of database"
	#
	# First just touch some bits in the file.  We want to go
	# through the paging system, so touch some data pages,
	# like the middle of page 2.
	# We should get a checksum error for the checksummed file.
	#
	set pg 2
	set fid [open $testdir/$testfile r+]
	fconfigure $fid -translation binary
	set seeklen [expr $pgsize * $pg + 200]
	seek $fid $seeklen start
	set byte [read $fid 1]
	binary scan $byte c val
	set newval [expr ~$val]
	set newbyte [binary format c $newval]
	seek $fid $seeklen start
	puts -nonewline $fid $newbyte
	close $fid

	#
	# Verify we get the checksum error.  When we get it, it should
	# log the error as well, so when we run recovery we'll need to
	# do catastrophic recovery.  We do this in a sub-process so that
	# the files are closed after the panic.
	#
	set f1 [open |$tclsh_path r+]
	puts $f1 "source $test_path/test.tcl"

	set env_cmd "berkdb_env_noerr $flags"
	set dbenv [send_cmd $f1 $env_cmd]
	error_check_good dbenv [is_valid_env $dbenv] TRUE

	set db [send_cmd $f1  "{berkdb_open_noerr} -env $dbenv $oflags"]
	error_check_good db [is_valid_db $db] TRUE

	# We need to set non-blocking mode so that after each command
	# we can read all the remaining output from that command and
	# we can know what the output from one command is.
	fconfigure $f1 -blocking 0
	set ret [read $f1]
	set got_err 0
	for { set i 1 } { $i <= $nument } { incr i } {
		set stat [send_cmd $f1  "catch {$db get $i} r"]
		set getret [send_cmd $f1  "puts \$r"]
		set ret [read $f1]
		if { $stat == 1 } {
			error_check_good dbget:fail [is_substr $getret \
			    "checksum error: catastrophic recovery required"] 1
			set got_err 1
			# Now verify that it was an error on the page we set.
			error_check_good dbget:pg$pg [is_substr $ret \
			    "failed for page $pg"] 1
			break
		} else {
			set key [lindex [lindex $getret 0] 0]
			set data [lindex [lindex $getret 0] 1]
			error_check_good keychk $key $i
			error_check_good datachk $data \
			    [pad_data $method $i$datastr]
		}
	}
	error_check_good got_chksum $got_err 1
	set ret [send_cmd $f1  "$db close"]
	set extra [read $f1]
	error_check_good db:fail [is_substr $ret "run recovery"] 1

	set ret [send_cmd $f1  "$dbenv close"]
	error_check_good env_close:fail [is_substr $ret "run recovery"] 1
	close $f1

        # Keep track of the log types we've seen
	if { $log_log_record_types == 1} {
		logtrack_read $testdir
	}

	puts "\tRecd020.d: Run normal recovery"
	set ret [catch {exec $util_path/db_recover -h $testdir} r]
	error_check_good db_recover $ret 1
	error_check_good dbrec:fail \
	    [is_substr $r "checksum error: catastrophic recovery required"] 1

	catch {fileremove $testdir/$testfile} ret
	puts "\tRecd020.e: Run catastrophic recovery"
	set ret [catch {exec $util_path/db_recover -c -h $testdir} r]
	error_check_good db_recover $ret 0

	#
	# Now verify the data was reconstructed correctly.
	#
	set env_cmd "berkdb_env_noerr $flags"
	set dbenv [eval $env_cmd]
	error_check_good dbenv [is_valid_env $dbenv] TRUE

	set db [eval {berkdb_open} -env $dbenv $oflags]
	error_check_good db [is_valid_db $db] TRUE

	for { set i 1 } { $i <= $nument } { incr i } {
		set stat [catch {$db get $i} ret]
		error_check_good stat $stat 0
		set key [lindex [lindex $ret 0] 0]
		set data [lindex [lindex $ret 0] 1]
		error_check_good keychk $key $i
		error_check_good datachk $data [pad_data $method $i$datastr]
	}
	error_check_good db_close [$db close] 0
	error_check_good env_close [$dbenv close] 0
}