1# See the file LICENSE for redistribution information.
2#
3# Copyright (c) 2002,2008 Oracle.  All rights reserved.
4#
5# $Id: rep063.tcl,v 1.15 2008/01/08 20:58:53 bostic Exp $
6#
7# TEST  rep063
8# TEST	Replication election test with simulated different versions
9# TEST	for each site.  This tests that old sites with real priority
10# TEST	trump ELECTABLE sites with zero priority even with greater LSNs.
11# TEST	There is a special case in the code for testing that if the
12# TEST	priority is <= 10, we simulate mixed versions for elections.
13# TEST
14# TEST	Run a rep_test in a replicated master environment and close;
15# TEST  hold an election among a group of clients to make sure they select
16# TEST  the master with varying LSNs and priorities.
17#
18proc rep063 { method args } {
19	source ./include.tcl
20	if { $is_windows9x_test == 1 } {
21		puts "Skipping replication test on Win 9x platform."
22		return
23	}
24	set tnum "063"
25
26	# Skip for all methods except btree.
27	if { $checking_valid_methods } {
28		set test_methods { btree }
29		return $test_methods
30	}
31	if { [is_btree $method] == 0 } {
32		puts "Rep$tnum: Skipping for method $method."
33		return
34	}
35
36	set nclients 5
37	set logsets [create_logsets [expr $nclients + 1]]
38
39	# Run the body of the test with and without recovery.
40	set recopts { "" "-recover" }
41	foreach r $recopts {
42		foreach l $logsets {
43			set logindex [lsearch -exact $l "in-memory"]
44			if { $r == "-recover" && $logindex != -1 } {
45				puts "Rep$tnum: Skipping\
46				    for in-memory logs with -recover."
47				continue
48			}
49			puts "Rep$tnum ($method $r): \
50			    Replication elections with varying versions."
51			puts "Rep$tnum: Master logs are [lindex $l 0]"
52			for { set i 0 } { $i < $nclients } { incr i } {
53				puts "Rep$tnum: Client $i logs are\
54				    [lindex $l [expr $i + 1]]"
55			}
56			rep063_sub $method $nclients $tnum $l $r $args
57		}
58	}
59}
60
61proc rep063_sub { method nclients tnum logset recargs largs } {
62	source ./include.tcl
63	global electable_pri
64	global rep_verbose
65	global verbose_type
66
67	set verbargs ""
68	if { $rep_verbose == 1 } {
69		set verbargs " -verbose {$verbose_type on} "
70	}
71
72	set niter 80
73
74	env_cleanup $testdir
75
76	set qdir $testdir/MSGQUEUEDIR
77	replsetup $qdir
78
79	set masterdir $testdir/MASTERDIR
80	file mkdir $masterdir
81
82	set m_logtype [lindex $logset 0]
83	set m_logargs [adjust_logargs $m_logtype]
84	set m_txnargs [adjust_txnargs $m_logtype]
85
86	for { set i 0 } { $i < $nclients } { incr i } {
87		set clientdir($i) $testdir/CLIENTDIR.$i
88		file mkdir $clientdir($i)
89		set c_logtype($i) [lindex $logset [expr $i + 1]]
90		set c_logargs($i) [adjust_logargs $c_logtype($i)]
91		set c_txnargs($i) [adjust_txnargs $c_logtype($i)]
92	}
93
94	# Open a master.
95	set envlist {}
96	repladd 1
97	set env_cmd(M) "berkdb_env_noerr -create -log_max 1000000 \
98	    -event rep_event \
99	    -home $masterdir $m_txnargs $m_logargs -rep_master $verbargs \
100	    -errpfx MASTER -rep_transport \[list 1 replsend\]"
101	set masterenv [eval $env_cmd(M) $recargs]
102	error_check_good master_env [is_valid_env $masterenv] TRUE
103	lappend envlist "$masterenv 1"
104
105	# Open the clients.
106	for { set i 0 } { $i < $nclients } { incr i } {
107		set envid [expr $i + 2]
108		repladd $envid
109		set env_cmd($i) "berkdb_env_noerr -create -home $clientdir($i) \
110		    -event rep_event \
111		    $c_txnargs($i) $c_logargs($i) -rep_client \
112		    -rep_transport \[list $envid replsend\]"
113		set clientenv($i) [eval $env_cmd($i) $recargs]
114		error_check_good \
115		    client_env($i) [is_valid_env $clientenv($i)] TRUE
116		lappend envlist "$clientenv($i) $envid"
117	}
118	# Bring the clients online by processing the startup messages.
119	process_msgs $envlist
120
121	# Run a modified test001 in the master.
122	puts "\tRep$tnum.a: Running rep_test in replicated env."
123	eval rep_test $method $masterenv NULL $niter 0 0 0 0 $largs
124	process_msgs $envlist
125
126	#
127	# We remove some client envs and run rep_test so that we can
128	# force some client LSNs to be further ahead/behind than others.
129	# When we're done, the LSNs look like this:
130	#
131	# Client0: ......................
132	# Client1: ...........
133	# Client2: ...........
134	# Client3: ......................
135	# Client4: .................................
136	#
137	# Remove client 1 and 2 from list to process, this guarantees
138	# clients 0, 3 and 4 are ahead in LSN.  We use each of these
139	# in different parts of the test so guarantee bigger LSNs.
140	#
141	set orig_env $envlist
142	set envlist [lreplace $envlist 3 3]
143	set envlist [lreplace $envlist 2 2]
144	eval rep_test $method $masterenv NULL $niter 0 0 0 0 $largs
145	process_msgs $envlist
146	#
147	# Remove client 3 so that client 4 has the biggest LSN of all.
148	#
149	set eend [llength $envlist]
150	set cl3_i [expr $eend - 2]
151	set envlist [lreplace $envlist $cl3_i $cl3_i]
152	eval rep_test $method $masterenv NULL $niter 0 0 0 0 $largs
153	process_msgs $envlist
154	#
155	# Put all removed clients back in.
156	#
157	set envlist $orig_env
158	error_check_good masterenv_close [$masterenv close] 0
159	set envlist [lreplace $envlist 0 0]
160
161	for { set i 0 } { $i < $nclients } { incr i } {
162		replclear [expr $i + 2]
163		#
164		# This test doesn't use the testing hooks, so
165		# initialize err_cmd and crash appropriately.
166		#
167		set err_cmd($i) "none"
168		set crash($i) 0
169		#
170		# Initialize the array pri.  We'll set it to
171		# appropriate values when the winner is determined.
172 		#
173		set pri($i) 0
174		#
175		if { $rep_verbose == 1 } {
176			error_check_good pfx [$clientenv($i) errpfx CLIENT$i] 0
177			$clientenv($i) verbose $verbose_type on
178			set env_cmd($i) [concat $env_cmd($i) \
179			    "-errpfx CLIENT$i $verbargs "]
180		}
181	}
182	#
183	# Remove clients 3 and 4 from the envlist.  We'll save those for
184	# later.
185	#
186	set cl4 [lindex $envlist 4]
187	set envlist [lreplace $envlist 4 4]
188	set cl3 [lindex $envlist 3]
189	set envlist [lreplace $envlist 3 3]
190
191	set m "Rep$tnum.b"
192	#
193	# Client 0 has the biggest LSN of clients 0, 1, 2.
194	# However, 'setpriority' will set the priority of client 1
195	# to simulate client 1 being an "older version" client.
196	# Client 1 should win even though its LSN is smaller.
197	# This tests one "older" client and the rest "newer".
198	#
199	puts "\t$m: Test old client trumps new clients with bigger LSN."
200	set orig_ncl $nclients
201	set nclients 3
202	set nsites $nclients
203	set nvotes $nclients
204	set winner 1
205	set elector 2
206	setpriority pri $nclients $winner 0 1
207	run_election env_cmd envlist err_cmd pri crash\
208	    $qdir $m $elector $nsites $nvotes $nclients $winner 0 test.db
209	#
210	# In all of the checks of the Election Priority stat field,
211	# we use clientenv(2).  The reason is that we never expect
212	# client 2 to be the winner.  The env handles of client 0 and 1
213	# are getting closed and reopened as a master/client in
214	# the election and the old recorded handles are invalid.
215	# This one is known to be valid throughout the entire test.
216	#
217	error_check_bad old_pri [stat_field $clientenv(2) rep_stat \
218	    "Election priority"] 0
219	#
220	# When we finish the election, all clients are at the same LSN.
221	# Call this proc to make the winner have a larger LSN than the
222	# other 2 remaining clients, and reopen the winner as a client.
223	#
224	rep063_movelsn_reopen $method envlist $env_cmd($winner) $winner $largs
225
226	set m "Rep$tnum.c"
227	puts "\t$m: Test old client with zero priority new client."
228	#
229	# Client 1 now has a bigger LSN, so make client 0 the old client
230	# and client 1 a real 0 priority new client.
231	#
232	set winner 0
233	setpriority pri $nclients $winner 0 1
234	set pri(1) 0
235	run_election env_cmd envlist err_cmd pri crash $qdir \
236	    $m $elector $nsites $nvotes $nclients $winner 0 test.db
237	error_check_bad old_pri [stat_field $clientenv(2) rep_stat \
238	    "Election priority"] 0
239	rep063_movelsn_reopen $method envlist $env_cmd($winner) $winner $largs
240
241	set m "Rep$tnum.d"
242	puts "\t$m: Test multiple old clients with new client."
243	#
244	# Client 0 is now has a bigger LSN, so make client 1 winner.
245	# We are setting client 2's priority to something bigger so that
246	# we simulate having 2 "older version" clients (clients 1 and 2)
247	# and one new client (client 0).  This tests that the right client
248	# among the older versions gets correctly elected even though there
249	# is a bigger LSN "new" client participating.
250	#
251	set winner 1
252	setpriority pri $nclients $winner 0 1
253	set pri(2) [expr $pri(1) / 2]
254	run_election env_cmd envlist err_cmd pri crash $qdir \
255	    $m $elector $nsites $nvotes $nclients $winner 0 test.db
256	error_check_bad old_pri [stat_field $clientenv(2) rep_stat \
257	    "Election priority"] 0
258	rep063_movelsn_reopen $method envlist $env_cmd($winner) $winner $largs
259
260	set m "Rep$tnum.e"
261	puts "\t$m: Test new clients, client 1 not electable."
262	#
263	# Client 1 now has a bigger LSN, so make it unelectable.  Add in
264	# old client 3 since that should be the biggest LSN of all these.
265	# Set all other priorities to electable_pri to make them all equal (and
266	# all "new" clients).  We know client 3 should win because we
267	# set its LSN much farther ahead in the beginning.
268	#
269	set winner 3
270	replclear [expr $winner + 2]
271	set nclients 4
272	set nsites $nclients
273	set nvotes $nclients
274	set pri(0) $electable_pri
275	set pri(1) 0
276	set pri(2) $electable_pri
277	set pri(3) $electable_pri
278	replclear [lindex $cl3 1]
279	lappend envlist $cl3
280	#
281	# Winner should be zero priority.
282	#
283	run_election env_cmd envlist err_cmd pri crash $qdir \
284	    $m $elector $nsites $nvotes $nclients $winner 0 test.db
285	error_check_good elect_pri [stat_field $clientenv(2) rep_stat \
286	    "Election priority"] 0
287	rep063_movelsn_reopen $method envlist $env_cmd($winner) $winner $largs
288
289	#
290	# Now add in Client 4, the site with the biggest LSN of all.
291	# Test with all being electable clients.
292	#
293	set m "Rep$tnum.f"
294	puts "\t$m: Test all new electable clients."
295	set winner 4
296	set nclients 5
297	set nsites $nclients
298	set nvotes $nclients
299	set pri(0) $electable_pri
300	set pri(1) $electable_pri
301	set pri(2) $electable_pri
302	set pri(3) $electable_pri
303	set pri(4) $electable_pri
304	replclear [expr $winner + 2]
305	lappend envlist $cl4
306	#
307	# Client 4 has biggest LSN and should now win, but winner should
308	# be zero priority.
309	#
310	run_election env_cmd envlist err_cmd pri crash $qdir \
311	    $m $elector $nsites $nvotes $nclients $winner 0 test.db
312	error_check_good elect_pri [stat_field $clientenv(2) rep_stat \
313	    "Election priority"] 0
314
315	foreach pair $envlist {
316		set cenv [lindex $pair 0]
317		error_check_good cenv_close [$cenv close] 0
318	}
319	replclose $testdir/MSGQUEUEDIR
320}
321
322#
323# Move the LSN ahead on the newly elected master, while not sending
324# those messages to the other clients.  Then close the env and
325# reopen it as a client.  Use upvar so that the envlist is
326# modified when we return and can get messages.
327#
328proc rep063_movelsn_reopen { method envlist env_cmd eindex largs } {
329	upvar $envlist elist
330
331	set clrlist { }
332	set i 0
333	foreach e $elist {
334		#
335		# If we find the master env entry, get its env handle.
336		# If not, then get the id so that we can replclear it later.
337		#
338		if { $i == $eindex } {
339			set masterenv [lindex $e 0]
340		} else {
341			lappend clrlist [lindex $e 1]
342		}
343		incr i
344	}
345	#
346	# Move this env's LSN ahead.
347	#
348	set niter 10
349	eval rep_test $method $masterenv NULL $niter 0 0 0 0 $largs
350
351	foreach cl $clrlist {
352		replclear $cl
353	}
354	#
355	# Now close this env and reopen it as a client.
356	#
357	error_check_good newmaster_close [$masterenv close] 0
358	set newclenv [eval $env_cmd]
359	error_check_good cl [is_valid_env $newclenv] TRUE
360	set newenv "$newclenv [expr $eindex + 2]"
361	set elist [lreplace $elist $eindex $eindex $newenv]
362	process_msgs $elist
363}
364