roma 0.8.2

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 (61) hide show
  1. data/LICENSE.rdoc +675 -0
  2. data/README.rdoc +0 -0
  3. data/Rakefile +70 -0
  4. data/bin/mkrecent +7 -0
  5. data/bin/mkroute +7 -0
  6. data/bin/recoverlost +8 -0
  7. data/bin/recoverlost_alist +8 -0
  8. data/bin/romad +7 -0
  9. data/bin/sample_watcher +8 -0
  10. data/bin/sample_watcher2 +8 -0
  11. data/bin/simple_bench +8 -0
  12. data/bin/ssroute +7 -0
  13. data/bin/tribunus +7 -0
  14. data/lib/roma/async_process.rb +696 -0
  15. data/lib/roma/command/bg_command_receiver.rb +188 -0
  16. data/lib/roma/command/mh_command_receiver.rb +117 -0
  17. data/lib/roma/command/receiver.rb +287 -0
  18. data/lib/roma/command/rt_command_receiver.rb +147 -0
  19. data/lib/roma/command/st_command_receiver.rb +564 -0
  20. data/lib/roma/command/util_command_receiver.rb +67 -0
  21. data/lib/roma/command/vn_command_receiver.rb +143 -0
  22. data/lib/roma/command_plugin.rb +11 -0
  23. data/lib/roma/config.rb +64 -0
  24. data/lib/roma/event/con_pool.rb +140 -0
  25. data/lib/roma/event/handler.rb +159 -0
  26. data/lib/roma/plugin/plugin_alist.rb +1572 -0
  27. data/lib/roma/plugin/plugin_debug.rb +19 -0
  28. data/lib/roma/plugin/plugin_test.rb +14 -0
  29. data/lib/roma/romad.rb +582 -0
  30. data/lib/roma/routing/cb_rttable.rb +326 -0
  31. data/lib/roma/routing/merkle_tree.rb +54 -0
  32. data/lib/roma/routing/rttable.rb +148 -0
  33. data/lib/roma/stats.rb +112 -0
  34. data/lib/roma/storage/basic_storage.rb +510 -0
  35. data/lib/roma/storage/dbm_storage.rb +80 -0
  36. data/lib/roma/storage/dummy_storage.rb +44 -0
  37. data/lib/roma/storage/rh_storage.rb +35 -0
  38. data/lib/roma/storage/sqlite3_storage.rb +73 -0
  39. data/lib/roma/storage/tc_storage.rb +133 -0
  40. data/lib/roma/tools/mkrecent.rb +138 -0
  41. data/lib/roma/tools/mkroute.rb +52 -0
  42. data/lib/roma/tools/recoverlost.rb +9 -0
  43. data/lib/roma/tools/recoverlost_alist.rb +9 -0
  44. data/lib/roma/tools/recoverlost_lib.rb +217 -0
  45. data/lib/roma/tools/sample_watcher.rb +38 -0
  46. data/lib/roma/tools/sample_watcher2.rb +38 -0
  47. data/lib/roma/tools/simple_bench.rb +57 -0
  48. data/lib/roma/tools/ssroute.rb +23 -0
  49. data/lib/roma/tools/tribunus.rb +299 -0
  50. data/lib/roma/version.rb +4 -0
  51. data/lib/roma/write_behind.rb +179 -0
  52. data/test/rcirb.rb +16 -0
  53. data/test/roma-test-utils.rb +65 -0
  54. data/test/run-test.rb +16 -0
  55. data/test/t_cpdata.rb +277 -0
  56. data/test/t_listplugin.rb +592 -0
  57. data/test/t_rclient.rb +318 -0
  58. data/test/t_routing_data.rb +100 -0
  59. data/test/t_storage.rb +644 -0
  60. data/test/t_writebehind.rb +200 -0
  61. metadata +134 -0
