zoidberg 0.1.4 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/lib/zoidberg.rb +16 -0
- data/lib/zoidberg/lazy.rb +56 -0
- data/lib/zoidberg/pool.rb +1 -1
- data/lib/zoidberg/proxy.rb +37 -18
- data/lib/zoidberg/proxy/confined.rb +51 -19
- data/lib/zoidberg/proxy/liberated.rb +1 -5
- data/lib/zoidberg/registry.rb +1 -1
- data/lib/zoidberg/shell.rb +17 -5
- data/lib/zoidberg/supervisor.rb +1 -1
- data/lib/zoidberg/task.rb +4 -0
- data/lib/zoidberg/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 08a8fcac4a08bd3faf0b9df558810aff252ad731
|
4
|
+
data.tar.gz: 592ee902246aa7894b9a06e3fe5a1a5004cd79cf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 30c31fccb644651b16bcb4800950abaad291a1c889e0610e35eda0544478b9b36d4395ded8689965ad6f27b25b3948e690bd051e7b4edb5f86013779595dd5e4
|
7
|
+
data.tar.gz: da72c8a5e1e394cd6acdd2898aa7e647da58478d5408c6b4f2c741fac92705fc1efe641d8cb729f2913f69bdbfcf66d8d30c9cebafd2f7b99e77eccab9a61cc9
|
data/CHANGELOG.md
CHANGED
data/lib/zoidberg.rb
CHANGED
@@ -7,6 +7,7 @@ require 'zoidberg/version'
|
|
7
7
|
module Zoidberg
|
8
8
|
autoload :DeadException, 'zoidberg/shell'
|
9
9
|
autoload :Future, 'zoidberg/future'
|
10
|
+
autoload :Lazy, 'zoidberg/lazy'
|
10
11
|
autoload :Logger, 'zoidberg/logger'
|
11
12
|
autoload :Pool, 'zoidberg/pool'
|
12
13
|
autoload :Proxy, 'zoidberg/proxy'
|
@@ -23,6 +24,7 @@ module Zoidberg
|
|
23
24
|
|
24
25
|
class << self
|
25
26
|
|
27
|
+
attr_accessor :signal_shutdown
|
26
28
|
attr_accessor :default_shell
|
27
29
|
|
28
30
|
# @return [Zoidberg::Logger]
|
@@ -46,6 +48,14 @@ module Zoidberg
|
|
46
48
|
SecureRandom.uuid
|
47
49
|
end
|
48
50
|
|
51
|
+
def signal_reset
|
52
|
+
self.signal_shutdown = false
|
53
|
+
end
|
54
|
+
|
55
|
+
def in_shutdown?
|
56
|
+
!!self.signal_shutdown
|
57
|
+
end
|
58
|
+
|
49
59
|
end
|
50
60
|
|
51
61
|
end
|
@@ -54,3 +64,9 @@ end
|
|
54
64
|
Zoidberg.logger = Zoidberg::Logger.new(STDERR)
|
55
65
|
# Set default shell to soft shell
|
56
66
|
Zoidberg.default_shell = Zoidberg::SoftShell
|
67
|
+
|
68
|
+
%w(INT TERM).each do |sig_name|
|
69
|
+
Signal.trap(sig_name) do |*_|
|
70
|
+
Zoidberg.signal_shutdown = true
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'zoidberg'
|
2
|
+
|
3
|
+
module Zoidberg
|
4
|
+
|
5
|
+
# Provide lazy evaluation of an instance for future work
|
6
|
+
class Lazy < BasicObject
|
7
|
+
|
8
|
+
# Create a new lazy evaluator
|
9
|
+
#
|
10
|
+
# @param klass [Class] optional class to use for type checkin
|
11
|
+
# @yield block to provide actual instance
|
12
|
+
# @return [self]
|
13
|
+
def initialize(klass=nil, &block)
|
14
|
+
@klass = klass
|
15
|
+
@lock = ::Mutex.new
|
16
|
+
unless(block)
|
17
|
+
::Kernel.raise ::ArgumentError.new('Block is required for providing instance!')
|
18
|
+
end
|
19
|
+
@instance_block = block
|
20
|
+
end
|
21
|
+
|
22
|
+
# Proxy any calls to actual instance
|
23
|
+
def method_missing(*args, &block)
|
24
|
+
_lazy_instance.send(*args, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Customized check to allow for type checking prior to instance
|
28
|
+
# being available via lazy loading
|
29
|
+
#
|
30
|
+
# @param chk [Class]
|
31
|
+
# @return [TrueClass, FalseClass]
|
32
|
+
def is_a?(chk)
|
33
|
+
if(@klass)
|
34
|
+
([@klass] + @klass.ancestors).include?(chk)
|
35
|
+
else
|
36
|
+
method_missing(:is_a?, chk)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# @return [Object]
|
43
|
+
def _lazy_instance
|
44
|
+
@lock.synchronize do
|
45
|
+
unless(@instance)
|
46
|
+
until(@instance = @instance_block.call)
|
47
|
+
::Kernel.sleep(0.1)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
@instance
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
data/lib/zoidberg/pool.rb
CHANGED
data/lib/zoidberg/proxy.rb
CHANGED
@@ -53,11 +53,31 @@ module Zoidberg
|
|
53
53
|
raise NotImplementedError
|
54
54
|
end
|
55
55
|
|
56
|
+
# Set the raw instance into the proxy and link proxy to instance
|
57
|
+
#
|
58
|
+
# @param inst [Object] raw instance being wrapped
|
59
|
+
# @return [NilClass]
|
60
|
+
def _zoidberg_set_instance(inst)
|
61
|
+
@_raw_instance = inst
|
62
|
+
@_raw_instance._zoidberg_proxy(self)
|
63
|
+
nil
|
64
|
+
end
|
65
|
+
|
56
66
|
# @return [TrueClass, FalseClass] currently locked
|
57
67
|
def _zoidberg_locked?
|
58
68
|
false
|
59
69
|
end
|
60
70
|
|
71
|
+
# @return [TrueClass]
|
72
|
+
def _aquire_lock!
|
73
|
+
true
|
74
|
+
end
|
75
|
+
|
76
|
+
# @return [TrueClass]
|
77
|
+
def _release_lock!
|
78
|
+
true
|
79
|
+
end
|
80
|
+
|
61
81
|
# @return [TrueClass, FalseClass] currently unlocked
|
62
82
|
def _zoidberg_available?
|
63
83
|
!_zoidberg_locked?
|
@@ -99,6 +119,7 @@ module Zoidberg
|
|
99
119
|
# @param e [Exception]
|
100
120
|
def _zoidberg_unexpected_error(e)
|
101
121
|
::Zoidberg.logger.error "Unexpected exception: #{e.class} - #{e}"
|
122
|
+
::Zoidberg.logger.debug "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
|
102
123
|
unless((defined?(Timeout) && e.is_a?(Timeout::Error)) || e.is_a?(::Zoidberg::DeadException))
|
103
124
|
if(_zoidberg_link)
|
104
125
|
if(_zoidberg_link.class.trap_exit)
|
@@ -131,25 +152,24 @@ module Zoidberg
|
|
131
152
|
# @param error [Exception] exception that was caught
|
132
153
|
# @return [TrueClass]
|
133
154
|
def _zoidberg_handle_unexpected_error(error)
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
155
|
+
unless(::Zoidberg.in_shutdown?)
|
156
|
+
if(_raw_instance.respond_to?(:restart))
|
157
|
+
begin
|
158
|
+
_raw_instance.restart(error)
|
159
|
+
return # short circuit
|
160
|
+
rescue => e
|
161
|
+
end
|
139
162
|
end
|
163
|
+
_zoidberg_destroy!
|
164
|
+
_aquire_lock!
|
165
|
+
args = _build_args.dup
|
166
|
+
inst = args.shift.unshelled_new(*args.first, &args.last)
|
167
|
+
_zoidberg_set_instance(inst)
|
168
|
+
if(_raw_instance.respond_to?(:restarted!))
|
169
|
+
_raw_instance.restarted!
|
170
|
+
end
|
171
|
+
_release_lock!
|
140
172
|
end
|
141
|
-
_zoidberg_destroy!
|
142
|
-
_aquire_lock!
|
143
|
-
args = _build_args.dup
|
144
|
-
@_raw_instance = args.shift.unshelled_new(
|
145
|
-
*args.first,
|
146
|
-
&args.last
|
147
|
-
)
|
148
|
-
_raw_instance._zoidberg_proxy(self)
|
149
|
-
if(_raw_instance.respond_to?(:restarted!))
|
150
|
-
_raw_instance.restarted!
|
151
|
-
end
|
152
|
-
_release_lock!
|
153
173
|
true
|
154
174
|
end
|
155
175
|
|
@@ -189,7 +209,6 @@ module Zoidberg
|
|
189
209
|
_raw_instance.send(:define_singleton_method, :to_s, &death_from_above_display)
|
190
210
|
_raw_instance.send(:define_singleton_method, :inspect, &death_from_above_display)
|
191
211
|
_raw_instance.send(:define_singleton_method, :_zoidberg_destroyed, ::Proc.new{ true })
|
192
|
-
_zoidberg_signal(:destroyed)
|
193
212
|
end
|
194
213
|
true
|
195
214
|
end
|
@@ -9,6 +9,8 @@ module Zoidberg
|
|
9
9
|
attr_reader :_source_thread
|
10
10
|
# @return [Queue] current request queue
|
11
11
|
attr_reader :_requests
|
12
|
+
# @return [Queue] result queue
|
13
|
+
attr_reader :_results
|
12
14
|
# @return [TrueClass, FalseClass] blocked running task
|
13
15
|
attr_reader :_blocked
|
14
16
|
|
@@ -18,6 +20,7 @@ module Zoidberg
|
|
18
20
|
# @return [self]
|
19
21
|
def initialize(klass, *args, &block)
|
20
22
|
@_requests = ::Queue.new
|
23
|
+
@_results = ::Queue.new
|
21
24
|
@_blocked = false
|
22
25
|
@_source_thread = ::Thread.new do
|
23
26
|
::Zoidberg.logger.debug 'Starting the isolation request processor'
|
@@ -25,11 +28,7 @@ module Zoidberg
|
|
25
28
|
_isolate!
|
26
29
|
end
|
27
30
|
@_build_args = [klass, *args, block]
|
28
|
-
@
|
29
|
-
@_raw_instance._zoidberg_proxy(self)
|
30
|
-
if(@_raw_instance.class.include?(::Zoidberg::Supervise))
|
31
|
-
@_supervised = true
|
32
|
-
end
|
31
|
+
@_supervised = klass.include?(::Zoidberg::Supervise)
|
33
32
|
::Zoidberg.logger.debug "Zoidberg object isolation wrap: #{@_build_args.inspect}"
|
34
33
|
end
|
35
34
|
|
@@ -44,7 +43,7 @@ module Zoidberg
|
|
44
43
|
:block => block,
|
45
44
|
:response => nil,
|
46
45
|
:async => true,
|
47
|
-
:
|
46
|
+
:blocked => !!blocking
|
48
47
|
)
|
49
48
|
nil
|
50
49
|
end
|
@@ -102,22 +101,41 @@ module Zoidberg
|
|
102
101
|
end
|
103
102
|
end
|
104
103
|
|
104
|
+
# @return [TrueClass, FalseClass]
|
105
105
|
def _zoidberg_available?
|
106
106
|
!_blocked
|
107
107
|
end
|
108
108
|
|
109
|
+
# @return [TrueClass, FalseClass]
|
110
|
+
def threaded?
|
111
|
+
::Thread.current != _source_thread
|
112
|
+
end
|
113
|
+
|
114
|
+
def task_defer(wait_task)
|
115
|
+
_results << wait_task
|
116
|
+
end
|
117
|
+
|
118
|
+
def inspect
|
119
|
+
_raw_instance.inspect
|
120
|
+
end
|
121
|
+
|
122
|
+
def to_s
|
123
|
+
_raw_inspect.to_s
|
124
|
+
end
|
125
|
+
|
109
126
|
protected
|
110
127
|
|
111
128
|
# Process requests
|
112
129
|
def _isolate!
|
113
130
|
begin
|
114
131
|
::Kernel.loop do
|
132
|
+
item = _requests.pop
|
115
133
|
begin
|
116
|
-
_process_request(
|
134
|
+
_process_request(item)
|
117
135
|
rescue => e
|
118
136
|
::Zoidberg.logger.error "Unexpected looping error! (#{e.class}: #{e})"
|
119
|
-
::Zoidberg.logger.
|
120
|
-
|
137
|
+
::Zoidberg.logger.debug "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
|
138
|
+
item.push(e)
|
121
139
|
end
|
122
140
|
end
|
123
141
|
ensure
|
@@ -130,43 +148,57 @@ module Zoidberg
|
|
130
148
|
# Process a request
|
131
149
|
#
|
132
150
|
# @param request [Hash]
|
133
|
-
# @return [
|
151
|
+
# @return [NilClass]
|
134
152
|
def _process_request(request)
|
135
153
|
begin
|
136
154
|
@_blocked = !request[:async]
|
137
155
|
::Zoidberg.logger.debug "Processing received request: #{request.inspect}"
|
138
156
|
unless(request[:task])
|
139
|
-
|
157
|
+
if(request[:response])
|
158
|
+
request[:result] = _results
|
159
|
+
end
|
160
|
+
request[:task] = ::Zoidberg::Task.new(!self.class.option?(:evented) || request[:async] ? :async : :serial, _raw_instance, [request]) do |req|
|
140
161
|
begin
|
141
162
|
result = origin.__send__(
|
142
163
|
*req[:arguments],
|
143
164
|
&req[:block]
|
144
165
|
)
|
145
166
|
if(req[:response])
|
146
|
-
req[:
|
167
|
+
req[:result] << result
|
147
168
|
end
|
148
169
|
rescue ::Exception => exception
|
149
170
|
if(req[:response])
|
150
|
-
req[:
|
171
|
+
req[:result] << exception
|
151
172
|
end
|
152
173
|
end
|
153
174
|
end
|
154
175
|
end
|
155
|
-
if(request[:
|
176
|
+
if(!request[:task_defer] || request[:task_defer].complete?)
|
156
177
|
if(_raw_instance.alive?)
|
157
|
-
request[:task].
|
158
|
-
|
178
|
+
if(request[:task].waiting?)
|
179
|
+
request[:task].proceed
|
180
|
+
end
|
181
|
+
if(!request[:async] || request[:blocking])
|
182
|
+
val = _results.pop
|
183
|
+
if(val.is_a?(::Zoidberg::Task))
|
184
|
+
::Thread.new do
|
185
|
+
val.value
|
186
|
+
_requests.push(request)
|
187
|
+
end
|
188
|
+
else
|
189
|
+
request[:response].push(val)
|
190
|
+
::Zoidberg.logger.debug "Request processing completed. #{request.inspect}"
|
191
|
+
end
|
192
|
+
end
|
159
193
|
else
|
160
194
|
request[:response] << ::Zoidberg::DeadException.new('Instance in terminated state!')
|
161
195
|
request[:task].halt!
|
162
196
|
end
|
163
197
|
end
|
164
|
-
_requests.push(request) unless request[:task].complete? || request[:async]
|
165
|
-
::Zoidberg.logger.debug "Request processing completed. #{request.inspect}"
|
166
198
|
ensure
|
167
199
|
@_blocked = false
|
168
200
|
end
|
169
|
-
|
201
|
+
nil
|
170
202
|
end
|
171
203
|
|
172
204
|
end
|
@@ -21,12 +21,8 @@ module Zoidberg
|
|
21
21
|
@_locker = nil
|
22
22
|
@_locker_count = 0
|
23
23
|
@_zoidberg_signal = nil
|
24
|
-
@_raw_instance = klass.unshelled_new(*args, &block)
|
25
|
-
@_raw_instance._zoidberg_proxy(self)
|
26
24
|
@_raw_threads = ::Smash.new{ ::Array.new }
|
27
|
-
|
28
|
-
@_supervised = true
|
29
|
-
end
|
25
|
+
@_supervised = klass.ancestors.include?(::Zoidberg::Supervise)
|
30
26
|
end
|
31
27
|
|
32
28
|
# Used to proxy request to real instance
|
data/lib/zoidberg/registry.rb
CHANGED
data/lib/zoidberg/shell.rb
CHANGED
@@ -132,9 +132,16 @@ module Zoidberg
|
|
132
132
|
# @yield block to execute without lock
|
133
133
|
# @return [Object] result of block
|
134
134
|
def defer(&block)
|
135
|
-
|
136
|
-
|
137
|
-
|
135
|
+
if(current_self.threaded?)
|
136
|
+
action = Task.new(:async, current_self){ block.call }
|
137
|
+
current_self.task_defer(action)
|
138
|
+
Thread.stop
|
139
|
+
action.value
|
140
|
+
else
|
141
|
+
Fiber.yield
|
142
|
+
if(block)
|
143
|
+
::Fiber.new(&block).resume
|
144
|
+
end
|
138
145
|
end
|
139
146
|
end
|
140
147
|
|
@@ -162,7 +169,7 @@ module Zoidberg
|
|
162
169
|
def sleep(length=nil)
|
163
170
|
start_time = ::Time.now.to_f
|
164
171
|
if(length)
|
165
|
-
::Kernel.sleep(length)
|
172
|
+
defer{ ::Kernel.sleep(length) }
|
166
173
|
else
|
167
174
|
::Thread.current[:root_fiber] == ::Fiber.current ? ::Kernel.sleep : ::Fiber.yield
|
168
175
|
end
|
@@ -258,7 +265,11 @@ module Zoidberg
|
|
258
265
|
if(oxy)
|
259
266
|
@_zoidberg_proxy = oxy
|
260
267
|
end
|
261
|
-
@_zoidberg_proxy
|
268
|
+
if(@_zoidberg_proxy)
|
269
|
+
@_zoidberg_proxy
|
270
|
+
else
|
271
|
+
Lazy.new(self.class){ @_zoidberg_proxy }
|
272
|
+
end
|
262
273
|
end
|
263
274
|
alias_method :current_self, :_zoidberg_proxy
|
264
275
|
alias_method :current_actor, :_zoidberg_proxy
|
@@ -286,6 +297,7 @@ module Zoidberg
|
|
286
297
|
else
|
287
298
|
raise TypeError.new "Unable to determine `Shell` type for this class `#{self}`!"
|
288
299
|
end
|
300
|
+
proxy._zoidberg_set_instance(self.unshelled_new(*args, &block))
|
289
301
|
weak_ref = Zoidberg::WeakRef.new(proxy)
|
290
302
|
Zoidberg::Proxy.register(weak_ref.__id__, proxy)
|
291
303
|
ObjectSpace.define_finalizer(weak_ref, Zoidberg::Proxy.method(:scrub!))
|
data/lib/zoidberg/supervisor.rb
CHANGED
data/lib/zoidberg/task.rb
CHANGED
data/lib/zoidberg/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zoidberg
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Roberts
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-09-
|
11
|
+
date: 2015-09-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bogo
|
@@ -78,6 +78,7 @@ files:
|
|
78
78
|
- README.md
|
79
79
|
- lib/zoidberg.rb
|
80
80
|
- lib/zoidberg/future.rb
|
81
|
+
- lib/zoidberg/lazy.rb
|
81
82
|
- lib/zoidberg/logger.rb
|
82
83
|
- lib/zoidberg/pool.rb
|
83
84
|
- lib/zoidberg/proxy.rb
|
@@ -113,9 +114,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
113
114
|
version: '0'
|
114
115
|
requirements: []
|
115
116
|
rubyforge_project:
|
116
|
-
rubygems_version: 2.
|
117
|
+
rubygems_version: 2.4.8
|
117
118
|
signing_key:
|
118
119
|
specification_version: 4
|
119
120
|
summary: Why not?
|
120
121
|
test_files: []
|
121
|
-
has_rdoc:
|