重命名()primefaces性和NFS?

参照: 是rename()primefaces吗?

我正在问类似的问题,但不完全相同,因为我想知道的是在使用NFS时依赖rename()的primefaces性是否安全?

这是我正在处理的一个场景 – 我有一个“索引”文件,必须始终存在。

所以:

  • 客户端创build一个新文件
  • 客户端通过“旧”索引文件重命名新文件。

独立客户:

  • 读取索引文件
  • 指基于索引的磁盘结构。

这是假定rename()是primefaces的意思 – 总是会有一个'index'文件(尽pipe它可能是一个过时的版本,因为caching和时间)

然而,我遇到的问题是 – 这是发生在NFS上 – 正在工作 – 但我的几个NFS客户端偶尔会报告“ENOENT” – 没有这样的文件或目录。 (例如,在数百次操作中,每隔5m发生一次,我们每隔几天就会遇到这个错误)。

所以我希望的是,是否有人能够启发我 – 在这种情况下实际上是不可能获得“安心”的?

我问的原因是RFC 3530中的这个条目:

RENAME操作对于客户端必须是primefaces的。

我想知道这是否意味着只是客户端发出重命名,而不是客户端查看目录? (我可以使用caching/过时的目录结构,但是这个操作的重点是这个文件总是以某种forms出现)

操作顺序(从执行写入操作的客户端)是:

 21401 14:58:11 open("fleeg.ext", O_RDWR|O_CREAT|O_EXCL, 0666) = -1 EEXIST (File exists) <0.000443> 21401 14:58:11 open("fleeg.ext", O_RDWR) = 3 <0.000547> 21401 14:58:11 fstat(3, {st_mode=S_IFREG|0600, st_size=572, ...}) = 0 <0.000012> 21401 14:58:11 fadvise64(3, 0, 572, POSIX_FADV_RANDOM) = 0 <0.000008> 21401 14:58:11 fcntl(3, F_SETLKW, {type=F_WRLCK, whence=SEEK_SET, start=1, len=1}) = 0 <0.001994> 21401 14:58:11 open("fleeg.ext.i", O_RDWR|O_CREAT, 0666) = 4 <0.000538> 21401 14:58:11 fstat(4, {st_mode=S_IFREG|0600, st_size=42, ...}) = 0 <0.000008> 21401 14:58:11 fadvise64(4, 0, 42, POSIX_FADV_RANDOM) = 0 <0.000006> 21401 14:58:11 close(4) = 0 <0.000011> 21401 14:58:11 fstat(3, {st_mode=S_IFREG|0600, st_size=572, ...}) = 0 <0.000007> 21401 14:58:11 open("fleeg.ext.i", O_RDONLY) = 4 <0.000577> 21401 14:58:11 fstat(4, {st_mode=S_IFREG|0600, st_size=42, ...}) = 0 <0.000007> 21401 14:58:11 fadvise64(4, 0, 42, POSIX_FADV_RANDOM) = 0 <0.000006> 21401 14:58:11 fstat(4, {st_mode=S_IFREG|0600, st_size=42, ...}) = 0 <0.000007> 21401 14:58:11 fstat(4, {st_mode=S_IFREG|0600, st_size=42, ...}) = 0 <0.000007> 21401 14:58:11 read(4, "\3PAX\1\0\0O}\270\370\206\20\225\24\22\t\2\0\203RD\0\0\0\0\17\r\0\2\0\n"..., 42) = 42 <0.000552> 21401 14:58:11 close(4) = 0 <0.000013> 21401 14:58:11 fcntl(3, F_SETLKW, {type=F_RDLCK, whence=SEEK_SET, start=466, len=68}) = 0 <0.001418> 21401 14:58:11 pread(3, "\21@\203\244I\240\333\272\252d\316\261\3770\361#\222\200\313\224&J\253\5\354\217-\256LA\345\253"..., 38, 534) = 38 <0.000010> 21401 14:58:11 pread(3, "\21@\203\244I\240\333\272\252d\316\261\3770\361#\222\200\313\224&J\253\5\354\217-\256LA\345\253"..., 38, 534) = 38 <0.000010> 21401 14:58:11 pread(3, "\21\"\30\361\241\223\271\256\317\302\363\262F\276]\260\241-x\227b\377\205\356\252\236\211\37\17.\216\364"..., 68, 466) = 68 <0.000010> 21401 14:58:11 pread(3, "\21\302d\344\327O\207C]M\10xxM\377\2340\0319\206k\201N\372\332\265R\242\313S\24H"..., 62, 300) = 62 <0.000011> 21401 14:58:11 pread(3, "\21\362cv'\37\204]\377q\362N\302/\212\255\255\370\200\236\350\2237>7i`\346\271Cy\370"..., 104, 362) = 104 <0.000010> 21401 14:58:11 pwrite(3, "\21\302\3174\252\273.\17\v\247\313\324\267C\222P\303\n~\341F\24oh/\300a\315\n\321\31\256"..., 127, 572) = 127 <0.000012> 21401 14:58:11 pwrite(3, "\21\212Q\325\371\223\235\256\245\247\\WT$\4\227\375[\\\3263\222\0305\0\34\2049A;2U"..., 68, 699) = 68 <0.000009> 21401 14:58:11 pwrite(3, "\21\262\20Kc(!.\350\367i\253hkl~\254\335H\250.d\0036\r\342\v\242\7\255\214\31"..., 38, 767) = 38 <0.000009> 21401 14:58:11 fsync(3) = 0 <0.001007> 21401 14:58:11 fstat(3, {st_mode=S_IFREG|0600, st_size=805, ...}) = 0 <0.000009> 21401 14:58:11 open("fleeg.ext.i.tmp", O_RDWR|O_CREAT|O_TRUNC, 0666) = 4 <0.001813> 21401 14:58:11 fstat(4, {st_mode=S_IFREG|0600, st_size=0, ...}) = 0 <0.000007> 21401 14:58:11 fadvise64(4, 0, 0, POSIX_FADV_RANDOM) = 0 <0.000007> 21401 14:58:11 write(4, "\3PAX\1\0\0qT2\225\226\20\225\24\22\t\2\0\205;D\0\0\0\0\17\r\0\2\0\n"..., 42) = 42 <0.000012> 21401 14:58:11 stat("fleeg.ext.i", {st_mode=S_IFREG|0600, st_size=42, ...}) = 0 <0.000011> 21401 14:58:11 fchmod(4, 0100600) = 0 <0.002517> 21401 14:58:11 fstat(4, {st_mode=S_IFREG|0600, st_size=42, ...}) = 0 <0.000008> 21401 14:58:11 close(4) = 0 <0.000011> 21401 14:58:11 rename("fleeg.ext.i.tmp", "fleeg.pax.i") = 0 <0.001201> 21401 14:58:11 close(3) = 0 <0.000795> 21401 14:58:11 munmap(0x7f1475cce000, 4198400) = 0 <0.000177> 21401 14:58:11 munmap(0x7f14760cf000, 4198400) = 0 <0.000173> 21401 14:58:11 futex(0x7f147cbcb908, FUTEX_WAKE_PRIVATE, 2147483647) = 0 <0.000010> 21401 14:58:11 exit_group(0) = ? 21401 14:58:11 +++ exited with 0 +++ 

