bdb/test/deadlock_test.rb
2009-11-24 13:29:07 -08:00

126 lines
2.5 KiB
Ruby

require File.dirname(__FILE__) + '/test_helper'
DIR = '/tmp/bdb_deadlock_test'
Bdb::Environment.config :path => DIR, :cache_size => 1 * 1024 * 1024, :page_size => 512
class DeadlockTest < Test::Unit::TestCase
def setup
FileUtils.rmtree DIR
FileUtils.mkdir DIR
Bdb::Environment[DIR].close
@db = Bdb::Database.new('foo')
end
attr_reader :db
N = 5000 # total number of records
R = 10 # number of readers
W = 10 # number of writers
T = 20 # reads per transaction
L = 100 # logging frequency
def test_detect_deadlock
pids = []
W.times do |n|
pids << fork(&writer)
end
sleep(1)
R.times do
pids << fork(&reader)
end
# Make sure that all processes finish with no errors.
pids.each do |pid|
Process.wait(pid)
assert_equal status, $?.exitstatus
end
end
C = 10
def test_detect_unclosed_resources
threads = []
threads << Thread.new do
C.times do
sleep(10)
pid = fork do
cursor = db.db.cursor(nil, 0)
cursor.get(nil, nil, Bdb::DB_FIRST)
exit!(1)
end
puts "\n====simulating exit with unclosed resources ===="
Process.wait(pid)
assert_equal 1, $?.exitstatus
end
end
threads << Thread.new do
C.times do
pid = fork(&writer(1000))
Process.wait(pid)
assert [0,9].include?($?.exitstatus)
end
end
sleep(3)
threads << Thread.new do
C.times do
pid = fork(&reader(1000))
Process.wait(pid)
assert [0,9].include?($?.exitstatus)
end
end
threads.each {|t| t.join}
end
def reader(n = N)
lambda do
T.times do
(1...n).to_a.shuffle.each_slice(T) do |ids|
db.transaction do
ids.each {|id| db.get(id)}
end
log('r')
end
end
db.close_environment
end
end
def writer(n = N)
lambda do
(1...n).to_a.shuffle.each do |id|
db.transaction do
begin
db.set(id, {:bar => "bar" * 1000 + " ayn #{rand}"})
rescue Bdb::DbError => e
if e.code == Bdb::DB_KEYEXIST
db.delete(id)
retry
else
raise(e)
end
end
end
log('w')
end
db.close_environment
end
end
def log(action)
@count ||= Hash.new(0)
if @count[action] % L == 0
print action.to_s
$stdout.flush
end
@count[action] += 1
end
end