drbqs 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -30,7 +30,7 @@ We make server.rb as the following.
30
30
 
31
31
  require_relative 'sum.rb'
32
32
 
33
- DRbQS.define_server do |server|
33
+ DRbQS.define_server do |server, argv, opts|
34
34
  10.step(100, 10) do |i|
35
35
  task = DRbQS::Task.new(Sum.new(i - 10, i), :exec)
36
36
  server.queue.add(task)
@@ -47,13 +47,15 @@ In terminal, we load server.rb and execute server of drbqs.
47
47
 
48
48
  === Start node and connect server
49
49
 
50
- We type in terminal.
50
+ Because nodes needs class Sum,
51
+ the nodes load sum.rb when they starts.
52
+ Then, we type in terminal.
51
53
 
52
- drbqs-node druby://localhost:13500/
54
+ drbqs-node druby://localhost:13500/ -l sum.rb
53
55
 
54
56
  To use two cpu cores we execute two processes by the following.
55
57
 
56
- drbqs-node 2 druby://localhost:13500/
58
+ drbqs-node 2 druby://localhost:13500/ -l sum.rb
57
59
 
58
60
  Then, if it succeeds, the calculation starts.
59
61
  If it finishes, the server and node ends.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.5
1
+ 0.0.6
data/drbqs.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{drbqs}
8
- s.version = "0.0.5"
8
+ s.version = "0.0.6"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Takayuki YAMAGUCHI"]
12
- s.date = %q{2011-03-05}
12
+ s.date = %q{2011-03-08}
13
13
  s.description = %q{Task queuing system over network that is implemented by dRuby.}
14
14
  s.email = %q{d@ytak.info}
15
15
  s.executables = ["drbqs-manage", "drbqs-node", "drbqs-server"]
@@ -41,29 +41,55 @@ Gem::Specification.new do |s|
41
41
  "lib/drbqs/connection.rb",
42
42
  "lib/drbqs/manage.rb",
43
43
  "lib/drbqs/message.rb",
44
+ "lib/drbqs/node_list.rb",
44
45
  "lib/drbqs/queue.rb",
45
46
  "lib/drbqs/server.rb",
46
47
  "lib/drbqs/server_define.rb",
48
+ "lib/drbqs/task.rb",
47
49
  "lib/drbqs/task_client.rb",
50
+ "lib/drbqs/task_generator.rb",
48
51
  "spec/acl_file_spec.rb",
52
+ "spec/connection_spec.rb",
49
53
  "spec/data/acl.txt",
50
- "spec/drbqs_spec.rb",
54
+ "spec/manage_spec.rb",
55
+ "spec/message_spec.rb",
56
+ "spec/node_list_spec.rb",
57
+ "spec/queue_spec.rb",
58
+ "spec/server_define_spec.rb",
51
59
  "spec/server_spec.rb",
52
- "spec/spec_helper.rb"
60
+ "spec/spec_helper.rb",
61
+ "spec/task_client_spec.rb",
62
+ "spec/task_generator_spec.rb",
63
+ "spec/task_spec.rb",
64
+ "spec/test/test1.rb",
65
+ "spec/test1_spec.rb",
66
+ "spec/test2_spec.rb"
53
67
  ]
