From: YANAGAWA Kazuhisa Date: 2002-09-26T22:43:39+09:00 Subject: [ruby-dev:18391] pstore.rb can make a broken store # お願いされたから書いてみよう :-) psore.rb はファイルに書き込むとき rewind して write して truncate して ますが,これだと外から SIGKILL を送られたりする中途半端な書き込みになっ て,データが壊れてしまうんじゃないかと思います. 別のファイルに書いて rename するとか,何かもっと安全な手段をとるべきだ と思うのですが,どうでしょうか. # だいたい後に付けたパッチのような感じでいいのかな? ついでに abort し # たとき content を unref してないのも直してます. それとは別ですが.... thread safe じゃないというか,複数のスレッドから アクセスすると nested transaction で例外があがるっていうのはちょっと変 な気がします. 方針の問題にもなりますが.1 プロセスでは高々一つのトランザクションしか 走らないっていうのも,それはそれで有りかも.それでも nested はうそだし な,と. -- 柳川和久 @ 東大阪市 . 大阪府 September 26, 2002 No gains without pains. *** pstore.rb.orig Thu Sep 26 22:37:50 2002 --- pstore.rb Thu Sep 26 22:39:16 2002 *************** *** 88,90 **** begin ! file = File::open(@filename, "rb+") orig = true --- 88,90 ---- begin ! file = File::open(@filename, "rb") orig = true *************** *** 92,94 **** raise if read_only ! file = File::open(@filename, "wb+") end --- 92,94 ---- raise if read_only ! file = File::open(@filename, "wb") end *************** *** 115,117 **** if !read_only && !@abort - file.rewind content = Marshal::dump(@table) --- 115,116 ---- *************** *** 120,124 **** begin ! file.write(content) ! file.truncate(file.pos) ! content = nil # unreference huge data rescue --- 119,123 ---- begin ! tmpname = "%s.%d.%d"%[@filename, Process::pid, Time.now.to_i] ! File::open(tmpname, "wb") {|f| f.write(content)} ! File::rename tmpname, @filename rescue *************** *** 126,127 **** --- 125,128 ---- raise + ensure + content = nil # unreference huge data end