1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
|
require "ftw/namespace"
require "thread"
# A simple thread-safe resource pool.
#
# Resources in this pool must respond to 'available?'.
# For best results, your resources should just 'include FTW::Poolable'
#
# The primary use case was as a way to pool FTW::Connection instances.
class FTW::Pool
def initialize
# Pool is a hash of arrays.
@pool = Hash.new { |h,k| h[k] = Array.new }
@lock = Mutex.new
end # def initialize
# Add an object to the pool with a given identifier. For example:
#
# pool.add("www.google.com:80", connection1)
# pool.add("www.google.com:80", connection2)
# pool.add("github.com:443", connection3)
def add(identifier, object)
@lock.synchronize do
@pool[identifier] << object
end
return object
end # def add
# Fetch a resource from this pool. If no available resources
# are found, the 'default_block' is invoked and expected to
# return a new resource to add to the pool that satisfies
# the fetch..
#
# Example:
#
# pool.fetch("github.com:443") do
# conn = FTW::Connection.new("github.com:443")
# conn.secure
# conn
# end
def fetch(identifier, &default_block)
@lock.synchronize do
@pool[identifier].delete_if { |o| o.available? && !o.connected? }
object = @pool[identifier].find { |o| o.available? }
return object if !object.nil?
end
# Otherwise put the return value of default_block in the
# pool and return it, but don't put nil values in the pool.
obj = default_block.call
if obj.nil?
return nil
else
return add(identifier, obj)
end
end # def fetch
# Iterate over all pool members.
#
# This holds the pool lock during this method, so you should not call 'fetch'
# or 'add'.
def each(&block)
@lock.synchronize do
@pool.each do |identifier, object|
block.call(identifier, object)
end
end
end # def each
end # class FTW::Pool
|