summaryrefslogtreecommitdiff
path: root/test/rep045.tcl
blob: ba406e99aef2b6f5da40f2e0762818c0a04ebe61 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# See the file LICENSE for redistribution information.
#
# Copyright (c) 2005-2009 Oracle.  All rights reserved.
#
# $Id$
#
# TEST	rep045
# TEST
# TEST	Replication with versions.
# TEST
# TEST	Mimic an application where a database is set up in the
# TEST	background and then put into a replication group for use.
# TEST	The "version database" identifies the current live
# TEST	version, the database against which queries are made.
# TEST	For example, the version database might say the current
# TEST	version is 3, and queries would then be sent to db.3.
# TEST	Version 4 is prepared for use while version 3 is in use.
# TEST	When version 4 is complete, the version database is updated
# TEST	to point to version 4 so queries can be directed there.
# TEST
# TEST	This test has a master and two clients.  One client swaps
# TEST	roles with the master, and the other client runs constantly
# TEST	in another process.

proc rep045 { method { tnum "045" } args } {

	source ./include.tcl
	global databases_in_memory
	global repfiles_in_memory

	if { $is_windows9x_test == 1 } {
		puts "Skipping replication test on Win 9x platform."
		return
	}

	# Valid for all access methods.
	if { $checking_valid_methods } {
		return "ALL"
	}

	set args [convert_args $method $args]
	set logsets [create_logsets 3]

	# Set up for on-disk or in-memory databases.
	set msg "using on-disk databases"
	if { $databases_in_memory } {
		set msg "using named in-memory databases"
		if { [is_queueext $method] } { 
			puts -nonewline "Skipping rep$tnum for method "
			puts "$method with named in-memory databases."
			return
		}
	}

	set msg2 "and on-disk replication files"
	if { $repfiles_in_memory } {
		set msg2 "and in-memory replication files"
	}

	foreach l $logsets {
		set logindex [lsearch -exact $l "in-memory"]
		puts "Rep$tnum ($method): Replication with version\
		    databases $msg $msg2."
		puts "Rep$tnum: Master logs are [lindex $l 0]"
		puts "Rep$tnum: Client 0 logs are [lindex $l 1]"
		puts "Rep$tnum: Client 1 logs are [lindex $l 2]"
		rep045_sub $method $tnum $l $args
	}
}

