higgs 0.1.0

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.
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
data/lib/higgs/jlog.rb ADDED
@@ -0,0 +1,159 @@
1
+ # = journal log writer
2
+ #
3
+ # Author:: $Author: toki $
4
+ # Date:: $Date: 2007-09-26 00:20:20 +0900 (Wed, 26 Sep 2007) $
5
+ # Revision:: $Revision: 559 $
6
+ #
7
+ # == license
8
+ # :include:LICENSE
9
+ #
10
+
11
+ require 'higgs/block'
12
+
13
+ module Higgs
14
+ # = journal log writer
15
+ class JournalLogger
16
+ # for ident(1)
17
+ CVS_ID = '$Id: jlog.rb 559 2007-09-25 15:20:20Z toki $'
18
+
19
+ include Block
20
+
21
+ MAGIC_SYMBOL = 'HIGGS_JLOG'
22
+ EOF_MARK = :END_OF_JLOG
23
+ BIN_EOF_MARK = Marshal.dump(EOF_MARK)
24
+
25
+ # see Higgs::Block#block_write for <tt>hash_type</tt>
26
+ def initialize(out, sync=false, hash_type=:MD5)
27
+ @out = out
28
+ @sync = sync
29
+ @hash_type = hash_type
30
+ end
31
+
32
+ def sync?
33
+ @sync
34
+ end
35
+
36
+ def size
37
+ @out.stat.size
38
+ end
39
+
40
+ def write(log, hash_type=nil)
41
+ bin_log = Marshal.dump(log)
42
+ start_pos = @out.tell
43
+ commit_completed = false
44
+ begin
45
+ block_write(@out, MAGIC_SYMBOL, bin_log, hash_type || @hash_type)
46
+ if (@sync) then
47
+ @out.fsync
48
+ else
49
+ @out.flush
50
+ end
51
+ commit_completed = true
52
+ ensure
53
+ @out.truncate(start_pos) unless commit_completed
54
+ end
55
+
56
+ self
57
+ end
58
+
59
+ def write_EOF
60
+ JournalLogger.eof_mark(@out)
61
+ self
62
+ end
63
+
64
+ def close(eof=true)
65
+ write_EOF if eof
66
+ @out.fsync
67
+ @out.close
68
+ @out = nil
69
+ nil
70
+ end
71
+
72
+ class << self
73
+ def has_eof_mark?(path)
74
+ unless (File.exist? path) then
75
+ return true
76
+ end
77
+
78
+ File.open(path, 'r') {|f|
79
+ f.binmode
80
+ fsiz = f.stat.size
81
+ if (fsiz < Block::BLOCK_SIZE * 2) then
82
+ return false
83
+ end
84
+ f.seek(fsiz - Block::BLOCK_SIZE * 2)
85
+
86
+ begin
87
+ bin_log = Block.block_read(f, MAGIC_SYMBOL) or return
88
+ log = Marshal.load(bin_log)
89
+ if (log == EOF_MARK) then
90
+ return true
91
+ end
92
+ rescue Block::BrokenError
93
+ return false
94
+ end
95
+ }
96
+
97
+ false
98
+ end
99
+
100
+ def need_for_recovery?(path)
101
+ ! (has_eof_mark? path)
102
+ end
103
+
104
+ def open(path, *args)
105
+ begin
106
+ f = File.open(path, File::WRONLY | File::CREAT | File::EXCL, 0660)
107
+ rescue Errno::EEXIST
108
+ if (need_for_recovery? path) then
109
+ raise "need for recovery: #{path}"
110
+ end
111
+ f = File.open(path, File::WRONLY, 0660)
112
+ fsiz = f.stat.size
113
+ f.truncate(fsiz - Block::BLOCK_SIZE * 2)
114
+ end
115
+ f.binmode
116
+ f.seek(0, IO::SEEK_END)
117
+ new(f, *args)
118
+ end
119
+
120
+ def eof_mark(out)
121
+ Block.block_write(out, MAGIC_SYMBOL, BIN_EOF_MARK)
122
+ nil
123
+ end
124
+
125
+ def scan_log(io)
126
+ safe_pos = io.tell
127
+ begin
128
+ while (bin_log = Block.block_read(io, MAGIC_SYMBOL))
129
+ log = Marshal.load(bin_log)
130
+ if (log == EOF_MARK) then
131
+ break
132
+ end
133
+ yield(log)
134
+ safe_pos = io.tell
135
+ end
136
+ rescue Block::BrokenError
137
+ io.seek(safe_pos)
138
+ raise
139
+ end
140
+ self
141
+ end
142
+
143
+ def each_log(path)
144
+ File.open(path, 'r') {|f|
145
+ f.binmode
146
+ scan_log(f) {|log|
147
+ yield(log)
148
+ }
149
+ }
150
+ nil
151
+ end
152
+ end
153
+ end
154
+ end
155
+
156
+ # Local Variables:
157
+ # mode: Ruby
158
+ # indent-tabs-mode: nil
159
+ # End:
data/lib/higgs/lock.rb ADDED
@@ -0,0 +1,189 @@
1
+ # = multi-thread lock manager
2
+ #
3
+ # Author:: $Author: toki $
4
+ # Date:: $Date: 2007-09-26 00:20:20 +0900 (Wed, 26 Sep 2007) $
5
+ # Revision:: $Revision: 559 $
6
+ #
7
+ # == license
8
+ # :include:LICENSE
9
+ #
10
+
11
+ require 'forwardable'
12
+ require 'higgs/cache'
13
+ require 'higgs/exceptions'
14
+ require 'singleton'
15
+ require 'thread'
16
+
17
+ module Higgs
18
+ # = multi-thread lock manager
19
+ class LockManager
20
+ # for ident(1)
21
+ CVS_ID = '$Id: lock.rb 559 2007-09-25 15:20:20Z toki $'
22
+
23
+ include Exceptions
24
+
25
+ class Error < HiggsError
26
+ end
27
+
28
+ class TryLockTimeoutError < Error
29
+ end
30
+
31
+ SPIN_LOCK_COUNT = 100
32
+ TRY_LOCK_LIMIT = 10
33
+ TRY_LOCK_INTERVAL = 0.1
34
+
35
+ RAND_GEN = proc{|seed|
36
+ n = seed
37
+ cycle = 0xFFFF
38
+ proc{
39
+ n = (n * 37549 + 12345) % cycle
40
+ n.to_f / cycle
41
+ }
42
+ }
43
+
44
+ def initialize(options={})
45
+ @spin_lock_count = options[:spin_lock_count] || SPIN_LOCK_COUNT
46
+ @try_lock_limit = options[:try_lock_limit] || TRY_LOCK_LIMIT
47
+ @try_lock_interval = options[:try_lock_interval] || TRY_LOCK_INTERVAL
48
+ @rand_gen = options[:random_number_generator] || RAND_GEN
49
+ end
50
+
51
+ attr_reader :spin_lock_count
52
+ attr_reader :try_lock_limit
53
+ attr_reader :try_lock_interval
54
+
55
+ def new_rand(seed)
56
+ @rand_gen.call(seed)
57
+ end
58
+
59
+ def self.try_lock(lock, attrs)
60
+ t0 = Time.now
61
+ c = attrs.spin_lock_count
62
+ while (c > 0)
63
+ if (lock.try_lock) then
64
+ return
65
+ end
66
+ c -= 1
67
+ end
68
+
69
+ if (attrs.try_lock_limit > 0) then
70
+ rand = attrs.new_rand(::Thread.current.object_id ^ t0.to_i)
71
+ while (Time.now - t0 < attrs.try_lock_limit)
72
+ if (lock.try_lock) then
73
+ return
74
+ end
75
+ sleep(attrs.try_lock_interval * rand.call)
76
+ end
77
+ raise TryLockTimeoutError, 'expired'
78
+ else
79
+ # brave man who doesn't fear deadlock.
80
+ lock.lock
81
+ end
82
+ end
83
+ end
84
+
85
+ class GiantLockManager < LockManager
86
+ # for ident(1)
87
+ CVS_ID = '$Id: lock.rb 559 2007-09-25 15:20:20Z toki $'
88
+
89
+ def initialize(*args)
90
+ super
91
+ @rw_lock = ReadWriteLock.new
92
+ end
93
+
94
+ class NoWorkLockHandler
95
+ include Singleton
96
+
97
+ def lock(key)
98
+ self
99
+ end
100
+
101
+ def unlock(key)
102
+ self
103
+ end
104
+ end
105
+
106
+ def transaction(read_only=false)
107
+ if (read_only) then
108
+ lock = @rw_lock.read_lock
109
+ else
110
+ lock = @rw_lock.write_lock
111
+ end
112
+ r = nil
113
+ lock.synchronize{
114
+ r = yield(NoWorkLockHandler.instance)
115
+ }
116
+ r
117
+ end
118
+ end
119
+
120
+ class FineGrainLockManager < LockManager
121
+ # for ident(1)
122
+ CVS_ID = '$Id: lock.rb 559 2007-09-25 15:20:20Z toki $'
123
+
124
+ def initialize(*args)
125
+ super
126
+ @cache = SharedWorkCache.new{|key| ReadWriteLock.new }
127
+ end
128
+
129
+ class LockHandler
130
+ def initialize(attrs, cache)
131
+ @attrs = attrs
132
+ @cache = cache
133
+ @lock_map = {}
134
+ end
135
+
136
+ def lock_list
137
+ @lock_map.values
138
+ end
139
+
140
+ def unlock(key)
141
+ if (lock = @lock_map.delete(key)) then
142
+ lock.unlock
143
+ else
144
+ raise "not locked key: #{key}"
145
+ end
146
+ self
147
+ end
148
+ end
149
+
150
+ class ReadOnlyLockHandler < LockHandler
151
+ def lock(key)
152
+ r_lock = @cache[key].read_lock
153
+ LockManager.try_lock(r_lock, @attrs)
154
+ @lock_map[key] = r_lock
155
+ self
156
+ end
157
+ end
158
+
159
+ class ReadWriteLockHandler < LockHandler
160
+ def lock(key)
161
+ w_lock = @cache[key].write_lock
162
+ LockManager.try_lock(w_lock, @attrs)
163
+ @lock_map[key] = w_lock
164
+ self
165
+ end
166
+ end
167
+
168
+ def transaction(read_only=false)
169
+ if (read_only) then
170
+ lock_handler = ReadOnlyLockHandler.new(self, @cache)
171
+ else
172
+ lock_handler = ReadWriteLockHandler.new(self, @cache)
173
+ end
174
+ begin
175
+ r = yield(lock_handler)
176
+ ensure
177
+ for lock in lock_handler.lock_list
178
+ lock.unlock
179
+ end
180
+ end
181
+ r
182
+ end
183
+ end
184
+ end
185
+
186
+ # Local Variables:
187
+ # mode: Ruby
188
+ # indent-tabs-mode: nil
189
+ # End: