drbqs 0.0.17 → 0.0.18
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.
- data/docs/FormatExecute.md +44 -2
- data/example/group/execute.rb +19 -0
- data/example/group/server.rb +27 -0
- data/example/group/sum.rb +9 -0
- data/example/mandelbrot/README.md +8 -0
- data/example/mandelbrot/execute.rb +4 -0
- data/lib/drbqs/command_line/command_node.rb +1 -0
- data/lib/drbqs/execute/execute_node.rb +4 -21
- data/lib/drbqs/node/connection.rb +1 -2
- data/lib/drbqs/node/node.rb +163 -102
- data/lib/drbqs/node/state.rb +100 -35
- data/lib/drbqs/node/task_client.rb +46 -33
- data/lib/drbqs/server/message.rb +13 -7
- data/lib/drbqs/server/server.rb +57 -29
- data/lib/drbqs/server/server_hook.rb +19 -5
- data/lib/drbqs/server/test/node.rb +31 -6
- data/lib/drbqs/setting/node.rb +11 -2
- data/lib/drbqs/setting/server.rb +1 -1
- data/lib/drbqs/task/task.rb +26 -6
- data/lib/drbqs/task/task_generator.rb +2 -1
- data/lib/drbqs/utility/temporary.rb +27 -6
- data/lib/drbqs/utility/transfer/transfer_client.rb +10 -12
- data/lib/drbqs/version.rb +1 -1
- data/lib/drbqs/worker.rb +2 -0
- data/lib/drbqs/worker/forked_process.rb +100 -0
- data/lib/drbqs/worker/serialize.rb +66 -0
- data/lib/drbqs/worker/worker.rb +133 -0
- data/lib/drbqs/worker/worker_process_set.rb +219 -0
- data/spec/integration_test/01_basic_usage_spec.rb +3 -2
- data/spec/integration_test/06_node_exit_after_task_spec.rb +3 -2
- data/spec/integration_test/07_command_server_with_node_spec.rb +1 -0
- data/spec/integration_test/08_shutdown_unused_nodes_spec.rb +3 -2
- data/spec/integration_test/10_test_server_spec.rb +2 -2
- data/spec/integration_test/11_special_tasks_spec.rb +61 -0
- data/spec/integration_test/12_multiple_workers_spec.rb +43 -0
- data/spec/integration_test/definition/task_obj_definition.rb +33 -6
- data/spec/node/connection_spec.rb +6 -6
- data/spec/node/node_spec.rb +10 -2
- data/spec/node/state_spec.rb +146 -62
- data/spec/node/task_client_spec.rb +58 -53
- data/spec/server/message_spec.rb +10 -6
- data/spec/server/queue_spec.rb +7 -4
- data/spec/server/server_hook_spec.rb +28 -1
- data/spec/task/task_spec.rb +43 -6
- data/spec/utility/temporary_spec.rb +32 -9
- data/spec/worker/forked_process_spec.rb +66 -0
- data/spec/worker/serialize_spec.rb +73 -0
- data/spec/worker/worker_process_set_spec.rb +104 -0
- data/spec/worker/worker_spec.rb +127 -0
- metadata +34 -19
data/lib/drbqs/node/state.rb
CHANGED
@@ -2,78 +2,142 @@ module DRbQS
|
|
2
2
|
class Node
|
3
3
|
class State
|
4
4
|
# Value of state is :sleep, :wait, or :calculate.
|
5
|
-
attr_reader :
|
5
|
+
attr_reader :calculating_task
|
6
6
|
|
7
|
-
ALL_STATES = [:sleep, :wait, :calculate]
|
7
|
+
ALL_STATES = [:sleep, :wait, :calculate, :exit]
|
8
8
|
DEFAULT_SLEEP_TIME = 300
|
9
9
|
LOADAVG_PATH = '/proc/loadavg'
|
10
10
|
|
11
|
-
def initialize(
|
12
|
-
@
|
13
|
-
@
|
11
|
+
def initialize(state_init, process_number, opts = {})
|
12
|
+
@process_number = process_number
|
13
|
+
@process_state = {}
|
14
|
+
@process_number.times do |i|
|
15
|
+
@process_state[i] = state_init
|
16
|
+
end
|
17
|
+
@calculating_task = {}
|
18
|
+
@state_after_task = nil
|
19
|
+
|
20
|
+
|
14
21
|
@load_average_threshold = opts[:max_loadavg]
|
15
22
|
@sleep_time = opts[:sleep_time] || DEFAULT_SLEEP_TIME
|
16
23
|
@auto_wakeup = nil
|
17
24
|
end
|
18
25
|
|
19
|
-
def
|
20
|
-
|
21
|
-
raise ArgumentError, "Invalid state of node '#{state}'."
|
22
|
-
end
|
23
|
-
@state = state
|
26
|
+
def get_state(wid)
|
27
|
+
@process_state[wid]
|
24
28
|
end
|
25
29
|
|
26
|
-
def
|
27
|
-
|
30
|
+
def each_worker_id(&block)
|
31
|
+
if block_given?
|
32
|
+
@process_state.each do |key, val|
|
33
|
+
yield(key)
|
34
|
+
end
|
35
|
+
else
|
36
|
+
to_enum(:each_worker_id)
|
37
|
+
end
|
28
38
|
end
|
29
39
|
|
30
|
-
def
|
31
|
-
|
40
|
+
def waiting_worker_id
|
41
|
+
ary = []
|
42
|
+
@process_state.each do |wid, state|
|
43
|
+
if state == :wait
|
44
|
+
ary << wid
|
45
|
+
end
|
46
|
+
end
|
47
|
+
ary
|
32
48
|
end
|
33
49
|
|
34
|
-
def
|
35
|
-
@
|
50
|
+
def request_task_number
|
51
|
+
waiting = @process_state.select do |wid, state|
|
52
|
+
state == :wait
|
53
|
+
end
|
54
|
+
waiting.size
|
36
55
|
end
|
37
56
|
|
38
57
|
def request?
|
39
|
-
|
58
|
+
request_task_number > 0
|
40
59
|
end
|
41
60
|
|
42
|
-
def
|
43
|
-
|
44
|
-
|
61
|
+
def all_workers_waiting?
|
62
|
+
each_worker_id.all? do |wid|
|
63
|
+
st = get_state(wid)
|
64
|
+
st == :wait || st == :exit
|
45
65
|
end
|
46
66
|
end
|
47
67
|
|
48
|
-
def
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
68
|
+
def set_calculating_task(wid, task_id)
|
69
|
+
@calculating_task[task_id] = wid
|
70
|
+
change(wid, :calculate)
|
71
|
+
end
|
72
|
+
|
73
|
+
def set_exit_after_task
|
74
|
+
@state_after_task = :exit
|
75
|
+
each_worker_id do |wid|
|
76
|
+
st = get_state(wid)
|
77
|
+
if (st == :wait) && (st == :sleep)
|
78
|
+
change(wid, :exit)
|
79
|
+
end
|
53
80
|
end
|
54
81
|
end
|
55
82
|
|
56
|
-
def
|
57
|
-
|
83
|
+
def set_finish_of_task(sent_task_id)
|
84
|
+
sent_task_id.each do |task_id|
|
85
|
+
if wid = @calculating_task.delete(task_id)
|
86
|
+
case @state_after_task
|
87
|
+
when :exit
|
88
|
+
@process_state[wid] = :exit
|
89
|
+
when :sleep
|
90
|
+
@process_state[wid] = :sleep
|
91
|
+
else
|
92
|
+
@process_state[wid] = :wait
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
58
96
|
end
|
59
97
|
|
60
|
-
def
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
98
|
+
def change(proc_id, state)
|
99
|
+
unless ALL_STATES.include?(state)
|
100
|
+
raise ArgumentError, "Invalid state of node '#{state}'."
|
101
|
+
end
|
102
|
+
@process_state[proc_id] = state
|
103
|
+
end
|
104
|
+
|
105
|
+
def wakeup_sleeping_worker
|
106
|
+
each_worker_id do |wid|
|
107
|
+
if get_state(wid) == :sleep
|
108
|
+
change(wid, :wait)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
@state_after_task = nil
|
112
|
+
end
|
113
|
+
|
114
|
+
def change_to_sleep
|
115
|
+
each_worker_id do |wid|
|
116
|
+
st = get_state(wid)
|
117
|
+
if st == :calculate
|
118
|
+
@state_after_task = :sleep
|
119
|
+
elsif st != :exit
|
120
|
+
change(wid, :sleep)
|
121
|
+
end
|
65
122
|
end
|
66
|
-
@sleep_at_calculated = nil
|
67
123
|
end
|
68
124
|
|
69
125
|
def sleep_with_auto_wakeup
|
70
|
-
|
126
|
+
each_worker_id do |wid|
|
127
|
+
if get_state(wid) == :wait
|
128
|
+
change(wid, :sleep)
|
129
|
+
end
|
130
|
+
end
|
71
131
|
@auto_wakeup = Time.now + @sleep_time
|
72
132
|
end
|
73
133
|
|
74
134
|
def wakeup_automatically_for_unbusy_system
|
75
135
|
if @auto_wakeup && Time.now > @auto_wakeup && !system_busy?
|
76
|
-
|
136
|
+
each_worker_id do |wid|
|
137
|
+
if get_state(wid) == :sleep
|
138
|
+
change(wid, :wait)
|
139
|
+
end
|
140
|
+
end
|
77
141
|
@auto_wakeup = nil
|
78
142
|
return true
|
79
143
|
end
|
@@ -96,6 +160,7 @@ module DRbQS
|
|
96
160
|
end
|
97
161
|
nil
|
98
162
|
end
|
163
|
+
private :system_busy?
|
99
164
|
|
100
165
|
def change_to_sleep_for_busy_system
|
101
166
|
if system_busy?
|
@@ -1,23 +1,18 @@
|
|
1
1
|
module DRbQS
|
2
2
|
class Node
|
3
3
|
class TaskClient
|
4
|
-
attr_reader :node_number, :
|
4
|
+
attr_reader :node_number, :group
|
5
5
|
|
6
|
-
def initialize(node_number, queue, result, logger = DRbQS::Misc::LoggerDummy.new)
|
6
|
+
def initialize(node_number, queue, result, group, logger = DRbQS::Misc::LoggerDummy.new)
|
7
7
|
@node_number = node_number
|
8
8
|
@queue = queue
|
9
9
|
@result = result
|
10
|
-
@calculating_task = nil
|
11
|
-
@exit_after_task = nil
|
12
10
|
@task_queue = Queue.new
|
13
11
|
@result_queue = Queue.new
|
12
|
+
@group = group || []
|
14
13
|
@logger = logger
|
15
14
|
end
|
16
15
|
|
17
|
-
def calculating?
|
18
|
-
!!@calculating_task
|
19
|
-
end
|
20
|
-
|
21
16
|
def task_empty?
|
22
17
|
@task_queue.empty?
|
23
18
|
end
|
@@ -31,57 +26,75 @@ module DRbQS
|
|
31
26
|
end
|
32
27
|
private :dequeue_result
|
33
28
|
|
34
|
-
|
35
|
-
|
29
|
+
# @param [Array] ary An array is [task_id, obj, method_name, args]
|
30
|
+
def queue_task(ary)
|
36
31
|
@task_queue.enq(ary)
|
37
32
|
end
|
38
33
|
|
34
|
+
# @return [nil,Array] If @task_queue is empty then return nil.
|
35
|
+
# Otherwise, an array [task_id, obj, method_name, args] is returned.
|
39
36
|
def dequeue_task
|
40
|
-
@task_queue.
|
37
|
+
if @task_queue.empty?
|
38
|
+
nil
|
39
|
+
else
|
40
|
+
@task_queue.deq
|
41
|
+
end
|
41
42
|
end
|
42
43
|
|
43
|
-
def
|
44
|
+
def get_task_by_group(grp)
|
44
45
|
begin
|
45
|
-
@queue.take([Fixnum, nil, Symbol, nil], 0)
|
46
|
+
@queue.take([grp, Fixnum, nil, Symbol, nil], 0)[1..-1]
|
46
47
|
rescue Rinda::RequestExpiredError
|
47
48
|
nil
|
48
49
|
end
|
49
50
|
end
|
50
51
|
|
51
|
-
def
|
52
|
-
@
|
52
|
+
def get_task
|
53
|
+
@group.each do |grp|
|
54
|
+
if task = get_task_by_group(grp)
|
55
|
+
return task
|
56
|
+
end
|
57
|
+
end
|
58
|
+
get_task_by_group(DRbQS::Task::DEFAULT_GROUP)
|
53
59
|
end
|
54
60
|
|
55
|
-
def add_new_task
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
61
|
+
def add_new_task(num)
|
62
|
+
get_task_id = []
|
63
|
+
num.times do |i|
|
64
|
+
if ary = get_task
|
65
|
+
task_id = ary[0]
|
66
|
+
@logger.info("Send accept signal: node #{@node_number} caluclating #{task_id}")
|
67
|
+
@result.write([:accept, task_id, @node_number])
|
68
|
+
queue_task(ary)
|
69
|
+
get_task_id << task_id
|
70
|
+
else
|
71
|
+
break
|
72
|
+
end
|
62
73
|
end
|
63
|
-
nil
|
74
|
+
get_task_id.empty? ? nil: get_task_id
|
64
75
|
end
|
65
76
|
|
66
|
-
#
|
77
|
+
# Return an array of task ID that is sent to the server.
|
67
78
|
def send_result
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
@
|
72
|
-
@
|
79
|
+
sent_task_id = []
|
80
|
+
while !result_empty?
|
81
|
+
task_id, result = dequeue_result
|
82
|
+
@logger.info("Send result: #{task_id}") { result.inspect }
|
83
|
+
@result.write([:result, task_id, @node_number, result])
|
84
|
+
sent_task_id << task_id
|
73
85
|
end
|
74
|
-
|
86
|
+
sent_task_id.empty? ? nil : sent_task_id
|
75
87
|
end
|
76
88
|
|
77
|
-
def queue_result(result)
|
78
|
-
@result_queue.enq(result)
|
89
|
+
def queue_result(task_id, result)
|
90
|
+
@result_queue.enq([task_id, result])
|
79
91
|
end
|
80
92
|
|
81
93
|
def dump_result_queue
|
82
94
|
results = []
|
83
95
|
while !result_empty?
|
84
|
-
|
96
|
+
task_id, res = dequeue_result
|
97
|
+
results << res
|
85
98
|
end
|
86
99
|
if results.size > 0
|
87
100
|
Marshal.dump(results)
|
data/lib/drbqs/server/message.rb
CHANGED
@@ -20,6 +20,8 @@ module DRbQS
|
|
20
20
|
# * [:wake_node, node_id]
|
21
21
|
# * [:sleep_node, node_id]
|
22
22
|
# * [:node_error, [node_id, error_message]]
|
23
|
+
# * [:initialize, Array]
|
24
|
+
# * [:finalize, Array]
|
23
25
|
#
|
24
26
|
# @return [Array] Message array
|
25
27
|
def get_message
|
@@ -148,23 +150,27 @@ module DRbQS
|
|
148
150
|
@node_list.exist?(node_id)
|
149
151
|
end
|
150
152
|
|
151
|
-
def set_special_task(label,
|
153
|
+
def set_special_task(label, *tasks)
|
154
|
+
task_ary = []
|
152
155
|
begin
|
153
|
-
@message.take([label,
|
156
|
+
task_ary = @message.take([label, Array], 0)[1]
|
154
157
|
rescue Rinda::RequestExpiredError
|
155
158
|
end
|
156
|
-
|
159
|
+
tasks.each do |task|
|
160
|
+
task_ary << task.simple_drb_args
|
161
|
+
end
|
162
|
+
@message.write([label, task_ary])
|
157
163
|
end
|
158
164
|
private :set_special_task
|
159
165
|
|
160
166
|
# If the task has already set,
|
161
167
|
# the method overwrite old task of initialization by new task.
|
162
|
-
def
|
163
|
-
set_special_task(:initialize,
|
168
|
+
def set_initialization_tasks(task_ary)
|
169
|
+
set_special_task(:initialize, *task_ary)
|
164
170
|
end
|
165
171
|
|
166
|
-
def
|
167
|
-
set_special_task(:
|
172
|
+
def set_finalization_tasks(task_ary)
|
173
|
+
set_special_task(:finalize, *task_ary)
|
168
174
|
end
|
169
175
|
|
170
176
|
def shutdown_unused_nodes(calculating_nodes)
|
data/lib/drbqs/server/server.rb
CHANGED
@@ -18,18 +18,33 @@ module DRbQS
|
|
18
18
|
attr_reader :queue, :uri
|
19
19
|
|
20
20
|
# @param [Hash] opts The options of server
|
21
|
-
# @option opts [
|
22
|
-
# @option opts [
|
23
|
-
# @option opts [
|
24
|
-
# @option opts [
|
25
|
-
# @option opts [
|
26
|
-
# @option opts [
|
27
|
-
# @option opts [
|
28
|
-
# @option opts [
|
29
|
-
# @option opts [
|
30
|
-
# @option opts [
|
31
|
-
# @option opts [
|
32
|
-
# @option opts [
|
21
|
+
# @option opts [Fixnum] :port Set the port of server.
|
22
|
+
# @option opts [String] :unix Set the path of unix domain socket. If :port is specified then :port is preceded.
|
23
|
+
# @option opts [Array] :acl Set the array of ACL.
|
24
|
+
# @option opts [String] :acl Set the file path of ACL.
|
25
|
+
# @option opts [String] :log_file Set the path of log files.
|
26
|
+
# @option opts [Fixnum] :log_level Set the level of logging.
|
27
|
+
# @option opts [Fixnum] :check_alive Set the time interval of checking alive nodes.
|
28
|
+
# @option opts [Boolean] :not_exit Not exit programs when all tasks are finished.
|
29
|
+
# @option opts [Boolean] :shutdown_unused_nodes Shutdown unused nodes.
|
30
|
+
# @option opts [Boolean] :signal_trap Set trapping signal. Default is true.
|
31
|
+
# @option opts [String] :sftp_user Set user of sftp.
|
32
|
+
# @option opts [String] :sftp_host Set host of sftp.
|
33
|
+
# @option opts [String] :file_directory Set the directory for nodes to send files.
|
34
|
+
#
|
35
|
+
# :nodoc:
|
36
|
+
# * Note of tuple spaces
|
37
|
+
# @ts[:message]
|
38
|
+
# - used in node/connection.rb
|
39
|
+
# - some messages to both server and node
|
40
|
+
# - special tasks from server to nodes
|
41
|
+
# @ts[:queue]
|
42
|
+
# - used in node/task_client.rb
|
43
|
+
# - tasks from server to nodes
|
44
|
+
# @ts[:result]
|
45
|
+
# - used in node/task_client.rb
|
46
|
+
# - accept signal from nodes
|
47
|
+
# - results from nodes
|
33
48
|
def initialize(opts = {})
|
34
49
|
@uri = DRbQS::Misc.create_uri(opts)
|
35
50
|
@acl = acl_init(opts[:acl])
|
@@ -48,7 +63,7 @@ module DRbQS
|
|
48
63
|
@task_generator = []
|
49
64
|
hook_init(!opts[:not_exit], opts[:shutdown_unused_nodes])
|
50
65
|
set_signal_trap if !opts.has_key?(:signal_trap) || opts[:signal_trap]
|
51
|
-
@finalization_task =
|
66
|
+
@finalization_task = []
|
52
67
|
@data_storage = []
|
53
68
|
@transfer_setting = DRbQS::Server::TransferSetting.new(opts[:sftp_host], opts[:sftp_user], opts[:file_directory])
|
54
69
|
@config = DRbQS::Config.new
|
@@ -107,7 +122,9 @@ module DRbQS
|
|
107
122
|
end
|
108
123
|
|
109
124
|
# Create new task generator and add it.
|
110
|
-
#
|
125
|
+
# @param [Hash] opts An argument is same as {DRbQS::Task::Generator#set}
|
126
|
+
# @yield [tgen] Block is same as {DRbQS::Task::Generator#set}
|
127
|
+
# @yieldparam [DRbQS::TaskGenerator] tgen Task generator to add to the server
|
111
128
|
def task_generator(opts = {}, &block)
|
112
129
|
gen = DRbQS::Task::Generator.new
|
113
130
|
gen.set(opts, &block)
|
@@ -145,29 +162,30 @@ module DRbQS
|
|
145
162
|
private :all_tasks_assigned?
|
146
163
|
|
147
164
|
# @param [DRbQS::task] task
|
148
|
-
def set_initialization_task(
|
149
|
-
@message.
|
165
|
+
def set_initialization_task(*tasks)
|
166
|
+
@message.set_initialization_tasks(tasks)
|
150
167
|
end
|
151
168
|
|
152
169
|
# @param [DRbQS::task] task
|
153
|
-
def set_finalization_task(
|
154
|
-
@finalization_task
|
155
|
-
@message.set_finalization(@finalization_task)
|
170
|
+
def set_finalization_task(*tasks)
|
171
|
+
@finalization_task.concat(tasks)
|
156
172
|
end
|
157
173
|
|
158
174
|
# Set a hook of server.
|
159
175
|
# @note When we set both :empty_queue and task generators,
|
160
176
|
# hook of :empty_queue is prior to task generators.
|
161
177
|
# @param [:empty_queue,:process_data,:finish] key Set the type of hook.
|
162
|
-
# @
|
178
|
+
# @option opts [Fixnum] :repeat If we execute the hook specified times then the hook is deleted.
|
179
|
+
# If the value is nil, the hook is repeated without limit.
|
180
|
+
# @option opts [String] :name Name of the hook. If the value is nil then the name is automatically created.
|
163
181
|
# @param [Proc] &block block is obligatory and takes server itself as an argument.
|
164
|
-
def add_hook(key,
|
182
|
+
def add_hook(key, opts = {}, &block)
|
165
183
|
if key == :process_data
|
166
184
|
if @hook.number_of_hook(:process_data) != 0
|
167
185
|
raise "Hook :process_data has already set."
|
168
186
|
end
|
169
187
|
end
|
170
|
-
@hook.add(key,
|
188
|
+
@hook.add(key, opts, &block)
|
171
189
|
end
|
172
190
|
|
173
191
|
# @param [:empty_queue,:process_data,:finish] key Set the type of hook.
|
@@ -238,7 +256,8 @@ module DRbQS
|
|
238
256
|
private :shutdown_unused_nodes
|
239
257
|
|
240
258
|
def exit
|
241
|
-
if
|
259
|
+
if !@finalization_task.empty?
|
260
|
+
@message.set_finalization_tasks(@finalization_task)
|
242
261
|
@message.send_finalization
|
243
262
|
wait_time = WAIT_TIME_NODE_FINALIZE
|
244
263
|
else
|
@@ -263,8 +282,8 @@ module DRbQS
|
|
263
282
|
|
264
283
|
# @param [String] directory Set the directory to save files from nodes.
|
265
284
|
# @param [Hash] opts The options for SFTP.
|
266
|
-
# @option opts [
|
267
|
-
# @option opts [
|
285
|
+
# @option opts [String] :host Hostname for SFTP.
|
286
|
+
# @option opts [String] :user User name for SFTP.
|
268
287
|
def set_file_transfer(directory, opts = {})
|
269
288
|
if @transfer_setting.setup_server(directory, opts)
|
270
289
|
@ts[:transfer] = @transfer_setting
|
@@ -295,6 +314,7 @@ module DRbQS
|
|
295
314
|
private :process_data
|
296
315
|
|
297
316
|
def send_status_for_request
|
317
|
+
task_message = []
|
298
318
|
messages = @queue.calculating_task_message
|
299
319
|
s = ''
|
300
320
|
@message.each_node_history do|node_id, events|
|
@@ -313,10 +333,9 @@ module DRbQS
|
|
313
333
|
task_ids = @queue.calculating[node_id].to_a
|
314
334
|
s << "task: "
|
315
335
|
if messages[node_id]
|
316
|
-
s << messages[node_id].map do |
|
317
|
-
|
318
|
-
|
319
|
-
calc_task
|
336
|
+
s << messages[node_id].map do |ary|
|
337
|
+
task_message << ary
|
338
|
+
ary[0].to_s
|
320
339
|
end.join(', ')
|
321
340
|
else
|
322
341
|
s << "none"
|
@@ -327,6 +346,15 @@ module DRbQS
|
|
327
346
|
end
|
328
347
|
s << " none\n" if s.size == 0
|
329
348
|
s = "Nodes:\n" << s
|
349
|
+
unless task_message.empty?
|
350
|
+
s << "Tasks:\n"
|
351
|
+
task_message.sort_by! do |task_id, mes|
|
352
|
+
task_id
|
353
|
+
end
|
354
|
+
task_message.each do |task_id, mes|
|
355
|
+
s << sprintf("%4d: %s\n", task_id, (mes ? mes.to_s : ''))
|
356
|
+
end
|
357
|
+
end
|
330
358
|
s << "Server:\n"
|
331
359
|
s << " calculating tasks: #{@queue.calculating_task_number}\n"
|
332
360
|
s << " finished tasks : #{@queue.finished_task_number}\n"
|