zoidberg 0.1.4 → 0.1.6
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.
- 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:
|