mirror of
https://github.com/berkeleydb/libdb.git
synced 2024-11-16 17:16:25 +00:00
245 lines
6.9 KiB
Tcl
245 lines
6.9 KiB
Tcl
# See the file LICENSE for redistribution information.
|
|
#
|
|
# Copyright (c) 2009, 2011 Oracle and/or its affiliates. All rights reserved.
|
|
#
|
|
# TEST rep089
|
|
# TEST Test of proper clean-up of mpool during interrupted internal init.
|
|
# TEST
|
|
# TEST Have a client in the middle of internal init when a new master
|
|
# TEST generation comes along, forcing the client to interrupt the internal
|
|
# TEST init, including doing the clean-up. The client is in the middle of
|
|
# TEST retrieving database pages, so that we are forced to clean up mpool.
|
|
# TEST (Regression test for bug 17121)
|
|
|
|
proc rep089 { method { niter 200 } { tnum "089" } args } {
|
|
source ./include.tcl
|
|
global databases_in_memory
|
|
global repfiles_in_memory
|
|
global env_private
|
|
|
|
if { $checking_valid_methods } {
|
|
set test_methods {}
|
|
foreach method $valid_methods {
|
|
if { [is_btree $method] == 1 || \
|
|
[is_queue $method] == 1 } {
|
|
lappend test_methods $method
|
|
}
|
|
}
|
|
return $test_methods
|
|
}
|
|
if { [is_btree $method] == 0 && [is_queue $method] == 0 } {
|
|
puts "Rep$tnum: skipping for non-btree, non-queue method."
|
|
return
|
|
}
|
|
|
|
# It's possible to run this test with in-memory databases.
|
|
set msg "with named databases"
|
|
if { $databases_in_memory } {
|
|
set msg "with in-memory named databases"
|
|
if { [is_queueext $method] == 1 } {
|
|
puts "Skipping rep$tnum for method $method"
|
|
return
|
|
}
|
|
}
|
|
|
|
set msg2 "and on-disk replication files"
|
|
if { $repfiles_in_memory } {
|
|
set msg2 "and in-memory replication files"
|
|
}
|
|
|
|
set msg3 ""
|
|
if { $env_private } {
|
|
set msg3 "with private env"
|
|
}
|
|
|
|
# This test needs to set its own pagesize.
|
|
set pgindex [lsearch -exact $args "-pagesize"]
|
|
if { $pgindex != -1 } {
|
|
puts "Rep$tnum: skipping for specific pagesizes"
|
|
return
|
|
}
|
|
|
|
set args [convert_args $method $args]
|
|
|
|
puts -nonewline "Rep$tnum: Mpool cleanup on aborted"
|
|
puts " internal init $msg $msg2 $msg3."
|
|
rep089_sub $method $niter $tnum $args
|
|
}
|
|
|
|
proc rep089_sub { method niter tnum largs } {
|
|
global testdir
|
|
global rep_verbose
|
|
global verbose_type
|
|
global databases_in_memory
|
|
global repfiles_in_memory
|
|
global env_private
|
|
|
|
set verbargs ""
|
|
if { $rep_verbose == 1 } {
|
|
set verbargs " -verbose {$verbose_type on} "
|
|
}
|
|
|
|
set repmemargs ""
|
|
if { $repfiles_in_memory } {
|
|
set repmemargs "-rep_inmem_files "
|
|
}
|
|
|
|
set privargs ""
|
|
if { $env_private == 1 } {
|
|
set privargs " -private "
|
|
}
|
|
|
|
env_cleanup $testdir
|
|
replsetup $testdir/MSGQUEUEDIR
|
|
|
|
file mkdir [set masterdir $testdir/MASTERDIR]
|
|
file mkdir [set clientdir $testdir/CLIENTDIR]
|
|
|
|
# Use a small page size, so that it won't take too long to accumulate a
|
|
# large number of pages.
|
|
#
|
|
append largs " -pagesize 512"
|
|
|
|
puts "\tRep$tnum.a: Create a master and three databases."
|
|
|
|
# Note that we use a special version of the "send" call-back function
|
|
# here and in the client, during this first "set up" part of the test.
|
|
#
|
|
repladd 1
|
|
set env_cmd(M) "berkdb_env -create -txn $repmemargs $privargs \
|
|
$verbargs -home $masterdir -errpfx MASTER -rep_master"
|
|
set masterenv [eval $env_cmd(M) -rep_transport {{1 rep089_send}}]
|
|
|
|
# Create three databases. Later, we will interrupt an internal init
|
|
# during the middle of transferring pages for the second database. This
|
|
# will force the client to exercise clean-up for all three cases: a
|
|
# fully intact, already materialized database; one that's in the process
|
|
# of being materialized; and one that we haven't even touched yet (i.e.,
|
|
# totally nonexistent).
|
|
#
|
|
foreach n {1 2 3} {
|
|
rep089_make_data $masterenv test$n.db $method $niter $largs
|
|
}
|
|
|
|
# Turn off transmission limits, so that we can be sure that we're
|
|
# controlling the pace of progress through internal init from the test
|
|
# script.
|
|
#
|
|
$masterenv rep_limit 0 0
|
|
|
|
puts "\tRep$tnum.b: Create a client, and start internal init."
|
|
|
|
repladd 2
|
|
set env_cmd(C) "berkdb_env -create -txn $repmemargs $privargs \
|
|
$verbargs -home $clientdir -errpfx CLIENT -rep_client \
|
|
-rep_transport \[list 2 rep089_send\]"
|
|
set clientenv [eval $env_cmd(C)]
|
|
|
|
set envlist "{$masterenv 1} {$clientenv 2}"
|
|
|
|
# Go through just a single message processing cycle at a time, until we
|
|
# see that we've received some PAGE messages. Since we're using a
|
|
# special send() function that discards some PAGE messages, the client
|
|
# will then be left in the middle of REP_F_RECOVER_PAGE state.
|
|
#
|
|
# We want to interrupt the internal init in the middle of materializing
|
|
# the 2nd database. Note that queue databases require two PAGE_REQ
|
|
# cycles.
|
|
#
|
|
if {[is_queue $method]} {
|
|
set max_cycles 4
|
|
} else {
|
|
set max_cycles 2
|
|
}
|
|
|
|
# Do as many cycles as it takes till we see the first PAGE_REQ, then do
|
|
# enough additional cycles to bring the total page-related cycles up to
|
|
# "max_cycles". Then turn on message dropping for the following cycle.
|
|
#
|
|
global rep089_page_count
|
|
global rep089_pagereq_seen
|
|
|
|
set rep089_page_count -1
|
|
set rep089_pagereq_seen 0
|
|
while {! $rep089_pagereq_seen} {
|
|
proc_msgs_once $envlist
|
|
}
|
|
for { set i 1 } { $i < $max_cycles } { incr i } {
|
|
proc_msgs_once $envlist
|
|
}
|
|
set rep089_page_count 0
|
|
proc_msgs_once $envlist
|
|
error_check_bad assert_page_count $rep089_page_count 0
|
|
|
|
puts "\tRep$tnum.c: Restart master, to force internal init clean-up."
|
|
|
|
# Trigger an interrupted internal init clean-up, by having the master
|
|
# restart at a higher gen.
|
|
#
|
|
replclear 1
|
|
$masterenv close
|
|
set masterenv [eval $env_cmd(M) -rep_transport {{1 replsend}} -recover]
|
|
set envlist "{$masterenv 1} {$clientenv 2}"
|
|
process_msgs $envlist
|
|
|
|
# (If we get to this point without a crash, the bug has been fixed.)
|
|
|
|
puts "\tRep$tnum.d: Sanity-check the sync-interrupted stat."
|
|
|
|
set n [stat_field $clientenv mpool_stat "Number of syncs interrupted"]
|
|
error_check_good nsyncs $n 1
|
|
|
|
$clientenv close
|
|
$masterenv close
|
|
replclose $testdir/MSGQUEUEDIR
|
|
}
|
|
|
|
proc rep089_send { control rec fromid toid flags lsn } {
|
|
global rep089_page_count
|
|
global rep089_pagereq_seen
|
|
|
|
if {[berkdb msgtype $control] eq "page_req"} {
|
|
set rep089_pagereq_seen 1
|
|
} elseif {[berkdb msgtype $control] eq "page" && $rep089_page_count >= 0 } {
|
|
incr rep089_page_count
|
|
if { $rep089_page_count < 3 || $rep089_page_count > 10 } {
|
|
return 0
|
|
}
|
|
}
|
|
return [replsend $control $rec $fromid $toid $flags $lsn]
|
|
}
|
|
|
|
proc rep089_make_data { env dbname method niter largs } {
|
|
global databases_in_memory
|
|
|
|
if { $databases_in_memory } {
|
|
set dbname " {} $dbname "
|
|
}
|
|
|
|
set omethod [convert_method $method]
|
|
set db [eval berkdb_open_noerr -env $env -auto_commit\
|
|
-create -mode 0644 $omethod $largs $dbname]
|
|
|
|
# Make sure the database has at least 15 pages. That number is
|
|
# arbitrary, but it should be more than the 10 that we skip in
|
|
# rep089_send, above.
|
|
#
|
|
set page_target 15
|
|
if {[is_queue $method]} {
|
|
set descriptor "Number of pages"
|
|
} else {
|
|
set descriptor "Leaf pages"
|
|
}
|
|
set start 0
|
|
while true {
|
|
eval rep_test $omethod $env $db $niter $start 0 0 $largs
|
|
incr start $niter
|
|
|
|
set npages [stat_field $db stat $descriptor]
|
|
if {$npages >= $page_target} {
|
|
break
|
|
}
|
|
}
|
|
|
|
$db close
|
|
}
|