Pergunta

Estou executando um trabalho científico muito computacionalmente intensivo que cospe resultados de vez em quando. O trabalho é, basicamente, apenas para simular a mesma coisa que um monte de vezes, por isso é dividido entre vários computadores, que usam diferentes sistemas operacionais. Eu gostaria de direcionar a saída de todos esses casos para o mesmo arquivo, já que todos os computadores podem ver o mesmo sistema de arquivos via NFS / Samba. Aqui estão as restrições:

  1. Deve permitir Anexa simultâneas seguros. Deve bloquear se alguma outra instância em outro computador está anexando ao arquivo.
  2. Performance faz não contagem. E / S para cada ocorrência é de apenas alguns bytes por minuto.
  3. Simplicidade não conta. O ponto de toda esta (além de pura curiosidade) é para que eu possa parar de ter todos os write exemplo para um arquivo diferente e fusão manualmente esses arquivos juntos.
  4. não deve depender os detalhes do sistema de arquivos. Deve trabalhar com um sistema de arquivos desconhecido em um NFS ou Samba montar.

A linguagem que estou usando é D, caso em que importa. Eu olhei, não há nada na lib padrão que parece fazer isso. Ambos específico-D e geral, as respostas de linguagem agnóstico são totalmente aceitável e apreciada.

Foi útil?

Solução

Ao longo NFS você enfrenta alguns problemas com o cache do lado do cliente e dados obsoletos. Eu escrevi um módulo de bloqueio independente do sistema operacional para trabalho ao longo NFS antes. A simples ideia de criação de um arquivo [arquivo de dados] .lock não funciona bem sobre NFS. A idéia básica para o trabalho em torno dele é criar um arquivo de bloqueio [arquivo de dados] .lock que se o arquivo atuais meios não está bloqueado e um processo que pretende adquirir um bloqueio renomeia o arquivo para um nome diferente, como [arquivo de dados] .lock. [ máquina]. [PID]. A renomeação é uma operação atômica suficiente que funciona bem o suficiente sobre NFS para exclusividade garantia da fechadura. O resto é basicamente um conjunto de fail safe, loops, verificação de erros e recuperação de bloqueio no caso das matrizes do processo antes de liberar o bloqueio e renomeando o arquivo de bloqueio de volta para [arquivo de dados] .lock

Outras dicas

A solução clássica é usar um arquivo de bloqueio, ou mais precisamente um diretório de bloqueio. Em toda comum OSs criação de um diretório é uma operação atômica assim a rotina é:

  • tentar criar um diretório de bloqueio com um nome fixo em um local fixo
  • se a criar falhou, esperar um segundo ou assim e tente novamente - repita até que o sucesso
  • escrever seus dados para o arquivo de dados reais
  • excluir o diretório de bloqueio

Este tem sido utilizado por aplicações como CVS por muitos anos em várias plataformas. O único problema ocorre em raros casos em que a sua aplicação deixa de funcionar enquanto escrito e antes de remover o bloqueio.

Porque não basta construir um simples servidor que fica entre o arquivo e os outros computadores?

Então, se você sempre quis mudar o formato de dados, você só tem que modificar o servidor, e não todos os clientes.

Na minha opinião a construção de um servidor seria muito mais fácil do que tentar usar um sistema de arquivos de rede.

arquivo de bloqueio com uma torção

Como outras respostas já mencionado, o método mais fácil é criar um arquivo de bloqueio no mesmo diretório que o arquivo de dados.

Uma vez que você quer ser capaz de acessar o mesmo arquivo mais de múltiplos PC a melhor solução que eu posso pensar é apenas para incluir o identificador da máquina atualmente escrevendo para o arquivo de dados.

