1# See the file LICENSE for redistribution information.
2#
3# Copyright (c) 2005-2009 Oracle.  All rights reserved.
4#
5# $Id$
6#
7# TEST	test116
8# TEST	Test of basic functionality of lsn_reset.
9# TEST
10# TEST	Create a database in an env.  Copy it to a new file within
11# TEST	the same env.  Reset the page LSNs.
12proc test116 { method {tnum "116"} args } {
13	source ./include.tcl
14	global util_path
15	global passwd
16
17	set orig_tdir $testdir
18	puts "Test$tnum ($method): Test lsn_reset."
19
20	set args [convert_args $method $args]
21	set encargs ""
22	set args [split_encargs $args encargs]
23	set omethod [convert_method $method]
24
25	set testfile A.db
26	set newtag new
27	set newfile $testfile.$newtag
28	set nentries 50
29	set filenames "A B C D E"
30
31	# This test needs two envs.  If one is provided, create the
32	# second under it.  If no env is provided, create both.
33	set txn ""
34	set txnenv 0
35	set envargs ""
36	set resetargs ""
37	set eindex [lsearch -exact $args "-env"]
38
39	if { $eindex == -1 } {
40		puts "\tTest$tnum.a: Creating env."
41		env_cleanup $testdir
42		set env [eval {berkdb_env} \
43		    -create $encargs $envargs -home $testdir -txn]
44		append args " -auto_commit "
45		error_check_good dbenv [is_valid_env $env] TRUE
46	} else {
47		incr eindex
48		set env [lindex $args $eindex]
49		puts "\tTest$tnum.a: Using provided env $env."
50
51		# Make sure the second env we create has all the
52		# same flags the provided env does.
53		if { [is_substr [$env get_open_flags] "-thread"] } {
54			append envargs " -thread "
55		}
56		if { [is_substr $args "-encrypt"] } {
57			append envargs " -encryptaes $passwd "
58		}
59		if { [is_substr [$env get_encrypt_flags] "-encryptaes"] } {
60			append envargs " -encryptaes $passwd "
61			append resetargs " -encrypt "
62		}
63		set txn ""
64		set txnenv [is_txnenv $env]
65		if { $txnenv == 1 } {
66			append args " -auto_commit "
67		} elseif { $txnenv == 0 } {
68			puts "Skipping Test$tnum for non-transactional env."
69			return
70		}
71	 	set testdir [get_home $env]
72	}
73
74	foreach lorder { 1234 4321 } {
75		if { $lorder == 1234 } {
76			set pattern "i i"
77		} else {
78			set pattern "I I"
79		}
80
81		# Open database A, populate and close.
82		puts "\tTest$tnum.b: Creating database with lorder $lorder."
83	 	cleanup $testdir $env
84
85		# Create a second directory, and create an env there.
86		set testdir [get_home $env]
87		set newdir $testdir/NEWDIR
88		file mkdir $newdir
89		set newenv [eval {berkdb_env} \
90		    -create $encargs $envargs -home $newdir -txn]
91		error_check_good newenv [is_valid_env $newenv] TRUE
92
93		# We test with subdatabases except with the queue access
94		# method, where they are not allowed.
95		if { [is_queue $method] == 1 || [is_partitioned $args] == 1} {
96			set db [eval {berkdb_open} -env $env -lorder $lorder \
97			    $omethod $args -create -mode 0644 $testfile]
98			error_check_good dbopen [is_valid_db $db] TRUE
99			set pgsize [stat_field $db stat "Page size"]
100			if { $txnenv == 1 } {
101				set t [$env txn]
102				error_check_good txn [is_valid_txn $t $env] TRUE
103				set txn "-txn $t"
104			}
105			for { set i 1 } { $i <= $nentries } { incr i } {
106				set key $i
107				set data DATA.$i
108				error_check_good db_put [eval {$db put} \
109				    $txn $key [chop_data $method $data]] 0
110			}
111			if { $txnenv == 1 } {
112				error_check_good t_commit [$t commit] 0
113			}
114			error_check_good db_close [$db close] 0
115		} else {
116			foreach filename $filenames {
117				set db [eval {berkdb_open} -env $env \
118				    -lorder $lorder $omethod $args -create \
119				    -mode 0644 $testfile $filename]
120				error_check_good dbopen [is_valid_db $db] TRUE
121				set pgsize [stat_field $db stat "Page size"]
122				if { $txnenv == 1 } {
123					set t [$env txn]
124					error_check_good \
125					    txn [is_valid_txn $t $env] TRUE
126					set txn "-txn $t"
127				}
128				for { set i 1 } { $i <= $nentries } { incr i } {
129					set key $i
130					set data DATA.$i
131					error_check_good \
132					    db_put [eval {$db put} $txn \
133					    $key [chop_data $method $data]] 0
134				}
135				if { $txnenv == 1 } {
136					error_check_good t_commit [$t commit] 0
137				}
138				error_check_good db_close [$db close] 0
139			}
140		}
141
142		# Copy database file A.  Reset LSNs on the copy. Then
143		# test that the copy is usable both in its native env
144		# and in a new env.
145
146		puts "\tTest$tnum.c: Copy database and reset its LSNs."
147		set testdir [get_home $env]
148		set newdir [get_home $newenv]
149
150		# Reset LSNs before copying.  We do a little dance here:
151		# first copy the file within the same directory, then reset
152		# the fileid on the copy, then reset the LSNs on the copy,
153		# and only then copy the new file to the new env.  Otherwise
154		# the LSNs would get reset on the original file.
155
156		file copy -force $testdir/$testfile $testdir/$newfile
157		# If we're using queue extents or partitions , we must
158		# copy the extents/partitions to the new file name as well.
159		set extents ""
160		if { [is_queueext $method] || [is_partitioned $args]} {
161			copy_extent_file $testdir $testfile $newtag
162		}
163		error_check_good fileid_reset [$env id_reset $newfile] 0
164		error_check_good \
165		    lsn_reset [eval {$env lsn_reset} $resetargs {$newfile}] 0
166
167		file copy -force $testdir/$newfile $newdir/$testfile
168
169		# If we're using queue extents, we must copy the extents
170		# to the new directory  as well.
171		if { [is_queueext $method] || [is_partitioned $args]} {
172			set extents [get_extfiles $testdir $newfile ""]
173			foreach extent $extents {
174				set nextent [make_ext_filename \
175				    $testdir/NEWDIR $testfile $extent]
176				file copy -force $extent $nextent
177			}
178		}
179
180		# Get the LSNs and check them.
181		set npages [getlsns \
182		     $testdir $testfile $extents $pgsize orig_lsns]
183		set newpages [getlsns \
184		     $testdir $newfile $extents $pgsize new_lsns]
185		set newdirpages [getlsns \
186		     $newdir $testfile $extents $pgsize newdir_lsns]
187		error_check_good newpages_match $npages $newpages
188		error_check_good newdirpages_match $npages $newdirpages
189		for { set i 0 } { $i < $npages } { incr i } {
190			error_check_binary \
191			    new_lsns [binary format $pattern 0 1]  $new_lsns($i)
192			error_check_binary \
193			    newdirlsns_match \
194			        [binary format $pattern 0 1] $newdir_lsns($i)
195		}
196
197		if { [ is_partitioned $args] } {
198			set nodump 1
199		} else {
200			set nodump 0
201		}
202		puts "\tTest$tnum.d: Verify directories with reset LSNs."
203	 	error_check_good \
204		    verify [verify_dir $testdir "\tTest$tnum.d: " 0 0 $nodump] 0
205	 	error_check_good \
206		    verify [verify_dir $newdir "\tTest$tnum.e: " 0 0 $nodump] 0
207
208		puts "\tTest$tnum.f: Open new db, check data, close db."
209		if { [is_queue $method] == 1 || [is_partitioned $args] == 1 } {
210			set db [eval {berkdb_open} -env $newenv \
211			    -lorder $lorder \
212			    $omethod $args -create -mode 0644 $testfile]
213			error_check_good dbopen [is_valid_db $db] TRUE
214			if { $txnenv == 1 } {
215				set t [$newenv txn]
216				error_check_good txn [is_valid_txn $t $newenv] TRUE
217				set txn "-txn $t"
218			}
219			for { set i 1 } { $i <= $nentries } { incr i } {
220				set key $i
221				set ret [eval {$db get} $txn $key]
222				error_check_good db_get \
223				    [lindex [lindex $ret 0] 1] \
224				    [pad_data $method DATA.$i]
225			}
226			if { $txnenv == 1 } {
227				error_check_good txn_commit [$t commit] 0
228			}
229			error_check_good db_close [$db close] 0
230		} else {
231			foreach filename $filenames {
232				set db [eval {berkdb_open} -env $newenv \
233				    -lorder $lorder $omethod $args \
234				    -create -mode 0644 $testfile $filename ]
235				error_check_good dbopen [is_valid_db $db] TRUE
236				if { $txnenv == 1 } {
237					set t [$newenv txn]
238					error_check_good \
239					    txn [is_valid_txn $t $newenv] TRUE
240					set txn "-txn $t"
241				}
242				for { set i 1 } { $i <= $nentries } { incr i } {
243					set key $i
244					set ret [eval {$db get} $txn $key]
245					error_check_good db_get \
246					    [lindex [lindex $ret 0] 1] \
247					    [pad_data $method DATA.$i]
248				}
249				if { $txnenv == 1 } {
250					error_check_good txn_commit [$t commit] 0
251				}
252				error_check_good db_close [$db close] 0
253			}
254		}
255		error_check_good newfile_rm [$env dbremove $newfile] 0
256		error_check_good newenv_close [$newenv close] 0
257		fileremove -f $newdir
258	}
259
260	set testdir $orig_tdir
261	# Close the parent env if this test created it.
262	if { $eindex == -1 } {
263		error_check_good env_close [$env close] 0
264	}
265}
266
267proc getlsns { testdir dbfile extents pgsize lsns } {
268	upvar $lsns file_lsns
269	set fid [open $testdir/$dbfile r]
270	fconfigure $fid -translation binary
271	set eof 0
272	set pg 0
273	while { $eof == 0 } {
274		set offset [expr $pg * $pgsize]
275		seek $fid $offset start
276		set file_lsns($pg) [read $fid 8]
277		set eof [eof $fid]
278		incr pg
279	}
280	close $fid
281	incr pg -1
282	foreach extent $extents {
283		set ep [getlsns $testdir \
284		    [make_ext_filename "." $dbfile $extent] \
285		    {} $pgsize elsns]
286		for {set i 0} {$i < $ep} {incr i} {
287			set file_lsns($pg) $elsns($i)
288			incr pg
289		}
290	}
291	return $pg
292}
293
294proc error_check_binary {func desired result} {
295	if { [binary_compare $desired $result] != 0 } {
296		flush stdout
297		flush stderr
298		binary scan $desired h16 d
299		binary scan $result h16 r
300		error "FAIL:[timestamp]\
301		    $func: expected $d, got $r"
302	}
303}
304