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,19 @@
1
+
2
+ module Roma
3
+ module CommandPlugin
4
+
5
+ module PluginOperation
6
+ include ::Roma::CommandPlugin
7
+
8
+ # DANGER!!
9
+ def ev_eval(s)
10
+ cmd = s[1..-1].join(' ')
11
+ @log.debug("eval(#{cmd})")
12
+ send_data("#{eval(cmd)}\r\n")
13
+ rescue =>e
14
+ send_data("#{e}\r\n")
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,14 @@
1
+
2
+ module Roma
3
+ module CommandPlugin
4
+
5
+ module PluginTest
6
+ include ::Roma::CommandPlugin
7
+
8
+ def ev_echo(s)
9
+ send_data("#{s.inspect}\r\n")
10
+ end
11
+
12
+ end
13
+ end
14
+ end
data/lib/roma/romad.rb ADDED
@@ -0,0 +1,582 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ #
4
+ require 'optparse'
5
+ require 'roma/config'
6
+ require 'roma/version'
7
+ require 'roma/stats'
8
+ require 'roma/command_plugin'
9
+ require 'roma/async_process'
10
+ require 'roma/write_behind'
11
+ require 'roma/logging/rlogger'
12
+ require 'roma/command/receiver'
13
+ require 'roma/messaging/con_pool'
14
+ require 'roma/event/con_pool'
15
+ require 'roma/routing/routing_data'
16
+ require 'timeout'
17
+
18
+ module Roma
19
+
20
+ class Romad
21
+ include AsyncProcess
22
+ include WriteBehindProcess
23
+
24
+ attr :storages
25
+ attr :rttable
26
+ attr :stats
27
+
28
+ attr_accessor :eventloop
29
+
30
+ def initialize(argv = nil)
31
+ @stats = Roma::Stats.instance
32
+ initialize_stats
33
+ options(argv)
34
+ initialize_logger
35
+ initialize_rttable
36
+ initialize_storages
37
+ initialize_handler
38
+ initialize_plugin
39
+ initialize_wb_witer
40
+ end
41
+
42
+ def start
43
+ if node_check(@stats.ap_str)
44
+ @log.error("#{@stats.ap_str} is already running.")
45
+ return
46
+ end
47
+
48
+ @storages.each{|hashname,st|
49
+ st.opendb
50
+ }
51
+
52
+ start_async_process
53
+ start_wb_process
54
+ timer
55
+
56
+ @eventloop = true
57
+ while(@eventloop)
58
+ @eventloop = false
59
+ begin
60
+ EventMachine::run do
61
+ EventMachine.start_server('0.0.0.0', @stats.port,
62
+ Roma::Command::Receiver,
63
+ @storages, @rttable)
64
+
65
+ @log.info("Now accepting connections on address #{@stats.address}, port #{@stats.port}")
66
+ end
67
+ rescue =>e
68
+ @log.error("#{e}\n#{$@}")
69
+ retry
70
+ end
71
+ end
72
+ stop_async_process
73
+ stop_wb_process
74
+ stop
75
+ end
76
+
77
+ def daemon?; @stats.daemon; end
78
+
79
+ private
80
+
81
+ def initialize_stats
82
+ if Roma::Config.const_defined?(:REDUNDANT_ZREDUNDANT_SIZE)
83
+ @stats.size_of_zredundant = Roma::Config::REDUNDANT_ZREDUNDANT_SIZE
84
+ end
85
+ end
86
+
87
+ def initialize_wb_witer
88
+ @wb_writer = Roma::WriteBehind::FileWriter.new(
89
+ Roma::Config::WRITEBEHIND_PATH,
90
+ Roma::Config::WRITEBEHIND_SHIFT_SIZE,
91
+ @log)
92
+ end
93
+
94
+ def initialize_plugin
95
+ return unless Roma::Config.const_defined? :PLUGIN_FILES
96
+
97
+ Roma::Config::PLUGIN_FILES.each do|f|
98
+ require "roma/plugin/#{f}"
99
+ @log.info("roma/plugin/#{f} loaded")
100
+ end
101
+ Roma::CommandPlugin.plugins.each do|plugin|
102
+ Roma::Command::Receiver.class_eval do
103
+ include plugin
104
+ end
105
+ @log.info("#{plugin.to_s} included")
106
+ end
107
+ end
108
+
109
+ def initialize_handler
110
+ return if @stats.verbose==false
111
+
112
+ Roma::Event::Handler.class_eval{
113
+ alias gets2 gets
114
+ undef gets
115
+
116
+ def gets
117
+ ret = gets2
118
+ @log.info("command log:#{ret.chomp}") if ret
119
+ ret
120
+ end
121
+ }
122
+ end
123
+
124
+ def initialize_logger
125
+ Roma::Logging::RLogger.create_singleton_instance("#{Roma::Config::LOG_PATH}/#{@stats.ap_str}.log",
126
+ Roma::Config::LOG_SHIFT_AGE,
127
+ Roma::Config::LOG_SHIFT_SIZE)
128
+ @log = Roma::Logging::RLogger.instance
129
+
130
+ if Config.const_defined? :LOG_LEVEL
131
+ case Config::LOG_LEVEL
132
+ when :debug
133
+ @log.level = Roma::Logging::RLogger::Severity::DEBUG
134
+ when :info
135
+ @log.level = Roma::Logging::RLogger::Severity::INFO
136
+ when :warn
137
+ @log.level = Roma::Logging::RLogger::Severity::WARN
138
+ when :error
139
+ @log.level = Roma::Logging::RLogger::Severity::ERROR
140
+ end
141
+ end
142
+ end
143
+
144
+ def options(argv)
145
+ opts = OptionParser.new
146
+ opts.banner="usage:#{File.basename($0)} [options] address"
147
+
148
+ @stats.daemon = false
149
+ opts.on("-d","--daemon") { |v| @stats.daemon = true }
150
+
151
+ opts.on_tail("-h", "--help", "Show this message") {
152
+ puts opts; exit
153
+ }
154
+
155
+ opts.on("-j","--join [address:port]") { |v| @stats.join_ap = v }
156
+
157
+ @stats.port = Roma::Config::DEFAULT_PORT.to_s
158
+ opts.on("-p", "--port [PORT]") { |v| @stats.port = v }
159
+
160
+ @stats.start_with_failover = false
161
+ opts.on(nil,"--start_with_failover"){ |v| @stats.start_with_failover = true }
162
+
163
+ @stats.verbose = false
164
+ opts.on(nil,"--verbose"){ |v| @stats.verbose = true }
165
+
166
+ opts.on_tail("-v", "--version", "Show version") {
167
+ puts "romad.rb #{Roma::VERSION}"; exit
168
+ }
169
+
170
+ @stats.name = Roma::Config::DEFAULT_NAME
171
+ opts.on("-n", "--name [name]") { |v| @stats.name = v }
172
+
173
+ @stats.enabled_repetition_host_in_routing = false
174
+ opts.on(nil,"--enabled_repeathost"){ |v|
175
+ @stats.enabled_repetition_host_in_routing = true
176
+ }
177
+
178
+ opts.parse!(argv)
179
+ raise OptionParser::ParseError.new if argv.length < 1
180
+ @stats.address = argv[0]
181
+
182
+ unless @stats.port =~ /^\d+$/
183
+ raise OptionParser::ParseError.new('Port number is not numeric.')
184
+ end
185
+
186
+ @stats.join_ap.sub!(':','_') if @stats.join_ap
187
+ if @stats.join_ap && !(@stats.join_ap =~ /^.+_\d+$/)
188
+ raise OptionParser::ParseError.new('[address:port] can not parse.')
189
+ end
190
+ rescue OptionParser::ParseError => e
191
+ $stderr.puts e.message
192
+ $stderr.puts opts.help
193
+ exit 1
194
+ end
195
+
196
+ def initialize_storages
197
+ @storages = {}
198
+ if Config.const_defined? :STORAGE_PATH
199
+ path = "#{Roma::Config::STORAGE_PATH}/#{@stats.ap_str}"
200
+ end
201
+
202
+ if Config.const_defined? :STORAGE_CLASS
203
+ st_class = Config::STORAGE_CLASS
204
+ end
205
+
206
+ if Config.const_defined? :STORAGE_DIVNUM
207
+ st_divnum = Config::STORAGE_DIVNUM
208
+ end
209
+ if Config.const_defined? :STORAGE_OPTION
210
+ st_option = Config::STORAGE_OPTION
211
+ end
212
+
213
+ path ||= './'
214
+ st_class ||= Storage::RubyHashStorage
215
+ st_divnum ||= 10
216
+ st_option ||= nil
217
+ Dir.glob("#{path}/*").each{|f|
218
+ if File.directory?(f)
219
+ hname = File.basename(f)
220
+ st = st_class.new
221
+ st.storage_path = "#{path}/#{hname}"
222
+ st.vn_list = @rttable.vnodes
223
+ st.divnum = st_divnum
224
+ st.option = st_option
225
+ @storages[hname] = st
226
+ end
227
+ }
228
+ if @storages.length == 0
229
+ hname = 'roma'
230
+ st = st_class.new
231
+ st.storage_path = "#{path}/#{hname}"
232
+ st.vn_list = @rttable.vnodes
233
+ st.divnum = st_divnum
234
+ st.option = st_option
235
+ @storages[hname] = st
236
+ end
237
+ end
238
+
239
+ def initialize_rttable
240
+ if @stats.join_ap
241
+ initialize_rttable_join
242
+ else
243
+ fname = "#{Roma::Config::RTTABLE_PATH}/#{@stats.ap_str}.route"
244
+ raise "#{fname} not found." unless File::exist?(fname)
245
+ rd = Roma::Routing::RoutingData::load(fname)
246
+ raise "It failed in loading the routing table data." unless rd
247
+ @rttable = Roma::Routing::ChurnbasedRoutingTable.new(rd,fname)
248
+ end
249
+
250
+ if Roma::Config.const_defined?(:ROUTING_FAIL_CNT_THRESHOLD)
251
+ @rttable.fail_cnt_threshold = Roma::Config::ROUTING_FAIL_CNT_THRESHOLD
252
+ end
253
+ if Roma::Config.const_defined?(:ROUTING_FAIL_CNT_GAP)
254
+ @rttable.fail_cnt_gap = Roma::Config::ROUTING_FAIL_CNT_GAP
255
+ end
256
+ @rttable.lost_action = Roma::Config::DEFAULT_LOST_ACTION
257
+ @rttable.enabled_failover = @stats.start_with_failover
258
+ @rttable.set_leave_proc{|nid|
259
+ Roma::Messaging::ConPool.instance.close_same_host(nid)
260
+ Roma::Event::EMConPool.instance.close_same_host(nid)
261
+ Roma::AsyncProcess::queue.push(Roma::AsyncMessage.new('broadcast_cmd',["leave #{nid}",[@stats.ap_str,nid,5]]))
262
+ }
263
+ @rttable.set_lost_proc{
264
+ if @rttable.lost_action == :shutdown
265
+ async_broadcast_cmd("rbalse lose_data\r\n")
266
+ EventMachine::stop_event_loop
267
+ @log.error("Romad has stopped, so that lose data.")
268
+ end
269
+ }
270
+ end
271
+
272
+ def initialize_rttable_join
273
+ name = async_send_cmd(@stats.join_ap,"whoami\r\n")
274
+ unless name
275
+ raise "No respons from #{@stats.join_ap}."
276
+ end
277
+
278
+ if name != @stats.name
279
+ raise "#{@stats.join_ap} has diffarent name.\n" +
280
+ "me = \"#{@stats.name}\" #{@stats.join_ap} = \"#{name}\""
281
+ end
282
+
283
+ fname = "#{Roma::Config::RTTABLE_PATH}/#{@stats.ap_str}.route"
284
+ if rd = get_routedump(@stats.join_ap)
285
+ rd.save(fname)
286
+ else
287
+ raise "It failed in getting the routing table data from #{@stats.join_ap}."
288
+ end
289
+
290
+ if rd.nodes.include?(@stats.ap_str)
291
+ raise "ROMA has already contained #{@stats.ap_str}."
292
+ end
293
+
294
+ @rttable = Roma::Routing::ChurnbasedRoutingTable.new(rd,fname)
295
+ nodes = @rttable.nodes
296
+
297
+ nodes.each{|nid|
298
+ begin
299
+ con = Roma::Messaging::ConPool.instance.get_connection(nid)
300
+ con.write("join #{@stats.ap_str}\r\n")
301
+ con.gets
302
+ Roma::Messaging::ConPool.instance.return_connection(nid, con)
303
+ rescue =>e
304
+ raise "Hotscale initialize failed.\n#{nid} unreachabled."
305
+ end
306
+ }
307
+ @rttable.add_node(@stats.ap_str)
308
+ end
309
+
310
+ def get_routedump(nid)
311
+ con = Roma::Messaging::ConPool.instance.get_connection(nid)
312
+ con.write("routingdump\r\n")
313
+ len = con.gets
314
+ if len.to_i <= 0
315
+ con.close
316
+ return nil
317
+ end
318
+
319
+ rcv=''
320
+ while(rcv.length != len.to_i)
321
+ rcv = rcv + con.read(len.to_i - rcv.length)
322
+ end
323
+ con.read(2)
324
+ con.gets
325
+ rd = Marshal.load(rcv)
326
+ Roma::Messaging::ConPool.instance.return_connection(nid,con)
327
+ rd
328
+ rescue
329
+ nil
330
+ end
331
+
332
+ def acquire_vnodes
333
+ return if @stats.run_acquire_vnodes || @rttable.nodes.length < 2
334
+
335
+ if @rttable.vnode_balance(@stats.ap_str)==:less
336
+ Roma::AsyncProcess::queue.push(Roma::AsyncMessage.new('start_acquire_vnodes_process'))
337
+ end
338
+ end
339
+
340
+ def timer
341
+ Thread.new do
342
+ loop do
343
+ sleep 1
344
+ timer_event_1sec
345
+ end
346
+ end
347
+ Thread.new do
348
+ loop do
349
+ sleep 10
350
+ timer_event_10sec
351
+ end
352
+ end
353
+ end
354
+
355
+ def timer_event_1sec
356
+ if @rttable.enabled_failover
357
+ nodes=@rttable.nodes
358
+ nodes.delete(@stats.ap_str)
359
+ nodes_check(nodes)
360
+ end
361
+
362
+ if (@stats.run_acquire_vnodes || @stats.run_recover) &&
363
+ @stats.run_storage_clean_up
364
+ @storages.each_value{|st| st.stop_clean_up}
365
+ @log.info("stop a storage clean up process")
366
+ end
367
+ end
368
+
369
+ def timer_event_10sec
370
+ if @rttable.enabled_failover == false
371
+ @log.debug("nodes_check start")
372
+ nodes=@rttable.nodes
373
+ nodes.delete(@stats.ap_str)
374
+ if nodes_check(nodes)
375
+ @log.info("all nodes started")
376
+ @rttable.enabled_failover = true
377
+ end
378
+ else
379
+ version_check
380
+ @rttable.delete_old_trans
381
+ start_sync_routing_process
382
+ end
383
+
384
+ if @stats.join_ap || @stats.enabled_vnodes_balance
385
+ acquire_vnodes
386
+ end
387
+
388
+ if (@rttable.enabled_failover &&
389
+ @stats.run_storage_clean_up == false &&
390
+ @stats.run_acquire_vnodes == false &&
391
+ @stats.run_recover == false &&
392
+ @stats.run_iterate_storage == false)
393
+ Roma::AsyncProcess::queue.push(Roma::AsyncMessage.new('start_storage_clean_up_process'))
394
+ end
395
+
396
+ @stats.clear_counters
397
+ rescue =>e
398
+ @log.error("#{e}\n#{$@}")
399
+ end
400
+
401
+ def nodes_check(nodes)
402
+ nodes.each{|nid|
403
+ return false unless node_check(nid)
404
+ }
405
+ return true
406
+ end
407
+
408
+ def node_check(nid)
409
+ name = async_send_cmd(nid,"whoami\r\n",1)
410
+ return false unless name
411
+ if name != @stats.name
412
+ @log.error("#{nid} has diffarent name.")
413
+ @log.error("me = \"#{@stats.name}\" #{nid} = \"#{name}\"")
414
+ return false
415
+ end
416
+ return true
417
+ end
418
+
419
+ def version_check
420
+ nodes=@rttable.nodes
421
+ nodes.each{|nid|
422
+ vs = async_send_cmd(nid,"version\r\n",1)
423
+ next unless vs
424
+ if /VERSION\s(\d+)\.(\d+)\.(\d+)/ =~ vs
425
+ ver = ($1.to_i << 16) + ($2.to_i << 8) + $3.to_i
426
+ @rttable.set_version(nid, ver)
427
+ end
428
+ }
429
+ end
430
+
431
+ def start_sync_routing_process
432
+ return if @stats.run_acquire_vnodes || @stats.run_recover || @stats.run_sync_routing
433
+
434
+ nodes = @rttable.nodes
435
+ return if nodes.length <= 1
436
+
437
+ @stats.run_sync_routing = true
438
+
439
+ idx=nodes.index(@stats.ap_str)
440
+ unless idx
441
+ @log.error("My node-id(=#{@stats.ap_str}) dose not found in the routingtable.")
442
+ EventMachine::stop_event_loop
443
+ return
444
+ end
445
+ Thread.new{
446
+ begin
447
+ ret = routing_hash_comparison(nodes[idx-1])
448
+ if ret == :inconsistent
449
+ @log.info("create nodes from v_idx");
450
+
451
+ @rttable.create_nodes_from_v_idx
452
+ begin
453
+ con = Roma::Messaging::ConPool.instance.get_connection(nodes[idx-1])
454
+ con.write("create_nodes_from_v_idx\r\n")
455
+ con.gets
456
+ Roma::Messaging::ConPool.instance.return_connection(nodes[idx-1], con)
457
+ rescue =>e
458
+ @log.error("create_nodes_from_v_idx command unreachabled to the #{nodes[idx-1]}.")
459
+ end
460
+ end
461
+ rescue =>e
462
+ @log.error("#{e}\n#{$@}")
463
+ end
464
+ @stats.run_sync_routing = false
465
+ }
466
+ end
467
+
468
+ def routing_hash_comparison(nid,id='0')
469
+ return :skip if @stats.run_acquire_vnodes || @stats.run_recover
470
+
471
+ h = async_send_cmd(nid,"mklhash #{id}\r\n")
472
+ if h && @rttable.mtree.get(id) != h
473
+ if (id.length - 1) == @rttable.div_bits
474
+ sync_routing(nid,id)
475
+ else
476
+ routing_hash_comparison(nid,"#{id}0")
477
+ routing_hash_comparison(nid,"#{id}1")
478
+ end
479
+ return :inconsistent
480
+ end
481
+ :consistent
482
+ end
483
+
484
+ def sync_routing(nid,id)
485
+ vn = @rttable.mtree.to_vn(id)
486
+ @log.warn("vn=#{vn} inconsistent")
487
+
488
+ res = async_send_cmd(nid,"getroute #{vn}\r\n")
489
+ return unless res
490
+ clk,*nids = res.split(' ')
491
+ clk = @rttable.set_route(vn, clk.to_i, nids)
492
+
493
+ if clk.is_a?(Integer) == false
494
+ clk,nids = @rttable.search_nodes_with_clk(vn)
495
+ cmd = "setroute #{vn} #{clk-1}"
496
+ nids.each{|nid2| cmd << " #{nid2}" }
497
+ async_send_cmd(nid,"#{cmd}\r\n")
498
+ end
499
+ end
500
+
501
+ def async_send_cmd(nid, cmd, tout=nil)
502
+ res = nil
503
+ if tout
504
+ timeout(tout){
505
+ con = Roma::Messaging::ConPool.instance.get_connection(nid)
506
+ con.write(cmd)
507
+ res = con.gets
508
+ Roma::Messaging::ConPool.instance.return_connection(nid, con)
509
+ }
510
+ else
511
+ con = Roma::Messaging::ConPool.instance.get_connection(nid)
512
+ con.write(cmd)
513
+ res = con.gets
514
+ Roma::Messaging::ConPool.instance.return_connection(nid, con)
515
+ end
516
+ if res
517
+ res.chomp!
518
+ @rttable.proc_succeed(nid) if @rttable
519
+ else
520
+ @rttable.proc_failed(nid) if @rttable
521
+ end
522
+ res
523
+ rescue => e
524
+ @rttable.proc_failed(nid) if @rttable
525
+ @log.error("#{__FILE__}:#{__LINE__}:Send command failed that node-id is #{nid},command is #{cmd}.")
526
+ nil
527
+ end
528
+
529
+ def async_broadcast_cmd(cmd,without_nids=nil,tout=nil)
530
+ without_nids=[@stats.ap_str] unless without_nids
531
+ res = {}
532
+ @rttable.nodes.each{ |nid|
533
+ res[nid] = async_send_cmd(nid,cmd,tout) unless without_nids.include?(nid)
534
+ }
535
+ res
536
+ rescue => e
537
+ @log.error("#{e}\n#{$@}")
538
+ nil
539
+ end
540
+
541
+ def stop
542
+ @storages.each_value{|st|
543
+ st.closedb
544
+ }
545
+ if @rttable.instance_of?(Roma::Routing::ChurnbasedRoutingTable)
546
+ @rttable.close_log
547
+ end
548
+ @log.info("Romad has stopped: #{@stats.ap_str}")
549
+ end
550
+
551
+ end
552
+
553
+ def self.daemon
554
+ p = Process.fork {
555
+ pid=Process.setsid
556
+ Signal.trap(:INT){
557
+ exit! 0
558
+ }
559
+ Signal.trap(:TERM){
560
+ exit! 0
561
+ }
562
+ Signal.trap(:HUP){
563
+ exit! 0
564
+ }
565
+ File.open("/dev/null","r+"){|f|
566
+ STDIN.reopen f
567
+ STDOUT.reopen f
568
+ STDERR.reopen f
569
+ }
570
+ yield
571
+ }
572
+ $stderr.puts p
573
+ exit! 0
574
+ end
575
+ end
576
+
577
+ $roma = Roma::Romad.new(ARGV)
578
+ if $roma.daemon?
579
+ Roma::daemon{ $roma.start }
580
+ else
581
+ $roma.start
582
+ end