2015-12-16 08:07:31 +03:00
|
|
|
# frozen_string_literal: false
|
2018-11-02 20:52:33 +03:00
|
|
|
require_relative 'drb'
|
2003-06-18 19:45:12 +04:00
|
|
|
require 'monitor'
|
|
|
|
|
|
|
|
module DRb
|
2013-01-25 07:25:39 +04:00
|
|
|
|
|
|
|
# Timer id conversion keeps objects alive for a certain amount of time after
|
|
|
|
# their last access. The default time period is 600 seconds and can be
|
|
|
|
# changed upon initialization.
|
|
|
|
#
|
|
|
|
# To use TimerIdConv:
|
|
|
|
#
|
|
|
|
# DRb.install_id_conv TimerIdConv.new 60 # one minute
|
|
|
|
|
2003-06-18 19:45:12 +04:00
|
|
|
class TimerIdConv < DRbIdConv
|
2013-01-25 07:25:39 +04:00
|
|
|
class TimerHolder2 # :nodoc:
|
2003-06-18 19:45:12 +04:00
|
|
|
include MonitorMixin
|
|
|
|
|
|
|
|
class InvalidIndexError < RuntimeError; end
|
|
|
|
|
2016-05-15 14:59:00 +03:00
|
|
|
def initialize(keeping=600)
|
2011-05-19 01:19:18 +04:00
|
|
|
super()
|
|
|
|
@sentinel = Object.new
|
|
|
|
@gc = {}
|
|
|
|
@renew = {}
|
2016-05-15 14:59:00 +03:00
|
|
|
@keeping = keeping
|
2016-05-22 14:03:43 +03:00
|
|
|
@expires = nil
|
2003-06-18 19:45:12 +04:00
|
|
|
end
|
|
|
|
|
|
|
|
def add(obj)
|
2011-05-19 01:19:18 +04:00
|
|
|
synchronize do
|
2016-05-15 14:59:00 +03:00
|
|
|
rotate
|
2011-05-19 01:19:18 +04:00
|
|
|
key = obj.__id__
|
2016-05-15 14:59:00 +03:00
|
|
|
@renew[key] = obj
|
2016-05-22 14:03:43 +03:00
|
|
|
invoke_keeper
|
2011-05-19 01:19:18 +04:00
|
|
|
return key
|
|
|
|
end
|
2003-06-18 19:45:12 +04:00
|
|
|
end
|
|
|
|
|
2016-05-22 14:03:43 +03:00
|
|
|
def fetch(key)
|
2011-05-19 01:19:18 +04:00
|
|
|
synchronize do
|
2016-05-15 14:59:00 +03:00
|
|
|
rotate
|
2011-05-19 01:19:18 +04:00
|
|
|
obj = peek(key)
|
2016-05-22 14:03:43 +03:00
|
|
|
raise InvalidIndexError if obj == @sentinel
|
2011-05-19 01:19:18 +04:00
|
|
|
@renew[key] = obj # KeepIt
|
|
|
|
return obj
|
|
|
|
end
|
2003-06-18 19:45:12 +04:00
|
|
|
end
|
|
|
|
|
2016-05-15 14:59:00 +03:00
|
|
|
private
|
2003-06-18 19:45:12 +04:00
|
|
|
def peek(key)
|
2016-05-22 14:03:43 +03:00
|
|
|
return @renew.fetch(key) { @gc.fetch(key, @sentinel) }
|
2003-06-18 19:45:12 +04:00
|
|
|
end
|
|
|
|
|
2016-05-22 14:03:43 +03:00
|
|
|
def invoke_keeper
|
|
|
|
return if @expires
|
|
|
|
@expires = Time.now + @keeping
|
|
|
|
on_gc
|
|
|
|
end
|
|
|
|
|
|
|
|
def on_gc
|
|
|
|
return unless Thread.main.alive?
|
|
|
|
return if @expires.nil?
|
|
|
|
Thread.new { rotate } if @expires < Time.now
|
2016-05-22 14:03:44 +03:00
|
|
|
ObjectSpace.define_finalizer(Object.new) {on_gc}
|
2003-06-18 19:45:12 +04:00
|
|
|
end
|
|
|
|
|
2016-05-22 14:03:43 +03:00
|
|
|
def rotate
|
|
|
|
synchronize do
|
|
|
|
if @expires &.< Time.now
|
|
|
|
@gc = @renew # GCed
|
|
|
|
@renew = {}
|
|
|
|
@expires = @gc.empty? ? nil : Time.now + @keeping
|
2011-05-19 01:19:18 +04:00
|
|
|
end
|
|
|
|
end
|
2003-06-18 19:45:12 +04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-05-15 14:59:00 +03:00
|
|
|
# Creates a new TimerIdConv which will hold objects for +keeping+ seconds.
|
|
|
|
def initialize(keeping=600)
|
|
|
|
@holder = TimerHolder2.new(keeping)
|
2003-06-18 19:45:12 +04:00
|
|
|
end
|
|
|
|
|
2013-01-25 07:25:39 +04:00
|
|
|
def to_obj(ref) # :nodoc:
|
2003-06-18 19:45:12 +04:00
|
|
|
return super if ref.nil?
|
|
|
|
@holder.fetch(ref)
|
|
|
|
rescue TimerHolder2::InvalidIndexError
|
|
|
|
raise "invalid reference"
|
|
|
|
end
|
|
|
|
|
2013-01-25 07:25:39 +04:00
|
|
|
def to_id(obj) # :nodoc:
|
2003-06-18 19:45:12 +04:00
|
|
|
return @holder.add(obj)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# DRb.install_id_conv(TimerIdConv.new)
|