【Webプログラミング - Code.011】CGI(Perl)ファイル処理 その4:「ファイルロック:flock 後編」

   Code.011                                                 2002年12月23日発行
■━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━■
                           【 Webプログラミング 】

                       〜 猫的プログラマーとその軌跡 〜
■━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━■

              ▼毎週月曜日に配信しています。
              ▼等幅フォントでご覧いただくとキレイに見えます。
              ▼登録・解除はこちらから可能です。
                < http://www.ichikoro.com/webp/ >
                  ※ぜひお友達にもご紹介ください(^^)/


○アンケートの受付期間を 12月29日(日) に延期します。
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 12月16日の配信時に募集しましたアンケートへのご応募、本当に
  ありがとうございます(^^)/ 今後の誌面作りの参考にさせていた
  だきたいと思います。

 さて、表題の通りアンケートの募集期間を一週間延期します。
 ご応募いただいた方の中から抽選で5名の方に1000円分のAmazon
 ギフト券があたる今回、現在の当選確率は何と55%(‾□‾;)!!

  まだの方はぜひご応募くださいませ。


 >>今号からご購読の皆様へ
 アンケートの性格上、一定期間ご購読いただいた方が対象となります。
 今後も、定期的にプレゼントつきのアンケートを実施する予定です。
  今回は申し訳ございませんがご遠慮ください。次回のご応募をお待ち
  しております(^^)

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 CGI(Perl)ファイル処理 その4:「ファイルロック:flock 後編」
──────────────────────────────────────
前回はflockを使用したファイルロック(排他制御)について解説しました。
しかし、flockの使用には注意が必要です。簡単に使用できる反面、間違った(危険な)
使い方をすると、使っていないのと同じくらいファイルが壊れやすくなります。
今回はどんな時に壊れるのか、その事例を紹介したいと思います。

↓前回の内容はコチラ
http://www.ichikoro.com/webp/bk/00055/


───────
   事例集
───────
今回は flock を使用したにも関わらずファイルが壊れてしまう(壊れやすい)、
期待していた動作と違う、そんな事例をいくつかご紹介したいと思います。


○開いた瞬間に真っ白
‾‾‾‾‾‾‾‾‾‾‾
    まずは最も有名で最も犯しやすい失敗をご紹介しましょう。
    下記のソースは一見正しいように見えますが...

        ;#
        ;#ファイルを逆順に記録する(失敗作)
        ;#
        use Fcntl;

        #----------------------------#
        #       情報を全て取得       #
        #----------------------------#
        open(DAT, "file.txt");            #読み込み専用モードで開く
        @buff = <DAT>;                    #ファイルの内容を全て @buff に
        close(DAT);

        #----------------------------#
        #       逆順に書き込む       #
        #----------------------------#
        open(DAT, ">file.txt");             #新規書き込みモード
        flock(DAT, LOCK_EX);                #ファイルロック
        foreach $line ( reverse @buff ){    #逆順で
            print DAT $line;                #ファイルに書き込み
        }
        close(DAT);

    問題となるのは、openした時点でファイルがすでに真っ白(0byte)に
    なっている点です。しかしopenした段階ではflockが効いていません。

>        open(DAT, ">file.txt");

    この段階で他のプロセスが「情報を全て取得」しようとした場合、
    そこにあるのは真っ白なファイルなワケです。掲示板やチャットなど
    で「ログが飛ぶ」のはこいつが原因の場合があります。

    これを改善するためにはいくつかの方法があります。


        ;#
        ;#ファイルを逆順に記録する(改善策 その1)
        ;#
        use Fcntl;

        #----------------------------#
        #       情報を全て取得       #
        #----------------------------#
        open(DAT, "file.txt");            #読み込み専用モードで開く
        @buff = <DAT>;                    #ファイルの内容を全て @buff に
        close(DAT);

        #----------------------------#
        #       逆順に書き込む       #
        #----------------------------#
        open(DAT, ">>file.txt");    #追加書き込みモード
        flock(DAT, LOCK_EX);        #ロックしてから
        truncate(DAT, 0);           #ファイルサイズを0byteに

        foreach $line ( reverse @buff ){    #逆順で
            print DAT $line;                #ファイルに書き込み
        }
        close(DAT);


    変更したのは2点、いずれも書き込む部分です。

        (1)いきなり新規書き込みモードではなく、追加書き込みモードに
        (2)flockをした後、ファイルを真っ白にする

    ポイントはファイルを開いた時点で真っ白にしないことです。
    さて、この問題に対する解決策はまだあります。

        ;#
        ;#ファイルを逆順に記録する(改善策 その2)
        ;#
        use Fcntl;

        #--------------------------#
        #      ファイルを開く      #
        #--------------------------#
        open(DAT, "+<file.txt");    #読み書きモードで開く
        flock(DAT, LOCK_EX);        #ロックしてから

        #--------------------------#
        #      情報を全て取得      #
        #--------------------------#
        @buff = <DAT>;

        #--------------------------#
        #      逆順に書き込む      #
        #--------------------------#
        truncate(DAT, 0);               #ファイルサイズを0byteに
        seek(DAT, 0, 0);                #念のため書き込む場所をファイルの先頭に
        foreach $line ( reverse @buff ){    #逆順で
            print DAT $line;                #ファイルに書き込み
        }
        close(DAT);

    このように、読み書きモードで開き一連の処理その物を
    ロックしてしまうという手もあります。


