File system virtuale di sola scrittura per la memorizzazione di file in archivio


8

Ho un processo imbarazzantemente parallelo che crea una quantità enorme di file quasi (ma non completamente) identici. C'è un modo per archiviare i file "al volo", in modo che i dati non consumino più spazio del necessario?

Il processo stesso accetta i parametri della riga di comando e stampa il nome di ciascun file creato su stdout. Lo sto invocando con il parallel --gnuquale si occupa di distribuire l'input (che proviene da un altro processo) e di raccogliere l'output:

arg_generating_process | parallel --gnu my_process | magic_otf_compressor

ESEMPIO SEMPLICE per la prima parte del tubo in bash:

for ((f = 0; $f < 100000; f++)); do touch $f; echo $f; done

Come potrebbe magic_otf_compressorapparire? Dovrebbe trattare ogni riga di input come nome file, copiare ogni file in un .tararchivio compresso (lo stesso archivio per tutti i file elaborati!) E quindi eliminarlo. (In realtà, dovrebbe essere sufficiente stampare il nome di ciascun file elaborato, un altro | parallel --gnu rmpotrebbe occuparsi di eliminare i file.)

Esiste un tale strumento? Non sto pensando di comprimere ogni file singolarmente, questo perderebbe troppo spazio. Ho esaminato archivemount(manterrà il file system in memoria -> impossibile, i miei file sono troppo grandi e troppi) e avfs(non riuscivo a farlo funzionare insieme a FUSE). Cosa mi sono perso?

Sono solo a un passo dall'hacking di un tale strumento, ma qualcuno deve averlo fatto prima ...

EDIT : Essenzialmente penso di essere alla ricerca di un front-end stdin per libtar(al contrario del front-end della riga di comando tarche legge gli argomenti, beh, dalla riga di comando).


Hai pensato di scrivere file in un formato con compressione nativa? Ad esempio, hdf5 può essere compresso poiché sono scritti con compressione gzip o szip. Hdf5 supporta anche MPI, quindi funziona bene con quei problemi imbarazzanti paralleli.
Casey,

2
Se vuoi compressione e deduplicazione, mi viene in mente zfs.
Stéphane Chazelas,

@casey: è HTML, ma suppongo che potrei usare un contenitore HDF5. Non l'ho ancora considerato.
krlmlr

@StephaneChazelas: può essere implementato in userland?
krlmlr

Risposte:


1

Sembra tarvoler conoscere tutti i nomi dei file in anticipo. Quindi è meno al volo e più dopo il volo. cpionon sembra avere questo problema:

| cpio -vo 2>&1 > >(gzip > /tmp/arc.cpio.gz) | parallel rm

Grazie. Quindi, anche RTFM non è abbastanza ;-) Ho anche cercato nel tarcodice per vedere che c'è una funzione che restituisce il nome del file successivo da elaborare, il che mi ha fatto leggere di nuovo la documentazione. - Quindi, stdoutviene indirizzato al gzipprocesso tramite la sostituzione del processo e stderrviene reindirizzato a stdoutquale processo viene elaborato dal passaggio successivo nella pipe?
krlmlr,

Sì. Il costrutto>> () non funziona in tutte le shell, ma funziona in Bash.
Ole Tange,

Posso confermare che tarlegge prima l'elenco dei file, usando il semplice esempio che ho aggiunto alla mia domanda. Tuttavia, leggendo di nuovo il tarcodice sorgente , mi sembra che dovrebbe leggere l'elenco dei file "al volo" se non si crea un archivio incrementale. Sfortunatamente, ho errori di compilazione tardal sorgente ... :-(
krlmlr

Non ho trovato un modo per sopprimere la riga finale nell'output di cpio, diverso da grep -v 'blocks$'. ( head -n -1usa un buffer molto grande ...) Rende questa soluzione un po 'un trucco, ma non importa ;-)
krlmlr

@krlmlr che è strano: il mio head -n -1usa solo 16 MB quando eseguito su pochi GB di dati. Puoi sempre usare perl: perl -ne 'print $ last; $ last = $ _'
Ole Tange

7

Un caso classico di RTFM (tutto!) . L' -Topzione per GNU tarleggerà i file da archiviare da un altro file (nel mio caso, /dev/stdinpuoi anche usare -), e c'è anche --remove-filesun'opzione:

alias magic_otf_compressor='tar --create -T - --remove-files -O | pixz'

(usando la versione parallela di xzper la compressione, ma puoi usare invece il tuo compressore preferito). Da usare come:

arg_generating_process |
  parallel --gnu my_process |
  magic_otf_compressor > file.tar.xz

EDIT : Come sottolinea Ole, tarsembra leggere l'intero elenco di file con l' -Topzione per qualche motivo. Il seguente test lo conferma:

for ((f = 0; $f < 1000; f++)); do
    touch $f; echo $f;
done | tar -c -f otf.tar -T - -v

C'è un ritardo di un secondo sul mio sistema prima che tutti i file vengano stampati contemporaneamente; al contrario, se il tarcomando viene sostituito da cat, tutti i file vengono stampati man mano che vengono creati. Ho presentato una richiesta di supporto con la gente del tar, vediamo.

EDIT ^ 2 : il più recente tardal sorgente risolve questo problema. Non è ancora in Ubuntu 13.10, ma potrebbe essere incluso con 14.04.


1

