roma 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
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