drbqs 0.0.14 → 0.0.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. data/VERSION +1 -1
  2. data/bin/drbqs-execute +6 -0
  3. data/bin/drbqs-manage +2 -2
  4. data/bin/drbqs-node +2 -2
  5. data/bin/drbqs-server +2 -2
  6. data/bin/drbqs-ssh +2 -2
  7. data/drbqs.gemspec +53 -16
  8. data/example/error_server/error.rb +6 -0
  9. data/example/error_server/server_def.rb +7 -0
  10. data/example/{error → error_task}/error.rb +0 -0
  11. data/example/{error → error_task}/server_def.rb +0 -0
  12. data/example/sum2/execute_def.rb +27 -0
  13. data/lib/drbqs/command_line/argument.rb +29 -0
  14. data/lib/drbqs/command_line/command_base.rb +81 -0
  15. data/lib/drbqs/command_line/command_execute.rb +33 -0
  16. data/lib/drbqs/command_line/command_line.rb +19 -0
  17. data/lib/drbqs/command_line/command_manage.rb +34 -0
  18. data/lib/drbqs/command_line/command_node.rb +26 -0
  19. data/lib/drbqs/command_line/command_server.rb +41 -0
  20. data/lib/drbqs/command_line/command_ssh.rb +51 -0
  21. data/lib/drbqs/command_line/option_setting.rb +42 -0
  22. data/lib/drbqs/execute/process_define.rb +213 -0
  23. data/lib/drbqs/execute/register.rb +147 -0
  24. data/lib/drbqs/{utility → execute}/server_define.rb +7 -14
  25. data/lib/drbqs/manage/execute_node.rb +4 -2
  26. data/lib/drbqs/manage/manage.rb +23 -16
  27. data/lib/drbqs/manage/send_signal.rb +31 -4
  28. data/lib/drbqs/manage/ssh_execute.rb +50 -6
  29. data/lib/drbqs/manage/ssh_shell.rb +95 -50
  30. data/lib/drbqs/node/connection.rb +1 -1
  31. data/lib/drbqs/node/node.rb +67 -17
  32. data/lib/drbqs/node/state.rb +109 -0
  33. data/lib/drbqs/node/task_client.rb +7 -7
  34. data/lib/drbqs/server/history.rb +16 -0
  35. data/lib/drbqs/server/message.rb +80 -15
  36. data/lib/drbqs/server/node_list.rb +16 -3
  37. data/lib/drbqs/server/prof.rb +48 -0
  38. data/lib/drbqs/server/queue.rb +20 -2
  39. data/lib/drbqs/server/server.rb +112 -70
  40. data/lib/drbqs/server/server_hook.rb +26 -6
  41. data/lib/drbqs/server/test/node.rb +34 -0
  42. data/lib/drbqs/server/test/server.rb +74 -0
  43. data/lib/drbqs/setting/base.rb +120 -0
  44. data/lib/drbqs/setting/data_container.rb +39 -0
  45. data/lib/drbqs/setting/execute.rb +71 -0
  46. data/lib/drbqs/setting/manage.rb +163 -0
  47. data/lib/drbqs/setting/node.rb +84 -0
  48. data/lib/drbqs/setting/server.rb +230 -0
  49. data/lib/drbqs/setting/setting.rb +14 -0
  50. data/lib/drbqs/setting/source.rb +220 -0
  51. data/lib/drbqs/setting/ssh.rb +165 -0
  52. data/lib/drbqs/task/task_generator.rb +4 -2
  53. data/lib/drbqs/utility/misc.rb +15 -1
  54. data/lib/drbqs/utility/temporary.rb +4 -2
  55. data/lib/drbqs.rb +3 -2
  56. data/spec/command_line/command_base_spec.rb +47 -0
  57. data/spec/{utility/command_line → command_line}/commands_spec.rb +3 -3
  58. data/spec/command_line/option_setting_spec.rb +29 -0
  59. data/spec/execute/def/execute1.rb +24 -0
  60. data/spec/execute/def/no_def.rb +2 -0
  61. data/spec/execute/process_define_spec.rb +167 -0
  62. data/spec/execute/register_spec.rb +77 -0
  63. data/spec/{utility → execute}/server_define_spec.rb +0 -0
  64. data/spec/integration_test/01_basic_usage_spec.rb +1 -1
  65. data/spec/integration_test/02_use_generator_spec.rb +1 -1
  66. data/spec/integration_test/03_use_temporary_file_spec.rb +1 -1
  67. data/spec/integration_test/04_use_unix_domain_spec.rb +1 -1
  68. data/spec/integration_test/05_server_exit_signal_spec.rb +1 -1
  69. data/spec/integration_test/06_node_exit_after_task_spec.rb +1 -1
  70. data/spec/integration_test/07_command_server_with_node_spec.rb +19 -16
  71. data/spec/integration_test/08_shutdown_unused_nodes_spec.rb +38 -0
  72. data/spec/integration_test/09_server_process_data_spec.rb +74 -0
  73. data/spec/integration_test/10_test_server_spec.rb +18 -0
  74. data/spec/integration_test/definition/task_obj_definition.rb +14 -0
  75. data/spec/manage/send_signal_spec.rb +8 -0
  76. data/spec/manage/ssh_shell_spec.rb +1 -1
  77. data/spec/node/state_spec.rb +148 -0
  78. data/spec/node/task_client_spec.rb +15 -0
  79. data/spec/server/history_spec.rb +51 -20
  80. data/spec/server/message_spec.rb +7 -2
  81. data/spec/server/node_list_spec.rb +1 -1
  82. data/spec/server/queue_spec.rb +93 -4
  83. data/spec/server/server_hook_spec.rb +62 -0
  84. data/spec/setting/base_spec.rb +35 -0
  85. data/spec/setting/data_container_spec.rb +92 -0
  86. data/spec/setting/execute_spec.rb +51 -0
  87. data/spec/setting/manage_spec.rb +63 -0
  88. data/spec/setting/node_spec.rb +43 -0
  89. data/spec/setting/server_spec.rb +46 -0
  90. data/spec/setting/source_spec.rb +245 -0
  91. data/spec/spec_helper.rb +17 -10
  92. data/spec/utility/argument_spec.rb +7 -7
  93. metadata +179 -146
  94. data/lib/drbqs/utility/argument.rb +0 -27
  95. data/lib/drbqs/utility/command_line/command_base.rb +0 -27
  96. data/lib/drbqs/utility/command_line/command_manage.rb +0 -121
  97. data/lib/drbqs/utility/command_line/command_node.rb +0 -103
  98. data/lib/drbqs/utility/command_line/command_server.rb +0 -165
  99. data/lib/drbqs/utility/command_line/command_ssh.rb +0 -126
  100. data/lib/drbqs/utility/command_line.rb +0 -15
  101. data/spec/utility/command_line/command_base_spec.rb +0 -33
