Refactor/consolidate legacy Bloom implementation details (#5784)
Summary: Refactoring to consolidate implementation details of legacy Bloom filters. This helps to organize and document some related, obscure code. Also added make/cpp var TEST_CACHE_LINE_SIZE so that it's easy to compile and run unit tests for non-native cache line size. (Fixed a related test failure in db_properties_test.) Pull Request resolved: https://github.com/facebook/rocksdb/pull/5784 Test Plan: make check, including Recently added Bloom schema unit tests (in ./plain_table_db_test && ./bloom_test), and including with TEST_CACHE_LINE_SIZE=128U and TEST_CACHE_LINE_SIZE=256U. Tested the schema tests with temporary fault injection into new implementations. Some performance testing with modified unit tests suggest a small to moderate improvement in speed. Differential Revision: D17381384 Pulled By: pdillinger fbshipit-source-id: ee42586da996798910fc45ac0b6289147f16d8dfmain
parent
638d239507
commit
68626249c3
@ -0,0 +1,140 @@ |
|||||||
|
// Copyright (c) 2019-present, Facebook, Inc. All rights reserved.
|
||||||
|
// This source code is licensed under both the GPLv2 (found in the
|
||||||
|
// COPYING file in the root directory) and Apache 2.0 License
|
||||||
|
// (found in the LICENSE.Apache file in the root directory).
|
||||||
|
//
|
||||||
|
// Implementation details of various Bloom filter implementations used in
|
||||||
|
// RocksDB. (DynamicBloom is in a separate file for now because it
|
||||||
|
// supports concurrent write.)
|
||||||
|
|
||||||
|
#pragma once |
||||||
|
#include <stddef.h> |
||||||
|
#include <stdint.h> |
||||||
|
|
||||||
|
#include "rocksdb/slice.h" |
||||||
|
|
||||||
|
namespace rocksdb { |
||||||
|
|
||||||
|
// A legacy Bloom filter implementation with no locality of probes (slow).
|
||||||
|
// It uses double hashing to generate a sequence of hash values.
|
||||||
|
// Asymptotic analysis is in [Kirsch,Mitzenmacher 2006], but known to have
|
||||||
|
// subtle accuracy flaws for practical sizes [Dillinger,Manolios 2004].
|
||||||
|
//
|
||||||
|
// DO NOT REUSE - faster and more predictably accurate implementations
|
||||||
|
// are available at
|
||||||
|
// https://github.com/pdillinger/wormhashing/blob/master/bloom_simulation_tests/foo.cc
|
||||||
|
// See e.g. RocksDB DynamicBloom.
|
||||||
|
//
|
||||||
|
class LegacyNoLocalityBloomImpl { |
||||||
|
public: |
||||||
|
static inline void AddHash(uint32_t h, uint32_t total_bits, |
||||||
|
int num_probes, char *data) { |
||||||
|
const uint32_t delta = (h >> 17) | (h << 15); // Rotate right 17 bits
|
||||||
|
for (int i = 0; i < num_probes; i++) { |
||||||
|
const uint32_t bitpos = h % total_bits; |
||||||
|
data[bitpos/8] |= (1 << (bitpos % 8)); |
||||||
|
h += delta; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static inline bool HashMayMatch(uint32_t h, uint32_t total_bits, |
||||||
|
int num_probes, const char *data) { |
||||||
|
const uint32_t delta = (h >> 17) | (h << 15); // Rotate right 17 bits
|
||||||
|
for (int i = 0; i < num_probes; i++) { |
||||||
|
const uint32_t bitpos = h % total_bits; |
||||||
|
if ((data[bitpos/8] & (1 << (bitpos % 8))) == 0) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
h += delta; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
// A legacy Bloom filter implementation with probes local to a single
|
||||||
|
// cache line (fast). Because SST files might be transported between
|
||||||
|
// platforms, the cache line size is a parameter rather than hard coded.
|
||||||
|
// (But if specified as a constant parameter, an optimizing compiler
|
||||||
|
// should take advantage of that.)
|
||||||
|
//
|
||||||
|
// When ExtraRotates is false, this implementation is notably deficient in
|
||||||
|
// accuracy. Specifically, it uses double hashing with a 1/512 chance of the
|
||||||
|
// increment being zero (when cache line size is 512 bits). Thus, there's a
|
||||||
|
// 1/512 chance of probing only one index, which we'd expect to incur about
|
||||||
|
// a 1/2 * 1/512 or absolute 0.1% FP rate penalty. More detail at
|
||||||
|
// https://github.com/facebook/rocksdb/issues/4120
|
||||||
|
//
|
||||||
|
// DO NOT REUSE - faster and more predictably accurate implementations
|
||||||
|
// are available at
|
||||||
|
// https://github.com/pdillinger/wormhashing/blob/master/bloom_simulation_tests/foo.cc
|
||||||
|
// See e.g. RocksDB DynamicBloom.
|
||||||
|
//
|
||||||
|
template <bool ExtraRotates> |
||||||
|
class LegacyLocalityBloomImpl { |
||||||
|
private: |
||||||
|
static inline uint32_t GetLine(uint32_t h, uint32_t num_lines) { |
||||||
|
uint32_t offset_h = ExtraRotates ? (h >> 11) | (h << 21) : h; |
||||||
|
return offset_h % num_lines; |
||||||
|
} |
||||||
|
public: |
||||||
|
static inline void AddHash(uint32_t h, uint32_t num_lines, |
||||||
|
int num_probes, char *data, |
||||||
|
int log2_cache_line_bytes) { |
||||||
|
const int log2_cache_line_bits = log2_cache_line_bytes + 3; |
||||||
|
|
||||||
|
char *data_at_offset = |
||||||
|
data + (GetLine(h, num_lines) << log2_cache_line_bytes); |
||||||
|
const uint32_t delta = (h >> 17) | (h << 15); |
||||||
|
for (int i = 0; i < num_probes; ++i) { |
||||||
|
// Mask to bit-within-cache-line address
|
||||||
|
const uint32_t bitpos = h & ((1 << log2_cache_line_bits) - 1); |
||||||
|
data_at_offset[bitpos / 8] |= (1 << (bitpos % 8)); |
||||||
|
if (ExtraRotates) { |
||||||
|
h = (h >> log2_cache_line_bits) | (h << (32 - log2_cache_line_bits)); |
||||||
|
} |
||||||
|
h += delta; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static inline void PrepareHashMayMatch(uint32_t h, uint32_t num_lines, |
||||||
|
const char *data, |
||||||
|
uint32_t /*out*/*byte_offset, |
||||||
|
int log2_cache_line_bytes) { |
||||||
|
uint32_t b = GetLine(h, num_lines) << log2_cache_line_bytes; |
||||||
|
PREFETCH(data + b, 0 /* rw */, 1 /* locality */); |
||||||
|
PREFETCH(data + b + ((1 << log2_cache_line_bytes) - 1), |
||||||
|
0 /* rw */, 1 /* locality */); |
||||||
|
*byte_offset = b; |
||||||
|
} |
||||||
|
|
||||||
|
static inline bool HashMayMatch(uint32_t h, uint32_t num_lines, |
||||||
|
int num_probes, const char *data, |
||||||
|
int log2_cache_line_bytes) { |
||||||
|
uint32_t b = GetLine(h, num_lines) << log2_cache_line_bytes; |
||||||
|
return HashMayMatchPrepared(h, num_probes, |
||||||
|
data + b, log2_cache_line_bytes); |
||||||
|
} |
||||||
|
|
||||||
|
static inline bool HashMayMatchPrepared(uint32_t h, int num_probes, |
||||||
|
const char *data_at_offset, |
||||||
|
int log2_cache_line_bytes) { |
||||||
|
const int log2_cache_line_bits = log2_cache_line_bytes + 3; |
||||||
|
|
||||||
|
const uint32_t delta = (h >> 17) | (h << 15); |
||||||
|
for (int i = 0; i < num_probes; ++i) { |
||||||
|
// Mask to bit-within-cache-line address
|
||||||
|
const uint32_t bitpos = h & ((1 << log2_cache_line_bits) - 1); |
||||||
|
if (((data_at_offset[bitpos / 8]) & (1 << (bitpos % 8))) == 0) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
if (ExtraRotates) { |
||||||
|
h = (h >> log2_cache_line_bits) | (h << (32 - log2_cache_line_bits)); |
||||||
|
} |
||||||
|
h += delta; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace rocksdb
|
Loading…
Reference in new issue