Skip to content

Commit d5c3752

Browse files
authored
feat: allow sharding by cluster slot id (#5006)
This is relevant only for cluster-enabled configurations. Also, inline the cluster config getter functions, as they are on critical path for 100% of requests. Finally, skip a test that triggers a check-fail bug filed in #5004 Fixes #5005 Signed-off-by: Roman Gershman <roman@dragonflydb.io>
1 parent 71dd189 commit d5c3752

File tree

4 files changed

+57
-23
lines changed

4 files changed

+57
-23
lines changed

src/server/cluster_support.cc

+13-20
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ ABSL_FLAG(string, cluster_mode, "",
1717
"Cluster mode supported. Possible values are "
1818
"'emulated', 'yes' or ''");
1919

20+
ABSL_FLAG(bool, experimental_cluster_shard_by_slot, false,
21+
"If true, cluster mode is enabled and sharding is done by slot. "
22+
"Otherwise, sharding is done by hash tag.");
23+
2024
namespace dfly {
2125

2226
void UniqueSlotChecker::Add(std::string_view key) {
@@ -43,16 +47,13 @@ optional<SlotId> UniqueSlotChecker::GetUniqueSlotId() const {
4347
return slot_id_ > kMaxSlotNum ? optional<SlotId>() : slot_id_;
4448
}
4549

46-
namespace {
47-
enum class ClusterMode {
48-
kUninitialized,
49-
kNoCluster,
50-
kEmulatedCluster,
51-
kRealCluster,
52-
};
53-
50+
namespace detail {
5451
ClusterMode cluster_mode = ClusterMode::kUninitialized;
55-
} // namespace
52+
bool cluster_shard_by_slot = false;
53+
54+
} // namespace detail
55+
56+
using namespace detail;
5657

5758
void InitializeCluster() {
5859
string cluster_mode_str = absl::GetFlag(FLAGS_cluster_mode);
@@ -67,25 +68,17 @@ void InitializeCluster() {
6768
LOG(ERROR) << "Invalid value for flag --cluster_mode. Exiting...";
6869
exit(1);
6970
}
70-
}
7171

72-
bool IsClusterEnabled() {
73-
return cluster_mode == ClusterMode::kRealCluster;
74-
}
75-
76-
bool IsClusterEmulated() {
77-
return cluster_mode == ClusterMode::kEmulatedCluster;
72+
if (cluster_mode != ClusterMode::kNoCluster) {
73+
cluster_shard_by_slot = absl::GetFlag(FLAGS_experimental_cluster_shard_by_slot);
74+
}
7875
}
7976

8077
SlotId KeySlot(std::string_view key) {
8178
string_view tag = LockTagOptions::instance().Tag(key);
8279
return crc16(tag.data(), tag.length()) & kMaxSlotNum;
8380
}
8481

85-
bool IsClusterEnabledOrEmulated() {
86-
return IsClusterEnabled() || IsClusterEmulated();
87-
}
88-
8982
bool IsClusterShardedByTag() {
9083
return IsClusterEnabledOrEmulated() || LockTagOptions::instance().enabled;
9184
}

src/server/cluster_support.h

+31-3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,20 @@
1010

1111
namespace dfly {
1212

13+
namespace detail {
14+
15+
enum class ClusterMode {
16+
kUninitialized,
17+
kNoCluster,
18+
kEmulatedCluster,
19+
kRealCluster,
20+
};
21+
22+
extern ClusterMode cluster_mode;
23+
extern bool cluster_shard_by_slot;
24+
25+
}; // namespace detail
26+
1327
using SlotId = std::uint16_t;
1428
constexpr SlotId kMaxSlotNum = 0x3FFF;
1529

@@ -42,9 +56,23 @@ class UniqueSlotChecker {
4256
SlotId KeySlot(std::string_view key);
4357

4458
void InitializeCluster();
45-
bool IsClusterEnabled();
46-
bool IsClusterEmulated();
47-
bool IsClusterEnabledOrEmulated();
59+
60+
inline bool IsClusterEnabled() {
61+
return detail::cluster_mode == detail::ClusterMode::kRealCluster;
62+
}
63+
64+
inline bool IsClusterEmulated() {
65+
return detail::cluster_mode == detail::ClusterMode::kEmulatedCluster;
66+
}
67+
68+
inline bool IsClusterEnabledOrEmulated() {
69+
return IsClusterEnabled() || IsClusterEmulated();
70+
}
71+
72+
inline bool IsClusterShardedBySlot() {
73+
return detail::cluster_shard_by_slot;
74+
}
75+
4876
bool IsClusterShardedByTag();
4977

5078
} // namespace dfly

src/server/engine_shard.cc

+11
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,17 @@ __thread EngineShard* EngineShard::shard_ = nullptr;
261261
uint64_t TEST_current_time_ms = 0;
262262

263263
ShardId Shard(string_view v, ShardId shard_num) {
264+
// This cluster sharding is not necessary and may degrade keys distribution among shard threads.
265+
// For example, if we have 3 shards, then no single-char keys will be assigned to shard 2 and
266+
// 32 single char keys in range ['_' - '~'] will be assigned to shard 0.
267+
// Yes, SlotId function does not have great distribution properties.
268+
// On the other side, slot based sharding may help with pipeline squashing optimizations,
269+
// because they rely on commands being single-sharded.
270+
// TODO: once we improve our squashing logic, we can remove this.
271+
if (IsClusterShardedBySlot()) {
272+
return KeySlot(v) % shard_num;
273+
}
274+
264275
if (IsClusterShardedByTag()) {
265276
v = LockTagOptions::instance().Tag(v);
266277
}

src/server/hll_family_test.cc

+2
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,8 @@ TEST_F(HllFamilyTest, MergeOverlapping) {
194194
}
195195

196196
TEST_F(HllFamilyTest, MergeInvalid) {
197+
GTEST_SKIP() << "TBD: MergeInvalid test fails with multi-shard runs, see #5004";
198+
197199
EXPECT_EQ(CheckedInt({"pfadd", "key1", "1", "2", "3"}), 1);
198200
EXPECT_EQ(Run({"set", "key2", "..."}), "OK");
199201
EXPECT_THAT(Run({"pfmerge", "key1", "key2"}), ErrArg(HllFamily::kInvalidHllErr));

0 commit comments

Comments
 (0)