Virtuelles schreibgeschütztes Dateisystem zum Speichern von Dateien im Archiv

8

Ich habe einen peinlich parallelen Prozess, der eine große Menge nahezu (aber nicht vollständig) identischer Dateien erstellt. Gibt es eine Möglichkeit, die Dateien "on the fly" zu archivieren, damit die Daten nicht mehr Speicherplatz als nötig beanspruchen?

Der Prozess selbst akzeptiert Befehlszeilenparameter und druckt den Namen jeder in stdout erstellten Datei. Ich rufe es auf, mit parallel --gnudem die Eingabe (die aus einem anderen Prozess stammt) verteilt und die Ausgabe gesammelt wird:

arg_generating_process | parallel --gnu my_process | magic_otf_compressor

EINFACHES BEISPIEL für den ersten Teil des Rohrs in bash:

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

Wie könnte das magic_otf_compressoraussehen? Es soll jede Eingabezeile als Dateinamen behandeln, jede Datei in ein komprimiertes .tarArchiv kopieren (dasselbe Archiv für alle verarbeiteten Dateien!) Und es dann löschen. (Eigentlich sollte es ausreichen, den Namen jeder verarbeiteten Datei zu drucken, ein anderer | parallel --gnu rmkönnte sich um das Löschen der Dateien kümmern.)

Gibt es ein solches Werkzeug? Ich denke nicht daran, jede Datei einzeln zu komprimieren, dies würde viel zu viel Speicherplatz verschwenden. Ich habe nachgesehen archivemount(wird das Dateisystem im Speicher halten -> unmöglich, meine Dateien sind zu groß und zu viele) und avfs(konnte es nicht dazu bringen, mit FUSE zusammenzuarbeiten). Was habe ich vermisst?

Ich bin nur einen Schritt davon entfernt, ein solches Tool selbst zu hacken, aber jemand muss es schon einmal getan haben ...

EDIT : Im Wesentlichen denke ich, dass ich nach einem Standard-Front-End suche libtar(im Gegensatz zum Befehlszeilen-Front-End tar, das Argumente aus der Befehlszeile liest).

krlmlr
quelle
Haben Sie darüber nachgedacht, Dateien in einem Format mit nativer Komprimierung zu schreiben? Beispielsweise kann hdf5 komprimiert werden, da sie entweder mit gzip- oder szip-Komprimierung geschrieben werden. Hdf5 unterstützt auch MPI, sodass es bei diesen peinlich parallelen Problemen gut funktioniert.
Casey
2
Wenn Sie Komprimierung und Deduplizierung wünschen, fällt Ihnen zfs ein.
Stéphane Chazelas
@casey: Es ist HTML, aber ich nehme an, ich könnte einen HDF5-Container verwenden. Habe das noch nicht bedacht.
krlmlr
@StephaneChazelas: Kann dies im Userland implementiert werden?
krlmlr

Antworten:

1

Es scheint tar, dass es alle Dateinamen im Voraus wissen möchte. Es ist also weniger on-the-fly und mehr after-the-fly. cpioscheint dieses Problem nicht zu haben:

| cpio -vo 2>&1 > >(gzip > /tmp/arc.cpio.gz) | parallel rm
Ole Tange
quelle
Vielen Dank. Selbst RTFM reicht also nicht aus ;-) Ich habe sogar in tarden Code geschaut, um festzustellen , dass es eine Funktion gibt, die den nächsten zu verarbeitenden Dateinamen zurückgibt, wodurch ich die Dokumentation erneut gelesen habe. - Wird stdoutalso über die gzipProzesssubstitution zum Prozess geleitet und stderrumgeleitet, zu stdoutwelchem ​​Prozess der nächste Schritt in der Pipe führt?
krlmlr
Jep. Das Konstrukt >> () funktioniert nicht in allen Shells, aber in Bash.
Ole Tange
Ich kann taranhand des einfachen Beispiels, das ich meiner Frage hinzugefügt habe, bestätigen, dass zuerst die Dateiliste gelesen wird. Beim erneuten Lesen tardes Quellcodes scheint es mir jedoch, dass die Liste der Dateien "on the fly" gelesen werden sollte, wenn kein inkrementelles Archiv erstellt wird. Leider habe ich Fehler beim Kompilieren taraus der Quelle ... :-(
krlmlr
Ich habe keine cpioandere Möglichkeit gefunden, die letzte Zeile in der Ausgabe von zu unterdrücken als grep -v 'blocks$'. ( head -n -1verwendet einen sehr großen Puffer ...) Macht diese Lösung ein bisschen zu einem Hack, aber
egal ;-)
@krlmlr das ist seltsam: Mein verwendet head -n -1nur 16 MB, wenn es mit ein paar GB Daten ausgeführt wird. Sie können immer perl verwenden: perl -ne 'print $ last; $ last = $ _'
Ole Tange
7

