cp 默认的情况下,通过文件系统提供的 fiemap 接口,获取到文件所有的空洞信息,然后跳过这些空洞,只 copy 有效的数据,极大的减少了磁盘 io 的数据量,所以才那么快 。
总结下 cp --sparse 三个参数的特点:
- auto 模式:默认模式,最一致的模式(如果没有用户全0 块数据,那么可能也是速度最快的),会根据源文件的实际空间占用复制数据,目标文件和源文件一致 。无论是文件 size 还是物理 blocks;
- always 模式:追求最小空间占用的模式,就算源文件不是稀疏文件,而仅仅是有些连续大块的全 0 数据,也会尝试在目标文件上 punch hole,从而节省空间,这种方式会导致目标文件的物理 blocks 可能比源文件要小;
- never 模式:最低效,速度最慢的方式 。这种方式无论源文件是啥,全都是实打实的复制,不管是空洞还是全 0 数据,都会在目标文件写入;
精髓所在,前面知识点就算全都忘了,只记得这三张图,你也赚了 。
cp src.txt dest.txt
文章插图
cp --sparse=always src.txt dest.txt
文章插图
cp --sparse=never src.txt dest.txt
文章插图

文章插图
稀疏文件的应用

文章插图
稀疏文件在哪些地方有应用呢?
- 数据库快照:生成一个数据库快照时会生成一个稀疏文件,稀疏文件一开始并不会占用磁盘空间 。当源数据库发生写操作时,就把修改前的原数据块复制且只复制一次到稀疏文件中;
- MySQL5.7 有一种数据压缩方式,其原理就是利用内核Punch hole特性,对于一个16kb的数据页,在写文件之前,除了 Page 头之外,其他部分进行压缩,压缩后留白的地方使用 punch hole 进行 “打洞”,在磁盘上表现为不占用空间,从而达到快速释放物理空间的目的;
- qemu 磁盘镜像文件的空间回收场景;

文章插图
一起做个实验

文章插图
最后我们演示下实验,检验看下你懂了吗?找一台 linux 机器,跟着运行下面的命令 。
初始条件准备
步骤一:创建一个文件(预期占用 1 个 block) 。
echo =========== test ======= > test.txt步骤二:truncate 成 1G 的稀疏文件 。truncate -s 1G ./test.txt步骤三:把 1M 到 1M+4K 的位置预分配出来(并且是写 0 分配,预期到这里要占用 2 个 block,也就是 8K 数据) 。fallocate -o 1048576 -l 4096 -z ./test.txt步骤四:stat 命令检查下情况 。sh-4.4# stat test.txt File: test.txt Size: 1073741824 Blocks: 16 IO Block: 4096 regular fileDevice: 6ah/106d Inode: 3148347 Links: 1Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)Access: 2021-03-12 15:37:54.427903000 +0000Modify: 2021-03-12 15:46:00.456246000 +0000Change: 2021-03-12 15:46:00.456246000 +0000 Birth: -我们看到 Size: 1073741824 Blocks: 16 ,Size 大小等于 1G,stat 显示的 Blocks 是扇区(512字节)的个数,也就是说,物理空间占用 8K,符合预期 。也就是说:
