Domanda

Sto scrivendo un programma, una sorta di banca dati. Mentre leggevo manuale di fclose(3) ho scoperto che chiama fflush(3) per ripulire i buffer FILE* su disco (in realtà a OS buffer, ma non importa in questo momento, si può sempre chiamare fsync(2)).

Perché io sto scrivendo un DB è ovvio che voglio evitare perdite di dati. Se non c'è spazio su disco e fflush(3) in fclose(3) fallisce - ci perderemo i nostri dati, in quanto

  

utilizzando FILE* dopo un errore in fclose() causerà un comportamento indefinito

Così ho pensato a uso esplicito di fflush(3) prima fclose(3), mettere in guardia utente circa lo spazio su disco a basso e il richiamo fflush(3) dopo un po '.

Ho letto il C di serie e pensato che questa fosse una buona idea. In pratica, dopo aver fallito fflush la seconda chiamata sarebbe sempre tornare 0 (nessun errore), ma sarebbe in realtà fare nulla. fsync non mi ha aiutato (ho pensato che i dati potrebbero essere salvati in RAM).

Come posso evitare la perdita di dati in una situazione del genere? Forse ci sono alcune regole pratiche.

Ecco il mio codice di prova:

#include <stdio.h>
int main()
{
    FILE *a = fopen("/tmp/1", "wb")
    if ( !a )
        perror("fopen");

    if ( fwrite("test", 1, 4, a) != 4 )
        perror("fwrite");  // always OK, cause data is buffered


    while( fflush(a) )  // ...second call will always return 0!
    {
        perror("fflush");  // if there is no disk space, I will get this perror, but ...
    }


    if ( fclose(a) )  // always ok, because calls only close(2)
        perror("fclose"); 

    return 0;
}
È stato utile?

Soluzione

La ragione operazioni la successiva fflush () successo è che non ci sono (nuovi) dati da scrivere su disco. Il primo fflush () non è riuscito; che è tragica ma la storia. Il fflush successiva () non ha nulla a che fare, quindi lo fa con successo.

Se si sta scrivendo in un database, bisogna stare attenti a ogni processo di scrittura - non solo affrontare i problemi alla fine. A seconda della criticità i vostri dati è, potrebbe essere necessario passare attraverso tutti i tipi di giravolte per affrontare i problemi - non ci sono ragioni per cui DBMS sono complesse, e non è riuscito scritture sono uno di loro

.

Un modo di affrontare il problema è quello di pre-allocare lo spazio per i dati. Come altri hanno notato, classici sistemi di file Unix consentire file sparsi (file dove ci sono blocchi vuoti senza spazio su disco assegnato per loro), in modo da avere in realtà scrivere alcuni dati su ogni pagina che avete bisogno assegnato. Poi si deve solo preoccuparsi di 'disco pieno' problemi quando si estende lo spazio -. E si sa quando fai così e si può fare con questo fallimento con attenzione

Sui sistemi basati su Unix, ci sono una serie di chiamate di sistema che possono aiutare a sincronizzare i dati su disco, e opzioni per 'aprire' ecc Questi includono il 'O_DSYNC' e valori correlati. Tuttavia, se si sta estendendo un file, possono ancora causare errori di 'fuori dallo spazio', anche con le opzioni di sincronizzazione di fantasia. E quando si esegue in quel fallimento, bisogna aspettare per lo spazio diventi disponibile (perché hai chiesto all'utente di dirvi quando è disponibile, forse), e quindi provare nuovamente la scrittura.

Altri suggerimenti

Si potrebbe preallocare qualche ragionevole quantità di spazio su disco. Scrivere, a filo, e fsync alcuni zeri binari (o altro) e poi cercare di nuovo a dove eravate. Risciacquare e ripetere se necessario. E ricordate per troncare, se necessario.

Un po 'di dolore, ma dovrebbe funzionare.

fflush sarà svuotare solo i buffer interni C della libreria per il sistema operativo, in modo da un fflush non garantisce che non ci saranno perdite di dati.

La chiamata fflush più volte (senza fwrites intermedi) non aiuterà, come avete già lavata i dati al sistema operativo una volta. La seconda chiamata fflush tornerà SUCCESSO quanto v'è non per irrigare al sistema operativo. Se non riesce a causa fflush disco rigido è pieno, hai già perso alcuni dati.

Per lavare i dati sul disco, è necessità per usare fsync.

Se il disco rigido è pieno, si è fuori di fortuna. L'unico modo per prevenire la perdita di dati è quello di mantenere ora il processo vivo (ed i dati in memoria: o nello spazio utente / buffer dei file del kernel) fino a trovare un pò di spazio sul disco per fsync a. Ora, se il potere esce, è perdere i dati.

In breve, non c'è modo si può garantire alcuna perdita di dati se il disco rigido è pieno.

Si potrebbe fseek (3) alla fine del file (supponendo che ci si conosce la lunghezza) prima di fare qualcosa. In questo modo ci si elimina la possibilità di fallimento a causa di spazio su disco insufficiente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top