refactor: add cluster namespace (#2948)

* refactor: add cluster namespace, remove extra includes
This commit is contained in:
Borys 2024-04-22 21:45:43 +03:00 committed by GitHub
parent 1a5eacca87
commit 2230397a12
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
43 changed files with 330 additions and 297 deletions

View file

@ -52,7 +52,7 @@ add_library(dragonfly_lib bloom_family.cc engine_shard_set.cc channel_store.cc
zset_family.cc version.cc bitops_family.cc container_utils.cc io_utils.cc zset_family.cc version.cc bitops_family.cc container_utils.cc io_utils.cc
top_keys.cc multi_command_squasher.cc hll_family.cc cluster/cluster_config.cc top_keys.cc multi_command_squasher.cc hll_family.cc cluster/cluster_config.cc
cluster/cluster_family.cc cluster/incoming_slot_migration.cc cluster/cluster_family.cc cluster/incoming_slot_migration.cc
cluster/outgoing_slot_migration.cc cluster/outgoing_slot_migration.cc cluster/cluster_defs.cc
acl/user.cc acl/user_registry.cc acl/acl_family.cc acl/user.cc acl/user_registry.cc acl/acl_family.cc
acl/validator.cc acl/helpers.cc) acl/validator.cc acl/helpers.cc)

View file

