drbqs 0.0.15 → 0.0.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. data/.document +3 -0
  2. data/README.md +137 -128
  3. data/VERSION +1 -1
  4. data/docs/FormatExecute.md +119 -0
  5. data/docs/GettingStarted.md +242 -0
  6. data/drbqs.gemspec +36 -13
  7. data/example/command/server_def.rb +4 -5
  8. data/example/execute/execute.rb +41 -0
  9. data/example/execute/server.rb +14 -0
  10. data/example/execute/task.rb +0 -0
  11. data/example/mandelbrot/README.md +15 -0
  12. data/example/mandelbrot/execute.rb +10 -0
  13. data/example/mandelbrot/mandelbrot.rb +56 -0
  14. data/example/mandelbrot/server.rb +49 -0
  15. data/example/server/server.rb +3 -6
  16. data/example/simple/README.md +18 -0
  17. data/example/simple/execute.rb +11 -0
  18. data/example/simple/server.rb +8 -0
  19. data/example/simple/task.rb +11 -0
  20. data/example/sum/server_def.rb +1 -1
  21. data/example/sum2/execute_def.rb +21 -8
  22. data/example/sum2/server_def.rb +8 -7
  23. data/example/transfer/file.rb +42 -8
  24. data/example/transfer/server_def.rb +43 -9
  25. data/lib/drbqs.rb +1 -1
  26. data/lib/drbqs/command_line/command_execute.rb +3 -3
  27. data/lib/drbqs/command_line/command_line.rb +1 -1
  28. data/lib/drbqs/execute/execute_node.rb +50 -0
  29. data/lib/drbqs/execute/process_define.rb +102 -54
  30. data/lib/drbqs/execute/register.rb +241 -87
  31. data/lib/drbqs/execute/server_define.rb +69 -58
  32. data/lib/drbqs/ext/task.rb +2 -0
  33. data/lib/drbqs/ext/task/command_task.rb +43 -0
  34. data/lib/drbqs/manage/manage.rb +5 -4
  35. data/lib/drbqs/manage/ssh_shell.rb +2 -8
  36. data/lib/drbqs/node/connection.rb +1 -1
  37. data/lib/drbqs/node/node.rb +8 -14
  38. data/lib/drbqs/node/task_client.rb +1 -1
  39. data/lib/drbqs/server/history.rb +5 -1
  40. data/lib/drbqs/server/message.rb +7 -34
  41. data/lib/drbqs/server/queue.rb +14 -2
  42. data/lib/drbqs/server/server.rb +86 -43
  43. data/lib/drbqs/server/server_hook.rb +3 -0
  44. data/lib/drbqs/server/test/node.rb +1 -1
  45. data/lib/drbqs/server/test/prof.rb +50 -0
  46. data/lib/drbqs/server/test/server.rb +2 -2
  47. data/lib/drbqs/server/transfer_setting.rb +23 -11
  48. data/lib/drbqs/setting/base.rb +15 -0
  49. data/lib/drbqs/setting/data_container.rb +1 -1
  50. data/lib/drbqs/setting/execute.rb +3 -3
  51. data/lib/drbqs/setting/node.rb +1 -1
  52. data/lib/drbqs/setting/server.rb +2 -2
  53. data/lib/drbqs/task/registrar.rb +39 -0
  54. data/lib/drbqs/task/task.rb +139 -59
  55. data/lib/drbqs/task/task_generator.rb +93 -116
  56. data/lib/drbqs/utility/misc.rb +15 -10
  57. data/lib/drbqs/utility/temporary.rb +7 -2
  58. data/lib/drbqs/utility/transfer/transfer.rb +81 -0
  59. data/lib/drbqs/utility/transfer/transfer_client.rb +68 -69
  60. data/lib/drbqs/utility/transfer/transfer_client_connect.rb +83 -0
  61. data/lib/drbqs/utility/transfer/transfer_file_list.rb +40 -0
  62. data/spec/execute/def/execute1.rb +4 -4
  63. data/spec/execute/def/execute2.rb +24 -0
  64. data/spec/execute/process_define_spec.rb +43 -6
  65. data/spec/execute/register_spec.rb +403 -9
  66. data/spec/execute/server_define_spec.rb +1 -1
  67. data/spec/ext/task/command_task_spec.rb +16 -0
  68. data/spec/integration_test/01_basic_usage_spec.rb +1 -1
  69. data/spec/integration_test/02_use_generator_spec.rb +2 -2
  70. data/spec/integration_test/04_use_unix_domain_spec.rb +1 -1
  71. data/spec/integration_test/05_server_exit_signal_spec.rb +1 -1
  72. data/spec/integration_test/06_node_exit_after_task_spec.rb +4 -4
  73. data/spec/integration_test/08_shutdown_unused_nodes_spec.rb +2 -2
  74. data/spec/integration_test/09_server_process_data_spec.rb +1 -1
  75. data/spec/integration_test/definition/server01.rb +4 -5
  76. data/spec/integration_test/definition/server02.rb +2 -4
  77. data/spec/node/node_spec.rb +34 -0
  78. data/spec/server/message_spec.rb +1 -1
  79. data/spec/server/queue_spec.rb +34 -7
  80. data/spec/server/server_spec.rb +21 -9
  81. data/spec/server/transfer_setting_spec.rb +59 -24
  82. data/spec/setting/base_spec.rb +11 -0
  83. data/spec/setting/data_container_spec.rb +8 -0
  84. data/spec/spec_helper.rb +1 -7
  85. data/spec/task/registrar_spec.rb +34 -0
  86. data/spec/task/task_generator_spec.rb +15 -15
  87. data/spec/task/task_spec.rb +132 -23
  88. data/spec/utility/misc_spec.rb +2 -2
  89. data/spec/utility/transfer/transfer_client_connect_spec.rb +90 -0
  90. data/spec/utility/transfer/transfer_file_list_spec.rb +27 -0
  91. data/spec/{task/file_transfer_spec.rb → utility/transfer/transfer_spec.rb} +24 -24
  92. metadata +66 -45
  93. data/lib/drbqs/manage/execute_node.rb +0 -50
  94. data/lib/drbqs/server/prof.rb +0 -48
  95. data/lib/drbqs/task/command_task.rb +0 -43
  96. data/lib/drbqs/utility/transfer/file_transfer.rb +0 -73
