drbqs 0.0.5 → 0.0.6

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/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