Copy/split PlainTableBloomV1 from DynamicBloom (refactor) (#5767)
Summary: DynamicBloom was being used both for memory-only and for on-disk filters, as part of the PlainTable format. To set up enhancements to the memtable Bloom filter, this splits the code into two copies and removes unused features from each copy. Adds test PlainTableDBTest.BloomSchema to ensure no accidental change to that format. Pull Request resolved: https://github.com/facebook/rocksdb/pull/5767 Differential Revision: D17206963 Pulled By: pdillinger fbshipit-source-id: 6cce8d55305ed0df051b4c58bdc98c8ad81d0553main
parent
3f2723a81b
commit
20dec1401f
@ -1,23 +0,0 @@ |
||||
// Copyright (c) 2011-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).
|
||||
|
||||
#include "table/bloom_block.h" |
||||
|
||||
#include <string> |
||||
#include "rocksdb/slice.h" |
||||
#include "util/dynamic_bloom.h" |
||||
|
||||
namespace rocksdb { |
||||
|
||||
void BloomBlockBuilder::AddKeysHashes(const std::vector<uint32_t>& keys_hashes) { |
||||
for (auto hash : keys_hashes) { |
||||
bloom_.AddHash(hash); |
||||
} |
||||
} |
||||
|
||||
Slice BloomBlockBuilder::Finish() { return bloom_.GetRawData(); } |
||||
|
||||
const std::string BloomBlockBuilder::kBloomBlock = "kBloomBlock"; |
||||
} // namespace rocksdb
|
@ -1,37 +0,0 @@ |
||||
// Copyright (c) 2011-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).
|
||||
#pragma once |
||||
|
||||
#include <vector> |
||||
#include <string> |
||||
#include "util/dynamic_bloom.h" |
||||
|
||||
namespace rocksdb { |
||||
class Logger; |
||||
|
||||
class BloomBlockBuilder { |
||||
public: |
||||
static const std::string kBloomBlock; |
||||
|
||||
explicit BloomBlockBuilder(uint32_t num_probes = 6) : bloom_(num_probes) {} |
||||
|
||||
void SetTotalBits(Allocator* allocator, uint32_t total_bits, |
||||
uint32_t locality, size_t huge_page_tlb_size, |
||||
Logger* logger) { |
||||
bloom_.SetTotalBits(allocator, total_bits, locality, huge_page_tlb_size, |
||||
logger); |
||||
} |
||||
|
||||
uint32_t GetNumBlocks() const { return bloom_.GetNumBlocks(); } |
||||
|
||||
void AddKeysHashes(const std::vector<uint32_t>& keys_hashes); |
||||
|
||||
Slice Finish(); |
||||
|
||||
private: |
||||
DynamicBloom bloom_; |
||||
}; |
||||
|
||||
}; // namespace rocksdb
|
@ -0,0 +1,78 @@ |
||||
// Copyright (c) 2011-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).
|
||||
|
||||
#include "table/plain/plain_table_bloom.h" |
||||
|
||||
#include <string> |
||||
#include <algorithm> |
||||
#include "util/dynamic_bloom.h" |
||||
|
||||
#include "memory/allocator.h" |
||||
|
||||
|
||||
namespace rocksdb { |
||||
|
||||
namespace { |
||||
|
||||
uint32_t GetTotalBitsForLocality(uint32_t total_bits) { |
||||
uint32_t num_blocks = |
||||
(total_bits + CACHE_LINE_SIZE * 8 - 1) / (CACHE_LINE_SIZE * 8); |
||||
|
||||
// Make num_blocks an odd number to make sure more bits are involved
|
||||
// when determining which block.
|
||||
if (num_blocks % 2 == 0) { |
||||
num_blocks++; |
||||
} |
||||
|
||||
return num_blocks * (CACHE_LINE_SIZE * 8); |
||||
} |
||||
} |
||||
|
||||
PlainTableBloomV1::PlainTableBloomV1(uint32_t num_probes) |
||||
: kTotalBits(0), kNumBlocks(0), kNumProbes(num_probes), data_(nullptr) {} |
||||
|
||||
void PlainTableBloomV1::SetRawData(unsigned char* raw_data, uint32_t total_bits, |
||||
uint32_t num_blocks) { |
||||
data_ = reinterpret_cast<uint8_t*>(raw_data); |
||||
kTotalBits = total_bits; |
||||
kNumBlocks = num_blocks; |
||||
} |
||||
|
||||
void PlainTableBloomV1::SetTotalBits(Allocator* allocator, |
||||
uint32_t total_bits, uint32_t locality, |
||||
size_t huge_page_tlb_size, |
||||
Logger* logger) { |
||||
kTotalBits = (locality > 0) ? GetTotalBitsForLocality(total_bits) |
||||
: (total_bits + 7) / 8 * 8; |
||||
kNumBlocks = (locality > 0) ? (kTotalBits / (CACHE_LINE_SIZE * 8)) : 0; |
||||
|
||||
assert(kNumBlocks > 0 || kTotalBits > 0); |
||||
assert(kNumProbes > 0); |
||||
|
||||
uint32_t sz = kTotalBits / 8; |
||||
if (kNumBlocks > 0) { |
||||
sz += CACHE_LINE_SIZE - 1; |
||||
} |
||||
assert(allocator); |
||||
|
||||
char* raw = allocator->AllocateAligned(sz, huge_page_tlb_size, logger); |
||||
memset(raw, 0, sz); |
||||
auto cache_line_offset = reinterpret_cast<uintptr_t>(raw) % CACHE_LINE_SIZE; |
||||
if (kNumBlocks > 0 && cache_line_offset > 0) { |
||||
raw += CACHE_LINE_SIZE - cache_line_offset; |
||||
} |
||||
data_ = reinterpret_cast<uint8_t*>(raw); |
||||
} |
||||
|
||||
void BloomBlockBuilder::AddKeysHashes(const std::vector<uint32_t>& keys_hashes) { |
||||
for (auto hash : keys_hashes) { |
||||
bloom_.AddHash(hash); |
||||
} |
||||
} |
||||
|
||||
Slice BloomBlockBuilder::Finish() { return bloom_.GetRawData(); } |
||||
|
||||
const std::string BloomBlockBuilder::kBloomBlock = "kBloomBlock"; |
||||
} // namespace rocksdb
|
@ -0,0 +1,161 @@ |
||||
// Copyright (c) 2011-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).
|
||||
#pragma once |
||||
|
||||
#include <vector> |
||||
#include <string> |
||||
|
||||
#include "rocksdb/slice.h" |
||||
|
||||
#include "port/port.h" |
||||
#include "util/hash.h" |
||||
|
||||
#include <memory> |
||||
|
||||
namespace rocksdb { |
||||
class Slice; |
||||
class Allocator; |
||||
class Logger; |
||||
|
||||
class PlainTableBloomV1 { |
||||
public: |
||||
// allocator: pass allocator to bloom filter, hence trace the usage of memory
|
||||
// total_bits: fixed total bits for the bloom
|
||||
// num_probes: number of hash probes for a single key
|
||||
// locality: If positive, optimize for cache line locality, 0 otherwise.
|
||||
// hash_func: customized hash function
|
||||
// huge_page_tlb_size: if >0, try to allocate bloom bytes from huge page TLB
|
||||
// within this page size. Need to reserve huge pages for
|
||||
// it to be allocated, like:
|
||||
// sysctl -w vm.nr_hugepages=20
|
||||
// See linux doc Documentation/vm/hugetlbpage.txt
|
||||
explicit PlainTableBloomV1(uint32_t num_probes = 6); |
||||
void SetTotalBits(Allocator* allocator, uint32_t total_bits, |
||||
uint32_t locality, size_t huge_page_tlb_size, |
||||
Logger* logger); |
||||
|
||||
~PlainTableBloomV1() {} |
||||
|
||||
// Assuming single threaded access to this function.
|
||||
void AddHash(uint32_t hash); |
||||
|
||||
// Multithreaded access to this function is OK
|
||||
bool MayContainHash(uint32_t hash) const; |
||||
|
||||
void Prefetch(uint32_t hash); |
||||
|
||||
uint32_t GetNumBlocks() const { return kNumBlocks; } |
||||
|
||||
Slice GetRawData() const { |
||||
return Slice(reinterpret_cast<char*>(data_), GetTotalBits() / 8); |
||||
} |
||||
|
||||
void SetRawData(unsigned char* raw_data, uint32_t total_bits, |
||||
uint32_t num_blocks = 0); |
||||
|
||||
uint32_t GetTotalBits() const { return kTotalBits; } |
||||
|
||||
bool IsInitialized() const { return kNumBlocks > 0 || kTotalBits > 0; } |
||||
|
||||
private: |
||||
uint32_t kTotalBits; |
||||
uint32_t kNumBlocks; |
||||
const uint32_t kNumProbes; |
||||
|
||||
uint8_t* data_; |
||||
}; |
||||
|
||||
#if defined(_MSC_VER) |
||||
#pragma warning(push) |
||||
// local variable is initialized but not referenced
|
||||
#pragma warning(disable : 4189) |
||||
#endif |
||||
inline void PlainTableBloomV1::Prefetch(uint32_t h) { |
||||
if (kNumBlocks != 0) { |
||||
uint32_t b = ((h >> 11 | (h << 21)) % kNumBlocks) * (CACHE_LINE_SIZE * 8); |
||||
PREFETCH(&(data_[b / 8]), 0, 3); |
||||
} |
||||
} |
||||
#if defined(_MSC_VER) |
||||
#pragma warning(pop) |
||||
#endif |
||||
|
||||
inline bool PlainTableBloomV1::MayContainHash(uint32_t h) const { |
||||
assert(IsInitialized()); |
||||
const uint32_t delta = (h >> 17) | (h << 15); // Rotate right 17 bits
|
||||
if (kNumBlocks != 0) { |
||||
uint32_t b = ((h >> 11 | (h << 21)) % kNumBlocks) * (CACHE_LINE_SIZE * 8); |
||||
for (uint32_t i = 0; i < kNumProbes; ++i) { |
||||
// Since CACHE_LINE_SIZE is defined as 2^n, this line will be optimized
|
||||
// to a simple and operation by compiler.
|
||||
const uint32_t bitpos = b + (h % (CACHE_LINE_SIZE * 8)); |
||||
if ((data_[bitpos / 8] & (1 << (bitpos % 8))) == 0) { |
||||
return false; |
||||
} |
||||
// Rotate h so that we don't reuse the same bytes.
|
||||
h = h / (CACHE_LINE_SIZE * 8) + |
||||
(h % (CACHE_LINE_SIZE * 8)) * (0x20000000U / CACHE_LINE_SIZE); |
||||
h += delta; |
||||
} |
||||
} else { |
||||
for (uint32_t i = 0; i < kNumProbes; ++i) { |
||||
const uint32_t bitpos = h % kTotalBits; |
||||
if ((data_[bitpos / 8] & (1 << (bitpos % 8))) == 0) { |
||||
return false; |
||||
} |
||||
h += delta; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
inline void PlainTableBloomV1::AddHash(uint32_t h) { |
||||
assert(IsInitialized()); |
||||
const uint32_t delta = (h >> 17) | (h << 15); // Rotate right 17 bits
|
||||
if (kNumBlocks != 0) { |
||||
uint32_t b = ((h >> 11 | (h << 21)) % kNumBlocks) * (CACHE_LINE_SIZE * 8); |
||||
for (uint32_t i = 0; i < kNumProbes; ++i) { |
||||
// Since CACHE_LINE_SIZE is defined as 2^n, this line will be optimized
|
||||
// to a simple and operation by compiler.
|
||||
const uint32_t bitpos = b + (h % (CACHE_LINE_SIZE * 8)); |
||||
data_[bitpos / 8] |= (1 << (bitpos % 8)); |
||||
// Rotate h so that we don't reuse the same bytes.
|
||||
h = h / (CACHE_LINE_SIZE * 8) + |
||||
(h % (CACHE_LINE_SIZE * 8)) * (0x20000000U / CACHE_LINE_SIZE); |
||||
h += delta; |
||||
} |
||||
} else { |
||||
for (uint32_t i = 0; i < kNumProbes; ++i) { |
||||
const uint32_t bitpos = h % kTotalBits; |
||||
data_[bitpos / 8] |= (1 << (bitpos % 8)); |
||||
h += delta; |
||||
} |
||||
} |
||||
} |
||||
|
||||
class BloomBlockBuilder { |
||||
public: |
||||
static const std::string kBloomBlock; |
||||
|
||||
explicit BloomBlockBuilder(uint32_t num_probes = 6) : bloom_(num_probes) {} |
||||
|
||||
void SetTotalBits(Allocator* allocator, uint32_t total_bits, |
||||
uint32_t locality, size_t huge_page_tlb_size, |
||||
Logger* logger) { |
||||
bloom_.SetTotalBits(allocator, total_bits, locality, huge_page_tlb_size, |
||||
logger); |
||||
} |
||||
|
||||
uint32_t GetNumBlocks() const { return bloom_.GetNumBlocks(); } |
||||
|
||||
void AddKeysHashes(const std::vector<uint32_t>& keys_hashes); |
||||
|
||||
Slice Finish(); |
||||
|
||||
private: |
||||
PlainTableBloomV1 bloom_; |
||||
}; |
||||
|
||||
}; // namespace rocksdb
|
Loading…
Reference in new issue