roma 0.8.2
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.rdoc +675 -0
- data/README.rdoc +0 -0
- data/Rakefile +70 -0
- data/bin/mkrecent +7 -0
- data/bin/mkroute +7 -0
- data/bin/recoverlost +8 -0
- data/bin/recoverlost_alist +8 -0
- data/bin/romad +7 -0
- data/bin/sample_watcher +8 -0
- data/bin/sample_watcher2 +8 -0
- data/bin/simple_bench +8 -0
- data/bin/ssroute +7 -0
- data/bin/tribunus +7 -0
- data/lib/roma/async_process.rb +696 -0
- data/lib/roma/command/bg_command_receiver.rb +188 -0
- data/lib/roma/command/mh_command_receiver.rb +117 -0
- data/lib/roma/command/receiver.rb +287 -0
- data/lib/roma/command/rt_command_receiver.rb +147 -0
- data/lib/roma/command/st_command_receiver.rb +564 -0
- data/lib/roma/command/util_command_receiver.rb +67 -0
- data/lib/roma/command/vn_command_receiver.rb +143 -0
- data/lib/roma/command_plugin.rb +11 -0
- data/lib/roma/config.rb +64 -0
- data/lib/roma/event/con_pool.rb +140 -0
- data/lib/roma/event/handler.rb +159 -0
- data/lib/roma/plugin/plugin_alist.rb +1572 -0
- data/lib/roma/plugin/plugin_debug.rb +19 -0
- data/lib/roma/plugin/plugin_test.rb +14 -0
- data/lib/roma/romad.rb +582 -0
- data/lib/roma/routing/cb_rttable.rb +326 -0
- data/lib/roma/routing/merkle_tree.rb +54 -0
- data/lib/roma/routing/rttable.rb +148 -0
- data/lib/roma/stats.rb +112 -0
- data/lib/roma/storage/basic_storage.rb +510 -0
- data/lib/roma/storage/dbm_storage.rb +80 -0
- data/lib/roma/storage/dummy_storage.rb +44 -0
- data/lib/roma/storage/rh_storage.rb +35 -0
- data/lib/roma/storage/sqlite3_storage.rb +73 -0
- data/lib/roma/storage/tc_storage.rb +133 -0
- data/lib/roma/tools/mkrecent.rb +138 -0
- data/lib/roma/tools/mkroute.rb +52 -0
- data/lib/roma/tools/recoverlost.rb +9 -0
- data/lib/roma/tools/recoverlost_alist.rb +9 -0
- data/lib/roma/tools/recoverlost_lib.rb +217 -0
- data/lib/roma/tools/sample_watcher.rb +38 -0
- data/lib/roma/tools/sample_watcher2.rb +38 -0
- data/lib/roma/tools/simple_bench.rb +57 -0
- data/lib/roma/tools/ssroute.rb +23 -0
- data/lib/roma/tools/tribunus.rb +299 -0
- data/lib/roma/version.rb +4 -0
- data/lib/roma/write_behind.rb +179 -0
- data/test/rcirb.rb +16 -0
- data/test/roma-test-utils.rb +65 -0
- data/test/run-test.rb +16 -0
- data/test/t_cpdata.rb +277 -0
- data/test/t_listplugin.rb +592 -0
- data/test/t_rclient.rb +318 -0
- data/test/t_routing_data.rb +100 -0
- data/test/t_storage.rb +644 -0
- data/test/t_writebehind.rb +200 -0
- 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
|