在 C++ 中处理大哈希表

问题描述

我正在编写一个程序,其中我得到了大量存储为块(4096 字节)的数据。对于每个块(如果哈希值不存在),我创建一个 Hashtable(std::multimap) 条目。一个条目看起来像这样

密钥:哈希值 SHA256 -> 64 字节

值:RefLink

class VideoPlayerApp extends StatelessWidget {
  VideoPlayerApp({
    Key key,this.uri,}) : super(key: key);

  final String uri;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Video Player Demo',home: VideoPlayerScreen(),);
  }
}

所以每个条目总共需要 76 个字节。如果我有 100 GB 的数据块,我的 Hashtable 将大约为 1.85 GB。如果我有 8 TB 的数据......你知道这会发生在哪里。你有什么提示我如何解决这个问题。有没有另一种方法我看不到管理我的哈希表。是否有更好的哈希函数(已经在 C++ 中实现)可以节省更多内存并且没有任何冲突?或者我可以在程序运行时以某种方式压缩表条目吗?

解决方法

SHA256 应该具有良好的雪崩特性(改变纯文本中的 1 位应该有 50% 的机会改变散列中的每一位)

因此,只使用 sha256 散列的一部分作为您的散列应该是安全的。显然,您包含的位越少,发生冲突的可能性就越高。

,

如果哈希值已经存在,我不会将该块放入系统中。如果不是这个块将被保存。这是一个重复数据删除工具。

我建议创建一个以 SHA256 键为键的实际哈希表,每个存储桶包含一个固定长度的 SHA256 值数组,这些值在那里发生冲突,以及一个相同长度的 RefLink 对象数组。非常粗略,从我的头顶:

using sha256 = std::array<std::byte,32>;
constexpr size_t max_slots = 16;
struct Bucket {
    std::vector<sha256> shas_;
    std::vector<RefLink> reflinks_;
};
std::vector<Bucket> buckets_;

void insert(const Data& data) {
    sha256 shaA = calc_sha256(data);

    size_t bucket_index_A = mod(sha256A,buckets_.size());
    auto& bucket_A = buckets_[bucket_index_A];

    sha256 shaB = shaA;
    for (int i = 0; i <= 15; ++i)
    std::swap(shaB[i],shaB[31-i]);  // cheap second hash value
    size_t bucket_index_B = mod(sha256B,buckets_.size());
    auto& bucket_B = buckets_[bucket_index_B];
    
    for (auto& bucket : { bucket_A,bucket_B })
        for (int i = 0; i < bucket_A.size(); ++i)
            if (bucket.shas[i] == sha &&
                Data::slow_equals(bucket.reflinks[i],data))
                return; // duplicate
    auto& smaller_bucket = bucket_A.size() < bucket_B.size()
                           ? bucket_A : bucket_B;
    auto& smaller_sha =    bucket_A.size() < bucket_B.size()
                           ? sha_A : sha_B;
    if (smaller_bucket.size() < max_slots) {
        smaller_bucket.shas.push_back(smaller_sha);
        smaller_bucket.reflinks.push_back(Data::store(data));
        return;
    }
    grow_and_rehash();  // construct a larger hash & copy elements
    insert(data);  // or goto top of fn if you prefer...
}

实现你自己的槽机制,在可能的情况下使用连续内存,并通过使用多个哈希值并插入到碰撞较少的桶来增加桶中冲突的均匀性,将显着提高内存利用率(需要的总内存)索引所有数据)和 CPU 缓存命中。