1# See the file LICENSE for redistribution information.
2#
3# Copyright (c) 2004,2008 Oracle.  All rights reserved.
4#
5# $Id: rep061.tcl,v 1.14 2008/01/08 20:58:53 bostic Exp $
6#
7# TEST	rep061
8# TEST	Test of internal initialization multiple files and pagesizes
9# TEST	with page gaps.
10# TEST
11# TEST	One master, one client.
12# TEST	Generate several log files.
13# TEST	Remove old master log files.
14# TEST	Delete client files and restart client.
15# TEST	Put one more record to the master.
16# TEST  Force some page messages to get dropped.
17#
18proc rep061 { method { niter 500 } { tnum "061" } args } {
19
20	source ./include.tcl
21	if { $is_windows9x_test == 1 } {
22		puts "Skipping replication test on Win 9x platform."
23		return
24	}
25
26	# Run for btree and queue only.
27	if { $checking_valid_methods } {
28		set test_methods {}
29		foreach method $valid_methods {
30			if { [is_btree $method] == 1 || [is_queue $method] == 1 } {
31				lappend test_methods $method
32			}
33		}
34		return $test_methods
35	}
36	if { [is_btree $method] != 1 && [is_queue $method] != 1 } {
37		puts "Skipping rep061 for method $method."
38		return
39	}
40	set args [convert_args $method $args]
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 logsets [create_logsets 2]
50
51	# Run the body of the test with and without recovery,
52	# and with and without cleaning.
53	set opts { noclean clean bulk }
54	# Try varying drop percentages.
55	set dpct { 10 5 }
56	foreach r $test_recopts {
57		foreach c $opts {
58			foreach l $logsets {
59				foreach d $dpct {
60					set logindex [lsearch -exact $l \
61					    "in-memory"]
62					if { $r == "-recover" && \
63					    $logindex != -1 } {
64						puts "Skipping rep$tnum \
65						    for -recover\
66						    with in-memory logs."
67						continue
68					}
69					puts "Rep$tnum ($method $r $c):\
70					    Internal initialization - with\
71					    $d pct page gaps."
72					puts "Rep$tnum: Master logs are \
73					    [lindex $l 0]"
74					puts "Rep$tnum: Client logs are \
75					    [lindex $l 1]"
76					rep061_sub $method $niter $tnum \
77					    $l $r $c $d $args
78				}
79			}
80		}
81	}
82}
83
84proc rep061_sub { method niter tnum logset recargs opts dpct largs } {
85	global testdir
86	global util_path
87	global drop drop_msg
88	global startup_done
89	global rep_verbose
90	global verbose_type
91
92	set verbargs ""
93	if { $rep_verbose == 1 } {
94		set verbargs " -verbose {$verbose_type on} "
95	}
96
97	env_cleanup $testdir
98
99	replsetup $testdir/MSGQUEUEDIR
100
101	set masterdir $testdir/MASTERDIR
102	set clientdir $testdir/CLIENTDIR
103
104	file mkdir $masterdir
105	file mkdir $clientdir
106
107	# Log size is small so we quickly create more than one.
108	# The documentation says that the log file must be at least
109	# four times the size of the in-memory log buffer.
110	set maxpg 16384
111	set log_max [expr $maxpg * 8]
112	set cache [expr $maxpg * 32 ]
113
114	set m_logtype [lindex $logset 0]
115	set c_logtype [lindex $logset 1]
116
117	# In-memory logs cannot be used with -txn nosync.
118	set m_txnargs [adjust_txnargs $m_logtype]
119	set c_txnargs [adjust_txnargs $c_logtype]
120
121	# Open a master.
122	repladd 1
123	set ma_envcmd "berkdb_env_noerr -create $m_txnargs $verbargs \
124	    -log_max $log_max -cachesize { 0 $cache 1 } -errpfx MASTER \
125	    -home $masterdir -rep_transport \[list 1 replsend\]"
126	set masterenv [eval $ma_envcmd $recargs -rep_master]
127
128	# Open a client
129	repladd 2
130	set cl_envcmd "berkdb_env_noerr -create $c_txnargs $verbargs \
131	    -log_max $log_max -cachesize { 0 $cache 1 } -errpfx CLIENT \
132	    -home $clientdir -rep_transport \[list 2 replsend\]"
133	set clientenv [eval $cl_envcmd $recargs -rep_client]
134
135	#
136	# Since we're dropping messages, set the rerequest values
137	# lower so we don't wait too long to request what we're
138	# missing.
139	#
140	#
141	# Set to 200/800 usecs.  An average ping to localhost should
142	# be a few 10s usecs.
143	#
144	$clientenv rep_request 200 800
145	# Bring the clients online by processing the startup messages.
146	set envlist "{$masterenv 1} {$clientenv 2}"
147	process_msgs $envlist
148
149	# Clobber replication's 30-second anti-archive timer, which will have
150	# been started by client sync-up internal init, so that we can do a
151	# log_archive in a moment.
152	#
153	$masterenv test force noarchive_timeout
154
155	#
156	# Note that by setting these 2 globals below, message dropping
157	# is automatically enabled.  By setting 'drop' to 0, further
158	# down in the test, we disable message dropping.
159	#
160	set drop 1
161	set drop_msg [expr 100 / $dpct]
162
163	# Run rep_test in the master (and update client).
164	set startpgsz 512
165	set pglist ""
166	for { set pgsz $startpgsz } { $pgsz <= $maxpg } \
167	    { set pgsz [expr $pgsz * 2] } {
168		lappend pglist $pgsz
169	}
170	set nfiles [llength $pglist]
171	puts "\tRep$tnum.a.0: Running rep_test $nfiles times in replicated env."
172	set dbopen ""
173	for { set i 0 } { $i < $nfiles } { incr i } {
174		set mult [expr $i * 10]
175		set nentries [expr $niter + $mult]
176		set pagesize [lindex $pglist $i]
177		set largs " -pagesize $pagesize "
178		eval rep_test $method $masterenv NULL $nentries $mult $mult \
179		    0 0 $largs
180		process_msgs $envlist
181
182		#
183		# Everytime we run 'rep_test' we create 'test.db'.  So
184		# rename it each time through the loop.
185		#
186		set old "test.db"
187		set new "test.$i.db"
188		error_check_good rename [$masterenv dbrename \
189		    -auto_commit $old $new] 0
190		process_msgs $envlist
191		#
192		# We want to keep some databases open so that we test the
193		# code finding the files in the data dir as well as finding
194		# them in dbreg list.
195		#
196		if { [expr $i % 2 ] == 0 } {
197			set db [berkdb_open_noerr -env $masterenv $new]
198			error_check_good dbopen.$i [is_valid_db $db] TRUE
199			lappend dbopen $db
200		}
201	}
202	#
203	# Set up a few special databases too.  We want one with a subdatabase
204	# and we want an empty database.
205	#
206	set testfile "test.db"
207	if { [is_queue $method] } {
208		set sub ""
209	} else {
210		set sub "subdb"
211	}
212	set omethod [convert_method $method]
213	set largs " -pagesize $maxpg "
214	set largs [convert_args $method $largs]
215	set emptyfile "empty.db"
216	#
217	# Create/close an empty database.
218	#
219	set db [eval {berkdb_open_noerr -env $masterenv -auto_commit -create \
220	    -mode 0644} $largs $omethod $emptyfile]
221	error_check_good emptydb [is_valid_db $db] TRUE
222	error_check_good empty_close [$db close] 0
223	#
224	# Keep this subdb (regular if queue) database open.
225	# We need it a few times later on.
226	#
227	set db [eval {berkdb_open_noerr -env $masterenv -auto_commit -create \
228	    -mode 0644} $largs $omethod $testfile $sub]
229	error_check_good subdb [is_valid_db $db] TRUE
230	eval rep_test $method $masterenv $db $niter 0 0 0 0 $largs
231	process_msgs $envlist
232
233	puts "\tRep$tnum.b: Close client."
234	error_check_good client_close [$clientenv close] 0
235
236	#
237	# Run rep_test in the master (don't update client).
238	# Need to guarantee that we will change log files during
239	# this run so run with the largest pagesize and double
240	# the number of entries.
241	#
242	puts "\tRep$tnum.c: Running rep_test ( $largs) in replicated env."
243	set nentries [expr $niter * 2]
244	eval rep_test $method $masterenv $db $nentries 0 0 0 0 $largs
245	replclear 2
246
247	puts "\tRep$tnum.d: Run db_archive on master."
248	set res [eval exec $util_path/db_archive -l -h $masterdir]
249	error_check_bad log.1.present [lsearch -exact $res log.0000000001] -1
250	set res [eval exec $util_path/db_archive -d -h $masterdir]
251	set res [eval exec $util_path/db_archive -l -h $masterdir]
252	error_check_good log.1.gone [lsearch -exact $res log.0000000001] -1
253
254	puts "\tRep$tnum.e: Reopen client ($opts)."
255	if { $opts == "clean" } {
256		env_cleanup $clientdir
257	}
258	if { $opts == "bulk" } {
259		error_check_good bulk [$masterenv rep_config {bulk on}] 0
260	}
261
262	set clientenv [eval $cl_envcmd $recargs -rep_client]
263	error_check_good client_env [is_valid_env $clientenv] TRUE
264	#
265	# Since we are dropping frequent messages, we set the
266	# rerequest rate low to make sure the test finishes.
267	#
268	$clientenv rep_request 200 800
269	set envlist "{$masterenv 1} {$clientenv 2}"
270	process_msgs $envlist 0 NONE err
271	set done 0
272	#
273	# We are done with this loop when the client has achieved
274	# startup_done and we've looped one more time after turning
275	# off dropping messages.  Otherwise we might get a few
276	# straggling log records that don't make it over.
277	#
278	# Set a maximum iteration count because some methods can get
279	# into a state where if we're regularly dropping messages we
280	# can never catch up (queue) and we loop forever.
281	#
282	set iter 1
283	set max_drop_iter 200
284	if { $opts == "bulk" } {
285		#
286		# Since bulk is sending several messages at once we need to
287		# loop more times to allow rerequests to get through.
288		#
289		set max_drop_iter [expr $max_drop_iter * 2]
290		$clientenv rep_request 100 400
291	}
292	while { $done == 0 } {
293		puts "\tRep$tnum.e.1.$iter: Trigger log request"
294		#
295		# When we don't clean, starting the client doesn't
296		# trigger any events.  We need to generate some log
297		# records so that the client requests the missing
298		# logs and that will trigger it.
299		#
300		set entries 4
301		eval rep_test $method $masterenv $db $entries $niter 0 0 0 $largs
302		process_msgs $envlist 0 NONE err
303		set stat [exec $util_path/db_stat -N -r -R A -h $clientdir]
304		#
305		# Loop until we are done with the RECOVER_PAGE phase.
306		#
307		set in_page [is_substr $stat "REP_F_RECOVER_PAGE"]
308		if { !$in_page || $iter >= $max_drop_iter } {
309			#
310			# If we're dropping, stop doing so.
311			# If we're not dropping, we're done.
312			#
313			if { $drop != 0 } {
314				set drop 0
315			} else {
316				set done 1
317			}
318		}
319		incr iter
320	}
321	error_check_good subdb_close [$db close] 0
322	#
323	# Stop dropping records, we've sent all the pages.
324	# We need to do that in order to make sure we get
325	# all the log records there and can accurately compare.
326	#
327	set drop 0
328	process_msgs $envlist 0 NONE err
329
330	puts "\tRep$tnum.f: Verify logs and databases"
331	#
332	# If doing bulk testing, turn it off now so that it forces us
333	# to flush anything currently in the bulk buffer.  We need to
334	# do this because rep_test might have aborted a transaction on
335	# its last iteration and those log records would still be in
336	# the bulk buffer causing the log comparison to fail.
337	#
338	if { $opts == "bulk" } {
339		puts "\tRep$tnum.f.1: Turn off bulk transfers."
340		error_check_good bulk [$masterenv rep_config {bulk off}] 0
341		process_msgs $envlist 0 NONE err
342	}
343	rep_verify $masterdir $masterenv $clientdir $clientenv 1
344
345	for { set i 0 } { $i < $nfiles } { incr i } {
346		set dbname "test.$i.db"
347		rep_verify $masterdir $masterenv $clientdir $clientenv \
348		    1 1 0 $dbname
349	}
350
351	#
352	# Close the database held open on master for initialization.
353	#
354	foreach db $dbopen {
355		error_check_good db_close [$db close] 0
356	}
357
358	# Add records to the master and update client.
359	puts "\tRep$tnum.g: Add more records and check again."
360	set entries 10
361	set db [eval {berkdb_open_noerr -env $masterenv -auto_commit \
362	    -mode 0644} $largs $omethod $testfile $sub]
363	error_check_good subdb [is_valid_db $db] TRUE
364	eval rep_test $method $masterenv $db $entries $niter 0 0 0 $largs
365	error_check_good subdb_close [$db close] 0
366	process_msgs $envlist 0 NONE err
367
368	rep_verify $masterdir $masterenv $clientdir $clientenv 1
369	for { set i 0 } { $i < $nfiles } { incr i } {
370		set dbname "test.$i.db"
371		rep_verify $masterdir $masterenv $clientdir $clientenv \
372		    1 1 0 $dbname
373	}
374	set bulkxfer [stat_field $masterenv rep_stat "Bulk buffer transfers"]
375	if { $opts == "bulk" } {
376		error_check_bad bulkxferon $bulkxfer 0
377	} else {
378		error_check_good bulkxferoff $bulkxfer 0
379	}
380
381	error_check_good masterenv_close [$masterenv close] 0
382	error_check_good clientenv_close [$clientenv close] 0
383	replclose $testdir/MSGQUEUEDIR
384}
385