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 +33 -2
- data/lib/opee.rb +2 -0
- data/lib/opee/actor.rb +82 -17
- data/lib/opee/env.rb +88 -0
- data/lib/opee/log.rb +43 -0
- data/lib/opee/version.rb +1 -1
- data/test/relay.rb +20 -0
- data/test/tc_opee_actor.rb +78 -0
- data/test/tc_opee_env.rb +22 -0
- data/test/tc_opee_log.rb +21 -0
- data/test/tests.rb +18 -18
- data/test/ts_opee.rb +16 -0
- metadata +10 -3
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
|
-
|
10
|
+
Once a reasonable API has been established a high performance C extension will
|
11
|
+
be written to improve performance.
|
11
12
|
|
12
|
-
|
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
|
|
data/lib/opee.rb
CHANGED
data/lib/opee/actor.rb
CHANGED
@@ -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
|
-
@
|
20
|
+
@state = RUNNING
|
21
|
+
Env.add_actor(self)
|
12
22
|
set_options(options)
|
13
23
|
@loop = Thread.start(self) do |me|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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 @
|
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
|
-
@
|
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
|
-
@
|
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
|
data/lib/opee/env.rb
ADDED
@@ -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
|
data/lib/opee/log.rb
ADDED
@@ -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
|
data/lib/opee/version.rb
CHANGED
data/test/relay.rb
ADDED
@@ -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
|
data/test/tc_opee_env.rb
ADDED
@@ -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
|
data/test/tc_opee_log.rb
ADDED
@@ -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
|
data/test/tests.rb
CHANGED
@@ -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
|
data/test/ts_opee.rb
ADDED
@@ -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.
|
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-
|
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.
|
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.
|