opee 0.0.1 → 0.0.2

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
@@ -7,16 +7,47 @@ push the flow forward, never returning values when using the ask()
7
7
  method. Other methods return immediately but they should never modify the data
8
8
  portions of the Actors. They can be used to modify the control of the Actor.
9
9
 
10
- # plans
10
+ Once a reasonable API has been established a high performance C extension will
11
+ be written to improve performance.
11
12
 
12
- - create an error handler that prints or logs rescued exceptions (::Opee::Log class)
13
+ This is no where close to being ready for prime time.
14
+
15
+ # Plans and Notes
16
+
17
+ - Env
18
+ - test
19
+ - create and close actors and make sure each_actor changes
20
+ - test logger return Log instance
21
+ - queue_count
22
+ - start/stop
23
+ - wait_close
24
+
25
+ - Log
26
+ - allow forward attribute to be set that forwards messages to another Actor
27
+ - turn output off (useful when there is a forward actor)
28
+ - test
29
+ - set formatter and stringio and test env methods
30
+ - test forwarding
31
+
32
+ - Actor
33
+
34
+ - implement a design pattern for a shared work queue
35
+ - queue is an actor
36
+ - place items on queue either as normal ask sequence or special mutex protected queue
37
+ - if normal then wait for a request for a job and send a job to requestor
13
38
 
14
39
  - pick a problem to test against
40
+ - checkers
41
+ - process some kind of file
42
+ - process random numbers to produce something
43
+ - life
15
44
 
16
45
  - describe patterns for use
17
46
 
18
47
  - Is the notion of a job needed to follow processing of an initial input?
19
48
  - avoid using job for storing data though unless rules can be set up to isolate portions of the data to a specific processing path
49
+ - need something for sharing large chunks of data
50
+ - maybe just another actor
20
51
 
21
52
  ### License:
22
53
 
@@ -2,4 +2,6 @@
2
2
  module Opee
3
3
  end # Opee
4
4
 
5
+ require 'opee/env'
5
6
  require 'opee/actor'
7
+ require 'opee/log'
@@ -2,28 +2,56 @@
2
2
  module Opee
3
3
 
4
4
  class Actor
5
+ STOPPED = 0
6
+ RUNNING = 1
7
+ CLOSING = 2
8
+ STEP = 3
5
9
 
6
10
  def initialize(options={})
7
11
  @queue = []
12
+ @idle = []
13
+ @priority = []
8
14
  @ask_mutex = Mutex.new()
15
+ @priority_mutex = Mutex.new()
16
+ @idle_mutex = Mutex.new()
17
+ @step_thread = nil
9
18
  @ask_timeout = 0.0
10
19
  @max_queue_count = nil
11
- @running = true
20
+ @state = RUNNING
21
+ Env.add_actor(self)
12
22
  set_options(options)
13
23
  @loop = Thread.start(self) do |me|
14
- begin
15
- sleep(1.0) if @queue.empty?
16
- unless @queue.empty?
17
- a = nil
18
- @ask_mutex.synchronize {
19
- a = @queue.pop()
20
- }
21
- send(a.op, *a.args)
24
+ while CLOSING != @state
25
+ begin
26
+ if RUNNING == @state || STEP == @state
27
+ a = nil
28
+ if !@priority.empty?
29
+ @priority_mutex.synchronize {
30
+ a = @priority.pop()
31
+ }
32
+ elsif !@queue.empty?
33
+ @ask_mutex.synchronize {
34
+ a = @queue.pop()
35
+ }
36
+ elsif !@idle.empty?
37
+ @idle_mutex.synchronize {
38
+ a = @idle.pop()
39
+ }
40
+ else
41
+ Env.wake_finish()
42
+ sleep(1.0)
43
+ end
44
+ send(a.op, *a.args) unless a.nil?
45
+ if STEP == @state
46
+ @step_thread.wakeup() unless @step_thread.nil?
47
+ @state = STOPPED
48
+ end
49
+ elsif STOPPED == @state
50
+ sleep(1.0)
51
+ end
52
+ rescue Exception => e
53
+ Env.log_rescue(e)
22
54
  end
23
- rescue Exception => e
24
- # TBD handle errors by passing them to a error handler
25
- puts "*** #{e.class}: #{e.message}"
26
- e.backtrace.each { |line| puts " " + line }
27
55
  end
28
56
  end
29
57
  end