@@ -6,39 +6,81 @@ module DRbQS
6
6
  class Manage
7
7
  # Requirements:
8
8
  # bash
9
- # nohup
10
9
  class SSHShell
10
+ class RubyEnvironment
11
+ DEFAULT_RVM_SCRIPT = '$HOME/.rvm/scripts/rvm'
12
+
13
+ attr_reader :directory, :rvm, :rvm_init, :env
14
+
15
+ # :directory
16
+ # :rvm
17
+ # :rvm_init
18
+ # :env
19
+ def initialize(opts = {})
20
+ @directory = opts[:directory]
21
+ @rvm = opts[:rvm]
22
+ @rvm_init = opts[:rvm_init]
23
+ if (@rvm || @rvm_init) && !(String === @rvm_init)
24
+ @rvm_init = DEFAULT_RVM_SCRIPT
25
+ end
26
+ @env = opts[:env]
27
+ end
28
+
29
+ def commands_to_set_env_on_bash
30
+ if @env
31
+ @env.map do |var, val|
32
+ "export #{var}=#{val}"
33
+ end
34
+ else
35
+ []
36
+ end
37
+ end
38
+ private :commands_to_set_env_on_bash
39
+
40
+ def setup_commands
41
+ cmds = commands_to_set_env_on_bash
42
+ cmds << "cd #{@directory}" if @directory
43
+ cmds << "source #{@rvm_init}" if @rvm_init
44
+ cmds << "rvm use #{@rvm}" if @rvm
45
+ cmds
46
+ end
47
+
48
+ def get_environment_commands
49
+ ['echo "directory: " `pwd`',
50
+ 'echo "files:"',
51
+ 'ls',
52
+ 'if which rvm > /dev/null; then rvm info; else ruby -v; fi']
53
+ end
54
+ end
55
+
11
56
  class InvalidDestination < StandardError
12
57
  end