@@ -27,6 +27,9 @@ module DRbQS
27
27
  private :create_proc_name
28
28
 
29
29
  def add(key, name = nil, &block)
30
+ unless block_given?
31
+ raise ArgumentError, "The main part of hook must be specified as a block."
32
+ end
30
33
  if (n = @argument_number[key]) && (block.arity != n)
31
34
  raise ArgumentError, "Invalid argument number of hook of #{key.inspect}."
32
35
  end
@@ -5,7 +5,7 @@ module DRbQS
5
5
  class Node < DRbQS::Node
6
6
  def initialize(log_level, transfer, queue)
7
7
  super(nil, :log_file => $stdout, :log_level => log_level)
8
- @transfer = transfer
8
+ DRbQS::Transfer::Client.set(transfer.get_client(true)) if transfer
9
9
  @task_client = DRbQS::Node::TaskClient.new(nil, queue, nil)
10
10
  end
11
11
 
@@ -0,0 +1,50 @@
1
+ require 'ruby-prof'
2
+
3
+ module DRbQS
4
+ module Test
5
+ class Prof
6
+ PRINTER_TYPE = [:flat, :graph, :graphhtml, :calltree]
7
+
8
+ # :flat
9
+ # :graph
10
+ # :graphhtml
11
+ # :calltree
12
+ def initialize(printer_type, output)
13
+ @printer_type = printer_type
14
+ unless PRINTER_TYPE.include?(@printer_type)
15
+ raise "Invalid printer type: #{@printer_type.inspect}"
16
+ end
17
+ @output = output
18
+ end
19
+
20
+ def get_printer(result)
21
+ case @printer_type
22
+ when :flat
23
+ RubyProf::FlatPrinter.new(result)
24
+ when :graph
25
+ RubyProf::GraphPrinter.new(result)
26
+ when :graphhtml
27
+ RubyProf::GraphHtmlPrinter.new(result)
28
+ when :calltree
29
+ RubyProf::CallTreePrinter.new(result)
30
+ end
31
+ end
32
+ private :get_printer
33
+
34
+ def start
35
+ RubyProf.start
36
+ end
37
+
38
+ def finish
39
+ printer = get_printer(RubyProf.stop)
40
+ if IO === @output
41
+ printer.print(@output)
42
+ else
43
+ Kernel.open(@output, 'w') do |f|
44
+ printer.print(f)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -11,9 +11,9 @@ module DRbQS
11
11
  result = { :start => Time.now }