@@ -37,22 +65,59 @@ module Opee
37
65
  @ask_mutex.synchronize {
38
66
  @queue << Act.new(op, args)
39
67
  }
40
- @loop.wakeup() if @running
68
+ @loop.wakeup() if RUNNING == @state
69
+ end
70
+
71
+ def on_idle(op, *args)
72
+ @idle_mutex.synchronize {
73
+ @idle << Act.new(op, args)
74
+ }
75
+ @loop.wakeup() if RUNNING == @state
76
+ end
77
+
78
+ def priority_ask(op, *args)
79
+ @priority_mutex.synchronize {
80
+ @priority << Act.new(op, args)
81
+ }
82
+ @loop.wakeup() if RUNNING == @state
83
+ end
84
+
85
+ def method_missing(m, *args, &blk)
86
+ ask(m, *args)
41
87
  end
42
88
 
43
89
  def queue_count()
44
- @queue.length
90
+ @queue.length + @priority.length + @idle.length
45
91
  end
46
92
 
47
93
  def stop()
48
- @running = false
94
+ @state = STOPPED
95
+ end
96
+
97
+ def step(max_wait=5)
98
+ @state = STEP
99
+ @step_thread = Thread.current
100
+ @loop.wakeup()
101
+ sleep(max_wait)
49
102
  end
50
103
 
51
104
  def start()
52
- @running = true
105
+ @state = RUNNING
53
106
  @loop.wakeup()
54
107
  end
55
108
 
109
+ def close()
110
+ @state = CLOSING
111
+ begin
112
+ # if the loop has already exited this will raise an Exception that can be ignored
113
+ @loop.wakeup()
114
+ rescue
115
+ # ignore
116
+ end
117
+ Env.remove_actor(self)
118
+ @loop.join()
119
+ end
120
+
56
121
  private
57
122
 
58
123
  class Act
@@ -0,0 +1,88 @@
1
+
2
+ module Opee
3
+ class Env
4
+
5
+ @@actors = []
6
+ @@log = nil
7
+ @@finish_thread = nil
8
+
9
+ def self.add_actor(actor)
10
+ @@actors << actor
11
+ end
12
+
13
+ def self.remove_actor(actor)
14
+ @@actors.delete(actor)
15
+ end
16
+
17
+ def self.each_actor(&blk)
18
+ @@actors.each { |a| blk.yield(a) }
19
+ end
20
+
21
+ def self.shutdown()
22
+ until @@actors.empty?
23
+ a = @@actors.pop()
24
+ a.close()
25
+ end
26
+ end
27
+
28
+ def self.log(severity, message)
29
+ @@log = Log.new() if @@log.nil?
30
+ @@log.ask(:log, severity, message)
31
+ end
32
+
33
+ def self.log_rescue(ex)
34
+ @@log = Log.new() if @@log.nil?
35
+ return unless Logger::Severity::ERROR >= @@log.level
36
+ msg = "#{ex.class}: #{ex.message}"
37
+ if Logger::Severity::WARN >= @@log.level
38
+ ex.backtrace.each { |line| msg << " #{line}\n" }
39
+ end
40
+ @@log.ask(:log, Logger::Severity::ERROR, msg)
41
+ end
42
+
43
+ def self.logger()
44
+ @@log = Log.new() if @@log.nil?
45
+ @@log
46
+ end
47
+
48
+ def self.queue_count()
49
+ cnt = 0
50
+ @@actors.each { |a| cnt += a.queue_count() }
51
+ cnt
52
+ end
53
+
54
+ def self.stop()
55
+ @@actors.each { |a| a.stop() }
56
+ end
57
+
58
+ def self.start()
59
+ @@finish_thread = nil
60
+ @@actors.each { |a| a.start() }
61
+ end
62
+
63
+ def self.wait_finish()
64
+ @@finish_thread = Thread.current
65
+ while 0 < queue_count()
66
+ sleep(0.2) # actors should wake up when queue is empty
67
+ end
68
+ end
69
+
70
+ def self.wake_finish()
71
+ @@finish_thread.wakeup() unless @@finish_thread.nil?
72
+ end
73
+
74
+ def self.wait_close()
75
+ while 0 < queue_count()
76
+ wait_finish()
77
+ stop()
78
+ break if 0 == queue_count()
79
+ start()
80
+ end
81
+ until @@actors.empty?
82
+ a = @@actors.pop()
83
+ a.close()
84
+ end
85
+ end
86
+
87
+ end # Env
88
+ end # Opee
@@ -0,0 +1,43 @@
1
+
2
+ require 'logger'
3
+
4
+ module Opee
5
+ class Log < Actor
6
+
7
+ def initialize(options={})
8
+ super(options)
9
+ end
10
+
11
+ private
12
+ # use ask() to invoke private methods
13
+
14
+ def set_options(options)
15
+ @logger = Logger.new(STDOUT)
16
+ severity = options[:severity] if options.has_key?(:severity)
17
+
18
+ # TBD options for setting a file, severity, max_file_size, max_file_count, formatter
19
+ end
20
+
21
+ def severity=(level)
22
+ if level.is_a?(String)
23
+ severity = {
24
+ 'FATAL' => Logger::Severity::FATAL,
25
+ 'ERROR' => Logger::Severity::ERROR,
26
+ 'WARN' => Logger::Severity::WARN,
27
+ 'INFO' => Logger::Severity::INFO,
28
+ 'DEBUG' => Logger::Severity::DEBUG
29
+ }[level]
30
+ raise "#{level} is not a severity" if severity.nil?
31
+ level = severity
32
+ elsif level < Logger::Severity::DEBUG || Logger::Severity::FATAL < level
33
+ raise "#{level} is not a severity"
34
+ end
35
+ @logger.level = level
36
+ end
37
+
38
+ def log(severity, message)
39
+ @logger.add(severity, message)
40
+ end
41
+
42
+ end # Log
43
+ end # Opee
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Opee
3
3
  # Current version of the module.
