1# See the file LICENSE for redistribution information.
2#
3# Copyright (c) 1996,2008 Oracle.  All rights reserved.
4#
5# $Id: test044.tcl,v 12.6 2008/01/08 20:58:53 bostic Exp $
6#
7# TEST	test044
8# TEST	Small system integration tests
9# TEST		Test proper functioning of the checkpoint daemon,
10# TEST		recovery, transactions, etc.
11# TEST
12# TEST	System integration DB test: verify that locking, recovery, checkpoint,
13# TEST	and all the other utilities basically work.
14# TEST
15# TEST	The test consists of $nprocs processes operating on $nfiles files.  A
16# TEST	transaction consists of adding the same key/data pair to some random
17# TEST	number of these files.  We generate a bimodal distribution in key size
18# TEST	with 70% of the keys being small (1-10 characters) and the remaining
19# TEST	30% of the keys being large (uniform distribution about mean $key_avg).
20# TEST	If we generate a key, we first check to make sure that the key is not
21# TEST	already in the dataset.  If it is, we do a lookup.
22#
23# XXX
24# This test uses grow-only files currently!
25proc test044 { method {nprocs 5} {nfiles 10} {cont 0} args } {
26	source ./include.tcl
27	global encrypt
28	global rand_init
29
30	set args [convert_args $method $args]
31	set omethod [convert_method $method]
32
33	berkdb srand $rand_init
34
35	# If we are using an env, then skip this test.  It needs its own.
36	set eindex [lsearch -exact $args "-env"]
37	if { $eindex != -1 } {
38		incr eindex
39		set env [lindex $args $eindex]
40		puts "Test044 skipping for env $env"
41		return
42	}
43	if { $encrypt != 0 } {
44		puts "Test044 skipping for security"
45		return
46	}
47
48	puts "Test044: system integration test db $method $nprocs processes \
49	    on $nfiles files"
50
51	# Parse options
52	set otherargs ""
53	set key_avg 10
54	set data_avg 20
55	set do_exit 0
56	for { set i 0 } { $i < [llength $args] } {incr i} {
57		switch -regexp -- [lindex $args $i] {
58			-key_avg { incr i; set key_avg [lindex $args $i] }
59			-data_avg { incr i; set data_avg [lindex $args $i] }
60			-testdir { incr i; set testdir [lindex $args $i] }
61			-x.* { set do_exit 1 }
62			default {
63				lappend otherargs [lindex $args $i]
64			}
65		}
66	}
67
68	if { $cont == 0 } {
69		# Create the database and open the dictionary
70		env_cleanup $testdir
71
72		# Create an environment
73		puts "\tTest044.a: creating environment and $nfiles files"
74		set dbenv [berkdb_env -create -txn -home $testdir]
75		error_check_good env_open [is_valid_env $dbenv] TRUE
76
77		# Create a bunch of files
78		set m $method
79
80		for { set i 0 } { $i < $nfiles } { incr i } {
81			if { $method == "all" } {
82				switch [berkdb random_int 1 2] {
83				1 { set m -btree }
84				2 { set m -hash }
85				}
86			} else {
87				set m $omethod
88			}
89
90			set db [eval {berkdb_open -env $dbenv -create \
91			    -mode 0644 $m} $otherargs {test044.$i.db}]
92			error_check_good dbopen [is_valid_db $db] TRUE
93			error_check_good db_close [$db close] 0
94		}
95	}
96
97	# Close the environment
98	$dbenv close
99
100	if { $do_exit == 1 } {
101		return
102	}
103
104	# Database is created, now fork off the kids.
105	puts "\tTest044.b: forking off $nprocs processes and utilities"
106	set cycle 1
107	set ncycles 3
108	while { $cycle <= $ncycles } {
109		set dbenv [berkdb_env -create -txn -home $testdir]
110		error_check_good env_open [is_valid_env $dbenv] TRUE
111
112		# Fire off deadlock detector and checkpointer
113		puts "Beginning cycle $cycle"
114		set ddpid [exec $util_path/db_deadlock -h $testdir -t 5 &]
115		set cppid [exec $util_path/db_checkpoint -h $testdir -p 2 &]
116		puts "Deadlock detector: $ddpid Checkpoint daemon $cppid"
117
118		set pidlist {}
119		for { set i 0 } {$i < $nprocs} {incr i} {
120			set p [exec $tclsh_path \
121			    $test_path/sysscript.tcl $testdir \
122			    $nfiles $key_avg $data_avg $omethod \
123			    >& $testdir/test044.$i.log &]
124			lappend pidlist $p
125		}
126		set sleep [berkdb random_int 300 600]
127		puts \
128"[timestamp] $nprocs processes running $pidlist for $sleep seconds"
129		tclsleep $sleep
130
131		# Now simulate a crash
132		puts "[timestamp] Crashing"
133
134		#
135		# The environment must remain open until this point to get
136		# proper sharing (using the paging file) on Win/9X.  [#2342]
137		#
138		error_check_good env_close [$dbenv close] 0
139
140		tclkill $ddpid
141		tclkill $cppid
142
143		foreach p $pidlist {
144			tclkill $p
145		}
146
147		# Check for test failure
148		set errstrings [eval findfail [glob $testdir/test044.*.log]]
149		foreach str $errstrings {
150			puts "FAIL: error message in log file: $str"
151		}
152
153		# Now run recovery
154		test044_verify $testdir $nfiles
155		incr cycle
156	}
157}
158
159proc test044_usage { } {
160	puts -nonewline "test044 method nentries [-d directory] [-i iterations]"
161	puts " [-p procs] -x"
162}
163
164proc test044_verify { dir nfiles } {
165	source ./include.tcl
166
167	# Save everything away in case something breaks
168#	for { set f 0 } { $f < $nfiles } {incr f} {
169#		file copy -force $dir/test044.$f.db $dir/test044.$f.save1
170#	}
171#	foreach f [glob $dir/log.*] {
172#		if { [is_substr $f save] == 0 } {
173#			file copy -force $f $f.save1
174#		}
175#	}
176
177	# Run recovery and then read through all the database files to make
178	# sure that they all look good.
179
180	puts "\tTest044.verify: Running recovery and verifying file contents"
181	set stat [catch {exec $util_path/db_recover -h $dir} result]
182	if { $stat == 1 } {
183		error "FAIL: Recovery error: $result."
184	}
185
186	# Save everything away in case something breaks
187#	for { set f 0 } { $f < $nfiles } {incr f} {
188#		file copy -force $dir/test044.$f.db $dir/test044.$f.save2
189#	}
190#	foreach f [glob $dir/log.*] {
191#		if { [is_substr $f save] == 0 } {
192#			file copy -force $f $f.save2
193#		}
194#	}
195
196	for { set f 0 } { $f < $nfiles } { incr f } {
197		set db($f) [berkdb_open $dir/test044.$f.db]
198		error_check_good $f:dbopen [is_valid_db $db($f)] TRUE
199
200		set cursors($f) [$db($f) cursor]
201		error_check_bad $f:cursor_open $cursors($f) NULL
202		error_check_good \
203		    $f:cursor_open [is_substr $cursors($f) $db($f)] 1
204	}
205
206	for { set f 0 } { $f < $nfiles } { incr f } {
207		for {set d [$cursors($f) get -first] } \
208		    { [string length $d] != 0 } \
209		    { set d [$cursors($f) get -next] } {
210
211			set k [lindex [lindex $d 0] 0]
212			set d [lindex [lindex $d 0] 1]
213
214			set flist [zero_list $nfiles]
215			set r $d
216			while { [set ndx [string first : $r]] != -1 } {
217				set fnum [string range $r 0 [expr $ndx - 1]]
218				if { [lindex $flist $fnum] == 0 } {
219					set fl "-set"
220				} else {
221					set fl "-next"
222				}
223
224				if { $fl != "-set" || $fnum != $f } {
225					if { [string compare $fl "-set"] == 0} {
226						set full [$cursors($fnum) \
227						    get -set $k]
228					} else  {
229						set full [$cursors($fnum) \
230						    get -next]
231					}
232					set key [lindex [lindex $full 0] 0]
233					set rec [lindex [lindex $full 0] 1]
234					error_check_good \
235					    $f:dbget_$fnum:key $key $k
236					error_check_good \
237					    $f:dbget_$fnum:data $rec $d
238				}
239
240				set flist [lreplace $flist $fnum $fnum 1]
241				incr ndx
242				set r [string range $r $ndx end]
243			}
244		}
245	}
246
247	for { set f 0 } { $f < $nfiles } { incr f } {
248		error_check_good $cursors($f) [$cursors($f) close] 0
249		error_check_good db_close:$f [$db($f) close] 0
250	}
251}
252