○flockを使わない物からは守れない
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
    これはflockを使う上での大前提です。
    下記のように二つのプログラムがあったとします。
        ※file.txtには整数の値が記録されている

        ;#
        ;#カウント数を1上げる(1pp.pl)
        ;#
        use Fcntl;

        #-------------------------------#
        #     ファイルの値に1足す       #
        #-------------------------------#
        open(DAT, "+<file.txt");    #読み書きモードで開く
        flock(DAT, LOCK_EX);        #ロックしてから

        #-------------------------------#
        #          一行目を取得         #
        #-------------------------------#
        $buff = <DAT>;

        #-------------------------------#
        #         ファイルに記録        #
        #-------------------------------#
        truncate(DAT, 0);           #ファイルサイズを0byteに
        seek(DAT, 0, 0);            #念のため書き込む場所をファイルの先頭に
        print DAT $buff + 1;        #ファイルに記録
        close(DAT);

    上記のソースはflockを使用し、正しく機能します。
    しかし下記のプログラムを同じ環境で同じように動作させたとすると...

        ;#
        ;#カウント数を2上げる(2pp.pl)
        ;#

        #-------------------------------#
        #     ファイルの値に2足す       #
        #-------------------------------#
        open(DAT, "+<file.txt");    #読み書きモードで開く

        #-------------------------------#
        #          一行目を取得         #
        #-------------------------------#
        $buff = <DAT>;

        #-------------------------------#
        #         ファイルに記録        #
        #-------------------------------#
        truncate(DAT, 0);           #ファイルサイズを0byteに
        seek(DAT, 0, 0);            #念のため書き込む場所をファイルの先頭に
        print DAT $buff + 2;        #ファイルに記録
        close(DAT);

    このプログラムを動作させたとたん、ファイルが壊れる確立は
    ググッと上がります。この解決は簡単で、2pp.plにflockを導入
    すればOKです。つまりflockは同じようにflock関数を使用してい
    る物しか上手い具合に機能してくれないのです。

    複数のCGIが同じファイルに書き込みをする場合にファイルが
    壊れる原因はココにある可能性があります。
        ※見つけるの大変なんですよね〜(^^;


○その他の事例
‾‾‾‾‾‾‾‾
・例えばWindows9X,MEのように、そもそもflockに対応していない
  環境があります。というかflock使っちゃうとプログラム自体が
  動きませんので使う前に気がつくと思いますが(^^;
    ※NT,2000では動作します。

・UNIXで使用される NFS(Network File System) 上では機能しません。
  別の手法を用いる必要があります。
    ※経験則ですが大抵のISPは使用してないと思われます。
      不安な方はサポートに連絡を。

・そもそもハードウェア的におかしい場合は、どんな手段を講じても
  壊れます(^^;
    ※ハードディスクに不良セクタがあるとか。
      強力な落雷の影響で突然電源が落ちたとか。


ようは壊れる時には壊れると言うことです(^^;
結論から言うと、大切なデータはきちんとバックアップしましょう、
ってな感じです。

───────
   次回予告
───────
小規模の個人サイトなどの場合は、flockを使っていれば、よほど運が
悪くなければ大抵大丈夫でしょう。バグに悩まされることはあるかも
しれませんが...。

次回はflock以外の手法を用いて、排他制御を行いたいと思います。


───────
   配信予定
───────
ファイル処理編の配信予定一覧です。

    ・CGI(Perl)ファイル処理 その1:「ファイルを読む」
      http://www.ichikoro.com/webp/bk/00053/
    ・CGI(Perl)ファイル処理 その2:「ファイルへの書き込み」
      http://www.ichikoro.com/webp/bk/00054/
    ・CGI(Perl)ファイル処理 その3:「ファイルロック:flock 前編」
      http://www.ichikoro.com/webp/bk/00055/

    ・CGI(Perl)ファイル処理 その4:「ファイルロック:flock 後編」<<今回
    ・CGI(Perl)ファイル処理 その5:「ファイルロック:mkdir編」
    ・CGI(Perl)ファイル処理 その6:「ディレクトリ操作」
    ・CGI(Perl)ファイル処理 その7:「DBMを使おう!」


以下にCGI(Perl)編で取り扱う大テーマをまとめてみました。

    ・CGI(Perl)基本動作【配信完了】
       クエリーの渡し方、受け取り方から文字コードのお話まで、
        CGIの基本的な動きや知っておかなければならないポイント
        を紹介しています。
          http://www.ichikoro.com/webp/bk/00046/

    ・CGI(Perl)ファイル処理
      ※現在配信中

    ・CGI(Perl)Cookie
    ・CGI(Perl)環境変数
    ・CGI(Perl)メール送受信

    ・CGI(Perl)文字列加工
    ・CGI(Perl)検索
    ・CGI(Perl)ソート
    ・CGI(Perl)暗号化

これ以降については未定です。
JavaScript(DHTML)とか、突然SOAP、XMLなんて可能性も。
掲示板、アクセスカウンターなど用途ごとに解説する
のも楽しそうですね。

    ○データベースはやらないの?
      PostgreSQL、MySQLなどのデータベースについては、
      CGI(Perl)の中で語るにはテーマが大きすぎるため
      大テーマとしてタイミングを見測ってゆっくり解説
      しようと思います。


これらの配信予定は都合により追加・変更・中止になる可能性が
あります。取り上げて欲しいテーマやご意見・ご要望はぜひ以下
までおよせください。

    ・BBS
      http://www.ichikoro.com/webp/bbs/

    ・メール
      mm-webp@ichikoro.com

───────
  分からない
───────
いまいちよく分からない場合は、以下へれっつらごー。

  ・サポートBBS
    このメルマガ専用のサポート掲示板です。
    疑問などがあったら、お気軽に書き込んでやってください(^^)/
      http://www.ichikoro.com/webp/bbs/

  ・CGIプログラミングML
    CGIなどWebに関する話題を繰り広げるメーリングリスト。
    このメルマガとは関係ありませんので発言時は注意を。
      http://www.ichikoro.com/cgi/ml/


━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 年末年始の発行予定
──────────────────────────────────────
早いものでもう年の瀬。
Webプログラミングの気になる(?)年末年始の発行スケジュールは
下記になります。

 ・2002年
   12/30(月) ← 発行します。
                2002年最終号!

 ・2003年
    1/ 6(月) ← お休みします
    1/13(月) ← 発行します。2003年初配信です。
    1/20(月) ← 発行します。これ以降は通常通りです。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
                           編    集    後    記
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
日本初の公認サンタクロース、知ってます?

クリスマスといえばなんと行ってもサンタガー...もといサンタさん!
会社で話題になっていたのですが、国際サンタクロース協会なる物が世の中には
あるそうで、世界各国の協会で行われる厳しい(?)試験に合格すると晴れてサンタ
クロースになれるという寸法だそうです。

で、日本人としてはパラダイス山本さんという方が公認のサンタ
さんなんだそうです。

    こどもにはナイショ!サンタのヒ・ミ・ツ!
    http://www.nifty.com/discover/special_1202/xmas/santa.htm

ちなみに試験の内容は、煙突から入り家の中にある大量のクッキーやビールを
食べ尽くし、また出てくるなどユーモラスな物だとか。

あ、そうそう。
実はこの試験を受けるためには前提条件がありまして、

  「既婚者で子供がいること」

が条件だそうです。
これでイブのプロポーズの台詞は決まった!?
  ※結婚できなくても当方では責任は取れませんのであしからず。

それでは、また来週お会いしましょう (^-^)/~~

#ネタの提供サンクスです > お姉さま方
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

                   【 Webプログラミング Code Sample 】

                    発  行 : ichikoro.com
                発行責任者 : 勝部 麻季人
                              < katsube@ichikoro.com >
                 Webサイト : < http://www.ichikoro.com/webp/ >
            お問い合わせ先 : < mm-webp@ichikoro.com >

                            Powerd by まぐまぐ
    All Right Reserved, CopyRight(C) 2001 Webプログラミング Code Sample
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■