ls4 0.9.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 (100) hide show
  1. data/AUTHORS +1 -0
  2. data/COPYING +661 -0
  3. data/ChangeLog +9 -0
  4. data/NOTICE +8 -0
  5. data/README.rdoc +61 -0
  6. data/bin/ls4-cs +3 -0
  7. data/bin/ls4-ds +3 -0
  8. data/bin/ls4-gw +3 -0
  9. data/bin/ls4-standalone +3 -0
  10. data/bin/ls4cmd +3 -0
  11. data/bin/ls4ctl +3 -0
  12. data/bin/ls4rpc +3 -0
  13. data/bin/ls4stat +3 -0
  14. data/bin/ls4top +3 -0
  15. data/lib/ls4/command/cmd.rb +241 -0
  16. data/lib/ls4/command/cs.rb +190 -0
  17. data/lib/ls4/command/ctl.rb +278 -0
  18. data/lib/ls4/command/ds.rb +335 -0
  19. data/lib/ls4/command/gw.rb +256 -0
  20. data/lib/ls4/command/rpc.rb +172 -0
  21. data/lib/ls4/command/standalone.rb +318 -0
  22. data/lib/ls4/command/stat.rb +244 -0
  23. data/lib/ls4/command/top.rb +291 -0
  24. data/lib/ls4/default.rb +26 -0
  25. data/lib/ls4/lib/cclog.rb +220 -0
  26. data/lib/ls4/lib/ebus.rb +553 -0
  27. data/lib/ls4/lib/vbcode.rb +228 -0
  28. data/lib/ls4/logic/fault_detector.rb +212 -0
  29. data/lib/ls4/logic/membership.rb +253 -0
  30. data/lib/ls4/logic/node.rb +66 -0
  31. data/lib/ls4/logic/okey.rb +45 -0
  32. data/lib/ls4/logic/tsv_data.rb +81 -0
  33. data/lib/ls4/logic/weight.rb +166 -0
  34. data/lib/ls4/service/balance.rb +62 -0
  35. data/lib/ls4/service/base.rb +29 -0
  36. data/lib/ls4/service/bus.rb +37 -0
  37. data/lib/ls4/service/config.rb +63 -0
  38. data/lib/ls4/service/config_cs.rb +33 -0
  39. data/lib/ls4/service/config_ds.rb +56 -0
  40. data/lib/ls4/service/config_gw.rb +42 -0
  41. data/lib/ls4/service/data_client.rb +122 -0
  42. data/lib/ls4/service/data_server.rb +168 -0
  43. data/lib/ls4/service/data_server_url.rb +83 -0
  44. data/lib/ls4/service/gateway.rb +375 -0
  45. data/lib/ls4/service/gateway_ro.rb +91 -0
  46. data/lib/ls4/service/gw_http.rb +821 -0
  47. data/lib/ls4/service/heartbeat.rb +182 -0
  48. data/lib/ls4/service/log.rb +81 -0
  49. data/lib/ls4/service/master_select.rb +148 -0
  50. data/lib/ls4/service/mds.rb +292 -0
  51. data/lib/ls4/service/mds_cache.rb +294 -0
  52. data/lib/ls4/service/mds_cache_mem.rb +63 -0
  53. data/lib/ls4/service/mds_cache_memcached.rb +65 -0
  54. data/lib/ls4/service/mds_ha.rb +176 -0
  55. data/lib/ls4/service/mds_memcache.rb +209 -0
  56. data/lib/ls4/service/mds_tc.rb +508 -0
  57. data/lib/ls4/service/mds_tt.rb +472 -0
  58. data/lib/ls4/service/membership.rb +331 -0
  59. data/lib/ls4/service/process.rb +90 -0
  60. data/lib/ls4/service/rpc.rb +50 -0
  61. data/lib/ls4/service/rpc_cs.rb +101 -0
  62. data/lib/ls4/service/rpc_ds.rb +96 -0
  63. data/lib/ls4/service/rpc_gw.rb +255 -0
  64. data/lib/ls4/service/rts.rb +94 -0
  65. data/lib/ls4/service/rts_file.rb +76 -0
  66. data/lib/ls4/service/rts_memory.rb +55 -0
  67. data/lib/ls4/service/slave.rb +132 -0
  68. data/lib/ls4/service/stat.rb +91 -0
  69. data/lib/ls4/service/stat_cs.rb +25 -0
  70. data/lib/ls4/service/stat_ds.rb +40 -0
  71. data/lib/ls4/service/stat_gw.rb +25 -0
  72. data/lib/ls4/service/storage.rb +116 -0
  73. data/lib/ls4/service/storage_dir.rb +201 -0
  74. data/lib/ls4/service/sync.rb +206 -0
  75. data/lib/ls4/service/time_check.rb +80 -0
  76. data/lib/ls4/service/ulog.rb +159 -0
  77. data/lib/ls4/service/ulog_file.rb +398 -0
  78. data/lib/ls4/service/ulog_memory.rb +53 -0
  79. data/lib/ls4/service/weight.rb +134 -0
  80. data/lib/ls4/version.rb +5 -0
  81. data/test/01_add_get_remove.rt +84 -0
  82. data/test/02_read.rt +61 -0
  83. data/test/03_getd_readd.rt +69 -0
  84. data/test/04_version_time.rt +170 -0
  85. data/test/05_version_name.rt +161 -0
  86. data/test/06_http_get_set_remove_1.rt +119 -0
  87. data/test/07_http_get_set_remove_2.rt +116 -0
  88. data/test/08_read_only_time.rt +177 -0
  89. data/test/09_read_only_name.rt +173 -0
  90. data/test/10_http_get_set_remove_3.rt +73 -0
  91. data/test/11_mds_cache_memcached.rt +88 -0
  92. data/test/12_mds_cache_local_memory.rt +86 -0
  93. data/test/13_memcache_mds.rt +84 -0
  94. data/test/14_delete.rt +63 -0
  95. data/test/15_standalone.rt +71 -0
  96. data/test/chukan.rb +516 -0
  97. data/test/common.rb +250 -0
  98. data/test/load_test.rb +79 -0
  99. data/test/load_test_offload.rb +86 -0
  100. metadata +295 -0
@@ -0,0 +1,294 @@
1
+ #
2
+ # LS4
3
+ # Copyright (C) 2010-2011 FURUHASHI Sadayuki
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as
7
+ # published by the Free Software Foundation, either version 3 of the
8
+ # License, or (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ #
18
+ module LS4
19
+
20
+
21
+ class MDSCacheBus < Bus
22
+ call_slot :get
23
+ call_slot :set
24
+ call_slot :invalidate
25
+ end
26
+
27
+
28
+ class MDSCacheConfigService < Service
29
+ def run
30
+ @uri = ConfigBus.get_initial_mds_cache_uri
31
+ @uri ||= "null"
32
+ on_change
33
+ end
34
+
35
+ def rpc_get_mds_cache_uri
36
+ @uri
37
+ end
38
+
39
+ def rpc_set_mds_cache_uri(uri)
40
+ @uri = uri
41
+ on_change
42
+ nil
43
+ end
44
+
45
+ def self.hash_uri(uri)
46
+ Digest::SHA1.digest(uri)
47
+ end
48
+
49
+ def on_change
50
+ SyncBus.update(SYNC_MDS_CACHE_URI,
51
+ @uri, MDSCacheConfigService.hash_uri(@uri))
52
+ end
53
+
54
+ ebus_connect :ProcessBus,
55
+ :run
56
+
57
+ ebus_connect :CSRPCBus,
58
+ :get_mds_cache_uri => :rpc_get_mds_cache_uri,
59
+ :set_mds_cache_uri => :rpc_set_mds_cache_uri
60
+ end
61
+
62
+
63
+ class MDSCacheService < Service
64
+ def initialize
65
+ @uri = ""
66
+ @cache = NullMDSCache.new
67
+ end
68
+
69
+ def run
70
+ SyncBus.register_callback(SYNC_MDS_CACHE_URI,
71
+ MDSCacheConfigService.hash_uri(@uri)) do |obj|
72
+ uri = obj
73
+ reopen(uri)
74
+ @uri = uri
75
+ MDSCacheConfigService.hash_uri(@uri)
76
+ end
77
+ end
78
+
79
+ def shutdown
80
+ if @cache
81
+ @cache.close rescue nil
82
+ end
83
+ end
84
+
85
+ def reopen(uri)
86
+ klass, expr = MDSCacheSelector.select_class(uri)
87
+
88
+ cache = klass.new
89
+ cache.open(expr)
90
+
91
+ old_cache = @cache
92
+ @cache = cache
93
+
94
+ $log.info "using MDS cache: #{@cache}"
95
+
96
+ begin
97
+ old_cache.close
98
+ rescue
99
+ $log.error "MDSCache close error: #{$!}"
100
+ $log.error_backtrace $!.backtrace
101
+ end
102
+ end
103
+
104
+ ebus_connect :ProcessBus,
105
+ :run,
106
+ :shutdown
107
+
108
+ ebus_connect :MDSCacheBus,
109
+ :get,
110
+ :set,
111
+ :invalidate
112
+
113
+ extend Forwardable
114
+
115
+ def_delegators :@cache,
116
+ :get,
117
+ :set,
118
+ :invalidate
119
+ end
120
+
121
+
122
+ module MDSCacheSelector
123
+ IMPLS = {}
124
+
125
+ def self.register(name, klass)
126
+ IMPLS[name.to_sym] = klass
127
+ nil
128
+ end
129
+
130
+ def self.select_class(uri)
131
+ if uri.empty?
132
+ return NullMDSCache
133
+ end
134
+
135
+ if m = /^(\w{1,8})\:(.*)/.match(uri)
136
+ type = m[1].to_sym
137
+ expr = m[2]
138
+ else
139
+ type = :null
140
+ expr = uri
141
+ end
142
+
143
+ klass = IMPLS[type]
144
+ unless klass
145
+ raise "unknown MDSCache type: #{type}"
146
+ end
147
+
148
+ return klass, expr
149
+ end
150
+ end
151
+
152
+
153
+ class MDSCache
154
+ #def open(expr)
155
+ #end
156
+
157
+ #def close
158
+ #end
159
+
160
+ #def get(key)
161
+ #end
162
+
163
+ #def set(key, val)
164
+ #end
165
+
166
+ #def invalidate(key)
167
+ #end
168
+ end
169
+
170
+
171
+ class NullMDSCache < MDSCache
172
+ MDSCacheSelector.register(:null, self)
173
+
174
+ def open(expr)
175
+ end
176
+
177
+ def close
178
+ end
179
+
180
+ def get(key)
181
+ nil
182
+ end
183
+
184
+ def set(key, val)
185
+ end
186
+
187
+ def invalidate(key)
188
+ end
189
+
190
+ def to_s
191
+ "no-cache"
192
+ end
193
+ end
194
+
195
+
196
+ class CachedMDSBus < Bus
197
+ call_slot :get_okey
198
+ call_slot :get_attrs
199
+ call_slot :get_okey_attrs
200
+ call_slot :add
201
+ call_slot :update_attrs
202
+ call_slot :remove
203
+ call_slot :delete
204
+ call_slot :util_locate
205
+ end
206
+
207
+
208
+ class CachedMDSService < Service
209
+ def get_okey(key, version=nil, &cb)
210
+ if version == nil
211
+ if okey = get_cache(key)
212
+ cb.call(okey, nil)
213
+ return
214
+ end
215
+ end
216
+ MDSBus.get_okey(key, version) {|okey,error|
217
+ set_cache(key, okey) if okey
218
+ cb.call(okey, error)
219
+ }
220
+ end
221
+
222
+ def get_attrs(key, version=nil, &cb)
223
+ MDSBus.get_attrs(key, version, &cb)
224
+ end
225
+
226
+ def get_okey_attrs(key, version=nil, &cb)
227
+ MDSBus.get_okey_attrs(key, version, &cb)
228
+ end
229
+
230
+ def add(key, attrs={}, vname=nil, &cb)
231
+ invalidate_cache(key)
232
+ MDSBus.add(key, attrs, vname, &cb)
233
+ end
234
+
235
+ def update_attrs(key, attrs, &cb)
236
+ invalidate_cache(key)
237
+ MDSBus.update_attrs(key, attrs, &cb)
238
+ end
239
+
240
+ def remove(key, &cb)
241
+ invalidate_cache(key)
242
+ MDSBus.remove(key, &cb)
243
+ end
244
+
245
+ def delete(key, version=nil, &cb)
246
+ invalidate_cache(key)
247
+ MDSBus.delete(key, version, &cb)
248
+ end
249
+
250
+ def util_locate(key, &cb)
251
+ MDSBus.util_locate(key, &cb)
252
+ end
253
+
254
+ ebus_connect :CachedMDSBus,
255
+ :get_okey,
256
+ :get_attrs,
257
+ :get_okey_attrs,
258
+ :add,
259
+ :update_attrs,
260
+ :remove,
261
+ :delete,
262
+ :util_locate
263
+
264
+ private
265
+ def get_cache(key)
266
+ if val = MDSCacheBus.get(key)
267
+ rsid, vtime = MessagePack.unpack(val)
268
+ return ObjectKey.new(key, vtime, rsid)
269
+ end
270
+ return nil
271
+ rescue
272
+ $log.warn("error when getting MDS cache: key=#{key.inspect}: #{$!.to_s}")
273
+ $log.debug_backtrace $!.backtrace
274
+ return nil
275
+ end
276
+
277
+ def set_cache(key, okey)
278
+ val = [okey.rsid, okey.vtime].to_msgpack
279
+ MDSCacheBus.set(key, val)
280
+ rescue
281
+ $log.warn("error when setting MDS cache: key=#{key.inspect}: #{$!.to_s}")
282
+ $log.debug_backtrace $!.backtrace
283
+ end
284
+
285
+ def invalidate_cache(key)
286
+ MDSCacheBus.invalidate(key)
287
+ rescue
288
+ $log.warn("error when invalidating MDS cache: key=#{key.inspect}: #{$!.to_s}")
289
+ $log.debug_backtrace $!.backtrace
290
+ end
291
+ end
292
+
293
+
294
+ end
@@ -0,0 +1,63 @@
1
+ #
2
+ # LS4
3
+ # Copyright (C) 2010-2011 FURUHASHI Sadayuki
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as
7
+ # published by the Free Software Foundation, either version 3 of the
8
+ # License, or (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ #
18
+ module LS4
19
+
20
+
21
+ class LocalMemoryMDSCache < MDSCache
22
+ MDSCacheSelector.register(:local, self)
23
+
24
+ def initialize
25
+ require 'tokyocabinet'
26
+ end
27
+
28
+ def open(expr)
29
+ @db = TokyoCabinet::ADB.new
30
+ if expr.empty?
31
+ @size = "32m"
32
+ else
33
+ @size = expr
34
+ end
35
+ name = "+#capsiz=#{@size}"
36
+ unless @db.open(name)
37
+ raise "failed to MDS local memory cache database: #{@db.errmsg(@db.ecode)}"
38
+ end
39
+ end
40
+
41
+ def close
42
+ @db.close
43
+ end
44
+
45
+ def get(key)
46
+ @db[key]
47
+ end
48
+
49
+ def set(key, val)
50
+ @db[key] = val
51
+ end
52
+
53
+ def invalidate(key)
54
+ @db.delete(key)
55
+ end
56
+
57
+ def to_s
58
+ "<LocalMemoryMDSCache size=#{@size}>"
59
+ end
60
+ end
61
+
62
+
63
+ end
@@ -0,0 +1,65 @@
1
+ #
2
+ # LS4
3
+ # Copyright (C) 2010-2011 FURUHASHI Sadayuki
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as
7
+ # published by the Free Software Foundation, either version 3 of the
8
+ # License, or (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ #
18
+ module LS4
19
+
20
+
21
+ class MemcachedMDSCache < MDSCache
22
+ MDSCacheSelector.register(:mc, self)
23
+
24
+ def initialize
25
+ require 'memcache'
26
+ end
27
+
28
+ def open(expr)
29
+ @expire = 0
30
+ if m = /\;expire\=(\d+)/.match(expr)
31
+ servers_line = expr[0,m.begin(0)]
32
+ @expire = m[1].to_i
33
+ else
34
+ servers_line = expr
35
+ end
36
+ @servers = servers_line.split(/\s*\,\s*/)
37
+ if @expire == 0
38
+ @expire = 60*60*24
39
+ end
40
+ @mc = MemCache.new(@servers, {:urlencode => false, :compression => false, :multithread => true, :timeout => 1.0})
41
+ end
42
+
43
+ def close
44
+ @mc.reset
45
+ end
46
+
47
+ def get(key)
48
+ @mc.get(key, true)
49
+ end
50
+
51
+ def set(key, val)
52
+ @mc.set(key, val, @expire, true)
53
+ end
54
+
55
+ def invalidate(key)
56
+ @mc.delete(key)
57
+ end
58
+
59
+ def to_s
60
+ "<MemcachedMDSCache servers=#{@servers.join(',')} expire=#{@expire}>"
61
+ end
62
+ end
63
+
64
+
65
+ end
@@ -0,0 +1,176 @@
1
+ #
2
+ # LS4
3
+ # Copyright (C) 2010-2011 FURUHASHI Sadayuki
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as
7
+ # published by the Free Software Foundation, either version 3 of the
8
+ # License, or (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ module LS4
20
+
21
+
22
+ # single node:
23
+ # host1:port1
24
+ #
25
+ # master-slave:
26
+ # host1:port1,host2:port2
27
+ #
28
+ # master-slave with read weight:
29
+ # host1:port1,host2:port2;0,1
30
+ #
31
+ # dual-master:
32
+ # host1:port1--host2:port2
33
+ #
34
+ class BasicHADB
35
+ DEFAULT_WEIGHT = 10
36
+
37
+ def initialize(expr)
38
+ @dbmap = {} # {Address => DB}
39
+ @writers = [] # [Address]
40
+ @readers = [] # [Address]
41
+ @readers_rr = 0
42
+
43
+ expr.split('--').each {|line|
44
+ nodes, weights = line.strip.split(';',2)
45
+
46
+ addrs = nodes.strip.split(',').map {|addr|
47
+ parse_addr(addr)
48
+ }
49
+
50
+ weights = (weights||"").strip.split(',').map {|x| x.to_i }
51
+
52
+ @writers << addrs.first
53
+
54
+ addrs.each_with_index {|addr,i|
55
+ weight = weights[i] ||= DEFAULT_WEIGHT
56
+ weight.times {
57
+ @readers << addr
58
+ }
59
+ @dbmap[addr] = nil
60
+ }
61
+
62
+ $log.info "MDS -- #{addrs.join(',')};#{weights.join(',')}"
63
+ }
64
+
65
+ if @dbmap.empty?
66
+ raise "empty expression"
67
+ end
68
+
69
+ if @dbmap.size == 1
70
+ # single node
71
+ @readers = [@readers[0]]
72
+ else
73
+ @readers = @readers.sort_by {|addr| rand }
74
+ end
75
+
76
+ # open remote database
77
+ @dbmap.keys.each {|addr|
78
+ @dbmap[addr] = open_db(addr)
79
+ }
80
+
81
+ rescue
82
+ @dbmap.each_pair {|addr,db|
83
+ if db
84
+ close_db(db) rescue nil
85
+ end
86
+ }
87
+ $log.error $!
88
+ $log.error_backtrace $!.backtrace
89
+ raise "MDS: invlaid address expression: #{$!}"
90
+ end
91
+
92
+ def write(shard_key, &block)
93
+ if @writers.size == 1
94
+ n = 0
95
+ else
96
+ n = hash_key(shard_key) % @writers.size
97
+ end
98
+ ha_call(@writers, n) {|db|
99
+ block.call(db)
100
+ }
101
+ end
102
+
103
+ def read(shard_key, &block)
104
+ @readers_rr += 1
105
+ @readers_rr = 0 if @readers_rr >= @readers.size
106
+ ha_call(@readers, @readers_rr) {|db|
107
+ block.call(db)
108
+ }
109
+ end
110
+
111
+ def close
112
+ @dbmap.each_pair {|addr,db|
113
+ close_db(db) rescue nil
114
+ }
115
+ end
116
+
117
+ protected
118
+ def parse_addr(addr)
119
+ host, port = addr.split(':',2)
120
+ port ||= self.class::DEFAULT_PORT
121
+ port = port.to_i
122
+ host.strip!
123
+ Address.new(host, port)
124
+ end
125
+
126
+ def open_db(addr)
127
+ raise "LOGIC ERROR: not implemented!"
128
+ end
129
+
130
+ def ensure_db(db, addr)
131
+ true
132
+ end
133
+
134
+ def error_result?(db, result)
135
+ nil
136
+ end
137
+
138
+ def close_db(db)
139
+ db.close
140
+ end
141
+
142
+ def hash_key(key)
143
+ digest = Digest::MD5.digest(key)
144
+ digest.unpack('C')[0]
145
+ end
146
+
147
+ def ha_call(array, idx, &block)
148
+ db = nil
149
+ failed = []
150
+ sz = array.size
151
+ sz.times {
152
+ addr = array[idx % sz]
153
+ unless failed.include?(addr)
154
+ db = @dbmap[addr]
155
+ if ensure_db(db, addr)
156
+ @dbmap[addr] = db # FIXME
157
+ begin
158
+ result = block.call(db)
159
+ if err = error_result?(db, result)
160
+ failed << [addr, err]
161
+ else
162
+ return result
163
+ end
164
+ rescue
165
+ failed << [addr, $!]
166
+ end
167
+ end
168
+ end
169
+ idx += 1
170
+ }
171
+ raise "MDS error: #{failed.inspect}" # TODO error message
172
+ end
173
+ end
174
+
175
+
176
+ end