drbqs 0.0.14 → 0.0.15

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