roma 1.2.0 → 1.3.0
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.
- 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
|