# 算法 ## 算法描述 - https://en.wikipedia.org/wiki/Bloom_filter - 数据结构:bit array(m 个 bits),初始为 0 - ![](https://upload.wikimedia.org/wikipedia/commons/thumb/a/ac/Bloom_filter.svg/1298px-Bloom_filter.svg.png) - Set a key: - 使用 k 个 hash 函数,对 key 计算 hash 值 - 针对每个 hash 值 h ,设置 bit array 的 h % m 位置为 1 - $bit\_array[h\mod m]=1$ - Probe a key: - 使用同样的 k 个 hash 函数,查看 bit array 的 k 个对应位置是否全部为 1 ## 公式 - 最优 hash 函数个数 k - $k=\frac{m}{n} \ln 2$ - **m**: bit array的位数 - **n**: key的个数 - 即只取决于 bits_per_key 参数,约等于 $bits\_per\_key \times0.69$ - false postitives 的概率 - ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/de73929baec5fd76dde95874189051648c635b1d) --------- # Rocksdb 实现 - 术语与算法的对应: - num_probes: k (hash 函数的个数) - hash 函数:32-bit hash,k 个 hash 值的计算 - 第一个hash 值:完整 key 经过 XXPH3 计算出 64位 hash 值 - 后续 k - 1 hash 值的计算:上一个 hash 值乘以黄金比例 - bits_per_key:m / n ## FilterPolicy - include/rocksdb/filter_policy.h - 入口类,表示不同的 filter 策略,内置 `BloomFilterPolcy` 和 `RibbonFilterPolicy` - 核心方法: - GetBuilderWithContext:返回 `FilterBitsBuilder` ,用于写入时构建 filter blocks - GetFilterBitsReader:返回 `FilterBitsReader`,用于读取 filter blocks ## Bloom filter - filter block 的格式 ``` 0 +-----------------------------------+ | Raw Bloom filter data | | ... | len +-----------------------------------+ | char{-1} byte -> new Bloom filter | len+1 +-----------------------------------+ | byte for subimplementation | | 0: FastLocalBloom | | other: reserved | len+2 +-----------------------------------+ | byte for block_and_probes | | 0 in top 3 bits -> 6 -> 64-byte | | reserved: | | 1 in top 3 bits -> 7 -> 128-byte| | 2 in top 3 bits -> 8 -> 256-byte| | ... | | num_probes in bottom 5 bits, | | except 0 and 31 reserved | len+3 +-----------------------------------+ | two bytes reserved | | possibly for hash seed | len_with_meta +-----------------------------------+ ``` - 末尾为元数据(5字节) - 包含 filter 的类型、num_probes 参数 ## FastLocalBloomImpl - 基础实现,方法类(无数据成员) - util/bloom_impl.h - **基本结构**: - 整个 filter data 由多个 cacheline 组成,一个 cacheline 一个 bloom 结构 - 先计算 key 的 hash 值(64位),使用 hash 来构建 - key 的 64位 hash 值拆分为==两个==部分: - 低 32 位 h1 用于定位 cacheline - 高32 位 h2 作为 bloom filter hash 函数的输入 - **EstimatedFpRate**:估算 false postive rate - 算法:[http://www.ccs.neu.edu/home/pete/pub/bloom-filters-verification.pdf](http://www.ccs.neu.edu/home/pete/pub/bloom-filters-verification.pdf) - 相比朴素算法,需要考虑 cacheline 冲突 - **ChooseNumProbes**: 根据 millibits_per_key 挑选 hash 函数个数 - **AddHash**:添加 key( 的 hash 值)到 bloom filter - 该函数只作演示,实际的添加分为两步: - **PrepareHash**: - prefetch bit_array 的目标 cacheline - 使用了 [FastRange](https://github.com/lemire/fastrange)来快速定位 cacheline - **AddHashPrepared**: - 使用 num_probes 个 hash 函数设置 cacheline 的 bit 位 - **HashMayMatch** / **HashMayMatchPrepared** - 检测 key 是否存在 - 计算 num_probes 个 hash 函数,依次查看对应 bit 是否为 0 ,为 0 返回 false ## FastLocalBloomBitsBuilder ^34417e - builder 类,写入时用于构建 bloom filter 数据 - table/block_based/filter_policy.cc - 关键数据成员: - **`hash_entries_info_`**: `HashEntriesInfo`, - 主要是 `std::deque<uint64_t> entries`, 保存 key 的 hash 值 - 关键方法: - **AddKey**:参数 `Slice& key`,添加一个 Key 到 bloom filter - 继承自 `XXPH3FilterBitsBuilder` - 实际上是将 key 的 hash值先缓存到 `hash_entries_info_` - 每次 Add 的 key 是递增的,并且对 hash 进行去除 - 只记录跟 last hash 不同的 - 尤其是使用 prefix bloom filter 后,重复概率会很高 - **Finish**: 分配内存,使用 FastLocalBloomImpl 构建 filter data - 优化 - ROCKSDB_MALLOC_USABLE_SIZE - malloc 会分配比请求更多的内存,使用实际分配到的,来减少内碎片节省空间。 ## FastLocalBloomBitsReader - reader 类,读取如 Get 时会调用到。 - 核心成员: - **`data_`**:`data_`,filter data - **`num_probes_`**:`num_probes_` - **MayMatch**: - 调用 FastLocalBloomImpl 检测 key 是否可能存在 ------ # TODO - [ ] 阅读引用论文,理解 IndependentProbabilitySum 的算法 - [ ] cache_res_mgr_