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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3632fd491e21d5b71dca06d2670227b281b27865
4
- data.tar.gz: 360be229f5e280316a28b6505b80e08fba50220b
3
+ metadata.gz: 08a8fcac4a08bd3faf0b9df558810aff252ad731
4
+ data.tar.gz: 592ee902246aa7894b9a06e3fe5a1a5004cd79cf
5
5
  SHA512:
6
- metadata.gz: f3d3c32e84acbd7b470f16166b070b8bf219d3db1d548eeb25bb758e9675c1b8b864ec45cbe5b4536b402147ce6b0513cefbb5af2008855eea4af48a21c29366
7
- data.tar.gz: 3bd1a5562bdab8f04ac8f0e1381b1db7aa10c33cb0e1f83e334802cf348b329dae5e6091052b875efab3b3c740371620147c679dcbdb72962f5cb690321fa15c
6
+ metadata.gz: 30c31fccb644651b16bcb4800950abaad291a1c889e0610e35eda0544478b9b36d4395ded8689965ad6f27b25b3948e690bd051e7b4edb5f86013779595dd5e4
7
+ data.tar.gz: da72c8a5e1e394cd6acdd2898aa7e647da58478d5408c6b4f2c741fac92705fc1efe641d8cb729f2913f69bdbfcf66d8d30c9cebafd2f7b99e77eccab9a61cc9
@@ -1,3 +1,9 @@
1
+ # v0.1.6
2
+ * Add Zoidberg::Lazy
3
+ * Explicitly state what shells are used internally
4
+ * DRY raw instance wrapping
5
+ * Flag signal context and disable any locking
6
+
1
7
  # v0.1.4
2
8
  * Timer updates and fix spec
3
9
 
@@ -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
@@ -5,7 +5,7 @@ module Zoidberg
5
5
  # instances within the pool
6
6
  class Pool
7
7
 
8
- include Zoidberg::Shell
8
+ include Zoidberg::SoftShell
9
9
 
10
10
  # @return [Array<Object>] workers within pool
11
11
  attr_reader :_workers
@@ -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
- if(_raw_instance.respond_to?(:restart))
135
- begin
136
- _raw_instance.restart(error)
137
- return # short circuit
138
- rescue => e
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
- @_raw_instance = klass.unshelled_new(*args, &block)
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
- :blocking => blocking == :blocking
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(_requests.pop)
134
+ _process_request(item)
117
135
  rescue => e
118
136
  ::Zoidberg.logger.error "Unexpected looping error! (#{e.class}: #{e})"
119
- ::Zoidberg.logger.error "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
120
- ::Thread.main.raise e
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 [self]
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
- request[:task] = ::Zoidberg::Task.new(request[:async] ? :async : :serial, _raw_instance, [request]) do |req|
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[:response] << result
167
+ req[:result] << result
147
168
  end
148
169
  rescue ::Exception => exception
149
170
  if(req[:response])
150
- req[:response] << exception
171
+ req[:result] << exception
151
172
  end
152
173
  end
153
174
  end
154
175
  end
155
- if(request[:task].waiting?)
176
+ if(!request[:task_defer] || request[:task_defer].complete?)
156
177
  if(_raw_instance.alive?)
157
- request[:task].proceed
158
- request[:task].value if request[:blocking]
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
- self
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
- if(@_raw_instance.class.ancestors.include?(::Zoidberg::Supervise))
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
@@ -2,6 +2,6 @@ require 'zoidberg'
2
2
 
3
3
  module Zoidberg
4
4
  class Registry < Bogo::Smash
5
- include Zoidberg::Shell
5
+ include Zoidberg::SoftShell
6
6
  end
7
7
  end
@@ -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
- Fiber.yield
136
- if(block)
137
- ::Fiber.new(&block).resume
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!))
@@ -3,7 +3,7 @@ require 'zoidberg'
3
3
  module Zoidberg
4
4
  class Supervisor
5
5
 
6
- include Zoidberg::Shell
6
+ include Zoidberg::SoftShell
7
7
 
8
8
  # @return [Registry] current supervision registry
9
9
  attr_reader :registry
@@ -140,6 +140,10 @@ module Zoidberg
140
140
  raise
141
141
  end
142
142
  end
143
+ until(@task.stop?)
144
+ sleep(0.01)
145
+ end
146
+ @task
143
147
  end
144
148
 
145
149
  end
@@ -1,4 +1,4 @@
1
1
  module Zoidberg
2
2
  # Current library version
3
- VERSION = Gem::Version.new('0.1.4')
3
+ VERSION = Gem::Version.new('0.1.6')
4
4
  end
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
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-17 00:00:00.000000000 Z
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.2.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: