
答案1
如果你想確保碎片但不防止它(所以你只能部分控制發生的事情),並且你不關心碎片的細節,這是一種快速而骯髒的做事方式。
若要建立n
至少包含兩個片段的區塊檔案:
- 使用同步寫入開啟文件,寫入 m < n 區塊。
- 開啟另一個文件。加到它,直到磁碟上最多有 n - m 區塊可用。不要錯誤地將其稀疏!
- 將剩餘的 n - m 區塊寫入第一個檔案。
- 關閉
unlink
第二個文件。
您可以透過交錯更多文件來分割更多片段。
這假設檔案系統可用於此類折磨,即不在多使用者或關鍵任務環境中。它還假設檔案系統沒有保留區塊,或者保留區塊是為您的 UID 保留的,或者您是 root。
沒有直接的確保碎片的方式,因為 Unix 系統採用檔案系統抽象,所以你永遠不會與原始檔案系統交談。
此外,請確保檔案系統層級碎片不會告訴您較低層級發生的情況。 LVM、軟體和硬體 RAID、硬體級磁區重新映射和其他抽象層可能會對您的期望(和測量)造成嚴重破壞。
答案2
我還沒有遇到 Linux 上的通用檔案系統會犧牲寫入吞吐量而不是連續檔案。也就是說,如果檔案以非順序順序寫入,則每個檔案系統都會產生碎片,尤其是對於稀疏檔案。
簡單的方法:透過 torrent 用戶端運行檔案-最好是不預先分配檔案的用戶端。 BitTornado 或 rtorrent 符合這個要求。 (前者有可配置的分配模式)
困難的方法:將原始檔分割成幾KB大小的片段,然後將它們打亂。開啟目標檔案。對於每一篇文章,找到它的正確位置並寫下來。
這是一個執行此操作的 Perl 腳本:
#!/usr/bin/perl
use List::Util qw/shuffle/;
use IO::Handle;
use constant BLOCK_SIZE => 4096;
my ($src, $dst) = @ARGV;
my $size = (stat($src))[7];
my @blocks = shuffle(0 .. ($size / BLOCK_SIZE));
my ($srcfh, $dstfh);
open $srcfh, "<", $src or die "cannot open $src: $!";
open $dstfh, ">", $dst or die "cannot open $dst: $!";
truncate $dstfh, $size; # undefined behaviour
my $buf;
for my $blockno (@blocks) {
seek $_, $blockno * BLOCK_SIZE, 0 for ($srcfh, $dstfh);
read $srcfh, $buf, BLOCK_SIZE;
print $dstfh $buf;
$dstfh->flush;
}
close $dstfh;
close $srcfh;
filefrag
您可以使用 e2fsprogs 套件中包含的命令檢查碎片。
以下是 torrent 的作用範例:
# ls -sh amd64memstick-5.1.2.fs.gz
239M amd64memstick-5.1.2.fs.gz
# filefrag amd64memstick-5.1.2.fs.gz
amd64memstick-5.1.2.fs.gz: 585 extents found
這是我的腳本(在 ext3 上)得到的結果:
$ ls -sh source.tar
42M source.tar
$ perl fragment.pl source.tar fragmented.tar
$ md5sum fragmented.tar source.tar
f77fdd7ab526ede434f416f9787fa9b3 fragmented.tar
f77fdd7ab526ede434f416f9787fa9b3 source.tar
# filefrag fragmented.tar
fragmented.tar: 395 extents found
編輯:沒關係,除了較大的檔案(肯定是 1.5 GB 的檔案碎片)之外,它似乎根本無法正常工作。
VM 系統可能正在快取並推遲/重新排序太小的寫入。這就是為什麼 torrent 用戶端會設法產生碎片(因為它們通常不會以 >10MB/s 的速度下載),但我的腳本卻不會。我認為可以透過降低虛擬機器閾值來調整。看/proc/sys/vm/dirty_*