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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a17bad1bbf7dabab9d9833e7458902691dae3117
4
- data.tar.gz: e97e8fb05d535d000d276dcea350317629ef9a00
3
+ metadata.gz: 5ad632c67885c4aaf13b8fdec745d45bbcd94feb
4
+ data.tar.gz: 9c5967e28f0ae8f250223b1e4d81852ad0723c38
5
5
  SHA512:
6
- metadata.gz: f5dc132fd3475bcd2a4edceaa579bbf9b18319a84dda1ce7c443b1e40ab1cdb538e7bb791cb693d497b98867990ad31c294ee4f7969f1b20616b31a6bcb05de3
7
- data.tar.gz: 3d2854df8f09147235a49a5891037fa65e5be84a59c73bacbfb3739decd8f0a3c728bdac2d44fb69e7aa2026c53ffef1abbe898695e62e5a098d7fcd9e76df59
6
+ metadata.gz: 343240d35ac31586f4325ac5f2b78de0e69b19a96684b76fff5ac0df0aa032eef53287283a35701b77d8ba6f06a8d58ed0116216fd5e5210d60851631b1ac6ba
7
+ data.tar.gz: 99bd24be9e021ae43d7330b69f0b6935422d790165c04a934118d76b3672d8c3d35627ac0b888ade65ebc56291409c2dc0c53303c9dae7f23ca55341285cfcb1
data/CHANGELOG CHANGED
@@ -1,4 +1,47 @@
1
- *1.1.0 (Aug 19 2015)*
1
+ *1.3.0 (Jan 21 2016)*
2
+
3
+ * change unit test to pass in the poor env [hiroaki-iwase] f0d9cc8
4
+
5
+ *1.3.0RC1 (Nov 13 2015)*
6
+
7
+ * Update README.md [Paras Patel] 3350844
8
+ * automation some manual tests [hiroaki-iwase] dea72fa
9
+ * auto_recover
10
+ * set_routing_trans_timeout
11
+ * st_class
12
+ * adm_tool
13
+ * check_enable_repeathost
14
+ * check_replication _in_host
15
+ * add below func's unit test [hiroaki-iwase] f9a1721
16
+ * jaro-winkler
17
+ * stat log level
18
+ * stat secondary
19
+ * shutdown_self
20
+ * stat failover
21
+ * get_key_info
22
+ * enabled_repetition_in_routing?
23
+ * switch_dns_caching
24
+ * add_rttable_sub_nid
25
+ * delete_rttable_sub_nid
26
+ * clear_rttable_sub_nid
27
+ * del_latency_avg_calc_cmd
28
+ * add_latency_avg_calc_cmd
29
+ * chg_latency_avg_calc_time_count
30
+ * set_latency_avg_calc_rule
31
+ * add test of below func [hiroaki-iwase] 613c0d0
32
+ * stat log level
33
+ * stat secondary
34
+ * shutdown_self
35
+ * add unit test of jaro winkler [hiroaki-iwase] 22fd7b2
36
+ * remove puts method in testfile [hiroaki-iwase] cec8a6d
37
+ * implement cluster replication function [hiroaki-iwase] a1fa5e8
38
+ * implement get_expt command [hiroaki-iwase] 04f1a14
39
+ * change log level of push_a_vnode_stream from info to debug [hiroaki-iwase] e668fc0
40
+ * add how to contributing [hiroaki-iwase] 6d9945a
41
+ * add progress rate to data accumulation tool [hiroaki-iwase] 2f9d8aa
42
+ * implement consistency check tool [Hiroaki Iwase] 3211bd9
43
+
44
+ *1.2.0 (Aug 19 2015)*
2
45
 
3
46
  * Change gemspec [Hiroaki Iwase] db2bb42
4
47
  * Modify unit-test [Hiroaki Iwase] 7479034
@@ -1,37 +1,37 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- roma (1.2.0)
4
+ roma (1.3.0)
5
5
  eventmachine (~> 1.0.0)
6
6
  jaro_winkler (~> 1.3.5)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- archive-zip (0.7.0)
