2013-06-11 12 views
5

Ho un'applicazione Node.js che memorizza alcuni dati di configurazione in un file. Se si modificano alcune impostazioni, il file di configurazione viene scritto sul disco.Scrittura transazionale di file in Node.js

Al momento, sto usando un semplice fs.writeFile.

Ora la mia domanda è: cosa succede quando Node.js si arresta in modo anomalo durante la scrittura del file? C'è la possibilità di avere un file danneggiato su disco? Oppure Node.js garantisce che il file sia scritto in modo atomico, in modo che la vecchia o la nuova versione siano valide?

In caso negativo, come posso implementare tale garanzia? Ci sono dei moduli per questo?

risposta

7

Cosa succede quando Node.js si arresta in modo anomalo durante la scrittura del file? c'è la possibilità di avere un file corrotto sul disco? Oppure Node.js garantisce che il file sia scritto in modo atomico, in modo che sia la vecchia o la nuova versione sia valida?

Il nodo implementa solo un (sottile) involucro asincrono sulle chiamate di sistema, pertanto non fornisce alcuna garanzia sull'atomicità delle scritture. Infatti, fs.writeAll chiama ripetutamente lo fs.write fino a quando non vengono scritti tutti i dati. Hai ragione quando Node.js si arresta in modo anomalo, potresti finire con un file danneggiato.

In caso negativo, come è possibile implementare tale garanzia? Ci sono dei moduli per questo?

La soluzione più semplice che riesco a trovare è quella utilizzata per es. per gli upload FTP:

  1. Salvare il contenuto in un file temporaneo con un nome diverso.
  2. Quando il contenuto è scritto su disco, rinominare il file temporaneo nel file di destinazione.

Il man page dice che rinominare garanzie di lasciare un'istanza di newpath in luogo (sui sistemi Unix, come Linux o OSX).

+0

Posso confermare che in OSX questo non risolve il problema del tutto, tuttavia riduce l'incidenza della corruzione dei file –

6

fs.writeFile, proprio come tutti gli altri metodi nel modulo fs sono implementati come semplici wrapper attorno alle funzioni POSIX standard (come indicato nello docs).

Scavando un bit nel codice del nodo, si può vedere che lo fs.js, in cui sono definiti tutti i wrapper, utilizza fs.c per tutte le sue chiamate al file system. Più specificamente, il metodo write viene utilizzato per scrivere il contenuto del buffer. Si scopre che la POSIX specification per la scrittura dice esplicitamente che:

atomica/non-atomica: Una scrittura è atomico se l'intero importo scritto in un'operazione non è intercalati con dati provenienti da qualsiasi altro processo. Questo è utile quando ci sono più scrittori che inviano dati a un singolo lettore . Le applicazioni devono sapere quanto è grande che una richiesta di scrittura possa essere eseguita atomicamente. Questo massimo è chiamato {PIPE_BUF}. Questo volume di IEEE Std 1003.1-2001 non dice se le richieste di scrittura di per più di {PIPE_BUF} sono atomiche, ma richiede che le scritture di {PIPE_BUF} o meno byte siano atomiche.

Quindi sembra che sia abbastanza sicuro scrivere, purché la dimensione del buffer sia inferiore a PIPE_BUF. Questa è una costante che dipende dal sistema, quindi potrebbe essere necessario controllarlo da qualche altra parte.

+0

Secondo http://manpages.courier-mta.org/htmlman7/pipe.7.html, PIPE_BUF è richiesto di essere almeno 512 byte e in Linux è 4.096 byte. Grazie per avermelo fatto notare, dato che questo è davvero interessante e interessante da sapere :-) –

2

write-file-atomic farà quello che ti serve. Scrive in un file temporaneo, quindi rinomina. Questo è sicuro.