Linuxサーバ関連情報 > PerlでNFS上のファイルロックの仕方

Perlでよく使われるflockはNFS上のファイルをロックする保障がされていません。
そこでfcntlを使ってファイルロックすることにします。

NFS上のファイルをflockでファイルロックできるのか?検証

Debian Etchを使ってNFS上のファイルをflockでロックするとどうなるか?
ロックはできましたが、ロックが開放されません。プロセスが終了すればロックが解除されますが、同じプログラム内で2回以上ロックするような処理では 画面が固まってしまう現象がありました。
他にもロックすらできない現象もありますが、kernelのバージョンとNFSのバージョンによって挙動はさまざまです。 比較的に新しいkernelとNFSのバージョンでおかしな挙動をするようです。

fcntlを使ってみよう

perlでファイルロックの仕方はflock以外にもlockfやfcntlがありますが、今回はfcntlを使ったファイルロックの仕方を説明します。

#!/usr/bin/perl

use Fcntl;

my $filepath = '/home/hoge/test.txt';
my $sdata = 'test';

# ロックのオプションを設定
my ($locked) = pack("ssL", Fcntl::F_WRLCK, 'SEEK_SET', 0);   
# ロック解除のオプションを設定
my ($unlocked) = pack("ssL", Fcntl::F_UNLCK, 'SEEK_SET', 0);   

# ファイルオープン
open(F, "+< $filepath") or &error($filepath);

# ロック
fcntl(F, F_SETLK, $locked) or &error('ロックできませんでした。'." $$ @_: $!");   

# ファイル書き込み
truncate(F, 0);
seek(F, 0, 0);
print(F $sdata);

# 解除
fcntl(F, F_SETLK, $unlocked) or &error('ロック解除できませんでした。');   

close(F);

print "Content-type: text/html; charset=EUC-JP\n\n";
print "OK!";
exit;


sub error {
   my $data = shift;
   print "Content-type: text/html; charset=EUC-JP\n\n";
   print $data;
   exit;
}

① ②
fcntlの第3の引数に渡す構造体を作成します。perlの場合、packする必要があります。


fcntl関数でロックします。
第1引数:ファイルハンドラ
第2引数:オプションです。今回ロックするために必要なオプションを紹介します。
【F_SETLK】ファイルのロックする場合、既にロックされている場合エラーを返します。
【F_SETLKW】ファイルのロックをする場合、既にロックされている場合は解除されるまで待ちます。
第3引数:① ②でpackしたスカラー変数


ロックしたファイルを解除します。この一行を書かなくても、ファイルをcloseすればロックは解除されます。

NFS上でファイルをロックするためのサーバ設定

NFS上のファイルをロックするためにはNFSサーバ側とマウントする側のどちらにもstatdとlockdが必要になります。
DEBIANの場合apt-get install nfs-commonしてnfs-commonを起動するとstatdとlockdが立ち上がります。
これをしないとNFS上のファイルをロックできません。