@@ -0,0 +1,696 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'thread'
3
+ require 'digest/sha1'
4
+
5
+ module Roma
6
+
7
+ class AsyncMessage
8
+ attr_accessor :event
9
+ attr_accessor :args
10
+ attr_accessor :callback
11
+
12
+ def initialize(ev,ag=nil,&cb)
13
+ @event = ev
14
+ @args = ag
15
+ @callback = cb
16
+ @retry_count = 0
17
+ @retry_max = 10
18
+ @retry_wait = 0.1
19
+ end
20
+
21
+ def retry?
22
+ @retry_max > @retry_count
23
+ end
24
+
25
+ def incr_count
26
+ @retry_count += 1
27
+ end
28
+
29
+ def wait
30
+ sleep(@retry_wait)
31
+ end
32
+ end
33
+
34
+ module AsyncProcess
35
+
36
+ @@async_queue = Queue.new
37
+
38
+ def self.queue
39
+ @@async_queue
40
+ end
41
+
42
+ def start_async_process
43
+ @async_thread = Thread.new{
44
+ async_process_loop
45
+ }
46
+ rescue =>e
47
+ @log.error("#{e}\n#{$@}")
48
+ end
49
+
50
+ private
51
+
52
+ def stop_async_process
53
+ count = 0
54
+ while @@async_queue.empty? == false && count < 100
55
+ count += 1
56
+ sleep 0.1
57
+ end
58
+ @async_thread.exit
59
+ end
60
+
61
+ def async_process_loop
62
+ loop {
63
+ while msg = @@async_queue.pop
64
+ if send("asyncev_#{msg.event}",msg.args)
65
+ msg.callback.call(msg,true) if msg.callback
66
+ else
67
+ if msg.retry?
68
+ Thread.new{
69
+ msg.wait
70
+ msg.incr_count
71
+ @@async_queue.push(msg)
72
+ }
73
+ else
74
+ @log.error("async process retry out:#{msg.inspect}")
75
+ msg.callback.call(msg,false) if msg.callback
76
+ end
77
+ end
78
+ end
79
+ }
80
+ rescue =>e
81
+ @log.error("#{e}\n#{$@}")
82
+ retry
83
+ end
84
+
85
+ def asyncev_broadcast_cmd(args)
86
+ @log.debug("asyncev_broadcast_cmd #{args.inspect}")
87
+ cmd, nids, tout = args
88
+ Thread::new{
89
+ async_broadcast_cmd("#{cmd}\r\n", nids, tout)
90
+ }
91
+ true
92
+ end
93
+
94
+ def asyncev_start_acquire_vnodes_process(args)
95
+ @log.debug("asyncev_start_acquire_vnodes_process")
96
+ if @stats.run_acquire_vnodes
97
+ @log.error("asyncev_start_acquire_vnodes_process:already in being")
98
+ return true
99
+ end
100
+ @stats.run_acquire_vnodes = true
101
+ Thread::new{
102
+ begin
103
+ acquire_vnodes_process
104
+ rescue =>e
105
+ @log.error("asyncev_start_acquire_vnodes_process:#{e.inspect} #{$@}")
106
+ ensure
107
+ @stats.run_acquire_vnodes = false
108
+ @stats.join_ap = nil
109
+ end
110
+ }
111
+ true
112
+ end
113
+
114
+ def asyncev_start_dumpfile_process(args)
115
+ @log.debug("asyncev_start_dumpfile_process #{args.inspect}")
116
+ key, path, cmd = args
117
+ path = Roma::Config::STORAGE_DUMP_PATH + '/' + path
118
+ Thread.new{
119
+ begin
120
+ except_vnh = {}
121
+ @rttable.each_vnode{|vn,nids|
122
+ if nids[0]!=@stats.ap_str
123
+ except_vnh[vn]=vn
124
+ end
125
+ }
126
+ # cmd expect the :dumpfile or :rdumpfile.
127
+ delete_to_end_of_dump(key) if cmd == :dumpfile
128
+ sleep 0.1
129
+ @storages.each_pair{|hname,st|
130
+ st.dump_file("#{path}/#{@stats.ap_str}/#{hname}",except_vnh)
131
+ }
132
+ ret = set_to_end_of_dump(key,@stats.ap_str)
133
+ if ret==nil || ret!="STORED"
134
+ @log.error("asyncev_start_dumpfile_process:result of set_to_end_of_dump was #{ret.inspect}")
135
+ end
136
+ @log.info("asyncev_start_dumpfile_process has done.")
137
+ rescue =>e
138
+ @log.error("#{e}\n#{$@}")
139
+ end
140
+ }
141
+ true
142
+ end
143
+
144
+ def delete_to_end_of_dump(key)
145
+ con = Roma::Messaging::ConPool.instance.get_connection(@stats.ap_str)
146
+ con.write("delete #{key}\eroma\r\n")
147
+ res = con.gets
148
+ res.chomp! if res
149
+ Roma::Messaging::ConPool.instance.return_connection(@stats.ap_str,con)
150
+ res
151
+ end
152
+
153
+ def set_to_end_of_dump(key,nid)
154
+ count = 0
155
+ begin
156
+ sleep 0.1
157
+ con = Roma::Messaging::ConPool.instance.get_connection(nid)
158
+ con.write("add #{key}\eroma 0 86400 #{nid.length}\r\n#{nid}\r\n")
159
+ res = con.gets
160
+ unless res=="STORED\r\n"
161
+ con.write("append #{key}\eroma 0 86400 #{nid.length+1}\r\n,#{nid}\r\n")
162
+ res = con.gets
163
+ end
164
+ Roma::Messaging::ConPool.instance.return_connection(nid,con)
165
+ count += 1
166
+ end while(res!="STORED\r\n" && count < 5)
167
+ res.chomp! if res
168
+ res
169
+ end
170
+
171
+ def asyncev_redundant(args)
172
+ nid,hname,k,d,clk,expt,v = args
173
+ @log.debug("asyncev_redundant #{args.inspect}")
174
+ unless @rttable.nodes.include?(nid)
175
+ @log.warn("async redundant failed:#{nid} dose not found in routing table.#{k}\e#{hname} #{d} #{clk} #{expt} #{v.length}")
176
+ return true # no retry
177
+ end
178
+ res = async_send_cmd(nid,"rset #{k}\e#{hname} #{d} #{clk} #{expt} #{v.length}\r\n#{v}\r\n",10)
179
+ unless res
180
+ @log.warn("async redundant failed:#{k}\e#{hname} #{d} #{clk} #{expt} #{v.length} -> #{nid}")
181
+ return false # retry
182
+ end
183
+ true
184
+ end
185
+
186
+ def asyncev_zredundant(args)
187
+ nid,hname,k,d,clk,expt,zv = args
188
+ @log.debug("asyncev_zredundant #{args.inspect}")
189
+ unless @rttable.nodes.include?(nid)
190
+ @log.warn("async zredundant failed:#{nid} dose not found in routing table.#{k}\e#{hname} #{d} #{clk} #{expt} #{zv.length}")
191
+ return true # no retry
192
+ end
193
+ res = async_send_cmd(nid,"rzset #{k}\e#{hname} #{d} #{clk} #{expt} #{zv.length}\r\n#{zv}\r\n",10)
194
+ unless res
195
+ @log.warn("async zredundant failed:#{k}\e#{hname} #{d} #{clk} #{expt} #{v.length} -> #{nid}")
196
+ return false # retry
197
+ end
198
+ true
199
+ end
200
+
201
+ def asyncev_reqpushv(args)
202
+ vn, nid, p = args
203
+ @log.debug("asyncev_reqpushv #{args.inspect}")
204
+ Thread::new{
205
+ sync_a_vnode(vn.to_i, nid, p == 'true')
206
+ }
207
+ end
208
+
209
+ def asyncev_start_recover_process(args)
210
+ @log.debug("asyncev_start_recover_process #{args.inspect}")
211
+ @stats.run_recover = true
212
+ Thread::new{
213
+ begin
214
+ if args != nil
215
+ acquired_recover_process
216
+ elsif args[0] == '-s'
217
+ recover_process
218
+ elsif args[0] == '-r' || args[0] == nil
219
+ acquired_recover_process
220
+ else
221
+ @log.error("asyncev_start_recover_process:argument error #{args.inspect}")
222
+ end
223
+ rescue => e
224
+ @log.error("asyncev_start_recover_process:#{e.inspect} #{$@}")
225
+ end
226
+ @stats.run_recover = false
227
+ }
228
+ end
229
+
230
+ def asyncev_start_release_process(args)
231
+ @log.debug("asyncev_start_release_process #{args}")
232
+ @stats.run_release = true
233
+ Thread::new{
234
+ begin
235
+ release_process
236
+ rescue => e
237
+ @log.error("asyncev_start_release_process:#{e.inspect} #{$@}")
238
+ end
239
+ @stats.run_relase = false
240
+ }
241
+ end
242
+
243
+ def asyncev_start_sync_process(args)
244
+ @log.debug("asyncev_start_sync_process")
245
+ @stats.run_recover = true
246
+ Thread::new{
247
+ sync_process(args)
248
+ @stats.run_recover = false
249
+ }
250
+ end
251
+
252
+ def sync_process(st)
253
+ own_nid = @stats.ap_str
254
+ @do_sync_process = true
255
+ @rttable.each_vnode{ |vn, nids|
256
+ break unless @do_sync_process
257
+ # my process charges of the primary node
258
+ if nids[0] == own_nid
259
+ nids[1..-1].each{ |nid|
260
+ unless sync_a_vnode(vn, nid)
261
+ @log.warn("sync_process:error at vn=#{vn} nid=#{nid}")
262
+ end
263
+ }
264
+ end
265
+ }
266
+ @log.info("Sync process has done.")
267
+ rescue =>e
268
+ @log.error("#{e.inspect} #{$@}")
269
+ ensure
270
+ @do_sync_process = false
271
+ Roma::Messaging::ConPool.instance.close_all
272
+ end
273
+
274
+ def acquired_recover_process
275
+ @log.info("acquired_recover_process:start")
276
+ exclude_nodes = @rttable.nodes
277
+
278
+ if @stats.enabled_repetition_host_in_routing
279
+ exclude_nodes = [@stats.ap_str]
280
+ else
281
+ myhost = @stats.ap_str.split(/[:_]/)[0]
282
+ exclude_nodes.delete_if{|nid| nid.split(/[:_]/)[0] != myhost }
283
+ end
284
+
285
+ @do_acquired_recover_process = true
286
+ loop {
287
+ break unless @do_acquired_recover_process
288
+ vnodes = @rttable.select_a_short_vnodes(exclude_nodes)
289
+ @log.info("acquired_recover_process:#{vnodes.length} short vnodes found.")
290
+ break if vnodes.length == 0
291
+ vn, nodes = vnodes[rand(vnodes.length)]
292
+ if nodes.length != 0
293
+ ret = req_push_a_vnode(vn, nodes[0], rand(@rttable.rn) == 0)
294
+ if ret == :rejected
295
+ sleep 1
296
+ elsif ret == false
297
+ break
298
+ end
299
+ sleep 1
300
+ end
301
+ }
302
+ @log.info("acquired_recover_process has done.")
303
+ rescue => e
304
+ @log.error("#{e.inspect} #{$@}")
305
+ ensure
306
+ @do_acquired_recover_process = false
307
+ end
308
+
309
+ def acquire_vnodes_process
310
+ count = 0
311
+ nv = @rttable.v_idx.length
312
+ @do_acquire_vnodes_process = true
313
+ while (@rttable.vnode_balance(@stats.ap_str) == :less && count < nv) do
314
+ break unless @do_acquire_vnodes_process
315
+ ret = acquire_vnode
316
+ if ret == :rejected
317
+ sleep 5
318
+ next
319
+ elsif ret == false
320
+ break
321
+ end
322
+ sleep 1
323
+ count += 1
324
+ end
325
+ @log.info("acquire_vnodes_prosess has done.")
326
+ rescue => e
327
+ @log.error("#{e.inspect} #{$@}")
328
+ ensure
329
+ @do_acquire_vnodes_process = false
330
+ end
331
+
332
+ def acquire_vnode
333
+ widthout_nodes = @rttable.nodes
334
+
335
+ if @stats.enabled_repetition_host_in_routing
336
+ widthout_nodes = [@stats.ap_str]
337
+ else
338
+ myhost = @stats.ap_str.split(/[:_]/)[0]
339
+ widthout_nodes.delete_if{|nid| nid.split(/[:_]/)[0] != myhost }
340
+ end
341
+
342
+ vn, nodes = @rttable.sample_vnode(widthout_nodes)
343
+ unless vn
344
+ @log.warn("acquire_vnode:sample_vnode dose not found")
345
+ return false
346
+ end
347
+ #
348
+ # tunning point
349
+ # sleep 0.1
350
+ #
351
+ req_push_a_vnode(vn, nodes[0], rand(@rttable.rn) == 0)
352
+ end
353
+
354
+ def req_push_a_vnode(vn, src_nid, is_primary)
355
+ con = Roma::Messaging::ConPool.instance.get_connection(src_nid)
356
+ con.write("reqpushv #{vn} #{@stats.ap_str} #{is_primary}\r\n")
357
+ res = con.gets # receive 'PUSHED\r\n' | 'REJECTED\r\n'
358
+ if res == "REJECTED\r\n"
359
+ @log.warn("req_push_a_vnode:request was rejected from #{src_nid}.")
360
+ return :rejected
361
+ end
362
+ Roma::Messaging::ConPool.instance.return_connection(src_nid,con)
363
+ # waiting for pushv
364
+ count = 0
365
+ while @rttable.search_nodes(vn).include?(@stats.ap_str)==false && count < 300
366
+ sleep 0.1
367
+ count += 1
368
+ end
369
+ if count >= 300
370
+ @log.warn("req_push_a_vnode:request has been time-out.vn=#{vn} nid=#{src_nid}")
371
+ return :timeout
372
+ end
373
+ true
374
+ rescue =>e
375
+ @log.error("req_push_a_vnode:#{e.inspect} #{$@}")
376
+ @rttable.proc_failed(src_nid)
377
+ false
378
+ end
379
+
380
+ def recover_process
381
+ @log.info("recover_process:start.")
382
+ nodes = @rttable.nodes
383
+
384
+ unless @stats.enabled_repetition_host_in_routing
385
+ host = @stats.ap_str.split(/[:_]/)[0]
386
+ nodes.delete_if{|nid| nid.split(/[:_]/)[0] == host }
387
+ else
388
+ nodes.delete(@stats.ap_str)
389
+ end
390
+
391
+ if nodes.length == 0
392
+ @log.error("New redundant node dose not found.")
393
+ return
394
+ end
395
+
396
+ @do_recover_process = true
397
+ @rttable.each_vnode{ |vn, nids|
398
+ break unless @do_recover_process
399
+ # my process charges of a primary node and it's short of redundant
400
+ if nids[0] == @stats.ap_str && nids.length < @rttable.rn
401
+ unless sync_a_vnode(vn, nodes[rand(nodes.length)])
402
+ @log.warn("recover_process:error at hname=#{hname} vn=#{vn}")
403
+ end
404
+ end
405
+ }
406
+ @log.info("Recover process has done.")
407
+ rescue =>e
408
+ @log.error("#{e}\n#{$@}")
409
+ ensure
410
+ @do_recover_process = false
411
+ Roma::Messaging::ConPool.instance.close_all
412
+ end
413
+
414
+ def release_process
415
+ @log.info("release_process:start.")
416
+ nodes = @rttable.nodes
417
+
418
+ unless @stats.enabled_repetition_host_in_routing
419
+ host = @stats.ap_str.split(/[:_]/)[0]
420
+ nodes.delete_if{|nid| nid.split(/[:_]/)[0] == host }
421
+ else
422
+ nodes.delete(@stats.ap_str)
423
+ end
424
+
425
+ if nodes.length < @rttable.rn
426
+ @log.error("Physcal node dose not found.")
427
+ return
428
+ end
429
+
430
+ @do_release_process = true
431
+ @rttable.each_vnode{ |vn, nids|
432
+ break unless @do_release_process
433
+ if nids.include?(@stats.ap_str)
434
+ buf = nodes.clone
435
+
436
+ unless @stats.enabled_repetition_host_in_routing
437
+ hosts = []
438
+ nids.each{|nid| hosts << nid.split(/[:_]/)[0]}
439
+ buf.delete_if{|nid| hosts.include?(nid.split(/[:_]/)[0])}
440
+ else
441
+ nids.each{|nid| buf.delete(nid) }
442
+ end
443
+
444
+ new_nid = buf[rand(buf.length)]
445
+ new_nids = nids.map{|n| n == @stats.ap_str ? new_nid : n }
446
+ unless sync_a_vnode_for_release(vn, new_nid, new_nids)
447
+ @log.warn("release_process:error at hname=#{hname} vn=#{vn}")
448
+ end
449
+ end
450
+ }
451
+ @log.info("Release process has done.")
452
+ rescue =>e
453
+ @log.error("#{e}\n#{$@}")
454
+ ensure
455
+ @do_release_process = false
456
+ Roma::Messaging::ConPool.instance.close_all
457
+ end
458
+
459
+ def sync_a_vnode_for_release(vn, to_nid, new_nids)
460
+ if @stats.run_iterate_storage == true
461
+ @log.warn("sync_a_vnode:already in being.#{vn} #{to_nid}")
462
+ return false
463
+ end
464
+ nids = @rttable.search_nodes(vn)
465
+
466
+ if nids.include?(to_nid)==false || (is_primary && nids[0]!=to_nid)
467
+ @log.debug("sync_a_vnode_for_release:#{vn} #{to_nid}")
468
+ # change routing data at the vnode and synchronize a data
469
+ nids << to_nid
470
+ return false unless @rttable.transaction(vn, nids)
471
+
472
+ # synchronize a data
473
+ @storages.each_key{ |hname|
474
+ res = push_a_vnode_stream(hname, vn, to_nid)
475
+
476
+ if res != "STORED"
477
+ @rttable.rollback(vn)
478
+ @log.error("push_a_vnode was failed:hname=#{hname} vn=#{vn}:#{res}")
479
+ return false
480
+ end
481
+ }
482
+
483
+ if (clk = @rttable.commit(vn)) == false
484
+ @rttable.rollback(vn)
485
+ @log.error("sync_a_vnode:routing table commit failed")
486
+ return false
487
+ end
488
+
489
+ clk = @rttable.set_route(vn, clk, new_nids)
490
+ if clk.is_a?(Integer) == false
491
+ clk,new_nids = @rttable.search_nodes_with_clk(vn)
492
+ end
493
+
494
+ cmd = "setroute #{vn} #{clk - 1}"
495
+ new_nids.each{ |nn| cmd << " #{nn}"}
496
+ res = async_broadcast_cmd("#{cmd}\r\n")
497
+ @log.debug("async_a_vnode_for_release:async_broadcast_cmd(#{cmd}) #{res}")
498
+ end
499
+
500
+ return true
501
+ rescue =>e
502
+ @log.error("#{e}\n#{$@}")
503
+ false
504
+ end
505
+
506
+ def sync_a_vnode(vn, to_nid, is_primary=nil)
507
+ if @stats.run_iterate_storage == true
508
+ @log.warn("sync_a_vnode:already in being.#{vn} #{to_nid} #{is_primary}")
509
+ return false
510
+ end
511
+ nids = @rttable.search_nodes(vn)
512
+
513
+ if nids.include?(to_nid)==false || (is_primary && nids[0]!=to_nid)
514
+ @log.debug("sync_a_vnode:#{vn} #{to_nid} #{is_primary}")
515
+ # change routing data at the vnode and synchronize a data
516
+ nids << to_nid
517
+ return false unless @rttable.transaction(vn, nids)
518
+
519
+ # synchronize a data
520
+ @storages.each_key{ |hname|
521
+ res = push_a_vnode_stream(hname, vn, to_nid)
522
+
523
+ if res != "STORED"
524
+ @rttable.rollback(vn)
525
+ @log.error("push_a_vnode was failed:hname=#{hname} vn=#{vn}:#{res}")
526
+ return false
527
+ end
528
+ }
529
+
530
+ if (clk = @rttable.commit(vn)) == false
531
+ @rttable.rollback(vn)
532
+ @log.error("sync_a_vnode:routing table commit failed")
533
+ return false
534
+ end
535
+
536
+ nids = edit_nodes(nids, to_nid, is_primary)
537
+ clk = @rttable.set_route(vn, clk, nids)
538
+ if clk.is_a?(Integer) == false
539
+ clk,nids = @rttable.search_nodes_with_clk(vn)
540
+ end
541
+
542
+ cmd = "setroute #{vn} #{clk - 1}"
543
+ nids.each{ |nn| cmd << " #{nn}"}
544
+ res = async_broadcast_cmd("#{cmd}\r\n")
545
+ @log.debug("sync_a_vnode:async_broadcast_cmd(#{cmd}) #{res}")
546
+ else
547
+ # synchronize a data
548
+ @storages.each_key{ |hname|
549
+ res = push_a_vnode_stream(hname, vn, to_nid)
550
+ if res != "STORED"
551
+ @log.error("push_a_vnode was failed:hname=#{hname} vn=#{vn}:#{res}")
552
+ return false
553
+ end
554
+ }
555
+ end
556
+
557
+ return true
558
+ rescue =>e
559
+ @log.error("#{e}\n#{$@}")
560
+ false
561
+ end
562
+
563
+ def edit_nodes(nodes, new_nid, is_primary)
564
+ if @rttable.rn == 1
565
+ return [new_nid]
566
+ end
567
+ if nodes.length > @rttable.rn
568
+ nodes.delete(new_nid)
569
+ nodes.delete(nodes.last)
570
+ nodes << new_nid
571
+ end
572
+ if is_primary
573
+ nodes.delete(new_nid)
574
+ nodes.insert(0,new_nid)
575
+ end
576
+ nodes
577
+ end
578
+
579
+ def push_a_vnode(hname, vn, nid)
580
+ dmp = @storages[hname].dump(vn)
581
+ unless dmp
582
+ @log.info("hname=#{hname} vn=#{vn} has a empty data.")
583
+ return "STORED"
584
+ end
585
+ con = Roma::Messaging::ConPool.instance.get_connection(nid)
586
+
587
+ con.write("pushv #{hname} #{vn}\r\n")
588
+ res = con.gets # READY\r\n or error string
589
+ if res != "READY\r\n"
590
+ con.close
591
+ return res.chomp
592
+ end
593
+ con.write("#{dmp.length}\r\n#{dmp}\r\nEND\r\n")
594
+ res = con.gets # STORED\r\n or error string
595
+
596
+ Roma::Messaging::ConPool.instance.return_connection(nid,con)
597
+ res.chomp! if res
598
+ res
599
+ rescue Errno::EPIPE
600
+ @log.debug("Errno::EPIPE retry")
601
+ retry
602
+ rescue =>e
603
+ @log.error("#{e.inspect}\n#{$@}")
604
+ "#{e}"
605
+ end
606
+
607
+ def push_a_vnode_stream(hname, vn, nid)
608
+ @stats.run_iterate_storage = true
609
+ @log.info("push_a_vnode_stream:hname=#{hname} vn=#{vn} nid=#{nid}")
610
+ con = Roma::Messaging::ConPool.instance.get_connection(nid)
611
+
612
+ con.write("spushv #{hname} #{vn}\r\n")
613
+
614
+ res = con.gets # READY\r\n or error string
615
+ if res != "READY\r\n"
616
+ con.close
617
+ return res.chomp
618
+ end
619
+
620
+ @storages[hname].each_vn_dump(vn){|data|
621
+ @stats.run_iterate_storage = true
622
+ con.write(data)
623
+ sleep @stats.stream_copy_wait_param
624
+ }
625
+ con.write("\0"*20) # end of steram
626
+
627
+ res = con.gets # STORED\r\n or error string
628
+ Roma::Messaging::ConPool.instance.return_connection(nid,con)
629
+ res.chomp! if res
630
+ res
631
+ rescue =>e
632
+ @log.error("#{e}\n#{$@}")
633
+ e.to_s
634
+ ensure
635
+ @stats.run_iterate_storage = false
636
+ end
637
+
638
+
639
+ def asyncev_start_storage_clean_up_process(args)
640
+ # @log.info("#{__method__}")
641
+ if @stats.run_storage_clean_up
642
+ @log.error("#{__method__}:already in being")
643
+ return
644
+ end
645
+ @stats.run_storage_clean_up = true
646
+ Thread::new{
647
+ begin
648
+ storage_clean_up_process
649
+ rescue =>e
650
+ @log.error("#{__method__}:#{e.inspect} #{$@}")
651
+ ensure
652
+ @stats.run_storage_clean_up = false
653
+ end
654
+ }
655
+ end
656
+
657
+ def storage_clean_up_process
658
+ # @log.info("#{__method__}:start")
659
+ me = @stats.ap_str
660
+ vnhash={}
661
+ @rttable.each_vnode{|vn, nids|
662
+ if nids.include?(me)
663
+ if nids[0] == me
664
+ vnhash[vn] = :primary
665
+ else
666
+ vnhash[vn] = :secondary
667
+ end
668
+ end
669
+ }
670
+ t = Time.now.to_i - Roma::Config::STORAGE_DELMARK_EXPTIME
671
+ count = 0
672
+ @storages.each_pair{|hname,st|
673
+ st.each_clean_up(t, vnhash){|key, vn|
674
+ count += 1
675
+ @stats.out_count += 1
676
+ # @log.debug("#{__method__}:key=#{key} vn=#{vn}")
677
+ nodes = @rttable.search_nodes_for_write(vn)
678
+ next if(nodes.length <= 1)
679
+ nodes[1..-1].each{|nid|
680
+ res = async_send_cmd(nid,"out #{key}\e#{hname} #{vn}\r\n")
681
+ unless res
682
+ @log.warn("send out command failed:#{key}\e#{hname} #{vn} -> #{nid}")
683
+ end
684
+ # @log.debug("#{__method__}:res=#{res}")
685
+ }
686
+ }
687
+ }
688
+ if count>0
689
+ @log.info("#{__method__}:#{count} keys deleted.")
690
+ end
691
+ end
692
+
693
+
694
+ end # module AsyncProcess
695
+
696
+ end # module Roma