Il file append è atomico in UNIX?


106

In generale, cosa possiamo dare per scontato quando aggiungiamo a un file in UNIX da più processi? È possibile perdere dati (un processo sovrascrive le modifiche dell'altro)? È possibile che i dati vengano alterati? (Ad esempio, ogni processo aggiunge una riga per append a un file di registro, è possibile che due righe vengano alterate?) Se l'append non è atomica nel senso precedente, qual è il modo migliore per garantire l'esclusione reciproca?

Risposte:


65

Una scrittura di dimensioni inferiori a "PIPE_BUF" dovrebbe essere atomica. Dovrebbe essere almeno 512 byte, anche se potrebbe facilmente essere più grande (Linux sembra averlo impostato su 4096).

Questo presume che tu stia parlando di tutti i componenti completamente conformi a POSIX. Ad esempio, questo non è vero su NFS.

Ma supponendo che tu scriva in un file di registro che hai aperto in modalità "O_APPEND" e mantieni le tue righe (inclusa la nuova riga) sotto i byte "PIPE_BUF", dovresti essere in grado di avere più scrittori in un file di registro senza problemi di corruzione. Eventuali interruzioni arriveranno prima o dopo la scrittura, non a metà. Se vuoi che l'integrità del file sopravviva a un riavvio, dovrai anche chiamare fsync(2)dopo ogni scrittura, ma è terribile per le prestazioni.

Chiarimento : leggi i commenti e la risposta di Oz Solomon . Non sono sicuro che O_APPENDdovrebbe avere PIPE_BUFquell'atomicità di quella dimensione. È del tutto possibile che sia proprio come Linux è stato implementato write(), o potrebbe essere dovuto alle dimensioni dei blocchi del file system sottostante.


11
Su filesystem sani, fsync(2)offre la stessa garanzia che sync(2)ha e non ha un impatto così grande sulle prestazioni.
effimero

4
Sei sicuro di questo? Potresti fornire qualche link su quel comportamento? Ho trovato confermato se il descrittore è un pipe, ma non sono riuscito a trovare prove che funzionasse per qualsiasi file. inclusi gli oggetti file normali non NFS.
Alan Franzoni

6
Dove esattamente in ... / write.html? Per O_APPEND, non vedo alcuna menzione di PIPE_BUF, e vedo la promessa che "non si verificherà alcuna operazione di modifica del file tra la modifica dell'offset del file e l'operazione di scrittura" , ma non sono sicuro che questo significhi che l'operazione di scrittura stessa è ininterrotto ...
akavel

6
Come sottolinea questa risposta , l'affermazione su PIPE_BUFin quella pagina si applica solo a pipe e FIFO, non file regolari.
Greg Inozemtsev

3
Con i segnali in arrivo questo può peggiorare ulteriormente: bugzilla.kernel.org/show_bug.cgi?id=55651 . Perché questo è anche contrassegnato come una risposta? PIPE_BUF non ha nulla a che fare con i file.
assottigliato il

35

Modifica: aggiornato ad agosto 2017 con gli ultimi risultati di Windows.

Ti darò una risposta con collegamenti al codice di test e risultati come autore della proposta Boost.AFIO che implementa un filesystem asincrono e una libreria di file i / o C ++.

In primo luogo, O_APPEND o l'equivalente FILE_APPEND_DATA su Windows significa che gli incrementi dell'estensione massima del file ("lunghezza" del file) sono atomici con i writer simultanei. Questo è garantito da POSIX e Linux, FreeBSD, OS X e Windows lo implementano correttamente. Anche Samba lo implementa correttamente, NFS prima della v5 non lo fa in quanto manca della capacità di formato wire per essere aggiunto in modo atomico. Quindi, se apri il tuo file con solo aggiunta , le scritture simultanee non si interromperanno l'una rispetto all'altra su nessun sistema operativo principale a meno che non sia coinvolto NFS.

Tuttavia, le letture simultanee su aggiunte atomiche possono vedere scritture danneggiate a seconda del sistema operativo, del sistema di archiviazione e dei flag con cui hai aperto il file: l'incremento dell'estensione massima del file è atomico, ma la visibilità delle scritture rispetto alle letture può o meno essere atomico. Ecco un breve riepilogo per flag, sistema operativo e sistema di archiviazione:


No O_DIRECT / FILE_FLAG_NO_BUFFERING:

Microsoft Windows 10 con NTFS: aggiornamento atomicità = 1 byte fino a 10.0.10240 compreso, da 10.0.14393 almeno 1 Mb, probabilmente infinito (*).

Linux 4.2.6 con ext4: aggiornamento atomicità = 1 byte

FreeBSD 10.2 con ZFS: aggiornamento atomicità = almeno 1Mb, probabilmente infinito (*)

O_DIRECT / FILE_FLAG_NO_BUFFERING:

Microsoft Windows 10 con NTFS: aggiorna atomicity = fino a 10.0.10240 compreso fino a 4096 byte solo se pagina allineata, altrimenti 512 byte se FILE_FLAG_WRITE_THROUGH disattivato, altrimenti 64 byte. Si noti che questa atomicità è probabilmente una caratteristica del PCIe DMA piuttosto che progettata in. Dal 10.0.14393, almeno 1 Mb, probabilmente infinita (*).

Linux 4.2.6 con ext4: aggiornamento atomicità = almeno 1Mb, probabilmente infinito (*). Si noti che i precedenti Linux con ext4 non superavano sicuramente i 4096 byte, XFS sicuramente aveva un blocco personalizzato, ma sembra che Linux recente abbia finalmente risolto questo problema.

FreeBSD 10.2 con ZFS: aggiornamento atomicità = almeno 1Mb, probabilmente infinito (*)


Puoi vedere i risultati del test empirico grezzo su https://github.com/ned14/afio/tree/master/programs/fs-probe . Nota che testiamo gli offset strappati solo su multipli di 512 byte, quindi non posso dire se un aggiornamento parziale di un settore di 512 byte si interromperebbe durante il ciclo di lettura-modifica-scrittura.

Quindi, per rispondere alla domanda dell'OP, le scritture O_APPEND non interferiranno tra loro, ma le letture simultanee alle scritture O_APPEND probabilmente vedranno scritture strappate su Linux con ext4 a meno che O_DIRECT non sia attivo, dopodiché le tue scritture O_APPEND dovrebbero essere un multiplo di dimensioni di settore.


(*) "Probabilmente infinito" deriva da queste clausole nelle specifiche POSIX:

Tutte le seguenti funzioni devono essere atomiche l'una rispetto all'altra negli effetti specificati in POSIX.1-2008 quando operano su file regolari o collegamenti simbolici ... [molte funzioni] ... read () ... write ( ) ... Se due thread chiamano ciascuno una di queste funzioni, ogni chiamata vedrà tutti gli effetti specificati dell'altra chiamata o nessuno di essi. [Fonte]

e

Le scritture possono essere serializzate rispetto ad altre letture e scritture. Se è possibile dimostrare (con qualsiasi mezzo) che una read () dei dati di un file si verifica dopo una write () dei dati, deve riflettere tale write (), anche se le chiamate vengono effettuate da processi diversi. [Fonte]

ma al contrario:

Questo volume di POSIX.1-2008 non specifica il comportamento delle scritture simultanee su un file da più processi. Le applicazioni dovrebbero utilizzare una qualche forma di controllo della concorrenza. [Fonte]

Puoi leggere di più sul significato di questi in questa risposta


29

Ho scritto uno script per testare empiricamente la dimensione massima di aggiunta atomica. Lo script, scritto in bash, genera più processi di lavoro che scrivono tutti firme specifiche del lavoratore nello stesso file. Quindi legge il file, cercando firme sovrapposte o danneggiate. Puoi vedere la fonte dello script in questo post del blog .

La dimensione effettiva massima di aggiunta atomica varia non solo in base al sistema operativo, ma in base al file system.

Su Linux + ext3 la dimensione è 4096 e su Windows + NTFS la dimensione è 1024. Vedere i commenti di seguito per ulteriori dimensioni.


Con quale filesystem hai testato su Linux? Mi chiedo se forse si basa sulle dimensioni dei blocchi del filesystem.
freiheit

@freiheit credo di averlo provato su ext3. Se lo esegui su un altro FS e ottieni un risultato diverso, per favore pubblica un commento.
Oz Solomon

3
@OzSolomon, ho usato il tuo script su Debian 7.8 e sono stato in grado di ottenere solo scritture atomiche fino a 1008 byte inclusi (1024-16 byte di overhead?) Sia sulla mia partizione ext4 che su un montaggio tmpfs. Qualunque cosa oltre a ciò si traduceva sempre in corruzione.
Eric Pruitt

6
Il tuo test sembra presumere che echo $line >> $OUTPUT_FILErisulterà in una singola chiamata a writeindipendentemente dalle dimensioni di $line.
Tomas

16

Ecco cosa dice lo standard: http://www.opengroup.org/onlinepubs/009695399/functions/pwrite.html .

Se il O_APPENDflag dei flag di stato del file è impostato, l'offset del file deve essere impostato alla fine del file prima di ogni scrittura e non deve verificarsi alcuna operazione di modifica del file tra la modifica dell'offset del file e l'operazione di scrittura.


20
"tra" - ma per quanto riguarda gli interventi durante la scrittura, che per la mia comprensione avvengono dopo il "tra"? (Ie: <change_offset_action> ... "the_between_period" ... <write_action>) - devo capire che non ci sono garanzie al riguardo?
akavel

@akavel concordato; non c'è alcuna garanzia che la scrittura stessa sia atomica. Ma sono confuso: in base alla garanzia fornita nel tuo preventivo, sembra che possiamo concludere che un'app multithread che aggiunge lo stesso file non mescolerà parti di record scritti diversi. Tuttavia, dagli esperimenti riportati da OzSolomon, vediamo che anche quell'ipotesi è violata. Perché?
max

@max mi dispiace, temo di non ricevere la tua domanda: in primo luogo, l'esperimento di OzSolomon è multi- processo , non un'app multi- thread (processo singolo); in secondo luogo, non capisco come si tragga la conclusione che "un'app multithread [...] non si mischierà" - è esattamente ciò che non vedo garantito dalla citazione di Bastien, come ho menzionato nel mio commento. Puoi chiarire la tua domanda?
akavel

2
Hmm non posso ricostruire la mia logica al momento in cui ho scritto quel commento ... Sì, se la tua interpretazione è corretta, ovviamente i diversi record potrebbero essere mescolati. Ma ora che sto rileggendo la citazione di Bastien, penso che debba significare che nessuno può interrompere "durante la scrittura" - altrimenti l'intero paragrafo dello standard sarebbe inutile, non fornendo letteralmente alcuna garanzia (nemmeno che la scrittura avverrà alla fine, poiché qualcun altro potrebbe spostare l'offset mentre viene eseguito il passaggio di "scrittura".
max
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.