12
12
  num = 0
13
13
  if profile
14
- require 'drbqs/server/prof'
14
+ require 'drbqs/server/test/prof'
15
15
  result[:profile] = FileName.create(PROF_FILE, :position => :middle)
16
- prof = DRbQS::Prof.new(printer || :flat, result[:profile])
16
+ prof = DRbQS::Test::Prof.new(printer || :flat, result[:profile])
17
17
  prof.start
18
18
  end
19
19
  begin
@@ -9,21 +9,33 @@ module DRbQS
9
9
  @host = host
10
10
  @user = user
11
11
  @directory = directory
12
- @created = false
12
+ @setup_server = false
13
13
  end
14
14
 
15
- def create(directory, opts = {})
16
- return nil if @created
15
+ def prepared_directory
16
+ @setup_server && @directory
17
+ end
18
+
19
+ def information
20
+ info = "directory: #{@directory}"
21
+ info << ", sftp: #{@user}@#{@host}" if @host && @user
22
+ info
23
+ end
24
+
25
+ def setup_server(directory, opts = {})
26
+ return nil if @setup_server
17
27
  @directory = directory || @directory
18
28
  return nil if !@directory
19
- @created = true
20
- transfer_client = DRbQS::TransferClient.new(@directory)
21
- transfer_client.make_directory
22
- if host = opts[:host] || @host
23
- user = opts[:user] || @user || ENV['USER']
24
- transfer_client.set_sftp(user, host)
25
- end
26
- transfer_client
29
+ @setup_server = true
30
+ @directory = File.expand_path(@directory)
31
+ FileUtils.mkdir_p(@directory)
32
+ @host = opts[:host] || @host
33
+ @user = opts[:user] || @user || ENV['USER']
34
+ true
35
+ end
36
+
37
+ def get_client(same_host)
38
+ @setup_server ? DRbQS::Transfer::Client.new(@directory, same_host, @host, @user) : nil
27
39
  end
28
40
  end
29
41
  end
@@ -47,6 +47,21 @@ module DRbQS
47
47
  @source.value
48
48
  end
49
49
 
50
+ def clone
51
+ new_obj = self.class.new
52
+ instance_variables.each do |var_name|
53
+ var = instance_variable_get(var_name)
54
+ case var
55
+ when NilClass, FalseClass, TrueClass, Symbol
56
+ new_var = var
57
+ else
58
+ new_var = var.clone
59
+ end
60
+ new_obj.instance_variable_set(var_name, new_var)
61
+ end
62
+ new_obj
63
+ end
64
+
50
65
  def preprocess!
51
66
  end
52
67
  private :preprocess!
@@ -30,7 +30,7 @@ module DRbQS
30
30
  cl = DRbQS::Setting::Source::DataContainer.new(Array)
31
31
  cl.argument = obj.argument.clone
32
32
  obj.__data__.each do |key, val|
33
- cl.__data__[key] = val
33
+ cl.__data__[key] = val.clone
34
34
  end
35
35
  cl
36
36
  end
@@ -25,11 +25,11 @@ module DRbQS
25
25
  @port = get_first(:port) do |val|
26
26
  val.to_i
27
27
  end
28
- @no_server = get_first(:no_server)
28
+ @no_server = set?(:no_server)
29
29
  @server = get_first(:server) do |val|
30
30
  val.intern
31
31
  end
32
- @no_node = get_first(:no_node)
32
+ @no_node = set?(:no_node)
33
33
  @node = get_first(:node) do |val|
