Sha256: dc32e429ecd5738e2b2b780ea3ae8ae05adeb47fceed8d0e943073f07390740c

Contents?: true

Size: 1.99 KB

Versions: 3

Compression:

Stored size: 1.99 KB

Contents

# frozen_string_literal: true

module Polyphony
  # Implements a limited resource pool
  class ResourcePool
    attr_reader :limit, :size

    # Initializes a new resource pool
    # @param opts [Hash] options
    # @param &block [Proc] allocator block
    def initialize(opts, &block)
      @allocator = block

      @stock = []
      @queue = []

      @limit = opts[:limit] || 4
      @size = 0
    end

    def available
      @stock.size
    end

    def acquire
      Gyro.ref
      resource = wait_for_resource
      return unless resource

      yield resource
    ensure
      Gyro.unref
      release(resource) if resource
    end

    def wait_for_resource
      fiber = Fiber.current
      @queue << fiber
      ready_resource = from_stock
      return ready_resource if ready_resource

      suspend
    ensure
      @queue.delete(fiber)
    end

    def release(resource)
      if resource.__discarded__
        @size -= 1
      elsif resource
        return_to_stock(resource)
        dequeue
      end
    end

    def dequeue
      return if @queue.empty? || @stock.empty?

      @queue.shift.schedule(@stock.shift)
    end

    def return_to_stock(resource)
      @stock << resource
    end

    def from_stock
      @stock.shift || (@size < @limit && allocate)
    end

    def method_missing(sym, *args, &block)
      acquire { |r| r.send(sym, *args, &block) }
    end

    def respond_to_missing?(*_args)
      true
    end

    # Extension to allow discarding of resources
    module ResourceExtensions
      def __discarded__
        @__discarded__
      end

      def __discard__
        @__discarded__ = true
      end
    end

    # Allocates a resource
    # @return [any] allocated resource
    def allocate
      @size += 1
      @allocator.().tap { |r| r.extend ResourceExtensions }
    end

    def <<(resource)
      @size += 1
      resource.extend ResourceExtensions
      @stock << resource
      dequeue
    end

    def preheat!
      (@limit - @size).times { @stock << allocate }
    end
  end
end

Version data entries

3 entries across 3 versions & 1 rubygems

Version Path
polyphony-0.40 lib/polyphony/core/resource_pool.rb
polyphony-0.39 lib/polyphony/core/resource_pool.rb
polyphony-0.38 lib/polyphony/core/resource_pool.rb