drbqs 0.0.17 → 0.0.18

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/docs/FormatExecute.md +44 -2
  2. data/example/group/execute.rb +19 -0
  3. data/example/group/server.rb +27 -0
  4. data/example/group/sum.rb +9 -0
  5. data/example/mandelbrot/README.md +8 -0
  6. data/example/mandelbrot/execute.rb +4 -0
  7. data/lib/drbqs/command_line/command_node.rb +1 -0
  8. data/lib/drbqs/execute/execute_node.rb +4 -21
  9. data/lib/drbqs/node/connection.rb +1 -2
  10. data/lib/drbqs/node/node.rb +163 -102
  11. data/lib/drbqs/node/state.rb +100 -35
  12. data/lib/drbqs/node/task_client.rb +46 -33
  13. data/lib/drbqs/server/message.rb +13 -7
  14. data/lib/drbqs/server/server.rb +57 -29
  15. data/lib/drbqs/server/server_hook.rb +19 -5
  16. data/lib/drbqs/server/test/node.rb +31 -6
  17. data/lib/drbqs/setting/node.rb +11 -2
  18. data/lib/drbqs/setting/server.rb +1 -1
  19. data/lib/drbqs/task/task.rb +26 -6
  20. data/lib/drbqs/task/task_generator.rb +2 -1
  21. data/lib/drbqs/utility/temporary.rb +27 -6
  22. data/lib/drbqs/utility/transfer/transfer_client.rb +10 -12
  23. data/lib/drbqs/version.rb +1 -1
  24. data/lib/drbqs/worker.rb +2 -0
  25. data/lib/drbqs/worker/forked_process.rb +100 -0
  26. data/lib/drbqs/worker/serialize.rb +66 -0
  27. data/lib/drbqs/worker/worker.rb +133 -0
  28. data/lib/drbqs/worker/worker_process_set.rb +219 -0
  29. data/spec/integration_test/01_basic_usage_spec.rb +3 -2
  30. data/spec/integration_test/06_node_exit_after_task_spec.rb +3 -2
  31. data/spec/integration_test/07_command_server_with_node_spec.rb +1 -0
  32. data/spec/integration_test/08_shutdown_unused_nodes_spec.rb +3 -2
  33. data/spec/integration_test/10_test_server_spec.rb +2 -2
  34. data/spec/integration_test/11_special_tasks_spec.rb +61 -0
  35. data/spec/integration_test/12_multiple_workers_spec.rb +43 -0
  36. data/spec/integration_test/definition/task_obj_definition.rb +33 -6
  37. data/spec/node/connection_spec.rb +6 -6
  38. data/spec/node/node_spec.rb +10 -2
  39. data/spec/node/state_spec.rb +146 -62
  40. data/spec/node/task_client_spec.rb +58 -53
  41. data/spec/server/message_spec.rb +10 -6
  42. data/spec/server/queue_spec.rb +7 -4
  43. data/spec/server/server_hook_spec.rb +28 -1
  44. data/spec/task/task_spec.rb +43 -6
  45. data/spec/utility/temporary_spec.rb +32 -9
  46. data/spec/worker/forked_process_spec.rb +66 -0
  47. data/spec/worker/serialize_spec.rb +73 -0
  48. data/spec/worker/worker_process_set_spec.rb +104 -0
  49. data/spec/worker/worker_spec.rb +127 -0
  50. metadata +34 -19
@@ -24,6 +24,7 @@ describe DRbQS do
24
24
  end
25
25
 
26
26
  it "should raise error in server." do
27
+ puts "**** This test output errors to stdout ****"
27
28
  @path = File.expand_path(File.join(File.dirname(__FILE__), 'definition/server02.rb'))
28
29
  @port = 14071
29
30
  lambda do
@@ -12,8 +12,9 @@ describe DRbQS::Server do
12
12
 
13
13
  it "should send node exit" do
14
14
  execute_node = DRbQS::Execution::ExecuteNode.new(@uri, nil, nil)
15
- execute_node.execute(1)
16
- client_process_id = execute_node.pid[0]
15
+ client_process_id = fork do
16
+ execute_node.execute(1)
17
+ end
17
18
  th = Process.detach(client_process_id)
18
19
  lambda do
19
20
  @max_wait_time.times do |i|
@@ -7,12 +7,12 @@ describe DRbQS::Test::Server do
7
7
  it "should execute as test." do
8
8
  DRbQS.define_server do |server, argv, opts|