34
34
  val.split(',').map do |s|
35
35
  s.intern
@@ -43,7 +43,7 @@ module DRbQS
43
43
  else
44
44
  @mode = nil
45
45
  end
46
- if !@output_help && !@definition
46
+ if @mode != :help && !@definition
47
47
  raise DRbQS::Setting::InvalidArgument, "Definition file must be specified."
48
48
  end
49
49
  end
@@ -74,7 +74,7 @@ module DRbQS
74
74
  io.puts "Execute #{@process_num} processes"
75
75
  end
76
76
 
77
- exec_node = DRbQS::ExecuteNode.new(@uri, @options[:log_prefix], @options[:log_level], @options[:node_opts])
77
+ exec_node = DRbQS::Execution::ExecuteNode.new(@uri, @options[:log_prefix], @options[:log_level], @options[:node_opts])
78
78
  exec_node.execute(@process_num)
79
79
  exec_node.wait
80
80
  true
@@ -131,7 +131,7 @@ module DRbQS
131
131
  unless IO === @options[:log_file]
132
132
  node_log_file = FileName.create(@options[:log_file], :add => :always, :position => :middle, :delimiter => '', :format => "_node_%02d")
133
133
  end
134
- exec_node = DRbQS::ExecuteNode.new(uri, node_log_file, @options[:log_level])
134
+ exec_node = DRbQS::Execution::ExecuteNode.new(uri, node_log_file, @options[:log_level])
135
135
  exec_node.execute(@execute_node_number, NODE_INTERVAL_TIME)
136
136
  exec_node.wait
137
137
  end
@@ -165,7 +165,7 @@ module DRbQS
165
165
  io.print "\n" << mes
166
166
  end
167
167
  rescue => err
168
- new_err = err.class.new("Error in loading #{path}: #{err.to_s}")
168
+ new_err = err.class.new("Error in loading: #{err.to_s}")
169
169
  new_err.set_backtrace(err.backtrace)
170
170
  raise new_err
171
171
  end
@@ -0,0 +1,39 @@
1
+ module DRbQS
2
+ class Task
3
+ # The object of this class is mainly used in DRbQS::Task::Generator#set
4
+ # and calls Fiber.yield.
5
+ class Registrar
6
+ # @param [Hash] data Set instance variables from the hash.
7
+ def initialize(data)
8
+ data.each do |key, val|
9
+ instance_variable_set("@#{key.to_s}", val)
10
+ end
11
+ end
12
+
13
+ # Add tasks to server.
14
+ # @param [DRbQS::Task] arg Add an ojbect of DRbQS::Task.
15
+ # @param [Array] arg Add all elements of an array of objects of DRbQS::Task.
16
+ def add(arg)
17
+ case arg
18
+ when DRbQS::Task
19
+ Fiber.yield(arg)
20
+ when Array
21
+ arg.each { |t| Fiber.yield(t) }
22
+ else
23
+ raise ArgumentError, "An argument must be DRbQS::Task or an array of DRbQS::Task."
24
+ end
25
+ end
26
+
27
+ # Create an object of DRbQS::Task and add it.
28
+ # The arguments are same as {DRbQS::Task}.
29
+ def create_add(*args, &block)
30
+ add(DRbQS::Task.new(*args, &block))
31
+ end
32
+
33
+ # Wait finishes of all tasks in queue of a server.
34
+ def wait
35
+ Fiber.yield(:wait)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -1,100 +1,180 @@
1
- require 'drbqs/utility/transfer/file_transfer'
1
+ require 'drbqs/utility/transfer/transfer_file_list'
2
+ require 'drbqs/utility/transfer/transfer'
3
+ require 'drbqs/task/registrar'
2
4
  require 'drbqs/task/task_generator'
3
5
 
4
6
  module DRbQS
5
7
 
6
8
  # The tasks defined by this class are sent to nodes and
7
9
  # calculated by the nodes.
8
- # After the node returns the result of calculation to server,
9
- # the server execute the hook.
10
10
  class Task
11
+ attr_reader :obj
12
+ attr_reader :args
13
+ attr_reader :method_name
11
14
  attr_reader :hook
