mirror of
https://github.com/berkeleydb/libdb.git
synced 2024-09-29 03:36:55 +00:00
445 lines
12 KiB
Tcl
445 lines
12 KiB
Tcl
# See the file LICENSE for redistribution information.
|
|
#
|
|
# Copyright (c) 2006, 2011 Oracle and/or its affiliates. All rights reserved.
|
|
#
|
|
# $Id$
|
|
#
|
|
# TEST rep065
|
|
# TEST Tests replication running with different versions.
|
|
# TEST This capability is introduced with 4.5.
|
|
# TEST
|
|
# TEST Start a replication group of 1 master and N sites, all
|
|
# TEST running some historical version greater than or equal to 4.4.
|
|
# TEST Take down a client and bring it up again running current.
|
|
# TEST Run some upgrades, make sure everything works.
|
|
# TEST
|
|
# TEST Each site runs the tcllib of its own version, but uses
|
|
# TEST the current tcl code (e.g. test.tcl).
|
|
proc rep065 { method { nsites 3 } args } {
|
|
source ./include.tcl
|
|
global repfiles_in_memory
|
|
global noenv_messaging
|
|
set noenv_messaging 1
|
|
|
|
#
|
|
# Skip all methods but btree - we don't use the method, as we
|
|
# run over all of them with varying versions.
|
|
#
|
|
if { $checking_valid_methods } {
|
|
set test_methods { btree }
|
|
return $test_methods
|
|
}
|
|
|
|
if { [is_btree $method] == 0 } {
|
|
puts "Rep065: Skipping for method $method."
|
|
return
|
|
}
|
|
|
|
set msg2 "and on-disk replication files"
|
|
if { $repfiles_in_memory } {
|
|
set msg2 "and in-memory replication files"
|
|
}
|
|
|
|
# Make the list of {method version} pairs to test.
|
|
#
|
|
set mvlist [method_version]
|
|
set mvlen [llength $mvlist]
|
|
puts "Rep065: Testing the following $mvlen method/version pairs:"
|
|
puts "Rep065: $mvlist"
|
|
puts "Rep065: $msg2"
|
|
set count 1
|
|
set total [llength $mvlist]
|
|
set slist [setup_sites $nsites]
|
|
foreach i $mvlist {
|
|
puts "Rep065: Test iteration $count of $total: $i"
|
|
rep065_sub $count $i $nsites $slist
|
|
incr count
|
|
}
|
|
set noenv_messaging 0
|
|
}
|
|
|
|
proc rep065_sub { iter mv nsites slist } {
|
|
source ./include.tcl
|
|
global machids
|
|
global util_path
|
|
set machids {}
|
|
set method [lindex $mv 0]
|
|
set vers [lindex $mv 1]
|
|
|
|
puts "\tRep065.$iter.a: Set up."
|
|
# Whatever directory we started this process from is referred
|
|
# to as the controlling directory. It will contain the message
|
|
# queue and start all the child processes.
|
|
set controldir [pwd]
|
|
env_cleanup $controldir/$testdir
|
|
replsetup_noenv $controldir/$testdir/MSGQUEUEDIR
|
|
|
|
# Set up the historical build directory. The master will start
|
|
# running with historical code.
|
|
#
|
|
# This test presumes we are running in the current build
|
|
# directory and that the expected historical builds are
|
|
# set up in a similar fashion. If they are not, quit gracefully.
|
|
|
|
set pwd [pwd]
|
|
set homedir [file dirname [file dirname $pwd]]
|
|
#
|
|
# Cannot use test_path because that is relative to the current
|
|
# directory (which will often be the old release directory).
|
|
# We need to send in the pathname to the reputils path to the
|
|
# current directory and that will be an absolute pathname.
|
|
#
|
|
set reputils_path $pwd/../test/tcl
|
|
set histdir $homedir/$vers/build_unix
|
|
if { [file exists $histdir] == 0 } {
|
|
puts -nonewline "Skipping iteration $iter: cannot find"
|
|
puts " historical version $vers."
|
|
return
|
|
}
|
|
if { [file exists $histdir/db_verify] == 0 } {
|
|
puts -nonewline "Skipping iteration $iter: historical version"
|
|
puts " $vers is missing some executables. Is it built?"
|
|
return
|
|
}
|
|
|
|
set histtestdir $histdir/TESTDIR
|
|
|
|
env_cleanup $histtestdir
|
|
set markerdir $controldir/$testdir/MARKER
|
|
file delete -force $markerdir
|
|
|
|
# Create site directories. They start running in the historical
|
|
# directory, too. They will be upgraded to the current version
|
|
# first.
|
|
set allids { }
|
|
for { set i 0 } { $i < $nsites } { incr i } {
|
|
set siteid($i) [expr $i + 1]
|
|
set sid $siteid($i)
|
|
lappend allids $sid
|
|
set histdirs($sid) $histtestdir/SITE.$i
|
|
set upgdir($sid) $controldir/$testdir/SITE.$i
|
|
file mkdir $histdirs($sid)
|
|
file mkdir $upgdir($sid)
|
|
}
|
|
|
|
# Open master env running 4.4.
|
|
#
|
|
# We know that slist has all sites starting in the histdir.
|
|
# So if we encounter an upgrade value, we upgrade that client
|
|
# from the hist dir.
|
|
#
|
|
set count 1
|
|
foreach sitevers $slist {
|
|
puts "\tRep065.b.$iter.$count: Run with sitelist $sitevers."
|
|
#
|
|
# Delete the marker directory each iteration so that
|
|
# we don't find old data in there.
|
|
#
|
|
file delete -force $markerdir
|
|
file mkdir $markerdir
|
|
#
|
|
# Get the chosen master index from the list of sites.
|
|
#
|
|
set mindex [get_master $nsites $sitevers]
|
|
set meid [expr $mindex + 1]
|
|
|
|
#
|
|
# Kick off the test processes. We need 1 test process
|
|
# per site and 1 message process per site.
|
|
#
|
|
set pids {}
|
|
for { set i 0 } { $i < $nsites } { incr i } {
|
|
set upg [lindex $sitevers $i]
|
|
set sid $siteid($i)
|
|
#
|
|
# If we are running "old" set up an array
|
|
# saying if this site has run old/new yet.
|
|
# The reason is that we want to "upgrade"
|
|
# only the first time we go from old to new,
|
|
# not every iteration through this loop.
|
|
#
|
|
if { $upg == 0 } {
|
|
puts -nonewline "\t\tRep065.b: Test: Old site $i"
|
|
set sitedir($i) $histdirs($sid)
|
|
set already_upgraded($i) 0
|
|
} else {
|
|
puts -nonewline "\t\tRep065.b: Test: Upgraded site $i"
|
|
set sitedir($i) $upgdir($sid)
|
|
if { $already_upgraded($i) == 0 } {
|
|
upg_repdir $histdirs($sid) $sitedir($i)
|
|
}
|
|
set already_upgraded($i) 1
|
|
}
|
|
if { $sid == $meid } {
|
|
set state MASTER
|
|
set runtest [list REPTEST $method 15 10]
|
|
puts " (MASTER)"
|
|
} else {
|
|
set state CLIENT
|
|
set runtest {REPTEST_GET}
|
|
puts " (CLIENT)"
|
|
}
|
|
lappend pids [exec $tclsh_path $test_path/wrap.tcl \
|
|
rep065script.tcl \
|
|
$controldir/$testdir/$count.S$i.log \
|
|
SKIP \
|
|
START $state \
|
|
$runtest \
|
|
$sid $allids $controldir \
|
|
$sitedir($i) $reputils_path &]
|
|
lappend pids [exec $tclsh_path $test_path/wrap.tcl \
|
|
rep065script.tcl \
|
|
$controldir/$testdir/$count.S$i.msg \
|
|
SKIP \
|
|
PROCMSGS $state \
|
|
NULL \
|
|
$sid $allids $controldir \
|
|
$sitedir($i) $reputils_path &]
|
|
}
|
|
|
|
watch_procs $pids 20
|
|
#
|
|
# At this point, clean up any message files. The message
|
|
# system leads to a significant number of duplicate
|
|
# requests. If the master site handled them after the
|
|
# client message processes exited, then there can be
|
|
# a large number of "dead" message files waiting for
|
|
# non-existent clients. Just clean up everyone.
|
|
#
|
|
for { set i 0 } { $i < $nsites } { incr i } {
|
|
replclear_noenv $siteid($i)
|
|
}
|
|
|
|
#
|
|
# Kick off the verification processes. These just walk
|
|
# their own logs and databases, so we don't need to have
|
|
# a message process. We need separate processes because
|
|
# old sites need to use old utilities.
|
|
#
|
|
set pids {}
|
|
puts "\tRep065.c.$iter.$count: Verify all sites."
|
|
for { set i 0 } { $i < $nsites } { incr i } {
|
|
if { $siteid($i) == $meid } {
|
|
set state MASTER
|
|
} else {
|
|
set state CLIENT
|
|
}
|
|
lappend pids [exec $tclsh_path $test_path/wrap.tcl \
|
|
rep065script.tcl \
|
|
$controldir/$testdir/$count.S$i.ver \
|
|
SKIP \
|
|
VERIFY $state \
|
|
{LOG DB} \
|
|
$siteid($i) $allids $controldir \
|
|
$sitedir($i) $reputils_path &]
|
|
}
|
|
|
|
watch_procs $pids 10
|
|
#
|
|
# Now that each site created its verification files,
|
|
# we can now verify everyone.
|
|
#
|
|
for { set i 0 } { $i < $nsites } { incr i } {
|
|
if { $i == $mindex } {
|
|
continue
|
|
}
|
|
puts \
|
|
"\t\tRep065.c: Verify: Compare databases master and client $i"
|
|
error_check_good db_cmp \
|
|
[filecmp $sitedir($mindex)/VERIFY/dbdump \
|
|
$sitedir($i)/VERIFY/dbdump] 0
|
|
set upg [lindex $sitevers $i]
|
|
# !!!
|
|
# Although db_printlog works and can read old logs,
|
|
# there have been some changes to the output text that
|
|
# makes comparing difficult. One possible solution
|
|
# is to run db_printlog here, from the current directory
|
|
# instead of from the historical directory.
|
|
#
|
|
if { $upg == 0 } {
|
|
puts \
|
|
"\t\tRep065.c: Verify: Compare logs master and client $i"
|
|
error_check_good log_cmp \
|
|
[filecmp $sitedir($mindex)/VERIFY/prlog \
|
|
$sitedir($i)/VERIFY/prlog] 0
|
|
} else {
|
|
puts \
|
|
"\t\tRep065.c: Verify: Compare LSNs master and client $i"
|
|
error_check_good log_cmp \
|
|
[filecmp $sitedir($mindex)/VERIFY/loglsn \
|
|
$sitedir($i)/VERIFY/loglsn] 0
|
|
}
|
|
}
|
|
|
|
#
|
|
# At this point we have a master and sites all up to date
|
|
# with each other. Now, one at a time, upgrade the sites
|
|
# to the current version and start everyone up again.
|
|
incr count
|
|
}
|
|
}
|
|
|
|
proc setup_sites { nsites } {
|
|
#
|
|
# Set up a list that goes from 0 to $nsites running
|
|
# upgraded. A 0 represents running old version and 1
|
|
# represents running upgraded. So, for 3 sites it will look like:
|
|
# { 0 0 0 } { 1 0 0 } { 1 1 0 } { 1 1 1 }
|
|
#
|
|
set sitelist {}
|
|
for { set i 0 } { $i <= $nsites } { incr i } {
|
|
set l ""
|
|
for { set j 1 } { $j <= $nsites } { incr j } {
|
|
if { $i < $j } {
|
|
lappend l 0
|
|
} else {
|
|
lappend l 1
|
|
}
|
|
}
|
|
lappend sitelist $l
|
|
}
|
|
return $sitelist
|
|
}
|
|
|
|
proc upg_repdir { histdir upgdir } {
|
|
global util_path
|
|
|
|
#
|
|
# Upgrade a site to the current version. This entails:
|
|
# 1. Removing any old files from the upgrade directory.
|
|
# 2. Copy all old version files to upgrade directory.
|
|
# 3. Remove any __db files from upgrade directory except __db.rep*gen.
|
|
# 4. Force checkpoint in new version.
|
|
file delete -force $upgdir
|
|
|
|
# Recovery was run before as part of upgradescript.
|
|
# Archive dir by copying it to upgrade dir.
|
|
file copy -force $histdir $upgdir
|
|
set dbfiles [glob -nocomplain $upgdir/__db*]
|
|
foreach d $dbfiles {
|
|
if { $d == "$upgdir/__db.rep.gen" ||
|
|
$d == "$upgdir/__db.rep.egen" } {
|
|
continue
|
|
}
|
|
file delete -force $d
|
|
}
|
|
# Force current version checkpoint
|
|
set stat [catch {eval exec $util_path/db_checkpoint -1 -h $upgdir} r]
|
|
if { $stat != 0 } {
|
|
puts "CHECKPOINT: $upgdir: $r"
|
|
}
|
|
error_check_good stat_ckp $stat 0
|
|
}
|
|
|
|
proc get_master { nsites verslist } {
|
|
error_check_good vlist_chk [llength $verslist] $nsites
|
|
#
|
|
# When we can, simply run an election to get a new master.
|
|
# We then verify we got an old client.
|
|
#
|
|
# For now, randomly pick among the old sites, or if no old
|
|
# sites just randomly pick anyone.
|
|
#
|
|
set old_count 0
|
|
# Pick 1 out of N old sites or 1 out of nsites if all upgraded.
|
|
foreach i $verslist {
|
|
if { $i == 0 } {
|
|
incr old_count
|
|
}
|
|
}
|
|
if { $old_count == 0 } {
|
|
set old_count $nsites
|
|
}
|
|
set master [berkdb random_int 0 [expr $old_count - 1]]
|
|
#
|
|
# Since the Nth old site may not be at the Nth place in the
|
|
# list unless we used the entire list, we need to loop to find
|
|
# the right index to return.
|
|
if { $old_count == $nsites } {
|
|
return $master
|
|
}
|
|
set ocount 0
|
|
set index 0
|
|
foreach i $verslist {
|
|
if { $i == 1 } {
|
|
incr index
|
|
continue
|
|
}
|
|
if { $ocount == $master } {
|
|
return $index
|
|
}
|
|
incr ocount
|
|
incr index
|
|
}
|
|
#
|
|
# If we get here there is a problem in the code.
|
|
#
|
|
error "FAIL: get_master problem"
|
|
}
|
|
|
|
proc method_version { } {
|
|
global valid_methods
|
|
|
|
set methods $valid_methods
|
|
set remaining_methods $methods
|
|
set methods_len [expr [llength $remaining_methods] - 1]
|
|
|
|
set versions {db-5.1.25 db-5.0.26 \
|
|
db-4.8.30 db-4.7.25 db-4.6.21 db-4.5.20 db-4.4.20}
|
|
set remaining_versions $versions
|
|
set versions_len [expr [llength $remaining_versions] - 1]
|
|
|
|
# Walk through the list of methods and the list of versions and
|
|
# pair them at random. Stop when either list is empty.
|
|
set mv {}
|
|
while { $versions_len >= 0 && $methods_len >= 0 } {
|
|
set vidx [berkdb random_int 0 $versions_len]
|
|
set midx [berkdb random_int 0 $methods_len]
|
|
|
|
set version [lindex $remaining_versions $vidx]
|
|
set method [lindex $remaining_methods $midx]
|
|
|
|
set remaining_versions [lreplace $remaining_versions $vidx $vidx]
|
|
set remaining_methods [lreplace $remaining_methods $midx $midx]
|
|
|
|
incr versions_len -1
|
|
incr methods_len -1
|
|
|
|
if { $method != "heap" } {
|
|
lappend mv [list $method $version]
|
|
}
|
|
}
|
|
|
|
# If there are remaining versions, randomly assign any of
|
|
# the original methods to each one.
|
|
while { $versions_len >= 0 } {
|
|
|
|
set methods_len [expr [llength $valid_methods] - 1]
|
|
set midx [berkdb random_int 0 $methods_len]
|
|
|
|
set version [lindex $remaining_versions 0]
|
|
set method [lindex $valid_methods $midx]
|
|
|
|
set remaining_versions [lreplace $remaining_versions 0 0]
|
|
incr versions_len -1
|
|
|
|
lappend mv [list $method $version]
|
|
}
|
|
|
|
# If there are remaining methods, randomly assign any of
|
|
# the original versions to each one.
|
|
while { $methods_len >= 0 } {
|
|
|
|
set versions_len [expr [llength $versions] - 1]
|
|
set vidx [berkdb random_int 0 $versions_len]
|
|
|
|
set version [lindex $versions $vidx]
|
|
set method [lindex $remaining_methods 0]
|
|
|
|
set remaining_methods [lreplace $remaining_methods 0 0]
|
|
incr methods_len -1
|
|
|
|
lappend mv [list $method $version]
|
|
}
|
|
return $mv
|
|
}
|