roma 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +44 -1
- data/Gemfile.lock +18 -15
- data/README.md +15 -1
- data/bin/consistency_test +10 -0
- data/bin/data_accumulation +11 -0
- data/lib/roma/async_process.rb +39 -2
- data/lib/roma/command/sys_command_receiver.rb +80 -0
- data/lib/roma/command/vn_command_receiver.rb +1 -1
- data/lib/roma/config.rb +1 -1
- data/lib/roma/plugin/plugin_storage.rb +105 -1
- data/lib/roma/romad.rb +13 -1
- data/lib/roma/routing/cb_rttable.rb +1 -1
- data/lib/roma/tools/consistency_test.rb +77 -0
- data/lib/roma/tools/data_accumulation.rb +64 -0
- data/lib/roma/version.rb +1 -1
- data/lib/roma/write_behind.rb +138 -1
- data/test/config4mhash.rb +1 -1
- data/test/config4storage_error.rb +1 -1
- data/test/config4test.rb +1 -1
- data/test/cpdbtest/config4cpdb_base.rb +1 -1
- data/test/optional_test/t_mkroute_rich.rb +44 -0
- data/test/optional_test/t_other_cpdb.rb +45 -0
- data/test/optional_test/t_other_database.rb +59 -0
- data/test/{t_routing_logic.rb → optional_test/t_routing_logic.rb} +1 -0
- data/test/roma-test-storage.rb +685 -0
- data/test/roma-test-utils.rb +24 -0
- data/test/run-test.rb +9 -0
- data/test/t_command_definition.rb +2 -0
- data/test/t_cpdata.rb +1 -0
- data/test/t_cpdb.rb +22 -34
- data/test/t_eventmachine.rb +1 -0
- data/test/t_listplugin.rb +2 -0
- data/test/t_logshift.rb +2 -4
- data/test/t_mapcountplugin.rb +48 -37
- data/test/t_mapplugin.rb +2 -0
- data/test/t_mhash.rb +2 -1
- data/test/t_new_func.rb +386 -0
- data/test/t_protocol.rb +66 -1
- data/test/t_rclient.rb +2 -0
- data/test/t_replication.rb +299 -0
- data/test/t_routing_data.rb +6 -5
- data/test/t_storage.rb +5 -740
- data/test/t_storage_error.rb +1 -0
- data/test/t_writebehind.rb +11 -2
- metadata +31 -19
data/lib/roma/romad.rb
CHANGED
@@ -22,6 +22,7 @@ module Roma
|
|
22
22
|
attr :rttable
|
23
23
|
attr :stats
|
24
24
|
attr :wb_writer
|
25
|
+
attr :cr_writer
|
25
26
|
|
26
27
|
attr_accessor :eventloop
|
27
28
|
attr_accessor :startup
|
@@ -229,6 +230,8 @@ module Roma
|
|
229
230
|
Roma::Config::WRITEBEHIND_PATH,
|
230
231
|
Roma::Config::WRITEBEHIND_SHIFT_SIZE,
|
231
232
|
@log)
|
233
|
+
|
234
|
+
@cr_writer = Roma::WriteBehind::StreamWriter.new(@log)
|
232
235
|
end
|
233
236
|
|
234
237
|
def initialize_plugin
|
@@ -602,6 +605,15 @@ module Roma
|
|
602
605
|
Roma::AsyncProcess::queue.push(Roma::AsyncMessage.new('start_storage_clean_up_process'))
|
603
606
|
end
|
604
607
|
|
608
|
+
if @cr_writer.run_replication
|
609
|
+
if @cr_writer.change_mklhash?
|
610
|
+
nid = @cr_writer.replica_nodelist.sample
|
611
|
+
@cr_writer.update_mklhash(nid)
|
612
|
+
@cr_writer.update_nodelist(nid)
|
613
|
+
@cr_writer.update_rttable(nid)
|
614
|
+
end
|
615
|
+
end
|
616
|
+
|
605
617
|
@stats.clear_counters
|
606
618
|
rescue Exception =>e
|
607
619
|
@log.error("#{e}\n#{$@}")
|
@@ -617,7 +629,7 @@ module Roma
|
|
617
629
|
def node_check(nid)
|
618
630
|
if @startup && @rttable.enabled_failover == false
|
619
631
|
unless Roma::Messaging::ConPool.instance.check_connection(nid)
|
620
|
-
@log.info("I'm
|
632
|
+
@log.info("I'm waiting for booting the #{nid} instance.")
|
621
633
|
return false
|
622
634
|
end
|
623
635
|
end
|
@@ -142,7 +142,7 @@ module Roma
|
|
142
142
|
hosts.length < @rd.rn
|
143
143
|
end
|
144
144
|
|
145
|
-
#
|
145
|
+
# Returns the list of losted-data vnode newer than argument time.
|
146
146
|
def search_lost_vnodes(t)
|
147
147
|
ret = []
|
148
148
|
@rd.each_log_all(@fname){|log_t,line|
|
@@ -0,0 +1,77 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
require 'date'
|
4
|
+
require 'roma/client/rclient'
|
5
|
+
|
6
|
+
@cnt = 0
|
7
|
+
@tmax = 0
|
8
|
+
@tmin = 100
|
9
|
+
|
10
|
+
Thread.new do
|
11
|
+
sleep_time=10
|
12
|
+
while(true)
|
13
|
+
sleep sleep_time
|
14
|
+
printf("qps=%d max=%f min=%f ave=%f (#{Time.now})\n",@cnt/sleep_time,@tmax,@tmin,sleep_time/@cnt.to_f)
|
15
|
+
@cnt=0
|
16
|
+
@tmax=0
|
17
|
+
@tmin=100
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def set_counts(rc, range, c)
|
22
|
+
range.each do |i|
|
23
|
+
ts = DateTime.now
|
24
|
+
res=rc.set("key_#{i}","#{c}")
|
25
|
+
puts "set k=#{i} #{res}" if res==nil || res.chomp != 'STORED'
|
26
|
+
t=(DateTime.now - ts).to_f * 86400.0
|
27
|
+
@tmax=t if t > @tmax
|
28
|
+
@tmin=t if t < @tmin
|
29
|
+
@cnt+=1
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def check_count(rc, range, c)
|
34
|
+
range.each do |i|
|
35
|
+
ts = DateTime.now
|
36
|
+
res = rc.get("key_#{i}")
|
37
|
+
if res != c.to_s
|
38
|
+
puts "error k=key_#{i} #{res}"
|
39
|
+
end
|
40
|
+
t=(DateTime.now - ts).to_f * 86400.0
|
41
|
+
@tmax=t if t > @tmax
|
42
|
+
@tmin=t if t < @tmin
|
43
|
+
@cnt+=1
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_round
|
48
|
+
rc=Roma::Client::RomaClient.new(ARGV)
|
49
|
+
n = 0
|
50
|
+
loop{
|
51
|
+
n += 1
|
52
|
+
set_counts(rc, 0...10000, n)
|
53
|
+
check_count(rc, 0...10000, n)
|
54
|
+
if (n%100 == 0)
|
55
|
+
puts "#{n} loop has finished."
|
56
|
+
end
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
opts = OptionParser.new
|
61
|
+
opts.banner = "usage:\r\n #{File.basename($0)} ${ROMA addr}:${ROMA port}"
|
62
|
+
opts.parse!(ARGV)
|
63
|
+
|
64
|
+
if ARGV.length == 0
|
65
|
+
STDERR.puts opts.help
|
66
|
+
exit
|
67
|
+
end
|
68
|
+
|
69
|
+
begin
|
70
|
+
test_round
|
71
|
+
rescue => e
|
72
|
+
puts "#{e.class} was happened."
|
73
|
+
puts "#{e.message}"
|
74
|
+
ensure
|
75
|
+
puts "#{File.basename($0)} has done."
|
76
|
+
end
|
77
|
+
|
@@ -0,0 +1,64 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
require 'date'
|
4
|
+
require 'roma/client/rclient'
|
5
|
+
|
6
|
+
@cnt = 0
|
7
|
+
@tmax = 0
|
8
|
+
@tmin = 100
|
9
|
+
|
10
|
+
Thread.new do
|
11
|
+
sleep_time=10
|
12
|
+
while(true)
|
13
|
+
sleep sleep_time
|
14
|
+
printf("qps=%d max=%f min=%f ave=%f\n",@cnt/sleep_time,@tmax,@tmin,sleep_time/@cnt.to_f)
|
15
|
+
@cnt=0
|
16
|
+
@tmax=0
|
17
|
+
@tmin=100
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def randstr(n)
|
22
|
+
s = ("a".."z").to_a
|
23
|
+
n.times.map{ s.sample }.join
|
24
|
+
end
|
25
|
+
|
26
|
+
def set_sequence(ini_nodes, n, v_size)
|
27
|
+
puts __method__
|
28
|
+
rc=Roma::Client::RomaClient.new(ini_nodes)
|
29
|
+
|
30
|
+
n.times do |i|
|
31
|
+
ts = DateTime.now
|
32
|
+
res=rc.set("key_#{i}", randstr(v_size))
|
33
|
+
puts "set k=#{i} #{res}" if res==nil || res.chomp != 'STORED'
|
34
|
+
t=(DateTime.now - ts).to_f * 86400.0
|
35
|
+
@tmax=t if t > @tmax
|
36
|
+
@tmin=t if t < @tmin
|
37
|
+
@cnt+=1
|
38
|
+
|
39
|
+
puts"=====#{(i*100)/n}%(#{i}keys) has finished.=====" if i%100000 == 0
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# default
|
44
|
+
param = { :num=>1000, :value_size=>1024 }
|
45
|
+
|
46
|
+
opts = OptionParser.new
|
47
|
+
opts.banner = "usage:#{File.basename($0)} [options] addr:port"
|
48
|
+
opts.on("-n", "--num [num]", "number of keys(default is 1000)"){|v| param[:num] = v.to_i }
|
49
|
+
opts.on("-v", "--value_size [byte]", "size of each values(default is 1024)"){|v| param[:value_size] = v.to_i }
|
50
|
+
opts.parse!(ARGV)
|
51
|
+
|
52
|
+
if ARGV.length == 0
|
53
|
+
STDERR.puts opts.help
|
54
|
+
exit
|
55
|
+
end
|
56
|
+
|
57
|
+
begin
|
58
|
+
set_sequence(ARGV, param[:num], param[:value_size])
|
59
|
+
rescue => e
|
60
|
+
puts "#{e.class}"
|
61
|
+
puts "#{e.message}"
|
62
|
+
ensure
|
63
|
+
puts "#{File.basename($0)} has done."
|
64
|
+
end
|
data/lib/roma/version.rb
CHANGED
data/lib/roma/write_behind.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'thread'
|
2
2
|
require 'roma/stats'
|
3
|
+
require 'socket'
|
4
|
+
require 'roma/messaging/con_pool'
|
3
5
|
|
4
6
|
module Roma
|
5
7
|
|
@@ -122,6 +124,138 @@ module Roma
|
|
122
124
|
end
|
123
125
|
|
124
126
|
end # class FileWriter
|
127
|
+
|
128
|
+
class StreamWriter
|
129
|
+
|
130
|
+
attr_accessor :run_replication
|
131
|
+
attr_accessor :run_existing_data_replication
|
132
|
+
attr_accessor :replica_mklhash
|
133
|
+
attr_accessor :replica_nodelist
|
134
|
+
attr_accessor :replica_rttable
|
135
|
+
|
136
|
+
def initialize(log)
|
137
|
+
@log = log
|
138
|
+
@run_replication = false
|
139
|
+
@run_existing_data_replication = false
|
140
|
+
@replica_mklhash = nil
|
141
|
+
@replica_nodelist = []
|
142
|
+
@replica_rttable = nil
|
143
|
+
@do_transmit = false
|
144
|
+
end
|
145
|
+
|
146
|
+
def get_stat
|
147
|
+
ret = {}
|
148
|
+
ret['write-behind.run_replication'] = @run_replication
|
149
|
+
ret['write-behind.run_existing_data_replication'] = @run_existing_data_replication
|
150
|
+
ret['write-behind.replica_mklhash'] = @replica_mklhash
|
151
|
+
ret['write-behind.replica_nodelist'] = @replica_nodelist
|
152
|
+
ret
|
153
|
+
end
|
154
|
+
|
155
|
+
def change_mklhash?
|
156
|
+
con = Roma::Messaging::ConPool.instance.get_connection(@replica_nodelist[0])
|
157
|
+
con.write("mklhash 0\r\n")
|
158
|
+
current_mklhash = con.gets.chomp
|
159
|
+
Roma::Messaging::ConPool.instance.return_connection(@replica_nodelist[0], con)
|
160
|
+
|
161
|
+
if current_mklhash == @replica_mklhash
|
162
|
+
return false
|
163
|
+
else
|
164
|
+
return true
|
165
|
+
end
|
166
|
+
rescue
|
167
|
+
@replica_nodelist.shift
|
168
|
+
if @replica_nodelist.length == 0
|
169
|
+
@run_replication = false
|
170
|
+
@log.error("Replicate Cluster was down.")
|
171
|
+
else
|
172
|
+
retry
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def update_mklhash(nid)
|
177
|
+
timeout(1) do
|
178
|
+
con = Roma::Messaging::ConPool.instance.get_connection(nid)
|
179
|
+
con.write("mklhash 0\r\n")
|
180
|
+
@replica_mklhash = con.gets.chomp
|
181
|
+
Roma::Messaging::ConPool.instance.return_connection(nid, con)
|
182
|
+
@log.debug("replica_mklhash has updated: [#{@replica_mklhash}]")
|
183
|
+
end
|
184
|
+
rescue => e
|
185
|
+
@log.error("#{e}\n#{$@}")
|
186
|
+
end
|
187
|
+
|
188
|
+
def update_nodelist(nid)
|
189
|
+
timeout(1) do
|
190
|
+
con = Roma::Messaging::ConPool.instance.get_connection(nid)
|
191
|
+
con.write("nodelist\r\n")
|
192
|
+
@replica_nodelist = con.gets.chomp.split("\s")
|
193
|
+
Roma::Messaging::ConPool.instance.return_connection(nid, con)
|
194
|
+
@log.debug("replica_nodelist has updated: #{@replica_nodelist}")
|
195
|
+
end
|
196
|
+
rescue => e
|
197
|
+
@log.error("#{e}\n#{$@}")
|
198
|
+
end
|
199
|
+
|
200
|
+
def update_rttable(nid)
|
201
|
+
timeout(1) do
|
202
|
+
con = Roma::Messaging::ConPool.instance.get_connection(nid)
|
203
|
+
con.write "routingdump\r\n"
|
204
|
+
routes_length = con.gets.to_i
|
205
|
+
if (routes_length <= 0)
|
206
|
+
con.close
|
207
|
+
@log.error("#{__method__} process was failed.\r\n") if routes_length < 0
|
208
|
+
return nil
|
209
|
+
end
|
210
|
+
|
211
|
+
routes = ''
|
212
|
+
while (routes.length != routes_length)
|
213
|
+
routes = routes + con.read(routes_length - routes.length)
|
214
|
+
end
|
215
|
+
con.read(2) # "\r\n"
|
216
|
+
con.gets
|
217
|
+
rd = Marshal.load(routes)
|
218
|
+
Roma::Messaging::ConPool.instance.return_connection(nid, con)
|
219
|
+
@replica_rttable = rd
|
220
|
+
@log.debug("replica_rttable has updated: [#{@replica_rttable}]")
|
221
|
+
end
|
222
|
+
rescue => e
|
223
|
+
@log.error("#{e}\n#{$@}")
|
224
|
+
nil
|
225
|
+
end
|
226
|
+
|
227
|
+
def search_replica_primary_node(key)
|
228
|
+
d = Digest::SHA1.hexdigest(key).hex % (2**@replica_rttable.dgst_bits)
|
229
|
+
nodes = @replica_rttable.v_idx[d & @replica_rttable.search_mask]
|
230
|
+
return nodes[0] # for send primary node of replica cluster
|
231
|
+
rescue => e
|
232
|
+
@log.error("#{e}\n#{$@}")
|
233
|
+
nil
|
234
|
+
end
|
235
|
+
|
236
|
+
def transmit(cmd, key, value) # value is for error log
|
237
|
+
timeout(5) do
|
238
|
+
@do_transmit = true
|
239
|
+
nid = search_replica_primary_node(key)
|
240
|
+
con = Roma::Messaging::ConPool.instance.get_connection(nid)
|
241
|
+
con.write(cmd)
|
242
|
+
con.gets # for return connection
|
243
|
+
Roma::Messaging::ConPool.instance.return_connection(nid, con)
|
244
|
+
end
|
245
|
+
rescue => e
|
246
|
+
@log.error("#{e}\n#{$@}")
|
247
|
+
@log.error("replication error: key=#{key} value=#{value}\r\n")
|
248
|
+
ensure
|
249
|
+
@do_transmit = false
|
250
|
+
end
|
251
|
+
|
252
|
+
def close_all
|
253
|
+
@replica_nodelist.each{|nid|
|
254
|
+
Roma::Messaging::ConPool.instance.close_at(nid)
|
255
|
+
}
|
256
|
+
end
|
257
|
+
|
258
|
+
end # class StreamWriter
|
125
259
|
|
126
260
|
end # module WriteBehind
|
127
261
|
|
@@ -148,6 +282,7 @@ module Roma
|
|
148
282
|
end
|
149
283
|
@wb_thread.exit
|
150
284
|
@wb_writer.close_all
|
285
|
+
@cr_writer.close_all
|
151
286
|
end
|
152
287
|
|
153
288
|
def wb_rotate(hname)
|
@@ -163,12 +298,14 @@ module Roma
|
|
163
298
|
end
|
164
299
|
|
165
300
|
def wb_get_stat
|
166
|
-
@wb_writer.get_stat
|
301
|
+
@wb_writer.get_stat.merge(@cr_writer.get_stat)
|
167
302
|
end
|
168
303
|
|
169
304
|
def wb_process_loop
|
170
305
|
loop {
|
171
306
|
while dat = @@wb_queue.pop
|
307
|
+
# dat ====> [hname, cmd, key, value]
|
308
|
+
@cr_writer.transmit(dat[1], dat[2], dat[3]) unless dat[0]
|
172
309
|
@wb_writer.write(dat[0], dat[1], dat[2], dat[3])
|
173
310
|
end
|
174
311
|
}
|
data/test/config4mhash.rb
CHANGED
data/test/config4test.rb
CHANGED
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'roma/routing/routing_data'
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
class RoutingDataTest < Test::Unit::TestCase
|
7
|
+
self.test_order = :defined
|
8
|
+
def setup
|
9
|
+
end
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_make_rich_routing
|
15
|
+
# digest bit count 32
|
16
|
+
# vn bit count 16
|
17
|
+
# redundancy 2
|
18
|
+
# array of node ID ['roma0_3300','roma1_3300','roma2_3300']
|
19
|
+
rd=Roma::Routing::RoutingData.create(32,16,2,['roma0_3300','roma1_3300','roma2_3300']) # vn bit count 16
|
20
|
+
|
21
|
+
assert( rd.v_idx.length==65536 )
|
22
|
+
assert( rd.nodes.length==3 )
|
23
|
+
assert( rd.search_mask==0xffff0000 )
|
24
|
+
assert( rd.dgst_bits==32 )
|
25
|
+
assert( rd.div_bits==16 )
|
26
|
+
assert( rd.rn==2 )
|
27
|
+
|
28
|
+
c0=c1=c2=0
|
29
|
+
rd.v_idx.each_value{|v|
|
30
|
+
case v[0]
|
31
|
+
when 'roma0_3300'
|
32
|
+
c0+=1
|
33
|
+
when 'roma1_3300'
|
34
|
+
c1+=1
|
35
|
+
when 'roma2_3300'
|
36
|
+
c2+=1
|
37
|
+
end
|
38
|
+
}
|
39
|
+
# confirming dispersion is lower than 10%
|
40
|
+
assert( (c0-c1).abs < rd.v_idx.length/10 )
|
41
|
+
assert( (c1-c2).abs < rd.v_idx.length/10 )
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|