drbqs 0.0.15 → 0.0.16

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