锁定档案
时间:2008-03-21 来源:剑心通明
任何一个脚本在存取分享档案时,就像是记录档一样,都需要一个可信赖的方法来锁住档案,这么一来,其他的脚 本程序就无法修改这个档案了。我们可以利用发讯号的方式来识别已锁定的档案,并告知此档目前在使用中,不能够存取。要求存取档案的脚本等待并且再要求,希 望档案可以很快的不受限制,意指解除档案的锁定。
锁定档案的工作是很难处理的。以下的例子是一个典型的处理方式,它可以解释这类型的问题:
while [ -f $lockfile ] ; do
sleep 1
done
touch $lockfile
看起来像是移除锁定了不是吗?你的循环会到锁定档案不见了才停止,之后会建立一个锁定档以确认档案可以安全的修改。如果有任何的程序要存取这个档 案,必须等到锁定档消失后才可正常运作。不过,实际上它沒有运作,因为当输到其他程序时,这个程序并沒有作交换的动作。试想会发生什么事:A程式在执行完 loop循环之后与返回到touch之前。B程序取代了它,这个B程序发现系统中沒有锁定档,自行建立了一个锁定档,而此时A程序回来了,并且尝试去存 取,这两个程序都各自认为它们是唯一有权存取这个挡案的,这下是不是很糟糕呢?
幸好,Stephen van den Berg与Philip Guenther这两个作者写了procmail的邮件过滤程式,里头包含lockfile的命令,让我们可以安全地在系统上正常的使用锁定档。许多的 Unix家族,包括Linux与Mac OS X都已经安装了lockfile程式,你可以利用man 1 lockfile来检查此档是否存在,如果你看到说明页,表示已存在,如果沒看到,请先从http://www.procmail.org/网站上下载procmail,之后再在系统上安装lockfile命令。笔者假设在你已经有lockfile指令了,本章以后如果有需要这个档案我们不会再多做敘述。
脚本源代码
#!/bin/sh
# filelock - A flexible file locking mechanism.
retries="10" # default number of retries
action="lock" # default action
nullcmd="/bin/true" # null command for lockfile
while getopts "lur:" opt; do
case $opt in
l ) action="lock" ;;
u ) action="unlock" ;;
r ) retries="$OPTARG" ;;
esac
done
shift $(($OPTIND - 1))
if [ $# -eq 0 ] ; then
cat << EOF >&2
Usage: $0 [-l|-u] [-r retries] lockfilename
Where -l requests a lock (the default), -u requests an unlock, -r X
specifies a maximum number of retries before it fails (default = $retries).
EOF
exit 1
fi
# Ascertain whether we have lockf or lockfile system apps
if [ -z "$(which lockfile | grep -v '^no ')" ] ; then
echo "$0 failed: 'lockfile' utility not found in PATH." >&2
exit 1
fi
if [ "$action" = "lock" ] ; then
if ! lockfile -1 -r $retries "$1" 2> /dev/null; then
echo "$0: Failed: Couldn't create lockfile in time" >&2
exit 1
fi
else # action = unlock
if [ ! -f "$1" ] ; then
echo "$0: Warning: lockfile $1 doesn't exist to unlock" >&2
exit 1
fi
rm -f "$1"
fi
exit 0
运行脚本
我们如果只执行一个lockfile程序可能无法看出它的功能,因此建议你开两个终端窗口,分别执行这个程序。建立锁定档时,请在filelock程序后多加一个要锁定的挡名,移除锁定档时,请加上-u参数。
结果
第一、建立一个锁定档:
$ filelock /tmp/exclusive.lck
$ ls -l /tmp/exclusive.lck
-r--r--r-- 1 taylor wheel 1 Mar 21 15:35 /tmp/exclusive.lck
第二、试图锁定档案,filelock预设会试10次,之后会失败,如同以下的结果:
$ filelock /tmp/exclusive.lck
filelock : Failed: Couldn't create lockfile in time
当第一个动作完成后,你可以试著解除档案的锁定:
$ filelock -u /tmp/exclusive.lck
为了更清楚filelock的运作,我们可以开2个终端窗口,当A窗口在试著建立自己独占的锁定档时,同时也在B窗口中执行unlock命令。
改进与加强
由于锁定档案的动作是靠确认锁定档存不存在而决定。因此如果能在程序执行的过程中,透过参数的方式,指定锁定档的锁定时间,或许会让工作发挥更大的 效用。如果锁定的时间点已经到了,程序要能检查锁定档最后一次存取的时间,如果这个值比指定的参数还要久,程序便能移除锁定档,当然如果想要做的更理想一 点,可以再给使用者一个警告信息。另外,Lockfile程式无法在NFS的挂载磁盘上工作,可能不会对你造成任何的影响。但是,事实上要在NFS挂载磁 盘上作业是很复杂的一件事,因此直接在本地端锁定档案或许是一个比较完美的做法。