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
}
|