Isso pode ser um pouco esotérico, mas tenho um tipo estranho de problema com stat ().
Especificamente - em um sistema Linux, com armazenamento NFS do Isilon montado. Eu tenho um processo que está obtendo diferenças de tempo ao executar fstat
no mesmo arquivo.
Eu posso reproduzir isso com um pouco de C, que não faz nada mais complicado que o open-write-stat-close; open-stat-close
E esses dois números - ocasionalmente - diferem em alguns milissegundos - um arquivo pode parecer "mais antigo" do que realmente é.
Não estou claro se o 'stat' está lendo a hora do host ou do servidor. E também não estou claro se o problema é com o Isilon (embora não pareça acontecer no armazenamento da NetApp).
Alguém pode me dar uma ideia do que pode estar acontecendo?
Como exemplo:
time mismatch: 1468936451.862865611 != 1468936451.860183107
O primeiro é o tempo lido quando o identificador de arquivo está aberto.
O segundo é o tempo lido após o fechamento (e fsync
).
Como você pode ver - o arquivo é um pouco mais antigo 'no servidor' do que no cliente.
O C
para testar isso é:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
int main ()
{
while (1)
{
struct stat sb[2];
/*
* Open file
*/
int fd = open ("test.dat", O_CREAT | O_RDWR | O_APPEND, 0644);
if (fd < 0)
{
perror ("failed to open file (1)");
return EXIT_FAILURE;
}
/*
* Write to it
*/
write (fd, "", 1);
/*
* Ensure it's sync'd to disk
*/
if (fsync (fd) < 0)
{
perror ("failed to fsync file");
return EXIT_FAILURE;
}
/*
* Stat the file
*/
if (fstat (fd, &(sb[0])) < 0)
{
perror ("failed to fstat file (1)");
return EXIT_FAILURE;
}
/*
* Close it
*/
close (fd);
/*
* Open file
*/
fd = open ("test.dat", O_RDONLY);
if (fd < 0)
{
perror ("failed to open file (2)");
return EXIT_FAILURE;
}
/*
* Stat it again
*/
if (fstat (fd, &(sb[1])) < 0)
{
perror ("failed to fstat file (2)");
return EXIT_FAILURE;
}
/*
* Close it
*/
close (fd);
/*
* Check the times match
*/
if (sb[0].st_mtime != sb[1].st_mtime ||
sb[0].st_mtim.tv_nsec !=sb[1].st_mtim.tv_nsec)
{
printf ("time mismatch: %d.%09ld != %d.%09ld\n",
(int)(sb[0].st_mtime), sb[0].st_mtim.tv_nsec,
(int)(sb[1].st_mtime), sb[1].st_mtim.tv_nsec);
}
}
}
E você pode acioná-lo executando isso em uma montagem NFS e, em seguida, chamando 'stat' (o comando shell é bom) de outro sistema. Por exemplo. no isilon em si:
while true
do
stat test.dat
done
Isso me causa erros como:
time mismatch: 1468936613.313045037 != 1468936613.310174576
time mismatch: 1468936613.547768543 != 1468936613.544878047
time mismatch: 1468936615.228495345 != 1468936615.225862947
time mismatch: 1468936619.036053897 != 1468936619.033362349
time mismatch: 1468936619.988151772 != 1468936619.985529620
time mismatch: 1468936664.541226541 != 1468936664.538549678
time mismatch: 1468936666.165674866 != 1468936666.163171366
time mismatch: 1468936666.787528027 != 1468936666.784797051
time mismatch: 1468936711.334376729 != 1468936711.331868927
E ... eu não acho que deveria.
Editar:
A plotagem fica mais espessa - ao executar os pacotes acima e capturar, a resposta da chamada NFS GETATTR do servidor é inconsistente. Eu recebo dois timestamps diferentes.
As opções de montagem não parecem fazer diferença, mas tentamos definir noac
e actimeo=0
, sync
lookupcache=none
etc.
Nossos nós isilon são todos sincronizados com ntp para as mesmas origens. Como de costume, há uma pequena quantidade de deriva entre eles.
Descobrimos que podemos aplicar uma solução alternativa na forma de isi export modify --zone <zoneid> <exportnumber> --time-delta 1
Isso define a resolução do timestamp como 1s em vez de 1ns. No entanto, embora diminua a frequência do problema que ocorre, isso ainda acontecerá - com menos frequência, porque ocorre apenas em um limite '1s'.