Ein klassischer Fall von RTFM (alles!) . Die -TOption für GNU tarliest die zu archivierenden Dateien aus einer anderen Datei (in meinem Fall /dev/stdinkönnen Sie sie auch verwenden -), und es gibt sogar eine --remove-filesOption:

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

(Verwenden Sie die parallele Version von xzfür die Komprimierung, aber Sie können stattdessen Ihren bevorzugten Kompressor verwenden). Zu verwenden als:

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

EDIT : Wie Ole betont, tarscheint -Taus irgendeinem Grund die gesamte Liste der Dateien mit der Option zu lesen . Der folgende Test bestätigt dies:

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

Auf meinem System gibt es eine Verzögerung von einer Sekunde, bevor alle Dateien gleichzeitig gedruckt werden. Wenn der tarBefehl dagegen durch ersetzt wird cat, werden alle Dateien beim Erstellen gedruckt. Ich habe eine Supportanfrage bei den Teerleuten gestellt, mal sehen.

EDIT ^ 2 : Das neueste taraus der Quelle behebt dies. Es ist noch nicht in Ubuntu 13.10 enthalten, könnte aber in 14.04 enthalten sein.

krlmlr
quelle
1

Irgendwie scheint dies für einen soliden Kompressor (bandbasierte Archivierer + Komprimierung) kein guter Job zu sein. Das Einfügen von Dateien nacheinander sieht aus wie ein Job für zipoder ein anderes Format, das den zufälligen Dateizugriff innerhalb des Archivs und das inkrementelle Einfügen ermöglicht.

Die Tatsache, dass die Dateien ähnlich sind, hilft in beiden Fällen nicht viel. In zipwerden Dateien separat komprimiert, und in festen Kompressoren gibt es normalerweise ein Fenster, in dem die Komprimierung stattfindet.

Wenn die Dateien textbasiert sind, können Sie Unterschiede im Vergleich zu einer einzelnen Referenzdatei speichern. Für Binärdateien ist es etwas kniffliger, kann aber durchgeführt werden.

Es gibt auch einen formalen Weg (nicht nur Schreiben, sondern richtige Dateisysteme). Beispielsweise bieten ZFS- und BTRFS-Dateisysteme eine transparente Komprimierung. Sie können auch diese http://developer.berlios.de/projects/fusecompress verwenden

Orion
quelle
Meine Dateien sind jeweils ca. 100.000. Wäre es nicht genug, dem Kompressor zu erlauben, ein Fenster von beispielsweise 1 M zu verwenden? xzscheint mit einer Standardwörterbuchgröße von 8 MB (bei Standardkomprimierungsstufe -6) zu arbeiten, was für meinen Anwendungsfall ausreichend zu sein scheint. - Diffs zu einer Referenzdatei sind nett, müssen aber zuerst eine Referenzdatei erstellen. Würde ein komprimierendes Dateisystem Dateien mit nahezu identischem Inhalt erkennen?
krlmlr
Das Komprimieren von Dateisystemen komprimiert nicht zwischen Dateien (und zip auch nicht), btrfsverfügt jedoch über Copy-on-Write. Wenn Sie also eine Datei kopieren und einen Teil davon ändern, werden nur Teile gespeichert, die Sie geändert haben. Wenn Sie Dateien nicht auf diese Weise erstellen, gibt es angeblich Deduplizierungswerkzeuge , aber es btrfshandelt sich noch nicht um ein ausgereiftes und stabiles Dateisystem. Die Deduplizierung befindet sich in einem frühen Entwicklungsstadium. Aber jetzt denke ich darüber nach, was ist mit lessfs.com/wordpress
orion
Ich bekomme beeindruckende Komprimierungsverhältnisse mit einem soliden Kompressor für meinen Anwendungsfall, aber wie Sie dargelegt haben, gehe ich davon aus, dass die Ergebnisse schlechter wären, wenn die Dateien größer als das Wörterbuch wären.
krlmlr
0