15
+ attr_accessor :note
12
16
 
13
- # Nodes execute obj.method_sym(*args).
14
- # Server executes &hook with a server instance and an object of result
15
- # after the server accepts the results from nodes.
16
- def initialize(obj, method_sym, args = [], &hook)
17
+ # Nodes calculate by obj.method_name(*opts[:args]) and send the result to their server.
18
+ # Then the server executes &hook with a server instance and an object of result.
19
+ # For the communication of a server and nodes we must convert obj to a string
20
+ # by Marshal.dump.
21
+ # If we set both opts[:hook] and &hook then &hook is prior to opts[:hook].
22
+ # @param [Object] obj An object that has a method "method_name"
23
+ # @param [Symbol] method_name Method name of calculation
24
+ # @param [Hash] opts The options of tasks.
25
+ # @option opts [Array] :args An array of arguments of method "method_name"
26
+ # @option opts [String] :note Note for a task
27
+ # @option opts [Symbol] :hook Method name for hook
28
+ # that takes two arguments server and the result object.
29
+ # @param [Proc] hook A server execute hook as a callback when the server receive the result
30
+ # @note Changes of obj on a node are not sent to a server.
31
+ # That is, opts[:hook] must not depend on changes of instance variables on a node.
32
+ def initialize(obj, method_name, opts = {}, &hook)
33
+ @obj = obj
17
34
  begin
18
- @marshal_obj = Marshal.dump(obj)
35
+ @marshal_obj = Marshal.dump(@obj)
19
36
  rescue
20
- raise "Can not dump an instance of #{obj.class}."
37
+ raise "Can not dump #{@obj.inspect}."
21
38
  end
22
- unless Array === args
39
+ @method_name = method_name.intern
40
+ @args = opts[:args] || []
41
+ unless Array === @args
23
42
  raise "Arguments of task must be an array."
24
43
  end
25
- @method_sym = method_sym.intern
26
- @args = args
27
- @hook = hook
44
+ begin
45
+ @marshal_args = Marshal.dump(@args)
46
+ rescue
47
+ raise "Can not dump #{@args.inspect}."
48
+ end
49
+ @note = opts[:note]
50
+ @hook = hook || opts[:hook]
28
51
  end
29
52
 
30
53
  def drb_args(task_id)
31
- [task_id, @marshal_obj, @method_sym, @args]
32
- end
33
-
34
- def same_target?(other)
35
- @marshal_obj == other.instance_variable_get(:@marshal_obj) &&
36
- @method_sym == other.instance_variable_get(:@method_sym) &&
37
- @args == other.instance_variable_get(:@args)
54
+ [task_id, @marshal_obj, @method_name, @marshal_args]
38
55
  end
39
56
 
40
57
  def exec_hook(server, result)
41
- if @hook
58
+ case @hook
59
+ when Proc
42
60
  @hook.call(server, result)
43
- true
61
+ when Symbol, String
62
+ @obj.__send__(@hook, server, result)
44
63
  else
45
- nil
64
+ return nil
46
65
  end
66
+ true
47
67
  end
48
68
 
49
- def self.execute_task(marshal_obj, method_sym, args)
50
- obj = Marshal.load(marshal_obj)
51
- obj.__send__(method_sym, *args)
52
- end
53
- end
54
-
55
- # Class to group a number of objects to process tasks.
56
- class TaskContainer
57
- def initialize(task_ary)
58
- @data = task_ary.map.with_index do |task, i|
59
- task.drb_args(i)
69
+ def ==(other)
70
+ if @marshal_obj == other.instance_variable_get(:@marshal_obj) &&
71
+ @method_name == other.instance_variable_get(:@method_name) &&
72
+ @marshal_args == other.instance_variable_get(:@marshal_args)
73
+ if Proc === @hook && Proc === other.hook
74
+ # Return false at this time.
75
+ false
76
+ else
77
+ @hook == other.hook
78
+ end
79
+ else
80
+ false
60
81
  end
61
82
  end
62
83
 
