1# See the file LICENSE for redistribution information.
2#
3# Copyright (c) 2001-2009 Oracle.  All rights reserved.
4#
5# $Id$
6#
7# TEST  	rep007
8# TEST	Replication and bad LSNs
9# TEST
10# TEST	Run rep_test in a replicated master env.
11# TEST  	Close the client.  Make additional changes to master.
12# TEST  	Close the master.  Open the client as the new master.
13# TEST 	Make several different changes.  Open the old master as
14# TEST	the client.  Verify periodically that contents are correct.
15# TEST	This test is not appropriate for named in-memory db testing
16# TEST	because the databases are lost when both envs are closed.
17proc rep007 { method { niter 10 } { tnum "007" } 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	# All access methods are allowed.
29	if { $checking_valid_methods } {
30		return "ALL"
31	}
32
33	set args [convert_args $method $args]
34	set logsets [create_logsets 3]
35
36	# Set up for on-disk or in-memory databases.
37	set msg "using on-disk databases"
38	if { $databases_in_memory } {
39		set msg "using named in-memory databases"
40		if { [is_queueext $method] } {
41			puts -nonewline "Skipping rep$tnum for method "
42			puts "$method with named in-memory databases."
43			return
44		}
45	}
46
47	set msg2 "and on-disk replication files"
48	if { $repfiles_in_memory } {
49		set msg2 "and in-memory replication files"
50	}
51
52	# Run the body of the test with and without recovery.
53	foreach r $test_recopts {
54		foreach l $logsets {
55			set logindex [lsearch -exact $l "in-memory"]
56			if { $r == "-recover" && $logindex != -1 } {
57				puts "Rep$tnum: Skipping for\
58				    in-memory logs with -recover."
59				continue
60			}
61			if { $r == "-recover" && $databases_in_memory } {
62				puts "Rep$tnum: Skipping for\
63				    named in-memory databases with -recover."
64				continue
65			}
66			puts "Rep$tnum ($method $r):\
67			    Replication and bad LSNs $msg $msg2."
68			puts "Rep$tnum: Master logs are [lindex $l 0]"
69			puts "Rep$tnum: Client1 logs are [lindex $l 1]"
70			puts "Rep$tnum: Client2 logs are [lindex $l 2]"
71			rep007_sub $method $niter $tnum $l $r $args
72		}
73	}
74}
75
76proc rep007_sub { method niter tnum logset recargs largs } {
77	global testdir
78	global databases_in_memory
79	global repfiles_in_memory
80	global rep_verbose
81	global verbose_type
82
83	set verbargs ""
84	if { $rep_verbose == 1 } {
85		set verbargs " -verbose {$verbose_type on} "
86	}
87
88	set repmemargs ""
89	if { $repfiles_in_memory } {
90		set repmemargs "-rep_inmem_files "
91	}
92
93	env_cleanup $testdir
94
95	set omethod [convert_method $method]
96
97	replsetup $testdir/MSGQUEUEDIR
98
99	set masterdir $testdir/MASTERDIR
100	set clientdir $testdir/CLIENTDIR
101	set clientdir2 $testdir/CLIENTDIR.2
102	file mkdir $masterdir
103	file mkdir $clientdir
104	file mkdir $clientdir2
105
106	set m_logtype [lindex $logset 0]
107	set m_logargs [adjust_logargs $m_logtype]
108	set m_txnargs [adjust_txnargs $m_logtype]
109
110	set c_logtype [lindex $logset 1]
111	set c_logargs [adjust_logargs $c_logtype]
112	set c_txnargs [adjust_txnargs $c_logtype]
113
114	set c2_logtype [lindex $logset 2]
115	set c2_logargs [adjust_logargs $c2_logtype]
116	set c2_txnargs [adjust_txnargs $c2_logtype]
117
118	# Open a master.
119	repladd 1
120	set ma_envcmd "berkdb_env_noerr -create $m_txnargs $m_logargs \
121	    -home $masterdir $verbargs -errpfx MASTER $repmemargs \
122	    -rep_transport \[list 1 replsend\]"
123	set masterenv [eval $ma_envcmd $recargs -rep_master]
124
125	# Open two clients
126	repladd 2
127	set cl_envcmd "berkdb_env_noerr -create $c_txnargs $c_logargs \
128	    -home $clientdir $verbargs -errpfx CLIENT1 $repmemargs \
129	    -rep_transport \[list 2 replsend\]"
130	set clientenv [eval $cl_envcmd $recargs -rep_client]
131
132	repladd 3
133	set cl2_envcmd "berkdb_env_noerr -create $c2_txnargs $c2_logargs \
134	    -home $clientdir2 $verbargs -errpfx CLIENT2 $repmemargs \
135	    -rep_transport \[list 3 replsend\]"
136	set cl2env [eval $cl2_envcmd $recargs -rep_client]
137
138	# Bring the clients online by processing the startup messages.
139	set envlist "{$masterenv 1} {$clientenv 2} {$cl2env 3}"
140	process_msgs $envlist
141
142	# Run rep_test in the master (and update clients).
143	puts "\tRep$tnum.a: Running rep_test in replicated env."
144	eval rep_test $method $masterenv NULL $niter 0 0 0 $largs
145	process_msgs $envlist
146
147	# Databases should now have identical contents.
148	if { $databases_in_memory } {
149		set dbname { "" "test.db" }
150	} else {
151		set dbname "test.db"
152	}
153
154	rep_verify $masterdir $masterenv $clientdir $clientenv 0 1 1
155	rep_verify $masterdir $masterenv $clientdir2 $cl2env 0 1 1
156
157	puts "\tRep$tnum.b: Close client 1 and make master changes."
158	# Flush the log so that we don't lose any changes, since we'll be
159	# relying on having a good log when we run recovery when we open it
160	# later.
161	#
162	$clientenv log_flush
163	error_check_good client_close [$clientenv close] 0
164
165	# Change master and propagate changes to client 2.
166	set start $niter
167	eval rep_test $method $masterenv NULL $niter $start $start 0 $largs
168	set envlist "{$masterenv 1} {$cl2env 3}"
169	process_msgs $envlist
170
171	# We need to do a deletion here to cause meta-page updates,
172	# particularly for queue.  Delete the first pair and remember
173	# what it is -- it should come back after the master is closed
174	# and reopened as a client.
175	set db1 [eval {berkdb_open_noerr} -env $masterenv -auto_commit $dbname]
176	error_check_good dbopen [is_valid_db $db1] TRUE
177	set txn [$masterenv txn]
178	set c [eval $db1 cursor -txn $txn]
179	error_check_good db_cursor [is_valid_cursor $c $db1] TRUE
180	set first [$c get -first]
181	set pair [lindex [$c get -first] 0]
182	set key [lindex $pair 0]
183	set data [lindex $pair 1]
184
185	error_check_good cursor_del [$c del] 0
186	error_check_good dbcclose [$c close] 0
187	error_check_good txn_commit [$txn commit] 0
188	error_check_good db1_close [$db1 close] 0
189	#
190	# Process the messages to get them out of the db.  This also
191	# propagates the delete to client 2.
192	#
193	process_msgs $envlist
194
195	# Nuke those for closed client
196	replclear 2
197
198	# Databases 1 and 3 should now have identical contents.
199	# Database 2 should be different.  First check 1 and 3.  We
200	# have to wait to check 2 until the env is open again.
201	rep_verify $masterdir $masterenv $clientdir2 $cl2env 0 1 1
202
203	puts "\tRep$tnum.c: Close master, reopen client as master."
204	$masterenv log_flush
205	error_check_good master_close [$masterenv close] 0
206	set newmasterenv [eval $cl_envcmd $recargs -rep_master]
207
208	# Now we can check that database 2 does not match 3.
209	rep_verify $clientdir $newmasterenv $clientdir2 $cl2env 0 0 0
210
211	puts "\tRep$tnum.d: Make incompatible changes to new master."
212	set envlist "{$newmasterenv 2} {$cl2env 3}"
213	process_msgs $envlist
214
215	set db [eval {berkdb_open_noerr} \
216	    -env $newmasterenv -auto_commit -create $omethod $dbname]
217	error_check_good dbopen [is_valid_db $db] TRUE
218	set t [$newmasterenv txn]
219
220	# Force in a pair {10 10}.  This works for all access
221	# methods and won't overwrite the old first pair for record-based.
222	set ret [eval {$db put} -txn $t 10 [chop_data $method 10]]
223	error_check_good put $ret 0
224	error_check_good txn [$t commit] 0
225	error_check_good dbclose [$db close] 0
226
227	eval rep_test $method $newmasterenv NULL $niter $start $start 0 $largs
228	set envlist "{$newmasterenv 2} {$cl2env 3}"
229	process_msgs $envlist
230
231	# Nuke those for closed old master
232	replclear 1
233
234	# Databases 2 and 3 should now match.
235	rep_verify $clientdir $newmasterenv $clientdir2 $cl2env 0 1 1
236
237	puts "\tRep$tnum.e: Open old master as client."
238	set newclientenv [eval $ma_envcmd -rep_client -recover]
239	set envlist "{$newclientenv 1} {$newmasterenv 2} {$cl2env 3}"
240	process_msgs $envlist
241
242	# The pair we deleted earlier from the master should now
243	# have reappeared.
244	set db1 [eval {berkdb_open_noerr}\
245	    -env $newclientenv -auto_commit $dbname]
246	error_check_good dbopen [is_valid_db $db1] TRUE
247	set ret [$db1 get -get_both $key [pad_data $method $data]]
248	error_check_good get_both $ret [list $pair]
249	error_check_good db1_close [$db1 close] 0
250
251	set start [expr $niter * 2]
252	eval rep_test $method $newmasterenv NULL $niter $start $start 0 $largs
253	set envlist "{$newclientenv 1} {$newmasterenv 2} {$cl2env 3}"
254	process_msgs $envlist
255
256	# Now all 3 should match again.
257	rep_verify $masterdir $newclientenv $clientdir $newmasterenv 0 1 1
258	rep_verify $masterdir $newclientenv $clientdir2 $cl2env 0 1 1
259
260	error_check_good newmasterenv_close [$newmasterenv close] 0
261	error_check_good newclientenv_close [$newclientenv close] 0
262	error_check_good cl2_close [$cl2env close] 0
263	replclose $testdir/MSGQUEUEDIR
264	return
265}
266