Resumo

  • No NFSv2, uma operação de modificação voltava depois de alcançar armazenamento estável. Isso simplificava a recuperação sem estado, mas fazia cada escrita esperar pela mídia persistente.
  • O NFSv3 criou UNSTABLE, DATA_SYNC e FILE_SYNC; a resposta informava a quantidade realmente escrita, o nível atingido e um write verifier opaco.
  • O cliente mantinha os dados até um COMMIT ou resultado forte. Se o verifier mudasse, tratava os dados instáveis da instância anterior como possivelmente perdidos e os reenviava.

Sucesso sem permissão para esquecer

Um WRITE remoto recebe NFS3_OK. Ainda assim, committed pode valer UNSTABLE. A chamada funcionou e algum intervalo foi aceito, mas esses bytes talvez não sobrevivam ao desaparecimento da memória do servidor.

O RFC 1094 descrevia o NFSv2 com operações modificadoras síncronas. Ao receber a resposta, o cliente podia assumir armazenamento estável e descartar sua cópia. A regra combinava com o servidor stateless, porém colocava a latência de persistência em cada operação.

O RFC 1813 identificou esse caminho como gargalo de throughput. A escrita assíncrona “segura” do NFSv3 não declarou o dado durable cedo demais. Ela preservou cópia, estado e evidência até a dívida ser encerrada.

Três graus e dois números decisivos

O pedido escolhe UNSTABLE, DATA_SYNC ou FILE_SYNC. O último exige dados e metadados no armazenamento estável; DATA_SYNC exige dados e metadados suficientes para recuperá-los; UNSTABLE permite responder depois de persistir tudo, parte ou nada.

O retorno committed relata o que ocorreu, não apenas o que foi pedido. Um servidor pode entregar nível mais forte. O retorno count relata quantos bytes realmente foram escritos, pois short writes são permitidos. Assim, o status geral não prova nem o comprimento integral nem a durabilidade integral.

O terceiro elemento é verf. Esse cookie fica constante durante uma instância relevante do serviço e muda quando uma nova instância pode ter perdido dados não committed. Reinício é o exemplo comum. O objeto da prova é a continuidade da custódia volátil.

O verifier não é hash de arquivo. Igualdade não demonstra conteúdo correto, ausência de concorrência ou escrita completa. Mudança não demonstra que todos os bytes sumiram. Ela elimina a base para confiar no buffer da instância antiga.

A memória do cliente era parte do protocolo

Após uma resposta instável, o cliente guarda o buffer. RFC 1813 descreve três estados: dirty; done but needs to be committed; done. O estado intermediário é o preço do ganho de velocidade. O servidor pode agrupar flushes, enquanto o cliente mantém a capacidade de repetir.

COMMIT força os dados modificados antes devolvidos como instáveis para armazenamento estável. Pode operar sobre um intervalo; offset zero e count zero cobrem do início ao fim. A comparação com fsync é útil, mas não transforma o resultado em recibo de aplicação, backup ou integridade.

O COMMIT bem-sucedido devolve outro verifier. Se corresponder aos valores dos WRITEs, o cliente liga as duas etapas à mesma instância. Se for diferente, deve assumir que intervalos antigos com resultado UNSTABLE podem ter sido perdidos e reescrevê-los nos offsets conhecidos.

Essa recuperação é conservadora. Parte dos dados pode ter chegado ao disco antes da falha, mas falta evidência para separá-la. Repetir uma escrita idempotente é mais seguro que inventar certeza.

Estável tinha limite

RFC 1813 descreve armazenamento estável capaz de atravessar falhas repetidas de energia, certos defeitos de hardware e ciclos de crash e reboot. Exclui a falha do próprio módulo estável. Logo, durabilidade não significa replicação, backup, consistência lógica ou imortalidade.

O protocolo também não promete consistência estrita entre caches. Um intervalo durable pode coexistir com visão antiga em outro cliente. Persistência responde se os bytes sobrevivem; coordenação responde qual versão deveria prevalecer.

O mecanismo continuou no RFC 3530, no RFC 7530 e no NFSv4.1 do RFC 8881. Este último diz explicitamente que uma mudança do write verifier exige presumir perdidos os dados antigos retornados como UNSTABLE4 e recuperá-los.

Desempenho era redistribuição

O caminho normal ficou mais rápido porque a persistência pôde ser adiada e agrupada. O trabalho reapareceu como memória no cliente, mapas de intervalos, COMMITs e tráfego de replay após troca de instância. Assíncrono não significava gratuito; significava uma obrigação condicional com dono identificado.

O próprio cliente também pode falhar antes do COMMIT, possibilidade reconhecida pelo RFC 1813. Um caminho correto de recuperação oferecido pelo servidor não prova que o chamador o percorreu. A camada que anuncia conclusão de negócio precisa decidir se espera persistência, o que exige no fechamento e como trata um processo que desaparece com buffers ainda pendentes.

Responder com um nível mais forte que o solicitado permitia ainda transmitir a vantagem de uma implementação sem expor sua arquitetura. Um servidor com meio não volátil rápido podia devolver FILE_SYNC; o cliente liberava memória usando o resultado, sem adivinhar hardware. Um servidor menos capaz continuava interoperável ao declarar honestamente a obrigação aberta.

O COMMIT por intervalo criava uma escolha adicional. Intervalos menores podem liberar buffers cedo, mas multiplicam chamadas. Intervalos maiores agrupam trabalho, porém mantêm mais dados recuperáveis por mais tempo. A política define tanto o throughput quanto o tamanho da rajada que seguirá uma mudança do verifier.

Há também uma fronteira entre replay seguro e efeitos externos. Repetir bytes nos mesmos offsets é compatível com a recuperação desenhada pelo NFS, mas uma aplicação que associa a escrita a ações fora do arquivo precisa coordená-las separadamente. O write verifier não transforma uma operação de arquivo em transação distribuída.