1# See the file LICENSE for redistribution information.
2#
3# Copyright (c) 1996,2008 Oracle.  All rights reserved.
4#
5# $Id: recd005.tcl,v 12.10 2008/01/08 20:58:53 bostic Exp $
6#
7# TEST	recd005
8# TEST	Verify reuse of file ids works on catastrophic recovery.
9# TEST
10# TEST	Make sure that we can do catastrophic recovery even if we open
11# TEST	files using the same log file id.
12proc recd005 { method {select 0 } args } {
13	source ./include.tcl
14	global rand_init
15
16	set envargs ""
17	set zero_idx [lsearch -exact $args "-zero_log"]
18	if { $zero_idx != -1 } {
19		set args [lreplace $args $zero_idx $zero_idx]
20		set envargs "-zero_log"
21	}
22
23	set args [convert_args $method $args]
24	set omethod [convert_method $method]
25
26	puts "Recd005: $method catastrophic recovery ($envargs)"
27
28	berkdb srand $rand_init
29
30	set testfile1 recd005.1.db
31	set testfile2 recd005.2.db
32	set max_locks 2000
33	set eflags "-create -txn -lock_max_locks $max_locks \
34	    -lock_max_objects $max_locks -home $testdir $envargs"
35
36	set tnum 0
37	foreach sizes "{1000 10} {10 1000}" {
38		foreach ops "{abort abort} {abort commit} {commit abort} \
39		{commit commit}" {
40			env_cleanup $testdir
41			incr tnum
42
43			set s1 [lindex $sizes 0]
44			set s2 [lindex $sizes 1]
45			set op1 [lindex $ops 0]
46			set op2 [lindex $ops 1]
47			puts "\tRecd005.$tnum: $s1 $s2 $op1 $op2"
48
49			puts "\tRecd005.$tnum.a: creating environment"
50			set env_cmd "berkdb_env $eflags"
51			set dbenv [eval $env_cmd]
52			error_check_bad dbenv $dbenv NULL
53
54			# Create the two databases.
55			set oflags \
56			    "-create -mode 0644 -env $dbenv $args $omethod"
57			set db1 [eval {berkdb_open} $oflags $testfile1]
58			error_check_bad db_open $db1 NULL
59			error_check_good db_open [is_substr $db1 db] 1
60			error_check_good db_close [$db1 close] 0
61
62			set db2 [eval {berkdb_open} $oflags $testfile2]
63			error_check_bad db_open $db2 NULL
64			error_check_good db_open [is_substr $db2 db] 1
65			error_check_good db_close [$db2 close] 0
66			$dbenv close
67
68			set dbenv [eval $env_cmd]
69			puts "\tRecd005.$tnum.b: Populating databases"
70			do_one_file \
71			    $testdir $method $dbenv $env_cmd $testfile1 $s1 $op1
72			do_one_file \
73			    $testdir $method $dbenv $env_cmd $testfile2 $s2 $op2
74
75			puts "\tRecd005.$tnum.c: Verifying initial population"
76			check_file $testdir $env_cmd $testfile1 $op1
77			check_file $testdir $env_cmd $testfile2 $op2
78
79			# Now, close the environment (so that recovery will work
80			# on NT which won't allow delete of an open file).
81			reset_env $dbenv
82
83			berkdb debug_check
84			puts -nonewline \
85			    "\tRecd005.$tnum.d: About to run recovery ... "
86			flush stdout
87
88			set stat [catch \
89			    {exec $util_path/db_recover -h $testdir -c} \
90			    result]
91			if { $stat == 1 } {
92				error "Recovery error: $result."
93			}
94			puts "complete"
95
96			# Substitute a file that will need recovery and try
97			# running recovery again.
98			if { $op1 == "abort" } {
99				file copy -force $testdir/$testfile1.afterop \
100				    $testdir/$testfile1
101				move_file_extent $testdir $testfile1 \
102				    afterop copy
103			} else {
104				file copy -force $testdir/$testfile1.init \
105				    $testdir/$testfile1
106				move_file_extent $testdir $testfile1 init copy
107			}
108			if { $op2 == "abort" } {
109				file copy -force $testdir/$testfile2.afterop \
110				    $testdir/$testfile2
111				move_file_extent $testdir $testfile2 \
112				    afterop copy
113			} else {
114				file copy -force $testdir/$testfile2.init \
115				    $testdir/$testfile2
116				move_file_extent $testdir $testfile2 init copy
117			}
118
119			berkdb debug_check
120			puts -nonewline "\tRecd005.$tnum.e:\
121			    About to run recovery on pre-op database ... "
122			flush stdout
123
124			set stat \
125			    [catch {exec $util_path/db_recover \
126			    -h $testdir -c} result]
127			if { $stat == 1 } {
128				error "Recovery error: $result."
129			}
130			puts "complete"
131
132			set dbenv [eval $env_cmd]
133			check_file $testdir $env_cmd $testfile1 $op1
134			check_file $testdir $env_cmd $testfile2 $op2
135			reset_env $dbenv
136
137			puts "\tRecd005.$tnum.f:\
138			    Verify db_printlog can read logfile"
139			set tmpfile $testdir/printlog.out
140			set stat [catch \
141			    {exec $util_path/db_printlog -h $testdir \
142			    > $tmpfile} ret]
143			error_check_good db_printlog $stat 0
144			fileremove $tmpfile
145		}
146	}
147}
148
149proc do_one_file { dir method env env_cmd filename num op } {
150	source ./include.tcl
151
152	set init_file $dir/$filename.t1
153	set afterop_file $dir/$filename.t2
154	set final_file $dir/$filename.t3
155
156	# Save the initial file and open the environment and the first file
157	file copy -force $dir/$filename $dir/$filename.init
158	copy_extent_file $dir $filename init
159	set oflags "-auto_commit -unknown -env $env"
160	set db [eval {berkdb_open} $oflags $filename]
161
162	# Dump out file contents for initial case
163	open_and_dump_file $filename $env $init_file nop \
164	    dump_file_direction "-first" "-next"
165
166	set txn [$env txn]
167	error_check_bad txn_begin $txn NULL
168	error_check_good txn_begin [is_substr $txn $env] 1
169
170	# Now fill in the db and the txnid in the command
171	populate $db $method $txn $num 0 0
172
173	# Sync the file so that we can capture a snapshot to test
174	# recovery.
175	error_check_good sync:$db [$db sync] 0
176	file copy -force $dir/$filename $dir/$filename.afterop
177	copy_extent_file $dir $filename afterop
178	open_and_dump_file $testdir/$filename.afterop NULL \
179	    $afterop_file nop dump_file_direction "-first" "-next"
180	error_check_good txn_$op:$txn [$txn $op] 0
181
182	if { $op == "commit" } {
183		puts "\t\tFile $filename executed and committed."
184	} else {
185		puts "\t\tFile $filename executed and aborted."
186	}
187
188	# Dump out file and save a copy.
189	error_check_good sync:$db [$db sync] 0
190	open_and_dump_file $testdir/$filename NULL $final_file nop \
191	    dump_file_direction "-first" "-next"
192	file copy -force $dir/$filename $dir/$filename.final
193	copy_extent_file $dir $filename final
194
195	# If this is an abort, it should match the original file.
196	# If this was a commit, then this file should match the
197	# afterop file.
198	if { $op == "abort" } {
199		filesort $init_file $init_file.sort
200		filesort $final_file $final_file.sort
201		error_check_good \
202		    diff(initial,post-$op):diff($init_file,$final_file) \
203		    [filecmp $init_file.sort $final_file.sort] 0
204	} else {
205		filesort $afterop_file $afterop_file.sort
206		filesort $final_file $final_file.sort
207		error_check_good \
208		    diff(post-$op,pre-commit):diff($afterop_file,$final_file) \
209		    [filecmp $afterop_file.sort $final_file.sort] 0
210	}
211
212	error_check_good close:$db [$db close] 0
213}
214
215proc check_file { dir env_cmd filename op } {
216	source ./include.tcl
217
218	set init_file $dir/$filename.t1
219	set afterop_file $dir/$filename.t2
220	set final_file $dir/$filename.t3
221
222	open_and_dump_file $testdir/$filename NULL $final_file nop \
223	    dump_file_direction "-first" "-next"
224	if { $op == "abort" } {
225		filesort $init_file $init_file.sort
226		filesort $final_file $final_file.sort
227		error_check_good \
228		    diff(initial,post-$op):diff($init_file,$final_file) \
229		    [filecmp $init_file.sort $final_file.sort] 0
230	} else {
231		filesort $afterop_file $afterop_file.sort
232		filesort $final_file $final_file.sort
233		error_check_good \
234		    diff(pre-commit,post-$op):diff($afterop_file,$final_file) \
235		    [filecmp $afterop_file.sort $final_file.sort] 0
236	}
237}
238