13
58
  class GetInvalidExitStatus < StandardError
14
59
  end
15
60
 
16
- attr_reader :user, :host, :directory, :port
17
-
18
- DEFAULT_RVM_SCRIPT = '$HOME/.rvm/scripts/rvm'
19
- DEFAULT_OUTPUT_FILE = 'drbqs_nohup.log'
61
+ attr_reader :user, :host, :port, :keys
20
62
 
21
63
  # :shell shell to use
64
+ # :env a hash of environmental variables and their values
22
65
  # :dir base directory of ssh server
23
66
  # :rvm version of ruby on rvm
24
67
  # :rvm_init path of script to initialize rvm
25
- # :output file to output of stdout and stderr
68
+ # :keys path of a ssh key
69
+ # :io IO to output results of commands
26
70
  def initialize(dest, opts = {})
27
71
  @user, @host, @port = split_destination(dest)
28
72
  if !(@host && @user)
29
73
  raise InvalidDestination, "Invalid destination of ssh server."
30
74
  end
75
+ @keys = opts.delete(:keys)
31
76
  @shell = opts[:shell] || 'bash'
32
- @rvm = opts[:rvm]
33
- @rvm_init = opts[:rvm_init]
34
- if (@rvm || @rvm_init) && !(String === @rvm_init)
35
- @rvm_init = DEFAULT_RVM_SCRIPT
36
- end
37
- @nohup_output = opts[:output] || DEFAULT_OUTPUT_FILE
38
- @directory = opts[:dir]
39
- @out = $stdout
40
- @nice = opts[:nice]
41
- @nohup = opts[:nohup]
77
+ @ruby_environment = DRbQS::Manage::SSHShell::RubyEnvironment.new(opts)
78
+ @out = opts[:io]
79
+ @ssh = nil
80
+ end
81
+
82
+ def directory
83
+ @ruby_environment.directory
42
84
  end
43
85
 
44
86
  def split_destination(dest)
@@ -62,11 +104,14 @@ module DRbQS
62
104
  private :split_destination
63
105
 
64
106
  def output_command(cmd, result)
65
- @out.puts "#{@user}@#{@host}$ #{cmd}" if @out
66
- @out.print result
107
+ if @out
108
+ @out.puts "#{@user}@#{@host}$ #{cmd}"
109
+ @out.print result
110
+ end
67
111
  end
68
112
  private :output_command
69
113
 
114
+ # Return an array of a Net::SSH::Shell::Process object and a result string.
70
115
  def shell_exec_get_output(sh, cmd)
71
116
  result = ''
72
117
  pr_cmd = sh.execute!(cmd) do |sh_proc|
@@ -90,53 +135,53 @@ module DRbQS
90
135
 
91
136
  def shell_exec_check(sh, cmd)
92
137
  ary = shell_exec(sh, cmd)
93
- if ary[0].exit_status != 0
94
- raise GetInvalidExitStatus, "Can not execute '#{cmd}' on #{@host} properly."
138
+ n = ary[0].exit_status
139
+ if n != 0
140
+ raise GetInvalidExitStatus, "Can not execute properly on #{@host}.\nExit status: #{n}\ncommand: #{cmd}"
95
141
  end
96
142
  ary
97
143
  end
98
144
  private :shell_exec_check
99
145
 
100
- def execute_command(&block)
101
- Net::SSH.start(@host, @user, :port => @port) do |ssh|
146
+ def exec(cmd, opts = {})
147
+ unless @ssh
148
+ raise "Not connect."
149
+ end
150
+ if opts[:check]
151
+ shell_exec_check(@ssh, cmd)
152
+ else
153
+ shell_exec(@ssh, cmd)
154
+ end
155
+ end
156
+
157
+ def start(&block)
158
+ Net::SSH.start(@host, @user, :port => @port, :keys => @keys) do |ssh|
102
159
  ssh.shell(@shell) do |sh|
103
- shell_exec_check(sh, "cd #{@directory}") if @directory
104
- shell_exec_check(sh, "source #{@rvm_init}") if @rvm_init
105
- shell_exec_check(sh, "rvm use #{@rvm}") if @rvm
106
- yield(sh)
160
+ @ruby_environment.setup_commands.each do |cmd|
161
+ shell_exec_check(sh, cmd)
162
+ end
163
+ @ssh = sh
164
+ yield(self)
107
165
  shell_exec(sh, "exit")
108
166
  end
109
167
  end
