1# See the file LICENSE for redistribution information.
2#
3# Copyright (c) 2001,2008 Oracle.  All rights reserved.
4#
5# $Id: rep012.tcl,v 12.16 2008/01/08 20:58:53 bostic Exp $
6#
7# TEST	rep012
8# TEST	Replication and dead DB handles.
9# TEST
10# TEST	Run a modified version of test001 in a replicated master env.
11# TEST	Run in replicated environment with secondary indices too.
12# TEST	Make additional changes to master, but not to the client.
13# TEST	Downgrade the master and upgrade the client with open db handles.
14# TEST	Verify that the roll back on clients gives dead db handles.
15proc rep012 { method { niter 10 } { tnum "012" } args } {
16
17	source ./include.tcl
18	if { $is_windows9x_test == 1 } {
19		puts "Skipping replication test on Win 9x platform."
20		return
21	}
22
23	# Run for all access methods.
24	if { $checking_valid_methods } {
25		return "ALL"
26	}
27
28	set args [convert_args $method $args]
29	set logsets [create_logsets 3]
30
31	# Run the body of the test with and without recovery.
32	foreach r $test_recopts {
33		foreach l $logsets {
34			set logindex [lsearch -exact $l "in-memory"]
35			if { $r == "-recover" && $logindex != -1 } {
36				puts "Rep$tnum: Skipping\
37				    for in-memory logs with -recover."
38				continue
39			}
40			puts "Rep$tnum ($method $r):\
41			    Replication and dead db handles."
42			puts "Rep$tnum: Master logs are [lindex $l 0]"
43			puts "Rep$tnum: Client 0 logs are [lindex $l 1]"
44			puts "Rep$tnum: Client 1 logs are [lindex $l 2]"
45			rep012_sub $method $niter $tnum $l $r $args
46		}
47	}
48}
49
50proc rep012_sub { method niter tnum logset recargs largs } {
51	global testdir
52	global verbose_check_secondaries
53	global rep_verbose
54	global verbose_type
55
56	set verbargs ""
57	if { $rep_verbose == 1 } {
58		set verbargs " -verbose {$verbose_type on} "
59	}
60
61	env_cleanup $testdir
62	set orig_tdir $testdir
63
64	replsetup $testdir/MSGQUEUEDIR
65
66	set masterdir $testdir/MASTERDIR
67	set clientdir $testdir/CLIENTDIR
68	set clientdir2 $testdir/CLIENTDIR.2
69	file mkdir $masterdir
70	file mkdir $clientdir
71	file mkdir $clientdir2
72
73	set m_logtype [lindex $logset 0]
74	set c_logtype [lindex $logset 1]
75	set c2_logtype [lindex $logset 2]
76
77	# In-memory logs require a large log buffer, and cannot
78	# be used with -txn nosync.
79	set m_logargs [adjust_logargs $m_logtype]
80	set c_logargs [adjust_logargs $c_logtype]
81	set c2_logargs [adjust_logargs $c2_logtype]
82	set m_txnargs [adjust_txnargs $m_logtype]
83	set c_txnargs [adjust_txnargs $c_logtype]
84	set c2_txnargs [adjust_txnargs $c2_logtype]
85
86	# Open a master.
87	repladd 1
88	set ma_envcmd "berkdb_env_noerr -create $m_txnargs \
89	    $m_logargs -errpfx ENV0 $verbargs \
90	    -home $masterdir -rep_transport \[list 1 replsend\]"
91	set env0 [eval $ma_envcmd $recargs -rep_master]
92	set masterenv $env0
93
94	# Open two clients
95	repladd 2
96	set cl_envcmd "berkdb_env_noerr -create $c_txnargs \
97	    $c_logargs -errpfx ENV1 $verbargs \
98	    -home $clientdir -rep_transport \[list 2 replsend\]"
99	set env1 [eval $cl_envcmd $recargs -rep_client]
100	set clientenv $env1
101
102	repladd 3
103	set cl2_envcmd "berkdb_env_noerr -create $c2_txnargs \
104	    $c2_logargs -errpfx ENV2 $verbargs \
105	    -home $clientdir2 -rep_transport \[list 3 replsend\]"
106	set cl2env [eval $cl2_envcmd $recargs -rep_client]
107
108	set testfile "test$tnum.db"
109	set pname "primary$tnum.db"
110	set sname "secondary$tnum.db"
111	set omethod [convert_method $method]
112	set env0db [eval {berkdb_open_noerr -env $env0 -auto_commit \
113	    -create -mode 0644} $largs $omethod $testfile]
114	error_check_good dbopen [is_valid_db $env0db] TRUE
115	set masterdb $env0db
116
117	set do_secondary 0
118	if { [is_btree $method] || [is_hash $method] } {
119		set do_secondary 1
120		# Open the primary
121		set mpdb [eval {berkdb_open_noerr -env $env0 -auto_commit \
122		    -create -mode 0644} $largs $omethod $pname]
123		error_check_good dbopen [is_valid_db $mpdb] TRUE
124
125		# Open the secondary
126		# Open a 2nd handle to the same secondary
127		set msdb [eval {berkdb_open_noerr -env $env0 -auto_commit \
128		    -create -mode 0644} $largs $omethod $sname]
129		error_check_good dbopen [is_valid_db $msdb] TRUE
130		error_check_good associate [$mpdb associate \
131		    [callback_n 0] $msdb] 0
132	}
133
134	# Bring the clients online by processing the startup messages.
135	set envlist "{$env0 1} {$env1 2} {$cl2env 3}"
136	process_msgs $envlist
137
138	set env1db [eval {berkdb_open_noerr -env $env1 -auto_commit \
139	     -mode 0644} $largs $omethod $testfile]
140	set clientdb $env1db
141	error_check_good dbopen [is_valid_db $env1db] TRUE
142	set env2db [eval {berkdb_open_noerr -env $cl2env -auto_commit \
143	     -mode 0644} $largs $omethod $testfile]
144	error_check_good dbopen [is_valid_db $env2db] TRUE
145
146	# Run a modified test001 in the master (and update clients).
147	puts "\tRep$tnum.a.0: Running rep_test in replicated env."
148	eval rep_test $method $masterenv $masterdb $niter 0 0 0 0 $largs
149	process_msgs $envlist
150
151	if { $do_secondary } {
152		# Put some data into the primary
153		puts "\tRep$tnum.a.1: Putting primary/secondary data on master."
154		eval rep012_sec $method $mpdb $niter keys data
155		process_msgs $envlist
156
157		set verbose_check_secondaries 1
158		check_secondaries $mpdb $msdb $niter keys data "Rep$tnum.b"
159	} else {
160		puts "\tRep$tnum.b: Skipping secondaries for method $method"
161	}
162	set nstart $niter
163	puts "\tRep$tnum.c: Run test in master and client 2 only"
164	eval rep_test\
165	    $method $masterenv $masterdb $niter $nstart $nstart 0 0 $largs
166
167	# Ignore messages for $env1.
168	set envlist "{$env0 1} {$cl2env 3}"
169	process_msgs $envlist
170
171	# Nuke those for client about to become master.
172	replclear 2
173	tclsleep 3
174	puts "\tRep$tnum.d: Swap envs"
175	set tmp $masterenv
176	set masterenv $clientenv
177	set clientenv $tmp
178	error_check_good downgrade [$clientenv rep_start -client] 0
179	error_check_good upgrade [$masterenv rep_start -master] 0
180	set envlist "{$env0 1} {$env1 2} {$cl2env 3}"
181	process_msgs $envlist
182
183	#
184	# At this point, env0 should have rolled back across a txn commit.
185	# If we do any operation on env0db, we should get an error that
186	# the handle is dead.
187	puts "\tRep$tnum.e: Try to access db handle after rollback"
188	set stat1 [catch {$env0db stat} ret1]
189	error_check_good stat1 $stat1 1
190	error_check_good dead1 [is_substr $ret1 DB_REP_HANDLE_DEAD] 1
191
192	set stat3 [catch {$env2db stat} ret3]
193	error_check_good stat3 $stat3 1
194	error_check_good dead3 [is_substr $ret3 DB_REP_HANDLE_DEAD] 1
195
196	if { $do_secondary } {
197		#
198		# Check both secondary get and close to detect DEAD_HANDLE.
199		#
200		puts "\tRep$tnum.f: Try to access secondary db handles after rollback"
201		set verbose_check_secondaries 1
202		check_secondaries $mpdb $msdb $niter \
203		    keys data "Rep$tnum.f" errp errs errsg
204		error_check_good deadp [is_substr $errp DB_REP_HANDLE_DEAD] 1
205		error_check_good deads [is_substr $errs DB_REP_HANDLE_DEAD] 1
206		error_check_good deadsg [is_substr $errsg DB_REP_HANDLE_DEAD] 1
207		puts "\tRep$tnum.g: Closing"
208		error_check_good mpdb [$mpdb close] 0
209		error_check_good msdb [$msdb close] 0
210	} else {
211		puts "\tRep$tnum.f: Closing"
212	}
213
214	error_check_good env0db [$env0db close] 0
215	error_check_good env1db [$env1db close] 0
216	error_check_good cl2db [$env2db close] 0
217	error_check_good env0_close [$env0 close] 0
218	error_check_good env1_close [$env1 close] 0
219	error_check_good cl2_close [$cl2env close] 0
220	replclose $testdir/MSGQUEUEDIR
221	set verbose_check_secondaries 0
222	set testdir $orig_tdir
223	return
224}
225
226proc rep012_sec {method pdb niter keysp datap} {
227	source ./include.tcl
228
229	upvar $keysp keys
230	upvar $datap data
231	set did [open $dict]
232	for { set n 0 } { [gets $did str] != -1 && $n < $niter } { incr n } {
233		if { [is_record_based $method] == 1 } {
234			set key [expr $n + 1]
235			set datum $str
236		} else {
237			set key $str
238			gets $did datum
239		}
240		set keys($n) $key
241		set data($n) [pad_data $method $datum]
242
243		set ret [$pdb put $key [chop_data $method $datum]]
244		error_check_good put($n) $ret 0
245	}
246	close $did
247}
248