dk-bdb 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +20 -0
- data/README.md +102 -0
- data/VERSION +1 -0
- data/examples/replication.rb +29 -0
- data/ext/bdb.c +3421 -0
- data/ext/bdb.h +104 -0
- data/ext/extconf.rb +59 -0
- data/lib/bdb/base.rb +68 -0
- data/lib/bdb/database.rb +207 -0
- data/lib/bdb/environment.rb +135 -0
- data/lib/bdb/partitioned_database.rb +74 -0
- data/lib/bdb/replication.rb +68 -0
- data/lib/bdb/result_set.rb +41 -0
- data/test/benchmark.rb +31 -0
- data/test/cursor_test.rb +150 -0
- data/test/database_test.rb +18 -0
- data/test/database_test_helper.rb +37 -0
- data/test/db_test.rb +157 -0
- data/test/deadlock_test.rb +125 -0
- data/test/env_test.rb +101 -0
- data/test/replication_test.rb +47 -0
- data/test/stat_test.rb +22 -0
- data/test/test_helper.rb +14 -0
- data/test/txn_test.rb +74 -0
- metadata +92 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
class Bdb::ResultSet
|
|
2
|
+
class LimitReached < Exception; end
|
|
3
|
+
|
|
4
|
+
def initialize(opts, &block)
|
|
5
|
+
@block = block
|
|
6
|
+
@count = 0
|
|
7
|
+
@limit = opts[:limit] || opts[:per_page]
|
|
8
|
+
@limit = @limit.to_i if @limit
|
|
9
|
+
@offset = opts[:offset] || (opts[:page] ? @limit * (opts[:page] - 1) : 0)
|
|
10
|
+
@offset = @offset.to_i if @offset
|
|
11
|
+
|
|
12
|
+
if @group = opts[:group]
|
|
13
|
+
raise 'block not supported with group' if @block
|
|
14
|
+
@results = hash_class.new
|
|
15
|
+
else
|
|
16
|
+
@results = []
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
attr_reader :count, :group, :limit, :offset, :results
|
|
20
|
+
|
|
21
|
+
def hash_class
|
|
22
|
+
@hash_class ||= defined?(ActiveSupport::OrderedHash) ? ActiveSupport::OrderedHash : Hash
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def <<(item)
|
|
26
|
+
@count += 1
|
|
27
|
+
return if count <= offset
|
|
28
|
+
|
|
29
|
+
raise LimitReached if limit and count > limit + offset
|
|
30
|
+
|
|
31
|
+
if group
|
|
32
|
+
key = item.bdb_locator_key
|
|
33
|
+
group_key = group.is_a?(Fixnum) ? key[0,group] : key
|
|
34
|
+
(results[group_key] ||= []) << item
|
|
35
|
+
elsif @block
|
|
36
|
+
@block.call(item)
|
|
37
|
+
else
|
|
38
|
+
results << item
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
data/test/benchmark.rb
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require File.dirname(__FILE__) + '/../lib/bdb/simple'
|
|
3
|
+
require 'benchmark'
|
|
4
|
+
|
|
5
|
+
N = 10_000
|
|
6
|
+
A = [5, 6, "foo", :bar, "bar", {}, :foo, [1,2,4], true, [1,2,3], false, [1], [2], nil].collect {|i| Marshal.dump(i)}
|
|
7
|
+
|
|
8
|
+
puts "compare_absolute (#{N} times)"
|
|
9
|
+
t = Benchmark.measure do
|
|
10
|
+
N.times do
|
|
11
|
+
A.sort {|a,b| Bdb::Simple.compare_absolute(Marshal.load(a), Marshal.load(b)) }
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
puts t
|
|
15
|
+
|
|
16
|
+
puts "compare_hash (#{N} times)"
|
|
17
|
+
t = Benchmark.measure do
|
|
18
|
+
N.times do
|
|
19
|
+
A.sort {|a,b| Marshal.load(a).hash <=> Marshal.load(b).hash }
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
puts t
|
|
23
|
+
|
|
24
|
+
puts "compare_raw (#{N} times)"
|
|
25
|
+
t = Benchmark.measure do
|
|
26
|
+
N.times do
|
|
27
|
+
A.sort
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
puts t
|
|
31
|
+
|
data/test/cursor_test.rb
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
class CursorTest < Test::Unit::TestCase
|
|
4
|
+
|
|
5
|
+
def setup
|
|
6
|
+
mkdir File.join(File.dirname(__FILE__), 'tmp')
|
|
7
|
+
@db = Bdb::Db.new
|
|
8
|
+
@db.open(nil, File.join(File.dirname(__FILE__), 'tmp', 'test.db'), nil, Bdb::Db::BTREE, Bdb::DB_CREATE, 0)
|
|
9
|
+
10.times { |i| @db.put(nil, i.to_s, "data-#{i}", 0)}
|
|
10
|
+
@cursor = @db.cursor(nil, 0)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def teardown
|
|
14
|
+
@cursor.close if @cursor
|
|
15
|
+
assert(@db.close(0)) if @db
|
|
16
|
+
rm_rf File.join(File.dirname(__FILE__), 'tmp')
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_get
|
|
20
|
+
key, value = @cursor.get(nil, nil, Bdb::DB_FIRST)
|
|
21
|
+
assert_equal '0', key
|
|
22
|
+
assert_equal 'data-0', value
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def test_get_range
|
|
26
|
+
keys = []
|
|
27
|
+
key, value = @cursor.get("4", nil, Bdb::DB_SET_RANGE)
|
|
28
|
+
while key and key <= "9"
|
|
29
|
+
keys << key
|
|
30
|
+
key, value = @cursor.get(nil, nil, Bdb::DB_NEXT)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
assert_equal (4..9).collect {|i| i.to_s}, keys
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def test_pget
|
|
37
|
+
@db1 = Bdb::Db.new
|
|
38
|
+
@db1.flags = Bdb::DB_DUPSORT
|
|
39
|
+
@db1.open(nil, File.join(File.dirname(__FILE__), 'tmp', 'test1.db'), nil, Bdb::Db::HASH, Bdb::DB_CREATE, 0)
|
|
40
|
+
|
|
41
|
+
@db.associate(nil, @db1, 0, proc { |sdb, key, data| key.split('-')[0] })
|
|
42
|
+
|
|
43
|
+
@db.put(nil, '1234-5678', 'data', 0)
|
|
44
|
+
@db.put(nil, '5678-1234', 'atad', 0)
|
|
45
|
+
|
|
46
|
+
@cursor1 = @db1.cursor(nil, 0)
|
|
47
|
+
key, pkey, value = @cursor1.pget(nil, nil, Bdb::DB_FIRST)
|
|
48
|
+
assert_equal '1234', key
|
|
49
|
+
assert_equal '1234-5678', pkey
|
|
50
|
+
assert_equal 'data', value
|
|
51
|
+
|
|
52
|
+
@cursor1.close
|
|
53
|
+
@db1.close(0)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def test_put
|
|
57
|
+
@cursor.put('10_000', 'data-10_000', Bdb::DB_KEYLAST)
|
|
58
|
+
value = @db.get(nil, '10_000', nil, 0)
|
|
59
|
+
assert_equal 'data-10_000', value
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def test_del
|
|
63
|
+
key, value = @cursor.get(nil, nil, Bdb::DB_FIRST)
|
|
64
|
+
value = @db.get(nil, '0', nil, 0)
|
|
65
|
+
assert_equal '0', key
|
|
66
|
+
assert_equal 'data-0', value
|
|
67
|
+
@cursor.del
|
|
68
|
+
value = @db.get(nil, '0', nil, 0)
|
|
69
|
+
assert_nil value
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def test_count
|
|
73
|
+
@cursor.get(nil, nil, Bdb::DB_FIRST)
|
|
74
|
+
assert_equal 1, @cursor.count
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def test_get_all_in_order
|
|
78
|
+
all = []
|
|
79
|
+
while pair = @cursor.get(nil, nil, Bdb::DB_NEXT)
|
|
80
|
+
all << pair.first
|
|
81
|
+
end
|
|
82
|
+
assert_equal (0..9).collect {|i| i.to_s}, all
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def test_get_all_with_btree_compare
|
|
86
|
+
@db1 = Bdb::Db.new
|
|
87
|
+
@db1.btree_compare = proc {|db, key1, key2| key2 <=> key1}
|
|
88
|
+
@db1.open(nil, File.join(File.dirname(__FILE__), 'tmp', 'test1.db'), nil, Bdb::Db::BTREE, Bdb::DB_CREATE, 0)
|
|
89
|
+
10.times { |i| @db1.put(nil, i.to_s, "data-#{i}", 0)}
|
|
90
|
+
@cursor1 = @db1.cursor(nil, 0)
|
|
91
|
+
|
|
92
|
+
all = []
|
|
93
|
+
while pair = @cursor1.get(nil, nil, Bdb::DB_NEXT)
|
|
94
|
+
all << pair.first
|
|
95
|
+
end
|
|
96
|
+
assert_equal (0..9).collect {|i| i.to_s}.reverse, all
|
|
97
|
+
@cursor1.close
|
|
98
|
+
@db1.close(0)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def test_btree_compare_raises_if_fixnum_not_returned
|
|
102
|
+
@db1 = Bdb::Db.new
|
|
103
|
+
@db1.btree_compare = proc {|db, key1, key2| key1}
|
|
104
|
+
@db1.open(nil, File.join(File.dirname(__FILE__), 'tmp', 'test1.db'), nil, Bdb::Db::BTREE, Bdb::DB_CREATE, 0)
|
|
105
|
+
|
|
106
|
+
assert_raises(TypeError) do
|
|
107
|
+
@db1.put(nil, "no", "way", 0)
|
|
108
|
+
@db1.put(nil, "ho", "say", 0)
|
|
109
|
+
end
|
|
110
|
+
@db1.close(Bdb::DB_NOSYNC)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def test_join
|
|
114
|
+
@personnel_db = Bdb::Db.new
|
|
115
|
+
@personnel_db.open(nil, File.join(File.dirname(__FILE__), 'tmp', 'personnel_db.db'), nil, Bdb::Db::HASH, Bdb::DB_CREATE, 0)
|
|
116
|
+
|
|
117
|
+
@names_db = Bdb::Db.new
|
|
118
|
+
@names_db.flags = Bdb::DB_DUPSORT
|
|
119
|
+
@names_db.open(nil, File.join(File.dirname(__FILE__), 'tmp', 'names_db.db'), nil, Bdb::Db::HASH, Bdb::DB_CREATE, 0)
|
|
120
|
+
|
|
121
|
+
@jobs_db = Bdb::Db.new
|
|
122
|
+
@jobs_db.flags = Bdb::DB_DUPSORT
|
|
123
|
+
@jobs_db.open(nil, File.join(File.dirname(__FILE__), 'tmp', 'jobs_db.db'), nil, Bdb::Db::HASH, Bdb::DB_CREATE, 0)
|
|
124
|
+
|
|
125
|
+
[{:ssn => '111-11-1111', :lastname => 'Smith', :job => 'welder'},
|
|
126
|
+
{:ssn => '222-22-2222', :lastname => 'Jones', :job => 'welder'},
|
|
127
|
+
{:ssn => '333-33-3333', :lastname => 'Smith', :job => 'painter'}].each do |e|
|
|
128
|
+
@personnel_db.put(nil, e[:ssn], Marshal.dump([e[:ssn], e[:lastname], e[:job]]), 0)
|
|
129
|
+
@names_db.put(nil, e[:lastname], e[:ssn], 0)
|
|
130
|
+
@jobs_db.put(nil, e[:job], e[:ssn], 0)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
@name_cursor = @names_db.cursor(nil, 0)
|
|
134
|
+
@name_cursor.get('Smith', nil, Bdb::DB_SET)
|
|
135
|
+
assert_equal 2, @name_cursor.count
|
|
136
|
+
@job_cursor = @jobs_db.cursor(nil, 0)
|
|
137
|
+
@job_cursor.get('welder', nil, Bdb::DB_SET)
|
|
138
|
+
assert_equal 2, @job_cursor.count
|
|
139
|
+
@personnel_cursor = @personnel_db.join([@name_cursor, @job_cursor], 0)
|
|
140
|
+
assert_equal '111-11-1111', @personnel_cursor.get(nil, nil, 0).first
|
|
141
|
+
|
|
142
|
+
@personnel_cursor.close
|
|
143
|
+
@name_cursor.close
|
|
144
|
+
@job_cursor.close
|
|
145
|
+
|
|
146
|
+
@jobs_db.close(0)
|
|
147
|
+
@names_db.close(0)
|
|
148
|
+
@personnel_db.close(0)
|
|
149
|
+
end
|
|
150
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/database_test_helper'
|
|
2
|
+
|
|
3
|
+
TMPDIR = File.dirname(__FILE__) + '/tmp'
|
|
4
|
+
FileUtils.rmtree TMPDIR
|
|
5
|
+
FileUtils.mkdir TMPDIR
|
|
6
|
+
|
|
7
|
+
class DatabaseTest < Test::Unit::TestCase
|
|
8
|
+
include DatabaseTestHelper
|
|
9
|
+
|
|
10
|
+
def setup
|
|
11
|
+
@db = Bdb::Database.new('foo', :path => TMPDIR)
|
|
12
|
+
@db.truncate!
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def teardown
|
|
16
|
+
@db.close
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
|
2
|
+
|
|
3
|
+
module DatabaseTestHelper
|
|
4
|
+
def db
|
|
5
|
+
@db
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def test_set_and_get
|
|
9
|
+
assert_equal nil, db['foo']
|
|
10
|
+
assert_equal [], db.get('foo')
|
|
11
|
+
|
|
12
|
+
db.set('foo', [1,2,3])
|
|
13
|
+
assert_equal [1,2,3], db['foo']
|
|
14
|
+
assert_equal [[1,2,3]], db.get('foo')
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def test_set_and_get_with_tuples
|
|
18
|
+
assert_equal [], db.get(['foo', 1])
|
|
19
|
+
assert_equal [], db.get(['foo', 2])
|
|
20
|
+
|
|
21
|
+
db.set(['foo', 1], [1,2,3])
|
|
22
|
+
assert_equal [[1,2,3]], db.get(['foo', 1])
|
|
23
|
+
|
|
24
|
+
db.set(['foo', 2], [3,4,5])
|
|
25
|
+
assert_equal [[3,4,5]], db.get(['foo', 2])
|
|
26
|
+
|
|
27
|
+
assert_equal [[1,2,3], [3,4,5]], db.get('foo', :partial => true)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_get_with_ranges
|
|
31
|
+
100.times do |i|
|
|
32
|
+
db.set([:foo, i], {:id => i, :type => 'foo'})
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
assert_equal (17..34).to_a, db.get([:foo, 17]..[:foo, 34]).collect {|r| r[:id]}
|
|
36
|
+
end
|
|
37
|
+
end
|
data/test/db_test.rb
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
class DbTest < Test::Unit::TestCase
|
|
4
|
+
|
|
5
|
+
def setup
|
|
6
|
+
mkdir File.join(File.dirname(__FILE__), 'tmp')
|
|
7
|
+
@db = Bdb::Db.new
|
|
8
|
+
@db.open(nil, File.join(File.dirname(__FILE__), 'tmp', 'test.db'), nil, Bdb::Db::BTREE, Bdb::DB_CREATE, 0)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def teardown
|
|
12
|
+
assert(@db.close(0)) if @db
|
|
13
|
+
rm_rf File.join(File.dirname(__FILE__), 'tmp')
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_put_and_get
|
|
17
|
+
@db.put(nil, 'key', 'data', 0)
|
|
18
|
+
result = @db.get(nil, 'key', nil, 0)
|
|
19
|
+
assert_equal 'data', result
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def test_del
|
|
23
|
+
@db.put(nil, 'key', 'data', 0)
|
|
24
|
+
result = @db.get(nil, 'key', nil, 0)
|
|
25
|
+
assert_equal 'data', result
|
|
26
|
+
@db.del(nil, 'key', 0)
|
|
27
|
+
result = @db.get(nil, 'key', nil, 0)
|
|
28
|
+
assert_nil result
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def test_flags_set_and_get
|
|
32
|
+
@db1 = Bdb::Db.new
|
|
33
|
+
@db1.flags = Bdb::DB_DUPSORT
|
|
34
|
+
assert Bdb::DB_DUPSORT, @db1.flags
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def test_associate_and_pget
|
|
38
|
+
@db1 = Bdb::Db.new
|
|
39
|
+
@db1.flags = Bdb::DB_DUPSORT
|
|
40
|
+
@db1.open(nil, File.join(File.dirname(__FILE__), 'tmp', 'test1.db'), nil, Bdb::Db::HASH, Bdb::DB_CREATE, 0)
|
|
41
|
+
|
|
42
|
+
@db.associate(nil, @db1, 0, proc { |sdb, key, data| key.split('-')[0] })
|
|
43
|
+
|
|
44
|
+
@db.put(nil, '1234-5678', 'data', 0)
|
|
45
|
+
@db.put(nil, '5678-1234', 'atad', 0)
|
|
46
|
+
|
|
47
|
+
result = @db.get(nil, '1234-5678', nil, 0)
|
|
48
|
+
assert_equal 'data', result
|
|
49
|
+
result = @db1.get(nil, '5678', nil, 0)
|
|
50
|
+
assert_equal 'atad', result
|
|
51
|
+
|
|
52
|
+
result = @db1.pget(nil, '1234', nil, 0)
|
|
53
|
+
assert_equal ['1234-5678', 'data'], result
|
|
54
|
+
|
|
55
|
+
@db1.close(0)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def test_associate_with_multiple_keys
|
|
59
|
+
@db1 = Bdb::Db.new
|
|
60
|
+
@db1.flags = Bdb::DB_DUPSORT
|
|
61
|
+
@db1.open(nil, File.join(File.dirname(__FILE__), 'tmp', 'test1.db'), nil, Bdb::Db::HASH, Bdb::DB_CREATE, 0)
|
|
62
|
+
|
|
63
|
+
@db.associate(nil, @db1, 0, proc { |sdb, key, data| key.split('-') })
|
|
64
|
+
|
|
65
|
+
@db.put(nil, '1234-5678', 'data', 0)
|
|
66
|
+
@db.put(nil, '8765-4321', 'atad', 0)
|
|
67
|
+
|
|
68
|
+
result = @db.get(nil, '1234-5678', nil, 0)
|
|
69
|
+
assert_equal 'data', result
|
|
70
|
+
result = @db1.get(nil, '5678', nil, 0)
|
|
71
|
+
assert_equal 'data', result
|
|
72
|
+
result = @db1.get(nil, '1234', nil, 0)
|
|
73
|
+
assert_equal 'data', result
|
|
74
|
+
result = @db1.get(nil, '8765', nil, 0)
|
|
75
|
+
assert_equal 'atad', result
|
|
76
|
+
result = @db1.get(nil, '4321', nil, 0)
|
|
77
|
+
assert_equal 'atad', result
|
|
78
|
+
|
|
79
|
+
@db1.close(0)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def test_aset_and_aget
|
|
83
|
+
@db['key'] = 'data'
|
|
84
|
+
result = @db.get(nil, 'key', nil, 0)
|
|
85
|
+
assert_equal 'data', result
|
|
86
|
+
result = @db['key']
|
|
87
|
+
assert_equal 'data', result
|
|
88
|
+
@db['key'] = 'data1'
|
|
89
|
+
result = @db['key']
|
|
90
|
+
assert_equal 'data1', result
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def test_get_byteswapped
|
|
94
|
+
@db.get_byteswapped
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def test_get_type
|
|
98
|
+
assert_equal Bdb::Db::BTREE, @db.get_type
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def test_remove
|
|
102
|
+
@db1 = Bdb::Db.new
|
|
103
|
+
@db1.open(nil, File.join(File.dirname(__FILE__), 'tmp', 'other_test.db'), nil, Bdb::Db::BTREE, Bdb::DB_CREATE, 0)
|
|
104
|
+
@db1.close(0)
|
|
105
|
+
Bdb::Db.new.remove(File.join(File.dirname(__FILE__), 'tmp', 'other_test.db'), nil, 0)
|
|
106
|
+
assert !File.exists?(File.join(File.dirname(__FILE__), 'tmp', 'other_test.db'))
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def test_key_range
|
|
110
|
+
10.times { |i| @db.put(nil, i.to_s, 'data', 0) }
|
|
111
|
+
@db.key_range(nil, '2', 0)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def test_rename
|
|
115
|
+
@db1 = Bdb::Db.new
|
|
116
|
+
@db1.open(nil, File.join(File.dirname(__FILE__), 'tmp', 'other_test.db'), nil, Bdb::Db::BTREE, Bdb::DB_CREATE, 0)
|
|
117
|
+
@db1.close(0)
|
|
118
|
+
assert Bdb::Db.new.rename(File.join(File.dirname(__FILE__), 'tmp', 'other_test.db'), nil, File.join(File.dirname(__FILE__), 'tmp', 'other2_test.db'), 0)
|
|
119
|
+
assert File.exists?(File.join(File.dirname(__FILE__), 'tmp', 'other2_test.db'))
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def test_pagesize_get_and_set
|
|
123
|
+
@db1 = Bdb::Db.new
|
|
124
|
+
@db1.pagesize = 1024
|
|
125
|
+
assert_equal 1024, @db1.pagesize
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def test_h_ffactor_get_and_set
|
|
129
|
+
@db1 = Bdb::Db.new
|
|
130
|
+
@db1.h_ffactor = 5
|
|
131
|
+
assert_equal 5, @db1.h_ffactor
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def test_h_nelem_get_and_set
|
|
135
|
+
@db1 = Bdb::Db.new
|
|
136
|
+
@db1.h_nelem = 10_000
|
|
137
|
+
assert_equal 10_000, @db1.h_nelem
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def test_sync
|
|
141
|
+
assert @db.sync
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def test_truncate
|
|
145
|
+
@db.put(nil, 'key', 'data', 0)
|
|
146
|
+
result = @db.get(nil, 'key', nil, 0)
|
|
147
|
+
assert_equal 'data', result
|
|
148
|
+
@db.truncate(nil)
|
|
149
|
+
result = @db.get(nil, 'key', nil, 0)
|
|
150
|
+
assert_nil result
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def test_compact
|
|
154
|
+
assert @db.compact(nil, nil, nil, nil, 0)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
end
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
|
2
|
+
|
|
3
|
+
DIR = '/tmp/bdb_deadlock_test'
|
|
4
|
+
Bdb::Environment.config :path => DIR, :cache_size => 1 * 1024 * 1024, :page_size => 512
|
|
5
|
+
|
|
6
|
+
class DeadlockTest < Test::Unit::TestCase
|
|
7
|
+
def setup
|
|
8
|
+
FileUtils.rmtree DIR
|
|
9
|
+
FileUtils.mkdir DIR
|
|
10
|
+
Bdb::Environment[DIR].close
|
|
11
|
+
@db = Bdb::Database.new('foo')
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
attr_reader :db
|
|
15
|
+
|
|
16
|
+
N = 5000 # total number of records
|
|
17
|
+
R = 10 # number of readers
|
|
18
|
+
W = 10 # number of writers
|
|
19
|
+
T = 20 # reads per transaction
|
|
20
|
+
L = 100 # logging frequency
|
|
21
|
+
|
|
22
|
+
def test_detect_deadlock
|
|
23
|
+
pids = []
|
|
24
|
+
|
|
25
|
+
W.times do |n|
|
|
26
|
+
pids << fork(&writer)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
sleep(1)
|
|
30
|
+
|
|
31
|
+
R.times do
|
|
32
|
+
pids << fork(&reader)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Make sure that all processes finish with no errors.
|
|
36
|
+
pids.each do |pid|
|
|
37
|
+
Process.wait(pid)
|
|
38
|
+
assert_equal status, $?.exitstatus
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
C = 10
|
|
43
|
+
def test_detect_unclosed_resources
|
|
44
|
+
threads = []
|
|
45
|
+
|
|
46
|
+
threads << Thread.new do
|
|
47
|
+
C.times do
|
|
48
|
+
sleep(10)
|
|
49
|
+
|
|
50
|
+
pid = fork do
|
|
51
|
+
cursor = db.db.cursor(nil, 0)
|
|
52
|
+
cursor.get(nil, nil, Bdb::DB_FIRST)
|
|
53
|
+
exit!(1)
|
|
54
|
+
end
|
|
55
|
+
puts "\n====simulating exit with unclosed resources ===="
|
|
56
|
+
Process.wait(pid)
|
|
57
|
+
assert_equal 1, $?.exitstatus
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
threads << Thread.new do
|
|
62
|
+
C.times do
|
|
63
|
+
pid = fork(&writer(1000))
|
|
64
|
+
Process.wait(pid)
|
|
65
|
+
assert [0,9].include?($?.exitstatus)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
sleep(3)
|
|
70
|
+
|
|
71
|
+
threads << Thread.new do
|
|
72
|
+
C.times do
|
|
73
|
+
pid = fork(&reader(1000))
|
|
74
|
+
Process.wait(pid)
|
|
75
|
+
assert [0,9].include?($?.exitstatus)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
threads.each {|t| t.join}
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def reader(n = N)
|
|
83
|
+
lambda do
|
|
84
|
+
T.times do
|
|
85
|
+
(1...n).to_a.shuffle.each_slice(T) do |ids|
|
|
86
|
+
db.transaction do
|
|
87
|
+
ids.each {|id| db.get(id)}
|
|
88
|
+
end
|
|
89
|
+
log('r')
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
db.close_environment
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def writer(n = N)
|
|
97
|
+
lambda do
|
|
98
|
+
(1...n).to_a.shuffle.each do |id|
|
|
99
|
+
db.transaction do
|
|
100
|
+
begin
|
|
101
|
+
db.set(id, {:bar => "bar" * 1000 + " ayn #{rand}"})
|
|
102
|
+
rescue Bdb::DbError => e
|
|
103
|
+
if e.code == Bdb::DB_KEYEXIST
|
|
104
|
+
db.delete(id)
|
|
105
|
+
retry
|
|
106
|
+
else
|
|
107
|
+
raise(e)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
log('w')
|
|
112
|
+
end
|
|
113
|
+
db.close_environment
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def log(action)
|
|
118
|
+
@count ||= Hash.new(0)
|
|
119
|
+
if @count[action] % L == 0
|
|
120
|
+
print action.to_s
|
|
121
|
+
$stdout.flush
|
|
122
|
+
end
|
|
123
|
+
@count[action] += 1
|
|
124
|
+
end
|
|
125
|
+
end
|
data/test/env_test.rb
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
class EnvTest < Test::Unit::TestCase
|
|
4
|
+
|
|
5
|
+
def test_cachesize
|
|
6
|
+
env = Bdb::Env.new(0)
|
|
7
|
+
env.cachesize = 1024*1024*500
|
|
8
|
+
assert_equal 1024*1024*500, env.cachesize
|
|
9
|
+
|
|
10
|
+
env.cachesize = 1024*1024*1024*3
|
|
11
|
+
assert_equal 1024*1024*1024*3, env.cachesize
|
|
12
|
+
|
|
13
|
+
env.cachesize = 1024*1024*1024*3+1
|
|
14
|
+
assert_equal 1024*1024*1024*3+1, env.cachesize
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def test_flags
|
|
18
|
+
env = Bdb::Env.new(0)
|
|
19
|
+
|
|
20
|
+
env.flags_on = Bdb::DB_AUTO_COMMIT | Bdb::DB_DSYNC_DB
|
|
21
|
+
assert_equal Bdb::DB_AUTO_COMMIT | Bdb::DB_DSYNC_DB, env.flags
|
|
22
|
+
|
|
23
|
+
env.flags_off = Bdb::DB_AUTO_COMMIT | Bdb::DB_DSYNC_DB
|
|
24
|
+
assert_equal 0, env.flags
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def test_list_dbs
|
|
28
|
+
env = Bdb::Env.new(0)
|
|
29
|
+
assert env.list_dbs.empty?
|
|
30
|
+
|
|
31
|
+
db = env.db
|
|
32
|
+
assert_equal db, env.list_dbs.first
|
|
33
|
+
db.close(0)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def test_set_and_get_timeout
|
|
37
|
+
env = Bdb::Env.new(0)
|
|
38
|
+
env.set_timeout(10, Bdb::DB_SET_LOCK_TIMEOUT)
|
|
39
|
+
assert_equal 10, env.get_timeout(Bdb::DB_SET_LOCK_TIMEOUT)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def test_set_and_get_tx_max
|
|
43
|
+
env = Bdb::Env.new(0)
|
|
44
|
+
env.set_tx_max(100)
|
|
45
|
+
assert_equal 100, env.get_tx_max
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def test_set_and_get_lk_detect
|
|
49
|
+
env = Bdb::Env.new(0)
|
|
50
|
+
env.set_lk_detect(Bdb::DB_LOCK_MAXWRITE)
|
|
51
|
+
assert_equal Bdb::DB_LOCK_MAXWRITE, env.get_lk_detect
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def test_set_and_get_lk_max_locks
|
|
55
|
+
env = Bdb::Env.new(0)
|
|
56
|
+
env.set_lk_max_locks(10_000)
|
|
57
|
+
assert_equal 10_000, env.get_lk_max_locks
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def test_set_and_get_lk_max_objects
|
|
61
|
+
env = Bdb::Env.new(0)
|
|
62
|
+
env.set_lk_max_objects(10_000)
|
|
63
|
+
assert_equal 10_000, env.get_lk_max_objects
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def test_set_and_get_shm_key
|
|
67
|
+
env = Bdb::Env.new(0)
|
|
68
|
+
env.set_shm_key(2506400)
|
|
69
|
+
assert_equal 2506400, env.get_shm_key
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def test_set_and_get_data_dir
|
|
73
|
+
env = Bdb::Env.new(0)
|
|
74
|
+
env.set_data_dir('/tmp')
|
|
75
|
+
assert_equal ['/tmp'], env.get_data_dirs
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def test_set_lg_dir
|
|
79
|
+
env = Bdb::Env.new(0)
|
|
80
|
+
env.set_lg_dir('/tmp')
|
|
81
|
+
assert_equal '/tmp', env.get_lg_dir
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def test_set_tmp_dir
|
|
85
|
+
env = Bdb::Env.new(0)
|
|
86
|
+
env.set_tmp_dir('/tmp')
|
|
87
|
+
assert_equal '/tmp', env.get_tmp_dir
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def test_get_home
|
|
91
|
+
env = Bdb::Env.new(0)
|
|
92
|
+
tmp_dir = File.expand_path(File.join(File.dirname(__FILE__), 'tmp'))
|
|
93
|
+
mkdir_p tmp_dir
|
|
94
|
+
env.open(tmp_dir, Bdb::DB_CREATE, 0);
|
|
95
|
+
assert_equal tmp_dir, env.get_home
|
|
96
|
+
env.close
|
|
97
|
+
ensure
|
|
98
|
+
rm_rf tmp_dir
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/database_test_helper'
|
|
2
|
+
|
|
3
|
+
MASTER_DIR = '/tmp/bdb_rep_test_master'
|
|
4
|
+
CLIENT_DIR = '/tmp/bdb_rep_test_client'
|
|
5
|
+
FileUtils.rmtree MASTER_DIR; FileUtils.mkdir MASTER_DIR;
|
|
6
|
+
FileUtils.rmtree CLIENT_DIR; FileUtils.mkdir CLIENT_DIR
|
|
7
|
+
|
|
8
|
+
MASTER = 'localhost:8888'
|
|
9
|
+
CLIENT = 'localhost:8889'
|
|
10
|
+
|
|
11
|
+
N = 100
|
|
12
|
+
|
|
13
|
+
class ReplicationTest < Test::Unit::TestCase
|
|
14
|
+
def setup
|
|
15
|
+
Bdb::Environment.replicate CLIENT_DIR, :from => MASTER, :to => CLIENT, :host => CLIENT #, :verbose => true
|
|
16
|
+
|
|
17
|
+
@pid = Process.fork do
|
|
18
|
+
Bdb::Environment.replicate MASTER_DIR, :from => MASTER, :to => CLIENT, :host => MASTER #, :verbose => true
|
|
19
|
+
db = Bdb::Database.new('foo', :path => MASTER_DIR)
|
|
20
|
+
|
|
21
|
+
N.times do |i|
|
|
22
|
+
db.set(i, i + 1)
|
|
23
|
+
log "m"
|
|
24
|
+
sleep 0.1
|
|
25
|
+
end
|
|
26
|
+
sleep 10
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def teardown
|
|
31
|
+
Process.kill(9, @pid)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def test_single_process_replication
|
|
35
|
+
db = Bdb::Database.new('foo', :path => CLIENT_DIR)
|
|
36
|
+
N.times do |i|
|
|
37
|
+
sleep 0.2
|
|
38
|
+
assert_equal i + 1, db[i]
|
|
39
|
+
log "c"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def log(action)
|
|
44
|
+
print action
|
|
45
|
+
$stdout.flush
|
|
46
|
+
end
|
|
47
|
+
end
|