opee 0.0.4 → 0.0.5

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.md CHANGED
@@ -16,16 +16,14 @@ Any comments, thoughts, or suggestions are welcome.
16
16
 
17
17
  ## <a name="release">Release Notes</a>
18
18
 
19
- ### Release 0.0.4
19
+ ### Release 0.0.5
20
20
 
21
- - Filling in the Log class and unit tests for it.
21
+ - Added tests for WorkQueue.
22
22
 
23
- - Added WorkQueue but have not tested it yet.
23
+ - Added busy method to Actor.
24
24
 
25
25
  # Plans and Notes
26
26
 
27
- - WorkQueue test tc_opee_workqueue
28
-
29
27
  - pick a problem to test against
30
28
  - file density distribution
31
29
  - find all files under a directory
@@ -36,18 +34,8 @@ Any comments, thoughts, or suggestions are welcome.
36
34
  - wait_finish
37
35
  - ask to print or write report
38
36
 
39
- - implement Actor max_queue_count limiter
40
- - test with actor that reports queue size and pauses for 0.1 seconds
41
- - try to send too many requests at it so it has to report busy
42
-
43
-
44
37
  - describe patterns for use
45
38
 
46
- - Is the notion of a job needed to follow processing of an initial input?
47
- - avoid using job for storing data though unless rules can be set up to isolate portions of the data to a specific processing path
48
- - need something for sharing large chunks of data
49
- - maybe just another actor
50
-
51
39
  ### License:
52
40
 
53
41
  Copyright (c) 2012, Peter Ohler
@@ -2,6 +2,7 @@
2
2
  module Opee
3
3
  end # Opee
4
4
 
5
+ require 'opee/errors'
5
6
  require 'opee/env'
6
7
  require 'opee/actor'
7
8
  require 'opee/log'
@@ -17,7 +17,9 @@ module Opee
17
17
  @step_thread = nil
18
18
  @ask_timeout = 0.0
19
19
  @max_queue_count = nil
20
+ @ask_thread = nil
20
21
  @state = RUNNING
22
+ @busy = false
21
23
  Env.add_actor(self)
22
24
  set_options(options)
23
25
  @loop = Thread.start(self) do |me|
@@ -33,6 +35,7 @@ module Opee
33
35
  @ask_mutex.synchronize {
34
36
  a = @queue.pop()
35
37
  }
38
+ @ask_thread.wakeup() unless @ask_thread.nil?
36
39
  elsif !@idle.empty?