NB – 为了一致性,在上面重命名的path和文件。 fleeg.ext是数据文件,而fleeg.ext.i是索引。 在这个过程中, fleeg.ext.i文件被覆盖( .tmp文件),这就是为什么这个信念是应该总是有一个文件在这个path(旧的,或刚刚被覆盖的新文件它)。

阅读客户端PCAP看起来像LOOKUP NFS调用是失败的:

 124 1.375777 10.10.41.35 -> 10.10.41.9 NFS 226 LOOKUP fleeg.ext.i V3 LOOKUP Call, DH: 0x6fbbff3a/fleeg.ext.i 125 1.375951 10.10.41.9 -> 10.10.41.35 NFS 186 5347 LOOKUP 0775 Directory V3 LOOKUP Reply (Call In 124) Error: NFS3ERR_NOENT 126 1.375975 10.10.41.35 -> 10.10.41.9 NFS 226 LOOKUP fleeg.ext.i V3 LOOKUP Call, DH: 0x6fbbff3a/fleeg.ext.i 127 1.376142 10.10.41.9 -> 10.10.41.35 NFS 186 5347 LOOKUP 0775 Directory V3 LOOKUP Reply (Call In 126) Error: NFS3ERR_NOENT 

我认为问题不在于RENAME不是原子,而是通过NFS打开文件不是原子的。

NFS使用Filehandles; 为了对文件做一些事情,客户端首先通过LOOKUP获得文件句柄,然后获得的文件句柄被用来执行其他请求。 至少需要两个数据报,它们之间的时间在特定情况下可能相当“大”。

我想,发生在你身上的是一个客户(client1)执行一个LOOKUP; 在这之后,由于RENAME(由client2)LOOKUPed文件被擦除; Filehandle client1已经不再有效了,因为它引用了一个inode,而不是一个命名路径。

所有这一切的原因是NFS的目标是无国籍。 本PDF文件中的更多信息: http : //pages.cs.wisc.edu/~remzi/OSTEP/dist-nfs.pdf

在第6和8页中,这个行为是很好的解释。

在这种情况下,实际上不可能获得ENOENT吗?

这是很有可能。 RFC 3530说:

该操作对于客户来说是必需的。

这很可能意味着调用这个操作的客户必须是原子 ,而不是所有的客户。

并进一步说:

如果目标目录已经包含具有名称的条目…现有目标在重命名之前被删除。

这也是其他客户有时会得到ENOENT的原因。

换句话说,在NFS上rename不是原子的。

