higgs 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +208 -0
- data/LICENSE +26 -0
- data/README +2 -0
- data/Rakefile +75 -0
- data/bin/higgs_backup +67 -0
- data/bin/higgs_dump_index +43 -0
- data/bin/higgs_dump_jlog +42 -0
- data/bin/higgs_verify +37 -0
- data/lib/cgi/session/higgs.rb +72 -0
- data/lib/higgs/block.rb +192 -0
- data/lib/higgs/cache.rb +117 -0
- data/lib/higgs/dbm.rb +55 -0
- data/lib/higgs/exceptions.rb +31 -0
- data/lib/higgs/flock.rb +77 -0
- data/lib/higgs/index.rb +164 -0
- data/lib/higgs/jlog.rb +159 -0
- data/lib/higgs/lock.rb +189 -0
- data/lib/higgs/storage.rb +1086 -0
- data/lib/higgs/store.rb +228 -0
- data/lib/higgs/tar.rb +390 -0
- data/lib/higgs/thread.rb +370 -0
- data/lib/higgs/tman.rb +513 -0
- data/lib/higgs/utils/bman.rb +285 -0
- data/lib/higgs/utils.rb +22 -0
- data/lib/higgs/version.rb +21 -0
- data/lib/higgs.rb +59 -0
- data/misc/cache_bench/cache_bench.rb +43 -0
- data/misc/dbm_bench/.strc +8 -0
- data/misc/dbm_bench/Rakefile +78 -0
- data/misc/dbm_bench/dbm_multi_thread.rb +199 -0
- data/misc/dbm_bench/dbm_rnd_delete.rb +43 -0
- data/misc/dbm_bench/dbm_rnd_read.rb +44 -0
- data/misc/dbm_bench/dbm_rnd_update.rb +44 -0
- data/misc/dbm_bench/dbm_seq_read.rb +45 -0
- data/misc/dbm_bench/dbm_seq_write.rb +44 -0
- data/misc/dbm_bench/st_verify.rb +28 -0
- data/misc/io_bench/cksum_bench.rb +48 -0
- data/misc/io_bench/jlog_bench.rb +71 -0
- data/misc/io_bench/write_bench.rb +128 -0
- data/misc/thread_bench/lock_bench.rb +132 -0
- data/mkrdoc.rb +8 -0
- data/rdoc.yml +13 -0
- data/sample/count.rb +60 -0
- data/sample/dbmtest.rb +38 -0
- data/test/Rakefile +45 -0
- data/test/run.rb +32 -0
- data/test/test_block.rb +163 -0
- data/test/test_cache.rb +214 -0
- data/test/test_cgi_session.rb +142 -0
- data/test/test_flock.rb +162 -0
- data/test/test_index.rb +258 -0
- data/test/test_jlog.rb +180 -0
- data/test/test_lock.rb +320 -0
- data/test/test_online_backup.rb +169 -0
- data/test/test_storage.rb +439 -0
- data/test/test_storage_conf.rb +202 -0
- data/test/test_storage_init_opts.rb +89 -0
- data/test/test_store.rb +211 -0
- data/test/test_tar.rb +432 -0
- data/test/test_thread.rb +541 -0
- data/test/test_tman.rb +875 -0
- data/test/test_tman_init_opts.rb +56 -0
- data/test/test_utils_bman.rb +234 -0
- metadata +115 -0
@@ -0,0 +1,132 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
|
3
|
+
# for ident(1)
|
4
|
+
CVS_ID = '$Id: lock_bench.rb 559 2007-09-25 15:20:20Z toki $'
|
5
|
+
|
6
|
+
$: << File.join(File.dirname($0), '..', '..', 'lib')
|
7
|
+
|
8
|
+
require 'benchmark'
|
9
|
+
require 'higgs/thread'
|
10
|
+
require 'monitor'
|
11
|
+
require 'sync'
|
12
|
+
require 'thread'
|
13
|
+
|
14
|
+
loop_count = (ARGV.shift || '1000').to_i
|
15
|
+
thread_count = (ARGV.shift || '10').to_i
|
16
|
+
puts "#{$0}: LOOP:#{loop_count}, THREAD:#{thread_count}"
|
17
|
+
|
18
|
+
Benchmark.bm(30) do |x|
|
19
|
+
[ [ Mutex.new, 'Mutex' ],
|
20
|
+
[ Monitor.new, 'Monitor' ],
|
21
|
+
[ Higgs::ReadWriteLock.new.read_lock, 'ReadWriteLock (read:M)' ],
|
22
|
+
[ Higgs::ReadWriteLock.new.write_lock, 'ReadWriteLock (write:M)' ]
|
23
|
+
].each do |m, name|
|
24
|
+
barrier = Higgs::Barrier.new(thread_count + 1)
|
25
|
+
th_grp = ThreadGroup.new
|
26
|
+
thread_count.times do
|
27
|
+
th_grp.add Thread.new{
|
28
|
+
barrier.wait
|
29
|
+
loop_count.times do
|
30
|
+
m.synchronize{
|
31
|
+
# nothing to do.
|
32
|
+
}
|
33
|
+
end
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
x.report(name) {
|
38
|
+
barrier.wait
|
39
|
+
for t in th_grp.list
|
40
|
+
t.join
|
41
|
+
end
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
r_lock, w_lock = Higgs::ReadWriteLock.new.to_a
|
46
|
+
barrier = Higgs::Barrier.new(thread_count + 1)
|
47
|
+
th_grp = ThreadGroup.new
|
48
|
+
(thread_count - 1).times do
|
49
|
+
th_grp.add Thread.new{
|
50
|
+
barrier.wait
|
51
|
+
loop_count.times do
|
52
|
+
r_lock.synchronize{
|
53
|
+
# nothing to do.
|
54
|
+
}
|
55
|
+
end
|
56
|
+
}
|
57
|
+
end
|
58
|
+
th_grp.add Thread.new{
|
59
|
+
barrier.wait
|
60
|
+
loop_count.times do
|
61
|
+
w_lock.synchronize{
|
62
|
+
# nothing to do.
|
63
|
+
}
|
64
|
+
end
|
65
|
+
}
|
66
|
+
|
67
|
+
x.report('ReadWriteLock (read:M/write:1)') {
|
68
|
+
barrier.wait
|
69
|
+
for t in th_grp.list
|
70
|
+
t.join
|
71
|
+
end
|
72
|
+
}
|
73
|
+
|
74
|
+
[ [ Sync::SH, 'Sync (read:M)' ],
|
75
|
+
[ Sync::EX, 'Sync (write:M)' ]
|
76
|
+
].each do |mode, name|
|
77
|
+
s = Sync.new
|
78
|
+
barrier = Higgs::Barrier.new(thread_count + 1)
|
79
|
+
th_grp = ThreadGroup.new
|
80
|
+
thread_count.times do
|
81
|
+
th_grp.add Thread.new{
|
82
|
+
barrier.wait
|
83
|
+
loop_count.times do
|
84
|
+
s.synchronize(mode) {
|
85
|
+
# nothing to do.
|
86
|
+
}
|
87
|
+
end
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
x.report(name) {
|
92
|
+
barrier.wait
|
93
|
+
for t in th_grp.list
|
94
|
+
t.join
|
95
|
+
end
|
96
|
+
}
|
97
|
+
end
|
98
|
+
|
99
|
+
s = Sync.new
|
100
|
+
barrier = Higgs::Barrier.new(thread_count + 1)
|
101
|
+
th_grp = ThreadGroup.new
|
102
|
+
(thread_count - 1).times do
|
103
|
+
th_grp.add Thread.new{
|
104
|
+
barrier.wait
|
105
|
+
loop_count.times do
|
106
|
+
s.synchronize(Sync::SH) {
|
107
|
+
# nothing to do.
|
108
|
+
}
|
109
|
+
end
|
110
|
+
}
|
111
|
+
end
|
112
|
+
th_grp.add Thread.new{
|
113
|
+
barrier.wait
|
114
|
+
loop_count.times do
|
115
|
+
s.synchronize(Sync::EX) {
|
116
|
+
# nothing to do.
|
117
|
+
}
|
118
|
+
end
|
119
|
+
}
|
120
|
+
|
121
|
+
x.report('Sync (read:M/write:1)') {
|
122
|
+
barrier.wait
|
123
|
+
for t in th_grp.list
|
124
|
+
t.join
|
125
|
+
end
|
126
|
+
}
|
127
|
+
end
|
128
|
+
|
129
|
+
# Local Variables:
|
130
|
+
# mode: Ruby
|
131
|
+
# indent-tabs-mode: nil
|
132
|
+
# End:
|
data/mkrdoc.rb
ADDED
data/rdoc.yml
ADDED
data/sample/count.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
|
3
|
+
require 'higgs'
|
4
|
+
require 'higgs/thread' # for Higgs::Barrier
|
5
|
+
|
6
|
+
num_of_write_threads = (ARGV.shift || '10').to_i
|
7
|
+
num_of_count = (ARGV.shift || '100').to_i
|
8
|
+
|
9
|
+
Higgs::Store.open('count') {|st|
|
10
|
+
st.transaction(true) {|tx|
|
11
|
+
puts "start - #{Time.now}"
|
12
|
+
p tx[:count]
|
13
|
+
puts ''
|
14
|
+
}
|
15
|
+
|
16
|
+
th_grp = ThreadGroup.new
|
17
|
+
barrier = Higgs::Barrier.new(num_of_write_threads + 2)
|
18
|
+
is_print = true
|
19
|
+
|
20
|
+
num_of_write_threads.times do
|
21
|
+
th_grp.add Thread.new{
|
22
|
+
barrier.wait
|
23
|
+
num_of_count.times do
|
24
|
+
st.transaction{|tx|
|
25
|
+
tx[:count] = 0 unless (tx.key? :count)
|
26
|
+
tx[:count] += 1
|
27
|
+
}
|
28
|
+
end
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
th_read = Thread.new{
|
33
|
+
barrier.wait
|
34
|
+
while (is_print)
|
35
|
+
st.transaction(true) {|tx|
|
36
|
+
p tx[:count]
|
37
|
+
}
|
38
|
+
sleep(0.1)
|
39
|
+
end
|
40
|
+
}
|
41
|
+
|
42
|
+
barrier.wait
|
43
|
+
for t in th_grp.list
|
44
|
+
t.join
|
45
|
+
end
|
46
|
+
|
47
|
+
is_print = false
|
48
|
+
th_read.join
|
49
|
+
|
50
|
+
st.transaction(true) {|tx|
|
51
|
+
puts ''
|
52
|
+
puts "last - #{Time.now}"
|
53
|
+
p tx[:count]
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
# Local Variables:
|
58
|
+
# mode: Ruby
|
59
|
+
# indent-tabs-mode: nil
|
60
|
+
# End:
|
data/sample/dbmtest.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
|
3
|
+
require 'higgs'
|
4
|
+
|
5
|
+
Higgs::DBM.open('test') {|dbm|
|
6
|
+
dbm.transaction{|tx|
|
7
|
+
keys = tx.keys
|
8
|
+
if (keys.length > 0) then
|
9
|
+
for k in keys
|
10
|
+
puts "-"
|
11
|
+
puts "key: #{k}"
|
12
|
+
puts "value: #{tx[k]}"
|
13
|
+
tx.each_property(k) do |name, value|
|
14
|
+
case (name)
|
15
|
+
when Symbol
|
16
|
+
puts "system_property[#{name}]: #{value}"
|
17
|
+
when String
|
18
|
+
puts "custom_property[#{name}]: #{value}"
|
19
|
+
else
|
20
|
+
raise "unexpected property name: #{name}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
else
|
25
|
+
tx['foobar'] = 'FB'
|
26
|
+
tx.set_property('foobar', 'number', 0)
|
27
|
+
tx['baz'] = 'BZ'
|
28
|
+
tx.set_property('baz', 'number', 1)
|
29
|
+
tx['quux'] = 'QX'
|
30
|
+
tx.set_property('quux', 'number', 2)
|
31
|
+
end
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
# Local Variables:
|
36
|
+
# mode: Ruby
|
37
|
+
# indent-tabs-mode: nil
|
38
|
+
# End:
|
data/test/Rakefile
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# for ident(1)
|
2
|
+
CVS_ID = '$Id: Rakefile 561 2007-09-26 15:46:49Z toki $'
|
3
|
+
|
4
|
+
LIB_DIR = File.join(File.dirname(__FILE__), '..', 'lib')
|
5
|
+
RCOV_DIR = File.join(File.dirname(__FILE__), 'coverage')
|
6
|
+
|
7
|
+
task :default => [ :test ]
|
8
|
+
|
9
|
+
task :test do
|
10
|
+
ruby '-I', LIB_DIR, 'run.rb'
|
11
|
+
end
|
12
|
+
|
13
|
+
task :rcov do
|
14
|
+
rm_rf RCOV_DIR
|
15
|
+
sh 'rcov', '-I', LIB_DIR, '-x', 'rcov\.rb,run\.rb', 'run.rb'
|
16
|
+
end
|
17
|
+
|
18
|
+
task :optional do
|
19
|
+
for opt_rb in Dir['optional/*.rb']
|
20
|
+
symlnk_rb = File.basename(opt_rb)
|
21
|
+
unless (File.symlink? symlnk_rb) then
|
22
|
+
ln_s opt_rb, symlnk_rb, :verbose => true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
task :clean do
|
28
|
+
rm_rf RCOV_DIR
|
29
|
+
end
|
30
|
+
|
31
|
+
task :clean_optional do
|
32
|
+
for opt_rb in Dir['optional/*.rb']
|
33
|
+
symlnk_rb = File.basename(opt_rb)
|
34
|
+
rm_f symlnk_rb
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
rule '.test' => [ '.rb' ] do |t|
|
39
|
+
ruby '-I', LIB_DIR, 'run.rb', '^' + Regexp.quote(t.source) + '$'
|
40
|
+
end
|
41
|
+
|
42
|
+
# Local Variables:
|
43
|
+
# mode: Ruby
|
44
|
+
# indent-tabs-mode: nil
|
45
|
+
# End:
|
data/test/run.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
|
3
|
+
$: << File.dirname(__FILE__)
|
4
|
+
$: << File.join(File.dirname(__FILE__), '..', 'lib')
|
5
|
+
|
6
|
+
# for ident(1)
|
7
|
+
CVS_ID = '$Id: run.rb 575 2007-09-29 08:13:51Z toki $'
|
8
|
+
|
9
|
+
mask = // # any match
|
10
|
+
if ($0 == __FILE__) then
|
11
|
+
if (ARGV.length > 0 && ARGV[0] !~ /^-/) then
|
12
|
+
mask = Regexp.compile(ARGV.shift)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
test_dir, this_name = File.split(__FILE__)
|
17
|
+
for test_rb in Dir.entries(test_dir).sort
|
18
|
+
case (test_rb)
|
19
|
+
when this_name
|
20
|
+
# skip
|
21
|
+
when /^test_.*\.rb$/
|
22
|
+
if (test_rb =~ mask) then
|
23
|
+
puts "load #{test_rb}"
|
24
|
+
require File.join(test_dir, test_rb)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Local Variables:
|
30
|
+
# mode: Ruby
|
31
|
+
# indent-tabs-mode: nil
|
32
|
+
# End:
|
data/test/test_block.rb
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
|
3
|
+
require 'digest/sha2'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'higgs/block'
|
6
|
+
require 'test/unit'
|
7
|
+
|
8
|
+
module Higgs::Test
|
9
|
+
class BlockTest < Test::Unit::TestCase
|
10
|
+
include Higgs::Block
|
11
|
+
|
12
|
+
# for ident(1)
|
13
|
+
CVS_ID = '$Id: test_block.rb 559 2007-09-25 15:20:20Z toki $'
|
14
|
+
|
15
|
+
def setup
|
16
|
+
@io = File.open('block.test_io', 'w+')
|
17
|
+
@io.binmode
|
18
|
+
end
|
19
|
+
|
20
|
+
def teardown
|
21
|
+
@io.close unless @io.closed?
|
22
|
+
FileUtils.rm_f('block.test_io')
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_single_head_write_read
|
26
|
+
body = 'foo'
|
27
|
+
body_cksum_bin = Digest::SHA512.digest(body)
|
28
|
+
head_write(@io, 'FOO', body.length, 'SHA512', body_cksum_bin)
|
29
|
+
|
30
|
+
@io.seek(0)
|
31
|
+
r = head_read(@io, 'FOO')
|
32
|
+
assert_equal(body.length, r[0])
|
33
|
+
assert_equal('SHA512', r[1])
|
34
|
+
assert_equal(body_cksum_bin, r[2])
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_single_block_write_read
|
38
|
+
body = 'foo'
|
39
|
+
block_write(@io, 'FOO', body)
|
40
|
+
|
41
|
+
@io.seek(0)
|
42
|
+
assert_equal(body, block_read(@io, 'FOO'))
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_many_block_write_read
|
46
|
+
data_list = (0..12).map{|i| 'Z' * 2**i }.map{|s| [ s[0..-2], s, s + 'Z' ] }.flatten
|
47
|
+
for s in data_list
|
48
|
+
block_write(@io, 'FOO', s)
|
49
|
+
end
|
50
|
+
|
51
|
+
i = 0
|
52
|
+
@io.seek(0)
|
53
|
+
while (s = block_read(@io, 'FOO'))
|
54
|
+
assert(! data_list.empty?, "nth:#{i}")
|
55
|
+
assert_equal(data_list.shift, s)
|
56
|
+
end
|
57
|
+
assert(data_list.empty?)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_empty_read
|
61
|
+
assert_nil(head_read(@io, 'FOO'))
|
62
|
+
assert_nil(block_read(@io, 'FOO'))
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_head_read_BrokenError_short_read
|
66
|
+
@io.write("\x00")
|
67
|
+
@io.seek(0)
|
68
|
+
assert_raise(BrokenError) {
|
69
|
+
head_read(@io, 'FOO')
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_head_read_BrokenError_broken_head_block
|
74
|
+
body = 'foo'
|
75
|
+
body_cksum_bin = Digest::SHA512.digest(body)
|
76
|
+
head_write(@io, 'FOO', body.length, 'SHA512', body_cksum_bin)
|
77
|
+
|
78
|
+
@io.seek(511)
|
79
|
+
@io.write("\xFF")
|
80
|
+
@io.seek(0)
|
81
|
+
|
82
|
+
assert_raise(BrokenError) {
|
83
|
+
head_read(@io, 'FOO')
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_head_read_BrokenError_unknown_magic_symbol
|
88
|
+
body = 'foo'
|
89
|
+
body_cksum_bin = Digest::SHA512.digest(body)
|
90
|
+
head_write(@io, 'BAR', body.length, 'SHA512', body_cksum_bin)
|
91
|
+
@io.seek(0)
|
92
|
+
|
93
|
+
assert_raise(BrokenError) {
|
94
|
+
head_read(@io, 'FOO')
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_block_read_BrokenError_short_unexpected_EOF_1
|
99
|
+
block_write(@io, 'FOO', 'foo')
|
100
|
+
@io.truncate(512)
|
101
|
+
@io.seek(0)
|
102
|
+
assert_raise(BrokenError) {
|
103
|
+
block_read(@io, 'FOO')
|
104
|
+
}
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_block_read_BrokenError_short_read_1
|
108
|
+
block_write(@io, 'FOO', 'foo')
|
109
|
+
@io.truncate(513)
|
110
|
+
@io.seek(0)
|
111
|
+
assert_raise(BrokenError) {
|
112
|
+
block_read(@io, 'FOO')
|
113
|
+
}
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_block_read_BrokenError_short_unexpected_EOF_2
|
117
|
+
block_write(@io, 'FOO', 'foo')
|
118
|
+
@io.truncate(515)
|
119
|
+
@io.seek(0)
|
120
|
+
assert_raise(BrokenError) {
|
121
|
+
block_read(@io, 'FOO')
|
122
|
+
}
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_block_read_BrokenError_short_read_2
|
126
|
+
block_write(@io, 'FOO', 'foo')
|
127
|
+
@io.truncate(1023)
|
128
|
+
@io.seek(0)
|
129
|
+
assert_raise(BrokenError) {
|
130
|
+
block_read(@io, 'FOO')
|
131
|
+
}
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_block_read_BrokenError_unknown_body_cksum_type
|
135
|
+
body = 'foo'
|
136
|
+
block_write(@io, 'FOO', body)
|
137
|
+
@io.seek(0)
|
138
|
+
head_write(@io, 'FOO', body.length, 'UNKNOWN', Digest::SHA512.digest(body))
|
139
|
+
@io.seek(0)
|
140
|
+
|
141
|
+
assert_raise(BrokenError) {
|
142
|
+
block_read(@io, 'FOO')
|
143
|
+
}
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_block_read_BrokenError_unknown_body_cksum_error
|
147
|
+
body = 'foo'
|
148
|
+
block_write(@io, 'FOO', body)
|
149
|
+
@io.seek(0)
|
150
|
+
head_write(@io, 'FOO', body.length, 'SHA512', '')
|
151
|
+
@io.seek(0)
|
152
|
+
|
153
|
+
assert_raise(BrokenError) {
|
154
|
+
block_read(@io, 'FOO')
|
155
|
+
}
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# Local Variables:
|
161
|
+
# mode: Ruby
|
162
|
+
# indent-tabs-mode: nil
|
163
|
+
# End:
|
data/test/test_cache.rb
ADDED
@@ -0,0 +1,214 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
|
3
|
+
require 'higgs/cache'
|
4
|
+
require 'higgs/thread'
|
5
|
+
require 'test/unit'
|
6
|
+
require 'timeout'
|
7
|
+
|
8
|
+
module Higgs::Test
|
9
|
+
class LRUCacheTest < Test::Unit::TestCase
|
10
|
+
include Higgs
|
11
|
+
|
12
|
+
# for ident(1)
|
13
|
+
CVS_ID = '$Id: test_cache.rb 559 2007-09-25 15:20:20Z toki $'
|
14
|
+
|
15
|
+
CACHE_LIMIT_SIZE = 10
|
16
|
+
|
17
|
+
def setup
|
18
|
+
@cache = LRUCache.new(CACHE_LIMIT_SIZE)
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_store_and_fetch
|
22
|
+
@cache[:foo] = 'apple'
|
23
|
+
@cache[:bar] = 'banana'
|
24
|
+
@cache[:baz] = 'orange'
|
25
|
+
assert_equal('apple', @cache[:foo])
|
26
|
+
assert_equal('banana', @cache[:bar])
|
27
|
+
assert_equal('orange', @cache[:baz])
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_fetch_not_defined_value
|
31
|
+
assert_nil(@cache[:foo])
|
32
|
+
assert_nil(@cache[:bar])
|
33
|
+
assert_nil(@cache[:baz])
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_delete
|
37
|
+
@cache[:foo] = 'apple'
|
38
|
+
@cache[:bar] = 'banana'
|
39
|
+
@cache[:baz] = 'orange'
|
40
|
+
@cache.delete(:bar)
|
41
|
+
assert_equal('apple', @cache[:foo])
|
42
|
+
assert_equal(nil, @cache[:bar])
|
43
|
+
assert_equal('orange', @cache[:baz])
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_LRU_read
|
47
|
+
CACHE_LIMIT_SIZE.times do |i|
|
48
|
+
@cache[i] = i.to_s
|
49
|
+
end
|
50
|
+
CACHE_LIMIT_SIZE.times do |i|
|
51
|
+
assert_equal(i.to_s, @cache[i], "#{i}")
|
52
|
+
end
|
53
|
+
|
54
|
+
old_key = 0
|
55
|
+
last_key = CACHE_LIMIT_SIZE - 1
|
56
|
+
new_key = CACHE_LIMIT_SIZE
|
57
|
+
|
58
|
+
@cache[new_key] = new_key.to_s
|
59
|
+
assert_equal(nil, @cache[old_key])
|
60
|
+
assert_equal(last_key.to_s, @cache[last_key])
|
61
|
+
assert_equal(new_key.to_s, @cache[new_key])
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_LRU_write
|
65
|
+
CACHE_LIMIT_SIZE.times do |i|
|
66
|
+
@cache[i] = i.to_s
|
67
|
+
end
|
68
|
+
(0...CACHE_LIMIT_SIZE).to_a.reverse_each do |i|
|
69
|
+
@cache[i] = i.to_s
|
70
|
+
end
|
71
|
+
|
72
|
+
old_key = CACHE_LIMIT_SIZE - 1
|
73
|
+
last_key = 0
|
74
|
+
new_key = CACHE_LIMIT_SIZE
|
75
|
+
|
76
|
+
@cache[new_key] = new_key.to_s
|
77
|
+
assert_equal(nil, @cache[old_key])
|
78
|
+
assert_equal(last_key.to_s, @cache[last_key])
|
79
|
+
assert_equal(new_key.to_s, @cache[new_key])
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class SharedWorkCacheTest < Test::Unit::TestCase
|
84
|
+
include Higgs
|
85
|
+
|
86
|
+
# for ident(1)
|
87
|
+
CVS_ID = '$Id: test_cache.rb 559 2007-09-25 15:20:20Z toki $'
|
88
|
+
|
89
|
+
def setup
|
90
|
+
@calc_calls = 0
|
91
|
+
@cache = SharedWorkCache.new{|key| calc(key) }
|
92
|
+
end
|
93
|
+
|
94
|
+
def calc(n)
|
95
|
+
@calc_calls += 1
|
96
|
+
@s = 0 # @s's scope is over multi-threading
|
97
|
+
for i in 1..n
|
98
|
+
@s += i
|
99
|
+
end
|
100
|
+
@s
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_calc
|
104
|
+
assert_equal(1, calc(1))
|
105
|
+
assert_equal(1, @calc_calls)
|
106
|
+
|
107
|
+
assert_equal(3, calc(2))
|
108
|
+
assert_equal(2, @calc_calls)
|
109
|
+
|
110
|
+
assert_equal(6, calc(3))
|
111
|
+
assert_equal(3, @calc_calls)
|
112
|
+
|
113
|
+
assert_equal(10, calc(4))
|
114
|
+
assert_equal(4, @calc_calls)
|
115
|
+
|
116
|
+
assert_equal(15, calc(5))
|
117
|
+
assert_equal(5, @calc_calls)
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_fetch
|
121
|
+
100.times do |i|
|
122
|
+
assert_equal(1, @cache[1], "loop(#{i})")
|
123
|
+
assert_equal(3, @cache[2], "loop(#{i})")
|
124
|
+
assert_equal(6, @cache[3], "loop(#{i})")
|
125
|
+
assert_equal(10, @cache[4], "loop(#{i})")
|
126
|
+
assert_equal(15, @cache[5], "loop(#{i})")
|
127
|
+
assert_equal(5, @calc_calls)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_delete
|
132
|
+
assert_equal(false, @cache.delete(5))
|
133
|
+
assert_equal(15, @cache[5])
|
134
|
+
assert_equal(1, @calc_calls)
|
135
|
+
|
136
|
+
assert_equal(true, @cache.delete(5))
|
137
|
+
assert_equal(15, @cache[5])
|
138
|
+
assert_equal(2, @calc_calls, 'reload')
|
139
|
+
end
|
140
|
+
|
141
|
+
NUM_OF_THREADS = 10
|
142
|
+
WORK_COUNT = 10000
|
143
|
+
|
144
|
+
def calc_race_condition
|
145
|
+
barrier = Higgs::Barrier.new(NUM_OF_THREADS + 1)
|
146
|
+
th_grp = ThreadGroup.new
|
147
|
+
|
148
|
+
result_list = [ nil ] * NUM_OF_THREADS
|
149
|
+
NUM_OF_THREADS.times{|i| # `i' should be local scope of thread block
|
150
|
+
th_grp.add Thread.new{
|
151
|
+
barrier.wait
|
152
|
+
result_list[i] = calc(WORK_COUNT)
|
153
|
+
}
|
154
|
+
}
|
155
|
+
|
156
|
+
barrier.wait
|
157
|
+
for t in th_grp.list
|
158
|
+
t.join
|
159
|
+
end
|
160
|
+
|
161
|
+
expected_value = calc(WORK_COUNT)
|
162
|
+
result_list.find{|v| v != expected_value }
|
163
|
+
end
|
164
|
+
private :calc_race_condition
|
165
|
+
|
166
|
+
def test_multi_thread_fetch
|
167
|
+
count = 0
|
168
|
+
timeout(10) {
|
169
|
+
begin
|
170
|
+
count += 1
|
171
|
+
end until (calc_race_condition)
|
172
|
+
}
|
173
|
+
|
174
|
+
@calc_calls = 0
|
175
|
+
expected_result = calc(WORK_COUNT)
|
176
|
+
assert_equal(1, @calc_calls)
|
177
|
+
|
178
|
+
count.times do |n|
|
179
|
+
barrier = Higgs::Barrier.new(NUM_OF_THREADS + 1)
|
180
|
+
th_grp = ThreadGroup.new
|
181
|
+
NUM_OF_THREADS.times{|i| # `i' should be local scope of thread block
|
182
|
+
th_grp.add Thread.new{
|
183
|
+
barrier.wait
|
184
|
+
assert_equal(expected_result, @cache[WORK_COUNT], "#{n}th: th#{i}")
|
185
|
+
}
|
186
|
+
}
|
187
|
+
|
188
|
+
barrier.wait
|
189
|
+
for t in th_grp.list
|
190
|
+
t.join
|
191
|
+
end
|
192
|
+
assert_equal(2, @calc_calls, "#{n}th")
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
class SharedWorkCacheNoWorkBlockTest < Test::Unit::TestCase
|
198
|
+
include Higgs
|
199
|
+
|
200
|
+
# for ident(1)
|
201
|
+
CVS_ID = '$Id: test_cache.rb 559 2007-09-25 15:20:20Z toki $'
|
202
|
+
|
203
|
+
def test_no_work_block
|
204
|
+
assert_raise(RuntimeError) {
|
205
|
+
SharedWorkCache.new
|
206
|
+
}
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
# Local Variables:
|
212
|
+
# mode: Ruby
|
213
|
+
# indent-tabs-mode: nil
|
214
|
+
# End:
|