In article <20020926134339.C8DAE1EE12 / milestones.dm4lab.to>,
  YANAGAWA Kazuhisa <kjana / dm4lab.to> writes:

> 別のファイルに書いて rename するとか,何かもっと安全な手段をとるべきだ
> と思うのですが,どうでしょうか.
> 
> # だいたい後に付けたパッチのような感じでいいのかな? ついでに abort し
> # たとき content を unref してないのも直してます.

lock しつつ rename という話はしばらく前に考えたことがあるんですが、も
うすこし複雑になると思います。

あるファイルを open して LOCK_EX な flock に成功した場合でも、それが即
座にロックを獲得したことにはなりません。これは他のプロセスがそのファイ
ルを rename によってすり替えてから終了した結果としてロックが解放された
からかもしれないからです。この場合、そのファイル名の最新のファイルに対
するロックが獲得できたわけではなく、unlink されてしまった意味のないファ
イルに対するロックが獲得できただけなので、やり直さないといけません。

しばらく前に次のようなのを書いたんですが、こんなかんじで flock した後
に stat して ino を比べ、必要に応じてやり直すような処置が必要ではない
でしょうか。

  def open_write(filename)
    dirname = File.dirname filename
    basename = File.basename filename
    tmpname = "#{dirname}/,#{basename},#$$"

    1.times {
      begin
        target = File.open(filename, File::RDWR|File::CREAT)
        stat1 = target.stat
        target.flock(File::LOCK_EX)
        stat2 = File.stat(filename)
        redo if stat1.ino != stat2.ino

        begin
          File.open(tmpname, 'w') {|tmp|
            yield tmp
          }
          stat2 = File.stat(filename)
          File.rename(tmpname, filename) if stat1.ino == stat2.ino
        ensure
          File.unlink tmpname if FileTest.exist? tmpname
        end
      ensure
        target.close
      end
    }
  end

  def open_read(filename, &block)
    File.open(filename, &block)
  end

あと、ついでにいえば "rb" で open したものには LOCK_EX できない OS も
あります。Solaris とか。

さらについでにいえば、flock より fcntl のほうが適切なこともあるようで
す。NFS ごしでも効く場合があるとか。
(手元で試した時には、Solaris と Linux では効いた。)
-- 
[田中 哲][たなか あきら][Tanaka Akira]
「ふえろ! わかめちゃん作戦です$(C⊇」(Little Worker, 桂遊生丸)