54
68
  s.homepage = %q{http://github.com/ytaka/drbqs}
55
69
  s.licenses = ["GPL3"]
56
70
  s.require_paths = ["lib"]
57
- s.rubygems_version = %q{1.5.2}
71
+ s.rubygems_version = %q{1.3.7}
58
72
  s.summary = %q{dRuby Queueing System}
59
73
  s.test_files = [
60
74
  "spec/acl_file_spec.rb",
61
- "spec/drbqs_spec.rb",
75
+ "spec/connection_spec.rb",
76
+ "spec/manage_spec.rb",
77
+ "spec/message_spec.rb",
78
+ "spec/node_list_spec.rb",
79
+ "spec/queue_spec.rb",
80
+ "spec/server_define_spec.rb",
62
81
  "spec/server_spec.rb",
63
- "spec/spec_helper.rb"
82
+ "spec/spec_helper.rb",
83
+ "spec/task_client_spec.rb",
84
+ "spec/task_generator_spec.rb",
85
+ "spec/task_spec.rb",
86
+ "spec/test/test1.rb",
87
+ "spec/test1_spec.rb",
88
+ "spec/test2_spec.rb"
64
89
  ]
65
90
 
66
91
  if s.respond_to? :specification_version then
92
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
67
93
  s.specification_version = 3
68
94
 
69
95
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
data/lib/drbqs/client.rb CHANGED
@@ -4,12 +4,18 @@ require 'drbqs/task_client'
4
4
  module DRbQS
5
5
 
6
6
  class Client
7
+
8
+ WAIT_NEW_TASK = 1
9
+ OUTPUT_NOT_SEND_RESULT = 'not_send_result'
10
+
11
+ # :continue
7
12
  def initialize(access_uri, opts = {})
8
13
  @access_uri = access_uri
9
14
  @logger = Logger.new(opts[:log_file] || 'drbqs_client.log')
10
15
  @logger.level = opts[:log_level] || Logger::ERROR
11
16
  @connection = nil
12
17
  @task_client = nil
18
+ @process_continue = opts[:continue]
13
19
  end
14
20
 
15
21
  def execute_task(marshal_obj, method_sym, args)
@@ -28,21 +34,55 @@ module DRbQS
28
34
  end
29
35
  end
30
36
 
31
- WAIT_NEW_TASK = 1
37
+ def dump_not_send_result_to_file
38
+ if data = @task_client.dump_result_queue
39
+ path = OUTPUT_NOT_SEND_RESULT + Time.now.to_i.to_s + '.dat'
40
+ open(path, 'w') { |f| f.print data }
41
+ end
42
+ end
43
+ private :dump_not_send_result_to_file
44
+
45
+ def output_error(err)
46
+ if @logger
47
+ @logger.error("Raise error in calculating thread: #{err.to_s}") { "\n" + err.backtrace.join("\n") }
48
+ end
49
+ end
50
+ private :output_error
51
+
52
+ def process_exit
53
+ dump_not_send_result_to_file
54
+ unless @process_continue
55
+ Kernel.exit
56
+ end
57
+ end
58
+ private :process_exit
32
59
 
33
- def calculate
60
+ def calculate(opts = {})
34
61
  cn = Thread.new do
35
- loop do
36
- @task_client.add_new_task
37
- @connection.respond_alive_signal
38
- @task_client.send_result
39
- sleep(WAIT_NEW_TASK)
62
+ begin
63
+ loop do
64
+ @task_client.add_new_task
65
+ if @connection.respond_alive_signal == :exit
66
+ break
67
+ end
68
+ @task_client.send_result
69
+ sleep(WAIT_NEW_TASK)
70
+ end
71
+ rescue => err
72
+ output_error(err)
73
+ ensure
74
+ process_exit
40
75
  end
41
76
  end
42
77
  exec = Thread.new do
43
- loop do
44
- marshal_obj, method_sym, args = @task_client.get
45
- @task_client.transmit(execute_task(marshal_obj, method_sym, args))
78
+ begin
79
+ loop do
80
+ marshal_obj, method_sym, args = @task_client.dequeue_task
81
+ @task_client.queue_result(execute_task(marshal_obj, method_sym, args))
82
+ end
83
+ rescue => err
84
+ output_error(err)
85
+ process_exit
46
86
  end
47
87
  end
48
88
  cn.join
@@ -6,21 +6,23 @@ module DRbQS
6
6
  def initialize(message, logger = nil)
7
7
  @message = message
8
8
  @logger = logger
9
- @id = nil
9
+ @id_number = nil
10
+ @id_string = create_id_string
10
11
  end
11
12
 
12
13
  def create_id_string
13
14
  t = Time.now
14
- sprintf("#{Socket.gethostname} %d%d%d", t.to_i, t.usec, rand(1000))
15
+ sprintf("%d%d%d:#{Socket.gethostname}", t.to_i, t.usec, rand(1000))
15
16
  end
16
17
  private :create_id_string
17
18
 
18
19
  def get_id
19
- s = create_id_string
20
- @message.write([:connect, s])
21
- @id = @message.take([s, Fixnum])[1]
22
- @logger.info("Get node id: #{@id}") if @logger
23
- @id
20
+ unless @id_number
21
+ @message.write([:connect, @id_string])
22
+ @id_number = @message.take([@id_string, Fixnum])[1]
23
+ @logger.info("Get node id: #{@id_number}") if @logger
24
+ end
25
+ @id_number
24
26
  end
25
27
 
26
28
  def get_initialization
@@ -34,14 +36,14 @@ module DRbQS
34
36
 
35
37
  def respond_alive_signal
36
38
  begin
37
- node_id, sym = @message.take([@id, Symbol], 0)
39
+ node_id, sym = @message.take([@id_number, Symbol], 0)
38
40
  case sym
39
41
  when :alive_p
40
- @message.write([:alive, @id])
41
- @logger.info("Send alive signal of node id #{@id}") if @logger
42
+ @message.write([:alive, @id_number])
43
+ @logger.info("Send alive signal of node id #{@id_number}") if @logger
42
44
  when :exit
43
45
  @logger.info("Get exit signal") if @logger
44
- Kernel.exit
46
+ return :exit
45
47
  end
46
48
  rescue Rinda::RequestExpiredError
47
49
  end
data/lib/drbqs/message.rb CHANGED
@@ -1,43 +1,6 @@
1
- module DRbQS
2
- class NodeList
3
- def initialize
4
- @id = 0
5
- @list = {}
6
- @check = []
7
- end
8
-
9
- def get_new_id(id_str)
10
- @id += 1
11
- @list[@id] = id_str
12
- @id
13
- end
14
-
15
- def each(&block)
16
- @list.each(&block)
17
- end
18
-
19
- def set_check_connection
20
- @check = @list.keys
21
- end
22
-
23
- def delete_not_alive
24
- @check.each do |id|
25
- @list.delete(id)
26
- end
27
- deleted = @check
28
- @check = []
29
- deleted
30
- end
31
-
32
- def set_alive(id)
33
- @check.delete(id)
34
- end
35
-
36
- def empty?
37
- @list.size == 0
38
- end
39
- end
1
+ require 'drbqs/node_list'
40
2
 
3
+ module DRbQS
41
4
  class MessageServer
42
5
  def initialize(message, logger = nil)
43
6
  @message = message
@@ -50,6 +13,7 @@ module DRbQS
50
13
  mes = @message.take([Symbol, nil], 0)
51
14
  manage_message(*mes)
52
15
  rescue Rinda::RequestExpiredError
16
+ nil
53
17
  end
54
18
  end
55
19
 
@@ -66,7 +30,8 @@ module DRbQS
66
30
  @logger.info("Get exit message from #{arg.to_s}") if @logger
67
31
  return :exit_server
68
32
  else
69
- puts "Invalid message from #{arg.to_s}"
33
+ @logger.error("Invalid message from #{arg.to_s}") if @logger
34
+ return nil
70
35
  end
71
36
  end
72
37
  private :manage_message
@@ -0,0 +1,41 @@
1
+ module DRbQS
2
+ class NodeList
3
+ def initialize
4
+ @id = 0
5
+ @list = {}
6
+ @check = []
7
+ end
8
+
9
+ def get_new_id(id_str)
10
+ @id += 1
11
+ @list[@id] = id_str
12
+ @id
13
+ end
14
+
15
+ def each(&block)
16
+ @list.each(&block)
17
+ end
18
+
19
+ def set_check_connection
20
+ @check = @list.keys
21
+ end
22
+
23
+ def delete_not_alive
24
+ @check.each do |id|
25
+ @list.delete(id)
26
+ end
27
+ deleted = @check
28
+ @check = []
29
+ deleted
30
+ end
31
+
32
+ def set_alive(id)
33
+ @check.delete(id)
34
+ end
35
+
36
+ def empty?
37
+ @list.size == 0
38
+ end
39
+ end
40
+
41
+ end
data/lib/drbqs/queue.rb CHANGED
@@ -1,25 +1,4 @@
1
1
  module DRbQS
2
- class Task
3
- attr_reader :hook
4
-
5
- def initialize(obj, method_sym, args = [], &hook)
6
- begin
7
- @marshal_obj = Marshal.dump(obj)
8
- rescue
9
- raise "Can not dump an instance of #{obj.class}."
10
- end
11
- unless Array === args
12
- raise "Arguments of task must be an array."
13
- end
14
- @method_sym = method_sym.intern
15
- @args = args
16
- @hook = hook
17
- end
18
-
19
- def drb_args(task_id)
20
- [task_id, @marshal_obj, @method_sym, @args]
21
- end
22
- end
23
2
 
24
3
  class QueueServer
25
4
 
@@ -38,11 +17,13 @@ module DRbQS
38
17
  private :queue_task
39
18
 
40
19
  # &hook take two arguments: a QueueServer object and a result of task.
20
+ # Return task ID (for debug).
41
21
  def add(task)
42
22
  @task_id += 1
43
23
  @logger.info("New task: #{@task_id}") if @logger
44
24
  @cache[@task_id] = task
45
25
  queue_task(@task_id)
26
+ @task_id
46
27
  end
47
28
 
48
29
  def get_accept_signal
data/lib/drbqs/server.rb CHANGED
@@ -18,6 +18,8 @@ module DRbQS
18
18
  end
19
19
  end
20
20
 
21
+ # When we set both empty_queue_hook and task_generator,
22
+ # empty_queue_hook is prior to task_generator.
21
23
  class Server
22
24
  attr_reader :queue
23
25
 
@@ -43,6 +45,7 @@ module DRbQS
43
45
  @message = MessageServer.new(@ts[:message], @logger)
44
46
  @queue= QueueServer.new(@ts[:queue], @ts[:result], @logger)
45
47
  @check_alive = CheckAlive.new(opts[:check_alive])
48
+ @task_generator = []
46
49
  @empty_queue_hook = nil
47
50
  end
48
51
 
@@ -74,10 +77,31 @@ module DRbQS
74
77
  end
75
78
  private :check_connection
76
79
 
80
+ def set_task_generator(task_generator)
81
+ @task_generator << task_generator
82
+ end
83
+
84
+ def add_tasks_from_generator
85
+ if @task_generator.size > 0 && @queue.empty?
86
+ if tasks = @task_generator[0].new_tasks
87
+ tasks.each { |t| @queue.add(t) }
88
+ @logger.debug("Generator add #{tasks.size} tasks.") if @logger
89
+ else
90
+ @task_generator.delete_at(0)
91
+ @logger.info("Generator creates all tasks and then has been deleted.") if @logger
92
+ if @task_generator.size > 0
93
+ add_tasks_from_generator
94
+ end
95
+ end
96
+ end
97
+ end
98
+ private :add_tasks_from_generator
99
+
77
100
  def set_initialization_task(task)
78
101
  @message.set_initialization(task)
79
102
  end
80
103
 
104
+ # &block takes self as an argument.
81
105
  def set_empty_queue_hook(&block)
82
106
  if block_given?
83
107
  @empty_queue_hook = block
@@ -86,6 +110,7 @@ module DRbQS
86
110
  end
87
111
  end
88
112
 
113
+ # &block takes self as an argument.
89
114
  def set_finish_hook(&block)
90
115
  if block_given?
91
116
  @finish_hook = block
@@ -99,6 +124,7 @@ module DRbQS
99
124
  @logger.info("Execute empty queue hook.") if @logger
100
125
  @empty_queue_hook.call(self)
101
126
  end
127
+ add_tasks_from_generator
102
128
  if @finish_hook && @queue.finished?
103
129
  @logger.info("Execute finish hook.") if @logger
104
130
  @finish_hook.call(self)
@@ -132,6 +158,7 @@ module DRbQS
132
158
  private :check_message
133
159
 
134
160
  def wait
161
+ @task_generator.each { |tgen| tgen.init }
135
162
  loop do
136
163
  check_message
137
164
  check_connection
@@ -44,7 +44,6 @@ HELP
44
44
  end
45
45
  server = DRbQS::Server.new(options)
46
46
  @server_create.call(server, @argv, @opts)
47
- # @server_create.call(server)
48
47
  server.set_signal_trap
49
48
  server.start
50
49
  server.wait
data/lib/drbqs/task.rb ADDED
@@ -0,0 +1,38 @@
1
+ module DRbQS
2
+
3
+ # The tasks defined by this class are sent to nodes and
4
+ # calculated by the nodes.
5
+ # After the node returns the result of calculation to server,
6
+ # the server execute the hook.
7
+ class Task
8
+ attr_reader :hook
9
+
10
+ # Nodes execute obj.method_sym(*args).
11
+ # Server executes &hook with a server instance and an array of result
12
+ # after the server accepts the results from nodes.
13
+ def initialize(obj, method_sym, args = [], &hook)
14
+ begin
15
+ @marshal_obj = Marshal.dump(obj)
16
+ rescue
17
+ raise "Can not dump an instance of #{obj.class}."
18
+ end
19
+ unless Array === args
20
+ raise "Arguments of task must be an array."
21
+ end
22
+ @method_sym = method_sym.intern
23
+ @args = args
24
+ @hook = hook
25
+ end
26
+
27
+ def drb_args(task_id)
28
+ [task_id, @marshal_obj, @method_sym, @args]
29
+ end
30
+
31
+ def same_target?(other)
32
+ @marshal_obj == other.instance_variable_get(:@marshal_obj) &&
33
+ @method_sym == other.instance_variable_get(:@method_sym) &&
34
+ @args == other.instance_variable_get(:@args)
35
+ end
36
+ end
37
+
38
+ end
@@ -1,5 +1,7 @@
1
1
  module DRbQS
2
2
  class TaskClient
3
+ attr_reader :node_id, :calculating_task
4
+
3
5
  def initialize(node_id, queue, result, logger = nil)
4
6
  @node_id = node_id
5
7
  @queue = queue
@@ -10,12 +12,33 @@ module DRbQS
10
12
  @logger = logger
11
13
  end
12
14
 
15
+ def task_empty?
16
+ @task_queue.empty?
17
+ end
18
+
19
+ def result_empty?
20
+ @result_queue.empty?
21
+ end
22
+
23
+ def dequeue_result
24
+ @result_queue.deq
25
+ end
26
+ private :dequeue_result
27
+
28
+ def queue_task(task_id, ary)
29
+ @task_queue.enq(ary)
30
+ @calculating_task = task_id
31
+ end
32
+
33
+ def dequeue_task
34
+ @task_queue.deq
35
+ end
36
+
13
37
  def add_new_task
14
38
  unless @calculating_task
15
39
  begin
16
40
  task_id, obj, method_sym, args = @queue.take([Fixnum, nil, Symbol, nil], 0)
17
- @calculating_task = task_id
18
- @task_queue.enq([obj, method_sym, args])
41
+ queue_task(task_id, [obj, method_sym, args])
19
42
  @logger.info("Send accept signal: node #{@node_id} caluclating #{@calculating_task}") if @logger
20
43
  @result.write([:accept, @calculating_task, @node_id])
21
44
  rescue Rinda::RequestExpiredError
@@ -24,22 +47,29 @@ module DRbQS
24
47
  end
25
48
 
26
49
  def send_result
27
- if @result_queue.size > 0
28
- result = @result_queue.deq
50
+ if !result_empty?
51
+ result = dequeue_result
29
52
  @logger.info("Send result: #{@calculating_task}") { result.inspect } if @logger
30
53
  @result.write([:result, @calculating_task, result])
31
54
  @calculating_task = nil
32
55
  end
33
56
  end
34
57
 
35
- def get
36
- @task_queue.deq
37
- end
38
-
39
- def transmit(result)
58
+ def queue_result(result)
40
59
  @result_queue.enq(result)
41
60
  end
42
61
 
62
+ def dump_result_queue
63
+ results = []
64
+ while !result_empty?
65
+ results << dequeue_result
66
+ end
67
+ if results.size > 0
68
+ Marshal.dump(results)
69
+ else
70
+ nil
71
+ end
72
+ end
43
73
  end
44
74
 
45
75
  end
@@ -0,0 +1,74 @@
1
+ module DRbQS
2
+ class TaskGenerator
3
+ def initialize(data = {})
4
+ data.each do |key, val|
5
+ instance_variable_set("@#{key.to_s}", val)
6
+ end
7
+ @__fiber__ = nil
8
+ @__iterate__ = nil
9
+ @__fiber_init__ = nil
10
+ end
11
+
12
+ def have_next?
13
+ !!@__fiber__
14
+ end
15
+
16
+ def create_add_task(*args, &block)
17
+ Fiber.yield(DRbQS::Task.new(*args, &block))
18
+ end
19
+
20
+ def set(iterate = 1, &block)
21
+ @__iterate__ = iterate
22
+ @__fiber_init__ = lambda do
23
+ @__fiber__ = Fiber.new do
24
+ instance_eval(&block)
25
+ nil
26
+ end
27
+ end
28
+ end
29
+
30
+ def init
31
+ @__fiber_init__.call
32
+ end
33
+
34
+ # Return an array of new tasks.
35
+ def new_tasks
36
+ if @__fiber__
37
+ task_ary = []
38
+ @__iterate__.times do |i|
39
+ if task_new = @__fiber__.resume
40
+ case task_new
41
+ when DRbQS::Task
42
+ task_ary << task_new
43
+ when Array
44
+ task_ary.concat(task_new)
45
+ else
46
+ raise "Invalid type of new task."
47
+ end
48
+ else
49
+ @__fiber__ = nil
50
+ break
51
+ end
52
+ end
53
+ if task_ary.size > 0
54
+ return task_ary
55
+ end
56
+ end
57
+ nil
58
+ end
59
+
60
+ # Create all tasks for test and return true if all tasks created properly.
61
+ def debug_all_tasks(limit = nil)
62
+ i = 0
63
+ while ary = new_tasks
64
+ ary.each? do |t|
65
+ unless DRbQS::TaskGenerator === t
66
+ raise "Invalid task by #{i}th generation: #{t.inspect}"
67
+ end
68
+ end
69
+ i += 1
70
+ end
71
+ true
72
+ end
73
+ end
74
+ end
data/lib/drbqs.rb CHANGED
@@ -11,6 +11,8 @@ require 'drbqs/server_define'
11
11
  module DRbQS
12
12
  autoload :Server, 'drbqs/server'
13
13
  autoload :Client, 'drbqs/client'
14
+ autoload :Task, 'drbqs/task'
15
+ autoload :TaskGenerator, 'drbqs/task_generator'
14
16
  autoload :Manage, 'drbqs/manage'
15
17
 
16
18
  ROOT_DEFAULT_PORT = 13500