class Pond
Constants
- DEFAULT_DETACH_IF
- VERSION
Attributes
allocated[R]
available[R]
collection[R]
detach_if[R]
maximum_size[R]
timeout[R]
Public Class Methods
new( maximum_size: 10, eager: false, timeout: 1, collection: :queue, detach_if: DEFAULT_DETACH_IF, &block )
click to toggle source
# File lib/pond.rb, line 14 def initialize( maximum_size: 10, eager: false, timeout: 1, collection: :queue, detach_if: DEFAULT_DETACH_IF, &block ) @block = block @monitor = Monitor.new @cv = MonitorMixin::ConditionVariable.new(@monitor) @allocated = {} @available = Array.new(eager ? maximum_size : 0, &block) self.timeout = timeout self.collection = collection self.detach_if = detach_if self.maximum_size = maximum_size end
Private Class Methods
wrap(*args, &block)
click to toggle source
# File lib/pond.rb, line 151 def wrap(*args, &block) Wrapper.new(*args, &block) end
Public Instance Methods
checkout(scope: nil) { |object| ... }
click to toggle source
# File lib/pond.rb, line 35 def checkout(scope: nil, &block) raise "Can't checkout with a non-frozen scope" unless scope.frozen? if object = current_object(scope: scope) yield object else checkout_object(scope: scope, &block) end end
collection=(type)
click to toggle source
# File lib/pond.rb, line 54 def collection=(type) raise "Bad value for Pond collection: #{type.inspect}" unless [:stack, :queue].include?(type) sync { @collection = type } end
detach_if=(callable)
click to toggle source
# File lib/pond.rb, line 67 def detach_if=(callable) raise "Object given for Pond detach_if must respond to #call" unless callable.respond_to?(:call) sync { @detach_if = callable } end
maximum_size=(max)
click to toggle source
# File lib/pond.rb, line 59 def maximum_size=(max) raise "Bad value for Pond maximum_size: #{max.inspect}" unless Integer === max && max >= 0 sync do @maximum_size = max {} until size <= max || pop_object.nil? end end
size()
click to toggle source
# File lib/pond.rb, line 45 def size sync { @allocated.inject(@available.size){|sum, (h, k)| sum + k.length} } end
timeout=(timeout)
click to toggle source
# File lib/pond.rb, line 49 def timeout=(timeout) raise "Bad value for Pond timeout: #{timeout.inspect}" unless Numeric === timeout && timeout >= 0 sync { @timeout = timeout } end
Private Instance Methods
checkout_object(scope:) { |current_object(scope: scope)| ... }
click to toggle source
# File lib/pond.rb, line 74 def checkout_object(scope:) lock_object(scope: scope) yield current_object(scope: scope) ensure unlock_object(scope: scope) end
current_object(scope:)
click to toggle source
# File lib/pond.rb, line 138 def current_object(scope:) sync { (@allocated[scope] ||= {})[Thread.current] } end
get_object(timeout)
click to toggle source
# File lib/pond.rb, line 127 def get_object(timeout) pop_object || size < maximum_size && @block || @cv.wait(timeout) && false end
lock_object(scope:)
click to toggle source
# File lib/pond.rb, line 81 def lock_object(scope:) deadline = Time.now + @timeout until current_object(scope: scope) raise Timeout if (time_left = deadline - Time.now) < 0 sync do if object = get_object(time_left) set_current_object(object, scope: scope) end end end # We need to protect changes to @allocated and @available with the monitor # so that #size always returns the correct value. But, we don't want to # call the instantiation block while we have the lock, since it may take a # long time to return. So, we set the checked-out object to the block as a # signal that it needs to be called. if current_object(scope: scope) == @block set_current_object(@block.call, scope: scope) end end
pop_object()
click to toggle source
# File lib/pond.rb, line 131 def pop_object case collection when :queue then @available.shift when :stack then @available.pop end end
set_current_object(object, scope:)
click to toggle source
# File lib/pond.rb, line 142 def set_current_object(object, scope:) sync { (@allocated[scope] ||= {})[Thread.current] = object } end
sync(&block)
click to toggle source
# File lib/pond.rb, line 146 def sync(&block) @monitor.synchronize(&block) end
unlock_object(scope:)
click to toggle source
# File lib/pond.rb, line 104 def unlock_object(scope:) object = nil detach_if = nil should_return_object = nil sync do object = current_object(scope: scope) detach_if = self.detach_if should_return_object = object && object != @block && size <= maximum_size end begin should_return_object = !detach_if.call(object) if should_return_object detach_check_finished = true ensure sync do @available << object if detach_check_finished && should_return_object @allocated[scope].delete(Thread.current) @cv.signal end end end