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