opee 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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.