Es mag nicht offensichtlich erscheinen, aber ich wette, es squashfswäre perfekt dafür - und es ist sogar im Kernel implementiert. Seit der Version 4.1 squashfsverarbeiten kann Pseudo-Dateien wie auf dem angegebene mksquashBefehlszeile oder über einen Shell-Skript und mksquashfsdie Dateien erzeugt , wie es das Archiv erstellt.

Es kann Rohre verarbeiten - zum Beispiel können Sie einen anderen Prozess stdoutin einem montierbaren Squash-Archiv erfassen - sogar Fifos - es ist ziemlich cool. In Ihrem Fall, wenn Sie das Skript Logistik erarbeiten könnte Ihr Prozess der Ausgabe durch von Rohrleitungen, könnten Sie Ihren Prozess wickeln ganz in mksquashfsund mit einem einzigen Archiv aufzuwickeln. Hier ist ein bisschen von der readmeFunktionsweise und hier gibt es noch mehr :

Mksquashfs 4.1 bietet Unterstützung für "dynamische Pseudodateien" und eine Änderungsoperation. Mit dynamischen Pseudodateien können Dateien dynamisch erstellt werden, wenn Mksquashfs ausgeführt wird. Ihr Inhalt ist das Ergebnis der Ausführung eines Befehls oder eines Shell-Skripts. Mit der Änderungsoperation kann der Modus / uid / gid einer vorhandenen Datei im Quelldateisystem geändert werden.

Beispiele für dynamische Dateien erstellen

Erstellen Sie eine Datei "dmesg", die die Ausgabe von dmesg enthält.

    dmesg f 444 root root dmesg

Erstellen Sie eine Datei RELEASE mit dem Versionsnamen, dem Datum, dem Build-Host und einer inkrementellen Versionsnummer. Die inkrementelle Version ist ein Nebeneffekt bei der Ausführung des Shell-Skripts und stellt sicher, dass bei jeder Ausführung von Mksquashfs eine neue Versionsnummer verwendet wird, ohne dass ein anderes Shell-Skript erforderlich ist.

    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`

Kopieren Sie 10 KB vom Gerät / dev / sda1 in die Dateieingabe. Normalerweise platziert Mksquashfs bei einem Gerät, einem FIFO oder einem benannten Socket diese spezielle Datei im Squashfs-Dateisystem. Dadurch können Eingaben aus diesen speziellen Dateien erfasst und im Squashfs-Dateisystem abgelegt werden.

        input f 444 root root dd if=/dev/sda1 bs=1024 count=10
mikeserv
quelle
Wie würde dies innerhalb der von mir beschriebenen Infrastruktur funktionieren?
krlmlr
Sie müssten Ihren Prozess dazu bringen, seine Dateinamen in das Aufrufskript von mksquash zu schreiben und sie während der Ausführung weiterhin anhängen zu lassen. Oder sogar in ein tmpfs, das Squash während der Ausführung liest und komprimiert. Oder, wie bereits erwähnt, über etwas anderes - rufen Sie cpio wie im obigen dd-Beispiel auf, aber verwenden Sie mit cpio möglicherweise die Kopierfunktion. Auf jeden Fall - es liest, erstellt und komprimiert definitiv im laufenden Betrieb.
Mikeserv
Wird es über Dateien hinweg komprimiert?
krlmlr
Es komprimiert seine Eingabe in einem Stream - alle Inodes, alles. Ich habe es mit dd verwendet und es war ziemlich cool - ich verwende immer die 1-MB-Blockgröße und die xz-Komprimierung.
mikeserv
Dies sieht nach einer Option aus, aber aus Ihrer Antwort geht nicht hervor, wie beispielsweise ein Squashfs-Archiv mit einem Verzeichnis testund einer Datei filein diesem Verzeichnis erstellt werden kann. Könnten Sie bitte ein kurzes Beispiel geben?
krlmlr