168
+ ensure
169
+ @ssh = nil
110
170
  end
111
- private :execute_command
112
171
 
113
- def get_environment
114
- execute_command do |sh|
115
- ['echo "directory: " `pwd`',
116
- 'echo "files:"',
117
- 'ls',
118
- 'if which rvm > /dev/null; then rvm info; else ruby -v; fi'].each do |cmd|
119
- shell_exec(sh, cmd)
172
+ # :check
173
+ def execute_all(commands, opts = {})
174
+ results = []
175
+ start do |ssh_shell|
176
+ commands.each do |cmd|
177
+ results << ssh_shell.exec(cmd, opts)
120
178
  end
121
179
  end
180
+ results
122
181
  end
123
182
 
124
- def start(*args)
125
- cmd = args.join(' ')
126
- if @nice
127
- if Integer === @nice
128
- cmd = "nice -n #{@nice.to_s} " + cmd
129
- else
130
- cmd = "nice " + cmd
131
- end
132
- end
133
- execute_command do |sh|
134
- if @nohup
135
- pr, path = shell_exec_check(sh, "filename-create new -p middle -D parent -t time #{@nohup_output}")
136
- cmd = "nohup #{cmd} > #{path.strip} 2>&1 &"
137
- end
138
- shell_exec(sh, cmd)
139
- end
183
+ def get_environment
184
+ execute_all(@ruby_environment.get_environment_commands)
140
185
  end
141
186
  end
142
187
  end
@@ -52,7 +52,7 @@ module DRbQS
52
52
  when :alive_p
53
53
  @message.write([:server, :alive, @node_number])
54
54
  @logger.info("Send alive signal of node id #{@node_number}")
55
- when :exit, :finalize, :exit_after_task
55
+ when :exit, :finalize, :exit_after_task, :sleep, :wake
56
56
  return sym
57
57
  else
58
58
  raise "Get invalid signal: #{sym.inspect}"
@@ -1,25 +1,29 @@
1
1
  require 'drbqs/task/task'
2
2
  require 'drbqs/utility/transfer/transfer_client'
3
+ require 'drbqs/utility/temporary'
3
4
  require 'drbqs/node/connection'
4
5
  require 'drbqs/node/task_client'
5
- require 'drbqs/utility/temporary'
6
+ require 'drbqs/node/state'
6
7
 
7
8
  module DRbQS
8
9
 
9
10
  class Node
10
11
 
11
- WAIT_NEW_TASK = 1
12
12
  PRIORITY_RESPOND = 10
13
13
  PRIORITY_CALCULATE = 0
14
14
  OUTPUT_NOT_SEND_RESULT = 'not_send_result'
15
15
  DEFAULT_LOG_FILE = 'drbqs_client.log'
16
+ INTERVAL_TIME_DEFAULT = 1
16
17
 
17
18
  # :continue
19
+ # :max_loadavg
20
+ # :sleep_time
18
21
  def initialize(access_uri, opts = {})
19
22
  @access_uri = access_uri
20
23
  @logger = DRbQS::Misc.create_logger(opts[:log_file] || DEFAULT_LOG_FILE, opts[:log_level])
21
24
  @connection = nil
22
25
  @task_client = nil
26
+ @state = DRbQS::Node::State.new(:wait, :max_loadavg => opts[:max_loadavg], :sleep_time => opts[:sleep_time])
23
27
  @process_continue = opts[:continue]
24
28
  @signal_queue = Queue.new
25
29
  @config = DRbQS::Config.new
@@ -108,19 +112,27 @@ module DRbQS
108
112
  end
109
113
  private :send_error
110
114
 
111
- def communicate_with_server
112
- flag_finilize_exit = false
113
- @task_client.add_new_task
114
- case @connection.respond_signal
115
- when :exit
116
- return nil
117
- when :finalize
118
- flag_finilize_exit = true
119
- when :exit_after_task
120
- @task_client.set_exit_after_task
121
- @process_continue = nil
115
+ def get_new_task
116
+ if @state.request?
117
+ if @state.change_to_sleep_for_busy_system
118
+ @logger.info("Sleep because system is busy.")
119
+ elsif @task_client.add_new_task
120
+ @state.change_to_calculate
121
+ end
122
122
  end
123
+ end
124
+ private :get_new_task
125
+
126
+ def send_result
123
127
  flag_finilize_exit = @task_client.send_result
