1# See the file LICENSE for redistribution information.
2#
3# Copyright (c) 2004,2008 Oracle.  All rights reserved.
4#
5# $Id: rep025.tcl,v 12.20 2008/01/08 20:58:53 bostic Exp $
6#
7# TEST  rep025
8# TEST  Test of DB_REP_JOIN_FAILURE.
9# TEST
10# TEST  One master, one client.
11# TEST  Generate several log files.
12# TEST  Remove old master log files.
13# TEST  Delete client files and restart client.
14# TEST  Put one more record to the master.  At the next
15# TEST  processing of messages, the client should get JOIN_FAILURE.
16# TEST  Recover with a hot failover.
17#
18proc rep025 { method { niter 200 } { tnum "025" } args } {
19	source ./include.tcl
20
21	# Run for all access methods.
22	if { $checking_valid_methods } {
23		return "ALL"
24	}
25
26	set args [convert_args $method $args]
27
28	# This test needs to set its own pagesize.
29	set pgindex [lsearch -exact $args "-pagesize"]
30	if { $pgindex != -1 } {
31		puts "Rep$tnum: skipping for specific pagesizes"
32		return
33	}
34
35	set logsets [create_logsets 2]
36
37	# Run the body of the test with and without recovery,
38	# and with and without cleaning.  Skip recovery with in-memory
39	# logging - it doesn't make sense.
40	foreach r $test_recopts {
41		foreach l $logsets {
42			set logindex [lsearch -exact $l "in-memory"]
43			if { $r == "-recover" && $logindex != -1 } {
44				puts "Skipping rep$tnum for -recover\
45				    with in-memory logs."
46				continue
47			}
48			puts "Rep$tnum ($method $r):\
49			    Test of manual initialization and join failure."
50			puts "Rep$tnum: Master logs are [lindex $l 0]"
51			puts "Rep$tnum: Client logs are [lindex $l 1]"
52			rep025_sub $method $niter $tnum $l $r $args
53		}
54	}
55}
56
57proc rep025_sub { method niter tnum logset recargs largs } {
58	global testdir
59	global util_path
60	global rep_verbose
61	global verbose_type
62
63	set verbargs ""
64	if { $rep_verbose == 1 } {
65		set verbargs " -verbose {$verbose_type on} "
66	}
67
68	env_cleanup $testdir
69
70	replsetup $testdir/MSGQUEUEDIR
71
72	set masterdir $testdir/MASTERDIR
73	set clientdir $testdir/CLIENTDIR
74
75	file mkdir $masterdir
76	file mkdir $clientdir
77
78	# Log size is small so we quickly create more than one.
79	# The documentation says that the log file must be at least
80	# four times the size of the in-memory log buffer.
81	set pagesize 4096
82	append largs " -pagesize $pagesize "
83	set log_max [expr $pagesize * 8]
84
85	set m_logtype [lindex $logset 0]
86	set c_logtype [lindex $logset 1]
87
88	# In-memory logs cannot be used with -txn nosync.
89	set m_logargs [adjust_logargs $m_logtype]
90	set c_logargs [adjust_logargs $c_logtype]
91	set m_txnargs [adjust_txnargs $m_logtype]
92	set c_txnargs [adjust_txnargs $c_logtype]
93
94	# Open a master.
95	repladd 1
96	set ma_envcmd "berkdb_env_noerr -create $m_txnargs \
97	    $m_logargs -log_max $log_max $verbargs -errpfx MASTER \
98	    -home $masterdir -rep_transport \[list 1 replsend\]"
99	set masterenv [eval $ma_envcmd $recargs -rep_master]
100
101	# Open a client
102	repladd 2
103	set cl_envcmd "berkdb_env_noerr -create $c_txnargs \
104	    $c_logargs -log_max $log_max $verbargs -errpfx CLIENT \
105	    -home $clientdir -rep_transport \[list 2 replsend\]"
106	set clientenv [eval $cl_envcmd $recargs -rep_client]
107
108	# Bring the clients online by processing the startup messages.
109	set envlist "{$masterenv 1} {$clientenv 2}"
110	process_msgs $envlist
111
112	# Clobber replication's 30-second anti-archive timer, which will have
113	# been started by client sync-up internal init, so that we can do a
114	# log_archive in a moment.
115	#
116	$masterenv test force noarchive_timeout
117
118	# Run a modified test001 in the master (and update client).
119	puts "\tRep$tnum.a: Running rep_test in replicated env."
120	set start 0
121	eval rep_test $method $masterenv NULL $niter $start $start 0 0 $largs
122	incr start $niter
123	process_msgs $envlist
124
125	# Find out what exists on the client.  We need to loop until
126	# the first master log file > last client log file.
127	puts "\tRep$tnum.b: Close client."
128	if { $c_logtype != "in-memory" } {
129		set res [eval exec $util_path/db_archive -l -h $clientdir]
130	}
131	set last_client_log [get_logfile $clientenv last]
132	error_check_good client_close [$clientenv close] 0
133
134	set stop 0
135	while { $stop == 0 } {
136		# Run rep_test in the master (don't update client).
137		puts "\tRep$tnum.c: Running rep_test in replicated env."
138	 	eval rep_test \
139		    $method $masterenv NULL $niter $start $start 0 0 $largs
140		incr start $niter
141		replclear 2
142
143		puts "\tRep$tnum.d: Run db_archive on master."
144		if { $m_logtype != "in-memory"} {
145			set res [eval exec $util_path/db_archive -d -h $masterdir]
146		}
147		set first_master_log [get_logfile $masterenv first]
148		if { $first_master_log > $last_client_log } {
149			set stop 1
150		}
151	}
152
153	puts "\tRep$tnum.e: Clean client and reopen."
154	env_cleanup $clientdir
155	set clientenv [eval $cl_envcmd $recargs -rep_client]
156	error_check_good client_env [is_valid_env $clientenv] TRUE
157	set envlist "{$masterenv 1} {$clientenv 2}"
158
159	# Set initialization to manual.
160	$clientenv rep_config {noautoinit on}
161	process_msgs $envlist 0 NONE err
162	error_check_good error_on_right_env [lindex $err 0] $clientenv
163	error_check_good right_error [is_substr $err DB_REP_JOIN_FAILURE] 1
164
165	# Add records to the master and update client.
166	puts "\tRep$tnum.f: Update master; client should return error."
167	set entries 100
168	eval rep_test $method $masterenv NULL $entries $start $start 0 0 $largs
169	incr start $entries
170	process_msgs $envlist 0 NONE err
171	error_check_good error_on_right_env [lindex $err 0] $clientenv
172	error_check_good right_error [is_substr $err DB_REP_JOIN_FAILURE] 1
173
174	# If the master logs are on-disk, copy from master to client and restart
175	# with recovery.  If the logs are in-memory, we'll have to re-enable
176	# internal initialization and restart the client.
177	if { $m_logtype == "on-disk" } {
178		puts "\tRep$tnum.g: Hot failover and catastrophic recovery."
179		error_check_good client_close [$clientenv close] 0
180		env_cleanup $clientdir
181		set files [glob $masterdir/log.* $masterdir/*.db]
182		foreach f $files {
183			set filename [file tail $f]
184			file copy -force $f $clientdir/$filename
185		}
186		set clientenv [eval $cl_envcmd -recover_fatal -rep_client]
187	} else {
188		puts "\tRep$tnum.g: Restart client forcing internal init."
189		set clientenv [eval $cl_envcmd -rep_client]
190		$clientenv rep_config {noautoinit off}
191	}
192	error_check_good client_env [is_valid_env $clientenv] TRUE
193	set envlist "{$masterenv 1} {$clientenv 2}"
194	process_msgs $envlist 0 NONE err
195	error_check_good no_errors1 $err 0
196
197	# Adding another entry should not flush out an error.
198	eval rep_test $method $masterenv NULL $entries $start $start 0 0 $largs
199	process_msgs $envlist 0 NONE err
200	error_check_good no_errors2 $err 0
201
202	error_check_good masterenv_close [$masterenv close] 0
203	error_check_good clientenv_close [$clientenv close] 0
204	replclose $testdir/MSGQUEUEDIR
205}
206