9
9
  5.times do |i|
10
- server.queue.add(DRbQS::Task.new(TestCount.new, :calc))
10
+ server.queue.add(DRbQS::Task.new(TestCountCalc.new, :calc))
11
11
  end
12
12
  end
13
13
  server = DRbQS.create_test_server({})
14
14
  data = server.test_exec
15
15
  data.should be_an_instance_of Hash
16
- TestCount.get.should == 5
16
+ TestCountCalc.get.should == 5
17
17
  end
18
18
  end
@@ -0,0 +1,61 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ require 'drbqs/task/task'
4
+ require_relative 'definition/task_obj_definition.rb'
5
+
6
+ describe DRbQS do
7
+ class TestValue
8
+ @file = File.join(File.dirname(__FILE__), 'value.txt')
9
+
10
+ def self.set(k, v)
11
+ open(@file, 'a+') do |f|
12
+ f.puts "#{k.to_s}\t#{v.to_s}"
13
+ end
14
+ end
15
+
16
+ def self.get(val)
17
+ if File.exist?(@file)
18
+ File.read(@file).each_line do |l|
19
+ if /^#{val.to_s}/ =~ l
20
+ return l.split[1].to_i
21
+ end
22
+ end
23
+ end
24
+ nil
25
+ end
26
+
27
+ def self.clear
28
+ FileUtils.rm(@file) if File.exist?(@file)
29
+ end
30
+ end
31
+
32
+ before(:all) do
33
+ @process_id, @uri = drbqs_fork_server(14110, :task => DRbQS::Task.new(Test1.new, :echo, args: [0])) do |server|
34
+ server.set_initialization_task(DRbQS::Task.new(TestValue, :set, args: [:first, 1]),
35
+ DRbQS::Task.new(TestValue, :set, args: [:second, 2]))
36
+ server.set_finalization_task(DRbQS::Task.new(TestValue, :set, args: [:third, 3]),
37
+ DRbQS::Task.new(TestValue, :set, args: [:fourth, 4]))
38
+ end
39
+ @node = DRbQS::Node.new(@uri, :log_file => $stdout, :continue => true)
40
+ end
41
+
42
+ it "should execute initialization tasks." do
43
+ @node.connect
44
+ TestValue.get(:first).should == 1
45
+ TestValue.get(:second).should == 2
46
+ end
47
+
48
+ it "should execute finalization tasks" do
49
+ @node.calculate
50
+ sleep(1) # Wait finish of task.
51
+ TestValue.get(:third).should == 3
52
+ TestValue.get(:fourth).should == 4
53
+ end
54
+
55
+ after(:all) do
56
+ TestValue.clear
57
+ lambda do
58
+ drbqs_wait_kill_server(@process_id, 30)
59
+ end.should_not raise_error
60
+ end
61
+ end
@@ -0,0 +1,43 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ require 'drbqs/task/task'
4
+ require_relative 'definition/task_obj_definition.rb'
5
+
6
+ describe DRbQS do
7
+ before(:all) do
8
+ @dir = 'test_pid_dir'
9
+ FileUtils.mkdir(@dir) unless File.exist?(@dir)
10
+ @number_of_task = 10
11
+ @tasks = @number_of_task.times.map do |i|
12
+ DRbQS::Task.new(TestPID.new, :save, args: [@dir])
13
+ end
14
+ @process_number = 3
15
+ @process_id, @uri = drbqs_fork_server(14120, :task => @tasks)
16
+ @node = DRbQS::Node.new(@uri, :log_file => $stdout, :continue => true, :process => @process_number)
17
+ end
18
+
19
+ it "should calculate" do
20
+ @node.connect
21
+ lambda do
22
+ @node.calculate
23
+ end.should_not raise_error
24
+ paths = Dir.glob(File.join(@dir, '*')).select do |file|
25
+ /^\d+$/ =~ File.basename(file)
26
+ end
27
+ paths.uniq.should have(@process_number).items
28
+ n = 0
29
+ paths.each do |path|
30
+ n += File.read(path).to_i
31
+ end
32
+ n.should == @number_of_task
33
+ end
34
+
35
+ after(:all) do
36
+ TestCount.clear
37
+ lambda do
38
+ drbqs_wait_kill_server(@process_id)
39
+ end.should_not raise_error
40
+ FileUtils.rm_r(@dir) if File.exist?(@dir)
41
+ end
42
+
43
+ end
@@ -1,14 +1,26 @@
1
- class Test1
2
- @@execute_echo_number = 0
1
+ class TestCount
2
+ @@file = File.join(File.dirname(__FILE__), 'count.txt')
3
3
 