128
+ if @state.calculate? && !@task_client.calculating_task
129
+ @state.change_to_finish_calculating
130
+ end
131
+ flag_finilize_exit
132
+ end
133
+ private :send_result
134
+
135
+ def send_signal
124
136
  until @signal_queue.empty?
125
137
  signal, obj = @signal_queue.pop
126
138
  case signal
@@ -129,10 +141,38 @@ module DRbQS
129
141
  process_exit
130
142
  end
131
143
  end
132
- if flag_finilize_exit
144
+ end
145
+ private :send_signal
146
+
147
+ def process_signal
148
+ case @connection.respond_signal
149
+ when :wake
150
+ @state.change_to_wait
151
+ when :sleep
152
+ @state.change_to_sleep
153
+ when :exit
154
+ return :exit
155
+ when :finalize
156
+ return :finalize
157
+ when :exit_after_task
158
+ @task_client.set_exit_after_task
159
+ @process_continue = nil
160
+ end
161
+ nil
162
+ end
163
+ private :process_signal
164
+
165
+ def communicate_with_server
166
+ get_new_task
167
+ sig = process_signal
168
+ return nil if sig == :exit
169
+ flag_finilize_exit = send_result
170
+ send_signal
171
+ if sig == :finalize || flag_finilize_exit
133
172
  execute_finalization
134
173
  return nil
135
174
  end
175
+ @state.wakeup_automatically_for_unbusy_system
136
176
  true
137
177
  end
138
178
  private :communicate_with_server
@@ -143,16 +183,26 @@ module DRbQS
143
183
  end
144
184
  private :calculate_task
145
185
 
186
+ def clear_node_files
187
+ DRbQS::Temporary.delete_all
188
+ @config.list.node.delete(Process.pid)
189
+ end
190
+ private :clear_node_files
191
+
192
+ def wait_interval_of_connection
193
+ sleep(INTERVAL_TIME_DEFAULT)
194
+ end
195
+ private :wait_interval_of_connection
196
+
146
197
  def thread_communicate
147
198
  Thread.new do
148
199
  begin
149
200
  loop do
150
201
  unless communicate_with_server
151
- DRbQS::Temporary.delete_all
152
- @config.list.node.delete(Process.pid)
202
+ clear_node_files
153
203
  break
154
204
  end
155
- sleep(WAIT_NEW_TASK)
205
+ wait_interval_of_connection
156
206
  end
157
207
  rescue => err
158
208
  send_error(err, "Calculating thread")
@@ -0,0 +1,109 @@
1
+ module DRbQS
2
+ class Node
3
+ # Value of state is :sleep, :wait, or :calculate.
4
+ class State
5
+ attr_reader :state
6
+
7
+ ALL_STATES = [:sleep, :wait, :calculate]
8
+ DEFAULT_SLEEP_TIME = 300
9
+ LOADAVG_PATH = '/proc/loadavg'
10
+
11
+ def initialize(state, opts = {})
12
+ @state = state
13
+ @sleep_at_calculated = nil
14
+ @load_average_threshold = opts[:max_loadavg]
15
+ @sleep_time = opts[:sleep_time] || DEFAULT_SLEEP_TIME
16
+ @auto_wakeup = nil
17
+ end
18
+
19
+ def change(state)
20
+ unless ALL_STATES.include?(state)
21
+ raise ArgumentError, "Invalid state of node '#{state}'."
22
+ end
23
+ @state = state
24
+ end
25
+
26
+ def calculate?
27
+ @state == :calculate
28
+ end
29
+
30
+ def rest?
31
+ !calculate?
32
+ end
33
+
34
+ def stop?
35
+ @state == :sleep
36
+ end
37
+
38
+ def request?
39
+ @state == :wait
40
+ end
41
+
42
+ def change_to_wait
43
+ unless calculate?
44
+ change(:wait)
45
+ end
46
+ end
47
+
48
+ def change_to_sleep
49
+ if calculate?
50
+ @sleep_at_calculated = true
51
+ else
52
+ change(:sleep)
53
+ end
54
+ end
55
+
56
+ def change_to_calculate
57
+ change(:calculate)
58
+ end
59
+
60
+ def change_to_finish_calculating
61
+ if @sleep_at_calculated
62
+ change(:sleep)
63
+ else
64
+ change(:wait)
65
+ end
66
+ @sleep_at_calculated = nil
67
+ end
68
+
69
+ def sleep_with_auto_wakeup
70
+ change(:sleep)
71
+ @auto_wakeup = Time.now + @sleep_time
72
+ end
73
+
74
+ def wakeup_automatically_for_unbusy_system
75
+ if @auto_wakeup && Time.now > @auto_wakeup && !system_busy?
76
+ change(:wait)
77
+ @auto_wakeup = nil
78
+ return true
79
+ end
80
+ nil
81
+ end
82
+
83
+ def get_load_average
84
+ File.read(LOADAVG_PATH).split[0..2].map do |s|
85
+ s.to_f
86
+ end
87
+ end
88
+ private :get_load_average
89
+
90
+ def system_busy?
91
+ if @load_average_threshold && File.exist?(LOADAVG_PATH)
92
+ avg = get_load_average
93
+ if (avg[0] + avg[1]) / 2 >= @load_average_threshold
94
+ return true
95
+ end
96
+ end
97
+ nil
98
+ end
99
+
100
+ def change_to_sleep_for_busy_system
101
+ if system_busy?
102
+ sleep_with_auto_wakeup
103
+ return true
104
+ end
105
+ nil
106
+ end
107
+ end
108
+ end
109
+ end
@@ -53,14 +53,14 @@ module DRbQS
53
53
  end
