roma 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +44 -1
  3. data/Gemfile.lock +18 -15
  4. data/README.md +15 -1
  5. data/bin/consistency_test +10 -0
  6. data/bin/data_accumulation +11 -0
  7. data/lib/roma/async_process.rb +39 -2
  8. data/lib/roma/command/sys_command_receiver.rb +80 -0
  9. data/lib/roma/command/vn_command_receiver.rb +1 -1
  10. data/lib/roma/config.rb +1 -1
  11. data/lib/roma/plugin/plugin_storage.rb +105 -1
  12. data/lib/roma/romad.rb +13 -1
  13. data/lib/roma/routing/cb_rttable.rb +1 -1
  14. data/lib/roma/tools/consistency_test.rb +77 -0
  15. data/lib/roma/tools/data_accumulation.rb +64 -0
  16. data/lib/roma/version.rb +1 -1
  17. data/lib/roma/write_behind.rb +138 -1
  18. data/test/config4mhash.rb +1 -1
  19. data/test/config4storage_error.rb +1 -1
  20. data/test/config4test.rb +1 -1
  21. data/test/cpdbtest/config4cpdb_base.rb +1 -1
  22. data/test/optional_test/t_mkroute_rich.rb +44 -0
  23. data/test/optional_test/t_other_cpdb.rb +45 -0
  24. data/test/optional_test/t_other_database.rb +59 -0
  25. data/test/{t_routing_logic.rb → optional_test/t_routing_logic.rb} +1 -0
  26. data/test/roma-test-storage.rb +685 -0
  27. data/test/roma-test-utils.rb +24 -0
  28. data/test/run-test.rb +9 -0
  29. data/test/t_command_definition.rb +2 -0
  30. data/test/t_cpdata.rb +1 -0
  31. data/test/t_cpdb.rb +22 -34
  32. data/test/t_eventmachine.rb +1 -0
  33. data/test/t_listplugin.rb +2 -0
  34. data/test/t_logshift.rb +2 -4
  35. data/test/t_mapcountplugin.rb +48 -37
  36. data/test/t_mapplugin.rb +2 -0
  37. data/test/t_mhash.rb +2 -1
  38. data/test/t_new_func.rb +386 -0
  39. data/test/t_protocol.rb +66 -1
  40. data/test/t_rclient.rb +2 -0
  41. data/test/t_replication.rb +299 -0
  42. data/test/t_routing_data.rb +6 -5
  43. data/test/t_storage.rb +5 -740
  44. data/test/t_storage_error.rb +1 -0
  45. data/test/t_writebehind.rb +11 -2
  46. metadata +31 -19
@@ -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 wating for booting the #{nid} instance.")
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
- # Retuens the list of losted-data vnode newer than argument time.
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
@@ -1,4 +1,4 @@
1
1
 
2
2
  module Roma
3
- VERSION = "1.2.0"
3
+ VERSION = "1.3.0"
4
4
  end
@@ -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
  }
@@ -4,7 +4,7 @@ require 'roma/storage/tc_storage'
4
4
  module Roma
5
5
 
6
6
  module Config
7
- VERSION = "1.2.0"
7
+ VERSION = "1.3.0"
8
8
 
9
9
  DEFAULT_PORT = 12000
10
10
  DEFAULT_NAME = 'ROMA'
@@ -4,7 +4,7 @@ require 'roma/storage/storage_error_storage'
4
4
  module Roma
5
5
 
6
6
  module Config
7
- VERSION = "1.2.0"
7
+ VERSION = "1.3.0"
8
8
 
9
9
  DEFAULT_PORT = 12000
10
10
  DEFAULT_NAME = 'ROMA'
@@ -3,7 +3,7 @@ require 'roma/storage/rh_storage'
3
3
  module Roma
4
4
 
5
5
  module Config
6
- VERSION = "1.2.0"
6
+ VERSION = "1.3.0"
7
7
 
8
8
  DEFAULT_PORT = 12000
9
9
  DEFAULT_NAME = 'ROMA'
@@ -1,7 +1,7 @@
1
1
  module CpdbBase
2
2
 
3
3
  module Config
4
- VERSION = "1.2.0"
4
+ VERSION = "1.3.0"
5
5
 
6
6
  DEFAULT_PORT = 12000
7
7
  DEFAULT_NAME = 'ROMA'
@@ -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