1# See the file LICENSE for redistribution information.
2#
3# Copyright (c) 2001,2008 Oracle.  All rights reserved.
4#
5# $Id: rep079.tcl,v 1.10 2008/04/30 19:12:50 carol Exp $
6#
7# TEST  rep079
8# TEST	Replication leases and invalid usage.
9# TEST
10# TEST	Open a client without leases.  Attempt to set leases after rep_start.
11# TEST	Attempt to declare as master without election.
12# TEST	Run an election with an nsites parameter value.
13# TEST	Elect a master with leases.  Put some data and send to clients.
14# TEST	Cleanly shutdown master env.  Restart without
15# TEST	recovery and verify leases are expired and refreshed.
16# TEST	Add a new client without leases to a group using leases.
17#
18proc rep079 { method { tnum "079" } args } {
19	source ./include.tcl
20
21	if { $is_windows9x_test == 1 } {
22		puts "Skipping replication test on Win9x platform."
23		return
24	}
25
26	# Valid for all access methods, but there is no difference
27	# running it with one method over any other.  Just use btree.
28	if { $checking_valid_methods } {
29		set test_methods { btree }
30		return $test_methods
31	}
32	if { [is_btree $method] == 0 } {
33		puts "Rep$tnum: Skipping for method $method."
34		return
35	}
36
37	set args [convert_args $method $args]
38	set logsets [create_logsets 4]
39
40	foreach l $logsets {
41		#
42        	# Skip the case where the master is in-memory and at least
43        	# one of the clients is on-disk.  If the master is in-memory,
44        	# the wrong site gets elected because on-disk envs write a log
45        	# record when they create the env and in-memory ones do not
46		# and the test wants to control which env gets elected.
47		#
48		set master_logs [lindex $l 0]
49		if { $master_logs == "in-memory" } {
50			set client_logs [lsearch -exact $l "on-disk"]
51			if { $client_logs != -1 } {
52				puts "Skipping for in-memory master\
53				    with on-disk client."
54				continue
55			}
56		}
57		puts "Rep$tnum: Replication leases and invalid usage."
58		puts "Rep$tnum: Master logs are [lindex $l 0]"
59		puts "Rep$tnum: Client logs are [lindex $l 1]"
60		puts "Rep$tnum: Client 2 logs are [lindex $l 2]"
61		puts "Rep$tnum: Client 3 logs are [lindex $l 3]"
62		rep079_sub $method $tnum $l $args
63	}
64}
65
66proc rep079_sub { method tnum logset largs } {
67	global testdir
68	global rep_verbose
69	global verbose_type
70
71	set verbargs ""
72	if { $rep_verbose == 1 } {
73		set verbargs " -verbose {$verbose_type on} "
74	}
75
76	env_cleanup $testdir
77
78	set qdir $testdir/MSGQUEUEDIR
79	replsetup $qdir
80
81	set masterdir $testdir/MASTERDIR
82	set clientdir $testdir/CLIENTDIR
83	set clientdir2 $testdir/CLIENTDIR2
84	set clientdir3 $testdir/CLIENTDIR3
85
86	file mkdir $masterdir
87	file mkdir $clientdir
88	file mkdir $clientdir2
89	file mkdir $clientdir3
90
91	set m_logtype [lindex $logset 0]
92	set c_logtype [lindex $logset 1]
93	set c2_logtype [lindex $logset 2]
94	set c3_logtype [lindex $logset 3]
95
96	# In-memory logs cannot be used with -txn nosync.
97	set m_logargs [adjust_logargs $m_logtype]
98	set c_logargs [adjust_logargs $c_logtype]
99	set c2_logargs [adjust_logargs $c2_logtype]
100	set c3_logargs [adjust_logargs $c3_logtype]
101	set m_txnargs [adjust_txnargs $m_logtype]
102	set c_txnargs [adjust_txnargs $c_logtype]
103	set c2_txnargs [adjust_txnargs $c2_logtype]
104	set c3_txnargs [adjust_txnargs $c3_logtype]
105
106	# Set leases for 4 sites, 1 second timeout, 1% clock skew
107	# [NOTE: We are not adding in client3 until later so don't
108	# set it in nvotes.]
109	set nsites 4
110	set nvotes 3
111	set lease_to 1000000
112	set lease_tosec [expr $lease_to / 1000000]
113	set clock_fast 101
114	set clock_slow 100
115
116	repladd 2
117	#
118	# Use a command without setting errpfx, errfile or verbose
119	# so that error messages can be caught correctly.
120	#
121	set envcmd_err "berkdb_env_noerr -create $m_txnargs $m_logargs \
122	    -home $masterdir -rep_transport \[list 2 replsend\]"
123
124	#
125	# This is the real env command, but we won't use it
126	# quite yet.
127	set envcmd(0) "berkdb_env -create $m_txnargs $m_logargs \
128	    $verbargs -errpfx MASTER -home $masterdir \
129	    -event rep_event \
130	    -rep_transport \[list 2 replsend\]"
131
132	#
133	# Leases must be configured before rep_start is called.
134	# Open a repl env without leases.  Try to configure leases
135	# after the open has already called rep_start.  Open as a client.
136	#
137	puts "\tRep$tnum.a: Try to configure leases after rep_start."
138	set noleaseenv [eval $envcmd_err -rep_client]
139	set stat [catch {$noleaseenv rep_lease \
140	    [list $nsites $lease_to $clock_fast $clock_slow]} lease]
141	error_check_bad stat $stat 0
142	error_check_good menverror [is_substr $lease "must be called before"] 1
143	error_check_good close [$noleaseenv close] 0
144	env_cleanup $masterdir
145
146	#
147	# If leases are being used, elections must be used.  A site
148	# cannot simply upgrade itself to master.  Test that we cannot
149	# open as a client and then upgrade ourself to a master just
150	# by calling rep_start.
151	#
152	set upgenv [eval $envcmd_err -rep_client \
153	    -rep_lease \[list $nsites $lease_to $clock_fast $clock_slow\]]
154	puts "\tRep$tnum.b: Try to upgrade a client without election."
155        set stat [catch {$upgenv rep_start -master} ret]
156	error_check_bad upg_stat $stat 0
157	error_check_good upg_str [is_substr $ret "Cannot become master"] 1
158	error_check_good close [$upgenv close] 0
159	env_cleanup $masterdir
160
161	#
162	# Now test inconsistencies dealing with having a group that
163	# is using lease up and running.  For instance, if leases are
164	# configured, the 'nsites' arg to rep_elect must be 0, etc.
165	#
166	# Open the master.  Must open as a client and get elected.
167	#
168	set err_cmd(0) "none"
169	set crash(0) 0
170	set pri(0) 100
171	set masterenv [eval $envcmd(0) -rep_client \
172	    -rep_lease \[list $nsites $lease_to $clock_fast $clock_slow\]]
173	error_check_good master_env [is_valid_env $masterenv] TRUE
174
175	# Open two clients.
176	repladd 3
177	set err_cmd(1) "none"
178	set crash(1) 0
179	set pri(1) 10
180	set envcmd(1) "berkdb_env -create $c_txnargs $c_logargs \
181	    $verbargs -errpfx CLIENT -home $clientdir \
182	    -event rep_event \
183	    -rep_lease \[list $nsites $lease_to $clock_fast $clock_slow\] \
184	    -rep_client -rep_transport \[list 3 replsend\]"
185	set clientenv [eval $envcmd(1)]
186	error_check_good client_env [is_valid_env $clientenv] TRUE
187
188	repladd 4
189	set err_cmd(2) "none"
190	set crash(2) 0
191	set pri(2) 10
192	set envcmd(2) "berkdb_env_noerr -create $c2_txnargs $c2_logargs \
193	    -home $clientdir2 -event rep_event \
194	    -rep_lease \[list $nsites $lease_to $clock_fast $clock_slow\] \
195	    -rep_client -rep_transport \[list 4 replsend\]"
196	set clientenv2 [eval $envcmd(2)]
197	error_check_good client_env [is_valid_env $clientenv2] TRUE
198
199	# Bring the clients online by processing the startup messages.
200	set envlist "{$masterenv 2} {$clientenv 3} {$clientenv2 4}"
201	process_msgs $envlist
202
203	#
204	# Send a non-zero nsites value for an election.  That is an error.
205	#
206	puts "\tRep$tnum.c: Try to run election with leases and nsites value."
207	#
208	# !!! We have not set -errpfx or -errfile in envcmd(2) above
209	# otherwise the error output won't be set in 'ret' below and
210	# the test will fail.  Set it after this piece of the test.
211	#
212	set timeout 5000000
213	set res [catch {$clientenv2 rep_elect $nsites $nvotes $pri(2) \
214	    $timeout} ret]
215	error_check_bad catch $res 0
216	error_check_good ret [is_substr $ret "nsites must be zero"] 1
217
218	#
219	# Now we can set verbose args, errpfx, etc.  Set it in the
220	# command (for elections) and also manually add it to the
221	# current env handle.
222	#
223	set envcmd(2) "$envcmd(2) $verbargs -errpfx CLIENT2"
224	if { $rep_verbose == 1 } {
225		$clientenv2 verbose $verbose_type on
226		$clientenv2 errpfx CLIENT2
227	}
228
229	#
230	# This next section will test that a replicated env that is master
231	# can cleanly close and then reopen without recovery and retain
232	# its master status.
233	#
234	set msg "Rep$tnum.d"
235	set nvotes [expr $nsites - 1]
236	set winner 0
237	setpriority pri $nsites $winner
238	set elector [berkdb random_int 0 2]
239	puts "\tRep$tnum.d: Run election for real to get master."
240	#
241	# Run election for real.  Set nsites to 0 for this command.
242	#
243	repladd 5
244	set err_cmd(3) "none"
245	set crash(3) 0
246	set pri(3) 0
247	run_election envcmd envlist err_cmd pri crash $qdir $msg \
248	    $elector 0 $nvotes $nsites $winner 0 NULL
249
250	puts "\tRep$tnum.e: Write a checkpoint."
251	#
252	# Writing a checkpoint forces a PERM record which will cause
253	# the clients to grant us their leases.  Then, while holding
254	# the lease grants we can do the next part of the test to
255	# close and cleanly reopen while holding leases.
256	$masterenv txn_checkpoint -force
257
258	process_msgs $envlist
259
260	puts "\tRep$tnum.f.0: Close master env."
261	error_check_good mclose [$masterenv close] 0
262	set sleep [expr $lease_tosec + 1]
263	puts "\tRep$tnum.f.1: Sleep $sleep secs to expire lease grants."
264	tclsleep $sleep
265	#
266	# We should be able to reopen the master env without running
267	# recovery and still retain our mastership.
268	set masterenv [eval $envcmd(0) -rep_master \
269	    -rep_lease \[list $nsites $lease_to $clock_fast $clock_slow\]]
270	error_check_good master_env [is_valid_env $masterenv] TRUE
271	set envlist "{$masterenv 2} {$clientenv 3} {$clientenv2 4}"
272
273	#
274	# Verify that if a non-lease site tries to join a group that
275	# is using leases, it gets an error.  Configuring leases
276	# must be all-or-none across all group members.
277	#
278	puts "\tRep$tnum.g: Add client3 that does not configure leases."
279	replclear 5
280	set envcmd(3) "berkdb_env_noerr -create $c3_txnargs $c3_logargs \
281	    -home $clientdir3 -event rep_event \
282	    $verbargs -errpfx CLIENT3 \
283	    -rep_client -rep_transport \[list 5 replsend\]"
284	set clientenv3 [eval $envcmd(3)]
285	error_check_good client_env [is_valid_env $clientenv3] TRUE
286
287	# Bring the clients online by processing the startup messages.
288	set origlist $envlist
289	set envlist "{$masterenv 2} {$clientenv 3} \
290	    {$clientenv2 4} {$clientenv3 5}"
291	process_msgs $envlist 0 NONE err
292
293	puts "\tRep$tnum.g.1: Verify client fatal error."
294	error_check_good process_msgs_err [is_substr $err DB_RUNRECOVERY] 1
295	#
296	# Close to reclaim Tcl resources, but we want to catch/ignore
297	# the continuing DB_RUNRECOVERY error.
298	#
299	catch {$clientenv3 close} ret
300	set envlist $origlist
301
302	puts "\tRep$tnum.h: Check expired lease error on txn commit."
303	#
304	# Leases are already expired, so attempt to commit should fail.
305	# (And this will be the 'before we commit' check that returns
306	# an error, not the 'after' check that panics).
307	#
308	set txn [$masterenv txn]
309	set stat [catch {$txn commit} ret]
310	error_check_good stat $stat 1
311	error_check_good exp [is_substr $ret REP_LEASE_EXPIRED] 1
312
313	error_check_good mclose [$masterenv close] 0
314	error_check_good cclose [$clientenv close] 0
315	error_check_good c2close [$clientenv2 close] 0
316	replclose $testdir/MSGQUEUEDIR
317}
318