@ -1,64 +1,17 @@
#include <optional> #include "cluster_config.h"
extern "C" {
#include "redis/crc16.h"
}
#include <absl/container/flat_hash_set.h> #include <absl/container/flat_hash_set.h>
#include <jsoncons/json.hpp> #include <jsoncons/json.hpp>
#include <shared_mutex> #include <optional>
#include <string_view> #include <string_view>
#include "absl/strings/match.h"
#include "base/flags.h"
#include "base/logging.h" #include "base/logging.h"
#include "cluster_config.h"
#include "core/json/json_object.h" #include "core/json/json_object.h"
using namespace std; using namespace std;
ABSL_FLAG(string, cluster_mode, "", "Cluster mode supported. Default: \"\""); namespace dfly::cluster {
namespace dfly {
namespace {
enum class ClusterMode {
kUninitialized,
kNoCluster,
kEmulatedCluster,
kRealCluster,
};
ClusterMode cluster_mode = ClusterMode::kUninitialized;
} // namespace
void ClusterConfig::Initialize() {
string cluster_mode_str = absl::GetFlag(FLAGS_cluster_mode);
if (cluster_mode_str == "emulated") {
cluster_mode = ClusterMode::kEmulatedCluster;
} else if (cluster_mode_str == "yes") {
cluster_mode = ClusterMode::kRealCluster;
} else if (cluster_mode_str.empty()) {
cluster_mode = ClusterMode::kNoCluster;
} else {
LOG(ERROR) << "Invalid value for flag --cluster_mode. Exiting...";
exit(1);
}
}
bool ClusterConfig::IsEnabled() {
return cluster_mode == ClusterMode::kRealCluster;
}
bool ClusterConfig::IsEmulated() {
return cluster_mode == ClusterMode::kEmulatedCluster;
}
SlotId ClusterConfig::KeySlot(string_view key) {
string_view tag = LockTagOptions::instance().Tag(key);
return crc16(tag.data(), tag.length()) & kMaxSlotNum;
}
namespace { namespace {
bool HasValidNodeIds(const ClusterShardInfos& new_config) { bool HasValidNodeIds(const ClusterShardInfos& new_config) {
@ -87,7 +40,7 @@ bool HasValidNodeIds(const ClusterShardInfos& new_config) {
bool IsConfigValid(const ClusterShardInfos& new_config) { bool IsConfigValid(const ClusterShardInfos& new_config) {
// Make sure that all slots are set exactly once. // Make sure that all slots are set exactly once.
array<bool, ClusterConfig::kMaxSlotNum + 1> slots_found = {}; array<bool, cluster::kMaxSlotNum + 1> slots_found = {};
if (!HasValidNodeIds(new_config)) { if (!HasValidNodeIds(new_config)) {
return false; return false;
@ -347,7 +300,7 @@ std::shared_ptr<ClusterConfig> ClusterConfig::CloneWithChanges(
} }
bool ClusterConfig::IsMySlot(SlotId id) const { bool ClusterConfig::IsMySlot(SlotId id) const {
if (id > ClusterConfig::kMaxSlotNum) { if (id > cluster::kMaxSlotNum) {
DCHECK(false) << "Requesting a non-existing slot id " << id; DCHECK(false) << "Requesting a non-existing slot id " << id;
return false; return false;
} }
@ -360,7 +313,7 @@ bool ClusterConfig::IsMySlot(std::string_view key) const {
} }
ClusterNodeInfo ClusterConfig::GetMasterNodeForSlot(SlotId id) const { ClusterNodeInfo ClusterConfig::GetMasterNodeForSlot(SlotId id) const {
CHECK_LE(id, ClusterConfig::kMaxSlotNum) << "Requesting a non-existing slot id " << id; CHECK_LE(id, cluster::kMaxSlotNum) << "Requesting a non-existing slot id " << id;
for (const auto& shard : config_) { for (const auto& shard : config_) {
for (const auto& range : shard.slot_ranges) { for (const auto& range : shard.slot_ranges) {
@ -417,4 +370,4 @@ std::vector<MigrationInfo> ClusterConfig::GetFinishedIncomingMigrations(
: std::vector<MigrationInfo>(); : std::vector<MigrationInfo>();
} }
} // namespace dfly } // namespace dfly::cluster

View file

@ -11,63 +11,10 @@
#include "src/server/cluster/slot_set.h" #include "src/server/cluster/slot_set.h"
#include "src/server/common.h" #include "src/server/common.h"
namespace dfly { namespace dfly::cluster {
// MigrationState constants are ordered in state changing order
enum class MigrationState : uint8_t {
C_NO_STATE,
C_CONNECTING,
C_SYNC,
C_FINISHED,
C_CANCELLED,
C_MAX_INVALID = std::numeric_limits<uint8_t>::max()
};
struct ClusterNodeInfo {
std::string id;
std::string ip;
uint16_t port = 0;
};
struct MigrationInfo {
std::vector<SlotRange> slot_ranges;
std::string node_id;
std::string ip;
uint16_t port = 0;
bool operator==(const MigrationInfo& r) const {
return ip == r.ip && port == r.port && slot_ranges == r.slot_ranges && node_id == r.node_id;
}
};
struct ClusterShardInfo {
SlotRanges slot_ranges;
ClusterNodeInfo master;
std::vector<ClusterNodeInfo> replicas;
std::vector<MigrationInfo> migrations;
};
using ClusterShardInfos = std::vector<ClusterShardInfo>;
class ClusterConfig { class ClusterConfig {
public: public:
static constexpr SlotId kMaxSlotNum = 0x3FFF;
static constexpr SlotId kInvalidSlotId = kMaxSlotNum + 1;
static SlotId KeySlot(std::string_view key);
static void Initialize();
static bool IsEnabled();
static bool IsEmulated();
static bool IsEnabledOrEmulated() {
return IsEnabled() || IsEmulated();
}
static bool IsShardedByTag() {
return IsEnabledOrEmulated() || LockTagOptions::instance().enabled;
}
// Returns an instance with `config` if it is valid. // Returns an instance with `config` if it is valid.
// Returns heap-allocated object as it is too big for a stack frame. // Returns heap-allocated object as it is too big for a stack frame.
static std::shared_ptr<ClusterConfig> CreateFromConfig(std::string_view my_id, static std::shared_ptr<ClusterConfig> CreateFromConfig(std::string_view my_id,
@ -119,4 +66,4 @@ class ClusterConfig {
std::vector<MigrationInfo> my_incoming_migrations_; std::vector<MigrationInfo> my_incoming_migrations_;
}; };
} // namespace dfly } // namespace dfly::cluster

View file

@ -14,9 +14,9 @@
using namespace std; using namespace std;
using namespace testing; using namespace testing;
using Node = dfly::ClusterNodeInfo; using Node = dfly::cluster::ClusterNodeInfo;
namespace dfly { namespace dfly::cluster {
MATCHER_P(NodeMatches, expected, "") { MATCHER_P(NodeMatches, expected, "") {
return arg.id == expected.id && arg.ip == expected.ip && arg.port == expected.port; return arg.id == expected.id && arg.ip == expected.ip && arg.port == expected.port;
@ -558,4 +558,4 @@ TEST_F(ClusterConfigTest, InvalidConfigMigrationsWithoutIP) {
EXPECT_EQ(config, nullptr); EXPECT_EQ(config, nullptr);
} }
} // namespace dfly } // namespace dfly::cluster

View file

@ -0,0 +1,63 @@
extern "C" {
#include "redis/crc16.h"
}
#include "base/flags.h"
#include "base/logging.h"
#include "cluster_defs.h"
#include "src/server/common.h"
using namespace std;
ABSL_FLAG(string, cluster_mode, "", "Cluster mode supported. Default: \"\"");
namespace dfly::cluster {
namespace {
enum class ClusterMode {
kUninitialized,
kNoCluster,
kEmulatedCluster,
kRealCluster,
};
ClusterMode cluster_mode = ClusterMode::kUninitialized;
} // namespace
void InitializeCluster() {
string cluster_mode_str = absl::GetFlag(FLAGS_cluster_mode);
if (cluster_mode_str == "emulated") {
cluster_mode = ClusterMode::kEmulatedCluster;
} else if (cluster_mode_str == "yes") {
cluster_mode = ClusterMode::kRealCluster;
} else if (cluster_mode_str.empty()) {
cluster_mode = ClusterMode::kNoCluster;
} else {
LOG(ERROR) << "Invalid value for flag --cluster_mode. Exiting...";
exit(1);
}
}
bool IsClusterEnabled() {
return cluster_mode == ClusterMode::kRealCluster;
}
bool IsClusterEmulated() {
return cluster_mode == ClusterMode::kEmulatedCluster;
}
SlotId KeySlot(std::string_view key) {
string_view tag = LockTagOptions::instance().Tag(key);
return crc16(tag.data(), tag.length()) & kMaxSlotNum;
}
bool IsClusterEnabledOrEmulated() {
return IsClusterEnabled() || IsClusterEmulated();
}
bool IsClusterShardedByTag() {
return IsClusterEnabledOrEmulated() || LockTagOptions::instance().enabled;
}
} // namespace dfly::cluster

View file

@ -0,0 +1,90 @@
// Copyright 2024, DragonflyDB authors. All rights reserved.
// See LICENSE for licensing terms.
//
#pragma once
#include <absl/strings/str_cat.h>
#include <absl/strings/str_join.h>
#include <memory>
#include <string>
#include <string_view>
#include <vector>
namespace dfly::cluster {
using SlotId = uint16_t;
constexpr SlotId kMaxSlotNum = 0x3FFF;
constexpr SlotId kInvalidSlotId = kMaxSlotNum + 1;
struct SlotRange {
static constexpr SlotId kMaxSlotId = 0x3FFF;
SlotId start = 0;
SlotId end = 0;
bool operator==(const SlotRange& r) const {
return start == r.start && end == r.end;
}
bool IsValid() {
return start <= end && start <= kMaxSlotId && end <= kMaxSlotId;
}
std::string ToString() const {
return absl::StrCat("[", start, ", ", end, "]");
}
static std::string ToString(const std::vector<SlotRange>& ranges) {
return absl::StrJoin(ranges, ", ", [](std::string* out, SlotRange range) {
absl::StrAppend(out, range.ToString());
});
}
};
using SlotRanges = std::vector<SlotRange>;
struct ClusterNodeInfo {
std::string id;
std::string ip;
uint16_t port = 0;
};
struct MigrationInfo {
std::vector<SlotRange> slot_ranges;
std::string node_id;
std::string ip;
uint16_t port = 0;
bool operator==(const MigrationInfo& r) const {
return ip == r.ip && port == r.port && slot_ranges == r.slot_ranges && node_id == r.node_id;
}
};
struct ClusterShardInfo {
SlotRanges slot_ranges;
ClusterNodeInfo master;
std::vector<ClusterNodeInfo> replicas;
std::vector<MigrationInfo> migrations;
};
using ClusterShardInfos = std::vector<ClusterShardInfo>;
// MigrationState constants are ordered in state changing order
enum class MigrationState : uint8_t {
C_NO_STATE,
C_CONNECTING,
C_SYNC,
C_FINISHED,
C_MAX_INVALID = std::numeric_limits<uint8_t>::max()
};
SlotId KeySlot(std::string_view key);
void InitializeCluster();
bool IsClusterEnabled();
bool IsClusterEmulated();
bool IsClusterEnabledOrEmulated();
bool IsClusterShardedByTag();
} // namespace dfly::cluster

View file

@ -32,6 +32,17 @@ ABSL_FLAG(std::string, cluster_node_id, "",
ABSL_DECLARE_FLAG(int32_t, port); ABSL_DECLARE_FLAG(int32_t, port);
namespace dfly { namespace dfly {
namespace acl {
constexpr uint32_t kCluster = SLOW;
// Reconsider to maybe more sensible defaults
constexpr uint32_t kDflyCluster = ADMIN | SLOW;
constexpr uint32_t kReadOnly = FAST | CONNECTION;
constexpr uint32_t kReadWrite = FAST | CONNECTION;
constexpr uint32_t kDflyMigrate = ADMIN | SLOW | DANGEROUS;
} // namespace acl
} // namespace dfly
namespace dfly::cluster {
namespace { namespace {
using namespace std; using namespace std;
@ -52,12 +63,12 @@ thread_local shared_ptr<ClusterConfig> tl_cluster_config;
ClusterFamily::ClusterFamily(ServerFamily* server_family) : server_family_(server_family) { ClusterFamily::ClusterFamily(ServerFamily* server_family) : server_family_(server_family) {
CHECK_NOTNULL(server_family_); CHECK_NOTNULL(server_family_);
ClusterConfig::Initialize(); InitializeCluster();
id_ = absl::GetFlag(FLAGS_cluster_node_id); id_ = absl::GetFlag(FLAGS_cluster_node_id);
if (id_.empty()) { if (id_.empty()) {
id_ = server_family_->master_replid(); id_ = server_family_->master_replid();
} else if (ClusterConfig::IsEmulated()) { } else if (IsClusterEmulated()) {
LOG(ERROR) << "Setting --cluster_node_id in emulated mode is unsupported"; LOG(ERROR) << "Setting --cluster_node_id in emulated mode is unsupported";
exit(1); exit(1);
} }
@ -68,7 +79,7 @@ ClusterConfig* ClusterFamily::cluster_config() {
} }
ClusterShardInfo ClusterFamily::GetEmulatedShardInfo(ConnectionContext* cntx) const { ClusterShardInfo ClusterFamily::GetEmulatedShardInfo(ConnectionContext* cntx) const {
ClusterShardInfo info{.slot_ranges = {{.start = 0, .end = ClusterConfig::kMaxSlotNum}}, ClusterShardInfo info{.slot_ranges = {{.start = 0, .end = kMaxSlotNum}},
.master = {}, .master = {},
.replicas = {}, .replicas = {},
.migrations = {}}; .migrations = {}};
@ -166,7 +177,7 @@ void ClusterShardsImpl(const ClusterShardInfos& config, ConnectionContext* cntx)
} // namespace } // namespace
void ClusterFamily::ClusterShards(ConnectionContext* cntx) { void ClusterFamily::ClusterShards(ConnectionContext* cntx) {
if (ClusterConfig::IsEmulated()) { if (IsClusterEmulated()) {
return ClusterShardsImpl({GetEmulatedShardInfo(cntx)}, cntx); return ClusterShardsImpl({GetEmulatedShardInfo(cntx)}, cntx);
} else if (tl_cluster_config != nullptr) { } else if (tl_cluster_config != nullptr) {
return ClusterShardsImpl(tl_cluster_config->GetConfig(), cntx); return ClusterShardsImpl(tl_cluster_config->GetConfig(), cntx);
@ -210,7 +221,7 @@ void ClusterSlotsImpl(const ClusterShardInfos& config, ConnectionContext* cntx)
} // namespace } // namespace
void ClusterFamily::ClusterSlots(ConnectionContext* cntx) { void ClusterFamily::ClusterSlots(ConnectionContext* cntx) {
if (ClusterConfig::IsEmulated()) { if (IsClusterEmulated()) {
return ClusterSlotsImpl({GetEmulatedShardInfo(cntx)}, cntx); return ClusterSlotsImpl({GetEmulatedShardInfo(cntx)}, cntx);
} else if (tl_cluster_config != nullptr) { } else if (tl_cluster_config != nullptr) {
return ClusterSlotsImpl(tl_cluster_config->GetConfig(), cntx); return ClusterSlotsImpl(tl_cluster_config->GetConfig(), cntx);
@ -265,7 +276,7 @@ void ClusterNodesImpl(const ClusterShardInfos& config, string_view my_id, Connec
} // namespace } // namespace
void ClusterFamily::ClusterNodes(ConnectionContext* cntx) { void ClusterFamily::ClusterNodes(ConnectionContext* cntx) {
if (ClusterConfig::IsEmulated()) { if (IsClusterEmulated()) {
return ClusterNodesImpl({GetEmulatedShardInfo(cntx)}, id_, cntx); return ClusterNodesImpl({GetEmulatedShardInfo(cntx)}, id_, cntx);
} else if (tl_cluster_config != nullptr) { } else if (tl_cluster_config != nullptr) {
return ClusterNodesImpl(tl_cluster_config->GetConfig(), id_, cntx); return ClusterNodesImpl(tl_cluster_config->GetConfig(), id_, cntx);
@ -284,7 +295,7 @@ void ClusterInfoImpl(const ClusterShardInfos& config, ConnectionContext* cntx) {
// Initialize response variables to emulated mode. // Initialize response variables to emulated mode.
string_view state = "ok"sv; string_view state = "ok"sv;
SlotId slots_assigned = ClusterConfig::kMaxSlotNum + 1; SlotId slots_assigned = kMaxSlotNum + 1;
size_t known_nodes = 1; size_t known_nodes = 1;
long epoch = 1; long epoch = 1;
size_t cluster_size = 1; size_t cluster_size = 1;
@ -329,7 +340,7 @@ void ClusterInfoImpl(const ClusterShardInfos& config, ConnectionContext* cntx) {
} // namespace } // namespace
void ClusterFamily::ClusterInfo(ConnectionContext* cntx) { void ClusterFamily::ClusterInfo(ConnectionContext* cntx) {
if (ClusterConfig::IsEmulated()) { if (IsClusterEmulated()) {
return ClusterInfoImpl({GetEmulatedShardInfo(cntx)}, cntx); return ClusterInfoImpl({GetEmulatedShardInfo(cntx)}, cntx);
} else if (tl_cluster_config != nullptr) { } else if (tl_cluster_config != nullptr) {
return ClusterInfoImpl(tl_cluster_config->GetConfig(), cntx); return ClusterInfoImpl(tl_cluster_config->GetConfig(), cntx);
@ -343,7 +354,7 @@ void ClusterFamily::KeySlot(CmdArgList args, ConnectionContext* cntx) {
return cntx->SendError(WrongNumArgsError("CLUSTER KEYSLOT")); return cntx->SendError(WrongNumArgsError("CLUSTER KEYSLOT"));
} }
SlotId id = ClusterConfig::KeySlot(ArgS(args, 1)); SlotId id = cluster::KeySlot(ArgS(args, 1));
return cntx->SendLong(id); return cntx->SendLong(id);
} }
@ -354,7 +365,7 @@ void ClusterFamily::Cluster(CmdArgList args, ConnectionContext* cntx) {
ToUpper(&args[0]); ToUpper(&args[0]);
string_view sub_cmd = ArgS(args, 0); string_view sub_cmd = ArgS(args, 0);
if (!ClusterConfig::IsEnabledOrEmulated()) { if (!IsClusterEnabledOrEmulated()) {
return cntx->SendError(kClusterDisabled); return cntx->SendError(kClusterDisabled);
} }
@ -376,21 +387,21 @@ void ClusterFamily::Cluster(CmdArgList args, ConnectionContext* cntx) {
} }
void ClusterFamily::ReadOnly(CmdArgList args, ConnectionContext* cntx) { void ClusterFamily::ReadOnly(CmdArgList args, ConnectionContext* cntx) {
if (!ClusterConfig::IsEmulated()) { if (!IsClusterEmulated()) {
return cntx->SendError(kClusterDisabled); return cntx->SendError(kClusterDisabled);
} }
cntx->SendOk(); cntx->SendOk();
} }
void ClusterFamily::ReadWrite(CmdArgList args, ConnectionContext* cntx) { void ClusterFamily::ReadWrite(CmdArgList args, ConnectionContext* cntx) {
if (!ClusterConfig::IsEmulated()) { if (!IsClusterEmulated()) {
return cntx->SendError(kClusterDisabled); return cntx->SendError(kClusterDisabled);
} }
cntx->SendOk(); cntx->SendOk();
} }
void ClusterFamily::DflyCluster(CmdArgList args, ConnectionContext* cntx) { void ClusterFamily::DflyCluster(CmdArgList args, ConnectionContext* cntx) {
if (!ClusterConfig::IsEnabledOrEmulated()) { if (!IsClusterEnabledOrEmulated()) {
return cntx->SendError(kClusterDisabled); return cntx->SendError(kClusterDisabled);
} }
@ -570,7 +581,7 @@ void ClusterFamily::DflyClusterGetSlotInfo(CmdArgList args, ConnectionContext* c
vector<std::pair<SlotId, SlotStats>> slots_stats; vector<std::pair<SlotId, SlotStats>> slots_stats;
do { do {
auto sid = parser.Next<uint32_t>(); auto sid = parser.Next<uint32_t>();
if (sid > ClusterConfig::kMaxSlotNum) if (sid > kMaxSlotNum)
return rb->SendError("Invalid slot id"); return rb->SendError("Invalid slot id");
slots_stats.emplace_back(sid, SlotStats{}); slots_stats.emplace_back(sid, SlotStats{});
} while (parser.HasNext()); } while (parser.HasNext());
@ -646,8 +657,6 @@ static string_view StateToStr(MigrationState state) {
return "SYNC"sv; return "SYNC"sv;
case MigrationState::C_FINISHED: case MigrationState::C_FINISHED:
return "FINISHED"sv; return "FINISHED"sv;
case MigrationState::C_CANCELLED:
return "CANCELLED"sv;
case MigrationState::C_MAX_INVALID: case MigrationState::C_MAX_INVALID:
break; break;
} }
@ -924,15 +933,6 @@ inline CommandId::Handler HandlerFunc(ClusterFamily* se, EngineFunc f) {
#define HFUNC(x) SetHandler(HandlerFunc(this, &ClusterFamily::x)) #define HFUNC(x) SetHandler(HandlerFunc(this, &ClusterFamily::x))
namespace acl {
constexpr uint32_t kCluster = SLOW;
// Reconsider to maybe more sensible defaults
constexpr uint32_t kDflyCluster = ADMIN | SLOW;
constexpr uint32_t kReadOnly = FAST | CONNECTION;
constexpr uint32_t kReadWrite = FAST | CONNECTION;
constexpr uint32_t kDflyMigrate = ADMIN | SLOW | DANGEROUS;
} // namespace acl
void ClusterFamily::Register(CommandRegistry* registry) { void ClusterFamily::Register(CommandRegistry* registry) {
registry->StartFamily(); registry->StartFamily();
*registry << CI{"CLUSTER", CO::READONLY, -2, 0, 0, acl::kCluster}.HFUNC(Cluster) *registry << CI{"CLUSTER", CO::READONLY, -2, 0, 0, acl::kCluster}.HFUNC(Cluster)
@ -945,4 +945,4 @@ void ClusterFamily::Register(CommandRegistry* registry) {
DflyMigrate); DflyMigrate);
} }
} // namespace dfly } // namespace dfly::cluster

View file

@ -15,9 +15,12 @@
#include "server/common.h" #include "server/common.h"
namespace dfly { namespace dfly {
class ServerFamily;
class CommandRegistry; class CommandRegistry;
class ConnectionContext; class ConnectionContext;
class ServerFamily; } // namespace dfly
namespace dfly::cluster {
class ClusterFamily { class ClusterFamily {
public: public:
@ -105,4 +108,4 @@ class ClusterFamily {
ServerFamily* server_family_ = nullptr; ServerFamily* server_family_ = nullptr;
}; };
} // namespace dfly } // namespace dfly::cluster

View file

@ -18,7 +18,7 @@
#include "facade/facade_test.h" #include "facade/facade_test.h"
#include "server/test_utils.h" #include "server/test_utils.h"
namespace dfly { namespace dfly::cluster {
namespace { namespace {
using namespace std; using namespace std;
@ -395,7 +395,7 @@ TEST_F(ClusterFamilyTest, ClusterConfigFullMultipleInstances) {
absl::InsecureBitGen eng; absl::InsecureBitGen eng;
while (true) { while (true) {
string random_key = GetRandomHex(eng, 40); string random_key = GetRandomHex(eng, 40);
SlotId slot = ClusterConfig::KeySlot(random_key); SlotId slot = KeySlot(random_key);
if (slot > 10'000) { if (slot > 10'000) {
continue; continue;
} }
@ -407,7 +407,7 @@ TEST_F(ClusterFamilyTest, ClusterConfigFullMultipleInstances) {
while (true) { while (true) {
string random_key = GetRandomHex(eng, 40); string random_key = GetRandomHex(eng, 40);
SlotId slot = ClusterConfig::KeySlot(random_key); SlotId slot = KeySlot(random_key);
if (slot <= 10'000) { if (slot <= 10'000) {
continue; continue;
} }
@ -429,7 +429,7 @@ TEST_F(ClusterFamilyTest, ClusterGetSlotInfo) {
ConfigSingleNodeCluster(GetMyId()); ConfigSingleNodeCluster(GetMyId());
constexpr string_view kKey = "some-key"; constexpr string_view kKey = "some-key";
const SlotId slot = ClusterConfig::KeySlot(kKey); const SlotId slot = KeySlot(kKey);
EXPECT_NE(slot, 0) << "We need to choose another key"; EXPECT_NE(slot, 0) << "We need to choose another key";
const string value(1'000, '#'); // Long string - to use heap const string value(1'000, '#'); // Long string - to use heap
@ -740,4 +740,4 @@ TEST_F(ClusterFamilyEmulatedTest, ClusterNodes) {
} }
} // namespace } // namespace
} // namespace dfly } // namespace dfly::cluster

View file

@ -11,7 +11,7 @@
#include "server/journal/tx_executor.h" #include "server/journal/tx_executor.h"
#include "server/main_service.h" #include "server/main_service.h"
namespace dfly { namespace dfly::cluster {
using namespace std; using namespace std;
using namespace util; using namespace util;
@ -140,4 +140,4 @@ void IncomingSlotMigration::StartFlow(uint32_t shard, util::FiberSocketBase* sou
shard_flows_[shard]->Start(&cntx_, source, bc_); shard_flows_[shard]->Start(&cntx_, source, bc_);
} }
} // namespace dfly } // namespace dfly::cluster

View file

@ -5,12 +5,15 @@
#include "helio/io/io.h" #include "helio/io/io.h"
#include "helio/util/fiber_socket_base.h" #include "helio/util/fiber_socket_base.h"
#include "server/cluster/cluster_config.h" #include "server/cluster/cluster_defs.h"
#include "server/common.h"
namespace dfly { namespace dfly {
class ClusterShardMigration;
class Service; class Service;
}
namespace dfly::cluster {
class ClusterShardMigration;
// The main entity on the target side that manage slots migration process // The main entity on the target side that manage slots migration process
// Manage connections between the target and source node, // Manage connections between the target and source node,
@ -55,4 +58,4 @@ class IncomingSlotMigration {
util::fb2::BlockingCounter bc_; util::fb2::BlockingCounter bc_;
}; };
} // namespace dfly } // namespace dfly::cluster

View file

@ -23,7 +23,7 @@ using namespace std;
using namespace facade; using namespace facade;
using namespace util; using namespace util;
namespace dfly { namespace dfly::cluster {
class OutgoingMigration::SliceSlotMigration : private ProtocolClient { class OutgoingMigration::SliceSlotMigration : private ProtocolClient {
public: public:
@ -221,4 +221,4 @@ std::error_code OutgoingMigration::Start(ConnectionContext* cntx) {
return {}; return {};
} }
} // namespace dfly } // namespace dfly::cluster

View file

@ -4,18 +4,18 @@
#pragma once #pragma once
#include "io/io.h" #include "io/io.h"
#include "server/cluster/cluster_config.h" #include "server/cluster/cluster_defs.h"
#include "server/common.h"
#include "server/protocol_client.h" #include "server/protocol_client.h"
namespace dfly { namespace dfly {
class DbSlice;
class ServerFamily;
namespace journal { namespace journal {
class Journal; class Journal;
} }
} // namespace dfly
class DbSlice; namespace dfly::cluster {
class ServerFamily;
class ClusterFamily; class ClusterFamily;
// Whole outgoing slots migration manager // Whole outgoing slots migration manager
@ -76,4 +76,4 @@ class OutgoingMigration : private ProtocolClient {
std::atomic<MigrationState> state_ = MigrationState::C_NO_STATE; std::atomic<MigrationState> state_ = MigrationState::C_NO_STATE;
}; };
} // namespace dfly } // namespace dfly::cluster

View file

@ -6,40 +6,11 @@
#include <bitset> #include <bitset>
#include <memory> #include <memory>
#include <string>
#include <vector> #include <vector>
#include "absl/strings/str_cat.h" #include "cluster_defs.h"
#include "absl/strings/str_join.h"
namespace dfly { namespace dfly::cluster {
using SlotId = uint16_t;
struct SlotRange {
static constexpr SlotId kMaxSlotId = 0x3FFF;
SlotId start = 0;
SlotId end = 0;
bool operator==(const SlotRange& r) const {
return start == r.start && end == r.end;
}
bool IsValid() {
return start <= end && start <= kMaxSlotId && end <= kMaxSlotId;
}
std::string ToString() const {
return absl::StrCat("[", start, ", ", end, "]");
}
static std::string ToString(const std::vector<SlotRange>& ranges) {
return absl::StrJoin(ranges, ", ", [](std::string* out, SlotRange range) {
absl::StrAppend(out, range.ToString());
});
}
};
using SlotRanges = std::vector<SlotRange>;
class SlotSet { class SlotSet {
public: public:
@ -117,4 +88,4 @@ class SlotSet {
std::unique_ptr<TBitSet> slots_{std::make_unique<TBitSet>()}; std::unique_ptr<TBitSet> slots_{std::make_unique<TBitSet>()};
}; };
} // namespace dfly } // namespace dfly::cluster

View file

@ -1,21 +1,21 @@
#include "server/cluster/unique_slot_checker.h" #include "server/cluster/unique_slot_checker.h"
#include "server/cluster/cluster_config.h" #include "server/cluster/cluster_defs.h"
using namespace std; using namespace std;
namespace dfly { namespace dfly::cluster {
void UniqueSlotChecker::Add(std::string_view key) { void UniqueSlotChecker::Add(std::string_view key) {
if (!ClusterConfig::IsEnabled()) { if (!IsClusterEnabled()) {
return; return;
} }
Add(ClusterConfig::KeySlot(key)); Add(KeySlot(key));
} }
void UniqueSlotChecker::Add(SlotId slot_id) { void UniqueSlotChecker::Add(SlotId slot_id) {
if (!ClusterConfig::IsEnabled()) { if (!IsClusterEnabled()) {
return; return;
} }
@ -25,16 +25,16 @@ void UniqueSlotChecker::Add(SlotId slot_id) {
} }
if (*slot_id_ != slot_id) { if (*slot_id_ != slot_id) {
slot_id_ = ClusterConfig::kInvalidSlotId; slot_id_ = kInvalidSlotId;
} }
} }
optional<SlotId> UniqueSlotChecker::GetUniqueSlotId() const { optional<SlotId> UniqueSlotChecker::GetUniqueSlotId() const {
if (slot_id_.has_value() && *slot_id_ == ClusterConfig::kInvalidSlotId) { if (slot_id_.has_value() && *slot_id_ == kInvalidSlotId) {
return nullopt; return nullopt;
} }
return slot_id_; return slot_id_;
} }
} // namespace dfly } // namespace dfly::cluster

View file

@ -7,9 +7,9 @@
#include <optional> #include <optional>
#include <string_view> #include <string_view>
#include "server/cluster/slot_set.h" #include "server/cluster/cluster_defs.h"
namespace dfly { namespace dfly::cluster {
// A simple utility class that "aggregates" SlotId-s and can tell whether all inputs were the same. // A simple utility class that "aggregates" SlotId-s and can tell whether all inputs were the same.
// Only works when cluster is enabled. // Only works when cluster is enabled.
@ -24,4 +24,4 @@ class UniqueSlotChecker {
std::optional<SlotId> slot_id_; std::optional<SlotId> slot_id_;
}; };
} // namespace dfly } // namespace dfly::cluster

View file

@ -18,7 +18,7 @@ extern "C" {
#include "base/flags.h" #include "base/flags.h"
#include "base/logging.h" #include "base/logging.h"
#include "core/compact_object.h" #include "core/compact_object.h"
#include "server/cluster/cluster_config.h" #include "server/cluster/cluster_defs.h"
#include "server/engine_shard_set.h" #include "server/engine_shard_set.h"
#include "server/error.h" #include "server/error.h"
#include "server/journal/journal.h" #include "server/journal/journal.h"
@ -269,7 +269,7 @@ void RecordJournalFinish(const OpArgs& op_args, uint32_t shard_cnt) {
void RecordExpiry(DbIndex dbid, string_view key) { void RecordExpiry(DbIndex dbid, string_view key) {
auto journal = EngineShard::tlocal()->journal(); auto journal = EngineShard::tlocal()->journal();
CHECK(journal); CHECK(journal);
journal->RecordEntry(0, journal::Op::EXPIRED, dbid, 1, ClusterConfig::KeySlot(key), journal->RecordEntry(0, journal::Op::EXPIRED, dbid, 1, cluster::KeySlot(key),
make_pair("DEL", ArgSlice{key}), false); make_pair("DEL", ArgSlice{key}), false);
} }

View file

@ -9,7 +9,7 @@
#include "base/flags.h" #include "base/flags.h"
#include "base/logging.h" #include "base/logging.h"
#include "generic_family.h" #include "generic_family.h"
#include "server/cluster/cluster_config.h" #include "server/cluster/cluster_defs.h"
#include "server/engine_shard_set.h" #include "server/engine_shard_set.h"
#include "server/error.h" #include "server/error.h"
#include "server/journal/journal.h" #include "server/journal/journal.h"
@ -60,8 +60,8 @@ void AccountObjectMemory(string_view key, unsigned type, int64_t size, DbTable*
stats.AddTypeMemoryUsage(type, size); stats.AddTypeMemoryUsage(type, size);
if (ClusterConfig::IsEnabled()) { if (cluster::IsClusterEnabled()) {
db->slots_stats[ClusterConfig::KeySlot(key)].memory_bytes += size; db->slots_stats[cluster::KeySlot(key)].memory_bytes += size;
} }
} }
@ -204,7 +204,7 @@ unsigned PrimeEvictionPolicy::Evict(const PrimeTable::HotspotBuckets& eb, PrimeT
// log the evicted keys to journal. // log the evicted keys to journal.
if (auto journal = db_slice_->shard_owner()->journal(); journal) { if (auto journal = db_slice_->shard_owner()->journal(); journal) {
ArgSlice delete_args(&key, 1); ArgSlice delete_args(&key, 1);
journal->RecordEntry(0, journal::Op::EXPIRED, cntx_.db_index, 1, ClusterConfig::KeySlot(key), journal->RecordEntry(0, journal::Op::EXPIRED, cntx_.db_index, 1, cluster::KeySlot(key),
make_pair("DEL", delete_args), false); make_pair("DEL", delete_args), false);
} }
@ -301,7 +301,7 @@ auto DbSlice::GetStats() const -> Stats {
return s; return s;
} }
SlotStats DbSlice::GetSlotStats(SlotId sid) const { SlotStats DbSlice::GetSlotStats(cluster::SlotId sid) const {
CHECK(db_arr_[0]); CHECK(db_arr_[0]);
return db_arr_[0]->slots_stats[sid]; return db_arr_[0]->slots_stats[sid];
} }
@ -528,8 +528,8 @@ OpResult<DbSlice::PrimeItAndExp> DbSlice::FindInternal(const Context& cntx, std:
break; break;
case UpdateStatsMode::kReadStats: case UpdateStatsMode::kReadStats:
events_.hits++; events_.hits++;
if (ClusterConfig::IsEnabled()) { if (cluster::IsClusterEnabled()) {
db.slots_stats[ClusterConfig::KeySlot(key)].total_reads++; db.slots_stats[cluster::KeySlot(key)].total_reads++;
} }
break; break;
} }
@ -661,8 +661,8 @@ OpResult<DbSlice::AddOrFindResult> DbSlice::AddOrFindInternal(const Context& cnt
events_.garbage_checked += evp.checked(); events_.garbage_checked += evp.checked();
memory_budget_ = evp.mem_budget() + evicted_obj_bytes; memory_budget_ = evp.mem_budget() + evicted_obj_bytes;
if (ClusterConfig::IsEnabled()) { if (cluster::IsClusterEnabled()) {
SlotId sid = ClusterConfig::KeySlot(key); cluster::SlotId sid = cluster::KeySlot(key);
db.slots_stats[sid].key_count += 1; db.slots_stats[sid].key_count += 1;
} }
@ -703,7 +703,7 @@ bool DbSlice::Del(DbIndex db_ind, Iterator it) {
return true; return true;
} }
void DbSlice::FlushSlotsFb(const SlotSet& slot_ids) { void DbSlice::FlushSlotsFb(const cluster::SlotSet& slot_ids) {
// Slot deletion can take time as it traverses all the database, hence it runs in fiber. // Slot deletion can take time as it traverses all the database, hence it runs in fiber.
// We want to flush all the data of a slot that was added till the time the call to FlushSlotsFb // We want to flush all the data of a slot that was added till the time the call to FlushSlotsFb
// was made. Therefore we delete slots entries with version < next_version // was made. Therefore we delete slots entries with version < next_version
@ -712,7 +712,7 @@ void DbSlice::FlushSlotsFb(const SlotSet& slot_ids) {
std::string tmp; std::string tmp;
auto del_entry_cb = [&](PrimeTable::iterator it) { auto del_entry_cb = [&](PrimeTable::iterator it) {
std::string_view key = it->first.GetSlice(&tmp); std::string_view key = it->first.GetSlice(&tmp);
SlotId sid = ClusterConfig::KeySlot(key); cluster::SlotId sid = cluster::KeySlot(key);
if (slot_ids.Contains(sid) && it.GetVersion() < next_version) { if (slot_ids.Contains(sid) && it.GetVersion() < next_version) {
PerformDeletion(Iterator::FromPrime(it), db_arr_[0].get()); PerformDeletion(Iterator::FromPrime(it), db_arr_[0].get());
} }
@ -765,8 +765,8 @@ void DbSlice::FlushSlotsFb(const SlotSet& slot_ids) {
etl.DecommitMemory(ServerState::kDataHeap); etl.DecommitMemory(ServerState::kDataHeap);
} }
void DbSlice::FlushSlots(SlotRanges slot_ranges) { void DbSlice::FlushSlots(cluster::SlotRanges slot_ranges) {
SlotSet slot_set(slot_ranges); cluster::SlotSet slot_set(slot_ranges);
InvalidateSlotWatches(slot_set); InvalidateSlotWatches(slot_set);
fb2::Fiber("flush_slots", [this, slot_set = std::move(slot_set)]() mutable { fb2::Fiber("flush_slots", [this, slot_set = std::move(slot_set)]() mutable {
FlushSlotsFb(slot_set); FlushSlotsFb(slot_set);
@ -1075,8 +1075,8 @@ void DbSlice::PostUpdate(DbIndex db_ind, Iterator it, std::string_view key, size
++events_.update; ++events_.update;
if (ClusterConfig::IsEnabled()) { if (cluster::IsClusterEnabled()) {
db.slots_stats[ClusterConfig::KeySlot(key)].total_writes += 1; db.slots_stats[cluster::KeySlot(key)].total_writes += 1;
} }
SendInvalidationTrackingMessage(key); SendInvalidationTrackingMessage(key);
@ -1333,7 +1333,7 @@ finish:
if (auto journal = owner_->journal(); journal) { if (auto journal = owner_->journal(); journal) {
for (string_view key : keys_to_journal) { for (string_view key : keys_to_journal) {
ArgSlice delete_args(&key, 1); ArgSlice delete_args(&key, 1);
journal->RecordEntry(0, journal::Op::EXPIRED, db_ind, 1, ClusterConfig::KeySlot(key), journal->RecordEntry(0, journal::Op::EXPIRED, db_ind, 1, cluster::KeySlot(key),
make_pair("DEL", delete_args), false); make_pair("DEL", delete_args), false);
} }
} }
@ -1466,9 +1466,9 @@ void DbSlice::InvalidateDbWatches(DbIndex db_indx) {
} }
} }
void DbSlice::InvalidateSlotWatches(const SlotSet& slot_ids) { void DbSlice::InvalidateSlotWatches(const cluster::SlotSet& slot_ids) {
for (const auto& [key, conn_list] : db_arr_[0]->watched_keys) { for (const auto& [key, conn_list] : db_arr_[0]->watched_keys) {
SlotId sid = ClusterConfig::KeySlot(key); cluster::SlotId sid = cluster::KeySlot(key);
if (!slot_ids.Contains(sid)) { if (!slot_ids.Contains(sid)) {
continue; continue;
} }
@ -1583,8 +1583,8 @@ void DbSlice::PerformDeletion(Iterator del_it, ExpIterator exp_it, DbTable* tabl
--stats.listpack_blob_cnt; --stats.listpack_blob_cnt;
} }
if (ClusterConfig::IsEnabled()) { if (cluster::IsClusterEnabled()) {
SlotId sid = ClusterConfig::KeySlot(del_it.key()); cluster::SlotId sid = cluster::KeySlot(del_it.key());
table->slots_stats[sid].key_count -= 1; table->slots_stats[sid].key_count -= 1;
} }

View file

@ -229,7 +229,7 @@ class DbSlice {
Stats GetStats() const; Stats GetStats() const;
// Returns slot statistics for db 0. // Returns slot statistics for db 0.
SlotStats GetSlotStats(SlotId sid) const; SlotStats GetSlotStats(cluster::SlotId sid) const;
void UpdateExpireBase(uint64_t now, unsigned generation) { void UpdateExpireBase(uint64_t now, unsigned generation) {
expire_base_[generation & 1] = now; expire_base_[generation & 1] = now;
@ -349,7 +349,7 @@ class DbSlice {
void FlushDb(DbIndex db_ind); void FlushDb(DbIndex db_ind);
// Flushes the data of given slot ranges. // Flushes the data of given slot ranges.
void FlushSlots(SlotRanges slot_ranges); void FlushSlots(cluster::SlotRanges slot_ranges);
EngineShard* shard_owner() const { EngineShard* shard_owner() const {
return owner_; return owner_;
@ -487,14 +487,14 @@ class DbSlice {
PrimeValue obj, uint64_t expire_at_ms, PrimeValue obj, uint64_t expire_at_ms,
bool force_update); bool force_update);
void FlushSlotsFb(const SlotSet& slot_ids); void FlushSlotsFb(const cluster::SlotSet& slot_ids);
void FlushDbIndexes(const std::vector<DbIndex>& indexes); void FlushDbIndexes(const std::vector<DbIndex>& indexes);
// Invalidate all watched keys in database. Used on FLUSH. // Invalidate all watched keys in database. Used on FLUSH.
void InvalidateDbWatches(DbIndex db_indx); void InvalidateDbWatches(DbIndex db_indx);
// Invalidate all watched keys for given slots. Used on FlushSlots. // Invalidate all watched keys for given slots. Used on FlushSlots.
void InvalidateSlotWatches(const SlotSet& slot_ids); void InvalidateSlotWatches(const cluster::SlotSet& slot_ids);
void PerformDeletion(Iterator del_it, ExpIterator exp_it, DbTable* table); void PerformDeletion(Iterator del_it, ExpIterator exp_it, DbTable* table);

View file

@ -627,7 +627,7 @@ optional<DebugCmd::PopulateOptions> DebugCmd::ParsePopulateArgs(CmdArgList args)
if (!absl::SimpleAtoi(slot_str, &slot_id)) { if (!absl::SimpleAtoi(slot_str, &slot_id)) {
return facade::OpStatus::INVALID_INT; return facade::OpStatus::INVALID_INT;
} }
if (slot_id > ClusterConfig::kMaxSlotNum) { if (slot_id > cluster::kMaxSlotNum) {
return facade::OpStatus::INVALID_VALUE; return facade::OpStatus::INVALID_VALUE;
} }
return slot_id; return slot_id;
@ -643,8 +643,8 @@ optional<DebugCmd::PopulateOptions> DebugCmd::ParsePopulateArgs(CmdArgList args)
cntx_->SendError(end.status()); cntx_->SendError(end.status());
return nullopt; return nullopt;
} }
options.slot_range = SlotRange{.start = static_cast<SlotId>(start.value()), options.slot_range = cluster::SlotRange{.start = static_cast<cluster::SlotId>(start.value()),
.end = static_cast<SlotId>(end.value())}; .end = static_cast<cluster::SlotId>(end.value())};
} else { } else {
cntx_->SendError(kSyntaxErr); cntx_->SendError(kSyntaxErr);
@ -716,7 +716,7 @@ void DebugCmd::PopulateRangeFiber(uint64_t from, uint64_t num_of_keys,
// <key_prefix>:<from+total_count+num_of_keys-1> and continue until num_of_keys are added. // <key_prefix>:<from+total_count+num_of_keys-1> and continue until num_of_keys are added.
// Add keys only in slot range. // Add keys only in slot range.
SlotId sid = ClusterConfig::KeySlot(key); cluster::SlotId sid = cluster::KeySlot(key);
if (sid < options.slot_range->start || sid > options.slot_range->end) { if (sid < options.slot_range->start || sid > options.slot_range->end) {
++index; ++index;
continue; continue;

View file

@ -4,7 +4,7 @@
#pragma once #pragma once
#include "server/cluster/slot_set.h" #include "server/cluster/cluster_defs.h"
#include "server/conn_context.h" #include "server/conn_context.h"
namespace dfly { namespace dfly {
@ -22,7 +22,7 @@ class DebugCmd {
std::string_view type{"STRING"}; std::string_view type{"STRING"};
uint32_t elements = 1; uint32_t elements = 1;
std::optional<SlotRange> slot_range; std::optional<cluster::SlotRange> slot_range;
}; };
public: public:

View file

@ -17,7 +17,7 @@ extern "C" {
#include "base/logging.h" #include "base/logging.h"
#include "io/proc_reader.h" #include "io/proc_reader.h"
#include "server/blocking_controller.h" #include "server/blocking_controller.h"
#include "server/cluster/cluster_config.h" #include "server/cluster/cluster_defs.h"
#include "server/search/doc_index.h" #include "server/search/doc_index.h"
#include "server/server_state.h" #include "server/server_state.h"
#include "server/tiered_storage.h" #include "server/tiered_storage.h"
@ -865,7 +865,7 @@ void EngineShardSet::TEST_EnableCacheMode() {
} }
ShardId Shard(string_view v, ShardId shard_num) { ShardId Shard(string_view v, ShardId shard_num) {
if (ClusterConfig::IsShardedByTag()) { if (cluster::IsClusterShardedByTag()) {
v = LockTagOptions::instance().Tag(v); v = LockTagOptions::instance().Tag(v);
} }

View file

@ -18,7 +18,7 @@ extern "C" {
#include "redis/rdb.h" #include "redis/rdb.h"
#include "server/acl/acl_commands_def.h" #include "server/acl/acl_commands_def.h"
#include "server/blocking_controller.h" #include "server/blocking_controller.h"
#include "server/cluster/cluster_config.h" #include "server/cluster/cluster_defs.h"
#include "server/command_registry.h" #include "server/command_registry.h"
#include "server/conn_context.h" #include "server/conn_context.h"
#include "server/container_utils.h" #include "server/container_utils.h"
@ -1231,7 +1231,7 @@ void GenericFamily::Select(CmdArgList args, ConnectionContext* cntx) {
if (!absl::SimpleAtoi(key, &index)) { if (!absl::SimpleAtoi(key, &index)) {
return cntx->SendError(kInvalidDbIndErr); return cntx->SendError(kInvalidDbIndErr);
} }
if (ClusterConfig::IsEnabled() && index != 0) { if (cluster::IsClusterEnabled() && index != 0) {
return cntx->SendError("SELECT is not allowed in cluster mode"); return cntx->SendError("SELECT is not allowed in cluster mode");
} }
if (index < 0 || index >= absl::GetFlag(FLAGS_dbnum)) { if (index < 0 || index >= absl::GetFlag(FLAGS_dbnum)) {

View file

@ -67,7 +67,7 @@ void JournalExecutor::FlushAll() {
Execute(cmd); Execute(cmd);
} }
void JournalExecutor::FlushSlots(const SlotRange& slot_range) { void JournalExecutor::FlushSlots(const cluster::SlotRange& slot_range) {
auto cmd = BuildFromParts("DFLYCLUSTER", "FLUSHSLOTS", slot_range.start, slot_range.end); auto cmd = BuildFromParts("DFLYCLUSTER", "FLUSHSLOTS", slot_range.start, slot_range.end);
Execute(cmd); Execute(cmd);
} }

View file

@ -7,7 +7,7 @@
#include <absl/types/span.h> #include <absl/types/span.h>
#include "facade/reply_capture.h" #include "facade/reply_capture.h"
#include "server/cluster/slot_set.h" #include "server/cluster/cluster_defs.h"
#include "server/journal/types.h" #include "server/journal/types.h"
namespace dfly { namespace dfly {
@ -26,7 +26,7 @@ class JournalExecutor {
void Execute(DbIndex dbid, journal::ParsedEntry::CmdData& cmd); void Execute(DbIndex dbid, journal::ParsedEntry::CmdData& cmd);
void FlushAll(); // Execute FLUSHALL. void FlushAll(); // Execute FLUSHALL.
void FlushSlots(const SlotRange& slot_range); void FlushSlots(const cluster::SlotRange& slot_range);
ConnectionContext* connection_context() { ConnectionContext* connection_context() {
return &conn_context_; return &conn_context_;

View file

@ -84,7 +84,7 @@ LSN Journal::GetLsn() const {
} }
void Journal::RecordEntry(TxId txid, Op opcode, DbIndex dbid, unsigned shard_cnt, void Journal::RecordEntry(TxId txid, Op opcode, DbIndex dbid, unsigned shard_cnt,
std::optional<SlotId> slot, Entry::Payload payload, bool await) { std::optional<cluster::SlotId> slot, Entry::Payload payload, bool await) {
journal_slice.AddLogRecord(Entry{txid, opcode, dbid, shard_cnt, slot, std::move(payload)}, await); journal_slice.AddLogRecord(Entry{txid, opcode, dbid, shard_cnt, slot, std::move(payload)}, await);
} }

View file

@ -35,7 +35,7 @@ class Journal {
LSN GetLsn() const; LSN GetLsn() const;
void RecordEntry(TxId txid, Op opcode, DbIndex dbid, unsigned shard_cnt, void RecordEntry(TxId txid, Op opcode, DbIndex dbid, unsigned shard_cnt,
std::optional<SlotId> slot, Entry::Payload payload, bool await); std::optional<cluster::SlotId> slot, Entry::Payload payload, bool await);
private: private:
mutable util::fb2::Mutex state_mu_; mutable util::fb2::Mutex state_mu_;

View file

@ -7,7 +7,7 @@
#include <absl/functional/bind_front.h> #include <absl/functional/bind_front.h>
#include "base/logging.h" #include "base/logging.h"
#include "server/cluster/cluster_config.h" #include "server/cluster/cluster_defs.h"
namespace dfly { namespace dfly {
using namespace util; using namespace util;
@ -60,7 +60,7 @@ void JournalStreamer::WriterFb(io::Sink* dest) {
} }
} }
RestoreStreamer::RestoreStreamer(DbSlice* slice, SlotSet slots, journal::Journal* journal, RestoreStreamer::RestoreStreamer(DbSlice* slice, cluster::SlotSet slots, journal::Journal* journal,
Context* cntx) Context* cntx)
: JournalStreamer(journal, cntx), db_slice_(slice), my_slots_(std::move(slots)) { : JournalStreamer(journal, cntx), db_slice_(slice), my_slots_(std::move(slots)) {
DCHECK(slice != nullptr); DCHECK(slice != nullptr);
@ -130,10 +130,10 @@ bool RestoreStreamer::ShouldWrite(const journal::JournalItem& item) const {
} }
bool RestoreStreamer::ShouldWrite(std::string_view key) const { bool RestoreStreamer::ShouldWrite(std::string_view key) const {
return ShouldWrite(ClusterConfig::KeySlot(key)); return ShouldWrite(cluster::KeySlot(key));
} }
bool RestoreStreamer::ShouldWrite(SlotId slot_id) const { bool RestoreStreamer::ShouldWrite(cluster::SlotId slot_id) const {
return my_slots_.Contains(slot_id); return my_slots_.Contains(slot_id);
} }

View file

@ -53,7 +53,7 @@ class JournalStreamer : protected BufferedStreamerBase {
// Only handles relevant slots, while ignoring all others. // Only handles relevant slots, while ignoring all others.
class RestoreStreamer : public JournalStreamer { class RestoreStreamer : public JournalStreamer {
public: public:
RestoreStreamer(DbSlice* slice, SlotSet slots, journal::Journal* journal, Context* cntx); RestoreStreamer(DbSlice* slice, cluster::SlotSet slots, journal::Journal* journal, Context* cntx);
~RestoreStreamer() override; ~RestoreStreamer() override;
void Start(io::Sink* dest, bool send_lsn = false) override; void Start(io::Sink* dest, bool send_lsn = false) override;
@ -70,7 +70,7 @@ class RestoreStreamer : public JournalStreamer {
void OnDbChange(DbIndex db_index, const DbSlice::ChangeReq& req); void OnDbChange(DbIndex db_index, const DbSlice::ChangeReq& req);
bool ShouldWrite(const journal::JournalItem& item) const override; bool ShouldWrite(const journal::JournalItem& item) const override;
bool ShouldWrite(std::string_view key) const; bool ShouldWrite(std::string_view key) const;
bool ShouldWrite(SlotId slot_id) const; bool ShouldWrite(cluster::SlotId slot_id) const;
// Returns whether anything was written // Returns whether anything was written
bool WriteBucket(PrimeTable::bucket_iterator it); bool WriteBucket(PrimeTable::bucket_iterator it);
@ -79,7 +79,7 @@ class RestoreStreamer : public JournalStreamer {
DbSlice* db_slice_; DbSlice* db_slice_;
uint64_t snapshot_version_ = 0; uint64_t snapshot_version_ = 0;
SlotSet my_slots_; cluster::SlotSet my_slots_;
Cancellation fiber_cancellation_; Cancellation fiber_cancellation_;
bool snapshot_finished_ = false; bool snapshot_finished_ = false;
}; };

View file

@ -4,7 +4,7 @@
#include "server/journal/types.h" #include "server/journal/types.h"
#include "server/cluster/cluster_config.h" #include "server/cluster/cluster_defs.h"
namespace dfly::journal { namespace dfly::journal {

View file

@ -7,7 +7,7 @@
#include <string> #include <string>
#include <variant> #include <variant>
#include "server/cluster/slot_set.h" #include "server/cluster/cluster_defs.h"
#include "server/common.h" #include "server/common.h"
#include "server/table.h" #include "server/table.h"
@ -31,7 +31,7 @@ struct EntryBase {
Op opcode; Op opcode;
DbIndex dbid; DbIndex dbid;
uint32_t shard_cnt; uint32_t shard_cnt;
std::optional<SlotId> slot; std::optional<cluster::SlotId> slot;
LSN lsn{0}; LSN lsn{0};
}; };
@ -45,12 +45,12 @@ struct Entry : public EntryBase {
std::pair<std::string_view, ArgSlice> // Command and its shard parts. std::pair<std::string_view, ArgSlice> // Command and its shard parts.
>; >;
Entry(TxId txid, Op opcode, DbIndex dbid, uint32_t shard_cnt, std::optional<SlotId> slot_id, Entry(TxId txid, Op opcode, DbIndex dbid, uint32_t shard_cnt,
Payload pl) std::optional<cluster::SlotId> slot_id, Payload pl)
: EntryBase{txid, opcode, dbid, shard_cnt, slot_id}, payload{pl} { : EntryBase{txid, opcode, dbid, shard_cnt, slot_id}, payload{pl} {
} }
Entry(journal::Op opcode, DbIndex dbid, std::optional<SlotId> slot_id) Entry(journal::Op opcode, DbIndex dbid, std::optional<cluster::SlotId> slot_id)
: EntryBase{0, opcode, dbid, 0, slot_id, 0} { : EntryBase{0, opcode, dbid, 0, slot_id, 0} {
} }
@ -58,7 +58,7 @@ struct Entry : public EntryBase {
} }
Entry(TxId txid, journal::Op opcode, DbIndex dbid, uint32_t shard_cnt, Entry(TxId txid, journal::Op opcode, DbIndex dbid, uint32_t shard_cnt,
std::optional<SlotId> slot_id) std::optional<cluster::SlotId> slot_id)
: EntryBase{txid, opcode, dbid, shard_cnt, slot_id, 0} { : EntryBase{txid, opcode, dbid, shard_cnt, slot_id, 0} {
} }
@ -85,7 +85,7 @@ struct JournalItem {
LSN lsn; LSN lsn;
Op opcode; Op opcode;
std::string data; std::string data;
std::optional<SlotId> slot; std::optional<cluster::SlotId> slot;
}; };
using ChangeCallback = std::function<void(const JournalItem&, bool await)>; using ChangeCallback = std::function<void(const JournalItem&, bool await)>;

View file

@ -575,7 +575,8 @@ void TxTable(const http::QueryArgs& args, HttpContext* send) {
send->Invoke(std::move(resp)); send->Invoke(std::move(resp));
} }
void ClusterHtmlPage(const http::QueryArgs& args, HttpContext* send, ClusterFamily* cluster) { void ClusterHtmlPage(const http::QueryArgs& args, HttpContext* send,
cluster::ClusterFamily* cluster_family) {
http::StringResponse resp = http::MakeStringResponse(h2::status::ok); http::StringResponse resp = http::MakeStringResponse(h2::status::ok);
resp.body() = R"( resp.body() = R"(
<html> <html>
@ -616,19 +617,19 @@ void ClusterHtmlPage(const http::QueryArgs& args, HttpContext* send, ClusterFami
auto print_kb = [&](string_view k, bool v) { print_kv(k, v ? "True" : "False"); }; auto print_kb = [&](string_view k, bool v) { print_kv(k, v ? "True" : "False"); };
print_kv("Mode", ClusterConfig::IsEmulated() ? "Emulated" print_kv("Mode", cluster::IsClusterEmulated() ? "Emulated"
: ClusterConfig::IsEnabled() ? "Enabled" : cluster::IsClusterEnabled() ? "Enabled"
: "Disabled"); : "Disabled");
if (ClusterConfig::IsEnabledOrEmulated()) { if (cluster::IsClusterEnabledOrEmulated()) {
print_kb("Lock on hashtags", LockTagOptions::instance().enabled); print_kb("Lock on hashtags", LockTagOptions::instance().enabled);
} }
if (ClusterConfig::IsEnabled()) { if (cluster::IsClusterEnabled()) {
if (cluster->cluster_config() == nullptr) { if (cluster_family->cluster_config() == nullptr) {
resp.body() += "<h2>Not yet configured.</h2>\n"; resp.body() += "<h2>Not yet configured.</h2>\n";
} else { } else {
auto config = cluster->cluster_config()->GetConfig(); auto config = cluster_family->cluster_config()->GetConfig();
for (const auto& shard : config) { for (const auto& shard : config) {
resp.body() += "<div class='master'>\n"; resp.body() += "<div class='master'>\n";
resp.body() += "<h3>Master</h3>\n"; resp.body() += "<h3>Master</h3>\n";
@ -922,12 +923,12 @@ optional<ErrorReply> Service::CheckKeysOwnership(const CommandId* cid, CmdArgLis
} }
const auto& key_index = *key_index_res; const auto& key_index = *key_index_res;
optional<SlotId> keys_slot; optional<cluster::SlotId> keys_slot;
bool cross_slot = false; bool cross_slot = false;
// Iterate keys and check to which slot they belong. // Iterate keys and check to which slot they belong.
for (unsigned i = key_index.start; i < key_index.end; i += key_index.step) { for (unsigned i = key_index.start; i < key_index.end; i += key_index.step) {
string_view key = ArgS(args, i); string_view key = ArgS(args, i);
SlotId slot = ClusterConfig::KeySlot(key); cluster::SlotId slot = cluster::KeySlot(key);
if (keys_slot && slot != *keys_slot) { if (keys_slot && slot != *keys_slot) {
cross_slot = true; // keys belong to different slots cross_slot = true; // keys belong to different slots
break; break;
@ -941,14 +942,14 @@ optional<ErrorReply> Service::CheckKeysOwnership(const CommandId* cid, CmdArgLis
} }
// Check keys slot is in my ownership // Check keys slot is in my ownership
const ClusterConfig* cluster_config = cluster_family_.cluster_config(); const cluster::ClusterConfig* cluster_config = cluster_family_.cluster_config();
if (cluster_config == nullptr) { if (cluster_config == nullptr) {
return ErrorReply{kClusterNotConfigured}; return ErrorReply{kClusterNotConfigured};
} }
if (keys_slot.has_value() && !cluster_config->IsMySlot(*keys_slot)) { if (keys_slot.has_value() && !cluster_config->IsMySlot(*keys_slot)) {
// See more details here: https://redis.io/docs/reference/cluster-spec/#moved-redirection // See more details here: https://redis.io/docs/reference/cluster-spec/#moved-redirection
ClusterNodeInfo master = cluster_config->GetMasterNodeForSlot(*keys_slot); cluster::ClusterNodeInfo master = cluster_config->GetMasterNodeForSlot(*keys_slot);
return ErrorReply{absl::StrCat("-MOVED ", *keys_slot, " ", master.ip, ":", master.port)}; return ErrorReply{absl::StrCat("-MOVED ", *keys_slot, " ", master.ip, ":", master.port)};
} }
@ -1094,7 +1095,7 @@ std::optional<ErrorReply> Service::VerifyCommandState(const CommandId* cid, CmdA
return ErrorReply{absl::StrCat("'", cmd_name, "' inside MULTI is not allowed")}; return ErrorReply{absl::StrCat("'", cmd_name, "' inside MULTI is not allowed")};
} }
if (ClusterConfig::IsEnabled()) { if (cluster::IsClusterEnabled()) {
if (auto err = CheckKeysOwnership(cid, tail_args, dfly_cntx); err) if (auto err = CheckKeysOwnership(cid, tail_args, dfly_cntx); err)
return err; return err;
} }
@ -1897,7 +1898,7 @@ void Service::EvalInternal(CmdArgList args, const EvalArgs& eval_args, Interpret
optional<ShardId> sid; optional<ShardId> sid;
UniqueSlotChecker slot_checker; cluster::UniqueSlotChecker slot_checker;
for (size_t i = 0; i < eval_args.keys.size(); ++i) { for (size_t i = 0; i < eval_args.keys.size(); ++i) {
string_view key = ArgS(eval_args.keys, i); string_view key = ArgS(eval_args.keys, i);
slot_checker.Add(key); slot_checker.Add(key);

View file

@ -181,7 +181,7 @@ class Service : public facade::ServiceInterface {
acl::UserRegistry user_registry_; acl::UserRegistry user_registry_;
acl::AclFamily acl_family_; acl::AclFamily acl_family_;
ServerFamily server_family_; ServerFamily server_family_;
ClusterFamily cluster_family_; cluster::ClusterFamily cluster_family_;
CommandRegistry registry_; CommandRegistry registry_;
absl::flat_hash_map<std::string, unsigned> unknown_cmds_; absl::flat_hash_map<std::string, unsigned> unknown_cmds_;

View file

@ -53,7 +53,7 @@ MultiCommandSquasher::MultiCommandSquasher(absl::Span<StoredCmd> cmds, Connectio
} }
MultiCommandSquasher::ShardExecInfo& MultiCommandSquasher::PrepareShardInfo( MultiCommandSquasher::ShardExecInfo& MultiCommandSquasher::PrepareShardInfo(
ShardId sid, optional<SlotId> slot_id) { ShardId sid, optional<cluster::SlotId> slot_id) {
if (sharded_.empty()) if (sharded_.empty())
sharded_.resize(shard_set->size()); sharded_.resize(shard_set->size());
@ -89,7 +89,7 @@ MultiCommandSquasher::SquashResult MultiCommandSquasher::TrySquash(StoredCmd* cm
// Check if all commands belong to one shard // Check if all commands belong to one shard
bool found_more = false; bool found_more = false;
UniqueSlotChecker slot_checker; cluster::UniqueSlotChecker slot_checker;
ShardId last_sid = kInvalidSid; ShardId last_sid = kInvalidSid;
IterateKeys(args, *keys, [&last_sid, &found_more, &slot_checker](MutableSlice key) { IterateKeys(args, *keys, [&last_sid, &found_more, &slot_checker](MutableSlice key) {
if (found_more) if (found_more)

View file

@ -48,7 +48,7 @@ class MultiCommandSquasher {
bool verify_commands, bool error_abort); bool verify_commands, bool error_abort);
// Lazy initialize shard info. // Lazy initialize shard info.
ShardExecInfo& PrepareShardInfo(ShardId sid, std::optional<SlotId> slot_id); ShardExecInfo& PrepareShardInfo(ShardId sid, std::optional<cluster::SlotId> slot_id);
// Retrun squash flags // Retrun squash flags
SquashResult TrySquash(StoredCmd* cmd); SquashResult TrySquash(StoredCmd* cmd);

View file

@ -3,10 +3,8 @@
// //
#pragma once #pragma once
#include <absl/container/inlined_vector.h>
#include <absl/strings/escaping.h> #include <absl/strings/escaping.h>
#include <boost/fiber/barrier.hpp>
#include <queue> #include <queue>
#include <variant> #include <variant>

View file

@ -70,7 +70,7 @@ vector<vector<unsigned>> Partition(unsigned num_flows) {
} // namespace } // namespace
Replica::Replica(string host, uint16_t port, Service* se, std::string_view id, Replica::Replica(string host, uint16_t port, Service* se, std::string_view id,
std::optional<SlotRange> slot_range) std::optional<cluster::SlotRange> slot_range)
: ProtocolClient(std::move(host), port), service_(*se), id_{id}, slot_range_(slot_range) { : ProtocolClient(std::move(host), port), service_(*se), id_{id}, slot_range_(slot_range) {
proactor_ = ProactorBase::me(); proactor_ = ProactorBase::me();
} }

View file

@ -12,7 +12,7 @@
#include "base/io_buf.h" #include "base/io_buf.h"
#include "facade/facade_types.h" #include "facade/facade_types.h"
#include "facade/redis_parser.h" #include "facade/redis_parser.h"
#include "server/cluster/slot_set.h" #include "server/cluster/cluster_defs.h"
#include "server/common.h" #include "server/common.h"
#include "server/journal/tx_executor.h" #include "server/journal/tx_executor.h"
#include "server/journal/types.h" #include "server/journal/types.h"
@ -55,7 +55,7 @@ class Replica : ProtocolClient {
public: public:
Replica(std::string master_host, uint16_t port, Service* se, std::string_view id, Replica(std::string master_host, uint16_t port, Service* se, std::string_view id,
std::optional<SlotRange> slot_range); std::optional<cluster::SlotRange> slot_range);
~Replica(); ~Replica();
// Spawns a fiber that runs until link with master is broken or the replication is stopped. // Spawns a fiber that runs until link with master is broken or the replication is stopped.
@ -173,7 +173,7 @@ class Replica : ProtocolClient {
bool is_paused_ = false; bool is_paused_ = false;
std::string id_; std::string id_;
std::optional<SlotRange> slot_range_; std::optional<cluster::SlotRange> slot_range_;
}; };
// This class implements a single shard replication flow from a Dragonfly master instance. // This class implements a single shard replication flow from a Dragonfly master instance.

View file

@ -549,13 +549,13 @@ std::string_view GetOSString() {
} }
string_view GetRedisMode() { string_view GetRedisMode() {
return ClusterConfig::IsEnabledOrEmulated() ? "cluster"sv : "standalone"sv; return cluster::IsClusterEnabledOrEmulated() ? "cluster"sv : "standalone"sv;
} }
struct ReplicaOfArgs { struct ReplicaOfArgs {
string host; string host;
uint16_t port; uint16_t port;
std::optional<SlotRange> slot_range; std::optional<cluster::SlotRange> slot_range;
static optional<ReplicaOfArgs> FromCmdArgs(CmdArgList args, ConnectionContext* cntx); static optional<ReplicaOfArgs> FromCmdArgs(CmdArgList args, ConnectionContext* cntx);
bool IsReplicaOfNoOne() const { bool IsReplicaOfNoOne() const {
return port == 0; return port == 0;
@ -588,8 +588,8 @@ optional<ReplicaOfArgs> ReplicaOfArgs::FromCmdArgs(CmdArgList args, ConnectionCo
return nullopt; return nullopt;
} }
if (parser.HasNext()) { if (parser.HasNext()) {
auto [slot_start, slot_end] = parser.Next<SlotId, SlotId>(); auto [slot_start, slot_end] = parser.Next<cluster::SlotId, cluster::SlotId>();
replicaof_args.slot_range = SlotRange{slot_start, slot_end}; replicaof_args.slot_range = cluster::SlotRange{slot_start, slot_end};
if (auto err = parser.Error(); err || !replicaof_args.slot_range->IsValid()) { if (auto err = parser.Error(); err || !replicaof_args.slot_range->IsValid()) {
cntx->SendError("Invalid slot range"); cntx->SendError("Invalid slot range");
return nullopt; return nullopt;
@ -2259,7 +2259,7 @@ void ServerFamily::Info(CmdArgList args, ConnectionContext* cntx) {
#endif #endif
if (should_enter("CLUSTER")) { if (should_enter("CLUSTER")) {
append("cluster_enabled", ClusterConfig::IsEnabledOrEmulated()); append("cluster_enabled", cluster::IsClusterEnabledOrEmulated());
} }
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder()); auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->SendVerbatimString(info); rb->SendVerbatimString(info);

View file

@ -43,8 +43,10 @@ std::string GetPassword();
namespace journal { namespace journal {
class Journal; class Journal;
} // namespace journal } // namespace journal
namespace cluster {
class ClusterFamily; class ClusterFamily;
}
class ConnectionContext; class ConnectionContext;
class CommandRegistry; class CommandRegistry;
class DflyCmd; class DflyCmd;

View file

@ -6,7 +6,7 @@
#include "base/flags.h" #include "base/flags.h"
#include "base/logging.h" #include "base/logging.h"
#include "server/cluster/cluster_config.h" #include "server/cluster/cluster_defs.h"
#include "server/server_state.h" #include "server/server_state.h"
ABSL_FLAG(bool, enable_top_keys_tracking, false, ABSL_FLAG(bool, enable_top_keys_tracking, false,
@ -86,8 +86,8 @@ DbTable::DbTable(PMR_NS::memory_resource* mr, DbIndex db_index)
mcflag(0, detail::ExpireTablePolicy{}, mr), mcflag(0, detail::ExpireTablePolicy{}, mr),
top_keys({.enabled = absl::GetFlag(FLAGS_enable_top_keys_tracking)}), top_keys({.enabled = absl::GetFlag(FLAGS_enable_top_keys_tracking)}),
index(db_index) { index(db_index) {
if (ClusterConfig::IsEnabled()) { if (cluster::IsClusterEnabled()) {
slots_stats.resize(ClusterConfig::kMaxSlotNum + 1); slots_stats.resize(cluster::kMaxSlotNum + 1);
} }
thread_index = ServerState::tlocal()->thread_index(); thread_index = ServerState::tlocal()->thread_index();
} }

View file

@ -139,7 +139,8 @@ Transaction::Transaction(const CommandId* cid) : cid_{cid} {
} }
} }
Transaction::Transaction(const Transaction* parent, ShardId shard_id, std::optional<SlotId> slot_id) Transaction::Transaction(const Transaction* parent, ShardId shard_id,
std::optional<cluster::SlotId> slot_id)
: multi_{make_unique<MultiData>()}, : multi_{make_unique<MultiData>()},
txid_{parent->txid()}, txid_{parent->txid()},
unique_shard_cnt_{1}, unique_shard_cnt_{1},
@ -1008,7 +1009,7 @@ ShardId Transaction::GetUniqueShard() const {
return unique_shard_id_; return unique_shard_id_;
} }
optional<SlotId> Transaction::GetUniqueSlotId() const { optional<cluster::SlotId> Transaction::GetUniqueSlotId() const {
return unique_slot_checker_.GetUniqueSlotId(); return unique_slot_checker_.GetUniqueSlotId();
} }

View file

@ -169,7 +169,8 @@ class Transaction {
explicit Transaction(const CommandId* cid); explicit Transaction(const CommandId* cid);
// Initialize transaction for squashing placed on a specific shard with a given parent tx // Initialize transaction for squashing placed on a specific shard with a given parent tx
explicit Transaction(const Transaction* parent, ShardId shard_id, std::optional<SlotId> slot_id); explicit Transaction(const Transaction* parent, ShardId shard_id,
std::optional<cluster::SlotId> slot_id);
// Initialize from command (args) on specific db. // Initialize from command (args) on specific db.
OpStatus InitByArgs(DbIndex index, CmdArgList args); OpStatus InitByArgs(DbIndex index, CmdArgList args);
@ -280,7 +281,7 @@ class Transaction {
// This method is meaningless if GetUniqueShardCnt() != 1. // This method is meaningless if GetUniqueShardCnt() != 1.
ShardId GetUniqueShard() const; ShardId GetUniqueShard() const;
std::optional<SlotId> GetUniqueSlotId() const; std::optional<cluster::SlotId> GetUniqueSlotId() const;
bool IsMulti() const { bool IsMulti() const {
return bool(multi_); return bool(multi_);
@ -616,7 +617,7 @@ class Transaction {
uint32_t unique_shard_cnt_{0}; // Number of unique shards active uint32_t unique_shard_cnt_{0}; // Number of unique shards active
ShardId unique_shard_id_{kInvalidSid}; // Set if unique_shard_cnt_ = 1 ShardId unique_shard_id_{kInvalidSid}; // Set if unique_shard_cnt_ = 1
UniqueSlotChecker unique_slot_checker_; cluster::UniqueSlotChecker unique_slot_checker_;
// Barrier for waking blocking transactions that ensures exclusivity of waking operation. // Barrier for waking blocking transactions that ensures exclusivity of waking operation.
BatonBarrier blocking_barrier_{}; BatonBarrier blocking_barrier_{};