Das deduplizierende , Warp -Geschwindigkeit erweiterte , schreibgeschützte Dateisystem .
Ein schnelles, hochkomprimiertes, schreibgeschütztes Dateisystem für Linux und Windows.
DwarFS ist ein schreibgeschütztes Dateisystem, dessen Schwerpunkt auf der Erzielung sehr hoher Komprimierungsraten insbesondere für sehr redundante Daten liegt.
Das klingt wahrscheinlich nicht sehr aufregend, denn wenn es redundant ist, sollte es gut komprimiert werden. Ich habe jedoch festgestellt, dass andere schreibgeschützte, komprimierte Dateisysteme diese Redundanz nicht besonders gut nutzen können. Einen Vergleich mit anderen komprimierten Dateisystemen finden Sie hier.
DwarFS macht auch keine Kompromisse bei der Geschwindigkeit und ich habe festgestellt, dass es für meine Anwendungsfälle mit SquashFS mithalten kann oder sogar besser ist. Für meinen primären Anwendungsfall ist die DwarFS-Komprimierung um eine Größenordnung besser als die SquashFS-Komprimierung , der Aufbau des Dateisystems ist sechsmal schneller , der Zugriff auf Dateien auf DwarFS ist normalerweise schneller und es verbraucht weniger CPU-Ressourcen.
Um Ihnen eine Vorstellung davon zu geben, wozu DwarFS in der Lage ist, finden Sie hier einen kurzen Vergleich von DwarFS und SquashFS anhand einer Reihe von Videodateien mit einer Gesamtgröße von 39 GiB. Der Clou besteht darin, dass jede einzelne Videodatei zwei Geschwisterdateien mit unterschiedlichen Audiostreams hat (dies ist ein tatsächlicher Anwendungsfall). Es gibt also Redundanz sowohl bei den Video- als auch bei den Audiodaten. Da die Streams jedoch verschachtelt sind und identische Blöcke normalerweise sehr weit voneinander entfernt sind, ist es schwierig, diese Redundanz für die Komprimierung zu nutzen. SquashFS schafft es praktisch überhaupt nicht, die Quelldaten zu komprimieren, wohingegen DwarFS in der Lage ist, die Größe um fast den Faktor 3 zu reduzieren, was nahe am theoretischen Maximum liegt:
$ du -hs dwarfs-video-test
39G dwarfs-video-test
$ ls -lh dwarfs-video-test.*fs
-rw-r--r-- 1 mhx users 14G Jul 2 13:01 dwarfs-video-test.dwarfs
-rw-r--r-- 1 mhx users 39G Jul 12 09:41 dwarfs-video-test.squashfs
Wenn außerdem das SquashFS-Image gemountet und ein Durchsatztest für zufälliges Lesen mit fio-3.34 durchgeführt wird, erreichen sowohl squashfuse
als auch squashfuse_ll
eine Höchstgeschwindigkeit von etwa 230 MiB/s:
$ fio --readonly --rw=randread --name=randread --bs=64k --direct=1
--opendir=mnt --numjobs=4 --ioengine=libaio --iodepth=32
--group_reporting --runtime=60 --time_based
[...]
READ: bw=230MiB/s (241MB/s), 230MiB/s-230MiB/s (241MB/s-241MB/s), io=13.5GiB (14.5GB), run=60004-60004msec
Im Vergleich dazu schafft es DwarFS , zufällige Leseraten von 20 GiB/s aufrechtzuerhalten:
READ: bw=20.2GiB/s (21.7GB/s), 20.2GiB/s-20.2GiB/s (21.7GB/s-21.7GB/s), io=1212GiB (1301GB), run=60001-60001msec
Besondere Merkmale von DwarFS sind:
Clustering von Dateien nach Ähnlichkeit mithilfe einer Ähnlichkeits-Hash-Funktion. Dies erleichtert die Ausnutzung der Redundanz über Dateigrenzen hinweg.
Segmentierungsanalyse über Dateisystemblöcke hinweg, um die Größe des unkomprimierten Dateisystems zu reduzieren. Dies spart Speicher bei Verwendung des komprimierten Dateisystems und ermöglicht somit möglicherweise höhere Cache-Trefferraten, da mehr Daten im Cache gehalten werden können.
Kategorisierungs-Framework, um Dateien oder sogar Dateifragmente zu kategorisieren und dann einzelne Kategorien unterschiedlich zu verarbeiten. Dadurch können Sie beispielsweise keine Zeit damit verschwenden, inkomprimierbare Dateien zu komprimieren oder PCM-Audiodaten mithilfe der FLAC-Komprimierung zu komprimieren.
Hochgradig multithreadige Implementierung. Sowohl das Dateisystem-Erstellungstool als auch der FUSE-Treiber sind in der Lage, die vielen Kerne Ihres Systems optimal zu nutzen.
Ich begann 2013 mit der Arbeit an DwarFS und mein Hauptanwendungsfall und meine Hauptmotivation waren, dass ich mehrere hundert verschiedene Versionen von Perl hatte, die etwa 30 Gigabyte Festplattenspeicher belegten, und ich nicht bereit war, mehr als 10 % meines Festplattenspeichers auszugeben Ich fahre und behalte sie für den Fall bei, dass ich sie brauche.
Bis dahin habe ich Cromfs verwendet, um sie auf eine handliche Größe zu komprimieren. Allerdings ärgerte mich immer mehr die Zeit, die es brauchte, um das Dateisystem-Image zu erstellen, und was die Sache noch schlimmer machte, stürzte es in den meisten Fällen schon nach etwa einer Stunde ab.
Ich hatte mich natürlich auch mit SquashFS befasst, kam aber nie annähernd an die Komprimierungsraten von Cromfs heran.
Das allein hätte nicht ausgereicht, um mich zum Schreiben von DwarFS zu bewegen, aber gleichzeitig war ich ziemlich besessen von den jüngsten Entwicklungen und Funktionen neuerer C++-Standards und wollte unbedingt an einem C++-Hobbyprojekt arbeiten. Außerdem wollte ich schon seit einiger Zeit etwas mit FUSE machen. Zu guter Letzt hatte ich schon eine Weile über das Problem komprimierter Dateisysteme nachgedacht und hatte einige Ideen, die ich unbedingt ausprobieren wollte.
Der Großteil des Codes wurde im Jahr 2013 geschrieben, dann habe ich hin und wieder ein paar Aufräumarbeiten, Bugfixes und Refaktorierungen durchgeführt, aber ich habe ihn nie wirklich in einen Zustand gebracht, in dem ich mich glücklich fühlen würde, ihn zu veröffentlichen. Es war zu umständlich, es aufzubauen, da es von Facebooks (ziemlich toller) Folly-Bibliothek abhängig war und es keine Dokumentation gab.
Als wir das Projekt dieses Jahr erneut ausgruben, sah es nicht mehr so düster aus wie früher. Folly erstellt jetzt mit CMake und deshalb habe ich es einfach als Submodul eingebunden. Die meisten anderen Abhängigkeiten können durch Pakete erfüllt werden, die allgemein verfügbar sein sollten. Und ich habe auch einige rudimentäre Dokumente geschrieben.
DwarFS sollte normalerweise mit minimalen Änderungen sofort einsatzbereit sein. Wenn dies nicht der Fall ist, reichen Sie bitte ein Problem ein. Ich habe CI-Jobs mit Docker-Images für Ubuntu (22.04 und 24.04), Fedora Rawhide und Arch eingerichtet, die bei der Ermittlung eines aktuellen Satzes von Abhängigkeiten helfen können. Beachten Sie, dass das Erstellen aus dem Release-Tarball weniger Abhängigkeiten erfordert als das Erstellen aus dem Git-Repository, insbesondere sind das ronn
-Tool sowie Python und das mistletoe
Python-Modul beim Erstellen aus dem Release-Tarball nicht erforderlich.
Es gibt einige Dinge, die Sie beachten sollten:
Es besteht die Tendenz, die Folly- und Fbthrift-Bibliotheken, die als Submodule enthalten sind und zusammen mit DwarFS erstellt werden, zu entbündeln. Auch wenn ich dieser Meinung zustimme, ist es leider eine schlechte Idee. Abgesehen von der Tatsache, dass folly keine Aussagen zur ABI-Stabilität macht (dh Sie können eine Binärdatei, die für eine Version von folly erstellt wurde, nicht einfach dynamisch mit einer anderen Version verknüpfen), ist es nicht einmal möglich, eine sichere Verknüpfung mit einer Folly-Bibliothek herzustellen, die mit einer anderen Kompilierung erstellt wurde Optionen. Selbst geringfügige Unterschiede, wie beispielsweise die C++-Standardversion, können Laufzeitfehler verursachen. Weitere Informationen finden Sie in dieser Ausgabe. Derzeit ist es nicht einmal möglich, externe Versionen von folly/fbthrift zu verwenden, da DwarFS nur minimale Teilmengen beider Bibliotheken erstellt; Diese sind in der dwarfs_common
-Bibliothek gebündelt und werden ausschließlich intern verwendet, dh keiner der Folly- oder Fbthrift-Header ist erforderlich, um mit den DwarFS-Bibliotheken zu bauen.
Ähnliche Probleme können auftreten, wenn Sie eine vom System installierte Version von GoogleTest verwenden. GoogleTest selbst empfiehlt, es als Teil des Builds herunterzuladen. Sie können jedoch die vom System installierte Version verwenden, indem Sie -DPREFER_SYSTEM_GTEST=ON
an den cmake
-Aufruf übergeben. Die Nutzung erfolgt auf eigene Gefahr.
Für andere gebündelte Bibliotheken (nämlich fmt
, parallel-hashmap
, range-v3
) wird die vom System installierte Version verwendet, solange sie die erforderliche Mindestversion erfüllt. Andernfalls wird die bevorzugte Version während des Builds abgerufen.
Für jede Version stehen vorgefertigte, statisch verknüpfte Binärdateien für Linux-x86_64
, Linux-aarch64
und Windows-AMD64
zum Download zur Verfügung. Diese sollten ohne Abhängigkeiten ausgeführt werden und können insbesondere bei älteren Distributionen nützlich sein, bei denen Sie die Tools nicht einfach aus dem Quellcode erstellen können.
Zusätzlich zu den binären Tarballs gibt es für jede Architektur eine universelle Binärdatei . Diese universellen Binärdateien enthalten alle Tools ( mkdwarfs
, dwarfsck
, dwarfsextract
und den dwarfs
FUSE-Treiber) in einer einzigen ausführbaren Datei. Diese ausführbaren Dateien werden mit upx komprimiert und sind daher viel kleiner als die einzelnen Tools zusammen. Allerdings bedeutet dies auch, dass die Binärdateien bei jeder Ausführung dekomprimiert werden müssen, was einen erheblichen Mehraufwand verursachen kann. Wenn dies ein Problem darstellt, können Sie entweder bei den „klassischen“ einzelnen Binärdateien bleiben oder die universelle Binärdatei dekomprimieren, z. B.:
upx -d dwarfs-universal-0.7.0-Linux-aarch64
Die universellen Binärdateien können über symbolische Links ausgeführt werden, die nach dem entsprechenden Tool benannt sind. z.B:
$ ln -s dwarfs-universal-0.7.0-Linux-aarch64 mkdwarfs
$ ./mkdwarfs --help
Dies funktioniert auch unter Windows, wenn das Dateisystem symbolische Links unterstützt:
> mklink mkdwarfs.exe dwarfs-universal-0.7.0-Windows-AMD64.exe
> .mkdwarfs.exe --help
Alternativ können Sie das Tool auswählen, indem Sie --tool=<name>
als erstes Argument in der Befehlszeile übergeben:
> .dwarfs-universal-0.7.0-Windows-AMD64.exe --tool=mkdwarfs --help
Beachten Sie, dass die universelle Windows-Binärdatei ebenso wie die Windows-Binärdatei dwarfs.exe
von der winfsp-x64.dll
aus dem WinFsp-Projekt abhängt. Bei der universellen Binärdatei wird die DLL jedoch verzögert geladen, sodass Sie alle anderen Tools auch ohne die DLL verwenden können. Weitere Informationen finden Sie im Abschnitt „Windows-Support“.
DwarFS verwendet CMake als Build-Tool.
Es verwendet sowohl Boost als auch Folly, wobei letzteres als Submodul enthalten ist, da nur sehr wenige Distributionen tatsächlich Pakete dafür anbieten. Folly selbst weist eine Reihe von Abhängigkeiten auf. Eine aktuelle Liste finden Sie hier.
Außerdem nutzt es Facebook Thrift, insbesondere die frozen
Bibliothek, um Metadaten in einem äußerst platzsparenden, speicherabbildbaren und gut definierten Format zu speichern. Es ist auch als Submodul enthalten und wir erstellen nur den Compiler und eine sehr reduzierte Bibliothek, die gerade genug enthält, damit DwarFS funktioniert.
Ansonsten hängt DwarFS eigentlich nur von FUSE3 und einer Reihe von Komprimierungsbibliotheken ab, von denen Folly bereits abhängig ist (nämlich lz4, zstd und liblzma).
Die Abhängigkeit von Googletest wird automatisch aufgelöst, wenn Sie mit Tests erstellen.
Ein guter Ausgangspunkt für apt-basierte Systeme ist wahrscheinlich:
$ apt install
gcc
g++
clang
git
ccache
ninja-build
cmake
make
bison
flex
fuse3
pkg-config
binutils-dev
libacl1-dev
libarchive-dev
libbenchmark-dev
libboost-chrono-dev
libboost-context-dev
libboost-filesystem-dev
libboost-iostreams-dev
libboost-program-options-dev
libboost-regex-dev
libboost-system-dev
libboost-thread-dev
libbrotli-dev
libevent-dev
libhowardhinnant-date-dev
libjemalloc-dev
libdouble-conversion-dev
libiberty-dev
liblz4-dev
liblzma-dev
libzstd-dev
libxxhash-dev
libmagic-dev
libparallel-hashmap-dev
librange-v3-dev
libssl-dev
libunwind-dev
libdwarf-dev
libelf-dev
libfmt-dev
libfuse3-dev
libgoogle-glog-dev
libutfcpp-dev
libflac++-dev
nlohmann-json3-dev
Beachten Sie, dass beim Erstellen mit gcc
die Optimierungsstufe für Release-Builds auf -O2
anstelle des CMake-Standards -O3
gesetzt wird. Zumindest bei Versionen bis gcc-10
ist der -O3
Build bis zu 70 % langsamer als ein Build mit -O2
.
Entpacken Sie zunächst das Release-Archiv:
$ tar xvf dwarfs-x.y.z.tar.xz
$ cd dwarfs-x.y.z
Alternativ können Sie auch das Git-Repository klonen. Beachten Sie jedoch, dass dies mehr Abhängigkeiten aufweist und der Build wahrscheinlich länger dauern wird, da das Release-Archiv mit den meisten automatisch generierten Dateien geliefert wird, die beim Erstellen aus dem Repository generiert werden müssen:
$ git clone --recurse-submodules https://github.com/mhx/dwarfs
$ cd dwarfs
Sobald alle Abhängigkeiten installiert sind, können Sie DwarFS erstellen mit:
$ mkdir build
$ cd build
$ cmake .. -GNinja -DWITH_TESTS=ON
$ ninja
Anschließend können Sie Tests durchführen mit:
$ ctest -j
Alle Binärdateien verwenden standardmäßig Jemalloc als Speicherzuweiser, da es im Vergleich zu den glibc
oder tcmalloc
Zuweisern normalerweise viel weniger Systemspeicher benötigt. Um die Verwendung von jemalloc
zu deaktivieren, übergeben Sie -DUSE_JEMALLOC=0
in der cmake
-Befehlszeile.
Es ist auch möglich, die DwarFS-Bibliotheken, Tools und den FUSE-Treiber unabhängig voneinander zu erstellen/installieren. Dies ist vor allem beim Packen von DwarFS interessant. Beachten Sie, dass die Tools und der FUSE-Treiber erfordern, dass die Bibliotheken entweder erstellt oder bereits installiert sind. Um nur die Bibliotheken zu erstellen, verwenden Sie:
$ cmake .. -GNinja -DWITH_TESTS=ON -DWITH_LIBDWARFS=ON -DWITH_TOOLS=OFF -DWITH_FUSE_DRIVER=OFF
Sobald die Bibliotheken getestet und installiert sind, können Sie die Tools (z. B. mkdwarfs
, dwarfsck
, dwarfsextract
) erstellen, indem Sie Folgendes verwenden:
$ cmake .. -GNinja -DWITH_TESTS=ON -DWITH_LIBDWARFS=OFF -DWITH_TOOLS=ON -DWITH_FUSE_DRIVER=OFF
Um den FUSE-Treiber zu erstellen, verwenden Sie:
$ cmake .. -GNinja -DWITH_TESTS=ON -DWITH_LIBDWARFS=OFF -DWITH_TOOLS=OFF -DWITH_FUSE_DRIVER=ON
Die Installation ist so einfach wie:
$ sudo ninja install
Allerdings müssen Sie die Tools nicht installieren, um damit zu spielen.
Vom Versuch, statisch verknüpfte Binärdateien zu erstellen, wird dringend abgeraten und dies wird auch nicht offiziell unterstützt. Vor diesem Hintergrund erfahren Sie hier, wie Sie eine Umgebung einrichten, in der Sie möglicherweise statische Binärdateien erstellen können.
Dies wurde mit ubuntu-22.04-live-server-amd64.iso
getestet. Installieren Sie zunächst alle oben als Abhängigkeiten aufgeführten Pakete. Installieren Sie außerdem:
$ apt install ccache ninja libacl1-dev
ccache
und ninja
sind optional, helfen aber bei einer schnellen Kompilierung.
Abhängig von Ihrer Distribution müssen Sie statische Versionen einiger Bibliotheken erstellen und installieren, z. B. libarchive
und libmagic
für Ubuntu:
$ wget https://github.com/libarchive/libarchive/releases/download/v3.6.2/libarchive-3.6.2.tar.xz
$ tar xf libarchive-3.6.2.tar.xz && cd libarchive-3.6.2
$ ./configure --prefix=/opt/static-libs --without-iconv --without-xml2 --without-expat
$ make && sudo make install
$ wget ftp://ftp.astron.com/pub/file/file-5.44.tar.gz
$ tar xf file-5.44.tar.gz && cd file-5.44
$ ./configure --prefix=/opt/static-libs --enable-static=yes --enable-shared=no
$ make && make install
Das ist es! Jetzt können Sie versuchen, statische Binärdateien für DwarFS zu erstellen:
$ git clone --recurse-submodules https://github.com/mhx/dwarfs
$ cd dwarfs && mkdir build && cd build
$ cmake .. -GNinja -DWITH_TESTS=ON -DSTATIC_BUILD_DO_NOT_USE=ON
-DSTATIC_BUILD_EXTRA_PREFIX=/opt/static-libs
$ ninja
$ ninja test
Bitte schauen Sie sich die Handbuchseiten für mkdwarfs, dwarfs, dwarfsck und dwarfsextract an. Sie können auch auf die Handbuchseiten zugreifen, indem Sie die Option --man
für jede Binärdatei verwenden, z. B.:
$ mkdwarfs --man
Die Dwarfs-Handbuchseite zeigt auch ein Beispiel für die Einrichtung von DwarFS mit OverlayFS, um einen beschreibbaren Dateisystem-Mount über einem schreibgeschützten DwarFS-Image zu erstellen.
Eine Beschreibung des DwarFS-Dateisystemformats finden Sie im Dwarfs-Format.
Eine allgemeine Übersicht über den internen Betrieb von mkdwarfs
wird in diesem Sequenzdiagramm dargestellt.
Die Verwendung der DwarFS-Bibliotheken sollte ziemlich einfach sein, wenn Sie CMake zum Erstellen Ihres Projekts verwenden. Schauen Sie sich für einen schnellen Einstieg den Beispielcode an, der die Bibliotheken verwendet, um Informationen über ein DwarFS-Image zu drucken (wie dwarfsck
) oder es zu extrahieren (wie dwarfsextract
).
Es gibt fünf einzelne Bibliotheken:
dwarfs_common
enthält den gemeinsamen Code, der von allen anderen Bibliotheken benötigt wird. Die Schnittstellen werden in dwarfs/
definiert.
dwarfs_reader
enthält den gesamten Code, der zum Lesen von Daten aus einem DwarFS-Image erforderlich ist. Die Schnittstellen sind in dwarfs/reader/
definiert.
dwarfs_extractor
enthält den Code, der zum Extrahieren eines DwarFS-Images mit libarchive
erforderlich ist. Die Schnittstellen sind in dwarfs/utility/filesystem_extractor.h
definiert.
dwarfs_writer
enthält den Code, der zum Erstellen von DwarFS-Images erforderlich ist. Die Schnittstellen werden in dwarfs/writer/
definiert.
dwarfs_rewrite
enthält den Code zum Neuschreiben von DwarFS-Bildern. Die Schnittstellen sind in dwarfs/utility/rewrite_filesystem.h
definiert.
Auf die Header in internal
Unterordnern kann nur zur Erstellungszeit zugegriffen werden und sie werden nicht installiert. Das Gleiche gilt für den tool
Unterordner.
Die Reader- und Extraktor-APIs sollten ziemlich stabil sein. Die Writer-APIs werden sich wahrscheinlich ändern. Beachten Sie jedoch, dass es keine Garantien für die API-Stabilität gibt, bevor dieses Projekt Version 1.0.0 erreicht.
Die Unterstützung für das Windows-Betriebssystem ist derzeit experimentell. Da ich in den letzten zwei Jahrzehnten fast ausschließlich in der Unix-Welt gearbeitet habe, ist meine Erfahrung mit der Windows-Entwicklung eher begrenzt und ich gehe davon aus, dass der Windows-Code definitiv Fehler und Ecken und Kanten aufweist.
Die Windows-Version des DwarFS-Dateisystemtreibers basiert auf dem fantastischen WinFsp-Projekt und seine winfsp-x64.dll
muss vom dwarfs.exe
-Treiber erkennbar sein.
Die verschiedenen Tools sollten sich weitgehend gleich verhalten, unabhängig davon, ob Sie sie unter Linux oder Windows verwenden. Die Dateisystem-Images können zwischen Linux und Windows kopiert werden und auf einem Betriebssystem erstellte Images sollten auf dem anderen Betriebssystem einwandfrei funktionieren.
Es gibt jedoch ein paar Dinge, die es wert sind, erwähnt zu werden:
DwarFS unterstützt sowohl Hardlinks als auch Symlinks unter Windows, genau wie unter Linux. Das Erstellen von Hardlinks und Symlinks scheint jedoch unter Windows Administratorrechte zu erfordern. Wenn Sie also beispielsweise ein DwarFS-Image extrahieren möchten, das Links enthält, kann es zu Fehlern kommen, wenn Sie nicht über die richtigen Berechtigungen verfügen.
Aufgrund eines Problems in WinFsp können Symlinks derzeit nicht auf außerhalb des gemounteten Dateisystems verweisen. Darüber hinaus werden aufgrund eines anderen Problems in WinFsp Symlinks mit einem Laufwerksbuchstaben mit einem verstümmelten Zielpfad angezeigt.
Der DwarFS-Treiber unter Windows meldet die Hardlink-Zählungen korrekt über seine API, aber derzeit werden diese Zählungen nicht korrekt an die Windows-Dateisystemebene weitergegeben. Dies liegt vermutlich an einem Problem in WinFsp.
Beim Mounten eines DwarFS-Images unter Windows darf der Mountpunkt nicht vorhanden sein. Dies unterscheidet sich von Linux, wo der Mount-Punkt tatsächlich vorhanden sein muss. Außerdem ist es möglich, ein DwarFS-Image als Laufwerksbuchstaben bereitzustellen, z. B
dwarfs.exe image.dwarfs Z:
Filterregeln für mkdwarfs
erfordern immer Unix-Pfadtrennzeichen, unabhängig davon, ob es unter Windows oder Linux ausgeführt wird.
Dank vcpkg ist das Erstellen unter Windows nicht allzu kompliziert. Sie müssen Folgendes installieren:
Visual Studio und der MSVC C/C++-Compiler
Git
CMake
Ninja
WinFsp
Es wird erwartet, dass WinFsp
unter C:Program Files (x86)WinFsp
installiert wird. Ist dies nicht der Fall, müssen Sie WINFSP_PATH
festlegen, wenn Sie CMake über cmake/win.bat
ausführen.
Jetzt müssen Sie vcpkg
und dwarfs
klonen:
> cd %HOMEPATH%
> mkdir git
> cd git
> git clone https://github.com/Microsoft/vcpkg.git
> git clone https://github.com/mhx/dwarfs
Dann booten Sie vcpkg
:
> .vcpkgbootstrap-vcpkg.bat
Und baue DwarFS:
> cd dwarfs
> mkdir build
> cd build
> ..cmakewin.bat
> ninja
Sobald dies erledigt ist, sollten Sie in der Lage sein, die Tests auszuführen. Stellen Sie CTEST_PARALLEL_LEVEL
entsprechend der Anzahl der CPU-Kerne in Ihrem Computer ein.
> set CTEST_PARALLEL_LEVEL=10
> ninja test
Die DwarFS-Bibliotheken und -Tools ( mkdwarfs
, dwarfsck
, dwarfsextract
) sind jetzt bei Homebrew verfügbar:
$ brew install dwarfs
$ brew test dwarfs
Die macOS-Version des DwarFS-Dateisystemtreibers basiert auf dem großartigen macFUSE-Projekt. Bis eine Formel hinzugefügt wurde, müssen Sie den DwarFS FUSE-Treiber manuell erstellen.
Der Aufbau auf macOS sollte relativ einfach sein:
Installieren Sie Homebrew
Verwenden Sie Homebrew, um die erforderlichen Abhängigkeiten zu installieren:
$ brew install cmake ninja macfuse brotli howard-hinnant-date double-conversion
fmt glog libarchive libevent flac openssl nlohmann-json pkg-config
range-v3 utf8cpp xxhash boost zstd
Wenn Sie macFUSE zum ersten Mal installieren, müssen Sie die Software in den Systemeinstellungen / Datenschutz und Sicherheit explizit zulassen. Es ist sehr wahrscheinlich, dass Sie danach einen Neustart durchführen müssen.
Laden Sie einen Release-Tarball von der Release-Seite herunter und extrahieren Sie ihn:
$ wget https://github.com/mhx/dwarfs/releases/download/v0.10.0/dwarfs-0.10.0.tar.xz
$ tar xf dwarfs-0.10.0.tar.xz
$ cmake --fresh -B dwarfs-build -S dwarfs-0.10.0 -GNinja -DWITH_TESTS=ON
$ cmake --build dwarfs-build
$ ctest --test-dir dwarfs-build -j
macfuse
bei der brew install
weglassen und anstelle des ersten cmake
Befehls oben Folgendes verwenden: $ cmake --fresh -B dwarfs-build -S dwarfs-0.10.0 -GNinja -DWITH_TESTS=ON -DWITH_FUSE_DRIVER=OFF
$ cmake --fresh -B dwarfs-build -S dwarfs-0.10.0 -GNinja -DWITH_TESTS=ON -DWITH_LIBDWARFS=OFF -DWITH_TOOLS=OFF
$ sudo cmake --install dwarfs-build
Das ist es!
Bei der Astrofotografie können riesige Mengen an Rohbilddaten entstehen. Es ist nicht unwahrscheinlich, dass in einer einzigen Nacht mehrere Dutzend Gigabyte an Daten anfallen. Bei den meisten dedizierten Kameras für die Astrofotografie liegen diese Daten in Form von FITS-Bildern vor. Diese sind normalerweise unkomprimiert, lassen sich mit Standardkomprimierungsalgorithmen nicht sehr gut komprimieren, und obwohl es bestimmte komprimierte FITS-Formate gibt, werden diese nicht allgemein unterstützt.
Eines der Komprimierungsformate (einfach „Rice“ genannt) komprimiert recht gut und ist sehr schnell. Die Implementierung für komprimierte FITS weist jedoch einige Nachteile auf. Der gravierendste Nachteil besteht darin, dass die Komprimierung nicht ganz so gut ist, wie sie bei Farbsensoren und Sensoren mit einer Auflösung von weniger als 16 Bit sein könnte.
DwarFS unterstützt die ricepp
-Komprimierung (Rice++), die auf der Grundidee der Rice-Komprimierung aufbaut, jedoch einige Verbesserungen vornimmt: Sie komprimiert Farbbilder und Bilder mit geringer Bittiefe deutlich besser und sucht bei der Komprimierung immer nach der optimalen Lösung, anstatt sich auf eine Heuristik zu verlassen .
Schauen wir uns ein Beispiel mit 129 Bildern (dunkle, flache und helle Bilder) an, die mit einer ASI1600MM-Kamera aufgenommen wurden. Jedes Bild ist 32 MiB groß, also insgesamt 4 GiB an Daten. Das Komprimieren dieser Daten mit dem Standard fpack
-Tool dauert etwa 16,6 Sekunden und ergibt eine Gesamtausgabegröße von 2,2 GiB:
$ time fpack */*.fit */*/*.fit
user 14.992
system 1.592
total 16.616
$ find . -name '*.fz' -print0 | xargs -0 cat | wc -c
2369943360
Allerdings bleiben dadurch *.fz
-Dateien zurück, die nicht jede Anwendung tatsächlich lesen kann.
Mit DwarFS erhalten wir Folgendes:
$ mkdwarfs -i ASI1600 -o asi1600-20.dwarfs -S 20 --categorize
I 08:47:47.459077 scanning "ASI1600"
I 08:47:47.491492 assigning directory and link inodes...
I 08:47:47.491560 waiting for background scanners...
I 08:47:47.675241 scanning CPU time: 1.051s
I 08:47:47.675271 finalizing file inodes...
I 08:47:47.675330 saved 0 B / 3.941 GiB in 0/258 duplicate files
I 08:47:47.675360 assigning device inodes...
I 08:47:47.675371 assigning pipe/socket inodes...
I 08:47:47.675381 building metadata...
I 08:47:47.675393 building blocks...
I 08:47:47.675398 saving names and symlinks...
I 08:47:47.675514 updating name and link indices...
I 08:47:47.675796 waiting for segmenting/blockifying to finish...
I 08:47:50.274285 total ordering CPU time: 616.3us
I 08:47:50.274329 total segmenting CPU time: 1.132s
I 08:47:50.279476 saving chunks...
I 08:47:50.279622 saving directories...
I 08:47:50.279674 saving shared files table...
I 08:47:50.280745 saving names table... [1.047ms]
I 08:47:50.280768 saving symlinks table... [743ns]
I 08:47:50.282031 waiting for compression to finish...
I 08:47:50.823924 compressed 3.941 GiB to 1.201 GiB (ratio=0.304825)
I 08:47:50.824280 compression CPU time: 17.92s
I 08:47:50.824316 filesystem created without errors [3.366s]
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
waiting for block compression to finish
5 dirs, 0/0 soft/hard links, 258/258 files, 0 other
original size: 3.941 GiB, hashed: 315.4 KiB (18 files, 0 B/s)
scanned: 3.941 GiB (258 files, 117.1 GiB/s), categorizing: 0 B/s
saved by deduplication: 0 B (0 files), saved by segmenting: 0 B
filesystem: 3.941 GiB in 4037 blocks (4550 chunks, 516/516 fragments, 258 inodes)
compressed filesystem: 4037 blocks/1.201 GiB written
In weniger als 3,4 Sekunden werden die Daten auf 1,2 GiB komprimiert, fast halb so groß wie die fpack
Ausgabe.
Dies spart nicht nur viel Speicherplatz, sondern kann auch nützlich sein, wenn Ihre Daten auf einem NAS gespeichert sind. Hier ist ein Vergleich desselben Datensatzes, auf den über eine 1-Gbit/s-Netzwerkverbindung zugegriffen wird, zunächst unter Verwendung der unkomprimierten Rohdaten:
find /mnt/ASI1600 -name '*.fit' -print0 | xargs -0 -P4 -n1 cat | dd of=/dev/null status=progress
4229012160 bytes (4.2 GB, 3.9 GiB) copied, 36.0455 s, 117 MB/s
Und als nächstes ein DwarFS-Image auf derselben Freigabe verwenden:
$ dwarfs /mnt/asi1600-20.dwarfs mnt
$ find mnt -name '*.fit' -print0 | xargs -0 -P4 -n1 cat | dd of=/dev/null status=progress
4229012160 bytes (4.2 GB, 3.9 GiB) copied, 14.3681 s, 294 MB/s
Das ist etwa 2,5-mal schneller. Ähnliche Ergebnisse können Sie sehr wahrscheinlich auch bei langsamen externen Festplatten sehen.
Derzeit verfügt DwarFS über keine integrierte Funktion zum Hinzufügen von Wiederherstellungsinformationen zu einem Dateisystem-Image. Für Archivierungszwecke ist es jedoch sinnvoll, über solche Wiederherstellungsinformationen zu verfügen, um ein beschädigtes Image reparieren zu können.
Glücklicherweise ist dies mit etwas wie par2cmdline relativ einfach:
$ par2create -n1 asi1600-20.dwarfs
Dadurch werden zwei zusätzliche Dateien erstellt, die Sie neben dem Image (oder auf einem anderen Speicher) platzieren können, da Sie sie nur benötigen, wenn DwarFS ein Problem mit dem Dateisystem-Image erkannt hat. Wenn es ein Problem gibt, können Sie es ausführen
$ par2repair asi1600-20.dwarfs
Dadurch kann das Image sehr wahrscheinlich wiederhergestellt werden, wenn weniger als 5 % (das ist die von par2create
verwendete Standardeinstellung) des Images beschädigt sind.
Erweiterte Attribute werden derzeit nicht unterstützt. Alle im Quelldateisystem gespeicherten erweiterten Attribute bleiben derzeit nicht erhalten, wenn ein DwarFS-Image mit mkdwarfs
erstellt wird.
Allerdings stellt der Root-Inode eines gemounteten DwarFS-Images unter Linux derzeit ein oder zwei erweiterte Attribute zur Verfügung:
$ attr -l mnt
Attribute "dwarfs.driver.pid" has a 4 byte value for mnt
Attribute "dwarfs.driver.perfmon" has a 4849 byte value for mnt
Das Attribut dwarfs.driver.pid
enthält einfach die PID des DwarFS FUSE-Treibers. Das Attribut dwarfs.driver.perfmon
enthält die aktuellen Ergebnisse des Leistungsmonitors.
Darüber hinaus stellt jede reguläre Datei ein Attribut dwarfs.inodeinfo
mit Informationen über den zugrunde liegenden Inode bereit:
$ attr -l "05 Disappear.caf"
Attribute "dwarfs.inodeinfo" has a 448 byte value for 05 Disappear.caf
Das Attribut enthält ein JSON-Objekt mit Informationen zum zugrunde liegenden Inode:
$ attr -qg dwarfs.inodeinfo "05 Disappear.caf"
{
"chunks": [
{
"block": 2,
"category": "pcmaudio/metadata",
"offset": 270976,
"size": 4096
},
{
"block": 414,
"category": "pcmaudio/waveform",
"offset": 37594368,
"size": 29514492
},
{
"block": 419,
"category": "pcmaudio/waveform",
"offset": 0,
"size": 29385468
}
],
"gid": 100,
"mode": 33188,
"modestring": "----rw-r--r--",
"uid": 1000
}
Dies ist beispielsweise nützlich, um zu überprüfen, wie eine bestimmte Datei auf mehrere Blöcke verteilt ist oder welche Kategorien der Datei zugewiesen wurden.
Die SquashFS-, xz
, lrzip
, zpaq
und wimlib
Tests wurden alle auf einer 8-Kern-Intel(R) Xeon(R) E-2286M-CPU mit 2,40 GHz und 64 GiB RAM durchgeführt.
Die Cromfs-Tests wurden mit einer älteren Version von DwarFS auf einer 6-Kern-Intel(R) Xeon(R)-CPU D-1528 mit 1,90 GHz und 64 GiB RAM durchgeführt.
Die EROFS-Tests wurden mit DwarFS v0.9.8 und EROFS v1.7.1 auf einem Intel(R) Core(TM) i9-13900K mit 64 GiB RAM durchgeführt.
Während aller Tests waren die Systeme überwiegend im Leerlauf.
Das Quellverzeichnis enthielt 1139 verschiedene Perl-Installationen aus 284 verschiedenen Versionen, insgesamt 47,65 GiB an Daten in 1.927.501 Dateien und 330.733 Verzeichnissen. Das Quellverzeichnis wurde frisch aus einem TAR-Archiv auf eine XFS-Partition auf einem 970 EVO Plus 2 TB NVME-Laufwerk entpackt, sodass der größte Teil seines Inhalts wahrscheinlich zwischengespeichert wurde.
Ich verwende für SquashFS denselben Komprimierungstyp und dieselbe Komprimierungsstufe wie die Standardeinstellung für DwarFS:
$ time mksquashfs install perl-install.squashfs -comp zstd -Xcompression-level 22
Parallel mksquashfs: Using 16 processors
Creating 4.0 filesystem on perl-install-zstd.squashfs, block size 131072.
[=========================================================/] 2107401/2107401 100%
Exportable Squashfs 4.0 filesystem, zstd compressed, data block size 131072
compressed data, compressed metadata, compressed fragments,
compressed xattrs, compressed ids
duplicates are removed
Filesystem size 4637597.63 Kbytes (4528.90 Mbytes)
9.29% of uncompressed filesystem size (49922299.04 Kbytes)
Inode table size 19100802 bytes (18653.13 Kbytes)
26.06% of uncompressed inode table size (73307702 bytes)
Directory table size 19128340 bytes (18680.02 Kbytes)
46.28% of uncompressed directory table size (41335540 bytes)
Number of duplicate files found 1780387
Number of inodes 2255794
Number of files 1925061
Number of fragments 28713
Number of symbolic links 0
Number of device nodes 0
Number of fifo nodes 0
Number of socket nodes 0
Number of directories 330733
Number of ids (unique uids + gids) 2
Number of uids 1
mhx (1000)
Number of gids 1
users (100)
real 32m54.713s
user 501m46.382s
sys 0m58.528s
Für DwarFS bleibe ich bei den Standardeinstellungen:
$ time mkdwarfs -i install -o perl-install.dwarfs
I 11:33:33.310931 scanning install
I 11:33:39.026712 waiting for background scanners...
I 11:33:50.681305 assigning directory and link inodes...
I 11:33:50.888441 finding duplicate files...
I 11:34:01.120800 saved 28.2 GiB / 47.65 GiB in 1782826/1927501 duplicate files
I 11:34:01.122608 waiting for inode scanners...
I 11:34:12.839065 assigning device inodes...
I 11:34:12.875520 assigning pipe/socket inodes...
I 11:34:12.910431 building metadata...
I 11:34:12.910524 building blocks...
I 11:34:12.910594 saving names and links...
I 11:34:12.910691 bloom filter size: 32 KiB
I 11:34:12.910760 ordering 144675 inodes using nilsimsa similarity...
I 11:34:12.915555 nilsimsa: depth=20000 (1000), limit=255
I 11:34:13.052525 updating name and link indices...
I 11:34:13.276233 pre-sorted index (660176 name, 366179 path lookups) [360.6ms]
I 11:35:44.039375 144675 inodes ordered [91.13s]
I 11:35:44.041427 waiting for segmenting/blockifying to finish...
I 11:37:38.823902 bloom filter reject rate: 96.017% (TPR=0.244%, lookups=4740563665)
I 11:37:38.823963 segmentation matches: good=454708, bad=6819, total=464247
I 11:37:38.824005 segmentation collisions: L1=0.008%, L2=0.000% [2233254 hashes]
I 11:37:38.824038 saving chunks...
I 11:37:38.860939 saving directories...
I 11:37:41.318747 waiting for compression to finish...
I 11:38:56.046809 compressed 47.65 GiB to 430.9 MiB (ratio=0.00883101)
I 11:38:56.304922 filesystem created without errors [323s]
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
waiting for block compression to finish
330733 dirs, 0/2440 soft/hard links, 1927501/1927501 files, 0 other
original size: 47.65 GiB, dedupe: 28.2 GiB (1782826 files), segment: 15.19 GiB
filesystem: 4.261 GiB in 273 blocks (319178 chunks, 144675/144675 inodes)
compressed filesystem: 273 blocks/430.9 MiB written [depth: 20000]
█████████████████████████████████████████████████████████████████████████████▏100% |
real 5m23.030s
user 78m7.554s
sys 1m47.968s
In diesem Vergleich ist mkdwarfs
also mehr als sechsmal schneller als mksquashfs
, sowohl in Bezug auf die CPU-Zeit als auch auf die Uhrzeit.
$ ll perl-install.*fs
-rw-r--r-- 1 mhx users 447230618 Mar 3 20:28 perl-install.dwarfs
-rw-r--r-- 1 mhx users 4748902400 Mar 3 20:10 perl-install.squashfs
In Bezug auf das Komprimierungsverhältnis ist das DwarFS-Dateisystem mehr als zehnmal kleiner als das SquashFS-Dateisystem . Mit DwarFS wurde der Inhalt auf weniger als 0,9 % (!) seiner ursprünglichen Größe komprimiert . Dieses Komprimierungsverhältnis berücksichtigt nur die in den einzelnen Dateien gespeicherten Daten, nicht den tatsächlich verwendeten Speicherplatz. Auf dem ursprünglichen XFS-Dateisystem belegt der Quellordner laut du
52 GiB, sodass das DwarFS-Image tatsächlich nur 0,8 % des ursprünglichen Speicherplatzes beansprucht .
Hier ist ein weiterer Vergleich mit lzma
Komprimierung anstelle von zstd
:
$ time mksquashfs install perl-install-lzma.squashfs -comp lzma
real 13m42.825s
user 205m40.851s
sys 3m29.088s
$ time mkdwarfs -i install -o perl-install-lzma.dwarfs -l9
real 3m43.937s
user 49m45.295s
sys 1m44.550s
$ ll perl-install-lzma.*fs
-rw-r--r-- 1 mhx users 315482627 Mar 3 21:23 perl-install-lzma.dwarfs
-rw-r--r-- 1 mhx users 3838406656 Mar 3 20:50 perl-install-lzma.squashfs
Es fällt sofort auf, dass die Durchläufe deutlich schneller und die resultierenden Bilder deutlich kleiner sind. Dennoch ist mkdwarfs
etwa viermal schneller und erzeugt ein Bild, das zwölfmal kleiner ist als das SquashFS-Bild. Das DwarFS-Image hat nur 0,6 % der ursprünglichen Dateigröße.
Warum also nicht standardmäßig lzma
anstelle von zstd
verwenden? Der Grund dafür ist, dass die Dekomprimierung lzma
etwa eine Größenordnung langsamer ist als zstd
. Wenn Sie nur gelegentlich auf Daten in Ihrem komprimierten Dateisystem zugreifen, ist das vielleicht keine große Sache, aber wenn Sie es ausgiebig nutzen, führt zstd
zu einer besseren Leistung.
Die obigen Vergleiche sind nicht ganz fair. mksquashfs
verwendet standardmäßig eine Blockgröße von 128 KiB, während mkdwarfs
standardmäßig 16 MiB-Blöcke oder sogar 64 MiB-Blöcke mit -l9
verwendet. Wenn für beide Dateisysteme identische Blockgrößen verwendet werden, wird der Unterschied erwartungsgemäß viel weniger dramatisch:
$ time mksquashfs install perl-install-lzma-1M.squashfs -comp lzma -b 1M
real 15m43.319s
user 139m24.533s
sys 0m45.132s
$ time mkdwarfs -i install -o perl-install-lzma-1M.dwarfs -l9 -S20 -B3
real 4m25.973s
user 52m15.100s
sys 7m41.889s
$ ll perl-install*.*fs
-rw-r--r-- 1 mhx users 935953866 Mar 13 12:12 perl-install-lzma-1M.dwarfs
-rw-r--r-- 1 mhx users 3407474688 Mar 3 21:54 perl-install-lzma-1M.squashfs
Auch das ist immer noch nicht ganz fair, da es eine Funktion ( -B3
) verwendet, die es DwarFS ermöglicht, auf Dateiblöcke von bis zu zwei vorherigen Dateisystemblöcken zu verweisen.
Aber der Punkt ist, dass SquashFS hier wirklich die Nase vorn hat, da es keine größeren Blockgrößen oder Rückverweise unterstützt. Und wie Sie weiter unten sehen werden, wirken sich die größeren Blöcke, die DwarFS standardmäßig verwendet, nicht unbedingt negativ auf die Leistung aus.
DwarFS bietet außerdem die Möglichkeit, ein vorhandenes Dateisystem mit einem anderen Komprimierungsalgorithmus erneut zu komprimieren. Dies kann nützlich sein, da es ein relativ schnelles Experimentieren mit verschiedenen Algorithmen und Optionen ermöglicht, ohne dass eine vollständige Neuerstellung des Dateisystems erforderlich ist. Beispiel: Neukomprimierung des oben genannten Dateisystems mit der bestmöglichen Komprimierung ( -l 9
):
$ time mkdwarfs --recompress -i perl-install.dwarfs -o perl-lzma-re.dwarfs -l9
I 20:28:03.246534 filesystem rewrittenwithout errors [148.3s]
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
filesystem: 4.261 GiB in 273 blocks (0 chunks, 0 inodes)
compressed filesystem: 273/273 blocks/372.7 MiB written
████████████████████████████████████████████████████████████████████▏100%
real 2m28.279s
user 37m8.825s
sys 0m43.256s