Não há uma verdadeira atomicidade na rede sem muita engenharia para fornecê-la, e quanto mais engenharia for necessária, mais complicada ela será.
Existem compromissos sérios a serem considerados. Essa resposta não oferece uma visão sobre o que fazer quando o trabalho está concluído pela metade.
O NFSv3 suporta um mecanismo de bloqueio atômico em novos kernels (bem, muito antigo para ser franco) link . Assim, algum mecanismo para um semáforo, em teoria, pode ser alcançado da seguinte maneira.
- Um arquivo 'done' já existe no host. (este é um sinal apenas para o script 2)
- Abra um arquivo 'acquire' no host usando
O_EXCL
.
- Renomeie "concluído" para "pronto.privado".
- Faça seu trabalho especial aqui.
- Abra um arquivo "feito no host usando
O_EXCL
.
- Desvincular 'done.old'.
- Desvincular 'adquirir'
Heres algum material de script de shell de modelo que tenta isso.
#!/bin/bash
# WARNING: This is a cricital line! NEVER EDIT THIS
set -e -o noclobber
BASEPATH=/tmp
cd "${BASEPATH}"
# 1. A done file exists on the host already (this is a signal for script 2 only)
# 2. Open an 'acquire' file on the host using 'O_EXCL'.
echo > 'acquire'
# 3. Rename 'done' to 'done.old'.
mv 'done' 'done.old' 2>/dev/null || :
# 4. Do your special work here.
echo "How much wood could a woodchuck chuck if a woodchuck could chuck wood?"
# 5. Open a 'done' file using O_EXCL
echo > 'done'
# 6. Unlink 'done.old'.
unlink 'done.old' || :
# 7. Unlink 'acquire'.
unlink 'acquire'
A linha mais importante é o set -e -o noclobber
, que serve a dois propósitos.
- Garante que, se algum comando falhar, o script sairá.
- O script não sobrescreve arquivos (faz com que ocorram no O_EXCL).
Dado o critério set
, a parte funcional mais importante é echo > acquire
, que abrirá atomicamente o arquivo de aquisição. Se isso falhar (porque outra pessoa o possui, mesmo que DOIS sejam abertos de uma vez, apenas um vencerá) a opção -e
de set
garante que o script seja encerrado.
Nunca deve haver dois desses scripts sendo executados em paralelo. Este script, no entanto, não oferece uma solução onde dois scripts são executados um após o outro (o que seria permitido em sua forma atual). Eu acho que a melhor maneira de fazer isso seria alterar o arquivo 'done' para ser um arquivo nomeado com timestamp que você procura pela existência antes que o processo comece. Assim, isso pressupõe que é "seguro" confiar no tempo como um meio para determinar a segurança da criticalidade do código.
Eu menciono que isso não é concreto. No momento, isso oferece a garantia de que dois processos não podem reivindicar o arquivo ao mesmo tempo. Como mencionado, mais modificações para permitir que ele não comece com a presença de um arquivo 'done' são necessárias.
Outras coisas não cobertas são:
- E se o processo começar, mas não terminar?
- Se o diretório compartilhado estiver indisponível antes ou na metade do caminho para lidar com isso.
- Se o host está demorando muito para fazer o material "seguro" na etapa 4, como isso afeta a próxima vez em que deseja executar? Devemos usar a instância antiga uma vez que sua instância acabada ou nova?
Para cobrir esses problemas, é necessário ter um mecanismo de 'vedação' (muita mudança de infraestrutura) para garantir que a recuperação do bloqueio em outro host seja uma operação segura.