日期:2014-05-16 浏览次数:20590 次
图8.1-1
这是一个简单的FilterPolicy的wrapper,以方便的把FilterPolicy应用在InternalKey上,InternalKey是Leveldb内部使用的key,这些前面都讲过。它所做的就是从InternalKey拆分得到user key,然后在user key上做FilterPolicy的操作。
它有一个成员:constFilterPolicy* const user_policy_;bool InternalFilterPolicy::KeyMayMatch(const Slice& key, constSlice& f) const { returnuser_policy_->KeyMayMatch(ExtractUserKey(key), f); } void InternalFilterPolicy::CreateFilter(const Slice* keys, int n,std::string* dst) const { Slice* mkey =const_cast<Slice*>(keys); for (int i = 0; i < n; i++)mkey[i] = ExtractUserKey(keys[i]); user_policy_->CreateFilter(keys, n, dst); }
图8.3-1
在leveldb的实现中,Name()返回"leveldb.BuiltinBloomFilter",因此metaindex block 中的key就是”filter.leveldb.BuiltinBloomFilter”。Leveldb使用了double hashing来模拟多个hash函数,当然这里不是用来解决冲突的。
和线性再探测(linearprobing)一样,Double hashing从一个hash值开始,重复向前迭代,直到解决冲突或者搜索完hash表。不同的是,double hashing使用的是另外一个hash函数,而不是固定的步长。
给定两个独立的hash函数h1和h2,对于hash表T和值k,第i次迭代计算出的位置就是:h(i, k) = (h1(k) + i*h2(k)) mod |T|。
对此,Leveldb选择的hash函数是:H1是一个基本的hash函数,H2是由H1循环右移得到的,Gi(x)就是第i次循环得到的hash值。【理论分析可参考论文Kirsch,Mitzenmacher2006】
在bloom_filter的数据的最后一个字节存放的是k_的值,k_实际上就是G(x)的个数,也就是计算时采用的hash函数个数。
bits_per_key_ = bits_per_key; k_ =static_cast<size_t>(bits_per_key * 0.69); // 0.69 =~ ln(2) if (k_ < 1) k_ = 1; if (k_ > 30) k_ = 30;
模拟hash函数的个数k_取值为bits_per_key_*ln(2),为何不是0.5或者0.4了,可能是什么理论推导的结果吧,不了解了。
size_t bits = n * bits_per_key_; if (bits < 64) bits = 64; // 如果n太小FP会很高,限定filter的最小长度 size_t bytes = (bits + 7) / 8;// 圆整到8byte bits = bytes * 8; // bit计算的空间大小 const size_t init_size =dst->size(); dst->resize(init_size +byt