我想我现在已经知道发生了什么事情了。 我在这里添加它,因为虽然其他人对此很有帮助,但问题的实际根源是:

阅读主持人:

 79542 10.643148 10.0.0.52 -> 10.0.0.24 NFS 222 ACCESS allowed testfile V3 ACCESS Call, FH: 0x76a9a83d, [Check: RD MD XT XE] 79543 10.643286 10.0.0.24 -> 10.0.0.52 NFS 194 0 ACCESS allowed 0600 Regular File testfile NFS3_OK V3 ACCESS Reply (Call In 79542), [Allowed: RD MD XT XE] 79544 10.643335 10.0.0.52 -> 10.0.0.24 NFS 222 ACCESS allowed V3 ACCESS Call, FH: 0xe0e7db45, [Check: RD LU MD XT DL] 79545 10.643456 10.0.0.24 -> 10.0.0.52 NFS 194 0 ACCESS allowed 0755 Directory NFS3_OK V3 ACCESS Reply (Call In 79544), [Allowed: RD LU MD XT DL] 79546 10.643487 10.0.0.52 -> 10.0.0.24 NFS 230 LOOKUP testfile V3 LOOKUP Call, DH: 0xe0e7db45/testfile 79547 10.643632 10.0.0.24 -> 10.0.0.52 NFS 190 0 LOOKUP 0755 Directory NFS3ERR_NOENT V3 LOOKUP Reply (Call In 79546) Error: NFS3ERR_NOENT 79548 10.643662 10.0.0.52 -> 10.0.0.24 NFS 230 LOOKUP testfile V3 LOOKUP Call, DH: 0xe0e7db45/testfile 79549 10.643814 10.0.0.24 -> 10.0.0.52 NFS 190 0 LOOKUP 0755 Directory NFS3ERR_NOENT V3 LOOKUP Reply (Call In 79548) Error: NFS3ERR_NOENT 

写作主持人:

 203306 13.805489 10.0.0.6 -> 10.0.0.24 NFS 246 LOOKUP .nfs00000000d59701e500001030 V3 LOOKUP Call, DH: 0xe0e7db45/.nfs00000000d59701e500001030 203307 13.805687 10.0.0.24 -> 10.0.0.6 NFS 186 0 LOOKUP 0755 Directory NFS3ERR_NOENT V3 LOOKUP Reply (Call In 203306) Error: NFS3ERR_NOENT 203308 13.805711 10.0.0.6 -> 10.0.0.24 NFS 306 RENAME testfile,.nfs00000000d59701e500001030 V3 RENAME Call, From DH: 0xe0e7db45/testfile To DH: 0xe0e7db45/.nfs00000000d59701e500001030 203309 13.805982 10.0.0.24 -> 10.0.0.6 NFS 330 0,0 RENAME 0755,0755 Directory,Directory NFS3_OK V3 RENAME Reply (Call In 203308) 203310 13.806008 10.0.0.6 -> 10.0.0.24 NFS 294 RENAME testfile_temp,testfile V3 RENAME Call, From DH: 0xe0e7db45/testfile_temp To DH: 0xe0e7db45/testfile 203311 13.806254 10.0.0.24 -> 10.0.0.6 NFS 330 0,0 RENAME 0755,0755 Directory,Directory NFS3_OK V3 RENAME Reply (Call In 203310) 203312 13.806297 10.0.0.6 -> 10.0.0.24 NFS 246 CREATE testfile_temp V3 CREATE Call, DH: 0xe0e7db45/testfile_temp Mode: EXCLUSIVE 203313 13.806538 10.0.0.24 -> 10.0.0.6 NFS 354 0,0 CREATE 0755,0755 Regular File,Directory testfile_temp NFS3_OK V3 CREATE Reply (Call In 203312) 203314 13.806560 10.0.0.6 -> 10.0.0.24 NFS 246 SETATTR 0600 testfile_temp V3 SETATTR Call, FH: 0x4b69a46a 203315 13.806767 10.0.0.24 -> 10.0.0.6 NFS 214 0 SETATTR 0600 Regular File testfile_temp NFS3_OK V3 SETATTR Reply (Call In 203314) 

如果您打开相同的文件进行读取,这只是可重现的 – 所以除了一个简单的C写入重命名循环之外:

 #!/usr/bin/env perl use strict; use warnings; while ( 1 ) { open ( my $input, '<', 'testfile' ) or warn $!; print "."; sleep 1; } 

这导致我的测试案例很快(分钟)失败,而不是看起来没有。 它取决于文件句柄打开然后删除(或被RENAME覆盖)时创建的'.nfsXXX'文件。

因为NFS是无状态的,所以对于客户端来说它必须有一些持久性,所以它仍然可以像在本地文件系统上打开/关闭链接那样读/写该文件。 要做到这一点 – 我们得到一个双重的RENAME和一个非常简短的(亚毫秒)时间间隔,我们所针对的文件存在于LOOKUP NFS RPC中查找。