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