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 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
|
# See the file LICENSE for redistribution information.
#
# Copyright (c) 2010, 2013 Oracle and/or its affiliates. All rights reserved.
#
# TEST rep092
# TEST Read-your-writes consistency.
# TEST Test events in one thread (process) waking up another sleeping thread,
# TEST before a timeout expires.
#
proc rep092 { method { niter 20 } { tnum "092" } args } {
source ./include.tcl
global repfiles_in_memory
# Skip for all methods except btree.
if { $checking_valid_methods } {
set test_methods { btree }
return $test_methods
}
if { [is_btree $method] == 0 } {
puts "Rep005: Skipping for method $method."
return
}
puts "Rep$tnum: read-your-writes consistency, multi-thread wake-up"
foreach pad_flag { no yes } {
foreach txn_flag { no yes } {
rep092a_sub $method $niter \
$tnum $pad_flag $txn_flag $args
rep092b_sub $method $niter \
$tnum $pad_flag $txn_flag $args
}
}
}
proc rep092a_sub { method niter tnum pad in_txn largs } {
source ./include.tcl
global rep_verbose
global testdir
global verbose_type
global repfiles_in_memory
set verbargs ""
if { $rep_verbose == 1 } {
set verbargs " -verbose {$verbose_type on} "
}
set repmemargs ""
if { $repfiles_in_memory } {
set repmemargs "-rep_inmem_files "
}
env_cleanup $testdir
replsetup $testdir/MSGQUEUEDIR
set masterdir $testdir/MASTERDIR
set clientdir $testdir/CLIENTDIR
file mkdir $masterdir
file mkdir $clientdir
puts "\tRep$tnum.a: Create master and client."
repladd 1
set ma_envcmd "berkdb_env_noerr -create -txn -errpfx MASTER \
$repmemargs \
$verbargs -home $masterdir -rep_transport \[list 1 replsend\]"
set masterenv [eval $ma_envcmd -rep_master]
repladd 2
set cl_envcmd "berkdb_env_noerr -create -txn -errpfx CLIENT \
$repmemargs -errfile /dev/stderr \
$verbargs -home $clientdir -rep_transport \[list 2 replsend\]"
set clientenv [eval $cl_envcmd -rep_client]
set envlist "{$masterenv 1} {$clientenv 2}"
process_msgs $envlist
puts "\tRep$tnum.b: Create and replicate a few warm-up txns."
set start 0
eval rep_test $method $masterenv NULL $niter $start $start 0 $largs
incr start $niter
process_msgs $envlist
puts "\tRep$tnum.c: Write txn and get its commit token."
if { $pad } {
eval rep_test $method $masterenv \
NULL $niter $start $start 0 $largs
incr start $niter
}
set omethod [convert_method $method]
set dbargs [convert_args $method $largs]
set db [eval berkdb_open_noerr -env $masterenv -auto_commit \
-create $omethod $dbargs test.db ]
set txn [$masterenv txn -token]
$db put -txn $txn "key1" "data1"
set token [$txn commit]
$db close
if { $pad } {
eval rep_test $method $masterenv \
NULL $niter $start $start 0 $largs
incr start $niter
}
# Don't process msgs just yet. We want to test the behavior when the
# client checks/waits for the transaction more quickly than the client
# receives it. In order to do that in a test, we simulate the
# replication being rather slow, by pausing for a moment after starting
# up the txn_applied thread (in a separate child Tcl process).
#
set pause 5
# Define an emergency upper limit on the sleeping time, so that in case
# the code is broken the test won't hang forever. The child process
# should complete promptly, as soon as we apply the transaction.
#
set limit 60
set tolerance 1
# Spawn a process to call txn_applied
#
puts "\tRep$tnum.d: Spawn child process, and pause to let it get started."
set timeout [expr $limit * 1000000]
error_check_good binary_scan [binary scan $token H40 token_chars] 1
set listing $testdir/repscript.log
set pid [exec $tclsh_path $test_path/wrap.tcl \
rep092script.tcl $listing $clientdir \
$token_chars $timeout $in_txn $rep_verbose $verbose_type &]
tclsleep $pause
puts "\tRep$tnum.e: Apply the transaction at the client."
process_msgs $envlist
watch_procs $pid 1
set fd [open $listing]
puts "\tRep$tnum.f: Examine the sub-process results."
set report [split [read $fd] "\n"]
close $fd
set result [lindex [lsearch -inline $report RESULT*] 1]
error_check_good wait_result $result 0
set duration [lindex [lsearch -inline $report DURATION*] 1]
error_check_good no_timeout \
[expr $duration < $limit - $tolerance] 1
# Add a third client.
#
set clientdir2 $testdir/CLIENTDIR2
file mkdir $clientdir2
puts "\tRep$tnum.g: Add another client, and make it master."
repladd 3
set cl_envcmd2 "berkdb_env_noerr -create -txn -errpfx CLIENT2 \
$repmemargs \
$verbargs -home $clientdir2 -rep_transport \[list 3 replsend\]"
set clientenv2 [eval $cl_envcmd2 -rep_client]
lappend envlist "$clientenv2 3"
process_msgs $envlist
# Swap roles between master and client2. First client will eventually
# see a gen change, while waiting.
#
$masterenv rep_start -client
$clientenv2 rep_start -master
if { $pad } {
eval rep_test $method $clientenv2 \
NULL $niter $start $start 0 $largs
incr start $niter
}
set db [eval berkdb_open_noerr -env $clientenv2 -auto_commit \
-create $omethod $dbargs test.db ]
set txn [$clientenv2 txn -token]
$db put -txn $txn "key2" "data2"
set token [$txn commit]
$db close
if { $pad } {
eval rep_test $method $clientenv2 \
NULL $niter $start $start 0 $largs
incr start $niter
}
puts "\tRep$tnum.h: Spawn another child process."
error_check_good binary_scan [binary scan $token H40 token_chars] 1
set pid [exec $tclsh_path $test_path/wrap.tcl \
rep092script.tcl $listing $clientdir \
$token_chars $timeout $in_txn $rep_verbose $verbose_type &]
tclsleep 5
puts "\tRep$tnum.i: Apply the transaction at the client."
process_msgs $envlist
watch_procs $pid 1
set fd [open $listing]
puts "\tRep$tnum.j: Examine the sub-process results."
set report [split [read $fd] "\n"]
close $fd
set result [lindex [lsearch -inline $report RESULT*] 1]
error_check_good wait_result $result 0
set duration [lindex [lsearch -inline $report DURATION*] 1]
error_check_good no_timeout2 \
[expr $duration < $limit - $tolerance] 1
$clientenv close
$masterenv close
$clientenv2 close
replclose $testdir/MSGQUEUEDIR
}
proc rep092b_sub { method niter tnum pad in_txn largs } {
source ./include.tcl
global rep_verbose
global testdir
global verbose_type
set verbargs ""
if { $rep_verbose == 1 } {
set verbargs " -verbose {$verbose_type on} "
}
# This part of the test only makes sense with INMEM
#
set repmemargs "-rep_inmem_files "
env_cleanup $testdir
replsetup $testdir/MSGQUEUEDIR
set masterdir $testdir/MASTERDIR
set clientdir $testdir/CLIENTDIR
file mkdir $masterdir
file mkdir $clientdir
puts "\tRep$tnum.a: Create master and client."
repladd 1
set ma_envcmd "berkdb_env_noerr -create -txn -errpfx MASTER \
$repmemargs \
$verbargs -home $masterdir -rep_transport \[list 1 replsend\]"
set masterenv [eval $ma_envcmd -rep_master]
repladd 2
set cl_envcmd "berkdb_env_noerr -create -txn -errpfx CLIENT \
$repmemargs -errfile /dev/stderr \
$verbargs -home $clientdir -rep_transport \[list 2 replsend\]"
set clientenv [eval $cl_envcmd -rep_client]
set envlist "{$masterenv 1} {$clientenv 2}"
process_msgs $envlist
puts "\tRep$tnum.b: Create and replicate a few warm-up txns."
set start 0
eval rep_test $method $masterenv NULL $niter $start $start 0 $largs
incr start $niter
process_msgs $envlist
puts "\tRep$tnum.x: Shut down client."
$clientenv close
puts "\tRep$tnum.c: Write txn and get its commit token."
if { $pad } {
eval rep_test $method $masterenv \
NULL $niter $start $start 0 $largs
incr start $niter
}
set omethod [convert_method $method]
set dbargs [convert_args $method $largs]
set db [eval berkdb_open_noerr -env $masterenv -auto_commit \
-create $omethod $dbargs test.db ]
set txn [$masterenv txn -token]
$db put -txn $txn "key1" "data1"
set token [$txn commit]
$db close
if { $pad } {
eval rep_test $method $masterenv \
NULL $niter $start $start 0 $largs
incr start $niter
}
puts "\tRep$tnum.x: Restart client, get partway through sync."
set clientenv [eval $cl_envcmd -rep_client -recover]
set envlist "{$masterenv 1} {$clientenv 2}"
# This will put the client into a state where it doesn't have the LSN
# history database, at a time when it needs to read it. Therefore, it
# will wait for it to be materialized in the "abbreviated internal init"
# cycle that is needed when in-memory databases are involved.
#
proc_msgs_once $envlist
proc_msgs_once $envlist
set pause 5
set limit 60
set tolerance 1
# Spawn a process to call txn_applied
#
puts "\tRep$tnum.d: Spawn child process, and pause to let it get started."
set timeout [expr $limit * 1000000]
error_check_good binary_scan [binary scan $token H40 token_chars] 1
set listing $testdir/repscript.log
set pid [exec $tclsh_path $test_path/wrap.tcl \
rep092script.tcl $listing $clientdir \
$token_chars $timeout $in_txn $rep_verbose $verbose_type &]
tclsleep $pause
puts "\tRep$tnum.e: Apply the transaction at the client."
process_msgs $envlist
watch_procs $pid 1
set fd [open $listing]
puts "\tRep$tnum.f: Examine the sub-process results."
set report [split [read $fd] "\n"]
close $fd
set result [lindex [lsearch -inline $report RESULT*] 1]
error_check_good wait_result $result 0
set duration [lindex [lsearch -inline $report DURATION*] 1]
error_check_good no_timeout \
[expr $duration < $limit - $tolerance] 1
$clientenv close
$masterenv close
replclose $testdir/MSGQUEUEDIR
}
|