roma-client 0.3.7
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 +674 -0
- data/README +17 -0
- data/Rakefile +59 -0
- data/bin/rcdaemon +6 -0
- data/bin/sample +23 -0
- data/bin/showbalance +6 -0
- data/lib/roma/client/client_rttable.rb +77 -0
- data/lib/roma/client/con_pool.rb +76 -0
- data/lib/roma/client/proxy/daemon.rb +281 -0
- data/lib/roma/client/proxy/version.rb +25 -0
- data/lib/roma/client/rclient.rb +409 -0
- data/lib/roma/client/rlogger.rb +148 -0
- data/lib/roma/client/routing/routing_data.rb +241 -0
- data/lib/roma/client/sender.rb +155 -0
- data/lib/roma/client/tools/showbalance.rb +33 -0
- data/lib/roma/client/version.rb +25 -0
- data/lib/roma/client.rb +22 -0
- metadata +75 -0
@@ -0,0 +1,241 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Roma
|
4
|
+
module Routing
|
5
|
+
|
6
|
+
class RoutingData
|
7
|
+
attr_accessor :dgst_bits
|
8
|
+
attr_accessor :div_bits
|
9
|
+
attr_accessor :rn
|
10
|
+
attr_accessor :nodes
|
11
|
+
attr_accessor :v_idx
|
12
|
+
attr_accessor :v_clk
|
13
|
+
|
14
|
+
def initialize(dgst_bits,div_bits,rn)
|
15
|
+
@dgst_bits=dgst_bits
|
16
|
+
@div_bits=div_bits
|
17
|
+
@rn=rn
|
18
|
+
@nodes=[]
|
19
|
+
@v_idx={}
|
20
|
+
@v_clk={}
|
21
|
+
end
|
22
|
+
|
23
|
+
def save(fname)
|
24
|
+
@nodes.sort!
|
25
|
+
open(fname,'wb'){|io|
|
26
|
+
io.write(YAML.dump(self))
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.load(fname)
|
31
|
+
rd=load_snapshot(fname)
|
32
|
+
rd.load_log_all(fname)
|
33
|
+
rd
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.load_snapshot(fname)
|
37
|
+
rd=nil
|
38
|
+
open(fname,'rb'){|io|
|
39
|
+
rd = YAML.load(io.read)
|
40
|
+
}
|
41
|
+
rd
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.snapshot(fname)
|
45
|
+
rd=load_snapshot(fname)
|
46
|
+
loglist=rd.get_file_list(fname)
|
47
|
+
if loglist.length<2
|
48
|
+
return false
|
49
|
+
end
|
50
|
+
loglist.delete(loglist.last)
|
51
|
+
loglist.each{|i,f|
|
52
|
+
rd.load_log_one(f)
|
53
|
+
File.rename(f,"#{f}~")
|
54
|
+
}
|
55
|
+
File.rename(fname,"#{fname}~")
|
56
|
+
rd.save(fname)
|
57
|
+
true
|
58
|
+
end
|
59
|
+
|
60
|
+
def each_log_all(fname)
|
61
|
+
loglist=get_file_list(fname)
|
62
|
+
loglist.each{|i,f|
|
63
|
+
each_log_one(f){|t,l| yield t,l}
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
def each_log_one(fname)
|
68
|
+
File.open(fname,"r"){|f|
|
69
|
+
while((line=f.gets)!=nil)
|
70
|
+
line.chomp!
|
71
|
+
next if line[0]=="#" || line.length==0
|
72
|
+
if line =~ /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\.\d+\s(.+)/
|
73
|
+
yield Time.mktime($1, $2, $3, $4, $5, $6), $7
|
74
|
+
end
|
75
|
+
end
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
def load_log_all(fname)
|
80
|
+
each_log_all(fname){|t,line|
|
81
|
+
parse_log(t,line)
|
82
|
+
}
|
83
|
+
@nodes.sort!
|
84
|
+
end
|
85
|
+
|
86
|
+
def load_log_one(fname)
|
87
|
+
each_log_one(fname){|t,line|
|
88
|
+
parse_log(t,line)
|
89
|
+
}
|
90
|
+
@nodes.sort!
|
91
|
+
end
|
92
|
+
|
93
|
+
def parse_log(t,line)
|
94
|
+
s=line.split(' ')
|
95
|
+
case s[0]
|
96
|
+
when 'setroute'
|
97
|
+
# setroute <vnode-id> <clock> <node-id> ...
|
98
|
+
nids=[]
|
99
|
+
s[3..-1].each{ |nid| nids << nid }
|
100
|
+
@v_idx[s[1].to_i]=nids
|
101
|
+
@v_clk[s[1].to_i]=s[2].to_i
|
102
|
+
when 'join'
|
103
|
+
# join <node-id>
|
104
|
+
@nodes << s[1] unless @nodes.include?(s[1])
|
105
|
+
when 'leave'
|
106
|
+
# leave <node-id>
|
107
|
+
@nodes.delete(s[1])
|
108
|
+
else
|
109
|
+
raise "RoutingData.parse_log:parse error #{line}"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def search_mask
|
114
|
+
2**@div_bits-1<<(@dgst_bits-@div_bits)
|
115
|
+
end
|
116
|
+
|
117
|
+
def next_vnode(vn)
|
118
|
+
n = (vn >> (@dgst_bits-@div_bits)) + 1
|
119
|
+
n = 0 if n == (2**@div_bits)
|
120
|
+
n << (@dgst_bits-@div_bits)
|
121
|
+
end
|
122
|
+
|
123
|
+
def create_nodes_from_v_idx
|
124
|
+
buf_nodes={}
|
125
|
+
v_idx.each_value{|nids|
|
126
|
+
nids.each{|nid| buf_nodes[nid]=nid }
|
127
|
+
}
|
128
|
+
@nodes=buf_nodes.values.sort
|
129
|
+
end
|
130
|
+
|
131
|
+
# Returns the losted vnode-id list.
|
132
|
+
def get_lost_vnodes
|
133
|
+
ret=[]
|
134
|
+
v_idx.each_pair{|vn,nids|
|
135
|
+
ret << vn if nids.length == 0
|
136
|
+
}
|
137
|
+
ret
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.create(dgst_bits,div_bits,rn,nodes,repethost=false)
|
141
|
+
ret=RoutingData.new(dgst_bits,div_bits,rn)
|
142
|
+
ret.nodes=nodes.clone
|
143
|
+
|
144
|
+
rnlm=RandomNodeListMaker.new(nodes,repethost)
|
145
|
+
|
146
|
+
(2**div_bits).times{|i|
|
147
|
+
vn=i<<(dgst_bits-div_bits)
|
148
|
+
ret.v_clk[vn]=0
|
149
|
+
ret.v_idx[vn]=rnlm.list(rn)
|
150
|
+
}
|
151
|
+
ret
|
152
|
+
end
|
153
|
+
|
154
|
+
# Returns the log file list by old ordered.
|
155
|
+
# +fname+:: Prefix of a log file.(ex.roma0_3300.route)
|
156
|
+
# One of the following example:
|
157
|
+
# [[1, "roma0_3300.route.1"], [2, "roma0_3300.route.2"]]
|
158
|
+
def get_file_list(fname)
|
159
|
+
l={}
|
160
|
+
files=Dir.glob("#{fname}*")
|
161
|
+
files.each{ |file|
|
162
|
+
if /#{fname}\.(\d+)$/=~file
|
163
|
+
l[$1.to_i]=$&
|
164
|
+
end
|
165
|
+
}
|
166
|
+
# sorted by old order
|
167
|
+
l.to_a.sort{|a,b| a[0]<=>b[0]}
|
168
|
+
end
|
169
|
+
|
170
|
+
def get_histgram
|
171
|
+
ret = {}
|
172
|
+
nodes.each{|nid|
|
173
|
+
ret[nid] = Array.new(rn,0)
|
174
|
+
}
|
175
|
+
v_idx.each_pair{|vn,nids|
|
176
|
+
nids.each_with_index{|nid,i|
|
177
|
+
ret[nid][i] += 1
|
178
|
+
}
|
179
|
+
}
|
180
|
+
ret
|
181
|
+
end
|
182
|
+
|
183
|
+
private
|
184
|
+
|
185
|
+
class RandomNodeListMaker
|
186
|
+
def initialize(nodes,repethost)
|
187
|
+
@repethost=repethost
|
188
|
+
@nodes=nodes
|
189
|
+
@host_idx={}
|
190
|
+
nodes.each{|nid|
|
191
|
+
h,p=nid.split('_')
|
192
|
+
if @host_idx.key?(h)
|
193
|
+
@host_idx[h] << nid
|
194
|
+
else
|
195
|
+
@host_idx[h]=[nid]
|
196
|
+
end
|
197
|
+
}
|
198
|
+
end
|
199
|
+
|
200
|
+
# Returns the random node-list without repetition.
|
201
|
+
# +n+:: list length
|
202
|
+
def list(n)
|
203
|
+
ret=[]
|
204
|
+
hosts=[]
|
205
|
+
proc_other_one = :get_other_one
|
206
|
+
proc_other_one = :get_other_one_repethost if @repethost
|
207
|
+
n.times{
|
208
|
+
nid=nil
|
209
|
+
nid=send(proc_other_one,hosts,ret)
|
210
|
+
break unless nid
|
211
|
+
hosts << nid.split('_')[0]
|
212
|
+
ret << nid
|
213
|
+
}
|
214
|
+
ret
|
215
|
+
end
|
216
|
+
|
217
|
+
# +exp_hosts+:: ignore
|
218
|
+
# +exp_nodes+:: exceptional nodes(ex.['roma0_11211'])
|
219
|
+
def get_other_one_repethost(exp_hosts,exp_nodes)
|
220
|
+
buf=@nodes.clone
|
221
|
+
buf.delete_if{|nid| exp_nodes.include?(nid)}
|
222
|
+
buf[rand(buf.length)]
|
223
|
+
end
|
224
|
+
|
225
|
+
# +exp_hosts+:: exceptional hosts(ex.['roma0','roma1'])
|
226
|
+
# +exp_nodes+:: ignore
|
227
|
+
def get_other_one(exp_hosts,exp_nodes)
|
228
|
+
hidx=@host_idx.clone
|
229
|
+
exp_hosts.each{|h| hidx.delete(h) }
|
230
|
+
return nil if hidx.length == 0
|
231
|
+
|
232
|
+
rh=hidx.keys[rand(hidx.keys.length)]
|
233
|
+
nodes=hidx[rh]
|
234
|
+
nodes[rand(nodes.length)]
|
235
|
+
end
|
236
|
+
end # class RandomNodeListMaker
|
237
|
+
|
238
|
+
end # class RoutingData
|
239
|
+
|
240
|
+
end # module Routing
|
241
|
+
end # module Roma
|
@@ -0,0 +1,155 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
require 'yaml'
|
3
|
+
require 'roma/client/con_pool'
|
4
|
+
|
5
|
+
module Roma
|
6
|
+
module Client
|
7
|
+
|
8
|
+
class Sender
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
end
|
12
|
+
|
13
|
+
def send_route_mklhash_command(node_id)
|
14
|
+
timeout(1){
|
15
|
+
conn = ConPool.instance.get_connection(node_id)
|
16
|
+
conn.write "mklhash 0\r\n"
|
17
|
+
ret = conn.gets
|
18
|
+
ConPool.instance.return_connection(node_id, conn)
|
19
|
+
return ret.chomp if ret
|
20
|
+
}
|
21
|
+
rescue =>e
|
22
|
+
STDERR.puts "#{node_id} #{e.inspect}"
|
23
|
+
return nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def send_routedump_command(node_id)
|
27
|
+
timeout(1){
|
28
|
+
buf = RUBY_VERSION.split('.')
|
29
|
+
if buf[0].to_i == 1 && buf[1].to_i == 8
|
30
|
+
return send_routedump_yaml_command(node_id)
|
31
|
+
end
|
32
|
+
conn = ConPool.instance.get_connection(node_id)
|
33
|
+
conn.write "routingdump\r\n"
|
34
|
+
routes_length = conn.gets.to_i
|
35
|
+
if (routes_length <= 0)
|
36
|
+
conn.close
|
37
|
+
return :error if routes_length < 0
|
38
|
+
return nil
|
39
|
+
end
|
40
|
+
|
41
|
+
routes = ''
|
42
|
+
while (routes.length != routes_length)
|
43
|
+
routes = routes + conn.read(routes_length - routes.length)
|
44
|
+
end
|
45
|
+
conn.read(2) # "\r\n"
|
46
|
+
conn.gets
|
47
|
+
rd = Marshal.load(routes)
|
48
|
+
ConPool.instance.return_connection(node_id, conn)
|
49
|
+
return rd
|
50
|
+
}
|
51
|
+
rescue =>e
|
52
|
+
STDERR.puts "#{node_id} #{e.inspect}"
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
|
56
|
+
def send_routedump_yaml_command(node_id)
|
57
|
+
conn = ConPool.instance.get_connection(node_id)
|
58
|
+
conn.write "routingdump yaml\r\n"
|
59
|
+
|
60
|
+
yaml = ''
|
61
|
+
while( (line = conn.gets) != "END\r\n" )
|
62
|
+
yaml << line
|
63
|
+
end
|
64
|
+
|
65
|
+
rd = YAML.load(yaml)
|
66
|
+
ConPool.instance.return_connection(node_id, conn)
|
67
|
+
return rd
|
68
|
+
end
|
69
|
+
|
70
|
+
def send_stats_command
|
71
|
+
# TODO
|
72
|
+
end
|
73
|
+
|
74
|
+
def send_version_command(ap)
|
75
|
+
conn = ConPool.instance.get_connection(ap)
|
76
|
+
conn.write("version\r\n")
|
77
|
+
res = conn.gets.chomp
|
78
|
+
ConPool.instance.return_connection(ap, conn)
|
79
|
+
raise unless res
|
80
|
+
return res
|
81
|
+
end
|
82
|
+
|
83
|
+
def send_verbosity_command(ap)
|
84
|
+
conn = ConPool.instance.get_connection(ap)
|
85
|
+
# TODO
|
86
|
+
ConPool.instance.return_connection(ap, conn)
|
87
|
+
end
|
88
|
+
|
89
|
+
def send_command(nid, cmd, value = nil, receiver = :oneline_receiver)
|
90
|
+
con = ConPool.instance.get_connection(nid)
|
91
|
+
raise unless con
|
92
|
+
if value
|
93
|
+
con.write "#{cmd}\r\n#{value}\r\n"
|
94
|
+
else
|
95
|
+
con.write "#{cmd}\r\n"
|
96
|
+
end
|
97
|
+
ret = send(receiver, con)
|
98
|
+
ConPool.instance.return_connection(nid, con)
|
99
|
+
if ret && ret.instance_of?(String) &&
|
100
|
+
(ret =~ /^SERVER_ERROR/ || ret =~ /^CLIENT_ERROR/)
|
101
|
+
raise ret
|
102
|
+
end
|
103
|
+
ret
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
def oneline_receiver(con)
|
109
|
+
ret = con.gets
|
110
|
+
raise "connection closed" if ret.nil?
|
111
|
+
ret.chomp
|
112
|
+
end
|
113
|
+
|
114
|
+
def value_list_receiver(con)
|
115
|
+
ret = []
|
116
|
+
while (line = con.gets) != "END\r\n"
|
117
|
+
s = line.split(' ')
|
118
|
+
return line.chomp if s[0] == 'SERVER_ERROR' || s[0] == 'CLIENT_ERROR'
|
119
|
+
ret << read_bytes(con, s[3].to_i)
|
120
|
+
read_bytes(con, 2)
|
121
|
+
end
|
122
|
+
ret
|
123
|
+
end
|
124
|
+
|
125
|
+
def value_hash_receiver(con)
|
126
|
+
ret = {}
|
127
|
+
while (line = con.gets) != "END\r\n"
|
128
|
+
s = line.split(' ')
|
129
|
+
return line.chomp if s[0] == 'SERVER_ERROR' || s[0] == 'CLIENT_ERROR'
|
130
|
+
ret[s[1]] = read_bytes(con, s[3].to_i)
|
131
|
+
read_bytes(con, 2)
|
132
|
+
end
|
133
|
+
ret
|
134
|
+
end
|
135
|
+
|
136
|
+
def multiplelines_receiver(con)
|
137
|
+
ret = []
|
138
|
+
while (line = con.gets) != "END\r\n"
|
139
|
+
ret << line.chomp
|
140
|
+
end
|
141
|
+
ret
|
142
|
+
end
|
143
|
+
|
144
|
+
def read_bytes(con, len)
|
145
|
+
ret = ''
|
146
|
+
until (ret.length == len)
|
147
|
+
ret = ret + con.read(len - ret.length)
|
148
|
+
end
|
149
|
+
ret
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'roma/client/sender'
|
4
|
+
require 'roma/client/routing/routing_data'
|
5
|
+
|
6
|
+
if ARGV.length < 1
|
7
|
+
STDERR.puts "usage:#{$0} node-id"
|
8
|
+
exit
|
9
|
+
end
|
10
|
+
|
11
|
+
sender = Roma::Client::Sender.new
|
12
|
+
rd = sender.send_routedump_command(ARGV[0])
|
13
|
+
hist = rd.get_histgram
|
14
|
+
|
15
|
+
# max length of node-id string
|
16
|
+
len_nid = 0
|
17
|
+
rd.nodes.each{|nid|
|
18
|
+
len_nid = nid.length if nid.length > len_nid
|
19
|
+
}
|
20
|
+
|
21
|
+
csum = Array.new(rd.rn, 0)
|
22
|
+
rd.nodes.each{|nid|
|
23
|
+
puts sprintf("%-#{len_nid}s %s %d",
|
24
|
+
nid,
|
25
|
+
hist[nid].inspect,
|
26
|
+
hist[nid].inject{|r,n| r + n})
|
27
|
+
hist[nid].each_with_index{|n,i|
|
28
|
+
csum[i] += n
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
puts sprintf("%#{len_nid}s %s","sum",csum.inspect)
|
33
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# = roma/client/version.rb
|
4
|
+
# This file is derived from roma client.
|
5
|
+
#
|
6
|
+
module Roma #:nodoc:
|
7
|
+
module Client #:nodoc:
|
8
|
+
# == What Is This Library?
|
9
|
+
# ROMA クライアントバージョン情報モジュール
|
10
|
+
#
|
11
|
+
module VERSION
|
12
|
+
# メジャーバージョン
|
13
|
+
MAJOR = 0
|
14
|
+
|
15
|
+
# マイナバージョン
|
16
|
+
MINOR = 3
|
17
|
+
|
18
|
+
# TINY version
|
19
|
+
TINY = 7
|
20
|
+
|
21
|
+
# バージョン文字列
|
22
|
+
STRING = [MAJOR, MINOR, TINY].join('.')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|