【问题标题】:Python : Locking text file on NFSPython:在 NFS 上锁定文本文件
【发布时间】:2016-06-04 19:03:02
【问题描述】:

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

如果进程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。

【问题讨论】:

  • 你能粘贴你使用fcntl.fcntl()的方式吗?
  • @vmonteco,我已经添加了代码 sn-p。
  • fcntl.fcntl(f, fcntl.LOCK_EX) 工作吗?
  • @vmonteco 它没有给出任何错误。但我不认为锁定正在被应用。我可以在两个不同的会话中在同一个文件上运行脚本,并且没有一个等待。

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


【解决方案1】:

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

引用项目page的作者:

[...] O_EXCL 在 NFS 文件系统上被破坏,程序依赖 它 用于执行锁定任务将包含竞争条件。这 使用 lockfile 执行原子文件锁定的解决方案是 在同一 fs 上创建一个唯一文件(例如,合并主机名和 pid),使用 link(2) 链接到锁定文件。如果链接()返回 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.")

这是一个对我有用的粗略实现。我一直在使用它,没有遇到任何问题。不过有很多可以改进的地方。希望这可以帮助。

【讨论】:

    猜你喜欢
    • 2010-09-07
    • 2010-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-14
    • 1970-01-01
    相关资源
    最近更新 更多