4
4
  def echo(*args)
5
- puts "execute Test1#echo(*#{args.inspect.strip})"
6
- @@execute_echo_number += 1
5
+ open(@@file, 'a+') do |f|
6
+ f.puts "count"
7
+ end
7
8
  args
8
9
  end
9
10
 
10
11
  def self.get_execute_echo_number
11
- @@execute_echo_number
12
+ File.read(@@file).lines.to_a.size
13
+ end
14
+
15
+ def self.clear
16
+ FileUtils.rm(@@file) if File.exist?(@@file)
17
+ end
18
+ end
19
+
20
+ class Test1
21
+ def echo(*args)
22
+ puts "execute Test1#echo(*#{args.inspect.strip})"
23
+ args
12
24
  end
13
25
  end
14
26
 
@@ -48,7 +60,7 @@ class TestSum
48
60
  end
49
61
  end
50
62
 
51
- class TestCount
63
+ class TestCountCalc
52
64
  @@count = 0
53
65
 
54
66
  def calc
@@ -61,3 +73,18 @@ class TestCount
61
73
  n
62
74
  end
63
75
  end
76
+
77
+ class TestPID
78
+ def save(dir)
79
+ path = File.join(dir, "#{Process.pid}")
80
+ if File.exist?(path)
81
+ n = File.read(path).to_i + 1
82
+ else
83
+ n = 1
84
+ end
85
+ Kernel.open(path, 'w') do |f|
86
+ f.print n.to_s
87
+ end
88
+ true
89
+ end
90
+ end
@@ -20,9 +20,9 @@ describe DRbQS::Node::Connection do
20
20
  end
21
21
 
22
22
  it "should get initialization." do
23
- ary = [:initialize, [1, 2], :size, []]
24
- @message.write(ary)
25
- @connection.get_initialization.should == ary[1..-1]
23
+ ary = DRbQS::Task.new([1, 2], :size).simple_drb_args
24
+ @message.write([:initialize, ary])
25
+ @connection.get_initialization.should == ary
26
26
  end
27
27
 
28
28
  it "should get no finalization method." do
@@ -30,9 +30,9 @@ describe DRbQS::Node::Connection do
30
30
  end
31
31
 
32
32
  it "should get finalization." do
33
- ary = [:finalize, [1, 2], :size, []]
34
- @message.write(ary)
35
- @connection.get_finalization.should == ary[1..-1]
33
+ ary = DRbQS::Task.new([1, 2], :size).simple_drb_args
34
+ @message.write([:finalize, ary])
35
+ @connection.get_finalization.should == ary
36
36
  end
37
37
 
38
38
  it "should raise error for invalid signal." do
@@ -22,12 +22,20 @@ describe DRbQS::Node do
22
22
  end
23
23
 
24
24
  it "should connect to server." do
25
+ node_number = 10
25
26
  DRb::DRbObject.should_receive(:new_with_uri).and_return(@drb_object)
26
27
  node_connection = mock('node connection')
27
- node_connection.stub(:node_number).and_return(10)
28
+ node_connection.stub(:node_number).and_return(node_number)
28
29
  node_connection.stub(:get_initialization).and_return(nil)
30
+ task_client = mock('task client')
31
+ task_client.stub(:node_number).and_return(node_number)
32
+ worker = mock('worker')
33
+ worker.stub(:create_process)
34
+ worker.stub(:on_error)
35
+ worker.stub(:on_result)
29
36
  DRbQS::Node::Connection.should_receive(:new).and_return(node_connection)
30
- DRbQS::Node::TaskClient.should_receive(:new)
37
+ DRbQS::Node::TaskClient.should_receive(:new).and_return(task_client)
38
+ DRbQS::Worker::ProcessSet.should_receive(:new).and_return(worker)
31
39
  subject.connect
32
40
  end
33
41
  end
@@ -1,79 +1,178 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
2
 
3
3
  describe DRbQS::Node::State do
4
+ def make_all_processes_wait
5
+ @process_number.times do |i|
6
+ subject.change(i, :wait)
7
+ end
8
+ end
9
+
10
+ before(:all) do
11
+ @process_number = 3
12
+ end
13
+
4
14
  subject do
5
- DRbQS::Node::State.new(:wait)
15
+ DRbQS::Node::State.new(:wait, @process_number)
6
16
  end
