El sistema de archivos avanzado de solo lectura y deduplicación a velocidad warp .
Un rápido sistema de archivos de solo lectura de alta compresión para Linux y Windows.
DwarFS es un sistema de archivos de sólo lectura centrado en lograr índices de compresión muy altos, en particular para datos muy redundantes.
Probablemente esto no suene muy interesante, porque si es redundante, debería comprimirse bien. Sin embargo, descubrí que otros sistemas de archivos comprimidos de sólo lectura no hacen un buen trabajo al aprovechar esta redundancia. Consulte aquí para obtener una comparación con otros sistemas de archivos comprimidos.
DwarFS tampoco compromete la velocidad y, para mis casos de uso, he descubierto que está a la par o funciona mejor que SquashFS. Para mi caso de uso principal, la compresión DwarFS es un orden de magnitud mejor que la compresión SquashFS , es 6 veces más rápida para construir el sistema de archivos , normalmente es más rápido acceder a archivos en DwarFS y utiliza menos recursos de CPU.
Para darle una idea de lo que DwarFS es capaz de hacer, aquí hay una comparación rápida de DwarFS y SquashFS en un conjunto de archivos de video con un tamaño total de 39 GiB. El problema es que cada archivo de vídeo único tiene dos archivos hermanos con un conjunto diferente de secuencias de audio (este es un caso de uso real). Por lo tanto, hay redundancia tanto en los datos de video como de audio, pero como las transmisiones están entrelazadas y los bloques idénticos generalmente están muy separados, es un desafío hacer uso de esa redundancia para la compresión. Básicamente, SquashFS no logra comprimir los datos de origen en absoluto, mientras que DwarFS puede reducir el tamaño en casi un factor de 3, lo que está cerca del máximo teórico:
$ 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
Además, al montar la imagen de SquashFS y realizar una prueba de rendimiento de lectura aleatoria usando fio-3.34, tanto squashfuse
como squashfuse_ll
alcanzan un máximo de alrededor de 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
En comparación, DwarFS logra mantener velocidades de lectura aleatoria de 20 GiB/s :
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
Las características distintivas de DwarFS son:
Agrupación de archivos por similitud mediante una función hash de similitud. Esto facilita el aprovechamiento de la redundancia entre límites de archivos.
Análisis de segmentación entre bloques del sistema de archivos para reducir el tamaño del sistema de archivos sin comprimir. Esto ahorra memoria cuando se utiliza el sistema de archivos comprimido y, por lo tanto, potencialmente permite tasas de aciertos de caché más altas, ya que se pueden mantener más datos en el caché.
Marco de categorización para categorizar archivos o incluso fragmentos de archivos y luego procesar categorías individuales de manera diferente. Por ejemplo, esto le permite no perder el tiempo intentando comprimir archivos incompresibles o comprimir datos de audio PCM mediante compresión FLAC.
Implementación altamente multiproceso. Tanto la herramienta de creación del sistema de archivos como el controlador FUSE pueden hacer un buen uso de los numerosos núcleos de su sistema.
Comencé a trabajar en DwarFS en 2013 y mi principal caso de uso y mi principal motivación fue que tenía varios cientos de versiones diferentes de Perl que ocupaban alrededor de 30 gigabytes de espacio en disco y no estaba dispuesto a gastar más del 10% de mi disco duro. conduje manteniéndolos a mano para cuando los necesitara.
Hasta entonces, había estado usando Cromfs para apretarlos a un tamaño manejable. Sin embargo, me molestaba cada vez más el tiempo que llevaba crear la imagen del sistema de archivos y, para empeorar las cosas, la mayoría de las veces fallaba después de aproximadamente una hora.
Obviamente también había investigado SquashFS, pero nunca me acerqué a las tasas de compresión de Cromfs.
Esto por sí solo no habría sido suficiente para empezar a escribir DwarFS, pero casi al mismo tiempo, estaba bastante obsesionado con los recientes desarrollos y características de los nuevos estándares de C++ y realmente quería un proyecto de pasatiempo de C++ en el que trabajar. Además, hacía bastante tiempo que quería hacer algo con FUSE. Por último, pero no menos importante, había estado pensando un poco en el problema de los sistemas de archivos comprimidos y tenía algunas ideas que definitivamente quería probar.
La mayor parte del código se escribió en 2013, luego hice un par de limpiezas, correcciones de errores y refactorizaciones de vez en cuando, pero nunca llegué a un estado en el que me sintiera feliz de publicarlo. Era demasiado incómodo de construir con su dependencia de la biblioteca de locura (bastante impresionante) de Facebook y no tenía ninguna documentación.
Al examinar nuevamente el proyecto este año, las cosas no parecían tan sombrías como antes. Folly ahora se compila con CMake, por lo que lo incorporé como un submódulo. La mayoría de las demás dependencias pueden satisfacerse con paquetes que deberían estar ampliamente disponibles. Y también he escrito algunos documentos rudimentarios.
DwarFS normalmente debería funcionar bien con cambios mínimos listos para usar. Si no es así, presente un problema. Configuré trabajos de CI usando imágenes de Docker para Ubuntu (22.04 y 24.04), Fedora Rawhide y Arch que pueden ayudar a determinar un conjunto actualizado de dependencias. Tenga en cuenta que compilar desde el tarball de lanzamiento requiere menos dependencias que compilar desde el repositorio de git; en particular, la herramienta ronn
, así como Python y el módulo Python mistletoe
no son necesarios cuando se compila desde el tarball de lanzamiento.
Hay algunas cosas a tener en cuenta:
Hay una tendencia a intentar desagregar las bibliotecas folly y fbthrift que se incluyen como submódulos y se construyen junto con DwarFS. Si bien estoy de acuerdo con el sentimiento, lamentablemente es una mala idea. Además del hecho de que Folly no hace ninguna afirmación sobre la estabilidad de ABI (es decir, no se puede vincular dinámicamente un binario creado con una versión de Folly con otra versión), ni siquiera es posible vincularlo de forma segura con una biblioteca Folly creada con diferentes compilaciones. opciones. Incluso las diferencias sutiles, como la versión estándar de C++, pueden provocar errores en tiempo de ejecución. Consulte este número para obtener más detalles. Actualmente, ni siquiera es posible utilizar versiones externas de folly/fbthrift ya que DwarFS está construyendo subconjuntos mínimos de ambas bibliotecas; estos están incluidos en la biblioteca dwarfs_common
y se usan estrictamente internamente, es decir, ninguno de los encabezados folly o fbthrift es necesario para compilar en las bibliotecas de DwarFS.
Pueden surgir problemas similares al utilizar una versión de GoogleTest instalada en el sistema. El propio GoogleTest recomienda que se descargue como parte de la compilación. Sin embargo, puede usar la versión instalada del sistema pasando -DPREFER_SYSTEM_GTEST=ON
a la llamada cmake
. Úselo bajo su propio riesgo.
Para otras bibliotecas incluidas (a saber, fmt
, parallel-hashmap
, range-v3
), se utiliza la versión instalada en el sistema siempre que cumpla con la versión mínima requerida. De lo contrario, la versión preferida se recupera durante la compilación.
Cada versión tiene archivos binarios prediseñados y vinculados estáticamente para Linux-x86_64
, Linux-aarch64
y Windows-AMD64
disponibles para descargar. Estos deberían ejecutarse sin dependencias y pueden ser útiles especialmente en distribuciones más antiguas donde no es posible crear herramientas fácilmente desde el código fuente.
Además de los archivos comprimidos binarios, hay un binario universal disponible para cada arquitectura. Estos binarios universales contienen todas las herramientas ( mkdwarfs
, dwarfsck
, dwarfsextract
y el controlador dwarfs
FUSE) en un único ejecutable. Estos ejecutables se comprimen usando upx, por lo que son mucho más pequeños que las herramientas individuales combinadas. Sin embargo, también significa que los archivos binarios deben descomprimirse cada vez que se ejecutan, lo que puede generar una sobrecarga significativa. Si eso es un problema, puede utilizar los binarios individuales "clásicos" o descomprimir el binario universal, por ejemplo:
upx -d dwarfs-universal-0.7.0-Linux-aarch64
Los binarios universales se pueden ejecutar a través de enlaces simbólicos que llevan el nombre de la herramienta adecuada. p.ej:
$ ln -s dwarfs-universal-0.7.0-Linux-aarch64 mkdwarfs
$ ./mkdwarfs --help
Esto también funciona en Windows si el sistema de archivos admite enlaces simbólicos:
> mklink mkdwarfs.exe dwarfs-universal-0.7.0-Windows-AMD64.exe
> .mkdwarfs.exe --help
Alternativamente, puede seleccionar la herramienta pasando --tool=<name>
como primer argumento en la línea de comando:
> .dwarfs-universal-0.7.0-Windows-AMD64.exe --tool=mkdwarfs --help
Tenga en cuenta que, al igual que el binario de Windows dwarfs.exe
, el binario universal de Windows depende del winfsp-x64.dll
del proyecto WinFsp. Sin embargo, para el binario universal, la DLL se carga de forma diferida, por lo que aún puedes usar todas las demás herramientas sin la DLL. Consulte la sección Soporte de Windows para obtener más detalles.
DwarFS utiliza CMake como herramienta de compilación.
Utiliza tanto Boost como Folly, aunque este último se incluye como un submódulo ya que muy pocas distribuciones ofrecen paquetes para ello. Folly en sí tiene varias dependencias, así que consulte aquí para obtener una lista actualizada.
También utiliza Facebook Thrift, en particular la biblioteca frozen
, para almacenar metadatos en un formato bien definido, mapeable en memoria y que ahorra mucho espacio. También se incluye como un submódulo, y solo construimos el compilador y una biblioteca muy reducida que contiene lo suficiente para que funcione DwarFS.
Aparte de eso, DwarFS realmente sólo depende de FUSE3 y de un conjunto de bibliotecas de compresión de las que Folly ya depende (es decir, lz4, zstd y liblzma).
La dependencia de googletest se resolverá automáticamente si construye con pruebas.
Un buen punto de partida para los sistemas basados en apt es probablemente:
$ 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
Tenga en cuenta que al compilar con gcc
, el nivel de optimización se establecerá en -O2
en lugar del valor predeterminado de CMake de -O3
para las compilaciones de lanzamiento. Al menos con versiones hasta gcc-10
, la compilación -O3
es hasta un 70% más lenta que una compilación con -O2
.
Primero, descomprima el archivo de lanzamiento:
$ tar xvf dwarfs-x.y.z.tar.xz
$ cd dwarfs-x.y.z
Alternativamente, también puedes clonar el repositorio de git, pero ten en cuenta que esto tiene más dependencias y la compilación probablemente llevará más tiempo porque el archivo de lanzamiento viene con la mayoría de los archivos generados automáticamente que deberán generarse al compilar desde el repositorio:
$ git clone --recurse-submodules https://github.com/mhx/dwarfs
$ cd dwarfs
Una vez que se hayan instalado todas las dependencias, puede compilar DwarFS usando:
$ mkdir build
$ cd build
$ cmake .. -GNinja -DWITH_TESTS=ON
$ ninja
Luego puede ejecutar pruebas con:
$ ctest -j
Todos los archivos binarios utilizan jemalloc como asignador de memoria de forma predeterminada, ya que normalmente utiliza mucha menos memoria del sistema en comparación con los asignadores glibc
o tcmalloc
. Para deshabilitar el uso de jemalloc
, pase -DUSE_JEMALLOC=0
en la línea de comando cmake
.
También es posible compilar/instalar las bibliotecas, herramientas y el controlador FUSE de DwarFS de forma independiente. Esto es sobre todo interesante al empaquetar DwarFS. Tenga en cuenta que las herramientas y el controlador FUSE requieren que las bibliotecas estén compiladas o ya instaladas. Para construir solo las bibliotecas, use:
$ cmake .. -GNinja -DWITH_TESTS=ON -DWITH_LIBDWARFS=ON -DWITH_TOOLS=OFF -DWITH_FUSE_DRIVER=OFF
Una vez que las bibliotecas estén probadas e instaladas, puede crear las herramientas (es decir, mkdwarfs
, dwarfsck
, dwarfsextract
) usando:
$ cmake .. -GNinja -DWITH_TESTS=ON -DWITH_LIBDWARFS=OFF -DWITH_TOOLS=ON -DWITH_FUSE_DRIVER=OFF
Para construir el controlador FUSE, use:
$ cmake .. -GNinja -DWITH_TESTS=ON -DWITH_LIBDWARFS=OFF -DWITH_TOOLS=OFF -DWITH_FUSE_DRIVER=ON
Instalar es tan fácil como:
$ sudo ninja install
Aunque no es necesario instalar las herramientas para jugar con ellas.
Se desaconseja intentar crear archivos binarios vinculados estáticamente y no se admite oficialmente. Dicho esto, a continuación se explica cómo configurar un entorno en el que pueda crear archivos binarios estáticos.
Esto ha sido probado con ubuntu-22.04-live-server-amd64.iso
. Primero, instale todos los paquetes enumerados como dependencias anteriormente. Instale también:
$ apt install ccache ninja libacl1-dev
ccache
y ninja
son opcionales, pero ayudan con una compilación rápida.
Dependiendo de su distribución, necesitará compilar e instalar versiones estáticas de algunas bibliotecas, por ejemplo, libarchive
y libmagic
para 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
¡Eso es todo! Ahora puedes intentar crear binarios estáticos para DwarFS:
$ 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
Consulte las páginas del manual de mkdwarfs, dwarfs, dwarfsck y dwarfsextract. También puede acceder a las páginas del manual usando la opción --man
para cada binario, por ejemplo:
$ mkdwarfs --man
La página del manual de Dwarfs también muestra un ejemplo para configurar DwarFS con superposiciones para crear un sistema de archivos grabable montado sobre una imagen de DwarFS de solo lectura.
Puede encontrar una descripción del formato del sistema de archivos DwarFS en formato enano.
En este diagrama de secuencia se muestra una descripción general de alto nivel del funcionamiento interno de mkdwarfs
.
Usar las bibliotecas DwarFS debería ser bastante sencillo si usas CMake para construir tu proyecto. Para comenzar rápidamente, eche un vistazo al código de ejemplo que utiliza las bibliotecas para imprimir información sobre una imagen DwarFS (como dwarfsck
) o extraerla (como dwarfsextract
).
Hay cinco bibliotecas individuales:
dwarfs_common
contiene el código común requerido por todas las demás bibliotecas. Las interfaces están definidas en dwarfs/
.
dwarfs_reader
contiene todo el código necesario para leer datos de una imagen DwarFS. Las interfaces están definidas en dwarfs/reader/
.
dwarfs_extractor
contiene el código C necesario para extraer una imagen DwarFS usando libarchive
. Las interfaces están definidas en dwarfs/utility/filesystem_extractor.h
.
dwarfs_writer
contiene el código necesario para crear imágenes DwarFS. Las interfaces están definidas en dwarfs/writer/
.
dwarfs_rewrite
contiene el código para reescribir imágenes de DwarFS. Las interfaces están definidas en dwarfs/utility/rewrite_filesystem.h
.
Solo se puede acceder a los encabezados de las subcarpetas internal
en el momento de la compilación y no se instalarán. Lo mismo ocurre con la subcarpeta tool
.
Las API de lectura y extracción deberían ser bastante estables. Es probable que las API del escritor cambien. Sin embargo, tenga en cuenta que no hay garantías sobre la estabilidad de la API antes de que este proyecto alcance la versión 1.0.0.
La compatibilidad con el sistema operativo Windows es actualmente experimental. Habiendo trabajado prácticamente exclusivamente en un mundo Unix durante las últimas dos décadas, mi experiencia con el desarrollo de Windows es bastante limitada y esperaría que definitivamente hubiera errores y asperezas en el código de Windows.
La versión de Windows del controlador del sistema de archivos DwarFS se basa en el increíble proyecto WinFsp y el controlador dwarfs.exe
debe poder detectar su winfsp-x64.dll
.
Las diferentes herramientas deberían comportarse más o menos igual ya sea que las use en Linux o Windows. Las imágenes del sistema de archivos se pueden copiar entre Linux y Windows y las imágenes creadas en un sistema operativo deberían funcionar bien en el otro.
Sin embargo, hay algunas cosas que vale la pena señalar:
DwarFS admite enlaces físicos y enlaces simbólicos en Windows, tal como lo hace en Linux. Sin embargo, la creación de enlaces físicos y enlaces simbólicos parece requerir privilegios de administrador en Windows, por lo que si desea, por ejemplo, extraer una imagen de DwarFS que contenga enlaces de algún tipo, puede encontrarse con errores si no tiene los privilegios adecuados.
Debido a un problema en WinFsp, los enlaces simbólicos actualmente no pueden apuntar fuera del sistema de archivos montado. Además, debido a otro problema en WinFsp, los enlaces simbólicos con una letra de unidad aparecerán con una ruta de destino destrozada.
El controlador DwarFS en Windows informa correctamente los recuentos de enlaces físicos a través de su API, pero actualmente estos recuentos no se propagan correctamente a la capa del sistema de archivos de Windows. Probablemente esto se deba a un problema en WinFsp.
Al montar una imagen DwarFS en Windows, el punto de montaje no debe existir. Esto es diferente de Linux, donde el punto de montaje debe existir realmente. Además, es posible montar una imagen DwarFS como letra de unidad, por ejemplo
enanos.exe imagen.enanos Z:
Las reglas de filtrado para mkdwarfs
siempre requieren separadores de ruta de Unix, independientemente de si se ejecuta en Windows o Linux.
Construir en Windows no es demasiado complicado gracias a vcpkg. Necesitará instalar:
Visual Studio y el compilador MSVC C/C++
git
Chacer
ninja
WinFsp
Se espera que WinFsp
se instale en C:Program Files (x86)WinFsp
; si no es así, deberá configurar WINFSP_PATH
cuando ejecute CMake a través de cmake/win.bat
.
Ahora necesitas clonar vcpkg
y dwarfs
:
> cd %HOMEPATH%
> mkdir git
> cd git
> git clone https://github.com/Microsoft/vcpkg.git
> git clone https://github.com/mhx/dwarfs
Luego, arranca vcpkg
:
> .vcpkgbootstrap-vcpkg.bat
Y construye DwarFS:
> cd dwarfs
> mkdir build
> cd build
> ..cmakewin.bat
> ninja
Una vez hecho esto, debería poder ejecutar las pruebas. Configure CTEST_PARALLEL_LEVEL
de acuerdo con la cantidad de núcleos de CPU en su máquina.
> set CTEST_PARALLEL_LEVEL=10
> ninja test
Las bibliotecas y herramientas de DwarFS ( mkdwarfs
, dwarfsck
, dwarfsextract
) ahora están disponibles en Homebrew:
$ brew install dwarfs
$ brew test dwarfs
La versión macOS del controlador del sistema de archivos DwarFS se basa en el fantástico proyecto macFUSE. Hasta que se agregue una fórmula, deberá crear el controlador DwarFS FUSE manualmente.
Construir en macOS debería ser relativamente sencillo:
Instalar cerveza casera
Utilice Homebrew para instalar las dependencias necesarias:
$ 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
Al instalar macFUSE por primera vez, deberá permitir explícitamente el software en Preferencias del Sistema / Privacidad y Seguridad . Es muy probable que tengas que reiniciar después de esto.
Descargue un tarball de lanzamiento desde la página de lanzamientos y extráigalo:
$ 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
de la brew install
y usar lo siguiente en lugar del primer comando cmake
anterior: $ 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
¡Eso es todo!
La astrofotografía puede generar enormes cantidades de datos de imágenes sin procesar. Durante una sola noche, no es improbable terminar con unas cuantas docenas de gigabytes de datos. Con la mayoría de las cámaras dedicadas a la astrofotografía, estos datos terminan en forma de imágenes FITS. Por lo general, no están comprimidos, no se comprimen muy bien con los algoritmos de compresión estándar y, si bien existen ciertos formatos FITS comprimidos, no son ampliamente compatibles.
Uno de los formatos de compresión (llamado simplemente "Rice") se comprime razonablemente bien y es realmente rápido. Sin embargo, su implementación para FITS comprimidos tiene algunos inconvenientes. Los inconvenientes más graves son que la compresión no es tan buena como podría ser para sensores de color y sensores con menos de 16 bits de resolución.
DwarFS admite la compresión ricepp
(Rice++), que se basa en la idea básica de la compresión Rice, pero realiza algunas mejoras: comprime significativamente mejor el color y las imágenes de baja profundidad de bits y siempre busca la solución óptima durante la compresión en lugar de depender de una heurística. .
Veamos un ejemplo usando 129 imágenes (oscuras, planas y claras) tomadas con una cámara ASI1600MM. Cada imagen tiene 32 MiB, por lo que hay un total de 4 GiB de datos. Comprimirlos con la herramienta fpack
estándar tarda unos 16,6 segundos y produce un tamaño de salida total de 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
Sin embargo, esto te deja con archivos *.fz
que no todas las aplicaciones pueden leer.
Usando DwarFS, esto es lo que obtenemos:
$ 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
En menos de 3,4 segundos, comprime los datos a 1,2 GiB, casi la mitad del tamaño de la salida fpack
.
Además de ahorrar mucho espacio en disco, esto también puede resultar útil cuando sus datos se almacenan en un NAS. A continuación se muestra una comparación del mismo conjunto de datos al que se accede a través de una conexión de red de 1 Gb/s, utilizando primero los datos sin comprimir:
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
Y luego usando una imagen DwarFS en el mismo recurso compartido:
$ 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
Eso es aproximadamente 2,5 veces más rápido. Es muy probable que puedas ver resultados similares con discos duros externos lentos.
Actualmente, DwarFS no tiene la capacidad integrada de agregar información de recuperación a una imagen del sistema de archivos. Sin embargo, para fines de archivo, es una buena idea tener dicha información de recuperación para poder reparar una imagen dañada.
Afortunadamente, esto es relativamente sencillo usando algo como par2cmdline:
$ par2create -n1 asi1600-20.dwarfs
Esto creará dos archivos adicionales que puede colocar junto a la imagen (o en un almacenamiento diferente), ya que solo los necesitará si DwarFS ha detectado un problema con la imagen del sistema de archivos. Si hay un problema, puedes ejecutar
$ par2repair asi1600-20.dwarfs
que muy probablemente podrá recuperar la imagen si menos del 5% (que es el valor predeterminado utilizado por par2create
) de la imagen está dañada.
Actualmente no se admiten los atributos extendidos. Cualquier atributo extendido almacenado en el sistema de archivos fuente no se conservará actualmente al crear una imagen DwarFS usando mkdwarfs
.
Dicho esto, el inodo raíz de una imagen DwarFS montada actualmente expone uno o dos atributos extendidos en Linux:
$ 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
El atributo dwarfs.driver.pid
simplemente contiene el PID del controlador DwarFS FUSE. El atributo dwarfs.driver.perfmon
contiene los resultados actuales del monitor de rendimiento.
Además, cada archivo normal expone un atributo dwarfs.inodeinfo
con información sobre el inodo subyacente:
$ attr -l "05 Disappear.caf"
Attribute "dwarfs.inodeinfo" has a 448 byte value for 05 Disappear.caf
El atributo contiene un objeto JSON con información sobre el inodo subyacente:
$ 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
}
Esto es útil, por ejemplo, para comprobar cómo se distribuye un archivo en particular en varios bloques o qué categorías se han asignado al archivo.
Las pruebas de SquashFS, xz
, lrzip
, zpaq
y wimlib
se realizaron en una CPU Intel(R) Xeon(R) E-2286M de 8 núcleos a 2,40 GHz con 64 GiB de RAM.
Las pruebas de Cromfs se realizaron con una versión anterior de DwarFS en una CPU Intel(R) Xeon(R) D-1528 de 6 núcleos a 1,90 GHz con 64 GiB de RAM.
Las pruebas de EROFS se realizaron utilizando DwarFS v0.9.8 y EROFS v1.7.1 en un Intel(R) Core(TM) i9-13900K con 64 GiB de RAM.
Los sistemas estuvieron mayoritariamente inactivos durante todas las pruebas.
El directorio fuente contenía 1139 instalaciones diferentes de Perl de 284 versiones distintas, un total de 47,65 GiB de datos en 1.927.501 archivos y 330.733 directorios. El directorio de origen se descomprimió recientemente de un archivo tar a una partición XFS en una unidad NVME 970 EVO Plus de 2 TB, por lo que la mayoría de su contenido probablemente estaba almacenado en caché.
Estoy usando el mismo tipo y nivel de compresión para SquashFS que es la configuración predeterminada para 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
Para DwarFS, me quedo con los valores predeterminados:
$ 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
Entonces, en esta comparación, mkdwarfs
es más de 6 veces más rápido que mksquashfs
, tanto en términos de tiempo de CPU como de reloj de pared.
$ 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
En términos de relación de compresión, el sistema de archivos DwarFS es más de 10 veces más pequeño que el sistema de archivos SquashFS . Con DwarFS, el contenido se ha comprimido a menos del 0,9% (!) de su tamaño original . Esta relación de compresión sólo considera los datos almacenados en los archivos individuales, no el espacio en disco real utilizado. En el sistema de archivos XFS original, según du
, la carpeta de origen usa 52 GiB, por lo que la imagen DwarFS en realidad solo usa el 0,8% del espacio original .
Aquí hay otra comparación que usa la compresión lzma
en lugar de 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 inmediatamente obvio que las ejecuciones son significativamente más rápidas y las imágenes resultantes son significativamente más pequeñas. Aún así, mkdwarfs
es aproximadamente 4 veces más rápido y produce una imagen 12 veces más pequeña que la imagen de SquashFS. La imagen de DwarFS tiene solo el 0,6% del tamaño del archivo original.
Entonces, ¿por qué no utilizar lzma
en lugar de zstd
de forma predeterminada? La razón es que lzma
es aproximadamente un orden de magnitud más lento de descomprimir que zstd
. Si solo accede ocasionalmente a los datos de su sistema de archivos comprimidos, puede que esto no sea un gran problema, pero si lo usa extensamente, zstd
dará como resultado un mejor rendimiento.
Las comparaciones anteriores no son del todo justas. mksquashfs
utiliza de forma predeterminada un tamaño de bloque de 128 KiB, mientras que mkdwarfs
utiliza bloques de 16 MiB de forma predeterminada, o incluso bloques de 64 MiB con -l9
. Cuando se utilizan tamaños de bloque idénticos para ambos sistemas de archivos, la diferencia, como era de esperar, se vuelve mucho menos dramática:
$ 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
Incluso esto todavía no es del todo justo, ya que utiliza una característica ( -B3
) que permite a DwarFS hacer referencia a fragmentos de archivos de hasta dos bloques anteriores del sistema de archivos.
Pero el punto es que aquí es realmente donde SquashFS alcanza su punto máximo, ya que no admite tamaños de bloques más grandes ni referencias inversas. Y como verá a continuación, los bloques más grandes que DwarFS utiliza de forma predeterminada no necesariamente afectan negativamente el rendimiento.
DwarFS también presenta una opción para recomprimir un sistema de archivos existente con un algoritmo de compresión diferente. Esto puede resultar útil ya que permite una experimentación relativamente rápida con diferentes algoritmos y opciones sin necesidad de una reconstrucción completa del sistema de archivos. Por ejemplo, recomprimir el sistema de archivos anterior con la mejor compresión posible ( -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