消除重複的Warp -speed高級唯讀檔案系統。
適用於 Linux 和 Windows 的快速高壓縮唯讀檔案系統。
DwarFS 是一個唯讀檔案系統,專注於實現非常高的壓縮比,特別是對於非常冗餘的資料。
這聽起來可能不太令人興奮,因為如果它是多餘的,它應該可以很好地壓縮。然而,我發現其他唯讀、壓縮檔案系統在利用這種冗餘方面做得不好。請參閱此處與其他壓縮檔案系統的比較。
DwarFS 也不會在速度上妥協,對於我的用例,我發現它與 SquashFS 相當或性能更好。對於我的主要用例, DwarFS 壓縮比 SquashFS 壓縮好一個數量級,建置檔案系統的速度快 6 倍,存取 DwarFS 上的檔案通常更快,並且使用更少的 CPU 資源。
為了讓您了解 DwarFS 的功能,以下是 DwarFS 和 SquashFS 在一組總大小為 39 GiB 的影片檔案上的快速比較。不同之處在於,每個唯一的視訊檔案都有兩個具有不同音訊串流集的同級檔案(這是一個實際用例)。因此,視訊和音訊資料都存在冗餘,但由於串流是交錯的,並且相同的區塊通常相距很遠,因此利用該冗餘進行壓縮具有挑戰性。 SquashFS 本質上根本無法壓縮來源數據,而 DwarFS 能夠將大小減少近 3 倍,接近理論最大值:
$ 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
此外,當安裝 SquashFS 映像並使用 fio-3.34 執行隨機讀取吞吐量測試時, squashfuse
和squashfuse_ll
最高速度約為 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
相較之下,DwarFS 能夠維持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
DwarFS 的顯著特徵是:
使用相似性雜湊函數按相似性對檔案進行聚類。這使得更容易利用跨文件邊界的冗餘。
跨檔案系統區塊的分段分析,以減少未壓縮檔案系統的大小。這在使用壓縮檔案系統時可以節省內存,因此可能會允許更高的快取命中率,因為快取中可以保存更多資料。
分類框架會將文件甚至文件片段進行分類,然後以不同的方式處理各個類別。例如,這使您不必浪費時間嘗試壓縮不可壓縮的檔案或使用 FLAC 壓縮來壓縮 PCM 音訊資料。
高度多執行緒實作。檔案系統建立工具和 FUSE 驅動程式都能夠充分利用系統的多個核心。
我從 2013 年開始研究 DwarFS,我的主要用例和主要動機是我有數百個不同版本的 Perl,它們佔用了大約 30 GB 的磁碟空間,而且我不願意花費超過 10% 的硬碟空間。把它們放在身邊,以備不時之需。
在那之前,我一直在使用 Cromfs 將它們壓縮成可管理的大小。然而,我對建立檔案系統映像所花費的時間越來越惱火,更糟糕的是,它通常會在大約一個小時左右後崩潰。
我顯然也研究過 SquashFS,但從來沒有接近過 Cromfs 的壓縮率。
僅此一點還不足以讓我開始編寫 DwarFS,但大約在同一時間,我非常著迷於較新的 C++ 標準的最新發展和功能,並且真的想要一個 C++ 業餘愛好項目。另外,我想用 FUSE 做一些事情已經有一段時間了。最後但並非最不重要的一點是,我一直在思考壓縮檔案系統的問題,並且有一些我絕對想嘗試的想法。
大部分程式碼是在 2013 年編寫的,然後我每隔一段時間就會進行一些清理、錯誤修復和重構,但我從未真正達到讓我樂意發布它的狀態。由於它依賴 Facebook 的(非常棒的)愚蠢的庫,所以構建起來太尷尬了,而且它沒有任何文件。
今年再次挖掘該項目,情況看起來並不像以前那麼嚴峻。 Folly 現在使用 CMake 構建,因此我只是將其作為子模組拉入。大多數其他依賴項可以透過應該廣泛可用的套件來滿足。我也寫了一些基本文檔。
DwarFS 通常應該可以透過開箱即用的最小變更來建構良好。如果沒有,請提出問題。我已經使用 Ubuntu(22.04 和 24.04)、Fedora Rawhide 和 Arch 的 Docker 映像設定了 CI 作業,它們可以協助確定一組最新的依賴項。請注意,從發布 tarball 建置需要的依賴項比從 git 儲存庫建置要少,特別是從發布 tarball 建置時不需要ronn
工具以及 Python 和mistletoe
Python 模組。
有一些事情要注意:
人們傾向於嘗試將 folly 和 fbthrift 庫拆分為子模組並與 DwarFS 一起建置。雖然我同意這種觀點,但不幸的是這是一個壞主意。除了folly 沒有對ABI 穩定性做出任何聲明(即,您不能僅將針對一個版本的folly 構建的二進製文件動態鏈接到另一個版本)之外,甚至不可能安全地鏈接到使用不同編譯構建的folly庫選項。即使是細微的差異(例如 C++ 標準版本)也可能導致執行時期錯誤。詳情請參閱本期。目前,甚至不可能使用 folly/fbthrift 的外部版本,因為 DwarFS 正在建立這兩個庫的最小子集;這些都捆綁在dwarfs_common
庫中,並且嚴格在內部使用,即針對 DwarFS 庫構建時不需要任何愚蠢或 fbthrift 標頭。
使用系統安裝的 GoogleTest 版本時可能會出現類似的問題。 GoogleTest 本身建議將其作為構建的一部分進行下載。但是,您可以透過將-DPREFER_SYSTEM_GTEST=ON
傳遞給cmake
呼叫來使用系統安裝的版本。使用風險自負。
對於其他捆綁庫(即fmt
、 parallel-hashmap
、 range-v3
),只要滿足最低版本要求,就使用系統安裝的版本。否則,將在建置期間取得首選版本。
每個版本都有適用於Linux-x86_64
、 Linux-aarch64
和Windows-AMD64
的預先建置靜態連結二進位檔案可供下載。這些應該在沒有任何依賴關係的情況下運行,並且在您無法輕鬆地從原始碼建立工具的舊發行版上尤其有用。
除了二進位 tarball 之外,還有適用於每種架構的通用二進位。這些通用二進位檔案在單一執行檔中包含所有工具( mkdwarfs
、 dwarfsck
、 dwarfsextract
和dwarfs
FUSE 驅動程式)。這些可執行檔是使用 upx 壓縮的,因此它們比單一工具的總和小得多。然而,這也意味著每次運行二進位檔案時都需要解壓縮,這可能會產生很大的開銷。如果這是一個問題,您可以堅持使用「經典」單一二進位文件,也可以解壓縮通用二進位文件,例如:
upx -d dwarfs-universal-0.7.0-Linux-aarch64
通用二進位檔案可以透過以適當工具命名的符號連結來運行。例如:
$ ln -s dwarfs-universal-0.7.0-Linux-aarch64 mkdwarfs
$ ./mkdwarfs --help
如果檔案系統支援符號鏈接,這也適用於 Windows:
> mklink mkdwarfs.exe dwarfs-universal-0.7.0-Windows-AMD64.exe
> .mkdwarfs.exe --help
或者,您可以透過傳遞--tool=<name>
作為命令列上的第一個參數來選擇該工具:
> .dwarfs-universal-0.7.0-Windows-AMD64.exe --tool=mkdwarfs --help
請注意,就像dwarfs.exe
Windows 二進位檔案一樣,通用 Windows 二進位檔案依賴 WinFsp 專案中的winfsp-x64.dll
。但是,對於通用二進位文件,DLL 是延遲載入的,因此您仍然可以在沒有 DLL 的情況下使用所有其他工具。有關更多詳細信息,請參閱 Windows 支援部分。
DwarFS 使用 CMake 作為建置工具。
它同時使用 Boost 和 Folly,儘管後者作為子模組包含在內,因為很少有發行版實際上為其提供軟體包。 Folly 本身有許多依賴項,因此請在此處查看最新清單。
它還使用 Facebook Thrift,特別是frozen
庫,以高度空間效率、記憶體可映射和定義明確的格式儲存元資料。它也作為子模組包含在內,我們只建構編譯器和一個非常精簡的函式庫,其中包含足以讓 DwarFS 運作的函式庫。
除此之外,DwarFS 實際上只依賴 FUSE3 和 Folly 已經依賴的一組壓縮函式庫(即 lz4、zstd 和 liblzma)。
如果您使用測試進行構建,對 googletest 的依賴將自動解決。
基於 apt 的系統的一個好的起點可能是:
$ 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
請注意,使用gcc
建置時,最佳化等級將設定為-O2
而不是發佈版本的 CMake 預設值-O3
。至少對於gcc-10
之前的版本, -O3
構建比使用-O2
的構建慢 70% 。
首先,解壓縮發布存檔:
$ tar xvf dwarfs-x.y.z.tar.xz
$ cd dwarfs-x.y.z
或者,您也可以克隆 git 存儲庫,但請注意,這具有更多依賴性,並且構建可能需要更長的時間,因為發布存檔附帶了從存儲庫構建時必須生成的大多數自動生成的文件:
$ git clone --recurse-submodules https://github.com/mhx/dwarfs
$ cd dwarfs
安裝所有依賴項後,您可以使用以下命令建置 DwarFS:
$ mkdir build
$ cd build
$ cmake .. -GNinja -DWITH_TESTS=ON
$ ninja
然後您可以使用以下命令執行測試:
$ ctest -j
預設情況下,所有二進位檔案都使用 jemalloc 作為記憶體分配器,因為與glibc
或tcmalloc
分配器相比,它通常使用較少的系統記憶體。若要停用jemalloc
的使用,請在cmake
命令列上傳遞-DUSE_JEMALLOC=0
。
還可以獨立建置/安裝 DwarFS 庫、工具和 FUSE 驅動程式。這在打包 DwarFS 時最有趣。請注意,工具和 FUSE 驅動程式要求已建置或已安裝庫。若要僅建置庫,請使用:
$ cmake .. -GNinja -DWITH_TESTS=ON -DWITH_LIBDWARFS=ON -DWITH_TOOLS=OFF -DWITH_FUSE_DRIVER=OFF
測試並安裝程式庫後,您可以使用下列命令建置工具(即mkdwarfs
、 dwarfsck
、 dwarfsextract
):
$ cmake .. -GNinja -DWITH_TESTS=ON -DWITH_LIBDWARFS=OFF -DWITH_TOOLS=ON -DWITH_FUSE_DRIVER=OFF
要建立 FUSE 驅動程序,請使用:
$ cmake .. -GNinja -DWITH_TESTS=ON -DWITH_LIBDWARFS=OFF -DWITH_TOOLS=OFF -DWITH_FUSE_DRIVER=ON
安裝非常簡單:
$ sudo ninja install
儘管您不必安裝工具來使用它們。
強烈建議不要嘗試建立靜態連結的二進位文件,並且不受官方支援。話雖這麼說,以下是如何設定一個可以建立靜態二進位檔案的環境。
這已使用ubuntu-22.04-live-server-amd64.iso
進行了測試。首先,安裝上面列出的所有依賴項。還安裝:
$ apt install ccache ninja libacl1-dev
ccache
和ninja
是可選的,但有助於快速編譯。
根據您的發行版,您需要建置和安裝某些程式庫的靜態版本,例如 Ubuntu 的libarchive
和libmagic
:
$ 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
就是這樣!現在您可以嘗試為 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
請查看 mkdwarfs、dwarfs、dwarfsck 和 dwarfsextract 的手冊頁。您也可以使用每個二進位檔案的--man
選項存取手冊頁,例如:
$ mkdwarfs --man
dwarfs 手冊頁也顯示了使用 overlayfs 設定 DwarFS 的範例,以便在唯讀 DwarFS 映像之上建立可寫入檔案系統掛載。
DwarFS 檔案系統格式的描述可以在 dwarfs-format 中找到。
此序列圖中顯示了mkdwarfs
內部操作的高階概述。
如果您使用 CMake 建置項目,那麼使用 DwarFS 函式庫應該非常簡單。為了快速入門,請查看範例程式碼,該程式碼使用庫來列印有關 DwarFS 圖像的資訊(如dwarfsck
)或提取它(如dwarfsextract
)。
有五個單獨的庫:
dwarfs_common
包含所有其他函式庫所需的通用程式碼。介面在dwarfs/
中定義。
dwarfs_reader
包含從 DwarFS 映像讀取資料所需的所有程式碼。介面在dwarfs/reader/
中定義。
dwarfs_extractor
包含使用libarchive
提取 DwarFS 映像所需的程式碼。這些介面在dwarfs/utility/filesystem_extractor.h
中定義。
dwarfs_writer
包含建立 DwarFS 映像所需的程式碼。介面在dwarfs/writer/
中定義。
dwarfs_rewrite
包含重寫 DwarFS 映像的程式碼。這些介面在dwarfs/utility/rewrite_filesystem.h
中定義。
internal
子資料夾中的標頭只能在建置時訪問,並且不會安裝。 tool
子資料夾也是如此。
讀取器和提取器 API 應該相當穩定。編寫器 API 可能會發生變化。但請注意,在專案達到版本 1.0.0 之前,無法保證 API 穩定性。
對 Windows 作業系統的支援目前處於實驗階段。在過去的二十年裡,我幾乎完全在 Unix 世界中工作,因此我在 Windows 開發方面的經驗相當有限,我預計 Windows 程式碼中肯定存在錯誤和粗糙的邊緣。
Windows 版本的 DwarFS 檔案系統驅動程式依賴出色的 WinFsp 項目,且其winfsp-x64.dll
必須可由dwarfs.exe
驅動程式發現。
無論您是在 Linux 還是 Windows 上使用不同的工具,它們的行為都應該幾乎相同。檔案系統映像可以在 Linux 和 Windows 之間複製,並且在一個作業系統上建立的映像應該可以在另一個作業系統上正常運作。
不過,有幾點值得指出:
DwarFS 在 Windows 上支援硬連結和符號鏈接,就像在 Linux 上一樣。然而,建立硬連結和符號連結似乎需要 Windows 上的管理員權限,因此,如果您想要提取包含某種連結的 DwarFS 映像,如果您沒有正確的權限,則可能會遇到錯誤。
由於 WinFsp 中的問題,符號連結目前無法指向已安裝的檔案系統之外。此外,由於 WinFsp 中的另一個問題,帶有磁碟機號碼的符號連結將出現錯誤的目標路徑。
Windows 上的 DwarFS 驅動程式透過其 API 正確報告硬連結計數,但目前這些計數未正確傳播到 Windows 檔案系統層。這可能是由於 WinFsp 中的問題造成的。
在 Windows 上掛載 DwarFS 映像時,掛載點不能存在。這與 Linux 不同,Linux 中掛載點必須實際存在。此外,還可以將 DwarFS 映像掛載為磁碟機號,例如
dwarfs.exe image.dwarfs Z:
mkdwarfs
的過濾規則始終需要 Unix 路徑分隔符,無論它是在 Windows 還是 Linux 上執行。
由於 vcpkg,在 Windows 上建置並不太複雜。您需要安裝:
Visual Studio 和 MSVC C/C++ 編譯器
git
CMake
忍者
作業系統
WinFsp
預計安裝在C:Program Files (x86)WinFsp
;如果不是,則需要在透過cmake/win.bat
執行 CMake 時設定WINFSP_PATH
。
現在您需要複製vcpkg
和dwarfs
:
> cd %HOMEPATH%
> mkdir git
> cd git
> git clone https://github.com/Microsoft/vcpkg.git
> git clone https://github.com/mhx/dwarfs
然後,引導vcpkg
:
> .vcpkgbootstrap-vcpkg.bat
並建構 DwarFS:
> cd dwarfs
> mkdir build
> cd build
> ..cmakewin.bat
> ninja
完成後,您應該能夠運行測試。根據您機器中CPU核心的數量設定CTEST_PARALLEL_LEVEL
。
> set CTEST_PARALLEL_LEVEL=10
> ninja test
DwarFS 函式庫和工具( mkdwarfs
、 dwarfsck
、 dwarfsextract
)現在可從 Homebrew 取得:
$ brew install dwarfs
$ brew test dwarfs
macOS 版本的 DwarFS 檔案系統驅動程式依賴於很棒的 macFUSE 專案。在新增公式之前,您必須手動建立 DwarFS FUSE 驅動程式。
在 macOS 上建置應該相對簡單:
安裝自製軟體
使用 Homebrew 安裝必要的依賴項:
$ 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
首次安裝 macFUSE 時,您需要在系統偏好設定/隱私和安全性中明確允許軟體。此後您很可能必須重新啟動。
從發布頁面下載發布 tarball 並解壓縮:
$ 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
brew install
中省略macfuse
,並使用以下命令代替上面的第一個cmake
命令: $ 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
就是這樣!
天文攝影可以產生大量原始影像資料。在一個晚上,最終可能會產生幾十 GB 的數據。對於大多數專用天文攝影相機,這些數據最終都會以 FITS 影像的形式出現。這些格式通常是未壓縮的,使用標準壓縮演算法不能很好地壓縮,並且雖然存在某些壓縮的 FITS 格式,但它們並未廣泛支援。
其中一種壓縮格式(簡稱為“Rice”)壓縮效果相當好,而且速度非常快。然而,其壓縮 FITS 的實作有一些缺點。最嚴重的缺點是,對於顏色感測器和解析度低於 16 位元的感測器,壓縮效果並不理想。
DwarFS 支援ricepp
(Rice++) 壓縮,該壓縮基於Rice 壓縮的基本思想,但進行了一些增強:它可以更好地壓縮彩色和低位深度圖像,並且在壓縮過程中始終搜索最佳解決方案,而不是依賴啟發式演算法。
讓我們來看一個使用 ASI1600MM 相機拍攝的 129 張影像(黑暗、平坦和明亮)的範例。每個影像為 32 MiB,因此總共 4 GiB 的資料。使用標準fpack
工具壓縮這些檔案大約需要 16.6 秒,總輸出大小為 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
但是,這會為您留下並非每個應用程式都能真正讀取的*.fz
檔案。
使用 DwarFS,我們得到以下結果:
$ 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
在不到 3.4 秒的時間內,它將資料壓縮至 1.2 GiB,幾乎是fpack
輸出大小的一半。
除了節省大量磁碟空間之外,當您的資料儲存在 NAS 上時,這也很有用。以下是透過 1 Gb/s 網路連線存取的同一組資料的比較,首先使用未壓縮的原始資料:
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
接下來在相同共用上使用 DwarFS 映像:
$ 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
這大約快了 2.5 倍。對於速度較慢的外部硬碟,您很可能會看到類似的結果。
目前,DwarFS 沒有內建功能將恢復資訊新增至檔案系統映像。但是,出於存檔目的,最好擁有此類恢復訊息,以便能夠修復損壞的影像。
幸運的是,使用 par2cmdline 之類的東西相對簡單:
$ par2create -n1 asi1600-20.dwarfs
這將建立兩個額外的文件,您可以將它們放置在映像旁邊(或放置在不同的儲存空間上),因為只有當 DwarFS 偵測到檔案系統映像有問題時,您才需要它們。如果出現問題,您可以運行
$ par2repair asi1600-20.dwarfs
如果少於 5%(這是par2create
使用的預設值)的圖像損壞,它很可能能夠恢復圖像。
目前不支援擴展屬性。使用mkdwarfs
建置 DwarFS 映像時,目前不會保留來源檔案系統中儲存的任何擴充屬性。
話雖這麼說,已安裝的 DwarFS 映像的根 inode 目前在 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
dwarfs.driver.pid
屬性僅包含 DwarFS FUSE 驅動程式的 PID。 dwarfs.driver.perfmon
屬性包含效能監視器的目前結果。
此外,每個常規檔案都會公開一個屬性dwarfs.inodeinfo
其中包含有關底層 inode 的資訊:
$ attr -l "05 Disappear.caf"
Attribute "dwarfs.inodeinfo" has a 448 byte value for 05 Disappear.caf
此屬性包含一個 JSON 對象,其中包含有關底層 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
}
例如,這對於檢查特定檔案如何分佈在多個區塊中或已將哪些類別指派給該檔案很有用。
SquashFS、 xz
、 lrzip
、 zpaq
和wimlib
測試皆在 8 核心 Intel(R) Xeon(R) E-2286M CPU @ 2.40GHz 和 64 GiB RAM 上完成。
Cromfs 測試是在 6 核心 Intel(R) Xeon(R) CPU D-1528 @ 1.90GHz 和 64 GiB RAM 上使用舊版的 DwarFS 完成的。
EROFS 測試是在具有 64 GiB RAM 的 Intel(R) Core(TM) i9-13900K 上使用 DwarFS v0.9.8 和 EROFS v1.7.1 完成的。
在所有測試期間,系統大部分處於閒置狀態。
來源目錄包含來自 284 個不同版本的1139 個不同的 Perl 安裝,1,927,501 個檔案和 330,733 個目錄中總共 47.65 GiB 的資料。來源目錄剛從 tar 檔案解壓縮到 970 EVO Plus 2TB NVME 磁碟機上的 XFS 分割區,因此其大部分內容可能已被快取。
我對 SquashFS 使用相同的壓縮類型和壓縮級別,這是 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
對於 DwarFS,我堅持使用預設值:
$ 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
因此,在此比較中,無論是 CPU 時間或掛鐘時間, mkdwarfs
都比mksquashfs
快 6 倍以上。
$ 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
在壓縮比方面, DwarFS檔案系統比SquashFS檔案系統小10倍以上。使用 DwarFS,內容已壓縮到原始大小的 0.9% (!) 以下。此壓縮率僅考慮單一檔案中儲存的數據,而不考慮實際使用的磁碟空間。在原始的 XFS 檔案系統上,根據du
的說法,原始資料夾使用了 52 GiB,因此DwarFS 鏡像實際上只使用了原始空間的 0.8% 。
這是使用lzma
壓縮而不是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
很明顯,運行速度明顯加快,生成的影像也明顯變小。儘管如此, mkdwarfs
速度大約是 SquashFS 影像的 4 倍,產生的影像比 SquashFS 影像小 12 倍。 DwarFS 映像只有原始檔案大小的 0.6%。
那麼,為什麼預設不使用lzma
而不是zstd
?原因是lzma
解壓縮速度比zstd
慢大約一個數量級。如果您只是偶爾存取壓縮檔案系統上的數據,這可能不是什麼大問題,但如果您廣泛使用它, zstd
將帶來更好的效能。
上述比較並不完全公平。 mksquashfs
預設使用 128KiB 的區塊大小,而mkdwarfs
預設使用 16MiB 區塊,甚至使用-l9
的 64MiB 區塊。當兩個檔案系統使用相同的區塊大小時,不出所料,差異變得不那麼顯著:
$ 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
即使這仍然不完全公平,因為它使用了一項功能( -B3
),該功能允許 DwarFS 引用最多兩個先前檔案系統區塊中的檔案區塊。
但重點是,這確實是 SquashFS 的優勢所在,因為它不支援更大的區塊大小或反向引用。正如您將在下面看到的,DwarFS 預設使用的較大區塊並不一定會對效能產生負面影響。
DwarFS 還提供一個選項,可以使用不同的壓縮演算法重新壓縮現有檔案系統。這非常有用,因為它允許相對快速地試驗不同的演算法和選項,而無需完全重建檔案系統。例如,使用最佳壓縮率 ( -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