7
17
 
8
- context "when state is :wait" do
18
+ context "when getting process number" do
19
+ it "should yield each process number." do
20
+ wids = []
21
+ subject.each_worker_id do |wid|
22
+ wids << wid
23
+ end
24
+ wids.sort.should == @process_number.times.to_a.sort
25
+ end
26
+
27
+ it "should get waiting process number." do
28
+ subject.waiting_worker_id.sort.should == @process_number.times.to_a.sort
29
+ end
30
+
31
+ it "should get waiting process number with not waiting process." do
32
+ waiting = []
33
+ @process_number.times do |i|
34
+ if i == 2
35
+ subject.change(i, :calculate)
36
+ else
37
+ waiting << i
38
+ end
39
+ end
40
+ subject.waiting_worker_id.sort.should == waiting
41
+ end
42
+ end
43
+
44
+ context "when requesting new tasks" do
9
45
  before(:each) do
10
- subject.change(:wait)
46
+ make_all_processes_wait
11
47
  end
12
48
 
13
- it "should change to :wait." do
14
- lambda do
15
- subject.change_to_wait
16
- end.should_not change { subject.state }
49
+ it "should request." do
50
+ subject.request?.should be_true
51
+ end
52
+
53
+ it "should request for all processes." do
54
+ subject.request_task_number.should == @process_number
55
+ end
56
+
57
+ it "should request except for one process." do
58
+ subject.change(0, :calculate)
59
+ subject.request_task_number.should == @process_number - 1
60
+ end
61
+ end
62
+
63
+ context "when state is :wait" do
64
+ before(:each) do
65
+ @process_number.times do |i|
66
+ subject.change(i, :wait)
67
+ end
17
68
  end
18
69
 
19
70
  it "should change to :sleep." do
20
- lambda do
21
- subject.change_to_sleep
22
- end.should change { subject.state }.from(:wait).to(:sleep)
71
+ subject.change_to_sleep
72
+ @process_number.times do |i|
73
+ subject.get_state(i).should == :sleep
74
+ end
23
75
  end
24
76
 
25
- it "should change to :calculate." do
26
- lambda do
27
- subject.change_to_calculate
28
- end.should change { subject.state }.from(:wait).to(:calculate)
77
+ it "should sleep." do
78
+ subject.sleep_with_auto_wakeup
79
+ @process_number.times do |i|
80
+ subject.get_state(i).should == :sleep
81
+ end
82
+ end
83
+
84
+ it "should wakeup." do
85
+ subject.wakeup_sleeping_worker
86
+ @process_number.times do |i|
87
+ subject.get_state(i).should == :wait
88
+ end
29
89
  end
30
90
  end
31
91
 
32
92
  context "when state is :sleep" do
33
93
  before(:each) do
34
- subject.change(:sleep)
94
+ @process_number.times do |i|
95
+ subject.change(i, :sleep)
96
+ end
35
97
  end
36
98
 
37
99
  it "should change to :sleep." do
38
- lambda do
39
- subject.change_to_wait
40
- end.should change { subject.state }.from(:sleep).to(:wait)
100
+ subject.change_to_sleep
101
+ @process_number.times do |i|
102
+ subject.get_state(i).should == :sleep
103
+ end
41
104
  end
42
105
 
43
- it "should change to :sleep." do
44
- lambda do
45
- subject.change_to_sleep
46
- end.should_not change { subject.state }
106
+ it "should sleep." do
107
+ subject.sleep_with_auto_wakeup
108
+ @process_number.times do |i|
109
+ subject.get_state(i).should == :sleep
110
+ end
47
111
  end
48
112
 
49
- it "should change to :calculate." do
50
- lambda do
51
- subject.change_to_calculate
52
- end.should change { subject.state }.from(:sleep).to(:calculate)
113
+ it "should wakeup." do
114
+ subject.wakeup_sleeping_worker
115
+ @process_number.times do |i|
116
+ subject.get_state(i).should == :wait
117
+ end
53
118
  end
54
119
  end
55
120
 
56
121
  context "when state is :calculate" do
57
122
  before(:each) do
58
- subject.change(:calculate)
123
+ @process_number.times do |i|
124
+ subject.change(i, :calculate)
125
+ end
59
126
  end
60
127
 
61
128
  it "should change to :sleep." do
