diff --git a/ChangeLog b/ChangeLog index 322ddd7d13..4a52a64046 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Sun May 22 20:01:21 2016 Masatoshi SEKI + + * lib/drb/timeridconv.rb: use finalizer trick instead of thread. + + * test/drb/ut_timerholder.rb: ditto. + Sun May 22 17:25:18 2016 Martin Duerst * test/ruby/enc/test_case_options.rb: adjust test class name diff --git a/lib/drb/timeridconv.rb b/lib/drb/timeridconv.rb index 7e2a6cf998..0f45f4a08e 100644 --- a/lib/drb/timeridconv.rb +++ b/lib/drb/timeridconv.rb @@ -24,7 +24,7 @@ module DRb @gc = {} @renew = {} @keeping = keeping - @expires = Time.now + @keeping + @expires = nil end def add(obj) @@ -32,18 +32,16 @@ module DRb rotate key = obj.__id__ @renew[key] = obj + invoke_keeper return key end end - def fetch(key, dv=@sentinel) + def fetch(key) synchronize do rotate obj = peek(key) - if obj == @sentinel - return dv unless dv == @sentinel - raise InvalidIndexError - end + raise InvalidIndexError if obj == @sentinel @renew[key] = obj # KeepIt return obj end @@ -51,25 +49,28 @@ module DRb private def peek(key) - synchronize do - return @renew.fetch(key) { @gc.fetch(key, @sentinel) } - end + return @renew.fetch(key) { @gc.fetch(key, @sentinel) } + end + + 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 + ObjectSpace.define_finalizer(Object.new) {on_gc} end def rotate synchronize do - return if @expires > Time.now - @gc = @renew # GCed - @renew = {} - @expires = Time.now + @keeping - end - end - - def keeper - Thread.new do - loop do - rotate - sleep(@keeping) + if @expires &.< Time.now + @gc = @renew # GCed + @renew = {} + @expires = @gc.empty? ? nil : Time.now + @keeping end end end diff --git a/test/drb/ut_timerholder.rb b/test/drb/ut_timerholder.rb index 252c7bd228..1753b30c74 100644 --- a/test/drb/ut_timerholder.rb +++ b/test/drb/ut_timerholder.rb @@ -12,7 +12,6 @@ class TimerIdConvTest < Test::Unit::TestCase key = idconv.to_id(self) assert_equal(key, self.__id__) sleep(keeping) - assert_equal(idconv.to_id(false), false.__id__) assert_equal(idconv.to_obj(key), self) sleep(keeping) @@ -24,11 +23,48 @@ class TimerIdConvTest < Test::Unit::TestCase sleep(keeping) assert_raise do - assert_equal(idconv.to_obj(key)) + assert_equal(idconv.to_obj(key), self) end assert_raise do - assert_equal(idconv.to_obj(false.__id__)) + assert_equal(idconv.to_obj(false.__id__), false) + end + + key = idconv.to_id(self) + assert_equal(key, self.__id__) + assert_equal(idconv.to_id(true), true.__id__) + sleep(keeping) + GC.start + sleep(keeping) + GC.start + assert_raise do + assert_equal(idconv.to_obj(key), self) + end + end + + def test_usecase_02 + keeping = 0.1 + idconv = DRb::TimerIdConv.new(keeping) + + key = idconv.to_id(self) + assert_equal(key, self.__id__) + sleep(keeping) + GC.start + sleep(keeping) + GC.start + assert_raise do + assert_equal(idconv.to_obj(key), self) + end + GC.start + + key = idconv.to_id(self) + assert_equal(key, self.__id__) + sleep(keeping) + GC.start + sleep(keeping) + GC.start + assert_raise do + assert_equal(idconv.to_obj(key), self) end end end