#content-defined #chunking #cdc #fork #original #data #chunk

fastcdc-alt

使用纯 Rust 编写的 FastCDC (内容定义分块) 实现,具有替代原始包的 API

1 个不稳定版本

0.2.2 2023 年 9 月 17 日
0.2.1 2023 年 8 月 16 日
0.2.0 2023 年 8 月 16 日
0.1.0 2023 年 8 月 14 日

#4 in #chunking

每月 36 次下载

MIT 许可协议

77KB
1K SLoC

FastCDC-Alt docs.rs Crates.io Test

此包是 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 迭代器。
  • 已调整 AsyncStreamCDCStreamCDC 实现,它们的 API 仅略有变化。
  • 为了仅关注此分支的2020版本,已移除ronomonv2016的实现和示例。

需求

  • Rust稳定版(2018版)

构建和测试

$ cargo clean
$ cargo build
$ cargo test

示例用法

示例可以在源存储库的examples目录中找到,其中展示了在给定的文件中查找数据块边界。既有流式处理示例,也有非流式处理示例,其中非流式处理示例使用memmap2crate有效地读取大文件。

$ 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(通过功能标志支持tokiofutures)并使用一个容量等于指定最大数据块大小的字节向量。

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年改进的“每次滚动两个字节”版本在基于数据去重存储系统的快速内容定义数据块设计中详细说明。

其他实现

依赖关系

~0–1.5MB
~25K SLoC