竟态条件 (wikipedia)
在上面锁文件的例子中,有一个竟态条件是不得不指出的,它存在于判断锁文件和创建锁文件之间。一个可行的解决方法是使用IO重定向和bash的noclobber(wikipedia)模式,重定向到不存在的文件。
可以这么做:
更复杂一点儿的问题是要更新一大堆文件,当它们更新过程中出现问题时,是否能让脚本挂得更加优雅一些。想确认那些正确更新了,哪些根本没有变化。比如需要一个添加用户的脚本。
当磁盘空间不足或者进程中途被杀死,这个脚本就会出现问题。在这种情况下,也许希望用户账户不存在,而且他的文件也应该被删除。
rollback() {
del_from_passwd $user
if [ -e /home/$user ]; then
rm -rf /home/$user
fi
exit
}
trap rollback INT TERM EXIT
add_to_passwd $user
cp -a /etc/skel /home/$user
chown $user /home/$user -R
trap - INT TERM EXIT
在脚本最后需要使用trap关闭rollback调用,否则当脚本正常退出的时候rollback将会被调用,那么脚本等于什么都没做。
保持原子化
又是需要一次更新目录中的一大堆文件,比如需要将URL重写到另一个网站的域名。
也许会写:
如果修改到一半是脚本出现问题,一部分使用www.example.com,而另一部分使用www.example.net。可以使用备份和trap解决,但在升级过程中的网站URL是不一致的。
解决方法:
将这个改变做成一个原子操作。先对数据做一个副本,在副本中更新URL,再用副本替换掉现在工作的版本。
需要确认副本和工作版本目录在同一个磁盘分区上,这样就可以利用Linux系统的优势,它移动目录仅仅是更新目录指向的inode节点。
这意味着如果更新过程出问题,线上系统不会受影响。线上系统受影响的时间降低为两次mv操作的时间,这个时间非常短,因为文件系统仅更新inode而不用真正的复制所有的数据。
缺点:
需要两倍的磁盘空间,而且那些长时间打开文件的进程需要比较长的时间才能升级到新文件版本,建议更新完成后重新启动这些进程。
对于 apache/ target=_blank class=infotextkey>apache服务器来说这不是问题,因为它每次都重新打开文件。
可以使用lsof命令查看当前正打开的文件。优势是有了一个先前的备份,当需要还原 时,它就派上用场了。