2012-09-04 19 views
6

C'è una regione nel file (possibile piccola) che desidero sovrascrivere. Suppongo che chiami fseek, fwrite, fsync. Esiste un modo per garantire l'atomicità di tale operazione di riscrittura delle regioni, ad es. Ho bisogno di essere sicuro, che in ogni caso di fallimento la regione conterrà solo vecchi dati (prima della modifica), o solo nuovi (modificati) dati, ma non un mix di questo.Modifica file atomico

Ci sono due cose che voglio evidenziare.

Prima: E 'ok se non v'è alcun modo per scrivere atomicamente qualsiasi regione dimensioni - siamo in grado di gestirlo aggiungendo dati al file, fsync'ing, e poi riscrivere 'puntatore' zona nel file, poi di nuovo fsyncing . Tuttavia, se la scrittura "pointer" non è atomica, possiamo comunque avere file corrotti con puntatori illegali.

Secondo: Sono sicuro che scrivere regioni di 1 byte è atomico: non vedrò nel file alcun byte che non ho mai inserito. Quindi possiamo usare alcuni trucchi con l'allocazione di due regioni per gli indirizzi e utilizzare lo switch da 1 byte, quindi riscrivere la regione è diventato - aggiungere nuovi dati, sincronizzare, riscrivere uno dei due (non utilizzati) slot del puntatore, sincronizzare di nuovo e quindi riscrivere 'switch byte 'e di nuovo sincronizzato. Quindi l'operazione di sovrascrittura ora contiene almeno 3 invocazioni fsync.

Tutto questo sarebbe molto più semplice, se avrò la scrittura atomica per i lunghi, ma ce l'ho davvero?

C'è un modo per gestire questa situazione senza utilizzare il metodo, di cui al punto 2?

Un'altra domanda è: c'è qualche garanzia di ordine tra scrittura e sincronizzazione? Ad esempio, se chiamo fseek, fwrite [1], fseek, fwrite [2], fsync, posso scrivere a [2] commited, e scrivere a [1] - not commit?

Questa domanda è applicabile al sistema operativo linux e windows, qualsiasi risposta particolare (ad esempio in Ubuntu versione a.b.c ....) è anche desiderata.

+0

[fsync] (http://linux.die.net/man/3/fsync) sembra essere abbastanza implementazione/filesystem dipendente. http://blogs.gnome.org/alexl/2009/03/16/ext4-vs-fsync-my-take/ – zapl

+0

Quello di cui parli è noto come "controllo del commit" o "commit/rollback", o "transazioni". –

+0

(L'unico modo (quasi) completamente affidabile di fare ciò che vuoi, in assenza di una funzione di elaborazione delle transazioni sulla scatola, è quello di fare il vecchio scambio di file: copia il vecchio file in nuovo, cambia nuovo, rinomina nuovo per sostituire vecchio.) –

risposta

1

In genere è sicuro assumere che la scrittura di blocchi da 512 byte sia eseguita in una sola scrittura dagli HDD. Tuttavia, non lo darei per scontato. Invece, andrei con la tua seconda soluzione, aggiungendo un checksum alla tua scrittura e verificandola prima di cambiare il puntatore nel file.

Generalmente, è una buona pratica aggiungere il checksum a tutto ciò che è stato scritto sul disco.

Per rispondere alla garanzia di "sincronizzazione", è possibile presumere che. Mentre la sincronizzazione è dipendente da FS e disco, diciamo che stiamo parlando di un'implementazione "ragionevole".

  • Dopo il 1 ° sync è garantita I dati da verranno scaricati sul disco (il disco potrebbe avere nel suo nascondiglio ancora) e se i dati ci si aspetta di ottenere ciò che hai scritto.
  • Se dopo il secondo sync i dati di entrambe le sincronizzazioni si trovano nella cache del disco, la situazione descritta può verificarsi, ma IMHO la probabilità è molto bassa.

In ogni caso, non esiste un altro meccanismo che garantisca che i dati siano su disco. Ecco perché il tuo deve avere il checksum.

qualche informazione in più: Ensure fsync did its job

+0

Grazie per la risposta. A proposito della garanzia di "sincronizzazione", puoi fornirmi una "prova" per questa ipotesi? Oppure, viene da alcuni (cosa?) Codice sorgente di tracciamento/esperto (che?) Consigliare? – andll

+0

ha aumentato la risposta con alcune informazioni. – Drakosha