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