4
- VERSION = '0.0.1'
4
+ VERSION = '0.0.2'
5
5
  end
@@ -0,0 +1,20 @@
1
+
2
+ require 'opee'
3
+
4
+ class Relay < ::Opee::Actor
5
+ attr_reader :last_data
6
+
7
+ def initialize(buddy)
8
+ super
9
+ @buddy = buddy
10
+ @last_data = nil
11
+ end
12
+
13
+ private
14
+
15
+ def relay(data)
16
+ @last_data = data
17
+ @buddy.ask(:relay, data) unless @buddy.nil?
18
+ end
19
+
20
+ end # Relay
@@ -0,0 +1,78 @@
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 'opee'
10
+ require 'relay'
11
+
12
+ class OpeeTest < ::Test::Unit::TestCase
13
+
14
+ def test_opee_actor_queue
15
+ a = ::Relay.new(nil)
16
+ assert_equal(0, a.queue_count())
17
+ a.stop()
18
+ a.ask(:relay, 5)
19
+ assert_equal(1, a.queue_count())
20
+ a.ask(:relay, 7)
21
+ assert_equal(2, a.queue_count())
22
+ a.close()
23
+ end
24
+
25
+ def test_opee_actor_ask
26
+ a = ::Relay.new(nil)
27
+ a.ask(:relay, 7)
28
+ sleep(0.5) # minimize dependencies for simplest possible test
29
+ assert_equal(7, a.last_data)
30
+ a.close()
31
+ end
32
+
33
+ def test_opee_actor_method_missing
34
+ a = ::Relay.new(nil)
35
+ a.relay(7)
36
+ ::Opee::Env.wait_close()
37
+ assert_equal(7, a.last_data)
38
+ a.close()
39
+ end
40
+
41
+ def test_opee_actor_raise_after_close
42
+ a = ::Relay.new(nil)
43
+ a.close()
44
+ assert_raise(ThreadError) { a.start() }
45
+ end
46
+
47
+ def test_opee_actor_priority
48
+ a = ::Relay.new(nil)
49
+ a.priority_ask(:relay, 7)
50
+ ::Opee::Env.wait_close()
51
+ assert_equal(7, a.last_data)
52
+ a.close()
53
+ end
54
+
55
+ def test_opee_actor_idle
56
+ a = ::Relay.new(nil)
57
+ a.on_idle(:relay, 7)
58
+ ::Opee::Env.wait_close()
59
+ assert_equal(7, a.last_data)
60
+ a.close()
61
+ end
62
+
63
+ def test_opee_actor_order
64
+ a = ::Relay.new(nil)
65
+ a.stop()
66
+ a.on_idle(:relay, 17)
67
+ a.priority_ask(:relay, 3)
68
+ a.ask(:relay, 7)
69
+ a.step()
70
+ assert_equal(3, a.last_data)
71
+ a.step()
72
+ assert_equal(7, a.last_data)
73
+ a.step()
74
+ assert_equal(17, a.last_data)
75
+ a.close()
76
+ end
77
+
78
+ end # OpeeTest
@@ -0,0 +1,22 @@
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 'opee'
10
+ require 'relay'
11
+
12
+ class OpeeTest < ::Test::Unit::TestCase
13
+
14
+ def test_wait_close
15
+ a = ::Relay.new(nil)
16
+ a.ask(:relay, 7)
17
+ ::Opee::Env.wait_close()
18
+ assert_equal(7, a.last_data)
19
+ a.close()
20
+ end
21
+
22
+ end # OpeeTest
@@ -0,0 +1,21 @@
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 'opee'
10
+
11
+ class OpeeTest < ::Test::Unit::TestCase
12
+
13
+ def test_opee_log_log
14
+ #::Opee::Env.logger.ask(:severity=, Logger::INFO)
15
+ ::Opee::Env.logger.severity= Logger::INFO
16
+ ::Opee::Env.log(Logger::INFO, "hello")
17
+ ::Opee::Env.each_actor { |a| puts a.to_s }
18
+ sleep(0.2)
19
+ end
20
+
21
+ end # OpeeTest
@@ -5,24 +5,7 @@ $: << File.join(File.dirname(__FILE__), "../lib")
5
5
 
