こんにちは。

Tanaka Akira wrote on the <87bro6b9dn.fsf / serein.a02.aist.go.jp>
>read only のときには書き戻さずに .new から読むだけにすればいいのでは?

あ,それでよさそうですね。
こんな感じ。あと,ついでにread onlyのときに[]=, delete()をエラーにする
ようにしています。

*** pstore.rb.orig	2004-02-08 20:30:25.000000000 +0900
--- pstore.rb	2004-02-14 01:24:25.864753912 +0900
***************
*** 35,41 ****
    def in_transaction
      raise PStore::Error, "not in transaction" unless @transaction
    end
!   private :in_transaction
  
    def [](name)
      in_transaction
--- 35,45 ----
    def in_transaction
      raise PStore::Error, "not in transaction" unless @transaction
    end
!   def in_transaction_wr()
!     in_transaction()
!     raise PStore::Error, "in read-only transaction" if @rdonly
!   end
!   private :in_transaction, :in_transaction_wr
  
    def [](name)
      in_transaction
***************
*** 52,62 ****
      self[name]
    end
    def []=(name, value)
!     in_transaction
      @table[name] = value
    end
    def delete(name)
!     in_transaction
      @table.delete name
    end
  
--- 56,66 ----
      self[name]
    end
    def []=(name, value)
!     in_transaction_wr()
      @table[name] = value
    end
    def delete(name)
!     in_transaction_wr()
      @table.delete name
    end
  
***************
*** 86,112 ****
    def transaction(read_only=false)
      raise PStore::Error, "nested transaction" if @transaction
      begin
        @transaction = true
        value = nil
!       backup = @filename+"~"
!       begin
! 	file = File::open(@filename, read_only ? "rb" : "rb+")
! 	orig = true
!       rescue Errno::ENOENT
! 	raise if read_only
! 	file = File::open(@filename, "wb+")
        end
!       file.flock(read_only ? File::LOCK_SH : File::LOCK_EX)
!       if read_only
! 	@table = Marshal::load(file)
!       elsif orig and (content = file.read) != ""
  	@table = Marshal::load(content)
! 	size = content.size
! 	md5 = Digest::MD5.digest(content)
! 	content = nil		# unreference huge data
        else
  	@table = {}
        end
        begin
  	catch(:pstore_abort_transaction) do
  	  value = yield(self)
--- 90,127 ----
    def transaction(read_only=false)
      raise PStore::Error, "nested transaction" if @transaction
      begin
+       @rdonly = read_only
+       @abort = false
        @transaction = true
        value = nil
!       new_file = @filename + ".new"
! 
!       content = nil
!       file = File.open(@filename, File::RDWR | File::CREAT)
!       if !read_only
!         file.flock(File::LOCK_EX)
!         commit_new() if FileTest.exist?(new_file)
!         content = file.read()
!       else
!         file.flock(File::LOCK_SH)
!         if FileTest.exist?(new_file)
!           File.open(new_file) {|fp| content = fp.read()}
!         else
!           content = file.read()
!         end
        end
! 
!       if content != ""
  	@table = Marshal::load(content)
!         if !read_only
!           size = content.size
!           md5 = Digest::MD5.digest(content)
!         end
        else
  	@table = {}
        end
+       content = nil		# unreference huge data
+ 
        begin
  	catch(:pstore_abort_transaction) do
  	  value = yield(self)
***************
*** 116,139 ****
  	raise
        ensure
  	if !read_only and !@abort
! 	  file.rewind
  	  content = Marshal::dump(@table)
  	  if !md5 || size != content.size || md5 != Digest::MD5.digest(content)
! 	    File::copy @filename, backup
! 	    begin
! 	      file.write(content)
! 	      file.truncate(file.pos)
! 	      content = nil		# unreference huge data
! 	    rescue
! 	      File::rename backup, @filename if File::exist?(backup)
! 	      raise
! 	    end
! 	  end
! 	end
! 	if @abort and !orig
! 	  File.unlink(@filename)
  	end
- 	@abort = false
        end
      ensure
        @table = nil
--- 131,147 ----
  	raise
        ensure
  	if !read_only and !@abort
!           tmp_file = @filename + ".tmp"
  	  content = Marshal::dump(@table)
  	  if !md5 || size != content.size || md5 != Digest::MD5.digest(content)
!             File.open(tmp_file, "w") {|t|
!               t.write(content)
!             }
!             File.rename(tmp_file, new_file)
!             commit_new()
!           end
!           content = nil		# unreference huge data
  	end
        end
      ensure
        @table = nil
***************
*** 142,147 ****
--- 150,164 ----
      end
      value
    end
+ 
+   private
+   def commit_new()
+     new_file = @filename + ".new"
+     if !File.copy(new_file, @filename)
+       raise IOError
+     end
+     File.unlink(new_file)
+   end
  end
  
  if __FILE__ == $0

-- 
HORIKAWA Hisashi (in Kanji: 堀川 久)
Netsphere Laboratories  http://www.nslabs.jp/