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