37
40
  @idle_mutex.synchronize {
38
41
  a = @idle.pop()
@@ -41,7 +44,9 @@ module Opee
41
44
  Env.wake_finish()
42
45
  sleep(1.0)
43
46
  end
47
+ @busy = true
44
48
  send(a.op, *a.args) unless a.nil?
49
+ @busy = false
45
50
  if STEP == @state
46
51
  @step_thread.wakeup() unless @step_thread.nil?
47
52
  @state = STOPPED
@@ -57,17 +62,28 @@ module Opee
57
62
  end
58
63
 
59
64
  def set_options(options)
60
- #
65
+ @max_queue_count = options.fetch(:max_queue_count, @max_queue_count)
66
+ @ask_timeout = options.fetch(:ask_timeout, @ask_timeout)
61
67
  end
62
68
 
63
69
  # deep copy and freeze args if not already frozen or primitive types
64
- def ask(op, *args)
70
+ def timeout_ask(timeout, op, *args)
71
+ unless @max_queue_count.nil? || 0 == @max_queue_count || @queue.size() < @max_queue_count
72
+ @ask_thread = Thread.current
73
+ sleep(timeout) unless timeout.nil?
74
+ @ask_thread = nil
75
+ raise BusyError.new() unless @queue.size() < @max_queue_count
76
+ end
65
77
  @ask_mutex.synchronize {
66
78
  @queue.insert(0, Act.new(op, args))
67
79
  }
68
80
  @loop.wakeup() if RUNNING == @state
69
81
  end
70
82
 
83
+ def ask(op, *args)
84
+ timeout_ask(@ask_timeout, op, *args)
85
+ end
86
+
71
87
  def on_idle(op, *args)
72
88
  @idle_mutex.synchronize {
73
89
  @idle.insert(0, Act.new(op, args))
@@ -91,6 +107,18 @@ module Opee
91
107
  @queue.length + @priority.length + @idle.length
92
108
  end
93
109
 
110
+ def busy?
111
+ @busy || !@queue.empty? || !@priority.empty? || !@idle.empty?
112
+ end
113
+
114
+ def ask_timeout()
115
+ @ask_timeout
116
+ end
117
+
118
+ def max_queue_count
119
+ @max_queue_count
120
+ end
121
+
94
122
  def stop()
95
123
  @state = STOPPED
96
124
  end
@@ -125,6 +153,14 @@ module Opee
125
153
 
126
154
  private
127
155
 
156
+ def ask_timeout=(timeout)
157
+ @ask_timeout = timeout
158
+ end
159
+
160
+ def max_queue_count=(max)
161
+ @max_queue_count = max
162
+ end
163
+
128
164
  class Act
129
165
  attr_accessor :op
130
166
  attr_accessor :args
@@ -82,6 +82,11 @@ module Opee
82
82
  cnt
83
83
  end
84
84
 
85
+ def self.busy?
86
+ @@actors.each { |a| return true if a.busy? }
87
+ false
88
+ end
89
+
85
90
  def self.stop()
86
91
  @@actors.each { |a| a.stop() }
87
92
  end
@@ -94,7 +99,7 @@ module Opee
94
99
  def self.wait_finish()
95
100
  @@finish_thread = Thread.current
96
101
  @@actors.each { |a| a.wakeup() }
97
- while 0 < queue_count()
102
+ while busy?
98
103
  sleep(0.2) # actors should wake up when queue is empty
99
104
  end
100
105
  end
@@ -0,0 +1,15 @@
1
+
2
+ module Opee
3
+ class MissingOptionError < Exception
4
+ def initialize(option, msg)
5
+ super("option #{option} for #{msg} missing")
6
+ end
7
+ end # MissingOptionError
8
+
9
+ class BusyError < Exception
10
+ def initialize()
11
+ super("Busy, try again later")
12
+ end
13
+ end # BusyError
14
+
15
+ end # Opee
@@ -27,6 +27,7 @@ module Opee
27
27
  # picked up by the Actor method_missing() method.
28
28
 
29
29
  def set_options(options)
30
+ super(options)
30
31
  if !(filename = options[:filename]).nil?
31
32
  max_file_size = options.fetch(:max_file_size, options.fetch(:shift_size, 1048576))
32
33
  max_file_count = options.fetch(:max_file_count, options.fetch(:shift_age, 7))
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Opee
3
3
  # Current version of the module.
4
- VERSION = '0.0.4'
4
+ VERSION = '0.0.5'
5
5
  end
@@ -6,6 +6,9 @@ module Opee
6
6
  @workers = []
7
7
  @work_queue = []
8
8
  @method = nil
9
+ @max_job_count = 0
10
+ @job_timeout = 3.0
11
+ @add_thread = nil
9
12
  super(options)
10
13
  end
11
14
 
@@ -13,10 +16,36 @@ module Opee
13
16
  @work_queue.size
14
17
  end
15
18
 
19
+ def worker_count()
20
+ @workers.size
21
+ end
22
+
23
+ def busy?
24
+ !@work_queue.empty? || super
25
+ end
26
+
27
+ def ask(op, *args)
28
+ if :add == op && 0 < @max_job_count && (@work_queue.size() + @queue.size()) >= @max_job_count
29
+ unless 0.0 >= @job_timeout
30
+ @add_thread = Thread.current
31
+ give_up_at = Time.now + @job_timeout
32
+ until Time.now > give_up_at || (@work_queue.size() + @queue.size()) < @max_job_count
33
+ sleep(@job_timeout)
34
+ end
35
+ @add_thread = nil
36
+ end
37
+ raise BusyError.new() unless @work_queue.size() < @max_job_count
38
+ end
39
+ super
40
+ end
41
+
16
42
  private
17
43
 
18
44
  def set_options(options)
19
- raise "A method for for processing jobs must be specified" if (@method = options[:method]).nil?
45
+ super(options)
46
+ raise MissingOptionError.new(:method, "for processing jobs") if (@method = options[:method]).nil?
47
+ @max_job_count = options.fetch(:max_job_count, @max_job_count)
48
+ @job_timeout = options.fetch(:job_timeout, @job_timeout)
20
49
  end
21
50
 
22
51
  def add(job)
@@ -33,6 +62,7 @@ module Opee
33
62
  @workers.insert(0, worker) unless @workers.include?(worker)
34
63
  else
35
64
  job = @work_queue.pop()
65
+ @add_thread.wakeup() unless @add_thread.nil?
36
66
  worker.ask(@method, job)
37
67
  end
38
68
  end
@@ -12,6 +12,7 @@ class Relay < ::Opee::Actor
12
12
  end
13
13
 
14
14
  def set_options(options)
15
+ super(options)
15
16
  @buddy = options[:buddy]
16
17
  end
17
18
 
@@ -22,4 +23,10 @@ class Relay < ::Opee::Actor
22
23
  @buddy.ask(:relay, data) unless @buddy.nil?
23
24
  end
24
25
 
26
+ def slow(delay)
27
+ @last_data = [] unless @last_data.is_a?(Array)
28
+ @last_data << queue_count()
29
+ sleep(delay)
30
+ end
31
+
25
32
  end # Relay
@@ -81,4 +81,11 @@ class OpeeTest < ::Test::Unit::TestCase
81
81
  a.close()
82
82
  end
83
83
 
84
+ def test_opee_actor_max_queue_count
85
+ a = ::Relay.new(:max_queue_count => 4, :ask_timeout => 1.0)
86
+ 10.times { |i| a.ask(:slow, 0.1) }
87
+ ::Opee::Env.wait_close()
88
+ assert(4 > a.last_data.max)
89
+ end
90
+
84
91
  end # OpeeTest
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env ruby -wW2
2
+ # encoding: UTF-8
3
+
4
+ [ File.dirname(__FILE__),
5
+ File.join(File.dirname(__FILE__), "../lib")
6
+ ].each { |path| $: << path unless $:.include?(path) }
7
+
8
+ require 'test/unit'
9
+ require 'stringio'
10
+ require 'opee'
11
+
12
+ class Worker < ::Opee::Actor
13
+
14
+ def initialize(options={})
15
+ @collector = nil
16
+ @work_queue = nil
17
+ super(options)
18
+ @work_queue.ask(:ready, self)
19
+ end
20
+
21
+ def set_options(options)
22
+ super(options)
23
+ @collector = options[:collector]
24
+ @work_queue = options[:work_queue]
25
+ end
26
+
27
+ private
28
+
29
+ def do_it(num)
30
+ @collector.ask(:accept, num * 2)
31
+ @work_queue.ask(:ready, self)
32
+ end
33
+
34
+ def how_busy(num)
35
+ @collector.ask(:accept, @work_queue.work_queue_size())
36
+ sleep(0.1)
37
+ @work_queue.ask(:ready, self)
38
+ end
39
+
40
+ end # Worker
41
+
42
+ class Collector < ::Opee::Actor
43
+ attr_reader :results
44
+
45
+ def initialize(options={})
46
+ @results = []
47
+ super(options)
48
+ end
49
+
50
+ private
51
+
52
+ def accept(num)
53
+ @results << num
54
+ end
55
+
56
+ end # Collector
57
+
58
+ class OpeeTest < ::Test::Unit::TestCase
59
+
60
+ def test_opee_workqueue_basic
61
+ col = Collector.new()
62
+ wq = ::Opee::WorkQueue.new(:method => :do_it,
63
+ :max_job_count => 10,
64
+ :job_timeout => 1.0)
65
+ 4.times { |i| Worker.new(:collector => col, :work_queue => wq) }
66
+ 10.times { |i| wq.ask(:add, i) }
67
+ ::Opee::Env.wait_close()
68
+ assert_equal([0, 2, 4, 6, 8, 10, 12, 14, 16, 18], col.results.sort())
69
+ end
70
+
71
+ def test_opee_workqueue_busy
72
+ col = Collector.new()
73
+ wq = ::Opee::WorkQueue.new(:method => :how_busy,
74
+ :max_job_count => 4,
75
+ :job_timeout => 1.0)
76
+ 2.times { |i| Worker.new(:collector => col, :work_queue => wq) }
77
+ 20.times { |i| wq.ask(:add, i) }
78
+ ::Opee::Env.wait_close()
79
+ assert(4 >= col.results.max)
80
+ end
81
+
82
+ end # OpeeTest
@@ -14,3 +14,4 @@ end # OpeeTest
14
14
  require 'tc_opee_actor'
15
15
  require 'tc_opee_log'
16
16
  require 'tc_opee_env'
17
+ require 'tc_opee_workqueue'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opee
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-01 00:00:00.000000000 Z
12
+ date: 2012-05-03 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: ! 'An experimental Object-base Parallel Evaluation Environment. '
15
15
  email: peter@ohler.com
@@ -20,6 +20,7 @@ extra_rdoc_files:
20
20
  files:
21
21
  - lib/opee/actor.rb
22
22
  - lib/opee/env.rb
23
+ - lib/opee/errors.rb
23
24
  - lib/opee/log.rb
24
25
  - lib/opee/version.rb
25
26
  - lib/opee/workqueue.rb
@@ -28,6 +29,7 @@ files:
28
29
  - test/tc_opee_actor.rb
29
30
  - test/tc_opee_env.rb
30
31
  - test/tc_opee_log.rb
32
+ - test/tc_opee_workqueue.rb
31
33
  - test/tests.rb
32
34
  - test/ts_opee.rb
33
35
  - LICENSE
@@ -54,9 +56,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
54
56
  version: '0'
55
57
  requirements: []
56
58
  rubyforge_project: opee
57
- rubygems_version: 1.8.21
59
+ rubygems_version: 1.8.23
58
60
  signing_key:
59
61
  specification_version: 3
60
62
  summary: An experimental Object-base Parallel Evaluation Environment.
61
63
  test_files: []
62
- has_rdoc: true