proc rep045_sub { method tnum logset largs } {
	source ./include.tcl
	set orig_tdir $testdir
	global databases_in_memory
	global repfiles_in_memory
	global rep_verbose
	global verbose_type

	set verbargs ""
	if { $rep_verbose == 1 } {
		set verbargs " -verbose {$verbose_type on} "
	}

	set repmemargs ""
	if { $repfiles_in_memory } {
		set repmemargs "-rep_inmem_files "
	}

	set masterdir $testdir/MASTERDIR
	set clientdir0 $testdir/CLIENTDIR0
	set clientdir1 $testdir/CLIENTDIR1

	env_cleanup $testdir
	replsetup $testdir/MSGQUEUEDIR
	file mkdir $masterdir
	file mkdir $clientdir0
	file mkdir $clientdir1

	set m_logtype [lindex $logset 0]
	set c_logtype [lindex $logset 1]
	set c2_logtype [lindex $logset 2]

	# In-memory logs require a large log buffer, and cannot
	# be used with -txn nosync.
	set m_logargs [adjust_logargs $m_logtype]
	set c_logargs [adjust_logargs $c_logtype]
	set c2_logargs [adjust_logargs $c2_logtype]
	set m_txnargs [adjust_txnargs $m_logtype]
	set c_txnargs [adjust_txnargs $c_logtype]
	set c2_txnargs [adjust_txnargs $c2_logtype]

	set omethod [convert_method $method]

	# Open a master.
	repladd 1
	set envcmd(M0) "berkdb_env_noerr -create $m_txnargs \
	    $m_logargs -errpfx ENV.M0 $verbargs $repmemargs \
	    -errfile /dev/stderr -lock_detect default \
	    -home $masterdir -rep_transport \[list 1 replsend\]"
	set menv [eval $envcmd(M0) -rep_master]

	# Open a client
	repladd 2
	set envcmd(C0) "berkdb_env_noerr -create $c_txnargs \
	    $c_logargs -errpfx ENV.C0 $verbargs $repmemargs \
	    -errfile /dev/stderr -lock_detect default \
	    -home $clientdir0 -rep_transport \[list 2 replsend\]"
	set cenv0 [eval $envcmd(C0) -rep_client]

	# Open second client.
	repladd 3
	set envcmd(C1) "berkdb_env_noerr -create $c2_txnargs \
	    $c2_logargs -errpfx ENV.C1 $verbargs $repmemargs \
	    -errfile /dev/stderr -lock_detect default \
	    -home $clientdir1 -rep_transport \[list 3 replsend\]"
	set cenv1 [eval $envcmd(C1) -rep_client]

	# Bring the clients online by processing the startup messages.
	set envlist "{$menv 1} {$cenv0 2} {$cenv1 3}"
	process_msgs $envlist

	# Clobber replication's 30-second anti-archive timer, which will have
	# been started by client sync-up internal init, so that we can do a
	# db_remove in a moment.
	#
	$menv test force noarchive_timeout

	puts "\tRep$tnum.a: Initialize version database."
	# Set up variables so we cycle through version numbers 1
	# through maxversion several times.
	if { $databases_in_memory } {
		set vname { "" "version.db" }
	} else {
		set vname "version.db"
	}
	set version 0
	set maxversion 5
	set iter 12
	set nentries 100
	set start 0

	# The version db is always btree.
	set vdb [eval {berkdb_open_noerr -env $menv -create \
	    -auto_commit -mode 0644} -btree $vname]
	error_check_good init_version [$vdb put VERSION $version] 0
	error_check_good vdb_close [$vdb close] 0
	process_msgs $envlist

	# Start up a separate process that constantly reads data
	# from the current official version.
	puts "\tRep$tnum.b: Spawn a child tclsh to do client work."
	set pid [exec $tclsh_path $test_path/wrap.tcl \
	    rep045script.tcl $testdir/rep045script.log \
		   $clientdir1 $vname $databases_in_memory &]

	# Main loop: update query database, process messages (or don't,
	# simulating a failure), announce the new version, process
	# messages (or don't), and swap masters.
	set version 1
	for { set i 1 } { $i < $iter } { incr i } {

		# If database.N exists on disk, clean it up.
		if { $databases_in_memory } {
			set dbname { "" "db.$version" }
		} else {
			set dbname "db.$version"
		}
		if { [file exists $masterdir/$dbname] == 1 } {
			puts "\tRep$tnum.c.$i: Removing old version $version."
			error_check_good dbremove \
			   [$menv dbremove -auto_commit $dbname] 0
		}

		puts "\tRep$tnum.c.$i: Set up query database $version."
		set db [eval berkdb_open_noerr -create -env $menv\
		    -auto_commit -mode 0644 $largs $omethod $dbname]
		error_check_good db_open [is_valid_db $db] TRUE
		eval rep_test $method $menv $db $nentries $start $start 0 $largs
		incr start $nentries
		error_check_good db_close [$db close] 0

		# We alternate between processing the messages and
		# clearing the messages to simulate a failure.

		set process [expr $i % 2]
		if { $process == 1 } {
			process_msgs $envlist
		} else {
			replclear 2
			replclear 3
		}

		# Announce new version.
		puts "\tRep$tnum.d.$i: Announce new version $version."
		set vdb [eval {berkdb_open_noerr -env $menv \
		    -auto_commit -mode 0644} $vname]
		error_check_good update_version [$vdb put VERSION $version] 0
		error_check_good vdb_close [$vdb close] 0

		# Process messages or simulate failure.
		if { $process == 1 } {
			process_msgs $envlist
		} else {
			replclear 2
			replclear 3
		}

		# Switch master, update envlist.
		puts "\tRep$tnum.e.$i: Switch masters."
		set envlist [switch_master $envlist]

		# Update values for next iteration.
		set menv [lindex [lindex $envlist 0] 0]
		set cenv0 [lindex [lindex $envlist 1] 0]
		incr version
		if { $version > $maxversion } {
			set version 1
		}
	}

	# Signal to child that we are done.
	set vdb [eval {berkdb_open_noerr -env $menv \
	    -auto_commit -mode 0644} $vname]
	error_check_good version_done [$vdb put VERSION DONE] 0
	error_check_good vdb_close [$vdb close] 0
	process_msgs $envlist

	# Watch for child to finish.
	watch_procs $pid 5

	puts "\tRep$tnum.f: Clean up."
	error_check_good menv_close [$menv close] 0
	error_check_good cenv0_close [$cenv0 close] 0
	error_check_good cenv1_close [$cenv1 close] 0

	replclose $testdir/MSGQUEUEDIR

	# Check for failures in child's log file.
	set errstrings [eval findfail $testdir/rep045script.log]
	foreach str $errstrings {
		puts "FAIL: error message in log file: $str"
	}

	set testdir $orig_tdir
	return
}

proc switch_master { envlist } {
	# Find env handles and machine ids.
	set menv [lindex [lindex $envlist 0] 0]
	set mid [lindex [lindex $envlist 0] 1]
	set cenv [lindex [lindex $envlist 1] 0]
	set cid [lindex [lindex $envlist 1] 1]
	set cenv1 [lindex [lindex $envlist 2] 0]
	set cid1 [lindex [lindex $envlist 2] 1]

	# Downgrade master, upgrade client.
	error_check_good master_downgrade [$menv rep_start -client] 0
	error_check_good client_upgrade [$cenv rep_start -master] 0
	process_msgs $envlist

	# Adjust envlist.  The former client env is the new master,
	# and vice versa.
	set newenvlist "{$cenv $cid} {$menv $mid} {$cenv1 $cid1}"
	return $newenvlist
}