mirror of
https://github.com/dragonflydb/dragonfly.git
synced 2025-05-10 18:05:44 +02:00
chore: dash table clean ups (#5064)
Remove stash template parameter because we only use dashtable with a single configuration of STASH_CNT=4. Signed-off-by: Roman Gershman <roman@dragonflydb.io>
This commit is contained in:
parent
3da7e49712
commit
4d07d7d053
4 changed files with 48 additions and 57 deletions
|
@ -16,7 +16,7 @@ namespace dfly {
|
|||
// After all, we added additional improvements we added as part of the dragonfly project,
|
||||
// that probably justify a right to choose our own name for this data structure.
|
||||
struct BasicDashPolicy {
|
||||
enum { kSlotNum = 12, kBucketNum = 64, kStashBucketNum = 2 };
|
||||
enum { kSlotNum = 12, kBucketNum = 64 };
|
||||
static constexpr bool kUseVersion = false;
|
||||
|
||||
template <typename U> static void DestroyValue(const U&) {
|
||||
|
@ -62,11 +62,11 @@ class DashTable : public detail::DashTableBase {
|
|||
|
||||
struct HotspotBuckets {
|
||||
static constexpr size_t kRegularBuckets = 4;
|
||||
static constexpr size_t kNumBuckets = kRegularBuckets + Policy::kStashBucketNum;
|
||||
static constexpr size_t kNumBuckets = kRegularBuckets + SegmentType::kStashBucketNum;
|
||||
|
||||
struct ByType {
|
||||
bucket_iterator regular_buckets[kRegularBuckets];
|
||||
bucket_iterator stash_buckets[Policy::kStashBucketNum];
|
||||
bucket_iterator stash_buckets[SegmentType::kStashBucketNum];
|
||||
};
|
||||
|
||||
union Probes {
|
||||
|
@ -822,7 +822,7 @@ auto DashTable<_Key, _Value, Policy>::InsertInternal(U&& key, V&& value, Evictio
|
|||
hotspot.probes.by_type.regular_buckets[j] = bucket_iterator{this, target_seg_id, bid[j]};
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < Policy::kStashBucketNum; ++i) {
|
||||
for (unsigned i = 0; i < SegmentType::kStashBucketNum; ++i) {
|
||||
hotspot.probes.by_type.stash_buckets[i] =
|
||||
bucket_iterator{this, target_seg_id, uint8_t(Policy::kBucketNum + i), 0};
|
||||
}
|
||||
|
|
|
@ -101,19 +101,17 @@ template <unsigned NUM_SLOTS> class SlotBitmap {
|
|||
Unaligned val_[kLen];
|
||||
}; // SlotBitmap
|
||||
|
||||
template <unsigned NUM_SLOTS, unsigned NUM_STASH_FPS> class BucketBase {
|
||||
template <unsigned NUM_SLOTS> class BucketBase {
|
||||
// We can not allow more than 4 stash fps because we hold stash positions in single byte
|
||||
// stash_pos_ variable that uses 2 bits per stash bucket to point which bucket holds that fp.
|
||||
// Hence we can point at most from 4 fps to 4 stash buckets.
|
||||
// If any of those limits need to be raised we should increase stash_pos_ similarly to how we did
|
||||
// with SlotBitmap.
|
||||
static_assert(NUM_STASH_FPS <= 4, "Can only hold at most 4 fp slots");
|
||||
|
||||
static constexpr unsigned kStashFpLen = NUM_STASH_FPS;
|
||||
static constexpr unsigned kStashFpLen = 4;
|
||||
static constexpr unsigned kStashPresentBit = 1 << 4;
|
||||
|
||||
using FpArray = std::array<uint8_t, NUM_SLOTS>;
|
||||
using StashFpArray = std::array<uint8_t, NUM_STASH_FPS>;
|
||||
using StashFpArray = std::array<uint8_t, kStashFpLen>;
|
||||
|
||||
public:
|
||||
using SlotId = uint8_t;
|
||||
|
@ -233,9 +231,9 @@ template <unsigned NUM_SLOTS, unsigned NUM_STASH_FPS> class BucketBase {
|
|||
uint8_t overflow_count_ = 0;
|
||||
}; // BucketBase
|
||||
|
||||
static_assert(sizeof(BucketBase<12, 4>) == 24, "");
|
||||
static_assert(alignof(BucketBase<14, 4>) == 1, "");
|
||||
static_assert(alignof(BucketBase<12, 4>) == 1, "");
|
||||
static_assert(sizeof(BucketBase<12>) == 24);
|
||||
static_assert(alignof(BucketBase<14>) == 1);
|
||||
static_assert(alignof(BucketBase<12>) == 1);
|
||||
|
||||
// Optional version support as part of DashTable.
|
||||
// This works like this: each slot has 2 bytes for version and a bucket has another 6.
|
||||
|
@ -243,9 +241,8 @@ static_assert(alignof(BucketBase<12, 4>) == 1, "");
|
|||
// In order to achieve this we store high6(max{version(entry)}) for every entry.
|
||||
// Hence our version control may have false positives, i.e. signal that an entry has changed
|
||||
// when in practice its neighbour incremented the high6 part of its bucket.
|
||||
template <unsigned NUM_SLOTS, unsigned NUM_STASH_FPS>
|
||||
class VersionedBB : public BucketBase<NUM_SLOTS, NUM_STASH_FPS> {
|
||||
using Base = BucketBase<NUM_SLOTS, NUM_STASH_FPS>;
|
||||
template <unsigned NUM_SLOTS> class VersionedBB : public BucketBase<NUM_SLOTS> {
|
||||
using Base = BucketBase<NUM_SLOTS>;
|
||||
|
||||
public:
|
||||
// one common version per bucket.
|
||||
|
@ -286,15 +283,14 @@ class VersionedBB : public BucketBase<NUM_SLOTS, NUM_STASH_FPS> {
|
|||
// std::array<uint8_t, NUM_SLOTS> low_ = {0};
|
||||
};
|
||||
|
||||
static_assert(alignof(VersionedBB<14, 4>) == 1, "");
|
||||
static_assert(sizeof(VersionedBB<12, 4>) == 12 * 2 + 8, "");
|
||||
static_assert(sizeof(VersionedBB<14, 4>) <= 14 * 2 + 8, "");
|
||||
static_assert(alignof(VersionedBB<14>) == 1);
|
||||
static_assert(sizeof(VersionedBB<12>) == 12 * 2 + 8);
|
||||
static_assert(sizeof(VersionedBB<14>) <= 14 * 2 + 8);
|
||||
|
||||
// Segment - static-hashtable of size kSlotNum*(kBucketNum + kStashBucketNum).
|
||||
struct DefaultSegmentPolicy {
|
||||
static constexpr unsigned kSlotNum = 12;
|
||||
static constexpr unsigned kBucketNum = 64;
|
||||
static constexpr unsigned kStashBucketNum = 2;
|
||||
static constexpr bool kUseVersion = true;
|
||||
};
|
||||
|
||||
|
@ -302,15 +298,14 @@ template <typename _Key, typename _Value, typename Policy = DefaultSegmentPolicy
|
|||
public:
|
||||
static constexpr unsigned kSlotNum = Policy::kSlotNum;
|
||||
static constexpr unsigned kBucketNum = Policy::kBucketNum;
|
||||
static constexpr unsigned kStashBucketNum = Policy::kStashBucketNum;
|
||||
static constexpr unsigned kStashBucketNum = 4;
|
||||
static constexpr bool kUseVersion = Policy::kUseVersion;
|
||||
|
||||
private:
|
||||
static_assert(kBucketNum + kStashBucketNum < 255);
|
||||
static constexpr unsigned kFingerBits = 8;
|
||||
|
||||
using BucketType =
|
||||
std::conditional_t<kUseVersion, VersionedBB<kSlotNum, 4>, BucketBase<kSlotNum, 4>>;
|
||||
using BucketType = std::conditional_t<kUseVersion, VersionedBB<kSlotNum>, BucketBase<kSlotNum>>;
|
||||
|
||||
struct Bucket : public BucketType {
|
||||
using BucketType::kNanSlot;
|
||||
|
@ -613,14 +608,14 @@ template <typename _Key, typename _Value, typename Policy = DefaultSegmentPolicy
|
|||
}; // Segment
|
||||
|
||||
class DashTableBase {
|
||||
DashTableBase(const DashTableBase&) = delete;
|
||||
DashTableBase& operator=(const DashTableBase&) = delete;
|
||||
|
||||
public:
|
||||
explicit DashTableBase(uint32_t gd)
|
||||
: unique_segments_(1 << gd), initial_depth_(gd), global_depth_(gd) {
|
||||
}
|
||||
|
||||
DashTableBase(const DashTableBase&) = delete;
|
||||
DashTableBase& operator=(const DashTableBase&) = delete;
|
||||
|
||||
uint32_t unique_segments() const {
|
||||
return unique_segments_;
|
||||
}
|
||||
|
@ -810,8 +805,8 @@ ___ _ _ ____ _ _ ____ ___ ___ ____ ____ ____
|
|||
|
||||
*/
|
||||
|
||||
template <unsigned NUM_SLOTS, unsigned NUM_OVR>
|
||||
bool BucketBase<NUM_SLOTS, NUM_OVR>::ClearStash(uint8_t fp, unsigned stash_pos, bool probe) {
|
||||
template <unsigned NUM_SLOTS>
|
||||
bool BucketBase<NUM_SLOTS>::ClearStash(uint8_t fp, unsigned stash_pos, bool probe) {
|
||||
auto cb = [stash_pos, this](unsigned i, unsigned pos) -> SlotId {
|
||||
if (pos == stash_pos) {
|
||||
stash_busy_ &= (~(1u << i));
|
||||
|
@ -828,16 +823,16 @@ bool BucketBase<NUM_SLOTS, NUM_OVR>::ClearStash(uint8_t fp, unsigned stash_pos,
|
|||
return res.second != kNanSlot;
|
||||
}
|
||||
|
||||
template <unsigned NUM_SLOTS, unsigned NUM_OVR>
|
||||
void BucketBase<NUM_SLOTS, NUM_OVR>::SetHash(unsigned slot_id, uint8_t meta_hash, bool probe) {
|
||||
template <unsigned NUM_SLOTS>
|
||||
void BucketBase<NUM_SLOTS>::SetHash(unsigned slot_id, uint8_t meta_hash, bool probe) {
|
||||
assert(slot_id < finger_arr_.size());
|
||||
|
||||
finger_arr_[slot_id] = meta_hash;
|
||||
slotb_.SetSlot(slot_id, probe);
|
||||
}
|
||||
|
||||
template <unsigned NUM_SLOTS, unsigned NUM_OVR>
|
||||
bool BucketBase<NUM_SLOTS, NUM_OVR>::SetStash(uint8_t fp, unsigned stash_pos, bool probe) {
|
||||
template <unsigned NUM_SLOTS>
|
||||
bool BucketBase<NUM_SLOTS>::SetStash(uint8_t fp, unsigned stash_pos, bool probe) {
|
||||
// stash_busy_ is never 0xFFFFF so it's safe to run __builtin_ctz below.
|
||||
unsigned free_slot = __builtin_ctz(~stash_busy_);
|
||||
if (free_slot >= kStashFpLen)
|
||||
|
@ -856,9 +851,8 @@ bool BucketBase<NUM_SLOTS, NUM_OVR>::SetStash(uint8_t fp, unsigned stash_pos, bo
|
|||
return true;
|
||||
}
|
||||
|
||||
template <unsigned NUM_SLOTS, unsigned NUM_OVR>
|
||||
void BucketBase<NUM_SLOTS, NUM_OVR>::SetStashPtr(unsigned stash_pos, uint8_t meta_hash,
|
||||
BucketBase* next) {
|
||||
template <unsigned NUM_SLOTS>
|
||||
void BucketBase<NUM_SLOTS>::SetStashPtr(unsigned stash_pos, uint8_t meta_hash, BucketBase* next) {
|
||||
assert(stash_pos < 4);
|
||||
|
||||
// we use only kStashFpLen fp slots for handling stash buckets,
|
||||
|
@ -874,9 +868,9 @@ void BucketBase<NUM_SLOTS, NUM_OVR>::SetStashPtr(unsigned stash_pos, uint8_t met
|
|||
stash_busy_ |= kStashPresentBit;
|
||||
}
|
||||
|
||||
template <unsigned NUM_SLOTS, unsigned NUM_OVR>
|
||||
unsigned BucketBase<NUM_SLOTS, NUM_OVR>::UnsetStashPtr(uint8_t fp_hash, unsigned stash_pos,
|
||||
BucketBase* next) {
|
||||
template <unsigned NUM_SLOTS>
|
||||
unsigned BucketBase<NUM_SLOTS>::UnsetStashPtr(uint8_t fp_hash, unsigned stash_pos,
|
||||
BucketBase* next) {
|
||||
/*also needs to ensure that this meta_hash must belongs to other bucket*/
|
||||
bool clear_success = ClearStash(fp_hash, stash_pos, false);
|
||||
unsigned res = 0;
|
||||
|
@ -907,8 +901,7 @@ unsigned BucketBase<NUM_SLOTS, NUM_OVR>::UnsetStashPtr(uint8_t fp_hash, unsigned
|
|||
}
|
||||
|
||||
#ifdef __s390x__
|
||||
template <unsigned NUM_SLOTS, unsigned NUM_OVR>
|
||||
uint32_t BucketBase<NUM_SLOTS, NUM_OVR>::CompareFP(uint8_t fp) const {
|
||||
template <unsigned NUM_SLOTS> uint32_t BucketBase<NUM_SLOTS>::CompareFP(uint8_t fp) const {
|
||||
static_assert(FpArray{}.size() <= 16);
|
||||
vector unsigned char v1;
|
||||
|
||||
|
@ -934,8 +927,7 @@ uint32_t BucketBase<NUM_SLOTS, NUM_OVR>::CompareFP(uint8_t fp) const {
|
|||
return mask;
|
||||
}
|
||||
#else
|
||||
template <unsigned NUM_SLOTS, unsigned NUM_OVR>
|
||||
uint32_t BucketBase<NUM_SLOTS, NUM_OVR>::CompareFP(uint8_t fp) const {
|
||||
template <unsigned NUM_SLOTS> uint32_t BucketBase<NUM_SLOTS>::CompareFP(uint8_t fp) const {
|
||||
static_assert(FpArray{}.size() <= 16);
|
||||
|
||||
// Replicate 16 times fp to key_data.
|
||||
|
@ -958,7 +950,7 @@ uint32_t BucketBase<NUM_SLOTS, NUM_OVR>::CompareFP(uint8_t fp) const {
|
|||
// Bucket slot array goes from left to right: [x, x, ...]
|
||||
// Shift right vacates the first slot on the left by shifting all the elements right and
|
||||
// possibly deleting the last one on the right.
|
||||
template <unsigned NUM_SLOTS, unsigned NUM_OVR> bool BucketBase<NUM_SLOTS, NUM_OVR>::ShiftRight() {
|
||||
template <unsigned NUM_SLOTS> bool BucketBase<NUM_SLOTS>::ShiftRight() {
|
||||
for (int i = NUM_SLOTS - 1; i > 0; --i) {
|
||||
finger_arr_[i] = finger_arr_[i - 1];
|
||||
}
|
||||
|
@ -970,9 +962,9 @@ template <unsigned NUM_SLOTS, unsigned NUM_OVR> bool BucketBase<NUM_SLOTS, NUM_O
|
|||
return res;
|
||||
}
|
||||
|
||||
template <unsigned NUM_SLOTS, unsigned NUM_OVR>
|
||||
template <unsigned NUM_SLOTS>
|
||||
template <typename F>
|
||||
auto BucketBase<NUM_SLOTS, NUM_OVR>::IterateStash(uint8_t fp, bool is_probe, F&& func) const
|
||||
auto BucketBase<NUM_SLOTS>::IterateStash(uint8_t fp, bool is_probe, F&& func) const
|
||||
-> ::std::pair<unsigned, SlotId> {
|
||||
unsigned om = is_probe ? stash_probe_mask_ : ~stash_probe_mask_;
|
||||
unsigned ob = stash_busy_;
|
||||
|
@ -991,14 +983,13 @@ auto BucketBase<NUM_SLOTS, NUM_OVR>::IterateStash(uint8_t fp, bool is_probe, F&&
|
|||
return std::pair<unsigned, SlotId>(0, BucketBase::kNanSlot);
|
||||
}
|
||||
|
||||
template <unsigned NUM_SLOTS, unsigned NUM_STASH_FPS>
|
||||
void VersionedBB<NUM_SLOTS, NUM_STASH_FPS>::SetVersion(uint64_t version) {
|
||||
template <unsigned NUM_SLOTS> void VersionedBB<NUM_SLOTS>::SetVersion(uint64_t version) {
|
||||
absl::little_endian::Store64(version_, version);
|
||||
}
|
||||
|
||||
#if 0
|
||||
template <unsigned NUM_SLOTS, unsigned NUM_STASH_FPS>
|
||||
uint64_t VersionedBB<NUM_SLOTS, NUM_STASH_FPS>::MinVersion() const {
|
||||
template <unsigned NUM_SLOTS>
|
||||
uint64_t VersionedBB<NUM_SLOTS>::MinVersion() const {
|
||||
uint32_t mask = this->GetBusy();
|
||||
if (mask == 0)
|
||||
return 0;
|
||||
|
|
|
@ -240,8 +240,8 @@ TEST_F(DashTest, Segment) {
|
|||
for (size_t i = 2; i < Segment::kBucketNum; ++i) {
|
||||
EXPECT_EQ(0, segment_.GetBucket(i).Size());
|
||||
}
|
||||
EXPECT_EQ(4 * Segment::kSlotNum, keys.size());
|
||||
EXPECT_EQ(4 * Segment::kSlotNum, segment_.SlowSize());
|
||||
EXPECT_EQ(6 * Segment::kSlotNum, keys.size());
|
||||
EXPECT_EQ(6 * Segment::kSlotNum, segment_.SlowSize());
|
||||
|
||||
auto hfun = &UInt64Policy::HashFn;
|
||||
unsigned has_called = 0;
|
||||
|
@ -268,7 +268,7 @@ TEST_F(DashTest, Segment) {
|
|||
ASSERT_TRUE(it.found());
|
||||
segment_.Delete(it, hash);
|
||||
}
|
||||
EXPECT_EQ(2 * Segment::kSlotNum, segment_.SlowSize());
|
||||
EXPECT_EQ(4 * Segment::kSlotNum, segment_.SlowSize());
|
||||
ASSERT_FALSE(Contains(arr.front()));
|
||||
}
|
||||
|
||||
|
@ -331,7 +331,7 @@ TEST_F(DashTest, Split) {
|
|||
ASSERT_EQ(segment_.SlowSize(), sum[0]);
|
||||
EXPECT_EQ(s2.SlowSize(), sum[1]);
|
||||
EXPECT_EQ(keys.size(), sum[0] + sum[1]);
|
||||
EXPECT_EQ(4 * Segment::kSlotNum, keys.size());
|
||||
EXPECT_EQ(6 * Segment::kSlotNum, keys.size());
|
||||
}
|
||||
|
||||
TEST_F(DashTest, Merge) {
|
||||
|
@ -456,12 +456,12 @@ struct Item {
|
|||
|
||||
constexpr size_t ItemAlign = alignof(Item);
|
||||
|
||||
struct MyBucket : public detail::BucketBase<16, 4> {
|
||||
struct MyBucket : public detail::BucketBase<16> {
|
||||
Item key[14];
|
||||
};
|
||||
|
||||
constexpr size_t kMySz = sizeof(MyBucket);
|
||||
constexpr size_t kBBSz = sizeof(detail::BucketBase<16, 4>);
|
||||
constexpr size_t kBBSz = sizeof(detail::BucketBase<16>);
|
||||
|
||||
TEST_F(DashTest, Custom) {
|
||||
using ItemSegment = detail::Segment<Item, uint64_t>;
|
||||
|
@ -659,7 +659,7 @@ struct TestEvictionPolicy {
|
|||
};
|
||||
|
||||
TEST_F(DashTest, Eviction) {
|
||||
TestEvictionPolicy ev(1500);
|
||||
TestEvictionPolicy ev(1540);
|
||||
|
||||
size_t num = 0;
|
||||
auto loop = [&] {
|
||||
|
|
|
@ -16,7 +16,7 @@ using PrimeKey = CompactObj;
|
|||
using PrimeValue = CompactObj;
|
||||
|
||||
struct PrimeTablePolicy {
|
||||
enum { kSlotNum = 14, kBucketNum = 56, kStashBucketNum = 4 };
|
||||
enum { kSlotNum = 14, kBucketNum = 56 };
|
||||
|
||||
static constexpr bool kUseVersion = true;
|
||||
|
||||
|
@ -46,7 +46,7 @@ struct PrimeTablePolicy {
|
|||
};
|
||||
|
||||
struct ExpireTablePolicy {
|
||||
enum { kSlotNum = 14, kBucketNum = 56, kStashBucketNum = 4 };
|
||||
enum { kSlotNum = 14, kBucketNum = 56 };
|
||||
static constexpr bool kUseVersion = false;
|
||||
|
||||
static uint64_t HashFn(const PrimeKey& s) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue