1# See the file LICENSE for redistribution information.
2#
3# Copyright (c) 2004-2009 Oracle.  All rights reserved.
4#
5# $Id$
6#
7# TEST	rep069
8# TEST	Test of internal initialization and elections.
9# TEST
10# TEST	If a client is in a recovery mode of any kind, it
11# TEST	participates in elections at priority 0 so it can
12# TEST	never be elected master.
13#
14proc rep069 { method { niter 200 } { tnum "069" } args } {
15
16	source ./include.tcl
17	global databases_in_memory
18	global repfiles_in_memory
19
20	if { $is_windows9x_test == 1 } {
21		puts "Skipping replication test on Win 9x platform."
22		return
23	}
24	if { $checking_valid_methods } {
25		set test_methods { btree }
26		return $test_methods
27	}
28	if { [is_btree $method] == 0 } {
29		puts "Rep$tnum: Skipping for method $method."
30		return
31	}
32
33	set args [convert_args $method $args]
34	set saved_args $args
35
36	set logsets [create_logsets 2]
37
38	# Set up for on-disk or in-memory databases.
39	set msg "using on-disk databases"
40	if { $databases_in_memory } {
41		set msg "using named in-memory databases"
42		if { [is_queueext $method] } {
43			puts -nonewline "Skipping rep$tnum for method "
44			puts "$method with named in-memory databases."
45			return
46		}
47	}
48
49	set msg2 "and on-disk replication files"
50	if { $repfiles_in_memory } {
51		set msg2 "and in-memory replication files"
52	}
53
54	foreach l $logsets {
55		set args $saved_args
56		puts "Rep$tnum ($method $args): Test internal\
57		    initialization and elections $msg $msg2."
58		puts "Rep$tnum: Master logs are [lindex $l 0]"
59		puts "Rep$tnum: Client logs are [lindex $l 1]"
60		rep069_sub $method $niter $tnum $l $args
61	}
62}
63
64proc rep069_sub { method niter tnum logset largs } {
65	global testdir
66	global util_path
67	global databases_in_memory
68	global repfiles_in_memory
69	global rep_verbose
70	global verbose_type
71	global timeout_ok
72
73	env_cleanup $testdir
74
75	set qdir $testdir/MSGQUEUEDIR
76	replsetup $qdir
77
78	set verbargs ""
79	if { $rep_verbose == 1 } {
80		set verbargs " -verbose {$verbose_type on} "
81	}
82
83	set repmemargs ""
84	if { $repfiles_in_memory } {
85		set repmemargs "-rep_inmem_files "
86	}
87
88	set masterdir $testdir/MASTERDIR
89	file mkdir $masterdir
90
91	set nclients 2
92	for { set i 0 } { $i < $nclients } { incr i } {
93		set clientdir($i) $testdir/CLIENTDIR.$i
94		file mkdir $clientdir($i)
95	}
96
97	# Log size is small so we quickly create more than one, and
98	# can easily force internal initialization.
99	set pagesize 4096
100	append largs " -pagesize $pagesize "
101	set log_max [expr $pagesize * 8]
102
103	set m_logtype [lindex $logset 0]
104	set c_logtype [lindex $logset 1]
105
106	# In-memory logs cannot be used with -txn nosync.
107	set m_logargs [adjust_logargs $m_logtype]
108	set c_logargs [adjust_logargs $c_logtype]
109	set m_txnargs [adjust_txnargs $m_logtype]
110	set c_txnargs [adjust_txnargs $c_logtype]
111
112	# Open a master.
113	set envlist {}
114	repladd 1
115	set ma_envcmd "berkdb_env_noerr -create $m_txnargs \
116	    $repmemargs \
117	    $m_logargs -log_max $log_max -event rep_event $verbargs \
118	    -home $masterdir -rep_transport \[list 1 replsend\]"
119	set masterenv [eval $ma_envcmd -recover -rep_master]
120	lappend envlist "$masterenv 1"
121
122	# Open clients.
123	for { set i 0 } { $i < $nclients } { incr i } {
124		set envid [expr $i + 2]
125		repladd $envid
126		set envcmd($i) "berkdb_env_noerr -create \
127		    $repmemargs \
128		    $c_txnargs $c_logargs -log_max $log_max \
129		    -home $clientdir($i) -event rep_event $verbargs \
130		    -rep_transport \[list $envid replsend\]"
131		set clientenv($i) [eval $envcmd($i) -recover -rep_client]
132		lappend envlist "$clientenv($i) $envid"
133	}
134
135	# Bring the clients online by processing the startup messages.
136	process_msgs $envlist
137
138	# Clobber replication's 30-second anti-archive timer, which will have
139	# been started by client sync-up internal init, so that we can do a
140	# db_archive in a moment.
141	#
142	$masterenv test force noarchive_timeout
143
144	# Run rep_test in the master and update clients.
145	puts "\tRep$tnum.a: Running rep_test in replicated env."
146	set start 0
147	eval rep_test \
148	    $method $masterenv NULL $niter $start $start 0 $largs
149	incr start $niter
150	process_msgs $envlist 0 NONE err
151	error_check_good process_msgs $err 0
152
153        # Find out what exists on the client.  We need to loop until
154        # the first master log file > last client log file.  The two
155	# clients should be the same, so just inspect one.
156        puts "\tRep$tnum.b: Close clients."
157        if { $c_logtype != "in-memory" } {
158                set res [eval exec $util_path/db_archive -l -h $clientdir(0)]
159                set res [eval exec $util_path/db_archive -l -h $clientdir(1)]
160        }
161        set last_client_log [get_logfile $clientenv(1) last]
162	for { set i 0 } { $i < $nclients } { incr i } {
163		error_check_good client_close [$clientenv($i) close] 0
164	}
165	set envlist [lreplace $envlist 1 2]
166
167	# Run the master forward.
168	set stop 0
169	while { $stop == 0 } {
170		puts "\tRep$tnum.c: Running rep_test in replicated env."
171		eval rep_test \
172		    $method $masterenv NULL $niter $start $start 0 $largs
173		incr start $niter
174
175		puts "\tRep$tnum.d: Run db_archive on master."
176                if { $m_logtype != "in-memory"} {
177                        set res [eval \
178			    exec $util_path/db_archive -d -h $masterdir]
179                }
180                set first_master_log [get_logfile $masterenv first]
181                if { $first_master_log > $last_client_log } {
182                        set stop 1
183                }
184        }
185
186	for { set i 0 } { $i < $nclients } { incr i } {
187		set envid [expr $i + 2]
188		replclear $envid
189	}
190
191	# Reopen clients.
192	puts "\tRep$tnum.e: Reopen clients."
193	for { set i 0 } { $i < $nclients } { incr i } {
194		env_cleanup $clientdir($i)
195		set clientenv($i) [eval $envcmd($i) -recover -rep_client]
196		set envid [expr $i + 2]
197		lappend envlist "$clientenv($i) $envid"
198	}
199
200	# Run proc_msgs_once until both clients are in internal
201	# initialization.
202	#
203	# We figure out whether each client is in initialization
204	# by searching for any of the flags REP_F_RECOVER_UPDATE,
205	# REP_F_RECOVER_PAGE, and REP_F_RECOVER_LOG.  As soon as
206	# a client produces one of these, it's marked as being
207	# in initialization, and stays that way even if it proceeds
208	# further, but we don't exit the loop until all clients
209	# have gotten into initialization.
210	#
211	puts "\tRep$tnum.f:\
212	    Run proc_msgs_once until all clients enter internal init."
213	set in_init 0
214	for { set i 0 } { $i < $nclients } { incr i } {
215		set initializing($i) 0
216	}
217
218	while { $in_init != 1 } {
219		set nproced [proc_msgs_once $envlist NONE err]
220		for { set i 0 } { $i < $nclients } { incr i } {
221			set stat($i) \
222			    [exec $util_path/db_stat -r -R A -h $clientdir(1)]
223			if {[is_substr $stat($i) "REP_F_RECOVER_UPDATE"] } {
224				set initializing($i) 1
225			}
226			if {[is_substr $stat($i) "REP_F_RECOVER_PAGE"] } {
227				set initializing($i) 1
228			}
229			if {[is_substr $stat($i) "REP_F_RECOVER_LOG"] } {
230				set initializing($i) 1
231			}
232		}
233		set in_init 1
234		for { set i 0 } { $i < $nclients } { incr i } {
235			if { $initializing($i) == 0 } {
236				set in_init 0
237			}
238		}
239	}
240
241	# Call an election.  It should fail, because both clients
242	# are in internal initialization and therefore not electable.
243	# Indicate failure with winner = -2.
244	# First, close the master.
245	error_check_good masterenv_close [$masterenv close] 0
246	set envlist [lreplace $envlist 0 0]
247
248        puts "\tRep$tnum.g: Run election; no one will get elected."
249	set m "Rep$tnum.g"
250        set nsites $nclients
251        set nvotes $nclients
252        set winner -2
253        set elector 0
254	for { set i 0 } { $i < $nclients } { incr i } {
255		set err_cmd($i) "none"
256		set crash($i) 0
257		set pri($i) 10
258	}
259
260	# This election will time out instead of succeeding.
261	set timeout_ok 1
262	if { $databases_in_memory } {
263		set dbname { "" "test.db" }
264	} else {
265		set dbname "test.db"
266	}
267        run_election envcmd envlist err_cmd pri crash \
268            $qdir $m $elector $nsites $nvotes $nclients $winner \
269	    0 $dbname 0 $timeout_ok
270
271	# Verify that each client saw the message that no
272	# electable site was found.
273	puts "\tRep$tnum.h: Check for right error message."
274	for { set i 0 } { $i < $nclients } { incr i } {
275		set none_electable 0
276		set id [expr $i + 1]
277		set fd [open $testdir/ELECTION_RESULT.$id r]
278		while { [gets $fd str] != -1 } {
279			if { [is_substr $str "Unable to elect a master"] == 1 } {
280				set none_electable 1
281				break
282			}
283		}
284		close $fd
285		error_check_good none_electable $none_electable 1
286	}
287
288	# Clean up for the next pass.
289	for { set i 0 } { $i < $nclients } { incr i } {
290		$clientenv($i) close
291	}
292
293	replclose $testdir/MSGQUEUEDIR
294}
295
296