Assim, a seqüência para a escrita para o arquivo de dados seria:

  1. Verifique se existe um arquivo de bloqueio presente

  2. Se houver um arquivo de bloqueio, ver se eu sou o único possuí-lo, verificando que seu conteúdo tem o meu identificador.
    Se for esse o caso, basta escrever para o arquivo de dados, em seguida, exclua o arquivo de bloqueio.
    Se isso não for o caso, é só esperar um segundo ou um pequeno comprimento de tempo aleatório e tentar todo o ciclo novamente.

  3. Se não houver um arquivo de bloqueio, criar uma com o meu identificador e tente todo o ciclo novamente à condição de evitar corrida (re-check que o arquivo de bloqueio é realmente meu).

Junto com o identificador, eu iria gravar um timestamp no arquivo de bloqueio e verificar se é mais velho do que um determinado valor de tempo limite.
Se o timestamp é muito antiga, em seguida, assumir que o arquivo de bloqueio é obsoleto e apenas excluí-lo como seria mea um dos PC de escrita para o arquivo de dados pode ter caído ou sua conexão pode ter sido perdida.

Outra solução

Se você está no controle do formato do arquivo de dados, pode ser reservar uma estrutura no início do arquivo para registrar se ele está bloqueado ou não.
Se você apenas reservar um byte para essa finalidade, você poderia supor, por exemplo, que 00 significaria o arquivo de dados não está bloqueada, e que outros valores representariam o identificador da máquina atualmente escrevendo para ele.

problemas com NFS

OK, eu estou adicionando algumas coisas porque Jiri Klouda corretamente apontou que NFS cache usos do lado do cliente que resultará no arquivo de bloqueio real estar em um estado indeterminado.

Algumas maneiras de resolver esse problema:

  • montar o diretório NFS com as opções noac ou sync. Isso é fácil, mas não completamente a consistência dos dados de garantia entre cliente e servidor embora, então ainda pode haver problemas, embora no seu caso pode ser OK.

  • Abra o arquivo de bloqueio ou arquivo de dados usando o O_DIRECT, os O_SYNC ou O_DSYNC atributos. Isto é suposto para desativar o cache completamente.
    Isto irá reduzir o desempenho, mas irá garantir a consistência.

  • Você pode ser capaz de usar flock() para bloquear o arquivo de dados, mas a sua execução é irregular e você terá que verificar se o seu sistema operacional em particular realmente usa os NFS serviço de bloqueio. Pode não fazer nada contrário.
    Se o arquivo de dados está bloqueado, em seguida, uma outra abertura cliente-lo por escrito irá falhar.
    Ah sim, e isso não parece trabalhar em compartilhamentos SMB, por isso é provavelmente melhor apenas esquecê-lo.

  • Não use NFS e usar apenas Samba em vez disso: há um bom artigo sobre o assunto e por NFS provavelmente não é a melhor resposta para o seu cenário de uso.
    Você também vai encontrar neste artigo vários métodos para arquivos de bloqueio.

  • A solução de Jiri também é uma boa.

Basicamente, se você quiser manter as coisas simples, não usam NFS para arquivos freqüentemente atualizadas que são compartilhados entre várias máquinas.

Algo diferente

Use um servidor de banco de dados pequeno para salvar seus dados em e ignorar as questões NFS / bloqueio SMB completamente ou manter o seu atual sistema de arquivos de dados múltiplos e apenas escrever um pequeno utilitário para concatenar os resultados.
Ele ainda pode ser o simpl mais segura esolução est para o seu problema.

Não sei D, mas eu coisa usando um arquivo de exclusão mútua para fazer o trabalho jobe poder. Aqui estão algumas pseudo-código que você pode achar útil:

do {
  // Try to create a new file to use as mutex.
  // If it's already created, it will throw some kind of error.
  mutex = create_file_for_writing('lock_file');
} while (mutex == null);

// Open your log file and write results
log_file = open_file_for_reading('the_log_file');
write(log_file, data);
close_file(log_file);

close_file(mutex);
// Free mutex and allow other processes to create the same file.
delete_file(mutex); 

Assim, todos os processos vão tentar criar o arquivo de exclusão mútua, mas só quem ganha será capaz de continuar. Uma vez que você escrever sua saída, fechar e eliminar a exclusão mútua para que outros processos podem fazer o mesmo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top