1require 'drb/drb' 2require 'monitor' 3 4module DRb 5 6 # Timer id conversion keeps objects alive for a certain amount of time after 7 # their last access. The default time period is 600 seconds and can be 8 # changed upon initialization. 9 # 10 # To use TimerIdConv: 11 # 12 # DRb.install_id_conv TimerIdConv.new 60 # one minute 13 14 class TimerIdConv < DRbIdConv 15 class TimerHolder2 # :nodoc: 16 include MonitorMixin 17 18 class InvalidIndexError < RuntimeError; end 19 20 def initialize(timeout=600) 21 super() 22 @sentinel = Object.new 23 @gc = {} 24 @curr = {} 25 @renew = {} 26 @timeout = timeout 27 @keeper = keeper 28 end 29 30 def add(obj) 31 synchronize do 32 key = obj.__id__ 33 @curr[key] = obj 34 return key 35 end 36 end 37 38 def fetch(key, dv=@sentinel) 39 synchronize do 40 obj = peek(key) 41 if obj == @sentinel 42 return dv unless dv == @sentinel 43 raise InvalidIndexError 44 end 45 @renew[key] = obj # KeepIt 46 return obj 47 end 48 end 49 50 def include?(key) 51 synchronize do 52 obj = peek(key) 53 return false if obj == @sentinel 54 true 55 end 56 end 57 58 def peek(key) 59 synchronize do 60 return @curr.fetch(key, @renew.fetch(key, @gc.fetch(key, @sentinel))) 61 end 62 end 63 64 private 65 def alternate 66 synchronize do 67 @gc = @curr # GCed 68 @curr = @renew 69 @renew = {} 70 end 71 end 72 73 def keeper 74 Thread.new do 75 loop do 76 alternate 77 sleep(@timeout) 78 end 79 end 80 end 81 end 82 83 # Creates a new TimerIdConv which will hold objects for +timeout+ seconds. 84 def initialize(timeout=600) 85 @holder = TimerHolder2.new(timeout) 86 end 87 88 def to_obj(ref) # :nodoc: 89 return super if ref.nil? 90 @holder.fetch(ref) 91 rescue TimerHolder2::InvalidIndexError 92 raise "invalid reference" 93 end 94 95 def to_id(obj) # :nodoc: 96 return @holder.add(obj) 97 end 98 end 99end 100 101# DRb.install_id_conv(TimerIdConv.new) 102