class SynCache::RemoteCache

Connects to a remote SynCache instance over DRb at the provided URI and replaces the remote fetch_or_add method with a slightly less bullet-proof version that invokes the supplied block locally (instead of sending it over DRb to the cache and then back to a different local thread via a local DRb service).

If another RemoteCache client is already working on the same key, this client will wait, using randomly increasing intervals. When a configured timeout runs out (counting from the time the other client has put a placeholder in the cache), the client will give up, discard the other client's placeholder and start working on the key itself.

Mixing access to the same cache entries from direct and RemoteCache clients is not recommended.

Public Class Methods

new(uri, timeout=REMOTE_TIMEOUT, first_delay=REMOTE_FIRST_DELAY) click to toggle source
# File lib/syncache/remote.rb, line 49
def initialize(uri, timeout=REMOTE_TIMEOUT, first_delay=REMOTE_FIRST_DELAY)
  @timeout = timeout
  @first_delay = first_delay
  @cache = DRbObject.new_with_uri(uri)
end

Public Instance Methods

fetch_or_add(key) { || ... } click to toggle source
# File lib/syncache/remote.rb, line 59
def fetch_or_add(key)
  placeholder = Placeholder.new
  value = @cache.fetch_or_add(key) { placeholder }

  case value
  when placeholder
    # our placeholder
    value = @cache[key] = yield

  when Placeholder
    # someone else's placeholder
    delay = @first_delay
    while value.kind_of?(Placeholder) and Time.now < value.timestamp + @timeout
      sleep(delay)
      delay *= 1 + rand
      value = @cache[key]
    end

    if value.kind_of?(Placeholder) or value.nil?
      # the other client timed out or got flushed;
      # reset the placeholder ttl and do it ourselves
      @cache[key] = Placeholder.new
      value = @cache[key] = yield
    end
  end

  value
end
method_missing(method, *args) click to toggle source
# File lib/syncache/remote.rb, line 55
def method_missing(method, *args)
  @cache.send(method, *args)
end