In qualche modo questo non sembra un buon lavoro per un compressore solido (archiviatori basati su nastro + compressione). L'inserimento di file uno dopo l'altro sembra un lavoro zipo un altro formato che consente l'accesso casuale ai file all'interno dell'archivio e l'inserimento incrementale.

Il fatto che i file siano simili non aiuterà molto in entrambi i casi. In zip, i file vengono compressi separatamente e in compressori solidi, di solito c'è una finestra all'interno della quale avviene la compressione.

Se i file sono basati su testo, è possibile memorizzare differenze rispetto a un singolo file di riferimento. Per i binari, è un po 'più complicato ma può essere fatto.

C'è anche un modo formale (non solo di scrittura, ma file system appropriati). Ad esempio, i filesystem ZFS e BTRFS offrono una compressione trasparente. Puoi anche utilizzare questo http://developer.berlios.de/projects/fusecompress


I miei file sono circa 100k ciascuno. Non sarebbe sufficiente per consentire al compressore di utilizzare una finestra, diciamo, 1M? xzsembra funzionare con una dimensione del dizionario predefinita di 8 M (al livello di compressione predefinito -6), che sembra essere abbastanza per il mio caso d'uso. - I diff in un file di riferimento sono utili, ma richiedono prima di costruire un file di riferimento. Un file system di compressione rileverà file con contenuti quasi identici?
krlmlr,

La compressione dei file system non si comprime su più file (né fa zip), ma btrfsha copia su scrittura, quindi se copi un file e ne modifichi una parte, salva solo le parti che hai modificato. Se non stai creando file in questo modo, presumibilmente esistono strumenti di deduplicazione , ma btrfsnon è ancora un file system maturo e stabile e la deduplicazione è nelle prime fasi di sviluppo. Ma ora ci penso, che dire di lessfs.com/wordpress
orion

Ottengo rapporti di compressione impressionanti con un compressore solido per il mio caso d'uso, ma, come hai sottolineato, presumo che i risultati sarebbero peggiori se i file fossero più grandi delle dimensioni del dizionario.
krlmlr

0

Potrebbe non sembrare ovvio, ma scommetto che squashfssarebbe perfetto per questo - ed è persino implementato nel kernel. Poiché la versione 4.1 è in squashfsgrado di gestire file pseudo come specificato nella mksquashriga di comando o tramite uno script di shell e mksquashfsgenererà i file durante la creazione dell'archivio.

Può gestire pipe - ad esempio, è possibile catturare un altro processo stdoutin un archivio di squash montabile - anche quindici - è piuttosto bello. Nel tuo caso, se si potesse lavorare la logistica di script di tubazioni di uscita del vostro processo attraverso di essa, si potrebbe avvolgere il vostro processo interamente in mksquashfse finire con un unico archivio. Ecco un po 'da readmecome funziona e c'è di più qui :

Mksquashfs 4.1 aggiunge il supporto per "pseudo file dinamici" e un'operazione di modifica. Gli pseudo file dinamici consentono la creazione dinamica di file durante l'esecuzione di Mksquashfs, il cui contenuto è il risultato dell'esecuzione di un comando o di uno script di shell. L'operazione di modifica consente di modificare la modalità / uid / gid di un file esistente nel filesystem di origine.

Creazione di esempi di file dinamici

Creare un file "dmesg" contenente l'output di dmesg.

    dmesg f 444 root root dmesg

Creare un file RELEASE contenente il nome della release, la data, l'host di build e un numero di versione incrementale. La versione incrementale è un effetto collaterale dell'esecuzione dello script di shell e garantisce che ogni volta che viene eseguito Mksquashfs viene utilizzato un nuovo numero di versione senza richiedere altri script di shell.

    RELEASE f 444 root root \
        if [ ! -e /tmp/ver ]; then \
        echo 0 > /tmp/ver; \
        fi; \
        ver=`cat /tmp/ver`; \
            ver=$((ver +1)); \
            echo $ver > /tmp/ver; \
            echo -n "release x.x"; \
            echo "-dev #"$ver `date` "Build host" `hostname`

Copia 10K dal dispositivo / dev / sda1 nell'input del file. Normalmente Mksquashfs, dato un dispositivo, un quo o un socket chiamato, inserirà quel file speciale all'interno del filesystem di Squashfs, questo consentirà di catturare e collocare l'input da questi file speciali nel filesystem di Squashfs.

        input f 444 root root dd if=/dev/sda1 bs=1024 count=10

Come funzionerebbe all'interno dell'infrastruttura che ho delineato?
krlmlr,

Dovresti ottenere il tuo processo per scrivere i nomi dei file nello script di invocazione di mksquash e far sì che continui ad aggiungerli mentre è in esecuzione. O anche in un tmpfs che squash leggerà e comprimerà mentre corre. O, come un altro ha detto, attraverso qualcos'altro - invocare cpio proprio come il precedente esempio dd, ma con cpio usare forse la sua funzione di copia. In ogni caso, legge, crea e comprime sicuramente al volo.
Mikeserv,

Comprimerà tra i file?
krlmlr,

Comprime il suo input in un flusso: tutti gli inode, tutti. L'ho usato con dd ed è stato abbastanza bello - uso sempre la dimensione del blocco da 1 MB e la compressione xz.
Mikeserv,

Sembra un'opzione, ma dalla tua risposta non riesco a vedere come creare, diciamo, un archivio squashfs con una directory teste un file filein questa directory. Potresti fornire un breve esempio?
krlmlr
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.