#数组 #去重 # #内存 #存储 #字节 #历史

已删除 array_cow

内存数组去重,用于高效存储数据版本的历史记录

使用旧的Rust 2015

0.1.0 2017年3月19日

#32 in #去重

Apache-2.0

92KB
2K SLoC

数组Cow

简介

内存数组去重,用于高效存储多个数据版本。

这适用于存储撤销历史,例如,对二进制和文本数据都有效。

  • 可配置的块大小。
  • 支持数组步长,以避免检测块和未解引用偏移的开销。(字节的步长为1也适用)
  • 使用块哈希进行去重。
  • 每个状态只能引用其前一个状态,这使得线性结构和树状结构都成为可能。

进一步工作

可能值得使用mmap进行数据存储。


lib.rs:

数组存储以最小化重复。

这是通过将数组分割成块并使用写时复制(COW)来去重块实现的,从用户的角度来看,这是一个实现细节。

概述

数据结构

此图是单个数组存储结构的概述。

注意:这里只有两种结构被外部引用。

  • BArrayStore:整个数组存储。
  • BArrayState:表示数据的一个状态(数组)。这些可以通过引用状态添加,虽然这可以被认为是前一个或父状态。不保持任何关系,因此调用者可以自由添加来自同一BArrayStore的任何状态作为引用。
<+> BArrayStore: root data-structure,
 |  can store many 'states', which share memory.
 |
 |  This can store many arrays, however they must share the same 'stride'.
 |  Arrays of different types will need to use a new BArrayStore.
 |
 +- <+> states (Collection of BArrayState's):
 |   |  Each represents an array added by the user of this API.
 |   |  and references a chunk_list (each state is a chunk_list user).
 |   |  Note that the list order has no significance.
 |   |
 |   +- <+> chunk_list (BChunkList):
 |       |  The chunks that make up this state.
 |       |  Each state is a chunk_list user,
 |       |  avoids duplicating lists when there is no change between states.
 |       |
 |       +- chunk_refs (List of BChunkRef): Each chunk_ref links to a a BChunk.
 |          Each reference is a chunk user,
 |          avoids duplicating smaller chunks of memory found in multiple states.
 |
 +- info (BArrayInfo):
 |  Sizes and offsets for this array-store.
 |  Also caches some variables for reuse.
 |
 +- <+> memory (BArrayMemory):
     |  Memory pools for storing BArrayStore data.
     |
     +- chunk_list (Pool of BChunkList):
     |  All chunk_lists, (reference counted, used by BArrayState).
     |
     +- chunk_ref (Pool of BChunkRef):
     |  All chunk_refs (link between BChunkList & BChunk).
     |
     +- chunks (Pool of BChunk):
        All chunks, (reference counted, used by BChunkList).
        These have their headers hashed for reuse so we can quickly check for duplicates.

去重

在创建新状态时,可以提供一个前一个状态作为引用,从该状态匹配的块将重新用于新状态。

检测到数组的两端匹配。对于相同的数组,这已经足够。

对剩余的块进行去重,通过哈希块的前几个字节(见:BCHUNK_HASH_TABLE_ACCUMULATE_STEPS)。

注意:由于引用数据永远不会更改,因此这被缓存以供重用。

创建一个数组来存储每个'步长'的哈希值,然后遍历以搜索匹配的块。

一旦找到匹配项,下一个块也很有可能匹配,因此这被检查以避免执行过多的哈希查找。否则将创建新的块。

示例

let mut bs = array_cow::BArrayStore::new(1, 8);
let data_src_a = b"The quick brown fox jumps over the lazy dog";
let data_src_b = b"The quick brown fox almost jumps over the lazy dog";
let data_src_c = b"The little quick brown fox jumps over the lazy dog!";

let state_a = bs.state_add(data_src_a, None);
let state_b = bs.state_add(data_src_b, Some(state_a));
let state_c = bs.state_add(data_src_c, Some(state_b));

// Check the data is stored correctly
let data_dst = array_cow::BArrayStore::state_data_get_alloc(state_a);
assert_eq!(&data_src_a[..], &data_dst[..]);

let data_dst = array_cow::BArrayStore::state_data_get_alloc(state_b);
assert_eq!(&data_src_b[..], &data_dst[..]);

let data_dst = array_cow::BArrayStore::state_data_get_alloc(state_c);
assert_eq!(&data_src_c[..], &data_dst[..]);

无运行时依赖