higgs 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/ChangeLog +208 -0
  2. data/LICENSE +26 -0
  3. data/README +2 -0
  4. data/Rakefile +75 -0
  5. data/bin/higgs_backup +67 -0
  6. data/bin/higgs_dump_index +43 -0
  7. data/bin/higgs_dump_jlog +42 -0
  8. data/bin/higgs_verify +37 -0
  9. data/lib/cgi/session/higgs.rb +72 -0
  10. data/lib/higgs/block.rb +192 -0
  11. data/lib/higgs/cache.rb +117 -0
  12. data/lib/higgs/dbm.rb +55 -0
  13. data/lib/higgs/exceptions.rb +31 -0
  14. data/lib/higgs/flock.rb +77 -0
  15. data/lib/higgs/index.rb +164 -0
  16. data/lib/higgs/jlog.rb +159 -0
  17. data/lib/higgs/lock.rb +189 -0
  18. data/lib/higgs/storage.rb +1086 -0
  19. data/lib/higgs/store.rb +228 -0
  20. data/lib/higgs/tar.rb +390 -0
  21. data/lib/higgs/thread.rb +370 -0
  22. data/lib/higgs/tman.rb +513 -0
  23. data/lib/higgs/utils/bman.rb +285 -0
  24. data/lib/higgs/utils.rb +22 -0
  25. data/lib/higgs/version.rb +21 -0
  26. data/lib/higgs.rb +59 -0
  27. data/misc/cache_bench/cache_bench.rb +43 -0
  28. data/misc/dbm_bench/.strc +8 -0
  29. data/misc/dbm_bench/Rakefile +78 -0
  30. data/misc/dbm_bench/dbm_multi_thread.rb +199 -0
  31. data/misc/dbm_bench/dbm_rnd_delete.rb +43 -0
  32. data/misc/dbm_bench/dbm_rnd_read.rb +44 -0
  33. data/misc/dbm_bench/dbm_rnd_update.rb +44 -0
  34. data/misc/dbm_bench/dbm_seq_read.rb +45 -0
  35. data/misc/dbm_bench/dbm_seq_write.rb +44 -0
  36. data/misc/dbm_bench/st_verify.rb +28 -0
  37. data/misc/io_bench/cksum_bench.rb +48 -0
  38. data/misc/io_bench/jlog_bench.rb +71 -0
  39. data/misc/io_bench/write_bench.rb +128 -0
  40. data/misc/thread_bench/lock_bench.rb +132 -0
  41. data/mkrdoc.rb +8 -0
  42. data/rdoc.yml +13 -0
  43. data/sample/count.rb +60 -0
  44. data/sample/dbmtest.rb +38 -0
  45. data/test/Rakefile +45 -0
  46. data/test/run.rb +32 -0
  47. data/test/test_block.rb +163 -0
  48. data/test/test_cache.rb +214 -0
  49. data/test/test_cgi_session.rb +142 -0
  50. data/test/test_flock.rb +162 -0
  51. data/test/test_index.rb +258 -0
  52. data/test/test_jlog.rb +180 -0
  53. data/test/test_lock.rb +320 -0
  54. data/test/test_online_backup.rb +169 -0
  55. data/test/test_storage.rb +439 -0
  56. data/test/test_storage_conf.rb +202 -0
  57. data/test/test_storage_init_opts.rb +89 -0
  58. data/test/test_store.rb +211 -0
  59. data/test/test_tar.rb +432 -0
  60. data/test/test_thread.rb +541 -0
  61. data/test/test_tman.rb +875 -0
  62. data/test/test_tman_init_opts.rb +56 -0
  63. data/test/test_utils_bman.rb +234 -0
  64. 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
@@ -0,0 +1,8 @@
1
+ #!/usr/local/bin/ruby
2
+
3
+ CVS_ID = '$Id: mkrdoc.rb 564 2007-09-27 16:10:25Z toki $' # for ident(1)
4
+
5
+ require 'yaml'
6
+
7
+ rdoc_opts = YAML.load(IO.read('rdoc.yml'))
8
+ system 'rdoc', *(rdoc_opts['CommonOptions'] + rdoc_opts['CommandLineOptions']).flatten
data/rdoc.yml ADDED
@@ -0,0 +1,13 @@
1
+ CommonOptions:
2
+ - -SNa
3
+ - [ -i, . ]
4
+ - [ -m, Higgs ]
5
+
6
+ CommandLineOptions:
7
+ - [ -i, lib ]
8
+ - [ -x, misc ]
9
+ - [ -x, mkrdoc ]
10
+ - [ -x, pkg ]
11
+ - [ -x, sample ]
12
+ - [ -x, test ]
13
+ - [ -o, api ]
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:
@@ -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:
@@ -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: