roma 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/LICENSE.rdoc +675 -0
  2. data/README.rdoc +0 -0
  3. data/Rakefile +70 -0
  4. data/bin/mkrecent +7 -0
  5. data/bin/mkroute +7 -0
  6. data/bin/recoverlost +8 -0
  7. data/bin/recoverlost_alist +8 -0
  8. data/bin/romad +7 -0
  9. data/bin/sample_watcher +8 -0
  10. data/bin/sample_watcher2 +8 -0
  11. data/bin/simple_bench +8 -0
  12. data/bin/ssroute +7 -0
  13. data/bin/tribunus +7 -0
  14. data/lib/roma/async_process.rb +696 -0
  15. data/lib/roma/command/bg_command_receiver.rb +188 -0
  16. data/lib/roma/command/mh_command_receiver.rb +117 -0
  17. data/lib/roma/command/receiver.rb +287 -0
  18. data/lib/roma/command/rt_command_receiver.rb +147 -0
  19. data/lib/roma/command/st_command_receiver.rb +564 -0
  20. data/lib/roma/command/util_command_receiver.rb +67 -0
  21. data/lib/roma/command/vn_command_receiver.rb +143 -0
  22. data/lib/roma/command_plugin.rb +11 -0
  23. data/lib/roma/config.rb +64 -0
  24. data/lib/roma/event/con_pool.rb +140 -0
  25. data/lib/roma/event/handler.rb +159 -0
  26. data/lib/roma/plugin/plugin_alist.rb +1572 -0
  27. data/lib/roma/plugin/plugin_debug.rb +19 -0
  28. data/lib/roma/plugin/plugin_test.rb +14 -0
  29. data/lib/roma/romad.rb +582 -0
  30. data/lib/roma/routing/cb_rttable.rb +326 -0
  31. data/lib/roma/routing/merkle_tree.rb +54 -0
  32. data/lib/roma/routing/rttable.rb +148 -0
  33. data/lib/roma/stats.rb +112 -0
  34. data/lib/roma/storage/basic_storage.rb +510 -0
  35. data/lib/roma/storage/dbm_storage.rb +80 -0
  36. data/lib/roma/storage/dummy_storage.rb +44 -0
  37. data/lib/roma/storage/rh_storage.rb +35 -0
  38. data/lib/roma/storage/sqlite3_storage.rb +73 -0
  39. data/lib/roma/storage/tc_storage.rb +133 -0
  40. data/lib/roma/tools/mkrecent.rb +138 -0
  41. data/lib/roma/tools/mkroute.rb +52 -0
  42. data/lib/roma/tools/recoverlost.rb +9 -0
  43. data/lib/roma/tools/recoverlost_alist.rb +9 -0
  44. data/lib/roma/tools/recoverlost_lib.rb +217 -0
  45. data/lib/roma/tools/sample_watcher.rb +38 -0
  46. data/lib/roma/tools/sample_watcher2.rb +38 -0
  47. data/lib/roma/tools/simple_bench.rb +57 -0
  48. data/lib/roma/tools/ssroute.rb +23 -0
  49. data/lib/roma/tools/tribunus.rb +299 -0
  50. data/lib/roma/version.rb +4 -0
  51. data/lib/roma/write_behind.rb +179 -0
  52. data/test/rcirb.rb +16 -0
  53. data/test/roma-test-utils.rb +65 -0
  54. data/test/run-test.rb +16 -0
  55. data/test/t_cpdata.rb +277 -0
  56. data/test/t_listplugin.rb +592 -0
  57. data/test/t_rclient.rb +318 -0
  58. data/test/t_routing_data.rb +100 -0
  59. data/test/t_storage.rb +644 -0
  60. data/test/t_writebehind.rb +200 -0
  61. metadata +134 -0
@@ -0,0 +1,147 @@
1
+
2
+ module Roma
3
+ module Command
4
+
5
+ module RoutingCommandReceiver
6
+
7
+ # join <node id>
8
+ def ev_join(s)
9
+ @rttable.add_node(s[1])
10
+ send_data("ADDED\r\n")
11
+ end
12
+
13
+ # leave <node id>
14
+ def ev_leave(s)
15
+ @log.warn("receive a leave #{s[1]} message.")
16
+ @rttable.leave(s[1])
17
+ send_data("DELETED\r\n")
18
+ end
19
+
20
+ def ev_nodelist(s)
21
+ nl = nil
22
+ @rttable.nodes.each{ |nid|
23
+ if nl
24
+ nl << " #{nid}"
25
+ else
26
+ nl = nid.clone
27
+ end
28
+ }
29
+ send_data("#{nl}\r\n")
30
+ end
31
+
32
+ def ev_create_nodes_from_v_idx(s)
33
+ @rttable.create_nodes_from_v_idx
34
+ send_data("CREATED\r\n")
35
+ end
36
+
37
+ # routingdump [yaml|json|yamlbytes]\r\n
38
+ def ev_routingdump(s)
39
+ if s.length == 1
40
+ dmp = @rttable.dump
41
+ send_data("#{dmp.length}\r\n#{dmp}\r\nEND\r\n")
42
+ elsif s[1] == 'yaml'
43
+ dmp = @rttable.dump_yaml
44
+ send_data("#{dmp}\r\nEND\r\n")
45
+ elsif s[1] == 'json'
46
+ dmp = @rttable.dump_json
47
+ send_data("#{dmp}\r\nEND\r\n")
48
+ elsif s[1] == 'yamlbytes'
49
+ dmp = @rttable.dump_yaml
50
+ send_data("#{dmp.length + 7}\r\nEND\r\n")
51
+ end
52
+ end
53
+
54
+ # setroute <vnode-id> <clock> <node-id> ...
55
+ def ev_setroute(s)
56
+ if s.length < 4
57
+ send_data("CLIENT_ERROR\r\n")
58
+ else
59
+ nids=[]
60
+ s[3..-1].each{ |nid| nids << nid }
61
+ res=@rttable.set_route(s[1].to_i, s[2].to_i, nids)
62
+ if res.is_a?(Integer)
63
+ send_data("STORED\r\n")
64
+ else
65
+ send_data("SERVER_ERROR #{res}\r\n")
66
+ end
67
+ end
68
+ end
69
+
70
+ # getroute <vnode-id>
71
+ def ev_getroute(s)
72
+ if s.length < 2
73
+ send_data("CLIENT_ERROR\r\n")
74
+ return
75
+ end
76
+ clk,nids = @rttable.search_nodes_with_clk(s[1].to_i)
77
+ if clk == nil
78
+ send_data("END\r\n")
79
+ return
80
+ end
81
+ res = "#{clk-1}"
82
+ nids.each{ |nid| res << " #{nid}" }
83
+ send_data("#{res}\r\n")
84
+ end
85
+
86
+ # mklhash <id>
87
+ def ev_mklhash(s)
88
+ send_data("#{@rttable.mtree.get(s[1])}\r\n")
89
+ end
90
+
91
+ # history_of_lost [yyyymmddhhmmss]
92
+ def ev_history_of_lost(s)
93
+ if s.length != 2
94
+ t = Time.mktime(2000, 1, 1, 0, 0, 0)
95
+ else
96
+ t = Time.mktime(s[1][0..3], s[1][4..5], s[1][6..7], s[1][8..9], s[1][10..11], s[1][12..13])
97
+ end
98
+ nodes = @rttable.search_lost_vnodes(t)
99
+ nodes.each{|vn| send_data("#{vn}\r\n") }
100
+ send_data("END\r\n")
101
+ rescue =>e
102
+ send_data("CLIENT_ERROR\r\n")
103
+ end
104
+
105
+ # set_threshold_for_failover <n>
106
+ def ev_set_threshold_for_failover(s)
107
+ if s.length != 2 || s[1].to_i == 0
108
+ return send_data("usage:set_threshold_for_failover <n>\r\n")
109
+ end
110
+ res = broadcast_cmd("rset_threshold_for_failover #{s[1]}\r\n")
111
+ @rttable.fail_cnt_threshold = s[1].to_i
112
+ res[@stats.ap_str] = "STORED"
113
+ send_data("#{res}\r\n")
114
+ end
115
+
116
+ # rset_threshold_for_failover <n>
117
+ def ev_rset_threshold_for_failover(s)
118
+ if s.length != 2 || s[1].to_i == 0
119
+ return send_data("usage:set_threshold_for_failover <n>\r\n")
120
+ end
121
+ @rttable.fail_cnt_threshold = s[1].to_i
122
+ send_data("STORED\r\n")
123
+ end
124
+
125
+ # set_gap_for_failover
126
+ def ev_set_gap_for_failover(s)
127
+ if s.length != 2
128
+ return send_data("usage:set_gap_for_failover <n>\r\n")
129
+ end
130
+ res = broadcast_cmd("rset_gap_for_failover #{s[1]}\r\n")
131
+ @rttable.fail_cnt_gap = s[1].to_f
132
+ res[@stats.ap_str] = "STORED"
133
+ send_data("#{res}\r\n")
134
+ end
135
+
136
+ # rset_gap_for_failover
137
+ def ev_rset_gap_for_failover(s)
138
+ if s.length != 2
139
+ return send_data("usage:rset_gap_for_failover <n>\r\n")
140
+ end
141
+ @rttable.fail_cnt_gap = s[1].to_f
142
+ send_data("STORED\r\n")
143
+ end
144
+
145
+ end # module RoutingCommandReceiver
146
+ end # module Command
147
+ end # module Roma
@@ -0,0 +1,564 @@
1
+ require 'zlib'
2
+ require 'digest/sha1'
3
+ require "roma/config"
4
+ require 'roma/async_process'
5
+
6
+ module Roma
7
+ module Command
8
+
9
+ module StorageCommandReceiver
10
+
11
+ # "set" means "store this data".
12
+ # <command name> <key> <flags> <exptime> <bytes> [noreply]\r\n
13
+ # <data block>\r\n
14
+ def ev_set(s); set(:set,s); end
15
+ def ev_fset(s); fset(:set,s); end
16
+
17
+ # rset <key> <hash value> <timelimit> <length>
18
+ # "set" means "store this data".
19
+ # <command name> <key> <digest> <exptime> <bytes> [noreply]\r\n
20
+ # <data block>\r\n
21
+ def ev_rset(s)
22
+ key,hname = s[1].split("\e")
23
+ hname ||= @defhash
24
+ d = s[2].to_i
25
+ d = Digest::SHA1.hexdigest(key).hex % @rttable.hbits if d == 0
26
+ data = read_bytes(s[5].to_i)
27
+ read_bytes(2)
28
+ vn = @rttable.get_vnode_id(d)
29
+ unless @storages.key?(hname)
30
+ send_data("SERVER_ERROR #{hname} dose not exists.\r\n")
31
+ return
32
+ end
33
+ if @storages[hname].rset(vn, key, d, s[3].to_i, s[4].to_i, data)
34
+ send_data("STORED\r\n")
35
+ else
36
+ @log.error("rset NOT_STORED:#{@storages[hname].error_message} #{vn} #{s[1]} #{d} #{s[3]} #{s[4]}")
37
+ send_data("NOT_STORED\r\n")
38
+ end
39
+ @stats.redundant_count += 1
40
+ end
41
+
42
+ # <command name> <key> <digest> <exptime> <bytes> [noreply]\r\n
43
+ # <compressed data block>\r\n
44
+ def ev_rzset(s)
45
+ key,hname = s[1].split("\e")
46
+ hname ||= @defhash
47
+ d = s[2].to_i
48
+ d = Digest::SHA1.hexdigest(key).hex % @rttable.hbits if d == 0
49
+ zdata = read_bytes(s[5].to_i)
50
+ read_bytes(2)
51
+ vn = @rttable.get_vnode_id(d)
52
+ unless @storages.key?(hname)
53
+ send_data("SERVER_ERROR #{hname} dose not exists.\r\n")
54
+ return
55
+ end
56
+
57
+ data = Zlib::Inflate.inflate(zdata)
58
+ if @storages[hname].rset(vn, key, d, s[3].to_i, s[4].to_i, data)
59
+ send_data("STORED\r\n")
60
+ else
61
+ @log.error("rzset NOT_STORED:#{@storages[hname].error_message} #{vn} #{s[1]} #{d} #{s[3]} #{s[4]}")
62
+ send_data("NOT_STORED\r\n")
63
+ end
64
+ @stats.redundant_count += 1
65
+ rescue Zlib::DataError => e
66
+ @log.error("rzset NOT_STORED:#{e} #{vn} #{s[1]} #{d} #{s[3]} #{s[4]}")
67
+ send_data("NOT_STORED\r\n")
68
+ end
69
+
70
+ # get <key>*\r\n
71
+ def ev_get(s)
72
+ return ev_gets(s) if s.length > 2
73
+
74
+ key,hname = s[1].split("\e")
75
+ hname ||= @defhash
76
+ d = Digest::SHA1.hexdigest(key).hex % @rttable.hbits
77
+ vn = @rttable.get_vnode_id(d)
78
+ unless @storages.key?(hname)
79
+ send_data("SERVER_ERROR #{hname} dose not exists.\r\n")
80
+ return
81
+ end
82
+ data = @storages[hname].get(vn, key, 0)
83
+ @stats.read_count += 1
84
+ if data
85
+ return send_data("VALUE #{s[1]} 0 #{data.length}\r\n#{data}\r\nEND\r\n")
86
+ end
87
+
88
+ nodes = @rttable.search_nodes(vn)
89
+ if nodes.include?(@nid)
90
+ return send_data("END\r\n")
91
+ end
92
+
93
+ nodes.delete(@nid)
94
+ if nodes.length != 0
95
+ @log.warn("forward get #{s[1]}")
96
+ res = forward_get(nodes[0], s[1], d)
97
+ if res
98
+ return send_data(res)
99
+ end
100
+ end
101
+ send_data("SERVER_ERROR Message forward failed.\r\n")
102
+ end
103
+
104
+ # gets <key>*\r\n
105
+ def ev_gets(s)
106
+ nk = {} # {node-id1=>[key1,key2,..],node-id2=>[key3,key4,..]}
107
+ kvn = {} # {key1=>vn1, key2=>vn2, ... }
108
+ s[1..-1].each{|kh|
109
+ key, = kh.split("\e") # split a hash-name
110
+ d = Digest::SHA1.hexdigest(key).hex % @rttable.hbits
111
+ kvn[key] = vn = @rttable.get_vnode_id(d)
112
+ nodes = @rttable.search_nodes(vn)
113
+ unless nodes.empty? # check the node existence
114
+ nk[nodes[0]]=[] unless nk.key?(nodes[0])
115
+ nk[nodes[0]] << kh
116
+ end
117
+ }
118
+
119
+ res = {} # result data {key1=>val1,key2=>val2,...}
120
+ if nk.key?(@nid)
121
+ nk[@nid].each{|kh|
122
+ key,hname = kh.split("\e")
123
+ hname ||= @defhash
124
+ if @storages.key?(hname)
125
+ vn, t, clk, expt, val = @storages[hname].get_raw(kvn[key], key, 0)
126
+ @stats.read_count += 1
127
+ res[key] = [clk, val] if val && Time.now.to_i <= expt
128
+ end
129
+ }
130
+ nk.delete(@nid)
131
+ end
132
+
133
+ nk.each_pair{|nid,keys|
134
+ res.merge!(forward_gets(nid,keys))
135
+ }
136
+
137
+ res.each_pair{|key,cv|
138
+ clk, val = cv
139
+ send_data("VALUE #{key} 0 #{val.length} #{clk}\r\n#{val}\r\n")
140
+ }
141
+ send_data("END\r\n")
142
+ end
143
+
144
+
145
+ # delete <key> [<time>] [noreply]\r\n
146
+ def ev_delete(s)
147
+ key,hname = s[1].split("\e")
148
+ hname ||= @defhash
149
+ d = Digest::SHA1.hexdigest(key).hex % @rttable.hbits
150
+ vn = @rttable.get_vnode_id(d)
151
+ nodes = @rttable.search_nodes_for_write(vn)
152
+ if nodes[0] != @nid
153
+ cmd = "fdelete #{s[1]}"
154
+ s[2..-1].each{|c| cmd << " #{c}"}
155
+ cmd << "\r\n"
156
+ @log.warn("forward delete #{s[1]}")
157
+ res = send_cmd(nodes[0], cmd)
158
+ if res
159
+ return send_data("#{res}\r\n")
160
+ end
161
+ return send_data("SERVER_ERROR Message forward failed.\r\n")
162
+ end
163
+ unless @storages.key?(hname)
164
+ send_data("SERVER_ERROR #{hname} dose not exists.\r\n")
165
+ return
166
+ end
167
+ res = @storages[hname].delete(vn, key, d)
168
+ @stats.delete_count += 1
169
+ return send_data("NOT_DELETED\r\n") unless res
170
+ return send_data("NOT_FOUND\r\n") if res == :deletemark
171
+
172
+ nodes[1..-1].each{ |nid|
173
+ send_cmd(nid,"rdelete #{s[1]} #{res[2]}\r\n")
174
+ }
175
+ return send_data("NOT_FOUND\r\n") unless res[4]
176
+ send_data("DELETED\r\n")
177
+ end
178
+
179
+ # fdelete <key> [<time>] [noreply]\r\n
180
+ def ev_fdelete(s)
181
+ key,hname = s[1].split("\e")
182
+ hname ||= @defhash
183
+ d = Digest::SHA1.hexdigest(key).hex % @rttable.hbits
184
+ vn = @rttable.get_vnode_id(d)
185
+ nodes = @rttable.search_nodes_for_write(vn)
186
+ if nodes.include?(@nid) == false
187
+ @log.error("fdelete failed delete key=#{s[1]} vn=#{vn}")
188
+ return send_data("SERVER_ERROR Routing table is inconsistent.\r\n")
189
+ end
190
+ unless @storages.key?(hname)
191
+ send_data("SERVER_ERROR #{hname} dose not exists.\r\n")
192
+ return
193
+ end
194
+ res = @storages[hname].delete(vn, key, d)
195
+ @stats.delete_count += 1
196
+ return send_data("NOT_DELETED\r\n") unless res
197
+ return send_data("NOT_FOUND\r\n") if res == :deletemark
198
+
199
+ nodes.delete(@nid)
200
+ nodes.each{ |nid|
201
+ send_cmd(nid,"rdelete #{s[1]} #{res[2]}\r\n")
202
+ }
203
+ return send_data("NOT_FOUND\r\n") unless res[4]
204
+ send_data("DELETED\r\n")
205
+ end
206
+
207
+ # rdelete <key> <clock>
208
+ def ev_rdelete(s)
209
+ key,hname = s[1].split("\e")
210
+ hname ||= @defhash
211
+ d = Digest::SHA1.hexdigest(key).hex % @rttable.hbits
212
+ vn = @rttable.get_vnode_id(d)
213
+ unless @storages.key?(hname)
214
+ send_data("SERVER_ERROR #{hname} dose not exists.\r\n")
215
+ return
216
+ end
217
+ if @storages[hname].rdelete(vn, key, d, s[2].to_i)
218
+ send_data("DELETED\r\n")
219
+ else
220
+ send_data("NOT_FOUND\r\n")
221
+ end
222
+ end
223
+
224
+ # out <key> <vn>
225
+ def ev_out(s)
226
+ key,hname = s[1].split("\e")
227
+ hname ||= @defhash
228
+ if s.length >= 3
229
+ vn = s[2].to_i
230
+ else
231
+ d = Digest::SHA1.hexdigest(key).hex % @rttable.hbits
232
+ vn = @rttable.get_vnode_id(d)
233
+ end
234
+ res = @storages[hname].out(vn, key, 0)
235
+ @stats.out_message_count += 1
236
+ unless res
237
+ return send_data("NOT_DELETED\r\n")
238
+ end
239
+ send_data("DELETED\r\n")
240
+ end
241
+
242
+ # "add" means that "add a new data to a store"
243
+ # <command name> <key> <flags> <exptime> <bytes> [noreply]\r\n
244
+ # <data block>\r\n
245
+ def ev_add(s); set(:add,s); end
246
+ def ev_fadd(s); fset(:add,s); end
247
+
248
+ # "replace" means that "replace the previous data with a new one"
249
+ # <command name> <key> <flags> <exptime> <bytes> [noreply]\r\n
250
+ # <data block>\r\n
251
+ def ev_replace(s); set(:replace,s); end
252
+ def ev_freplace(s); fset(:replace,s); end
253
+
254
+ # "append" means that "append a new data to the previous one"
255
+ # <command name> <key> <flags> <exptime> <bytes> [noreply]\r\n
256
+ # <data block>\r\n
257
+ def ev_append(s); set(:append,s); end
258
+ def ev_fappend(s); fset(:append,s); end
259
+
260
+ # "prepend" means that "prepend a new data to the previous one"
261
+ # <command name> <key> <flags> <exptime> <bytes> [noreply]\r\n
262
+ # <data block>\r\n
263
+ def ev_prepend(s); set(:prepend,s); end
264
+ def ev_fprepend(s); fset(:prepend,s); end
265
+
266
+
267
+ # "cas" means that "store this data but only if no one else has updated since I last fetched it."
268
+ # <command name> <key> <flags> <exptime> <bytes> <cas-id>[noreply]\r\n
269
+ # <data block>\r\n
270
+ def ev_cas(s)
271
+ key,hname = s[1].split("\e")
272
+ hname ||= @defhash
273
+ d = Digest::SHA1.hexdigest(key).hex % @rttable.hbits
274
+ v = read_bytes(s[4].to_i)
275
+ read_bytes(2)
276
+ vn = @rttable.get_vnode_id(d)
277
+ nodes = @rttable.search_nodes_for_write(vn)
278
+ if nodes[0] != @nid
279
+ @log.warn("forward cas key=#{key} vn=#{vn} to #{nodes[0]}")
280
+ res = send_cmd(nodes[0],"fcas #{s[1]} #{d} #{s[3]} #{v.length} #{s[5]}\r\n#{v}\r\n")
281
+ if res
282
+ return send_data("#{res}\r\n")
283
+ end
284
+ return send_data("SERVER_ERROR Message forward failed.\r\n")
285
+ end
286
+
287
+ store_cas(hname, vn, key, d, s[5].to_i, s[3].to_i, v, nodes[1..-1])
288
+ end
289
+
290
+ def ev_fcas(s)
291
+ key,hname = s[1].split("\e")
292
+ hname ||= @defhash
293
+ d = s[2].to_i
294
+ d = Digest::SHA1.hexdigest(key).hex % @rttable.hbits if d == 0
295
+ v = read_bytes(s[4].to_i)
296
+ read_bytes(2)
297
+ vn = @rttable.get_vnode_id(d)
298
+ nodes = @rttable.search_nodes_for_write(vn)
299
+ if nodes.include?(@nid) == false
300
+ @log.error("fcas failed key = #{s[1]} vn = #{vn}")
301
+ return send_data("SERVER_ERROR Routing table is inconsistent.\r\n")
302
+ end
303
+
304
+ nodes.delete(@nid)
305
+ store_cas(hname, vn, key, d, s[5].to_i, s[3].to_i, v, nodes)
306
+ end
307
+
308
+ # incr <key> <value> [noreply]\r\n
309
+ def ev_incr(s); incr_decr(:incr,s); end
310
+ def ev_fincr(s); fincr_fdecr(:incr,s); end
311
+
312
+ # decr <key> <value> [noreply]\r\n
313
+ def ev_decr(s); incr_decr(:decr,s); end
314
+ def ev_fdecr(s); fincr_fdecr(:decr,s); end
315
+
316
+ # set_size_of_zredundant <n>
317
+ def ev_set_size_of_zredundant(s)
318
+ if s.length != 2 || s[1].to_i == 0
319
+ return send_data("usage:set_set_size_of_zredundant <n>\r\n")
320
+ end
321
+ res = broadcast_cmd("rset_size_of_zredundant #{s[1]}\r\n")
322
+ @stats.size_of_zredundant = s[1].to_i
323
+ res[@stats.ap_str] = "STORED"
324
+ send_data("#{res}\r\n")
325
+ end
326
+
327
+ # rset_size_of_zredundant <n>
328
+ def ev_rset_size_of_zredundant(s)
329
+ if s.length != 2 || s[1].to_i == 0
330
+ return send_data("usage:set_set_size_of_zredundant <n>\r\n")
331
+ end
332
+ @stats.size_of_zredundant = s[1].to_i
333
+ send_data("STORED\r\n")
334
+ end
335
+
336
+ private
337
+
338
+ def forward_get(nid, k, d)
339
+ con = get_connection(nid)
340
+ con.send("get #{k}\r\n")
341
+ res = con.gets
342
+ return res if res == "END\r\n"
343
+ s = res.split(/ /)
344
+ res << con.read_bytes(s[3].to_i + 2)
345
+ res << con.gets
346
+ return_connection(nid, con)
347
+ @rttable.proc_succeed(nid)
348
+ res
349
+ rescue => e
350
+ @rttable.proc_failed(nid)
351
+ @log.error("forward get failed:nid=#{nid} key=#{key}")
352
+ nil
353
+ end
354
+
355
+ def forward_gets(nid, keys)
356
+ con = get_connection(nid)
357
+ con.send("gets #{keys.join(' ')}\r\n")
358
+ res = {}
359
+ while((line = con.gets)!="END\r\n")
360
+ s = line.chomp.split(/ /)
361
+ res[s[1]] = [s[4], con.read_bytes(s[3].to_i)]
362
+ con.read_bytes(2)
363
+ end
364
+ return_connection(nid, con)
365
+ @rttable.proc_succeed(nid)
366
+ res
367
+ rescue => e
368
+ @rttable.proc_failed(nid)
369
+ @log.error("forward gets failed:nid=#{nid} key=#{keys}")
370
+ nil
371
+ end
372
+
373
+ def store(fnc, hname, vn, k, d, expt, v, nodes)
374
+ if expt == 0
375
+ expt = 0x7fffffff
376
+ elsif expt < 2592000
377
+ expt += Time.now.to_i
378
+ end
379
+ unless @storages.key?(hname)
380
+ send_data("SERVER_ERROR #{hname} dose not exists.\r\n")
381
+ return
382
+ end
383
+ ret = @storages[hname].send(fnc, vn, k, d, expt ,v)
384
+ @stats.write_count += 1
385
+ if ret
386
+ redundant(nodes, hname, k, d, ret[2], expt, ret[4])
387
+ send_data("STORED\r\n")
388
+ else
389
+ @log.error("#{fnc} NOT_STORED:#{hname} #{vn} #{k} #{d} #{expt}")
390
+ send_data("NOT_STORED\r\n")
391
+ end
392
+ end
393
+
394
+ def store_cas(hname, vn, k, d, clk, expt, v, nodes)
395
+ if expt == 0
396
+ expt = 0x7fffffff
397
+ elsif expt < 2592000
398
+ expt += Time.now.to_i
399
+ end
400
+ unless @storages.key?(hname)
401
+ send_data("SERVER_ERROR #{hname} dose not exists.\r\n")
402
+ return
403
+ end
404
+
405
+ ret = @storages[hname].cas(vn, k, d, clk, expt ,v)
406
+ @stats.write_count += 1
407
+ case ret
408
+ when nil
409
+ @log.error("cas NOT_STORED:#{hname} #{vn} #{k} #{d} #{expt} #{clk}")
410
+ send_data("NOT_STORED\r\n")
411
+ when :not_found
412
+ send_data("NOT_FOUND\r\n")
413
+ when :exists
414
+ send_data("EXISTS\r\n")
415
+ else
416
+ redundant(nodes, hname, k, d, ret[2], expt, ret[4])
417
+ send_data("STORED\r\n")
418
+ end
419
+ end
420
+
421
+ def redundant(nodes, hname, k, d, clk, expt, v)
422
+ if @rttable.min_version == nil || @rttable.min_version < 0x000306 # ver.0.3.6
423
+ return redundant_older_than_000306(nodes, hname, k, d, clk, expt, v)
424
+ end
425
+
426
+ if @stats.size_of_zredundant > 0 && @stats.size_of_zredundant < v.length
427
+ return zredundant(nodes, hname, k, d, clk, expt, v)
428
+ end
429
+
430
+ nodes.each{ |nid|
431
+ res = send_cmd(nid,"rset #{k}\e#{hname} #{d} #{clk} #{expt} #{v.length}\r\n#{v}\r\n")
432
+ unless res
433
+ Roma::AsyncProcess::queue.push(Roma::AsyncMessage.new('redundant',[nid,hname,k,d,clk,expt,v]))
434
+ @log.warn("redundant failed:#{k}\e#{hname} #{d} #{clk} #{expt} #{v.length} -> #{nid}")
435
+ end
436
+ }
437
+ end
438
+
439
+ def redundant_older_than_000306(nodes, hname, k, d, clk, expt, v)
440
+ nodes.each{ |nid|
441
+ if @rttable.version_of_nodes[nid] >= 0x000306 &&
442
+ @stats.size_of_zredundant > 0 && @stats.size_of_zredundant < v.length
443
+
444
+ zv = Zlib::Deflate.deflate(v) unless zv
445
+ res = send_cmd(nid,"rzset #{k}\e#{hname} #{d} #{clk} #{expt} #{zv.length}\r\n#{zv}\r\n")
446
+ unless res
447
+ Roma::AsyncProcess::queue.push(Roma::AsyncMessage.new('zredundant',[nid,hname,k,d,clk,expt,zv]))
448
+ @log.warn("redundant_older_than_000306 failed:#{k}\e#{hname} #{d} #{clk} #{expt} #{zv.length} -> #{nid}")
449
+ end
450
+ else
451
+ res = send_cmd(nid,"rset #{k}\e#{hname} #{d} #{clk} #{expt} #{v.length}\r\n#{v}\r\n")
452
+ unless res
453
+ Roma::AsyncProcess::queue.push(Roma::AsyncMessage.new('redundant',[nid,hname,k,d,clk,expt,v]))
454
+ @log.warn("redundant_older_than_000306 failed:#{k}\e#{hname} #{d} #{clk} #{expt} #{v.length} -> #{nid}")
455
+ end
456
+ end
457
+ }
458
+ end
459
+
460
+ def zredundant(nodes, hname, k, d, clk, expt, v)
461
+ zv = Zlib::Deflate.deflate(v)
462
+
463
+ nodes.each{ |nid|
464
+ res = send_cmd(nid,"rzset #{k}\e#{hname} #{d} #{clk} #{expt} #{zv.length}\r\n#{zv}\r\n")
465
+ unless res
466
+ Roma::AsyncProcess::queue.push(Roma::AsyncMessage.new('zredundant',[nid,hname,k,d,clk,expt,zv]))
467
+ @log.warn("zredundant failed:#{k}\e#{hname} #{d} #{clk} #{expt} #{zv.length} -> #{nid}")
468
+ end
469
+ }
470
+ end
471
+
472
+ def set(fnc,s)
473
+ key,hname = s[1].split("\e")
474
+ hname ||= @defhash
475
+ d = Digest::SHA1.hexdigest(key).hex % @rttable.hbits
476
+ v = read_bytes(s[4].to_i)
477
+ read_bytes(2)
478
+ vn = @rttable.get_vnode_id(d)
479
+ nodes = @rttable.search_nodes_for_write(vn)
480
+ if nodes[0] != @nid
481
+ @log.warn("forward #{fnc} key=#{key} vn=#{vn} to #{nodes[0]}")
482
+ res = send_cmd(nodes[0],"f#{fnc} #{s[1]} #{d} #{s[3]} #{v.length}\r\n#{v}\r\n")
483
+ if res
484
+ return send_data("#{res}\r\n")
485
+ end
486
+ return send_data("SERVER_ERROR Message forward failed.\r\n")
487
+ end
488
+
489
+ store(fnc, hname, vn, key, d, s[3].to_i, v, nodes[1..-1])
490
+ end
491
+
492
+ def fset(fnc,s)
493
+ key,hname = s[1].split("\e")
494
+ hname ||= @defhash
495
+ d = s[2].to_i
496
+ d = Digest::SHA1.hexdigest(key).hex % @rttable.hbits if d == 0
497
+ v = read_bytes(s[4].to_i)
498
+ read_bytes(2)
499
+ vn = @rttable.get_vnode_id(d)
500
+ nodes = @rttable.search_nodes_for_write(vn)
501
+ if nodes.include?(@nid) == false
502
+ @log.error("f#{fnc} failed key = #{s[1]} vn = #{vn}")
503
+ return send_data("SERVER_ERROR Routing table is inconsistent.\r\n")
504
+ end
505
+
506
+ nodes.delete(@nid)
507
+ store(fnc, hname, vn, key, d, s[3].to_i, v, nodes)
508
+ end
509
+
510
+ def store_incr_decr(fnc, hname, vn, k, d, v, nodes)
511
+ unless @storages.key?(hname)
512
+ send_data("SERVER_ERROR #{hname} dose not exists.\r\n")
513
+ return
514
+ end
515
+ res = @storages[hname].send(fnc, vn, k, d, v)
516
+ @stats.write_count += 1
517
+ if res
518
+ redundant(nodes, hname, k, d, res[2], res[3], res[4])
519
+ send_data("#{res[4]}\r\n")
520
+ else
521
+ send_data("NOT_FOUND\r\n")
522
+ end
523
+ end
524
+
525
+ def incr_decr(fnc,s)
526
+ key,hname = s[1].split("\e")
527
+ hname ||= @defhash
528
+ d = Digest::SHA1.hexdigest(key).hex % @rttable.hbits
529
+ v = s[2].to_i
530
+ vn = @rttable.get_vnode_id(d)
531
+ nodes = @rttable.search_nodes_for_write(vn)
532
+ if nodes[0] != @nid
533
+ @log.debug("forward #{fnc} key=#{s[1]} vn=#{vn} to #{nodes[0]}")
534
+ res = send_cmd(nodes[0],"f#{fnc} #{s[1]} #{d} #{s[2]}\r\n")
535
+ if res
536
+ return send_data("#{res}\r\n")
537
+ end
538
+ return send_data("SERVER_ERROR Message forward failed.\r\n")
539
+ end
540
+
541
+ store_incr_decr(fnc, hname, vn, key, d, v, nodes[1..-1])
542
+ end
543
+
544
+ def fincr_fdecr(fnc,s)
545
+ key,hname = s[1].split("\e")
546
+ hname ||= @defhash
547
+ d = s[2].to_i
548
+ d = Digest::SHA1.hexdigest(key).hex % @rttable.hbits if d == 0
549
+ v = s[3].to_i
550
+ vn = @rttable.get_vnode_id(d)
551
+ nodes = @rttable.search_nodes_for_write(vn)
552
+ if nodes.include?(@nid) == false
553
+ @log.debug("f#{fnc} failed key = #{s[1]} vn = #{vn}")
554
+ return send_data("SERVER_ERROR Routing table is inconsistent.\r\n")
555
+ end
556
+
557
+ nodes.delete(@nid)
558
+ store_incr_decr(fnc, hname, vn, key, d, v, nodes)
559
+ end
560
+
561
+ end # module StorageCommandReceiver
562
+
563
+ end # module Command
564
+ end # module Roma