63
- def exec
64
- @data.map do |ary|
65
- DRbQS::Task.execute_task(*ary[1..-1])
66
- end
84
+ def self.call_task_method(obj, method_name, args)
85
+ obj.__send__(method_name, *args)
67
86
  end
68
87
 
69
- def data
70
- @data
88
+ def self.execute_task(marshal_obj, method_name, marshal_args)
89
+ self.call_task_method(Marshal.load(marshal_obj), method_name, Marshal.load(marshal_args))
71
90
  end
72
- protected :data
73
91
 
74
- def ==(other)
75
- other.data.each_with_index.all? do |ary, i|
76
- ary == @data[i]
92
+ # DRbQS::Task::TaskSet is a child class of DRbQS::Task and consists of group of a number of tasks.
93
+ # Objects of the class are generated when we set the option :collect to {DRbQS::Task::Generator#set}
94
+ # and therefore we are unaware of the objects of DRbQS::TaskSet in many cases.
95
+ class TaskSet < Task
96
+
97
+ class Container
98
+ def data
99
+ @data
100
+ end
101
+ protected :data
102
+
103
+ def ==(other)
104
+ other.data.each_with_index.all? do |ary, i|
105
+ ary == @data[i]
106
+ end
107
+ end
77
108
  end
78
- end
79
- end
80
109
 
81
- # Task to group a number of tasks,
82
- # which uses TaskContainer and manages hooks of the tasks.
83
- class TaskSet < Task
84
- def initialize(task_ary)
85
- @original_hook = task_ary.map do |task|
86
- task.hook
110
+ class ContainerTask < DRbQS::Task::TaskSet::Container
111
+ def initialize(task_ary)
112
+ @data = task_ary
113
+ end
114
+
115
+ def exec
116
+ @data.map do |task|
117
+ DRbQS::Task.call_task_method(task.obj, task.method_name, task.args)
118
+ end
119
+ end
120
+
121
+ def exec_all_hooks(srv, result)
122
+ result.each_with_index do |res, i|
123
+ @data[i].exec_hook(srv, res)
124
+ end
125
+ end
87
126
  end
88
- super(DRbQS::TaskContainer.new(task_ary), :exec) do |srv, result|
89
- result.each_with_index do |res, i|
90
- if hook = @original_hook[i]
91
- hook.call(srv, res)
127
+
128
+ # Class to group a number of objects to process tasks.
129
+ class ContainerWithoutHook < DRbQS::Task::TaskSet::Container
130
+ def initialize(task_ary)
131
+ @data = task_ary.map.with_index do |task, i|
132
+ task.drb_args(i)
133
+ end
134
+ end
135
+
136
+ def exec
137
+ @data.map do |ary|
138
+ DRbQS::Task.execute_task(*ary[1..-1])
92
139
  end
93
140
  end
94
141
  end
142
+
143
+ attr_reader :original_note
144
+
145
+ def initialize(task_ary)
146
+ @original_note = task_ary.map do |task|
147
+ task.note
148
+ end.compact!
149
+ if task_ary.all? { |task| !(Proc === task.hook) }
150
+ container = DRbQS::Task::TaskSet::ContainerTask.new(task_ary)
151
+ super(container, :exec, hook: :exec_all_hooks, note: note_string)
152
+ else
153
+ container = DRbQS::Task::TaskSet::ContainerWithoutHook.new(task_ary)
154
+ @original_task = task_ary
155
+ super(container, :exec, note: note_string) do |srv, result|
156
+ result.each_with_index do |res, i|
157
+ @original_task[i].exec_hook(srv, res)
158
+ end
159
+ end
160
+ end
161
+ end
162
+
163
+ def note_string
164
+ str = "TaskSet"
165
+ unless @original_note.empty?
166
+ case @original_note.size
167
+ when 1
168
+ str << ": " << @original_note[0]
169
+ when 2
170
+ str << ": " << @original_note.join(", ")
171
+ else
172
+ str << ": " << @original_note[0] << ' - ' << @original_note[-1]
173
+ end
174
+ end
175
+ str
176
+ end
177
+ private :note_string
95
178
  end
96
179
  end
97
-
98
180
  end
99
-
100
- require 'drbqs/task/command_task'