54
54
 
55
55
  def add_new_task
56
- if !@calculating_task && !@exit_after_task
57
- if ary = get_task
58
- task_id, obj, method_sym, args = ary
59
- @logger.info("Send accept signal: node #{@node_number} caluclating #{task_id}")
60
- @result.write([:accept, task_id, @node_number])
61
- queue_task(task_id, [obj, method_sym, args])
62
- end
56
+ if !@calculating_task && !@exit_after_task && (ary = get_task)
57
+ task_id, obj, method_sym, args = ary
58
+ @logger.info("Send accept signal: node #{@node_number} caluclating #{task_id}")
59
+ @result.write([:accept, task_id, @node_number])
60
+ queue_task(task_id, [obj, method_sym, args])
61
+ return true
63
62
  end
63
+ nil
64
64
  end
65
65
 
66
66
  # If the method return true, a node should finilize and exit.
@@ -28,6 +28,22 @@ module DRbQS
28
28
  def each(&block)
29
29
  @data.each(&block)
30
30
  end
31
+ end
32
+
33
+ class TaskHistory < DRbQS::Server::History
34
+ attr_reader :finished_task_number
35
+
36
+ def initialize
37
+ super
38
+ @finished_task_number = 0
39
+ end
40
+
41
+ def set(id, *args)
42
+ if args[0] == :result
43
+ @finished_task_number += 1
44
+ end
45
+ super(id, *args)
46
+ end
31
47
 
32
48
  def log_strings
33
49
  s = ''
@@ -11,6 +11,14 @@ module DRbQS
11
11
  @logger = logger
12
12
  end
13
13
 
14
+ # Returned values:
15
+ # [:exit_server, nil]
16
+ # [:request_status, nil]
17
+ # [:request_history, nil]
18
+ # [:exit_after_task, node_id]
19
+ # [:wake_node, node_id]
20
+ # [:sleep_node, node_id]
21
+ # [:node_error, [node_id, error_message]]
14
22
  def get_message
15
23
  begin
16
24
  mes = @message.take([:server, Symbol, nil], 0)
@@ -36,10 +44,20 @@ module DRbQS
36
44
  return [mes, arg]
37
45
  when :request_status
38
46
  @logger.info("Get status request from #{arg.to_s}")
47
+ when :request_history
48
+ @logger.info("Get history request from #{arg.to_s}")
49
+ when :sleep_node
50
+ @logger.info("Get sleep node message for node #{arg.to_s}")
51
+ return [mes, arg]
52
+ when :wake_node
53
+ @logger.info("Get wake node message for node #{arg.to_s}")
54
+ return [mes, arg]
39
55
  when :node_error
40
- @node_list.delete(arg[0])
56
+ @node_list.delete(arg[0], :error)
41
57
  @logger.info("Node Error (#{arg[0]})") { arg[1] }
42
58
  return [mes, arg[0]]
59
+ when :new_data
60
+ return [mes, arg]
43
61
  else
44
62
  @logger.error("Invalid message from #{arg.to_s}")
45
63
  return nil
@@ -59,7 +77,9 @@ module DRbQS
59
77
  end
60
78
 
61
79
  def send_signal(node_id, signal)
