1# See the file LICENSE for redistribution information.
2#
3# Copyright (c) 2004,2008 Oracle.  All rights reserved.
4#
5# $Id: env012.tcl,v 12.18 2008/01/08 20:58:53 bostic Exp $
6#
7# TEST	env012
8# TEST	Test DB_REGISTER.
9# TEST
10# TEST	DB_REGISTER will fail on systems without fcntl.  If it
11# TEST	fails, make sure we got the expected DB_OPNOTSUP return.
12# TEST
13# TEST	Then, the real tests:
14# TEST	For each test, we start a process that opens an env with -register.
15# TEST
16# TEST	1. Verify that a 2nd process can enter the existing env with -register.
17# TEST
18# TEST	2. Kill the 1st process, and verify that the 2nd process can enter
19# TEST	with "-register -recover".
20# TEST
21# TEST	3. Kill the 1st process, and verify that the 2nd process cannot
22# TEST	enter with just "-register".
23# TEST
24# TEST	4. While the 1st process is still running, a 2nd process enters
25# TEST	with "-register".  Kill the 1st process.  Verify that a 3rd process
26# TEST	can enter with "-register -recover".  Verify that the 3rd process,
27# TEST	entering, causes process 2 to fail with the message DB_RUNRECOVERY.
28# TEST
29# TEST	5. We had a bug where recovery was always run with -register
30# TEST	if there were empty slots in the process registry file.  Verify
31# TEST	that recovery doesn't automatically run if there is an empty slot.
32proc env012 { } {
33	source ./include.tcl
34	set tnum "012"
35
36	puts "Env$tnum: Test of DB_REGISTER."
37
38	puts "\tEnv$tnum.a: Platforms without fcntl fail with DB_OPNOTSUP."
39	env_cleanup $testdir
40	if {[catch {eval {berkdb_env} \
41	    -create -home $testdir -txn -register -recover} env]} {
42		error_check_good fail_OPNOTSUP [is_substr $env DB_OPNOTSUP] 1
43		puts "Skipping env$tnum; DB_REGISTER is not supported."
44	}
45	error_check_good env_close [$env close] 0
46
47	puts "\tEnv$tnum.b: Second process can join with -register."
48	env_cleanup $testdir
49	set testfile TESTFILE
50	set key KEY
51	set data DATA1
52
53	puts "\t\tEnv$tnum.b1: Start process 1."
54	set p1 [exec $tclsh_path $test_path/wrap.tcl envscript.tcl \
55	    $testdir/env$tnum.log.p1 \
56	    $testdir $testfile PUT $key $data RECOVER 10 &]
57
58	# Wait a while so process 1 has a chance to get going.
59	tclsleep 2
60
61	puts "\t\tEnv$tnum.b2: Start process 2."
62	set p2 [exec $tclsh_path $test_path/wrap.tcl envscript.tcl \
63	    $testdir/env$tnum.log.p2 \
64	    $testdir $testfile GET $key $data 0 0 &]
65
66	watch_procs $p1 1 120
67	watch_procs $p2 1 120
68
69	# Check log files for failures.
70	logcheck $testdir/env$tnum.log.p1
71	logcheck $testdir/env$tnum.log.p2
72
73	puts "\tEnv$tnum.c: Second process can join with -register\
74	    -recover after first process is killed."
75	env_cleanup $testdir
76
77	puts "\t\tEnv$tnum.c1: Start process 1."
78	set pids {}
79	set p1 [exec $tclsh_path $test_path/wrap.tcl envscript.tcl \
80	    $testdir/env$tnum.log.p1 \
81	    $testdir $testfile PUT $key $data RECOVER 10 &]
82	lappend pids $p1
83	tclsleep 2
84
85	puts "\t\tEnv$tnum.c2: Kill process 1."
86	set pids [findprocessids $testdir $pids]
87	foreach pid $pids {
88		tclkill $pid
89	}
90
91	puts "\t\tEnv$tnum.c3: Start process 2."
92	set p2 [exec $tclsh_path $test_path/wrap.tcl envscript.tcl \
93	    $testdir/env$tnum.log.p2 \
94	    $testdir $testfile GET $key $data RECOVER 0 &]
95
96	watch_procs $p2 1 120
97
98	# Check log files for failures.
99	logcheck $testdir/env$tnum.log.p1
100	logcheck $testdir/env$tnum.log.p2
101
102	if { $is_windows_test == 1 } {
103		puts "Skipping sections .d and .e on Windows platform."
104	} else {
105		puts "\tEnv$tnum.d: Second process cannot join without -recover\
106		    after first process is killed."
107		env_cleanup $testdir
108
109		puts "\t\tEnv$tnum.d1: Start process 1."
110		set pids {}
111		set p1 [exec $tclsh_path $test_path/wrap.tcl envscript.tcl \
112		    $testdir/env$tnum.log.p1 \
113		    $testdir $testfile PUT $key $data RECOVER 10 &]
114		lappend pids $p1
115		tclsleep 2
116
117		puts "\t\tEnv$tnum.d2: Kill process 1."
118		set pids [findprocessids $testdir $pids]
119		foreach pid $pids {
120			tclkill $pid
121		}
122
123		puts "\t\tEnv$tnum.d3: Start process 2."
124		set p2 [exec $tclsh_path $test_path/wrap.tcl envscript.tcl \
125		    $testdir/env$tnum.log.p2 \
126		    $testdir $testfile GET $key $data 0 0 &]
127		tclsleep 2
128		watch_procs $p2 1 120
129
130		# Check log files.  Log p1 should be clean, but we
131		# expect DB_RUNRECOVERY in log p2.
132		logcheck $testdir/env$tnum.log.p1
133		logcheckfails $testdir/env$tnum.log.p2 DB_RUNRECOVERY
134
135		puts "\tEnv$tnum.e: Running registered process detects failure."
136		env_cleanup $testdir
137
138		puts "\t\tEnv$tnum.e1: Start process 1."
139		set pids {}
140		set p1 [exec $tclsh_path $test_path/wrap.tcl envscript.tcl \
141		    $testdir/env$tnum.log.p1 \
142		    $testdir $testfile PUT $key $data RECOVER 10 &]
143		lappend pids $p1
144		tclsleep 2
145
146		# Identify child process to kill later.
147		set pids [findprocessids $testdir $pids]
148
149		puts "\t\tEnv$tnum.e2: Start process 2."
150		set p2 [exec $tclsh_path $test_path/wrap.tcl envscript.tcl \
151		    $testdir/env$tnum.log.p2 \
152		    $testdir $testfile LOOP $key $data 0 10 &]
153
154		puts "\t\tEnv$tnum.e3: Kill process 1."
155		foreach pid $pids {
156			tclkill $pid
157		}
158
159		puts "\t\tEnv$tnum.e4: Start process 3."
160		set p3 [exec $tclsh_path $test_path/wrap.tcl envscript.tcl \
161		    $testdir/env$tnum.log.p3 \
162		    $testdir $testfile GET $key $data RECOVER 0 &]
163		tclsleep 2
164
165		watch_procs $p2 1 120
166		watch_procs $p3 1 120
167
168		# Check log files.  Logs p1 and p3 should be clean, but we
169		# expect DB_RUNRECOVERY in log p2.
170		logcheck $testdir/env$tnum.log.p1
171		logcheckfails $testdir/env$tnum.log.p2 DB_RUNRECOVERY
172		logcheck $testdir/env$tnum.log.p3
173	}
174
175	puts "\tEnv$tnum.f: Empty slot shouldn't cause automatic recovery."
176
177	# Create 2 empty slots in the registry by letting two processes
178	# run to completion.
179	puts "\t\tEnv$tnum.f1: Start process 1."
180	set p1 [exec $tclsh_path $test_path/wrap.tcl envscript.tcl \
181	    $testdir/env$tnum.log.p1 \
182	    $testdir $testfile PUT $key $data RECOVER 1 &]
183
184	puts "\t\tEnv$tnum.f2: Start process 2."
185	set p2 [exec $tclsh_path $test_path/wrap.tcl envscript.tcl \
186	    $testdir/env$tnum.log.p2 \
187	    $testdir $testfile GET $key $data 0 1 &]
188
189	watch_procs $p1 1 60
190	watch_procs $p2 1 60
191
192	logcheck $testdir/env$tnum.log.p1
193	logcheck $testdir/env$tnum.log.p2
194
195	# Start two more process.  Neither should signal a need for recovery.
196	puts "\t\tEnv$tnum.f3: Start process 3."
197	set p3 [exec $tclsh_path $test_path/wrap.tcl envscript.tcl \
198	    $testdir/env$tnum.log.p3 \
199	    $testdir $testfile GET $key $data RECOVER 10 &]
200
201	tclsleep 2
202
203	puts "\t\tEnv$tnum.f4: Start process 4."
204	set p4 [exec $tclsh_path $test_path/wrap.tcl envscript.tcl \
205	    $testdir/env$tnum.log.p4 \
206	    $testdir $testfile PUT $key $data 0 10 &]
207
208	watch_procs $p3 1 120
209	watch_procs $p4 1 120
210
211	# Check log files: neither process should have returned DB_RUNRECOVERY.
212	logcheck $testdir/env$tnum.log.p3
213	logcheck $testdir/env$tnum.log.p4
214}
215
216# Check log file and report failures with FAIL.  Use this when
217# we don't expect failures.
218proc logcheck { logname } {
219	set errstrings [eval findfail $logname]
220	foreach errstring $errstrings {
221		puts "FAIL: error in $logname : $errstring"
222	}
223}
224
225# When we expect a failure, verify we find the one we expect.
226proc logcheckfails { logname message }  {
227	set f [open $logname r]
228	while { [gets $f line] >= 0 } {
229		if { [is_substr $line $message] == 1 } {
230			close $f
231			return 0
232		}
233	}
234	close $f
235	puts "FAIL: Did not find expected error $message."
236}
237
238# The script wrap.tcl creates a parent and a child process.  We
239# can't see the child pids, so find them by their sentinel files.
240# This creates a list where the parent pid is always listed
241# before the child pid.
242proc findprocessids { testdir plist }  {
243	set beginfiles [glob $testdir/begin.*]
244	foreach b $beginfiles {
245		regsub $testdir/begin. $b {} pid
246		if { [lsearch -exact $plist $pid] == -1 } {
247			lappend plist $pid
248		}
249	}
250	return $plist
251}
252
253