62
- lambda do
63
- subject.change_to_wait
64
- end.should_not change { subject.state }
129
+ subject.change_to_sleep
130
+ @process_number.times do |i|
131
+ subject.get_state(i).should == :calculate
132
+ end
133
+ end
134
+
135
+ it "should sleep." do
136
+ subject.sleep_with_auto_wakeup
137
+ @process_number.times do |i|
138
+ subject.get_state(i).should == :calculate
139
+ end
140
+ end
141
+
142
+ it "should wakeup." do
143
+ subject.wakeup_sleeping_worker
144
+ @process_number.times do |i|
145
+ subject.get_state(i).should == :calculate
146
+ end
147
+ end
148
+ end
149
+
150
+ context "when state is :calculate" do
151
+ before(:each) do
152
+ @process_number.times do |i|
153
+ subject.change(i, :exit)
154
+ end
65
155
  end
66
156
 
67
157
  it "should change to :sleep." do
68
- lambda do
69
- subject.change_to_sleep
70
- end.should_not change { subject.state }
158
+ subject.change_to_sleep
159
+ @process_number.times do |i|
160
+ subject.get_state(i).should == :exit
161
+ end
71
162
  end
72
163
 
73
- it "should change to :calculate." do
74
- lambda do
75
- subject.change_to_calculate
76
- end.should_not change { subject.state }
164
+ it "should sleep." do
165
+ subject.sleep_with_auto_wakeup
166
+ @process_number.times do |i|
167
+ subject.get_state(i).should == :exit
168
+ end
169
+ end
170
+
171
+ it "should wakeup." do
172
+ subject.wakeup_sleeping_worker
173
+ @process_number.times do |i|
174
+ subject.get_state(i).should == :exit
175
+ end
77
176
  end
78
177
  end
79
178
 
@@ -91,50 +190,35 @@ describe DRbQS::Node::State do
91
190
 
92
191
  context "when setting load average" do
93
192
  subject do
94
- DRbQS::Node::State.new(:wait, :max_loadavg => 2)
193
+ DRbQS::Node::State.new(:wait, 1, :max_loadavg => 2)
95
194
  end
96
195
 
97
196
  it "should be true" do
98
197
  subject.stub(:get_load_average).and_return([2.0, 2,0, 2.0])
99
- subject.system_busy?.should be_true
198
+ subject.__send__(:system_busy?).should be_true
100
199
  end
101
200
 
102
201
  it "should be nil" do
103
202
  subject.stub(:get_load_average).and_return([1.0, 1,0, 1.0])
104
- subject.system_busy?.should be_nil
203
+ subject.__send__(:system_busy?).should be_nil
105
204
  end
106
205
  end
107
206
 
108
- context "when changing state to finish calculating" do
109
- before(:each) do
110
- subject.change(:calculate)
111
- end
112
-
113
- it "should change to :wait." do
114
- lambda do
115
- subject.change_to_finish_calculating
116
- end.should change { subject.state }.from(:calculate).to(:wait)
117
- end
118
-
119
- it "should change to :sleep." do
120
- subject.change_to_sleep
121
- lambda do
122
- subject.change_to_finish_calculating
123
- end.should change { subject.state }.from(:calculate).to(:sleep)
207
+ context "when setting auto wakeup" do
208
+ before(:all) do
209
+ @check_worker_id = 0
124
210
  end
125
- end
126
211
 
127
- context "when setting auto wakeup" do
128
212
  subject do
129
- DRbQS::Node::State.new(:wait, :sleep_time => 0)
213
+ DRbQS::Node::State.new(:wait, 1, :sleep_time => 0)
130
214
  end
131
215
 
132
216
  it "should do nothing." do
217
+ make_all_processes_wait
133
218
  subject.stub(:system_busy?).and_return(nil)
134
- subject.change(:wait)
135
219
  lambda do
136
220
  subject.wakeup_automatically_for_unbusy_system
137
- end.should_not change { subject.state }
221
+ end.should_not change { subject.get_state(@check_worker_id) }
138
222
  end
139
223
 
140
224
  it "should do nothing." do
@@ -142,7 +226,7 @@ describe DRbQS::Node::State do
142
226
  subject.sleep_with_auto_wakeup
143
227
  lambda do
144
228
  subject.wakeup_automatically_for_unbusy_system
145
- end.should change { subject.state }.from(:sleep).to(:wait)
229
+ end.should change { subject.get_state(@check_worker_id) }.from(:sleep).to(:wait)
146
230
  end
147
231
  end
148
232
  end