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