6
6
  require 'test/unit'
7
7
  require 'opee'
8
-
9
- class Relay < ::Opee::Actor
10
- attr_reader :last_data
11
-
12
- def initialize(buddy)
13
- super
14
- @buddy = buddy
15
- @last_data = nil
16
- end
17
-
18
- private
19
-
20
- def relay(data)
21
- @last_data = data
22
- @buddy.ask(:relay, data) unless @buddy.nil?
23
- end
24
-
25
- end # Relay
8
+ require 'relay'
26
9
 
27
10
  class Opeet < ::Test::Unit::TestCase
28
11
 
@@ -33,8 +16,25 @@ class Opeet < ::Test::Unit::TestCase
33
16
  a.ask(:relay, 7)
34
17
  assert_equal(1, a.queue_count())
35
18
  a.start()
19
+ sleep(0.5)
20
+ assert_equal(7, a.last_data)
21
+ a.close()
22
+ end
23
+
24
+ def test_log
25
+ #::Opee::Env.logger.ask(:severity=, Logger::INFO)
26
+ ::Opee::Env.logger.severity= Logger::INFO
27
+ ::Opee::Env.log(Logger::INFO, "hello")
28
+ ::Opee::Env.each_actor { |a| puts a.to_s }
36
29
  sleep(0.2)
30
+ end
31
+
32
+ def test_wait_close
33
+ a = ::Relay.new(nil)
34
+ a.ask(:relay, 7)
35
+ ::Opee::Env.wait_close()
37
36
  assert_equal(7, a.last_data)
37
+ a.close()
38
38
  end
39
39
 
40
40
  end # Opeet
@@ -0,0 +1,16 @@
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 'opee'
10
+
11
+ class OpeeTest < ::Test::Unit::TestCase
12
+ end # OpeeTest
13
+
14
+ require 'tc_opee_actor'
15
+ require 'tc_opee_log'
16
+ require 'tc_opee_env'
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.1
4
+ version: 0.0.2
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-04-17 00:00:00.000000000 Z
12
+ date: 2012-04-29 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: ! 'An experimental Object-base Parallel Evaluation Environment. '
15
15
  email: peter@ohler.com
@@ -19,9 +19,16 @@ extra_rdoc_files:
19
19
  - README.md
20
20
  files:
21
21
  - lib/opee/actor.rb
22
+ - lib/opee/env.rb
23
+ - lib/opee/log.rb
22
24
  - lib/opee/version.rb
23
25
  - lib/opee.rb
26
+ - test/relay.rb
27
+ - test/tc_opee_actor.rb
28
+ - test/tc_opee_env.rb
29
+ - test/tc_opee_log.rb
24
30
  - test/tests.rb
31
+ - test/ts_opee.rb
25
32
  - LICENSE
26
33
  - README.md
27
34
  homepage: http://www.ohler.com/opee
@@ -46,7 +53,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
46
53
  version: '0'
47
54
  requirements: []
48
55
  rubyforge_project: opee
49
- rubygems_version: 1.8.21
56
+ rubygems_version: 1.8.11
50
57
  signing_key:
51
58
  specification_version: 3
52
59
  summary: An experimental Object-base Parallel Evaluation Environment.