1 个不稳定版本
0.2.2 | 2023 年 9 月 17 日 |
---|---|
0.2.1 |
|
0.2.0 |
|
0.1.0 |
|
#4 in #chunking
每月 36 次下载
77KB
1K SLoC
FastCDC-Alt
此包是 Nathan Fiedler 的原始 Rust 实现的分支。 (nlfiedler/fastcdc-rs)
此处包含 Wen Xia 等人描述的 2020 年增强的 "FastCDC" 内容定义分块算法。
此分支引入了一种调整的、稍微复杂一点的替代 API,以提高灵活性和减少内存开销。
此分支生成的切点与原始包生成的切点相同。
此 README 和所有文档都已根据调整的 API 进行了适配。
有什么不同?
调整后的 FastCDC
结构现在允许您逐个提供查找下一个切点所需的数据块。
这种方法的优势是不需要将整个数据保持在连续的内存块中,因此也可以节省一些内存复制。
这对于例如高级流式处理逻辑非常有用。
与原始包的示例使用
fn main(consumer: Receiver<Box<[u8]>>) {
let cursor = 0;
let mut intermediate_buffer = vec![1024 * 1024 * 16]; // 16 MiB
for buffer in consumer.iter() {
&intermediate_buffer[cursor..cursor + 4096].copy_from_slice(&buffer);
cursor += 4096;
if cursor == intermediate_buffer.len() {
let fastcdc = FastCDC::new(&intermediate_buffer, 65535, 1048576, 16777216);
for chunk in fastcdc {
// .. process chunk
}
cursor = 0;
}
}
}
使用此分支的非常基本的示例使用。
您可以在 fastcdc_cut 文件中看到一个完整的示例。
use std::collections::VecDeque;
fn main(consumer: Receiver<Box<[u8]>>) {
let mut fastcdc = FastCDC::new(65535, 1048576, 16777216).unwrap();
// Inform the FastCDC struct how much data we are expecting.
fastcdc.set_content_length(134217728); // 128 MiB
for buffer in consumer.iter() {
let mut cursor = 0;
loop {
if let Some(chunk) = fastcdc.cut(&buffer[cursor..]) {
// .. process chunk hash
cursor += chunk.cutpoint;
if cursor == buffer.len() {
break;
}
}
break;
}
}
}
}
还有其他什么?
- 现在可以通过
FastCDC::as_iterator(&self, buffer: &[u8])
方法访问FastCDC
迭代器。 - 已调整
AsyncStreamCDC
和StreamCDC
实现,它们的 API 仅略有变化。 - 为了仅关注此分支的2020版本,已移除ronomon和v2016的实现和示例。
需求
- Rust稳定版(2018版)
构建和测试
$ cargo clean
$ cargo build
$ cargo test
示例用法
示例可以在源存储库的examples
目录中找到,其中展示了在给定的文件中查找数据块边界。既有流式处理示例,也有非流式处理示例,其中非流式处理示例使用memmap2
crate有效地读取大文件。
$ cargo run --example v2020 -- --size 16384 test/fixtures/SekienAkashita.jpg
Finished dev [unoptimized + debuginfo] target(s) in 0.03s
Running `target/debug/examples/v2020 --size 16384 test/fixtures/SekienAkashita.jpg`
hash=17968276318003433923 offset=0 size=21325
hash=4098594969649699419 offset=21325 size=17140
hash=15733367461443853673 offset=38465 size=28084
hash=4509236223063678303 offset=66549 size=18217
hash=2504464741100432583 offset=84766 size=24700
非流式
使用FastCDC
在内存中加载数据时查找数据块边界的示例
let contents = std::fs::read("test/fixtures/SekienAkashita.jpg").unwrap();
let mut chunker = fastcdc_alt::FastCDC::new(16384, 32768, 65536).unwrap();
for chunk in chunker.as_iterator(&contents) {
println!("offset={} length={}", chunk.offset, chunk.get_length());
}
流式
StreamCDC
版本接受一个Read
源,并使用一个容量等于指定最大数据块大小的字节向量。
let source = std::fs::File::open("test/fixtures/SekienAkashita.jpg").unwrap();
let chunker = fastcdc_alt::StreamCDC::new(source, 4096, 16384, 65535).unwrap();
for result in chunker {
let (_data, chunk) = result.unwrap();
println!("offset={} length={}", chunk.offset, chunk.get_length());
}
异步流式
还有一个名为AsyncStreamCDC
的异步流式FastCDC版本,它接受一个AsyncRead
(通过功能标志支持tokio
和futures
)并使用一个容量等于指定最大数据块大小的字节向量。
let source = std::fs::File::open("test/fixtures/SekienAkashita.jpg").unwrap();
let chunker = fastcdc_alt::AsyncStreamCDC::new(&source, 4096, 16384, 65535).unwrap();
let stream = chunker.as_stream();
let chunks = stream.collect::<Vec<_>>().await;
for result in chunks {
let chunk = result.unwrap();
println!("offset={} length={}", chunk.offset, chunk.get_length());
}
参考资料
2016年的原始算法在FastCDC:一种用于数据去重的快速和高效的内容定义数据块方法中描述。
2020年改进的“每次滚动两个字节”版本在基于数据去重存储系统的快速内容定义数据块设计中详细说明。
其他实现
- nlfiedler/fastcdc-rs
- 此分支的基础。
- jrobhoward/quickcdc
- 一些相同作者的一些类似但略早的算法?
- rdedup_cdc at docs.rs
- Rust中的另一种实现。
- ronomon/deduplication
- FastCDC的变种的C++和JavaScript实现。
- titusz/fastcdc-py
- FastCDC的纯Python端口。与这个实现兼容。
- wxiacode/FastCDC-c
- 使用齿轮表生成和掩码值的C中的规范算法。
- wxiacode/restic-FastCDC
- 具有附加掩码值的Go的另一种实现。
依赖关系
~0–1.5MB
~25K SLoC