11
+ archive-zip (0.8.0)
12
12
  io-like (~> 0.3.0)
13
- eventmachine (1.0.3)
14
- ffi (1.9.6)
15
- gdbm (1.2)
13
+ eventmachine (1.0.9.1)
14
+ ffi (1.9.10)
15
+ gdbm (1.3.0)
16
16
  gqtp (1.0.6)
17
- groonga-client (0.1.0)
17
+ groonga-client (0.1.9)
18
18
  gqtp (>= 1.0.4)
19
19
  groonga-command (>= 1.0.8)
20
- groonga-command (1.0.9)
20
+ groonga-command (1.1.5)
21
21
  json
22
22
  io-like (0.3.0)
23
- jaro_winkler (1.3.5)
24
- json (1.8.1)
25
- pkg-config (1.1.6)
26
- power_assert (0.2.2)
27
- rake (10.2.2)
28
- rroonga (4.0.8)
23
+ jaro_winkler (1.3.7)
24
+ json (1.8.3)
25
+ pkg-config (1.1.7)
26
+ power_assert (0.2.7)
27
+ rake (10.5.0)
28
+ rroonga (5.1.1)
29
29
  archive-zip
30
30
  groonga-client (>= 0.0.3)
31
31
  json
32
32
  pkg-config
33
- sqlite3 (1.3.9)
34
- test-unit (3.1.2)
33
+ sqlite3 (1.3.11)
34
+ test-unit (3.1.7)
35
35
  power_assert
36
36
 
37
37
  PLATFORMS
@@ -45,3 +45,6 @@ DEPENDENCIES
45
45
  rroonga
46
46
  sqlite3
47
47
  test-unit
48
+
49
+ BUNDLED WITH
50
+ 1.11.2
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # ROMA - A Distributed Key-Value Store in Ruby
1
+ # ROMA - A Distributed Key-Value Store in Ruby
2
2
 
3
3
  ROMA is one of the data storing systems for distributed key-value stores.
4
4
  It is a completely decentralized distributed system that consists of multiple
@@ -74,5 +74,19 @@ END
74
74
 
