Python:在NFS上锁定文本文件

时间:2016-06-04 19:03:03

标签: python python-2.7 nfs file-locking fcntl

我在服务器上有一个文件results.txt,可由多个VM通过NFS访问。一个进程在每个VM上运行,这些VM读取results.txt文件并对其进行修改。如果两个进程AB同时读取该文件,则根据进程写入的顺序,results.txt中将出现对A或B的修改文件。

如果进程A对文件有写锁定,那么进程B必须等到释放锁才能读取results.txt文件。

我尝试使用Python实现它:

import fcntl


f = open("/path/result.txt")
fcntl.flock(f,fcntl.LOCK_EX)
#code

它可以正常工作在本地磁盘上。

但是当我运行尝试锁定已安装路径上的文件时,我收到以下错误:

Traceback (most recent call last):
  File "lock.py", line 12, in <module>
    fcntl.flock(f,fcntl.LOCK_EX)
IOError: [Errno 45] Operation not supported 

我尝试了fcntl.fcntlfcntl.flock,但却遇到了同样的错误。这是我使用fcntl的方式的问题吗?是否需要在存储文件的服务器上进行任何配置?

修改

这就是我使用fcntl.fcntl的方式:

f= open("results.txt")
lockdata = struct.pack('hhllhh', fcntl.F_RDLCK,0,0,0,0,0)
rv = fcntl.fcntl(f, fcntl.F_SETLKW, lockdata)

NFS服务器版本为3。

1 个答案:

答案 0 :(得分:3)

我发现flufl.lock最符合我的要求。

从项目page引用作者:

  

[...] O_EXCL在NFS文件系统上被破坏,这些程序依赖于   它           执行锁定任务将包含竞争条件。该           使用锁文件执行原子文件锁定的解决方案是           在相同的fs上创建一个唯一的文件(例如,合并主机名和           pid),使用link(2)建立到lockfile的链接。如果link()返回           0,锁定成功。否则,在唯一文件上使用stat(2)           检查其链接数是否增加到2,在这种情况下锁定           也很成功。

由于它不是标准库的一部分,我无法使用它。此外,我的要求只是该模块提供的所有功能的一部分。

以下功能是基于模块编写的。请根据要求进行更改。

def lockfile(target,link,timeout=300):                                             
        global lock_owner                                                          
        poll_time=10                                                               
        while timeout > 0:                                                         
                try:                                                               
                        os.link(target,link)                                       
                        print("Lock acquired")                                      
                        lock_owner=True                                            
                        break                                                      
                except OSError as err:                                             
                        if err.errno == errno.EEXIST:                              
                                print("Lock unavailable. Waiting for 10 seconds...")
                                time.sleep(poll_time)                              
                                timeout-=poll_time                                 
                        else:                                                      
                                raise err                                          
        else:                                                                      
                print("Timed out waiting for the lock.") 

def releaselock(link):                          
        try:                                    
                if lock_owner:                  
                        os.unlink(link)         
                        print("File unlocked")   
        except OSError:                         
                print("Error:didn't possess lock.")

这是一个适用于我的粗略实现。我一直在使用它,并没有遇到任何问题。有很多事情可以改进。希望这可以帮助。