62
- @message.write([node_id, signal])
80
+ if node_exist?(node_id)
81
+ @message.write([node_id, signal])
82
+ end
63
83
  end
64
84
  private :send_signal
65
85
 
@@ -75,30 +95,56 @@ module DRbQS
75
95
  send_signal_to_all_nodes(:exit)
76
96
  end
77
97
 
98
+ def send_sleep(node_id)
99
+ send_signal(node_id, :sleep)
100
+ end
101
+
102
+ def send_wake(node_id)
103
+ send_signal(node_id, :wake)
104
+ end
105
+
78
106
  # Send all nodes a message to finalize and exit.
79
107
  def send_finalization
80
108
  send_signal_to_all_nodes(:finalize)
81
109
  end
82
110
 
83
111
  def send_exit_after_task(node_id)
112
+ @node_list.add_to_preparation_to_exit(node_id)
84
113
  send_signal(node_id, :exit_after_task)
85
114
  end
86
115
 
87
- def send_status(calculating_task_id)
88
- s = ''
89
- @node_list.history.each do |node_id, events|
90
- if events.size == 0 || events.size > 2
91
- raise "Invalid history of nodes: #{events.inspect}"
92
- end
93
- connect = events[0]
94
- s << sprintf("%4d %s\t", node_id, connect[2])
95
- if disconnect = events[1]
96
- s << "disconnected: (#{time_to_history_string(connect[0])} - #{time_to_history_string(disconnect[0])})\n"
97
- else
98
- task_ids = calculating_task_id[node_id].to_a
99
- s << "task: #{task_ids.map { |num| num.to_s }.join(', ')} (#{time_to_history_string(connect[0])})\n"
116
+ # +data+ is a hash including server information.
117
+ # The keys are :calculating_task_number, :finished_task_number, :stocked_task_number,
118
+ # :calculating_nodes, and :generator_number.
119
+ def send_status(data)
120
+ s = "Nodes:\n"
121
+ if @node_list.history.size == 0
122
+ s << " none\n"
123
+ else
124
+ @node_list.history.each do |node_id, events|
125
+ if events.size == 0
126
+ s << "Empty history of node #{node_id}\n"
127
+ else
128
+ connect = events[0]
129
+ s << sprintf("%4d %s\t", node_id, connect[2])
130
+ if events.size > 1
131
+ s << "start:#{time_to_history_string(connect[0])}"
132
+ events[1..-1].each do |t, key|
133
+ s << ", #{key}: #{time_to_history_string(t)}"
134
+ end
135
+ s << "\n"
136
+ elsif data[:calculating_nodes]
137
+ task_ids = data[:calculating_nodes][node_id].to_a
138
+ s << "task: #{task_ids.map { |num| num.to_s }.join(', ')} (#{time_to_history_string(connect[0])})\n"
139
+ end
140
+ end
100
141
  end
101
142
  end
143
+ s << "Server:\n"
144
+ s << " calculating tasks: #{data[:calculating_task_number]}\n"
145
+ s << " finished tasks : #{data[:finished_task_number]}\n"
146
+ s << " stocked tasks : #{data[:stocked_task_number]}\n"
147
+ s << " task generator : #{data[:generator_number]}"
102
148
  begin
103
149
  @message.take([:status, nil], 0)
104
150
  rescue Rinda::RequestExpiredError
@@ -106,6 +152,14 @@ module DRbQS
106
152
  @message.write([:status, s])
107
153
  end
108
154
 
155
+ def send_history(history_string)
156
+ begin
157
+ @message.take([:history, nil], 0)
158
+ rescue Rinda::RequestExpiredError
159
+ end
160
+ @message.write([:history, history_string])
161
+ end
162
+
109
163
  def get_all_nodes
110
164
  @node_list.list.dup
111
165
  end
@@ -136,6 +190,17 @@ module DRbQS
136
190
  def set_finalization(task)
137
191
  set_special_task(:finalization, task)
138
192
  end
193
+
194
+ def shutdown_unused_nodes(calculating_nodes)
195
+ shutdown_nodes = []
196
+ @node_list.each do |node_id, id_str|
197
+ if !@node_list.prepare_to_exit?(node_id) && !calculating_nodes.include?(node_id)
198
+ send_exit_after_task(node_id)
199
+ shutdown_nodes << node_id
200
+ end
201
+ end
202
+ shutdown_nodes
203
+ end
139
204
  end
140
205
 
141
206
  end