roma 0.8.2

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 (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