1# See the file LICENSE for redistribution information.
2#
3# Copyright (c) 2005,2008 Oracle.  All rights reserved.
4#
5# $Id: rep044.tcl,v 12.16 2008/01/08 20:58:53 bostic Exp $
6#
7# TEST	rep044
8# TEST
9# TEST	Test rollbacks with open file ids.
10# TEST
11# TEST	We have one master with two handles and one client.
12# TEST	Each time through the main loop, we open a db, write
13# TEST	to the db, and close the db.  Each one of these actions
14# TEST	is propagated to the client, or a roll back is forced
15# TEST	by swapping masters.
16
17proc rep044 { method { tnum "044" } args } {
18
19	source ./include.tcl
20	if { $is_windows9x_test == 1 } {
21		puts "Skipping replication test on Win 9x platform."
22		return
23	}
24
25	# Valid for all access methods.
26	if { $checking_valid_methods } {
27		return "ALL"
28	}
29
30	set args [convert_args $method $args]
31	set logsets [create_logsets 2]
32
33	# HP-UX can't open two handles on the same env, so it
34	# can't run this test.
35	if { $is_hp_test == 1 } {
36		puts "Skipping rep$tnum for HP-UX."
37		return
38	}
39
40	foreach l $logsets {
41		set logindex [lsearch -exact $l "in-memory"]
42		puts "Rep$tnum ($method): Replication with rollbacks\
43		    and open file ids."
44		puts "Rep$tnum: Master logs are [lindex $l 0]"
45		puts "Rep$tnum: Client 0 logs are [lindex $l 1]"
46		rep044_sub $method $tnum $l $args
47	}
48}
49
50proc rep044_sub { method tnum logset largs } {
51	source ./include.tcl
52	set orig_tdir $testdir
53
54	global rep_verbose
55	global verbose_type
56
57	set verbargs ""
58	if { $rep_verbose == 1 } {
59		set verbargs " -verbose {$verbose_type on} "
60	}
61
62	set masterdir $testdir/ENV0
63	set clientdir $testdir/ENV1
64
65	set m_logtype [lindex $logset 0]
66	set c_logtype [lindex $logset 1]
67
68	# In-memory logs require a large log buffer, and cannot
69	# be used with -txn nosync.
70	set m_logargs [adjust_logargs $m_logtype]
71	set c_logargs [adjust_logargs $c_logtype]
72	set m_txnargs [adjust_txnargs $m_logtype]
73	set c_txnargs [adjust_txnargs $c_logtype]
74
75	set niter 20
76	set omethod [convert_method $method]
77
78	# The main loop runs all the permutations of processing/not
79	# processing the database open to the clients; processing/not
80	# processing the database writes to the clients; and processing/
81	# not processing the database close to the clients.  Set up the
82	# options in advance so the loop is not heavily indented.
83	#
84	# Each entry displays { open write close }.
85	# For example { 1 1 0 } means we process messages after the
86	# db open and the db writes but not after the db close.
87
88	set optionsets {
89		{1 1 1}
90		{1 1 0}
91		{1 0 1}
92		{1 0 0}
93		{0 1 1}
94		{0 1 0}
95		{0 0 1}
96		{0 0 0}
97	}
98
99	# Main loop.
100	foreach set $optionsets {
101
102		env_cleanup $testdir
103		replsetup $testdir/MSGQUEUEDIR
104		file mkdir $masterdir
105		file mkdir $clientdir
106
107		set processopens [lindex $set 0]
108		set processwrites [lindex $set 1]
109		set processcloses [lindex $set 2]
110
111		set notdoing {}
112		if { $processopens == 0 } {
113			append notdoing " OPENS"
114		}
115		if { $processwrites == 0 } {
116			append notdoing " WRITES"
117		}
118		if { $processcloses == 0 } {
119			append notdoing " CLOSES"
120		}
121		if { $notdoing != {} } {
122			puts "Rep$tnum:\
123			    Loop with $notdoing not processed to client."
124		}
125
126		# Open a master.
127		repladd 1
128		set envcmd(M0) "berkdb_env_noerr -create $m_txnargs \
129		    $m_logargs -lock_detect default \
130		    -errpfx ENV.M0 $verbargs \
131		    -home $masterdir -rep_transport \[list 1 replsend\]"
132		set menv0 [eval $envcmd(M0) -rep_master]
133
134		# Open second handle on master env.
135		set envcmd(M1) "berkdb_env_noerr $m_txnargs \
136		    $m_logargs -lock_detect default \
137		    -errpfx ENV.M1 $verbargs \
138		    -home $masterdir -rep_transport \[list 1 replsend\]"
139		set menv1 [eval $envcmd(M1)]
140		error_check_good rep_start [$menv1 rep_start -master] 0
141
142		# Open a client
143		repladd 2
144		set envcmd(C) "berkdb_env_noerr -create $c_txnargs \
145		    $c_logargs -errpfx ENV.C $verbargs \
146		    -lock_detect default \
147		    -home $clientdir -rep_transport \[list 2 replsend\]"
148		set cenv [eval $envcmd(C) -rep_client]
149
150		# Bring the client online by processing the startup messages.
151		set envlist "{$menv0 1} {$cenv 2}"
152		process_msgs $envlist
153
154		puts "\tRep$tnum.a: Run rep_test in 1st master env."
155		set start 0
156		eval rep_test $method $menv0 NULL $niter $start $start 0 0 $largs
157		incr start $niter
158		process_msgs $envlist
159
160		puts "\tRep$tnum.b: Open db in 2nd master env."
161		# Open the db here; we want it to remain open after rep_test.
162		set db1 [eval {berkdb_open_noerr -env $menv1 -auto_commit \
163		     -mode 0644} $largs $omethod test.db]
164		error_check_good dbopen [is_valid_db $db1] TRUE
165
166		if { $processopens == 1 } {
167			puts "\tRep$tnum.b1:\
168			    Process db open messages to client."
169			process_msgs $envlist
170		} else {
171			set start [do_switch $method $niter $start $menv0 $cenv $largs]
172		}
173
174		puts "\tRep$tnum.c: Write to database in 2nd master."
175		# We don't use rep_test here, because sometimes we abort.
176		for { set i 1 } { $i <= $niter } { incr i } {
177			set t [$menv1 txn]
178			set key $i
179			set str STRING.$i
180			if [catch {eval {$db1 put}\
181			    -txn $t {$key [chop_data $method $str]}} result] {
182				# If handle is dead, abort txn, then
183				# close and reopen db.
184				error_check_good handle_dead \
185				    [is_substr $result HANDLE_DEAD] 1
186				error_check_good txn_abort [$t abort] 0
187				error_check_good close_handle [$db1 close] 0
188				set db1 [eval {berkdb_open_noerr \
189				    -env $menv1 -auto_commit -mode 0644}\
190				    $largs $omethod test.db]
191			} else {
192				error_check_good txn_commit [$t commit] 0
193			}
194		}
195
196		if { $processwrites == 1 } {
197			puts "\tRep$tnum.c1:\
198			    Process db put messages to client."
199			process_msgs $envlist
200		} else {
201			set start [do_switch $method $niter $start $menv0 $cenv $largs]
202		}
203
204		puts "\tRep$tnum.d: Close database using 2nd master env handle."
205		error_check_good db_close [$db1 close] 0
206
207		if { $processcloses == 1 } {
208			puts "\tRep$tnum.d1:\
209			    Process db close messages to client."
210			process_msgs $envlist
211		} else {
212			set start [do_switch $method $niter $start $menv0 $cenv $largs]
213		}
214
215		puts "\tRep$tnum.e: Clean up."
216		error_check_good menv0_close [$menv0 close] 0
217		error_check_good menv1_close [$menv1 close] 0
218		error_check_good cenv_close [$cenv close] 0
219
220		replclose $testdir/MSGQUEUEDIR
221	}
222	set testdir $orig_tdir
223	return
224}
225
226proc do_switch { method niter start masterenv clientenv largs } {
227	set envlist "{$masterenv 1} {$clientenv 2}"
228
229	# Downgrade master, upgrade client.
230	error_check_good master_downgrade [$masterenv rep_start -client] 0
231	error_check_good client_upgrade [$clientenv rep_start -master] 0
232	process_msgs $envlist
233
234	# Run rep_test in the new master.
235	eval rep_test $method $clientenv NULL $niter $start $start 0 0 $largs
236	incr start $niter
237	process_msgs $envlist
238
239	# Downgrade newmaster, upgrade original master.
240	error_check_good client_downgrade [$clientenv rep_start -client] 0
241	error_check_good master_upgrade [$masterenv rep_start -master] 0
242
243	# Run rep_test in the restored master.
244	eval rep_test $method $masterenv NULL $niter $start $start 0 0 $largs
245	incr start $niter
246	process_msgs $envlist
247
248	return $start
249}
250