けいじゅ@日本ラショナルソフトウェアです.

pstoreに関してですが, transactionをコミットしたあとでも @table の参照
が残ったままですよね? marshalした後, @table = nil とした方がよかないで
すか? 今のままだと, @tableの内容がGCの対象になりません.

そんでもって, いいの考えました. キャッシュ機能付きPStoreです.

コミットした後, @tableの参照しているインスタンスをWeakRefを用いて保存
しておいて, 次にtransactionを開始した時に, GCされずに残っていたらそれ
をそのまま使う方法です. 

こうすると, 読み込みのコストが下がる可能性が高くなっるのでよいと思いま
せん?

-- ここから
#
# How to use:
#
# db = PStoreWC.new("/tmp/foo")
# db.transaction do
#   p db.roots
#   ary = db["root"] = [1,2,3,4]
#   ary[0] = [1,1.5]
# end

# db.transaction do
#   p db["root"]
# end

require "pstore"
require "weakref"

class PStoreWC < PStore
  
  def initialize(file)
    super
    @cache = nil
  end

  def transaction
    raise PStore::Error, "nested transaction" if @transaction
    begin
      @transaction = true
      value = file = nil
      if @cache and @cache.weakref_alive?
	@table = @cache[]
      else
	begin
	  File::open(@filename, "r") do |file|
	    @table = Marshal.load(file)
	  end
	rescue Errno::ENOENT
	  @table = {}
	end
      end
      begin
	catch(:pstore_abort_transaction) do
	  value = yield(self)
	end
      rescue Exception
	@abort = true
	raise
      ensure
	unless @abort
	  begin
	    File::rename @filename, @filename+"~"
	  rescue Errno::ENOENT
	    no_orig = true
	  end
	  begin
	    File::open(@filename, "w") do |file|
	      Marshal::dump(@table, file)
	      @cache = WeakRef.new(@table)
	    end
	  rescue
	    File::rename @filename+"~", @filename unless no_orig
	  end
	end
	@abort = false
      end
    ensure
      @transaction = false
    end
    value
  end
end

PSWC = PStoreWC

if __FILE__ == $0
  db = PStoreWC.new("/tmp/foo")
  db.transaction do
    p db.roots
    ary = db["root"] = [1,2,3,4]
    ary[0] = [1,1.5]
  end

  db.transaction do
    p db["root"]
  end

  ObjectSpace.garbage_collect

  db.transaction do
    p db["root"]
  end
  
end


__
..............................石塚 圭樹@日本ラショナルソフトウェア...
----------------------------------->> e-mail: keiju / rational.com <<---