75
75
  Refer to [Commands](http://roma-kvs.org/commands.html "Commands") for more detail information about ROMA Commands.
76
76
 
77
+
78
+ ## Contributing
79
+
80
+ If you would like to contribute, please...
81
+
82
+ 1. Fork.
83
+ 2. Download [Ruby Client](https://github.com/roma/roma-ruby-client) to same directory.
84
+ 3. Make changes in a branch & add unit tests.
85
+ 4. Run Unit Test
86
+ * `ruby test/run_test.rb` (if unit test fails, run it again - it's fickle).
87
+ 5. Create a pull request.
88
+
89
+ Contributions, improvements, comments and suggestions are welcome!
90
+
77
91
  ## Promoters
78
92
  Roma is promoted by [Rakuten, Inc.](http://global.rakuten.com/corp/) and [Rakuten Institute of Technology](http://rit.rakuten.co.jp/).
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ require 'pathname'
3
+
4
+ base_path = Pathname(__FILE__).dirname.parent.expand_path
5
+ $LOAD_PATH.unshift("#{base_path}/lib")
6
+
7
+ client_base_path = Pathname(__FILE__).dirname.parent.parent.expand_path
8
+ $LOAD_PATH.unshift("#{client_base_path}/roma-ruby-client/lib")
9
+
10
+ require 'roma/tools/consistency_test'
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ require 'pathname'
3
+
4
+ base_path = Pathname(__FILE__).dirname.parent.expand_path
5
+ $LOAD_PATH.unshift("#{base_path}/lib")
6
+
7
+ client_base_path = Pathname(__FILE__).dirname.parent.parent.expand_path
8
+ $LOAD_PATH.unshift("#{client_base_path}/roma-ruby-client/lib")
9
+
10
+ require 'roma/tools/data_accumulation'
11
+
@@ -643,7 +643,7 @@ module Roma
643
643
  end
644
644
 
645
645
  def push_a_vnode_stream(hname, vn, nid)
646
- @log.info("#{__method__}:hname=#{hname} vn=#{vn} nid=#{nid}")
646
+ @log.debug("#{__method__}:hname=#{hname} vn=#{vn} nid=#{nid}")
647
647
 
648
648
  stop_clean_up
649
649
 
@@ -670,7 +670,7 @@ module Roma
670
670
  con.write(data)
671
671
  sleep @stats.stream_copy_wait_param
672
672
  end
673
- con.write("\0" * 20) # end of steram
673
+ con.write("\0" * 20) # end of stream
674
674
 
675
675
  res = con.gets # STORED\r\n or error string
676
676
  Roma::Messaging::ConPool.instance.return_connection(nid, con)
@@ -1043,5 +1043,42 @@ module Roma
1043
1043
 
1044
1044
  get_point(f, target_time, type, latency_time, new_pos, target_pos)
1045
1045
  end
1046
+
1047
+ def asyncev_start_replicate_existing_data_process(args)
1048
+ # args is [$roma.cr_writer.replica_rttable])
1049
+ t = Thread.new do
1050
+ begin
1051
+ $roma.cr_writer.run_existing_data_replication = true
1052
+ replicate_existing_data_process(args)
1053
+ rescue => e
1054
+ @log.error("#{__method__}:#{e.inspect} #{$ERROR_POSITION}")
1055
+ ensure
1056
+ $roma.cr_writer.run_existing_data_replication = false
1057
+ end
1058
+ end
1059
+ t[:name] = __method__
1060
+ end
1061
+
1062
+ def replicate_existing_data_process(args)
1063
+ @log.info("#{__method__} :start.")
1064
+
1065
+ @storages.each_key do |hname|
1066
+ @rttable.v_idx.each_key do |vn|
1067
+ raise unless $roma.cr_writer.run_existing_data_replication
1068
+ args[0].v_idx[vn].each do |replica_nid|
1069
+ res = push_a_vnode_stream(hname, vn, replica_nid)
1070
+ if res != 'STORED'
1071
+ @log.error("#{__method__}:push_a_vnode was failed:hname=#{hname} vn=#{vn}:#{res}")
1072
+ return false
1073
+ end
1074
+ end
1075
+ end
1076
+ end
1077
+
1078
+ @log.info("#{__method__} has done.")
1079
+ rescue => e
1080
+ @log.error("#{e}\n#{$ERROR_POSITION}")
1081
+ end
1082
+
1046
1083
  end # module AsyncProcess
1047
1084
  end # module Roma
@@ -224,6 +224,86 @@ module Roma
224
224
  end
225
225
  end
226
226
 
227
+ # switch_replication command is change status of cluster replication
228
+ # if you want to activate, assign 1 nid(addr_port) of replication cluster as argument.
229
+ # if you want to copy existing data, add the 'all' after nid as argument
230
+ # switch_replication <true|false> [nid] [copy target]
231
+ def ev_switch_replication(s)
232
+ unless s.length.between?(2, 4)
233
+ return send_data("CLIENT_ERROR number of arguments\r\n")
234
+ end
235
+ unless s[1] =~ /^(true|false)$/
236
+ return send_data("CLIENT_ERROR value must be true or false\r\n")
237
+ end
238
+ if s[3] && s[3] != 'all'
239
+ return send_data("CLIENT_ERROR [copy target] must be all or nil\r\n")
240
+ end
241
+
242
+ res = broadcast_cmd("rswitch_replication #{s[1]} #{s[2]} #{s[3]}\r\n")
243
+
244
+ timeout(1){
245
+ case s[1]
246
+ when 'true'
247
+ $roma.cr_writer.update_mklhash(s[2])
248
+ $roma.cr_writer.update_nodelist(s[2])
249
+ $roma.cr_writer.update_rttable(s[2])
250
+ $roma.cr_writer.run_replication = true
251
+ if s[3] == 'all'
252
+ $roma.cr_writer.run_existing_data_replication = true
253
+ Roma::AsyncProcess::queue.push(Roma::AsyncMessage.new('start_replicate_existing_data_process', [$roma.cr_writer.replica_rttable]))
254
+ end
255
+ res[@stats.ap_str] = "ACTIVATED"
256
+ when 'false'
257
+ $roma.cr_writer.replica_mklhash = nil
258
+ $roma.cr_writer.replica_nodelist = []
259
+ $roma.cr_writer.replica_rttable = nil
260
+ $roma.cr_writer.run_replication = false
261
+ $roma.cr_writer.run_existing_data_replication = false
262
+ res[@stats.ap_str] = "DEACTIVATED"
263
+ end
264
+ }
265
+ send_data("#{res}\r\n")
266
+ rescue => e
267
+ send_data("#{e.class}: #{e}\r\n")
268
+ end
269
+
270
+ # rswitch_replication <true|false> [nid] [copy target]
271
+ def ev_rswitch_replication(s)
272
+ unless s.length.between?(2, 4)
273
+ return send_data("CLIENT_ERROR number of arguments\n\r")
274
+ end
275
+ unless s[1] =~ /^(true|false)$/
276
+ return send_data("CLIENT_ERROR value must be true or false\n\r")
277
+ end
278
+ if s[3] && s[3] != 'all'
279
+ return send_data("CLIENT_ERROR [copy target] must be all or nil\r\n")
280
+ end
281
+
282
+ timeout(1){
283
+ case s[1]
284
+ when 'true'
285
+ $roma.cr_writer.update_mklhash(s[2])
286
+ $roma.cr_writer.update_nodelist(s[2])
287
+ $roma.cr_writer.update_rttable(s[2])
288
+ $roma.cr_writer.run_replication = true
289
+ if s[3] == 'all'
290
+ $roma.cr_writer.run_existing_data_replication = true
291
+ Roma::AsyncProcess::queue.push(Roma::AsyncMessage.new('start_replicate_existing_data_process', [$roma.cr_writer.replica_rttable]))
292
+ end
293
+ send_data("ACTIVATED\r\n")
294
+ when 'false'
295
+ $roma.cr_writer.replica_mklhash = nil
296
+ $roma.cr_writer.replica_nodelist = []
297
+ $roma.cr_writer.replica_rttable = nil
298
+ $roma.cr_writer.run_replication = false
299
+ $roma.cr_writer.run_existing_data_replication = false
300
+ send_data("DEACTIVATED\r\n")
301
+ end
302
+ }
303
+ rescue => e
304
+ send_data("#{e.class}: #{e}\r\n")
305
+ end
306
+
227
307
  # dcnice command is setting priority for a data-copy thread.
228
308
  # a niceness of 1 is the highest priority and 5 is the lowest priority.
229
309
  # dcnice <priority:1 to 5>
@@ -6,7 +6,7 @@ module Roma
6
6
 
7
7
  module VnodeCommandReceiver
8
8
 
9
- # spushv <true/false>
9
+ # spushv_protection <true/false>
10
10
  def ev_spushv_protection(s)
11
11
  if s.length == 1
12
12
  send_data("#{@stats.spushv_protection}\r\n")
@@ -4,7 +4,7 @@ module Roma
4
4
 
5
5
  module Config
6
6
  # check when the booting
7
- VERSION = "1.2.0"
7
+ VERSION = "1.3.0"
8
8
 
9
9
  DEFAULT_PORT = 12000
10
10
  DEFAULT_NAME = 'ROMA'
@@ -126,6 +126,7 @@ module Roma
126
126
  d = Digest::SHA1.hexdigest(key).hex % @rttable.hbits
127
127
  vn = @rttable.get_vnode_id(d)
128
128
  nodes = @rttable.search_nodes_for_write(vn)
129
+
129
130
  if nodes[0] != @nid
130
131
  cmd = "fdelete #{key}\e#{hname}"
131
132
  s[2..-1].each{|c| cmd << " #{c}"}
@@ -137,6 +138,7 @@ module Roma
137
138
  end
138
139
  return send_data("#{res}\r\n")
139
140
  end
141
+
140
142
  unless @storages.key?(hname)
141
143
  send_data("SERVER_ERROR #{hname} does not exists.\r\n")
142
144
  return
@@ -165,6 +167,12 @@ module Roma
165
167
  end
166
168
  }
167
169
  return send_data("NOT_FOUND\r\n") unless res[4]
170
+
171
+ if $roma.cr_writer.run_replication
172
+ fnc = 'delete'
173
+ Roma::WriteBehindProcess::push(nil, "#{fnc} #{s[1]}\r\n", s[1], nil)
174
+ end
175
+
168
176
  send_data("DELETED\r\n")
169
177
  end
170
178
 
@@ -208,6 +216,12 @@ module Roma
208
216
  end
209
217
  }
210
218
  return send_data("NOT_FOUND\r\n") unless res[4]
219
+
220
+ if $roma.cr_writer.run_replication
221
+ fnc = 'delete'
222
+ Roma::WriteBehindProcess::push(nil, "#{fnc} #{s[1]}\r\n", s[1], nil)
223
+ end
224
+
211
225
  send_data("DELETED\r\n")
212
226
  end
213
227
 
@@ -339,6 +353,10 @@ module Roma
339
353
  Roma::WriteBehindProcess::push(hname, @stats.wb_command_map[:set_expt], key, expt.to_s)
340
354
  end
341
355
  redundant(nodes[1..-1], hname, key, d, ret[2], ret[3], ret[4])
356
+ if $roma.cr_writer.run_replication
357
+ fnc = 'set_expt'
358
+ Roma::WriteBehindProcess::push(nil, "#{fnc} #{s[1]} #{expt}\r\n", s[1], expt)
359
+ end
342
360
  send_data("STORED\r\n")
343
361
  else
344
362
  return send_data("NOT_STORED\r\n")
@@ -376,12 +394,69 @@ module Roma
376
394
  Roma::WriteBehindProcess::push(hname, @stats.wb_command_map[:set_expt], key, expt.to_s)
377
395
  end
378
396
  redundant(nodes[1..-1], hname, key, d, ret[2], ret[3], ret[4])
397
+ if $roma.cr_writer.run_replication
398
+ fnc = 'set_expt'
399
+ Roma::WriteBehindProcess::push(nil, "#{fnc} #{s[1]} #{expt}\r\n", s[1], expt)
400
+ end
379
401
  send_data("STORED\r\n")
380
402
  else
381
403
  return send_data("NOT_STORED\r\n")
382
404
  end
383
405
  end
384
406
 
407
+ # If you want to get expired time as UNIXTIME, set the 'unix' in last argument
408
+ # Unless set this, expired time will be sent back as date format.
409
+ # get_expt <key> [unix]
410
+ def ev_get_expt(s)
411
+ unless s.length.between?(2, 3)
412
+ @log.error("get_expt: wrong number of arguments(#{s.length-1} to 2-3)")
413
+ return send_data("CLIENT_ERROR Wrong number of arguments.\r\n")
414
+ end
415
+ case s[2]
416
+ when 'unix'
417
+ is_unix = true
418
+ when nil
419
+ is_unix = false
420
+ else
421
+ @log.error("get_expt: wrong format of arguments.")
422
+ return send_data("CLIENT_ERROR Wrong format of arguments.\r\n")
423
+ end
424
+
425
+ key, hname = s[1].split("\e")
426
+ hname ||= @defhash
427
+ unless @storages.key?(hname)
428
+ send_data("SERVER_ERROR #{hname} does not exists.\r\n")
429
+ return
430
+ end
431
+
432
+ d = Digest::SHA1.hexdigest(key).hex % @rttable.hbits
433
+ vn = @rttable.get_vnode_id(d)
434
+
435
+ nodes = @rttable.search_nodes(vn)
436
+ unless nodes.include?(@nid)
437
+ @log.warn("forward get_expt #{s[1]} #{s[2]}")
438
+ res = forward_get_expt(nodes[0], vn, s[1], s[2])
439
+ if res
440
+ send_data(res)
441
+ else
442
+ send_data("SERVER_ERROR Message forward failed.\r\n")
443
+ end
444
+ return
445
+ end
446
+
447
+ data = @storages[hname].db_get(vn, key)
448
+ if data
449
+ if is_unix
450
+ expt = data.unpack('NNNNa*')[3]
451
+ else
452
+ expt = Time.at(data.unpack('NNNNa*')[3])
453
+ end
454
+ send_data("#{expt}\r\n")
455
+ end
456
+ send_data("END\r\n")
457
+ end
458
+
459
+
385
460
  # set_size_of_zredundant <n>
386
461
  def ev_set_size_of_zredundant(s)
387
462
  if s.length != 2 || s[1].to_i == 0
@@ -451,6 +526,22 @@ module Roma
451
526
  nil
452
527
  end
453
528
 
529
+ def forward_get_expt(nid, vn, key, is_unix=nil)
530
+ con = get_connection(nid)
531
+ con.send("get_expt #{key} #{is_unix}\r\n")
532
+ res = ''
533
+ while((line = con.gets)!="END\r\n")
534
+ res = line.chomp
535
+ end
536
+ return_connection(nid, con)
537
+ @rttable.proc_succeed(nid)
538
+ res
539
+ rescue => e
540
+ @rttable.proc_failed(nid)
541
+ @log.error("forward get_expt failed:nid=#{nid} key=#{key}")
542
+ nil
543
+ end
544
+
454
545
  def store(fnc, hname, vn, k, d, expt, v, nodes)
455
546
  expt = chg_time_expt(expt)
456
547
  unless @storages.key?(hname)
@@ -471,6 +562,10 @@ module Roma
471
562
  Roma::WriteBehindProcess::push(hname, @stats.wb_command_map[fnc], k, ret[4])
472
563
  end
473
564
  redundant(nodes, hname, k, d, ret[2], expt, ret[4])
565
+ if $roma.cr_writer.run_replication
566
+ k = "#{k}\e#{hname}" if hname != @defhash
567
+ Roma::WriteBehindProcess::push(nil, "#{fnc} #{k} 1 #{expt} #{v.length} \r\n#{v}\r\n", k, v)
568
+ end
474
569
  send_data("STORED\r\n")
475
570
  else
476
571
  @log.error("#{fnc} NOT_STORED:#{hname} #{vn} #{k} #{d} #{expt}")
@@ -505,6 +600,11 @@ module Roma
505
600
  if @stats.wb_command_map.key?(:cas)
506
601
  Roma::WriteBehindProcess::push(hname, @stats.wb_command_map[:cas], k, ret[4])
507
602
  end
603
+ if $roma.cr_writer.run_replication
604
+ k = "#{k}\e#{hname}" if hname != @defhash
605
+ fnc = 'set' # To restrain a defference between main and replica cluster due to clk
606
+ Roma::WriteBehindProcess::push(nil, "#{fnc} #{k} 0 #{expt} #{v.length} \r\n#{v}\r\n", k, v)
607
+ end
508
608
  redundant(nodes, hname, k, d, ret[2], expt, ret[4])
509
609
  send_data("STORED\r\n")
510
610
  end
@@ -585,7 +685,7 @@ module Roma
585
685
  store(fnc, hname, vn, key, d, s[3].to_i, v, nodes)
586
686
  end
587
687
 
588
- def store_incr_decr(fnc, hname, vn, k, d, v, nodes)
688
+ def store_incr_decr(fnc, hname, vn, k, d, v, nodes)
589
689
  unless @storages.key?(hname)
590
690
  send_data("SERVER_ERROR #{hname} does not exists.\r\n")
591
691
  return
@@ -603,6 +703,10 @@ module Roma
603
703
  if @stats.wb_command_map.key?(fnc)
604
704
  Roma::WriteBehindProcess::push(hname, @stats.wb_command_map[fnc], k, res[4])
605
705
  end
706
+ if $roma.cr_writer.run_replication
707
+ k = "#{k}\e#{hname}" if hname != @defhash
708
+ Roma::WriteBehindProcess::push(nil, "#{fnc} #{k} #{v}\r\n", k, v)
709
+ end
606
710
  redundant(nodes, hname, k, d, res[2], res[3], res[4])
607
711
  send_data("#{res[4]}\r\n")
608
712
  else