blob: 12c69e5df09cd56d9f3c3ad39e91e8a468a6d259 (
plain)
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-2009 Oracle. All rights reserved.
#
# $Id$
#
# TEST recd016
# TEST Test recovery after checksum error.
proc recd016 { 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 "Recd016: skipping for specific pagesizes"
return
}
if { [is_queueext $method] == 1 || [is_partitioned $args]} {
puts "Recd016: skipping for method $method"
return
}
puts "Recd016: $method recovery after checksum error"
# Create the database and environment.
env_cleanup $testdir
set testfile recd016.db
set flags "-create -txn -home $testdir"
puts "\tRecd016.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 "\tRecd016.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 log_flush [$dbenv log_flush] 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 "\tRecd016.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: page $pg"] 1
set got_err 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 "handles still open"] 1
close $f1
# Keep track of the log types we've seen
if { $log_log_record_types == 1} {
logtrack_read $testdir
}
puts "\tRecd016.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"] 1
catch {fileremove $testdir/$testfile} ret
puts "\tRecd016.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 log_flush [$dbenv log_flush] 0
error_check_good env_close [$dbenv close] 0
set fixed_len $orig_fixed_len
return
}
|