1# See the file LICENSE for redistribution information.
2#
3# Copyright (c) 2004-2009 Oracle.  All rights reserved.
4#
5# $Id$
6#
7# TEST	rep031
8# TEST	Test of internal initialization and blocked operations.
9# TEST
10# TEST	One master, one client.
11# TEST	Put one more record to the master.
12# TEST  Test that internal initialization blocks:
13# TEST  log_archive, rename, remove, fileid_reset, lsn_reset.
14# TEST	Sleep 30+ seconds.
15# TEST  Test that blocked operations are now unblocked.
16#
17proc rep031 { method { niter 200 } { tnum "031" } args } {
18
19	source ./include.tcl
20	global databases_in_memory
21	global repfiles_in_memory
22
23	if { $is_windows9x_test == 1 } {
24		puts "Skipping replication test on Win 9x platform."
25		return
26	}
27
28	# There is nothing method-sensitive in this test, so
29	# skip for all except btree.
30	if { $checking_valid_methods } {
31		set test_methods { btree }
32		return $test_methods
33	}
34	if { [is_btree $method] != 1 } {
35		puts "Skipping rep031 for method $method."
36		return
37	}
38
39	set args [convert_args $method $args]
40	set logsets [create_logsets 2]
41
42	# This test needs to set its own pagesize.
43	set pgindex [lsearch -exact $args "-pagesize"]
44        if { $pgindex != -1 } {
45                puts "Rep$tnum: skipping for specific pagesizes"
46                return
47        }
48
49	# Set up for on-disk or in-memory databases.
50	set msg "using on-disk databases"
51	if { $databases_in_memory } {
52		set msg "using named in-memory databases"
53		if { [is_queueext $method] } {
54			puts -nonewline "Skipping rep$tnum for method "
55			puts "$method with named in-memory databases."
56			return
57		}
58	}
59
60	set msg2 "and on-disk replication files"
61	if { $repfiles_in_memory } {
62		set msg2 "and in-memory replication files"
63	}
64
65	# Run the body of the test with and without recovery,
66	# and with and without cleaning.  Skip recovery with in-memory
67	# logging - it doesn't make sense.
68	set cleanopts { clean noclean }
69	foreach r $test_recopts {
70		foreach c $cleanopts {
71			foreach l $logsets {
72				set logindex [lsearch -exact $l "in-memory"]
73				if { $r == "-recover" && $logindex != -1 } {
74					puts "Skipping rep$tnum for -recover\
75					    with in-memory logs."
76					continue
77				}
78				puts "Rep$tnum ($method $r $c $args):\
79				    Test of internal init and blocked\
80				    operations $msg $msg2."
81				puts "Rep$tnum: Master logs are [lindex $l 0]"
82				puts "Rep$tnum: Client logs are [lindex $l 1]"
83				rep031_sub $method $niter $tnum $l $r $c $args
84			}
85		}
86	}
87}
88
89proc rep031_sub { method niter tnum logset recargs clean largs } {
90	source ./include.tcl
91	global databases_in_memory
92	global repfiles_in_memory
93	global rep_verbose
94	global verbose_type
95
96	set verbargs ""
97	if { $rep_verbose == 1 } {
98		set verbargs " -verbose {$verbose_type on} "
99	}
100
101	set repmemargs ""
102	if { $repfiles_in_memory } {
103		set repmemargs "-rep_inmem_files "
104	}
105
106	env_cleanup $testdir
107
108	replsetup $testdir/MSGQUEUEDIR
109
110	set masterdir $testdir/MASTERDIR
111	set clientdir $testdir/CLIENTDIR
112
113	file mkdir $masterdir
114	file mkdir $clientdir
115
116	# Log size is small so we quickly create more than one.
117	# The documentation says that the log file must be at least
118	# four times the size of the in-memory log buffer.
119	set pagesize 4096
120	append largs " -pagesize $pagesize "
121	set log_max [expr $pagesize * 8]
122
123	set m_logtype [lindex $logset 0]
124	set c_logtype [lindex $logset 1]
125
126	# In-memory logs cannot be used with -txn nosync.
127	set m_logargs [adjust_logargs $m_logtype]
128	set c_logargs [adjust_logargs $c_logtype]
129	set m_txnargs [adjust_txnargs $m_logtype]
130	set c_txnargs [adjust_txnargs $c_logtype]
131
132	# Open a master.
133	repladd 1
134	set ma_envcmd "berkdb_env_noerr -create $m_txnargs \
135	    $m_logargs -log_max $log_max $verbargs $repmemargs \
136	    -home $masterdir -rep_transport \[list 1 replsend\]"
137	set masterenv [eval $ma_envcmd $recargs -rep_master]
138
139	# Open a client
140	repladd 2
141	set cl_envcmd "berkdb_env_noerr -create $c_txnargs \
142	    $c_logargs -log_max $log_max $verbargs $repmemargs \
143	    -home $clientdir -rep_transport \[list 2 replsend\]"
144	set clientenv [eval $cl_envcmd $recargs -rep_client]
145
146	# Bring the clients online by processing the startup messages.
147	set envlist "{$masterenv 1} {$clientenv 2}"
148	process_msgs $envlist
149
150	$masterenv test force noarchive_timeout
151
152	# Run rep_test in the master (and update client).
153	puts "\tRep$tnum.a: Running rep_test in replicated env."
154	set start 0
155	eval rep_test $method $masterenv NULL $niter $start $start 0 $largs
156	incr start $niter
157	process_msgs $envlist
158
159	puts "\tRep$tnum.b: Close client."
160	# Find out what exists on the client.  We need to loop until
161	# the first master log file > last client log file.
162	if { $c_logtype != "in-memory" } {
163		set res [eval exec $util_path/db_archive -l -h $clientdir]
164	}
165	set last_client_log [get_logfile $clientenv last]
166	error_check_good client_close [$clientenv close] 0
167
168	set stop 0
169	while { $stop == 0 } {
170		# Run rep_test in the master (don't update client).
171		puts "\tRep$tnum.c: Running rep_test in replicated env."
172	 	eval rep_test \
173		    $method $masterenv NULL $niter $start $start 0 $largs
174		incr start $niter
175		replclear 2
176
177		puts "\tRep$tnum.d: Run db_archive on master."
178		if { $m_logtype != "in-memory"} {
179			set res \
180			    [eval exec $util_path/db_archive -d -h $masterdir]
181		}
182		set first_master_log [get_logfile $masterenv first]
183		if { $first_master_log > $last_client_log } {
184			set stop 1
185		}
186	}
187
188	puts "\tRep$tnum.e: Reopen client ($clean)."
189	if { $clean == "clean" } {
190		env_cleanup $clientdir
191	}
192	set clientenv [eval $cl_envcmd $recargs -rep_client]
193	error_check_good client_env [is_valid_env $clientenv] TRUE
194	set envlist "{$masterenv 1} {$clientenv 2}"
195	process_msgs $envlist 0 NONE err
196	if { $clean == "noclean" } {
197		puts "\tRep$tnum.e.1: Trigger log request"
198		#
199		# When we don't clean, starting the client doesn't
200		# trigger any events.  We need to generate some log
201		# records so that the client requests the missing
202		# logs and that will trigger it.
203		#
204		set entries 10
205		eval rep_test \
206		    $method $masterenv NULL $entries $start $start 0 $largs
207		incr start $entries
208		process_msgs $envlist 0 NONE err
209	}
210
211	#
212	# We have now forced an internal initialization.  Verify it is correct.
213	#
214	puts "\tRep$tnum.f: Verify logs and databases"
215	rep_verify $masterdir $masterenv $clientdir $clientenv 1 1 1
216
217	#
218	# Internal initializations disable certain operations on the master for
219	# 30 seconds after the last init-related message is received
220	# by the master.  Those operations are dbremove, dbrename and
221	# log_archive (with removal).
222	#
223	puts "\tRep$tnum.g: Try to remove and rename the database."
224	set dbname "test.db"
225	set old $dbname
226	set new $dbname.new
227	if { $databases_in_memory } {
228		set stat [catch {$masterenv dbrename -auto_commit "" $old $new} ret]
229	} else {
230		set stat [catch {$masterenv dbrename -auto_commit $old $new} ret]
231	}
232	error_check_good rename_fail $stat 1
233	error_check_good rename_err [is_substr $ret "invalid"] 1
234	if { $databases_in_memory } {
235		set stat [catch {$masterenv dbremove -auto_commit "" $old} ret]
236	} else {
237		set stat [catch {$masterenv dbremove -auto_commit $old} ret]
238	}
239	error_check_good remove_fail $stat 1
240	error_check_good remove_err [is_substr $ret "invalid"] 1
241
242	# The fileid_reset and lsn_reset operations work on physical files
243	# so we do not need to test them for in-memory databases.
244	if { $databases_in_memory != 1 } {
245		puts "\tRep$tnum.h: Try to reset LSNs and fileid on the database."
246		set stat [catch {$masterenv id_reset $old} ret]
247		error_check_good id_reset $stat 1
248		error_check_good id_err [is_substr $ret "invalid"] 1
249		set stat [catch {$masterenv lsn_reset $old} ret]
250		error_check_good lsn_reset $stat 1
251		error_check_good lsn_err [is_substr $ret "invalid"] 1
252	}
253
254	#
255	# Need entries big enough to generate additional log files.
256	# However, db_archive will not return an error, it will
257	# just retain the log file.
258	#
259	puts "\tRep$tnum.i: Run rep_test to generate more logs."
260	set entries 200
261	eval rep_test $method $masterenv NULL $entries $start $start 0 $largs
262	incr start $entries
263	process_msgs $envlist 0 NONE err
264
265	# Test lockout of archiving only in on-disk case.
266	if { $m_logtype != "in-memory" } {
267		puts "\tRep$tnum.j: Try to db_archive."
268		set res [eval exec $util_path/db_archive -l -h $masterdir]
269		set first [lindex $res 0]
270		set res [eval exec $util_path/db_archive -d -h $masterdir]
271		set res [eval exec $util_path/db_archive -l -h $masterdir]
272		error_check_bad log.gone [lsearch -exact $res $first] -1
273
274		puts "\tRep$tnum.j.0: Try to log_archive in master env."
275		set res [$masterenv log_archive -arch_remove]
276		set res [eval exec $util_path/db_archive -l -h $masterdir]
277		error_check_bad log.gone0 [lsearch -exact $res $first] -1
278
279		# We can't open a second handle on the env in HP-UX.
280		if { $is_hp_test != 1 } {
281			puts "\tRep$tnum.j.1: Log_archive in new non-rep env."
282			set newenv [berkdb_env_noerr -txn nosync \
283			    -log_max $log_max -home $masterdir]
284			error_check_good newenv [is_valid_env $newenv] TRUE
285			set res [$newenv log_archive -arch_remove]
286			set res [eval exec \
287			    $util_path/db_archive -l -h $masterdir]
288			error_check_bad \
289			    log.gone1 [lsearch -exact $res $first] -1
290		}
291	}
292
293	# Check that databases are in-memory or on-disk as expected, before
294	# we try to delete the databases!
295	check_db_location $masterenv
296	check_db_location $clientenv
297
298	set timeout 30
299	#
300	# Sleep timeout+2 seconds - The timeout is 30 seconds, but we need
301	# to sleep a bit longer to make sure we cross the timeout.
302	#
303	set to [expr $timeout + 2]
304	puts "\tRep$tnum.k: Wait $to seconds to timeout"
305	tclsleep $to
306	puts "\tRep$tnum.l: Retry blocked operations after wait"
307	if { $databases_in_memory == 1 } {
308		set stat [catch {$masterenv dbrename -auto_commit "" $old $new} ret]
309		error_check_good rename_work $stat 0
310		set stat [catch {$masterenv dbremove -auto_commit "" $new} ret]
311		error_check_good remove_work $stat 0
312	} else {
313		set stat [catch {$masterenv id_reset $old} ret]
314		error_check_good id_reset_work $stat 0
315		set stat [catch {$masterenv lsn_reset $old} ret]
316		error_check_good lsn_reset_work $stat 0
317		set stat [catch {$masterenv dbrename -auto_commit $old $new} ret]
318		error_check_good rename_work $stat 0
319		set stat [catch {$masterenv dbremove -auto_commit $new} ret]
320		error_check_good remove_work $stat 0
321	}
322	process_msgs $envlist 0 NONE err
323
324	if { $m_logtype != "in-memory" } {
325		# Remove files via the 2nd non-rep env, check via db_archive.
326		if { $is_hp_test != 1 } {
327			set res [$newenv log_archive -arch_remove]
328			set res \
329			    [eval exec $util_path/db_archive -l -h $masterdir]
330			error_check_good \
331			    log.gone [lsearch -exact $res $first] -1
332			error_check_good newenv_close [$newenv close] 0
333		} else {
334			set res [$masterenv log_archive -arch_remove]
335			set res \
336			    [eval exec $util_path/db_archive -l -h $masterdir]
337			error_check_good \
338			    log.gone [lsearch -exact $res $first] -1
339		}
340	}
341
342	error_check_good masterenv_close [$masterenv close] 0
343	error_check_good clientenv_close [$clientenv close] 0
344	replclose $testdir/MSGQUEUEDIR
345}
346