Class: Authorize::ResourcePool

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/authorize/resource_pool.rb

Overview

Arbitrate thread-safe access to a limited set of expensive and perishable objects

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(max_size, factory) ⇒ ResourcePool

Create a new unfilled resource pool with a capacity of of at most max_size objects. The pool is lazily filled by the factory lambda.



17
18
19
20
21
22
23
24
25
# File 'lib/authorize/resource_pool.rb', line 17

def initialize(max_size, factory)
  @factory = factory
  @pool = []
  @tokens = []
  @monitor = Monitor.new
  @tokens_cv = @monitor.new_cond
  @num_waiting = 0
  max_size.times {|i| @tokens.unshift(i)}
end

Instance Attribute Details

#num_waitingObject (readonly)

Returns the value of attribute num_waiting.



13
14
15
# File 'lib/authorize/resource_pool.rb', line 13

def num_waiting
  @num_waiting
end

Instance Method Details

#availableObject



31
32
33
# File 'lib/authorize/resource_pool.rb', line 31

def available
  @tokens.size
end

#checkin(obj) ⇒ Object

Return an object to the pool



51
52
53
54
55
56
57
58
# File 'lib/authorize/resource_pool.rb', line 51

def checkin(obj)
  @monitor.synchronize do
    token = @pool.index(obj)
    raise "#{obj} has not been checked out from this pool" unless token && !@tokens.include?(token)
    @tokens.push(token) if token
    @tokens_cv.signal
  end
end

#checkout(*args) ⇒ Object

Checkout an object from the pool. Arguments are passed unmolested to ConditionVariable#wait to manage timeouts.



36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/authorize/resource_pool.rb', line 36

def checkout(*args)
  @monitor.synchronize do
    until token = @tokens.pop
      begin
        @num_waiting += 1
        raise "Timed out during checkout" unless @tokens_cv.wait(*args)
      ensure
        @num_waiting -= 1
      end
    end
    @pool[token] ||= @factory.call
  end
end

#clear!Object

Remove all resources from the pool and revoke all tokens TODO: don’t brutally/blindly revoke tokens -raise an exception or fire a callback, and address waiting threads.



79
80
81
82
83
84
85
# File 'lib/authorize/resource_pool.rb', line 79

def clear!
  @monitor.synchronize do
    @pool.each_index {|i| @tokens << i}
    @tokens.uniq!
    @pool.clear
  end
end

#expireObject

Expire resources in inventory with the given block. Available (not reserved) pool members are yielded to the block. The object is expired (removed permanently from the pool) if the block returns a true-ish value.



63
64
65
66
67
68
69
70
# File 'lib/authorize/resource_pool.rb', line 63

def expire
  @monitor.synchronize do
    @tokens.each do |i|
      next unless obj = @pool[i]
      @pool[i] = nil if yield obj
    end
  end
end

#freshenObject

Freshen objects in inventory with the given block



73
74
75
# File 'lib/authorize/resource_pool.rb', line 73

def freshen
  expire {|obj| yield(obj) ; return false}
end

#sizeObject



27
28
29
# File 'lib/authorize/resource_pool.rb', line 27

def size
  @pool.compact.length
end