1
0
Fork 0
mirror of https://github.com/dragonflydb/dragonfly.git synced 2024-12-14 11:58:02 +00:00

refactor: conn_context and reply_builder refactoring (#2251)

* refactor: conn_context and reply_builder refactoring
This commit is contained in:
Borys 2023-12-06 08:23:32 +02:00 committed by GitHub
parent 1900e499ba
commit 33d0879416
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 1424 additions and 1314 deletions

View file

@ -36,11 +36,6 @@ class ConnectionContext {
return protocol_;
}
// A convenient proxy for redis interface.
// Use with caution -- should only be used only
// in execution paths that are Redis *only*
RedisReplyBuilder* operator->();
SinkReplyBuilder* reply_builder() {
return rbuilder_.get();
}
@ -56,8 +51,28 @@ class ConnectionContext {
rbuilder_->SendError(str, type);
}
void SendError(ErrorReply&& error) {
rbuilder_->SendError(std::move(error));
void SendError(ErrorReply error) {
rbuilder_->SendError(error);
}
void SendError(OpStatus status) {
rbuilder_->SendError(status);
}
void SendStored() {
rbuilder_->SendStored();
}
void SendSetSkipped() {
rbuilder_->SendSetSkipped();
}
void SendMGetResponse(SinkReplyBuilder::MGetResponse resp) {
rbuilder_->SendMGetResponse(std::move(resp));
}
void SendLong(long val) {
rbuilder_->SendLong(val);
}
void SendSimpleString(std::string_view str) {
@ -68,6 +83,10 @@ class ConnectionContext {
rbuilder_->SendOk();
}
void SendProtocolError(std::string_view str) {
rbuilder_->SendProtocolError(str);
}
virtual size_t UsedMemory() const {
return dfly::HeapSize(rbuilder_);
}

View file

@ -138,12 +138,6 @@ ConnectionContext::ConnectionContext(::io::Sink* stream, Connection* owner) : ow
subscriptions = 0;
}
RedisReplyBuilder* ConnectionContext::operator->() {
CHECK(Protocol::REDIS == protocol());
return static_cast<RedisReplyBuilder*>(rbuilder_.get());
}
CommandId::CommandId(const char* name, uint32_t mask, int8_t arity, int8_t first_key,
int8_t last_key, uint32_t acl_categories)
: name_(name),

View file

@ -24,7 +24,7 @@ thread_local ConnectionStats tl_stats;
class OkService : public ServiceInterface {
public:
void DispatchCommand(CmdArgList args, ConnectionContext* cntx) final {
(*cntx)->SendOk();
cntx->SendOk();
}
size_t DispatchManyCommands(absl::Span<CmdArgList> args_lists, ConnectionContext* cntx) final {

View file

@ -50,13 +50,14 @@ AclFamily::AclFamily(UserRegistry* registry, util::ProactorPool* pool)
}
void AclFamily::Acl(CmdArgList args, ConnectionContext* cntx) {
(*cntx)->SendError("Wrong number of arguments for acl command");
cntx->SendError("Wrong number of arguments for acl command");
}
void AclFamily::List(CmdArgList args, ConnectionContext* cntx) {
const auto registry_with_lock = registry_->GetRegistryWithLock();
const auto& registry = registry_with_lock.registry;
(*cntx)->StartArray(registry.size());
auto* rb = static_cast<facade::RedisReplyBuilder*>(cntx->reply_builder());
rb->StartArray(registry.size());
for (const auto& [username, user] : registry) {
std::string buffer = "user ";
@ -71,7 +72,7 @@ void AclFamily::List(CmdArgList args, ConnectionContext* cntx) {
absl::StrAppend(&buffer, username, " ", user.IsActive() ? "on "sv : "off "sv, password, " ",
acl_cat, maybe_space, acl_commands);
(*cntx)->SendSimpleString(buffer);
cntx->SendSimpleString(buffer);
}
}
@ -97,7 +98,7 @@ using facade::ErrorReply;
void AclFamily::SetUser(CmdArgList args, ConnectionContext* cntx) {
std::string_view username = facade::ToSV(args[0]);
auto req = ParseAclSetUser(args.subspan(1), *cmd_registry_);
auto error_case = [cntx](ErrorReply&& error) { (*cntx)->SendError(error); };
auto error_case = [cntx](ErrorReply&& error) { cntx->SendError(std::move(error)); };
auto update_case = [username, cntx, this](User::UpdateRequest&& req) {
auto user_with_lock = registry_->MaybeAddAndUpdateWithLock(username, std::move(req));
if (user_with_lock.exists) {
@ -313,7 +314,7 @@ void AclFamily::Load(CmdArgList args, ConnectionContext* cntx) {
void AclFamily::Log(CmdArgList args, ConnectionContext* cntx) {
if (args.size() > 1) {
(*cntx)->SendError(facade::OpStatus::OUT_OF_RANGE);
cntx->SendError(facade::OpStatus::OUT_OF_RANGE);
}
size_t max_output = 10;
@ -322,12 +323,12 @@ void AclFamily::Log(CmdArgList args, ConnectionContext* cntx) {
if (absl::EqualsIgnoreCase(option, "RESET")) {
pool_->AwaitFiberOnAll(
[](auto index, auto* context) { ServerState::tlocal()->acl_log.Reset(); });
(*cntx)->SendOk();
cntx->SendOk();
return;
}
if (!absl::SimpleAtoi(facade::ToSV(args[0]), &max_output)) {
(*cntx)->SendError("Invalid count");
cntx->SendError("Invalid count");
return;
}
}
@ -342,32 +343,33 @@ void AclFamily::Log(CmdArgList args, ConnectionContext* cntx) {
total_entries += log.size();
}
auto* rb = static_cast<facade::RedisReplyBuilder*>(cntx->reply_builder());
if (total_entries == 0) {
(*cntx)->SendEmptyArray();
rb->SendEmptyArray();
return;
}
(*cntx)->StartArray(total_entries);
auto print_element = [cntx](const auto& entry) {
(*cntx)->StartArray(12);
(*cntx)->SendSimpleString("reason");
rb->StartArray(total_entries);
auto print_element = [rb](const auto& entry) {
rb->StartArray(12);
rb->SendSimpleString("reason");
using Reason = AclLog::Reason;
std::string_view reason = entry.reason == Reason::COMMAND ? "COMMAND" : "AUTH";
(*cntx)->SendSimpleString(reason);
(*cntx)->SendSimpleString("object");
(*cntx)->SendSimpleString(entry.object);
(*cntx)->SendSimpleString("username");
(*cntx)->SendSimpleString(entry.username);
(*cntx)->SendSimpleString("age-seconds");
rb->SendSimpleString(reason);
rb->SendSimpleString("object");
rb->SendSimpleString(entry.object);
rb->SendSimpleString("username");
rb->SendSimpleString(entry.username);
rb->SendSimpleString("age-seconds");
auto now_diff = std::chrono::system_clock::now() - entry.entry_creation;
auto secs = std::chrono::duration_cast<std::chrono::seconds>(now_diff);
auto left_over = now_diff - std::chrono::duration_cast<std::chrono::microseconds>(secs);
auto age = absl::StrCat(secs.count(), ".", left_over.count());
(*cntx)->SendSimpleString(absl::StrCat(age));
(*cntx)->SendSimpleString("client-info");
(*cntx)->SendSimpleString(entry.client_info);
(*cntx)->SendSimpleString("timestamp-created");
(*cntx)->SendLong(entry.entry_creation.time_since_epoch().count());
rb->SendSimpleString(absl::StrCat(age));
rb->SendSimpleString("client-info");
rb->SendSimpleString(entry.client_info);
rb->SendSimpleString("timestamp-created");
rb->SendLong(entry.entry_creation.time_since_epoch().count());
};
auto n_way_minimum = [](const auto& logs) {
@ -394,15 +396,16 @@ void AclFamily::Log(CmdArgList args, ConnectionContext* cntx) {
void AclFamily::Users(CmdArgList args, ConnectionContext* cntx) {
const auto registry_with_lock = registry_->GetRegistryWithLock();
const auto& registry = registry_with_lock.registry;
(*cntx)->StartArray(registry.size());
auto* rb = static_cast<facade::RedisReplyBuilder*>(cntx->reply_builder());
rb->StartArray(registry.size());
for (const auto& [username, _] : registry) {
(*cntx)->SendSimpleString(username);
rb->SendSimpleString(username);
}
}
void AclFamily::Cat(CmdArgList args, ConnectionContext* cntx) {
if (args.size() > 1) {
(*cntx)->SendError(facade::OpStatus::SYNTAX_ERR);
cntx->SendError(facade::OpStatus::SYNTAX_ERR);
return;
}
@ -411,7 +414,7 @@ void AclFamily::Cat(CmdArgList args, ConnectionContext* cntx) {
std::string_view category = facade::ToSV(args[0]);
if (!CATEGORY_INDEX_TABLE.contains(category)) {
auto error = absl::StrCat("Unkown category: ", category);
(*cntx)->SendError(error);
cntx->SendError(error);
return;
}
@ -423,10 +426,11 @@ void AclFamily::Cat(CmdArgList args, ConnectionContext* cntx) {
}
};
auto* rb = static_cast<facade::RedisReplyBuilder*>(cntx->reply_builder());
cmd_registry_->Traverse(cb);
(*cntx)->StartArray(results.size());
rb->StartArray(results.size());
for (const auto& command : results) {
(*cntx)->SendSimpleString(command);
rb->SendSimpleString(command);
}
return;
@ -439,10 +443,11 @@ void AclFamily::Cat(CmdArgList args, ConnectionContext* cntx) {
}
}
(*cntx)->StartArray(total_categories);
auto* rb = static_cast<facade::RedisReplyBuilder*>(cntx->reply_builder());
rb->StartArray(total_categories);
for (auto& elem : REVERSE_CATEGORY_INDEX_TABLE) {
if (elem != "_RESERVED") {
(*cntx)->SendSimpleString(elem);
rb->SendSimpleString(elem);
}
}
}
@ -453,39 +458,40 @@ void AclFamily::GetUser(CmdArgList args, ConnectionContext* cntx) {
const auto& registry = registry_with_lock.registry;
if (!registry.contains(username)) {
auto error = absl::StrCat("User: ", username, " does not exists!");
(*cntx)->SendError(error);
cntx->SendError(error);
return;
}
auto& user = registry.find(username)->second;
std::string status = user.IsActive() ? "on" : "off";
auto pass = user.Password();
(*cntx)->StartArray(6);
auto* rb = static_cast<facade::RedisReplyBuilder*>(cntx->reply_builder());
rb->StartArray(6);
(*cntx)->SendSimpleString("flags");
rb->SendSimpleString("flags");
const size_t total_elements = (pass != "nopass") ? 1 : 2;
(*cntx)->StartArray(total_elements);
(*cntx)->SendSimpleString(status);
rb->StartArray(total_elements);
rb->SendSimpleString(status);
if (total_elements == 2) {
(*cntx)->SendSimpleString(pass);
rb->SendSimpleString(pass);
}
(*cntx)->SendSimpleString("passwords");
rb->SendSimpleString("passwords");
if (pass != "nopass") {
(*cntx)->SendSimpleString(pass);
rb->SendSimpleString(pass);
} else {
(*cntx)->SendEmptyArray();
rb->SendEmptyArray();
}
(*cntx)->SendSimpleString("commands");
rb->SendSimpleString("commands");
std::string acl = absl::StrCat(AclCatToString(user.AclCategory()), " ",
AclCommandToString(user.AclCommandsRef()));
(*cntx)->SendSimpleString(acl);
rb->SendSimpleString(acl);
}
void AclFamily::GenPass(CmdArgList args, ConnectionContext* cntx) {
if (args.length() > 1) {
(*cntx)->SendError(facade::UnknownSubCmd("GENPASS", "ACL"));
cntx->SendError(facade::UnknownSubCmd("GENPASS", "ACL"));
return;
}
uint32_t random_bits = 256;
@ -493,7 +499,7 @@ void AclFamily::GenPass(CmdArgList args, ConnectionContext* cntx) {
auto requested_bits = facade::ArgS(args, 0);
if (!absl::SimpleAtoi(requested_bits, &random_bits) || random_bits == 0 || random_bits > 4096) {
return (*cntx)->SendError(
return cntx->SendError(
"ACL GENPASS argument must be the number of bits for the output password, a positive "
"number up to 4096");
}
@ -508,7 +514,7 @@ void AclFamily::GenPass(CmdArgList args, ConnectionContext* cntx) {
response.resize(result_length);
(*cntx)->SendSimpleString(response);
cntx->SendSimpleString(response);
}
void AclFamily::DryRun(CmdArgList args, ConnectionContext* cntx) {
@ -517,7 +523,7 @@ void AclFamily::DryRun(CmdArgList args, ConnectionContext* cntx) {
const auto& registry = registry_with_lock.registry;
if (!registry.contains(username)) {
auto error = absl::StrCat("User: ", username, " does not exists!");
(*cntx)->SendError(error);
cntx->SendError(error);
return;
}
@ -526,18 +532,18 @@ void AclFamily::DryRun(CmdArgList args, ConnectionContext* cntx) {
auto* cid = cmd_registry_->Find(command);
if (!cid) {
auto error = absl::StrCat("Command: ", command, " does not exists!");
(*cntx)->SendError(error);
cntx->SendError(error);
return;
}
const auto& user = registry.find(username)->second;
if (IsUserAllowedToInvokeCommandGeneric(user.AclCategory(), user.AclCommandsRef(), *cid)) {
(*cntx)->SendOk();
cntx->SendOk();
return;
}
auto error = absl::StrCat("User: ", username, " is not allowed to execute command: ", command);
(*cntx)->SendError(error);
cntx->SendError(error);
}
using MemberFunc = void (AclFamily::*)(CmdArgList args, ConnectionContext* cntx);

View file

@ -500,17 +500,17 @@ template <typename T> void HandleOpValueResult(const OpResult<T>& result, Connec
"we are only handling types that are integral types in the return types from "
"here");
if (result) {
(*cntx)->SendLong(result.value());
cntx->SendLong(result.value());
} else {
switch (result.status()) {
case OpStatus::WRONG_TYPE:
(*cntx)->SendError(kWrongTypeErr);
cntx->SendError(kWrongTypeErr);
break;
case OpStatus::OUT_OF_MEMORY:
(*cntx)->SendError(kOutOfMemory);
cntx->SendError(kOutOfMemory);
break;
default:
(*cntx)->SendLong(0); // in case we don't have the value we should just send 0
cntx->SendLong(0); // in case we don't have the value we should just send 0
break;
}
}
@ -523,7 +523,7 @@ void BitPos(CmdArgList args, ConnectionContext* cntx) {
// See details at https://redis.io/commands/bitpos/
if (args.size() < 1 || args.size() > 5) {
return (*cntx)->SendError(kSyntaxErr);
return cntx->SendError(kSyntaxErr);
}
std::string_view key = ArgS(args, 0);
@ -534,21 +534,21 @@ void BitPos(CmdArgList args, ConnectionContext* cntx) {
bool as_bit = false;
if (!absl::SimpleAtoi(ArgS(args, 1), &value)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
if (args.size() >= 3) {
if (!absl::SimpleAtoi(ArgS(args, 2), &start)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
if (args.size() >= 4) {
if (!absl::SimpleAtoi(ArgS(args, 3), &end)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
if (args.size() >= 5) {
if (!ToUpperAndGetAsBit(args, 4, &as_bit)) {
return (*cntx)->SendError(kSyntaxErr);
return cntx->SendError(kSyntaxErr);
}
}
}
@ -568,7 +568,7 @@ void BitCount(CmdArgList args, ConnectionContext* cntx) {
// Please note that if the key don't exists, it would return 0
if (args.size() == 2 || args.size() > 4) {
return (*cntx)->SendError(kSyntaxErr);
return cntx->SendError(kSyntaxErr);
}
std::string_view key = ArgS(args, 0);
@ -578,11 +578,11 @@ void BitCount(CmdArgList args, ConnectionContext* cntx) {
if (args.size() >= 3) {
if (absl::SimpleAtoi(ArgS(args, 1), &start) == 0 ||
absl::SimpleAtoi(ArgS(args, 2), &end) == 0) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
if (args.size() == 4) {
if (!ToUpperAndGetAsBit(args, 3, &as_bit)) {
return (*cntx)->SendError(kSyntaxErr);
return cntx->SendError(kSyntaxErr);
}
}
}
@ -1068,26 +1068,28 @@ nonstd::expected<CommandList, std::string> ParseToCommandList(CmdArgList args, b
}
void SendResults(const std::vector<ResultType>& results, ConnectionContext* cntx) {
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
const size_t total = results.size();
if (total == 0) {
(*cntx)->SendNullArray();
rb->SendNullArray();
return;
}
(*cntx)->StartArray(total);
rb->StartArray(total);
for (const auto& elem : results) {
if (elem) {
(*cntx)->SendLong(*elem);
rb->SendLong(*elem);
continue;
}
(*cntx)->SendNull();
rb->SendNull();
}
}
void BitFieldGeneric(CmdArgList args, bool read_only, ConnectionContext* cntx) {
if (args.size() == 1) {
(*cntx)->SendNullArray();
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->SendNullArray();
return;
}
auto key = ArgS(args, 0);
@ -1136,7 +1138,7 @@ void BitOp(CmdArgList args, ConnectionContext* cntx) {
[&op](auto val) { return op == val; });
if (illegal || (op == NOT_OP_NAME && args.size() > 3)) {
return (*cntx)->SendError(kSyntaxErr); // too many arguments
return cntx->SendError(kSyntaxErr); // too many arguments
}
// Multi shard access - read only
@ -1166,7 +1168,7 @@ void BitOp(CmdArgList args, ConnectionContext* cntx) {
// Second phase - save to targe key if successful
if (!joined_results) {
cntx->transaction->Conclude();
(*cntx)->SendError(joined_results.status());
cntx->SendError(joined_results.status());
return;
} else {
auto op_result = joined_results.value();
@ -1187,7 +1189,7 @@ void BitOp(CmdArgList args, ConnectionContext* cntx) {
};
cntx->transaction->Execute(std::move(store_cb), true);
(*cntx)->SendLong(op_result.size());
cntx->SendLong(op_result.size());
}
}
@ -1199,7 +1201,7 @@ void GetBit(CmdArgList args, ConnectionContext* cntx) {
std::string_view key = ArgS(args, 0);
if (!absl::SimpleAtoi(ArgS(args, 1), &offset)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
auto cb = [&](Transaction* t, EngineShard* shard) {
return ReadValueBitsetAt(t->GetOpArgs(shard), key, offset);
@ -1218,7 +1220,7 @@ void SetBit(CmdArgList args, ConnectionContext* cntx) {
std::string_view key = ArgS(args, 0);
if (!absl::SimpleAtoi(ArgS(args, 1), &offset) || !absl::SimpleAtoi(ArgS(args, 2), &value)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
auto cb = [&](Transaction* t, EngineShard* shard) {

View file

@ -107,46 +107,48 @@ void ClusterFamily::ClusterHelp(ConnectionContext* cntx) {
"HELP",
" Prints this help.",
};
return (*cntx)->SendSimpleStrArr(help_arr);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
return rb->SendSimpleStrArr(help_arr);
}
namespace {
void ClusterShardsImpl(const ClusterShards& config, ConnectionContext* cntx) {
// For more details https://redis.io/commands/cluster-shards/
constexpr unsigned int kEntrySize = 4;
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
auto WriteNode = [&](const Node& node, string_view role) {
constexpr unsigned int kNodeSize = 14;
(*cntx)->StartArray(kNodeSize);
(*cntx)->SendBulkString("id");
(*cntx)->SendBulkString(node.id);
(*cntx)->SendBulkString("endpoint");
(*cntx)->SendBulkString(node.ip);
(*cntx)->SendBulkString("ip");
(*cntx)->SendBulkString(node.ip);
(*cntx)->SendBulkString("port");
(*cntx)->SendLong(node.port);
(*cntx)->SendBulkString("role");
(*cntx)->SendBulkString(role);
(*cntx)->SendBulkString("replication-offset");
(*cntx)->SendLong(0);
(*cntx)->SendBulkString("health");
(*cntx)->SendBulkString("online");
rb->StartArray(kNodeSize);
rb->SendBulkString("id");
rb->SendBulkString(node.id);
rb->SendBulkString("endpoint");
rb->SendBulkString(node.ip);
rb->SendBulkString("ip");
rb->SendBulkString(node.ip);
rb->SendBulkString("port");
rb->SendLong(node.port);
rb->SendBulkString("role");
rb->SendBulkString(role);
rb->SendBulkString("replication-offset");
rb->SendLong(0);
rb->SendBulkString("health");
rb->SendBulkString("online");
};
(*cntx)->StartArray(config.size());
rb->StartArray(config.size());
for (const auto& shard : config) {
(*cntx)->StartArray(kEntrySize);
(*cntx)->SendBulkString("slots");
rb->StartArray(kEntrySize);
rb->SendBulkString("slots");
(*cntx)->StartArray(shard.slot_ranges.size() * 2);
rb->StartArray(shard.slot_ranges.size() * 2);
for (const auto& slot_range : shard.slot_ranges) {
(*cntx)->SendLong(slot_range.start);
(*cntx)->SendLong(slot_range.end);
rb->SendLong(slot_range.start);
rb->SendLong(slot_range.end);
}
(*cntx)->SendBulkString("nodes");
(*cntx)->StartArray(1 + shard.replicas.size());
rb->SendBulkString("nodes");
rb->StartArray(1 + shard.replicas.size());
WriteNode(shard.master, "master");
for (const auto& replica : shard.replicas) {
WriteNode(replica, "replica");
@ -161,19 +163,20 @@ void ClusterFamily::ClusterShards(ConnectionContext* cntx) {
} else if (tl_cluster_config != nullptr) {
return ClusterShardsImpl(tl_cluster_config->GetConfig(), cntx);
} else {
return (*cntx)->SendError(kClusterNotConfigured);
return cntx->SendError(kClusterNotConfigured);
}
}
namespace {
void ClusterSlotsImpl(const ClusterShards& config, ConnectionContext* cntx) {
// For more details https://redis.io/commands/cluster-slots/
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
auto WriteNode = [&](const Node& node) {
constexpr unsigned int kNodeSize = 3;
(*cntx)->StartArray(kNodeSize);
(*cntx)->SendBulkString(node.ip);
(*cntx)->SendLong(node.port);
(*cntx)->SendBulkString(node.id);
rb->StartArray(kNodeSize);
rb->SendBulkString(node.ip);
rb->SendLong(node.port);
rb->SendBulkString(node.id);
};
unsigned int slot_ranges = 0;
@ -181,14 +184,14 @@ void ClusterSlotsImpl(const ClusterShards& config, ConnectionContext* cntx) {
slot_ranges += shard.slot_ranges.size();
}
(*cntx)->StartArray(slot_ranges);
rb->StartArray(slot_ranges);
for (const auto& shard : config) {
for (const auto& slot_range : shard.slot_ranges) {
const unsigned int array_size =
/* slot-start, slot-end */ 2 + /* master */ 1 + /* replicas */ shard.replicas.size();
(*cntx)->StartArray(array_size);
(*cntx)->SendLong(slot_range.start);
(*cntx)->SendLong(slot_range.end);
rb->StartArray(array_size);
rb->SendLong(slot_range.start);
rb->SendLong(slot_range.end);
WriteNode(shard.master);
for (const auto& replica : shard.replicas) {
WriteNode(replica);
@ -204,7 +207,7 @@ void ClusterFamily::ClusterSlots(ConnectionContext* cntx) {
} else if (tl_cluster_config != nullptr) {
return ClusterSlotsImpl(tl_cluster_config->GetConfig(), cntx);
} else {
return (*cntx)->SendError(kClusterNotConfigured);
return cntx->SendError(kClusterNotConfigured);
}
}
@ -247,7 +250,8 @@ void ClusterNodesImpl(const ClusterShards& config, string_view my_id, Connection
}
}
return (*cntx)->SendBulkString(result);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
return rb->SendBulkString(result);
}
} // namespace
@ -257,7 +261,7 @@ void ClusterFamily::ClusterNodes(ConnectionContext* cntx) {
} else if (tl_cluster_config != nullptr) {
return ClusterNodesImpl(tl_cluster_config->GetConfig(), server_family_->master_id(), cntx);
} else {
return (*cntx)->SendError(kClusterNotConfigured);
return cntx->SendError(kClusterNotConfigured);
}
}
@ -309,7 +313,8 @@ void ClusterInfoImpl(const ClusterShards& config, ConnectionContext* cntx) {
append("cluster_stats_messages_pong_received", 1);
append("cluster_stats_messages_meet_received", 0);
append("cluster_stats_messages_received", 1);
(*cntx)->SendBulkString(msg);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->SendBulkString(msg);
}
} // namespace
@ -325,11 +330,11 @@ void ClusterFamily::ClusterInfo(ConnectionContext* cntx) {
void ClusterFamily::KeySlot(CmdArgList args, ConnectionContext* cntx) {
if (args.size() != 2) {
return (*cntx)->SendError(WrongNumArgsError("CLUSTER KEYSLOT"));
return cntx->SendError(WrongNumArgsError("CLUSTER KEYSLOT"));
}
SlotId id = ClusterConfig::KeySlot(ArgS(args, 1));
return (*cntx)->SendLong(id);
return cntx->SendLong(id);
}
void ClusterFamily::Cluster(CmdArgList args, ConnectionContext* cntx) {
@ -340,7 +345,7 @@ void ClusterFamily::Cluster(CmdArgList args, ConnectionContext* cntx) {
string_view sub_cmd = ArgS(args, 0);
if (!ClusterConfig::IsEnabledOrEmulated()) {
return (*cntx)->SendError(kClusterDisabled);
return cntx->SendError(kClusterDisabled);
}
if (sub_cmd == "HELP") {
@ -356,31 +361,31 @@ void ClusterFamily::Cluster(CmdArgList args, ConnectionContext* cntx) {
} else if (sub_cmd == "KEYSLOT") {
return KeySlot(args, cntx);
} else {
return (*cntx)->SendError(facade::UnknownSubCmd(sub_cmd, "CLUSTER"), facade::kSyntaxErrType);
return cntx->SendError(facade::UnknownSubCmd(sub_cmd, "CLUSTER"), facade::kSyntaxErrType);
}
}
void ClusterFamily::ReadOnly(CmdArgList args, ConnectionContext* cntx) {
if (!ClusterConfig::IsEmulated()) {
return (*cntx)->SendError(kClusterDisabled);
return cntx->SendError(kClusterDisabled);
}
(*cntx)->SendOk();
cntx->SendOk();
}
void ClusterFamily::ReadWrite(CmdArgList args, ConnectionContext* cntx) {
if (!ClusterConfig::IsEmulated()) {
return (*cntx)->SendError(kClusterDisabled);
return cntx->SendError(kClusterDisabled);
}
(*cntx)->SendOk();
cntx->SendOk();
}
void ClusterFamily::DflyCluster(CmdArgList args, ConnectionContext* cntx) {
if (!ClusterConfig::IsEnabledOrEmulated()) {
return (*cntx)->SendError(kClusterDisabled);
return cntx->SendError(kClusterDisabled);
}
if (cntx->conn() && !cntx->conn()->IsPrivileged()) {
return (*cntx)->SendError(kDflyClusterCmdPort);
return cntx->SendError(kDflyClusterCmdPort);
}
ToUpper(&args[0]);
@ -400,14 +405,15 @@ void ClusterFamily::DflyCluster(CmdArgList args, ConnectionContext* cntx) {
return DflySlotMigrationStatus(args, cntx);
}
return (*cntx)->SendError(UnknownSubCmd(sub_cmd, "DFLYCLUSTER"), kSyntaxErrType);
return cntx->SendError(UnknownSubCmd(sub_cmd, "DFLYCLUSTER"), kSyntaxErrType);
}
void ClusterFamily::DflyClusterMyId(CmdArgList args, ConnectionContext* cntx) {
if (!args.empty()) {
return (*cntx)->SendError(WrongNumArgsError("DFLYCLUSTER MYID"));
return cntx->SendError(WrongNumArgsError("DFLYCLUSTER MYID"));
}
(*cntx)->SendBulkString(server_family_->master_id());
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->SendBulkString(server_family_->master_id());
}
namespace {
@ -533,17 +539,18 @@ void ClusterFamily::DflyClusterConfig(CmdArgList args, ConnectionContext* cntx)
void ClusterFamily::DflyClusterGetSlotInfo(CmdArgList args, ConnectionContext* cntx) {
CmdArgParser parser(args);
parser.ExpectTag("SLOTS");
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
vector<std::pair<SlotId, SlotStats>> slots_stats;
do {
auto sid = parser.Next<uint32_t>();
if (sid > ClusterConfig::kMaxSlotNum)
return (*cntx)->SendError("Invalid slot id");
return rb->SendError("Invalid slot id");
slots_stats.emplace_back(sid, SlotStats{});
} while (parser.HasNext());
if (auto err = parser.Error(); err)
return (*cntx)->SendError(err->MakeReply());
return rb->SendError(err->MakeReply());
Mutex mu;
@ -560,36 +567,34 @@ void ClusterFamily::DflyClusterGetSlotInfo(CmdArgList args, ConnectionContext* c
shard_set->pool()->AwaitFiberOnAll(std::move(cb));
(*cntx)->StartArray(slots_stats.size());
rb->StartArray(slots_stats.size());
for (const auto& slot_data : slots_stats) {
(*cntx)->StartArray(7);
(*cntx)->SendLong(slot_data.first);
(*cntx)->SendBulkString("key_count");
(*cntx)->SendLong(static_cast<long>(slot_data.second.key_count));
(*cntx)->SendBulkString("total_reads");
(*cntx)->SendLong(static_cast<long>(slot_data.second.total_reads));
(*cntx)->SendBulkString("total_writes");
(*cntx)->SendLong(static_cast<long>(slot_data.second.total_writes));
rb->StartArray(7);
rb->SendLong(slot_data.first);
rb->SendBulkString("key_count");
rb->SendLong(static_cast<long>(slot_data.second.key_count));
rb->SendBulkString("total_reads");
rb->SendLong(static_cast<long>(slot_data.second.total_reads));
rb->SendBulkString("total_writes");
rb->SendLong(static_cast<long>(slot_data.second.total_writes));
}
}
void ClusterFamily::DflyClusterFlushSlots(CmdArgList args, ConnectionContext* cntx) {
SinkReplyBuilder* rb = cntx->reply_builder();
SlotSet slots;
slots.reserve(args.size());
for (size_t i = 0; i < args.size(); ++i) {
unsigned slot;
if (!absl::SimpleAtoi(ArgS(args, i), &slot) || (slot > ClusterConfig::kMaxSlotNum)) {
return rb->SendError(kSyntaxErrType);
return cntx->SendError(kSyntaxErrType);
}
slots.insert(static_cast<SlotId>(slot));
}
DeleteSlots(slots);
return rb->SendOk();
return cntx->SendOk();
}
void ClusterFamily::DflyClusterStartSlotMigration(CmdArgList args, ConnectionContext* cntx) {
@ -601,26 +606,24 @@ void ClusterFamily::DflyClusterStartSlotMigration(CmdArgList args, ConnectionCon
slots.emplace_back(SlotRange{slot_start, slot_end});
} while (parser.HasNext());
SinkReplyBuilder* rb = cntx->reply_builder();
if (auto err = parser.Error(); err)
return rb->SendError(err->MakeReply());
return cntx->SendError(err->MakeReply());
auto* node = AddMigration(std::string(host_ip), port, std::move(slots));
if (!node) {
return rb->SendError("Can't start the migration, another one is in progress");
return cntx->SendError("Can't start the migration, another one is in progress");
}
node->Start(cntx);
return rb->SendOk();
return cntx->SendOk();
}
void ClusterFamily::DflySlotMigrationStatus(CmdArgList args, ConnectionContext* cntx) {
CmdArgParser parser(args);
auto [host_ip, port] = parser.Next<std::string_view, uint16_t>();
SinkReplyBuilder* rb = cntx->reply_builder();
if (auto err = parser.Error(); err)
return rb->SendError(err->MakeReply());
return cntx->SendError(err->MakeReply());
auto state = [&] {
lock_guard lk(migrations_jobs_mu_);
@ -647,7 +650,7 @@ void ClusterFamily::DflySlotMigrationStatus(CmdArgList args, ConnectionContext*
return "UNDEFINED_STATE"sv;
}();
return rb->SendSimpleString(state_str);
return cntx->SendSimpleString(state_str);
}
void ClusterFamily::DflyMigrate(CmdArgList args, ConnectionContext* cntx) {
@ -657,7 +660,7 @@ void ClusterFamily::DflyMigrate(CmdArgList args, ConnectionContext* cntx) {
if (sub_cmd == "CONF") {
MigrationConf(args, cntx);
} else {
(*cntx)->SendError(facade::UnknownSubCmd(sub_cmd, "DFLYMIGRATE"), facade::kSyntaxErrType);
cntx->SendError(facade::UnknownSubCmd(sub_cmd, "DFLYMIGRATE"), facade::kSyntaxErrType);
}
}
@ -687,10 +690,10 @@ void ClusterFamily::MigrationConf(CmdArgList args, ConnectionContext* cntx) {
} while (parser.HasNext());
if (auto err = parser.Error(); err)
return (*cntx)->SendError(err->MakeReply());
return cntx->SendError(err->MakeReply());
if (!tl_cluster_config) {
(*cntx)->SendError(kClusterNotConfigured);
cntx->SendError(kClusterNotConfigured);
return;
}
@ -699,7 +702,7 @@ void ClusterFamily::MigrationConf(CmdArgList args, ConnectionContext* cntx) {
if (!tl_cluster_config->IsMySlot(i)) {
VLOG(1) << "Invalid migration slot " << i << " in range " << migration_range.start << ':'
<< migration_range.end;
(*cntx)->SendError("Invalid slots range");
cntx->SendError("Invalid slots range");
return;
}
}
@ -707,7 +710,7 @@ void ClusterFamily::MigrationConf(CmdArgList args, ConnectionContext* cntx) {
cntx->conn()->SetName("slot_migration_ctrl");
(*cntx)->SendLong(shard_set->size());
cntx->SendLong(shard_set->size());
return;
}

View file

@ -33,7 +33,7 @@ error_code ClusterSlotMigration::Start(ConnectionContext* cntx) {
auto check_connection_error = [this, &cntx](error_code ec, const char* msg) -> error_code {
if (ec) {
(*cntx)->SendError(absl::StrCat(msg, ec.message()));
cntx->SendError(absl::StrCat(msg, ec.message()));
}
return ec;
};

View file

@ -177,10 +177,11 @@ void ConnectionContext::ChangeSubscription(bool to_add, bool to_reply, CmdArgLis
if (to_reply) {
for (size_t i = 0; i < result.size(); ++i) {
const char* action[2] = {"unsubscribe", "subscribe"};
(*this)->StartCollection(3, RedisReplyBuilder::CollectionType::PUSH);
(*this)->SendBulkString(action[to_add]);
(*this)->SendBulkString(ArgS(args, i));
(*this)->SendLong(result[i]);
auto rb = static_cast<RedisReplyBuilder*>(reply_builder());
rb->StartCollection(3, RedisReplyBuilder::CollectionType::PUSH);
rb->SendBulkString(action[to_add]);
rb->SendBulkString(ArgS(args, i));
rb->SendLong(result[i]);
}
}
}
@ -224,13 +225,14 @@ void ConnectionContext::PUnsubscribeAll(bool to_reply) {
void ConnectionContext::SendSubscriptionChangedResponse(string_view action,
std::optional<string_view> topic,
unsigned count) {
(*this)->StartCollection(3, RedisReplyBuilder::CollectionType::PUSH);
(*this)->SendBulkString(action);
auto rb = static_cast<RedisReplyBuilder*>(reply_builder());
rb->StartCollection(3, RedisReplyBuilder::CollectionType::PUSH);
rb->SendBulkString(action);
if (topic.has_value())
(*this)->SendBulkString(topic.value());
rb->SendBulkString(topic.value());
else
(*this)->SendNull();
(*this)->SendLong(count);
rb->SendNull();
rb->SendLong(count);
}
size_t ConnectionContext::UsedMemory() const {

View file

@ -251,7 +251,8 @@ void DebugCmd::Run(CmdArgList args) {
"HELP",
" Prints this help.",
};
return (*cntx_)->SendSimpleStrArr(help_arr);
auto* rb = static_cast<RedisReplyBuilder*>(cntx_->reply_builder());
return rb->SendSimpleStrArr(help_arr);
}
VLOG(1) << "subcmd " << subcmd;
@ -298,7 +299,7 @@ void DebugCmd::Run(CmdArgList args) {
}
string reply = UnknownSubCmd(subcmd, "DEBUG");
return (*cntx_)->SendError(reply, kSyntaxErrType);
return cntx_->SendError(reply, kSyntaxErrType);
}
void DebugCmd::Reload(CmdArgList args) {
@ -312,7 +313,7 @@ void DebugCmd::Reload(CmdArgList args) {
if (opt == "NOSAVE") {
save = false;
} else {
return (*cntx_)->SendError("DEBUG RELOAD only supports the NOSAVE options.");
return cntx_->SendError("DEBUG RELOAD only supports the NOSAVE options.");
}
}
@ -322,7 +323,7 @@ void DebugCmd::Reload(CmdArgList args) {
GenericError ec = sf_.DoSave();
if (ec) {
return (*cntx_)->SendError(ec.Format());
return cntx_->SendError(ec.Format());
}
}
@ -335,24 +336,25 @@ void DebugCmd::Replica(CmdArgList args) {
ToUpper(&args[0]);
string_view opt = ArgS(args, 0);
auto* rb = static_cast<RedisReplyBuilder*>(cntx_->reply_builder());
if (opt == "PAUSE" || opt == "RESUME") {
sf_.PauseReplication(opt == "PAUSE");
return (*cntx_)->SendOk();
return rb->SendOk();
} else if (opt == "OFFSET") {
const auto offset_info = sf_.GetReplicaOffsetInfo();
if (offset_info) {
(*cntx_)->StartArray(2);
(*cntx_)->SendBulkString(offset_info.value().sync_id);
(*cntx_)->StartArray(offset_info.value().flow_offsets.size());
rb->StartArray(2);
rb->SendBulkString(offset_info.value().sync_id);
rb->StartArray(offset_info.value().flow_offsets.size());
for (uint64_t offset : offset_info.value().flow_offsets) {
(*cntx_)->SendLong(offset);
rb->SendLong(offset);
}
return;
} else {
return (*cntx_)->SendError("I am master");
return rb->SendError("I am master");
}
}
return (*cntx_)->SendError(UnknownSubCmd("replica", "DEBUG"));
return rb->SendError(UnknownSubCmd("replica", "DEBUG"));
}
void DebugCmd::Load(string_view filename) {
@ -389,22 +391,22 @@ void DebugCmd::Load(string_view filename) {
ec = fut_ec.get();
if (ec) {
LOG(INFO) << "Could not load file " << ec.message();
return (*cntx_)->SendError(ec.message());
return cntx_->SendError(ec.message());
}
}
(*cntx_)->SendOk();
cntx_->SendOk();
}
optional<DebugCmd::PopulateOptions> DebugCmd::ParsePopulateArgs(CmdArgList args) {
if (args.size() < 2 || args.size() > 8) {
(*cntx_)->SendError(UnknownSubCmd("populate", "DEBUG"));
cntx_->SendError(UnknownSubCmd("populate", "DEBUG"));
return nullopt;
}
PopulateOptions options;
if (!absl::SimpleAtoi(ArgS(args, 1), &options.total_count)) {
(*cntx_)->SendError(kUintErr);
cntx_->SendError(kUintErr);
return nullopt;
}
@ -414,7 +416,7 @@ optional<DebugCmd::PopulateOptions> DebugCmd::ParsePopulateArgs(CmdArgList args)
if (args.size() > 3) {
if (!absl::SimpleAtoi(ArgS(args, 3), &options.val_size)) {
(*cntx_)->SendError(kUintErr);
cntx_->SendError(kUintErr);
return nullopt;
}
}
@ -426,7 +428,7 @@ optional<DebugCmd::PopulateOptions> DebugCmd::ParsePopulateArgs(CmdArgList args)
options.populate_random_values = true;
} else if (str == "SLOTS") {
if (args.size() < index + 3) {
(*cntx_)->SendError(kSyntaxErr);
cntx_->SendError(kSyntaxErr);
return nullopt;
}
@ -443,19 +445,19 @@ optional<DebugCmd::PopulateOptions> DebugCmd::ParsePopulateArgs(CmdArgList args)
auto start = parse_slot(ArgS(args, ++index));
if (start.status() != facade::OpStatus::OK) {
(*cntx_)->SendError(start.status());
cntx_->SendError(start.status());
return nullopt;
}
auto end = parse_slot(ArgS(args, ++index));
if (end.status() != facade::OpStatus::OK) {
(*cntx_)->SendError(end.status());
cntx_->SendError(end.status());
return nullopt;
}
options.slot_range = ClusterConfig::SlotRange{.start = static_cast<SlotId>(start.value()),
.end = static_cast<SlotId>(end.value())};
} else {
(*cntx_)->SendError(kSyntaxErr);
cntx_->SendError(kSyntaxErr);
return nullopt;
}
}
@ -491,7 +493,7 @@ void DebugCmd::Populate(CmdArgList args) {
for (auto& fb : fb_arr)
fb.Join();
(*cntx_)->SendOk();
cntx_->SendOk();
}
void DebugCmd::PopulateRangeFiber(uint64_t from, uint64_t num_of_keys,
@ -607,7 +609,7 @@ void DebugCmd::Inspect(string_view key) {
string resp;
if (!res.found) {
(*cntx_)->SendError(kKeyNotFoundErr);
cntx_->SendError(kKeyNotFoundErr);
return;
}
@ -625,7 +627,7 @@ void DebugCmd::Inspect(string_view key) {
if (res.lock_status != ObjInfo::NONE) {
StrAppend(&resp, " lock:", res.lock_status == ObjInfo::X ? "x" : "s");
}
(*cntx_)->SendSimpleString(resp);
cntx_->SendSimpleString(resp);
}
void DebugCmd::Watched() {
@ -647,12 +649,13 @@ void DebugCmd::Watched() {
}
};
auto* rb = static_cast<RedisReplyBuilder*>(cntx_->reply_builder());
shard_set->RunBlockingInParallel(cb);
(*cntx_)->StartArray(4);
(*cntx_)->SendBulkString("awaked");
(*cntx_)->SendStringArr(awaked_trans);
(*cntx_)->SendBulkString("watched");
(*cntx_)->SendStringArr(watched_keys);
rb->StartArray(4);
rb->SendBulkString("awaked");
rb->SendStringArr(awaked_trans);
rb->SendBulkString("watched");
rb->SendStringArr(watched_keys);
}
void DebugCmd::TxAnalysis() {
@ -708,8 +711,8 @@ void DebugCmd::TxAnalysis() {
shard_set->RunBriefInParallel(cb);
(*cntx_)->SendSimpleString(absl::StrCat("queue_len:", queue_len.load(),
"armed: ", armed_cnt.load(), " free:", free_cnt.load()));
cntx_->SendSimpleString(absl::StrCat("queue_len:", queue_len.load(), "armed: ", armed_cnt.load(),
" free:", free_cnt.load()));
}
void DebugCmd::ObjHist() {
@ -735,7 +738,8 @@ void DebugCmd::ObjHist() {
}
absl::StrAppend(&result, "___end object histogram___\n");
(*cntx_)->SendBulkString(result);
auto* rb = static_cast<RedisReplyBuilder*>(cntx_->reply_builder());
rb->SendBulkString(result);
}
void DebugCmd::Stacktrace() {
@ -744,7 +748,7 @@ void DebugCmd::Stacktrace() {
std::unique_lock lk(m);
fb2::detail::FiberInterface::PrintAllFiberStackTraces();
});
(*cntx_)->SendOk();
cntx_->SendOk();
}
void DebugCmd::Shards() {
@ -798,8 +802,8 @@ void DebugCmd::Shards() {
#undef ADD_STAT
#undef MAXMIN_STAT
(*cntx_)->SendBulkString(out);
auto* rb = static_cast<RedisReplyBuilder*>(cntx_->reply_builder());
rb->SendBulkString(out);
}
} // namespace dfly

View file

@ -105,8 +105,6 @@ DflyCmd::DflyCmd(ServerFamily* server_family) : sf_(server_family) {
}
void DflyCmd::Run(CmdArgList args, ConnectionContext* cntx) {
RedisReplyBuilder* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
DCHECK_GE(args.size(), 1u);
ToUpper(&args[0]);
string_view sub_cmd = ArgS(args, 0);
@ -143,7 +141,7 @@ void DflyCmd::Run(CmdArgList args, ConnectionContext* cntx) {
return ReplicaOffset(args, cntx);
}
rb->SendError(kSyntaxErr);
cntx->SendError(kSyntaxErr);
}
#if 0
@ -395,7 +393,7 @@ void DflyCmd::TakeOver(CmdArgList args, ConnectionContext* cntx) {
parser.Next();
float timeout = parser.Next<float>();
if (timeout < 0) {
return (*cntx)->SendError("timeout is negative");
return cntx->SendError("timeout is negative");
}
bool save_flag = static_cast<bool>(parser.Check("SAVE").IgnoreCase());
@ -403,7 +401,7 @@ void DflyCmd::TakeOver(CmdArgList args, ConnectionContext* cntx) {
string_view sync_id_str = parser.Next<std::string_view>();
if (auto err = parser.Error(); err)
return (*cntx)->SendError(err->MakeReply());
return cntx->SendError(err->MakeReply());
VLOG(1) << "Got DFLY TAKEOVER " << sync_id_str << " time out:" << timeout;
@ -479,7 +477,7 @@ void DflyCmd::TakeOver(CmdArgList args, ConnectionContext* cntx) {
sf_->service().SwitchState(GlobalState::TAKEN_OVER, GlobalState::ACTIVE);
return rb->SendError("Takeover failed!");
}
(*cntx)->SendOk();
cntx->SendOk();
if (save_flag) {
VLOG(1) << "Save snapshot after Takeover.";

View file

@ -687,24 +687,25 @@ void GenericFamily::Del(CmdArgList args, ConnectionContext* cntx) {
mc_builder->SendSimpleString("DELETED");
}
} else {
(*cntx)->SendLong(del_cnt);
cntx->SendLong(del_cnt);
}
}
void GenericFamily::Ping(CmdArgList args, ConnectionContext* cntx) {
if (args.size() > 1) {
return (*cntx)->SendError(facade::WrongNumArgsError("ping"), kSyntaxErrType);
return cntx->SendError(facade::WrongNumArgsError("ping"), kSyntaxErrType);
}
// We synchronously block here until the engine sends us the payload and notifies that
// the I/O operation has been processed.
if (args.size() == 0) {
return (*cntx)->SendSimpleString("PONG");
return cntx->SendSimpleString("PONG");
} else {
string_view arg = ArgS(args, 0);
DVLOG(2) << "Ping " << arg;
return (*cntx)->SendBulkString(arg);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
return rb->SendBulkString(arg);
}
}
@ -725,7 +726,7 @@ void GenericFamily::Exists(CmdArgList args, ConnectionContext* cntx) {
OpStatus status = transaction->ScheduleSingleHop(std::move(cb));
CHECK_EQ(OpStatus::OK, status);
return (*cntx)->SendLong(result.load(memory_order_acquire));
return cntx->SendLong(result.load(memory_order_acquire));
}
void GenericFamily::Persist(CmdArgList args, ConnectionContext* cntx) {
@ -735,9 +736,9 @@ void GenericFamily::Persist(CmdArgList args, ConnectionContext* cntx) {
OpStatus status = cntx->transaction->ScheduleSingleHop(move(cb));
if (status == OpStatus::OK)
(*cntx)->SendLong(1);
cntx->SendLong(1);
else
(*cntx)->SendLong(0);
cntx->SendLong(0);
}
std::optional<int32_t> ParseExpireOptionsOrReply(const CmdArgList args, ConnectionContext* cntx) {
@ -754,16 +755,16 @@ std::optional<int32_t> ParseExpireOptionsOrReply(const CmdArgList args, Connecti
} else if (arg_sv == "LT") {
flags |= ExpireFlags::EXPIRE_LT;
} else {
(*cntx)->SendError(absl::StrCat("Unsupported option: ", arg_sv));
cntx->SendError(absl::StrCat("Unsupported option: ", arg_sv));
return nullopt;
}
}
if ((flags & ExpireFlags::EXPIRE_NX) && (flags & ~ExpireFlags::EXPIRE_NX)) {
(*cntx)->SendError("NX and XX, GT or LT options at the same time are not compatible");
cntx->SendError("NX and XX, GT or LT options at the same time are not compatible");
return nullopt;
}
if ((flags & ExpireFlags::EXPIRE_GT) && (flags & ExpireFlags::EXPIRE_LT)) {
(*cntx)->SendError("GT and LT options at the same time are not compatible");
cntx->SendError("GT and LT options at the same time are not compatible");
return nullopt;
}
return flags;
@ -775,11 +776,11 @@ void GenericFamily::Expire(CmdArgList args, ConnectionContext* cntx) {
int64_t int_arg;
if (!absl::SimpleAtoi(sec, &int_arg)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
if (int_arg > kMaxExpireDeadlineSec || int_arg < -kMaxExpireDeadlineSec) {
return (*cntx)->SendError(InvalidExpireTime(cntx->cid->name()));
return cntx->SendError(InvalidExpireTime(cntx->cid->name()));
}
int_arg = std::max<int64_t>(int_arg, -1);
@ -794,7 +795,7 @@ void GenericFamily::Expire(CmdArgList args, ConnectionContext* cntx) {
};
OpStatus status = cntx->transaction->ScheduleSingleHop(move(cb));
(*cntx)->SendLong(status == OpStatus::OK);
cntx->SendLong(status == OpStatus::OK);
}
void GenericFamily::ExpireAt(CmdArgList args, ConnectionContext* cntx) {
@ -803,7 +804,7 @@ void GenericFamily::ExpireAt(CmdArgList args, ConnectionContext* cntx) {
int64_t int_arg;
if (!absl::SimpleAtoi(sec, &int_arg)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
int_arg = std::max<int64_t>(int_arg, 0L);
@ -820,9 +821,9 @@ void GenericFamily::ExpireAt(CmdArgList args, ConnectionContext* cntx) {
OpStatus status = cntx->transaction->ScheduleSingleHop(std::move(cb));
if (status == OpStatus::OUT_OF_RANGE) {
return (*cntx)->SendError(kExpiryOutOfRange);
return cntx->SendError(kExpiryOutOfRange);
} else {
(*cntx)->SendLong(status == OpStatus::OK);
cntx->SendLong(status == OpStatus::OK);
}
}
@ -841,9 +842,10 @@ void GenericFamily::Keys(CmdArgList args, ConnectionContext* cntx) {
cursor = ScanGeneric(cursor, scan_opts, &keys, cntx);
} while (cursor != 0 && keys.size() < output_limit);
(*cntx)->StartArray(keys.size());
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->StartArray(keys.size());
for (const auto& k : keys) {
(*cntx)->SendBulkString(k);
rb->SendBulkString(k);
}
}
@ -853,7 +855,7 @@ void GenericFamily::PexpireAt(CmdArgList args, ConnectionContext* cntx) {
int64_t int_arg;
if (!absl::SimpleAtoi(msec, &int_arg)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
int_arg = std::max<int64_t>(int_arg, 0L);
auto expire_options = ParseExpireOptionsOrReply(args.subspan(2), cntx);
@ -871,9 +873,9 @@ void GenericFamily::PexpireAt(CmdArgList args, ConnectionContext* cntx) {
OpStatus status = cntx->transaction->ScheduleSingleHop(std::move(cb));
if (status == OpStatus::OUT_OF_RANGE) {
return (*cntx)->SendError(kExpiryOutOfRange);
return cntx->SendError(kExpiryOutOfRange);
} else {
(*cntx)->SendLong(status == OpStatus::OK);
cntx->SendLong(status == OpStatus::OK);
}
}
@ -883,7 +885,7 @@ void GenericFamily::Pexpire(CmdArgList args, ConnectionContext* cntx) {
int64_t int_arg;
if (!absl::SimpleAtoi(msec, &int_arg)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
int_arg = std::max<int64_t>(int_arg, 0L);
auto expire_options = ParseExpireOptionsOrReply(args.subspan(2), cntx);
@ -899,9 +901,9 @@ void GenericFamily::Pexpire(CmdArgList args, ConnectionContext* cntx) {
OpStatus status = cntx->transaction->ScheduleSingleHop(std::move(cb));
if (status == OpStatus::OUT_OF_RANGE) {
return (*cntx)->SendError(kExpiryOutOfRange);
return cntx->SendError(kExpiryOutOfRange);
} else {
(*cntx)->SendLong(status == OpStatus::OK);
cntx->SendLong(status == OpStatus::OK);
}
}
@ -925,7 +927,7 @@ void GenericFamily::Stick(CmdArgList args, ConnectionContext* cntx) {
DVLOG(2) << "Stick ts " << transaction->txid();
uint32_t match_cnt = result.load(memory_order_relaxed);
(*cntx)->SendLong(match_cnt);
cntx->SendLong(match_cnt);
}
// Used to conditionally store double score
@ -1045,11 +1047,11 @@ void GenericFamily::Sort(CmdArgList args, ConnectionContext* cntx) {
} else if (arg == "LIMIT") {
int offset, limit;
if (i + 2 >= args.size()) {
return (*cntx)->SendError(kSyntaxErr);
return cntx->SendError(kSyntaxErr);
}
if (!absl::SimpleAtoi(ArgS(args, i + 1), &offset) ||
!absl::SimpleAtoi(ArgS(args, i + 2), &limit)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
bounds = {offset, limit};
i += 2;
@ -1062,10 +1064,11 @@ void GenericFamily::Sort(CmdArgList args, ConnectionContext* cntx) {
});
if (fetch_result.status() == OpStatus::WRONG_TYPE)
return (*cntx)->SendError("One or more scores can't be converted into double");
return cntx->SendError("One or more scores can't be converted into double");
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
if (!fetch_result.ok())
return (*cntx)->SendEmptyArray();
return rb->SendEmptyArray();
auto result_type = fetch_result.type();
auto sort_call = [cntx, bounds, reversed, result_type](auto& entries) {
@ -1089,11 +1092,12 @@ void GenericFamily::Sort(CmdArgList args, ConnectionContext* cntx) {
}
bool is_set = (result_type == OBJ_SET || result_type == OBJ_ZSET);
(*cntx)->StartCollection(std::distance(start_it, end_it),
is_set ? RedisReplyBuilder::SET : RedisReplyBuilder::ARRAY);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->StartCollection(std::distance(start_it, end_it),
is_set ? RedisReplyBuilder::SET : RedisReplyBuilder::ARRAY);
for (auto it = start_it; it != end_it; ++it) {
(*cntx)->SendBulkString(it->key);
rb->SendBulkString(it->key);
}
};
std::visit(std::move(sort_call), fetch_result.value());
@ -1104,15 +1108,15 @@ void GenericFamily::Restore(CmdArgList args, ConnectionContext* cntx) {
std::string_view serialized_value = ArgS(args, 2);
int rdb_version = 0;
if (!VerifyFooter(serialized_value, &rdb_version)) {
return (*cntx)->SendError("ERR DUMP payload version or checksum are wrong");
return cntx->SendError("ERR DUMP payload version or checksum are wrong");
}
OpResult<RestoreArgs> restore_args = RestoreArgs::TryFrom(args);
if (!restore_args) {
if (restore_args.status() == OpStatus::OUT_OF_RANGE) {
return (*cntx)->SendError("Invalid IDLETIME value, must be >= 0");
return cntx->SendError("Invalid IDLETIME value, must be >= 0");
} else {
return (*cntx)->SendError(restore_args.status());
return cntx->SendError(restore_args.status());
}
}
@ -1124,18 +1128,18 @@ void GenericFamily::Restore(CmdArgList args, ConnectionContext* cntx) {
if (result) {
if (result.value()) {
return (*cntx)->SendOk();
return cntx->SendOk();
} else {
return (*cntx)->SendError("Bad data format");
return cntx->SendError("Bad data format");
}
} else {
switch (result.status()) {
case OpStatus::KEY_EXISTS:
return (*cntx)->SendError("BUSYKEY: key name already exists.");
return cntx->SendError("BUSYKEY: key name already exists.");
case OpStatus::WRONG_TYPE:
return (*cntx)->SendError("Bad data format");
return cntx->SendError("Bad data format");
default:
return (*cntx)->SendError(result.status());
return cntx->SendError(result.status());
}
}
}
@ -1151,11 +1155,11 @@ void GenericFamily::FieldTtl(CmdArgList args, ConnectionContext* cntx) {
OpResult<long> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
if (result) {
(*cntx)->SendLong(*result);
cntx->SendLong(*result);
return;
}
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
void GenericFamily::Move(CmdArgList args, ConnectionContext* cntx) {
@ -1164,15 +1168,15 @@ void GenericFamily::Move(CmdArgList args, ConnectionContext* cntx) {
int64_t target_db;
if (!absl::SimpleAtoi(target_db_sv, &target_db)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
if (target_db < 0 || target_db >= absl::GetFlag(FLAGS_dbnum)) {
return (*cntx)->SendError(kDbIndOutOfRangeErr);
return cntx->SendError(kDbIndOutOfRangeErr);
}
if (target_db == cntx->db_index()) {
return (*cntx)->SendError("source and destination objects are the same");
return cntx->SendError("source and destination objects are the same");
}
OpStatus res = OpStatus::SKIPPED;
@ -1194,23 +1198,23 @@ void GenericFamily::Move(CmdArgList args, ConnectionContext* cntx) {
cntx->transaction->ScheduleSingleHop(std::move(cb));
// Exactly one shard will call OpMove.
DCHECK(res != OpStatus::SKIPPED);
(*cntx)->SendLong(res == OpStatus::OK);
cntx->SendLong(res == OpStatus::OK);
}
void GenericFamily::Rename(CmdArgList args, ConnectionContext* cntx) {
OpResult<void> st = RenameGeneric(args, false, cntx);
(*cntx)->SendError(st.status());
cntx->SendError(st.status());
}
void GenericFamily::RenameNx(CmdArgList args, ConnectionContext* cntx) {
OpResult<void> st = RenameGeneric(args, true, cntx);
OpStatus status = st.status();
if (status == OpStatus::OK) {
(*cntx)->SendLong(1);
cntx->SendLong(1);
} else if (status == OpStatus::KEY_EXISTS) {
(*cntx)->SendLong(0);
cntx->SendLong(0);
} else {
(*cntx)->SendError(status);
cntx->SendError(status);
}
}
@ -1230,18 +1234,18 @@ void GenericFamily::TtlGeneric(CmdArgList args, ConnectionContext* cntx, TimeUni
if (result) {
long ttl = (unit == TimeUnit::SEC) ? (result.value() + 500) / 1000 : result.value();
(*cntx)->SendLong(ttl);
cntx->SendLong(ttl);
return;
}
switch (result.status()) {
case OpStatus::KEY_NOTFOUND:
(*cntx)->SendLong(-2);
cntx->SendLong(-2);
break;
default:
LOG_IF(ERROR, result.status() != OpStatus::SKIPPED)
<< "Unexpected status " << result.status();
(*cntx)->SendLong(-1);
cntx->SendLong(-1);
break;
}
}
@ -1250,13 +1254,13 @@ void GenericFamily::Select(CmdArgList args, ConnectionContext* cntx) {
string_view key = ArgS(args, 0);
int64_t index;
if (!absl::SimpleAtoi(key, &index)) {
return (*cntx)->SendError(kInvalidDbIndErr);
return cntx->SendError(kInvalidDbIndErr);
}
if (ClusterConfig::IsEnabled() && 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)) {
return (*cntx)->SendError(kDbIndOutOfRangeErr);
return cntx->SendError(kDbIndOutOfRangeErr);
}
cntx->conn_state.db_index = index;
auto cb = [index](EngineShard* shard) {
@ -1265,7 +1269,7 @@ void GenericFamily::Select(CmdArgList args, ConnectionContext* cntx) {
};
shard_set->RunBriefInParallel(std::move(cb));
return (*cntx)->SendOk();
return cntx->SendOk();
}
void GenericFamily::Dump(CmdArgList args, ConnectionContext* cntx) {
@ -1275,12 +1279,13 @@ void GenericFamily::Dump(CmdArgList args, ConnectionContext* cntx) {
Transaction* trans = cntx->transaction;
OpResult<string> result = trans->ScheduleSingleHopT(std::move(cb));
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
if (result) {
DVLOG(1) << "Dump " << trans->DebugId() << ": " << key << ", dump size "
<< result.value().size();
(*cntx)->SendBulkString(*result);
rb->SendBulkString(*result);
} else {
(*cntx)->SendNull();
rb->SendNull();
}
}
@ -1297,9 +1302,9 @@ void GenericFamily::Type(CmdArgList args, ConnectionContext* cntx) {
};
OpResult<int> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
if (!result) {
(*cntx)->SendSimpleString("none");
cntx->SendSimpleString("none");
} else {
(*cntx)->SendSimpleString(ObjTypeName(result.value()));
cntx->SendSimpleString(ObjTypeName(result.value()));
}
}
@ -1311,9 +1316,10 @@ void GenericFamily::Time(CmdArgList args, ConnectionContext* cntx) {
now_usec = absl::GetCurrentTimeNanos() / 1000;
}
(*cntx)->StartArray(2);
(*cntx)->SendLong(now_usec / 1000000);
(*cntx)->SendLong(now_usec % 1000000);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->StartArray(2);
rb->SendLong(now_usec / 1000000);
rb->SendLong(now_usec % 1000000);
}
OpResult<void> GenericFamily::RenameGeneric(CmdArgList args, bool skip_exist_dest,
@ -1349,7 +1355,8 @@ OpResult<void> GenericFamily::RenameGeneric(CmdArgList args, bool skip_exist_des
void GenericFamily::Echo(CmdArgList args, ConnectionContext* cntx) {
string_view key = ArgS(args, 0);
return (*cntx)->SendBulkString(key);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
return rb->SendBulkString(key);
}
void GenericFamily::Scan(CmdArgList args, ConnectionContext* cntx) {
@ -1357,13 +1364,13 @@ void GenericFamily::Scan(CmdArgList args, ConnectionContext* cntx) {
uint64_t cursor = 0;
if (!absl::SimpleAtoi(token, &cursor)) {
return (*cntx)->SendError("invalid cursor");
return cntx->SendError("invalid cursor");
}
OpResult<ScanOpts> ops = ScanOpts::TryFrom(args.subspan(1));
if (!ops) {
DVLOG(1) << "Scan invalid args - return " << ops << " to the user";
return (*cntx)->SendError(ops.status());
return cntx->SendError(ops.status());
}
ScanOpts scan_op = ops.value();
@ -1371,11 +1378,12 @@ void GenericFamily::Scan(CmdArgList args, ConnectionContext* cntx) {
StringVec keys;
cursor = ScanGeneric(cursor, scan_op, &keys, cntx);
(*cntx)->StartArray(2);
(*cntx)->SendBulkString(absl::StrCat(cursor));
(*cntx)->StartArray(keys.size());
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->StartArray(2);
rb->SendBulkString(absl::StrCat(cursor));
rb->StartArray(keys.size());
for (const auto& k : keys) {
(*cntx)->SendBulkString(k);
rb->SendBulkString(k);
}
}

View file

@ -32,20 +32,20 @@ template <typename T> void HandleOpValueResult(const OpResult<T>& result, Connec
"we are only handling types that are integral types in the return types from "
"here");
if (result) {
(*cntx)->SendLong(result.value());
cntx->SendLong(result.value());
} else {
switch (result.status()) {
case OpStatus::WRONG_TYPE:
(*cntx)->SendError(kWrongTypeErr);
cntx->SendError(kWrongTypeErr);
break;
case OpStatus::OUT_OF_MEMORY:
(*cntx)->SendError(kOutOfMemory);
cntx->SendError(kOutOfMemory);
break;
case OpStatus::INVALID_VALUE:
(*cntx)->SendError(HllFamily::kInvalidHllErr);
cntx->SendError(HllFamily::kInvalidHllErr);
break;
default:
(*cntx)->SendLong(0); // in case we don't have the value we should just send 0
cntx->SendLong(0); // in case we don't have the value we should just send 0
break;
}
}
@ -275,9 +275,9 @@ void PFMerge(CmdArgList args, ConnectionContext* cntx) {
OpResult<int> result = PFMergeInternal(args, cntx);
if (result.ok()) {
if (result.value() == 0) {
(*cntx)->SendOk();
cntx->SendOk();
} else {
(*cntx)->SendError(HllFamily::kInvalidHllErr);
cntx->SendError(HllFamily::kInvalidHllErr);
}
} else {
HandleOpValueResult(result, cntx);

View file

@ -709,19 +709,20 @@ void HGetGeneric(CmdArgList args, ConnectionContext* cntx, uint8_t getall_mask)
OpResult<vector<string>> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
if (result) {
bool is_map = (getall_mask == (VALUES | FIELDS));
(*cntx)->SendStringArr(absl::Span<const string>{*result},
is_map ? RedisReplyBuilder::MAP : RedisReplyBuilder::ARRAY);
rb->SendStringArr(absl::Span<const string>{*result},
is_map ? RedisReplyBuilder::MAP : RedisReplyBuilder::ARRAY);
} else {
(*cntx)->SendError(result.status());
rb->SendError(result.status());
}
}
// HSETEX key tll_sec field value field value ...
void HSetEx(CmdArgList args, ConnectionContext* cntx) {
if (args.size() % 2 != 0) {
return (*cntx)->SendError(facade::WrongNumArgsError(cntx->cid->name()), kSyntaxErrType);
return cntx->SendError(facade::WrongNumArgsError(cntx->cid->name()), kSyntaxErrType);
}
string_view key = ArgS(args, 0);
@ -730,7 +731,7 @@ void HSetEx(CmdArgList args, ConnectionContext* cntx) {
constexpr uint32_t kMaxTtl = (1UL << 26);
if (!absl::SimpleAtoi(ttl_str, &ttl_sec) || ttl_sec == 0 || ttl_sec > kMaxTtl) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
args.remove_prefix(2);
@ -743,9 +744,9 @@ void HSetEx(CmdArgList args, ConnectionContext* cntx) {
OpResult<uint32_t> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
if (result) {
(*cntx)->SendLong(*result);
cntx->SendLong(*result);
} else {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
}
@ -761,9 +762,9 @@ void HSetFamily::HDel(CmdArgList args, ConnectionContext* cntx) {
OpResult<uint32_t> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
if (result || result.status() == OpStatus::KEY_NOTFOUND) {
(*cntx)->SendLong(*result);
cntx->SendLong(*result);
} else {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
}
@ -774,9 +775,9 @@ void HSetFamily::HLen(CmdArgList args, ConnectionContext* cntx) {
OpResult<uint32_t> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
if (result) {
(*cntx)->SendLong(*result);
cntx->SendLong(*result);
} else {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
}
@ -790,9 +791,9 @@ void HSetFamily::HExists(CmdArgList args, ConnectionContext* cntx) {
OpResult<int> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
if (result) {
(*cntx)->SendLong(*result);
cntx->SendLong(*result);
} else {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
}
@ -806,26 +807,27 @@ void HSetFamily::HMGet(CmdArgList args, ConnectionContext* cntx) {
OpResult<vector<OptStr>> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
if (result) {
SinkReplyBuilder::ReplyAggregator agg(cntx->reply_builder());
(*cntx)->StartArray(result->size());
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->StartArray(result->size());
for (const auto& val : *result) {
if (val) {
(*cntx)->SendBulkString(*val);
rb->SendBulkString(*val);
} else {
(*cntx)->SendNull();
rb->SendNull();
}
}
} else if (result.status() == OpStatus::KEY_NOTFOUND) {
SinkReplyBuilder::ReplyAggregator agg(cntx->reply_builder());
(*cntx)->StartArray(args.size());
rb->StartArray(args.size());
for (unsigned i = 0; i < args.size(); ++i) {
(*cntx)->SendNull();
rb->SendNull();
}
} else {
(*cntx)->SendError(result.status());
rb->SendError(result.status());
}
}
@ -837,14 +839,15 @@ void HSetFamily::HGet(CmdArgList args, ConnectionContext* cntx) {
return OpGet(t->GetOpArgs(shard), key, field);
};
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
OpResult<string> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
if (result) {
(*cntx)->SendBulkString(*result);
rb->SendBulkString(*result);
} else {
if (result.status() == OpStatus::KEY_NOTFOUND) {
(*cntx)->SendNull();
rb->SendNull();
} else {
(*cntx)->SendError(result.status());
rb->SendError(result.status());
}
}
}
@ -856,7 +859,7 @@ void HSetFamily::HIncrBy(CmdArgList args, ConnectionContext* cntx) {
int64_t ival = 0;
if (!absl::SimpleAtoi(incrs, &ival)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
IncrByParam param{ival};
@ -868,17 +871,17 @@ void HSetFamily::HIncrBy(CmdArgList args, ConnectionContext* cntx) {
OpStatus status = cntx->transaction->ScheduleSingleHop(std::move(cb));
if (status == OpStatus::OK) {
(*cntx)->SendLong(get<int64_t>(param));
cntx->SendLong(get<int64_t>(param));
} else {
switch (status) {
case OpStatus::INVALID_VALUE:
(*cntx)->SendError("hash value is not an integer");
cntx->SendError("hash value is not an integer");
break;
case OpStatus::OUT_OF_RANGE:
(*cntx)->SendError(kIncrOverflow);
cntx->SendError(kIncrOverflow);
break;
default:
(*cntx)->SendError(status);
cntx->SendError(status);
break;
}
}
@ -891,7 +894,7 @@ void HSetFamily::HIncrByFloat(CmdArgList args, ConnectionContext* cntx) {
double dval = 0;
if (!absl::SimpleAtod(incrs, &dval)) {
return (*cntx)->SendError(kInvalidFloatErr);
return cntx->SendError(kInvalidFloatErr);
}
IncrByParam param{dval};
@ -903,14 +906,15 @@ void HSetFamily::HIncrByFloat(CmdArgList args, ConnectionContext* cntx) {
OpStatus status = cntx->transaction->ScheduleSingleHop(std::move(cb));
if (status == OpStatus::OK) {
(*cntx)->SendDouble(get<double>(param));
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->SendDouble(get<double>(param));
} else {
switch (status) {
case OpStatus::INVALID_VALUE:
(*cntx)->SendError("hash value is not a float");
cntx->SendError("hash value is not a float");
break;
default:
(*cntx)->SendError(status);
cntx->SendError(status);
break;
}
}
@ -935,19 +939,19 @@ void HSetFamily::HScan(CmdArgList args, ConnectionContext* cntx) {
uint64_t cursor = 0;
if (!absl::SimpleAtoi(token, &cursor)) {
return (*cntx)->SendError("invalid cursor");
return cntx->SendError("invalid cursor");
}
// HSCAN key cursor [MATCH pattern] [COUNT count]
if (args.size() > 6) {
DVLOG(1) << "got " << args.size() << " this is more than it should be";
return (*cntx)->SendError(kSyntaxErr);
return cntx->SendError(kSyntaxErr);
}
OpResult<ScanOpts> ops = ScanOpts::TryFrom(args.subspan(2));
if (!ops) {
DVLOG(1) << "HScan invalid args - return " << ops << " to the user";
return (*cntx)->SendError(ops.status());
return cntx->SendError(ops.status());
}
ScanOpts scan_op = ops.value();
@ -956,16 +960,17 @@ void HSetFamily::HScan(CmdArgList args, ConnectionContext* cntx) {
return OpScan(t->GetOpArgs(shard), key, &cursor, scan_op);
};
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
OpResult<StringVec> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
if (result.status() != OpStatus::WRONG_TYPE) {
(*cntx)->StartArray(2);
(*cntx)->SendBulkString(absl::StrCat(cursor));
(*cntx)->StartArray(result->size()); // Within scan the page type is array
rb->StartArray(2);
rb->SendBulkString(absl::StrCat(cursor));
rb->StartArray(result->size()); // Within scan the page type is array
for (const auto& k : *result) {
(*cntx)->SendBulkString(k);
rb->SendBulkString(k);
}
} else {
(*cntx)->SendError(result.status());
rb->SendError(result.status());
}
}
@ -975,7 +980,7 @@ void HSetFamily::HSet(CmdArgList args, ConnectionContext* cntx) {
string_view cmd{cntx->cid->name()};
if (args.size() % 2 != 1) {
return (*cntx)->SendError(facade::WrongNumArgsError(cmd), kSyntaxErrType);
return cntx->SendError(facade::WrongNumArgsError(cmd), kSyntaxErrType);
}
args.remove_prefix(1);
@ -986,9 +991,9 @@ void HSetFamily::HSet(CmdArgList args, ConnectionContext* cntx) {
OpResult<uint32_t> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
if (result && cmd == "HSET") {
(*cntx)->SendLong(*result);
cntx->SendLong(*result);
} else {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
}
@ -1002,9 +1007,9 @@ void HSetFamily::HSetNx(CmdArgList args, ConnectionContext* cntx) {
OpResult<uint32_t> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
if (result) {
(*cntx)->SendLong(*result);
cntx->SendLong(*result);
} else {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
}
@ -1018,9 +1023,9 @@ void HSetFamily::HStrLen(CmdArgList args, ConnectionContext* cntx) {
OpResult<size_t> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
if (result) {
(*cntx)->SendLong(*result);
cntx->SendLong(*result);
} else {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
}
@ -1035,7 +1040,7 @@ void StrVecEmplaceBack(StringVec& str_vec, const listpackEntry& lp) {
void HSetFamily::HRandField(CmdArgList args, ConnectionContext* cntx) {
if (args.size() > 3) {
DVLOG(1) << "Wrong number of command arguments: " << args.size();
return (*cntx)->SendError(kSyntaxErr);
return cntx->SendError(kSyntaxErr);
}
string_view key = ArgS(args, 0);
@ -1043,13 +1048,13 @@ void HSetFamily::HRandField(CmdArgList args, ConnectionContext* cntx) {
bool with_values = false;
if ((args.size() > 1) && (!SimpleAtoi(ArgS(args, 1), &count))) {
return (*cntx)->SendError("count value is not an integer", kSyntaxErrType);
return cntx->SendError("count value is not an integer", kSyntaxErrType);
}
if (args.size() == 3) {
ToUpper(&args[2]);
if (ArgS(args, 2) != "WITHVALUES")
return (*cntx)->SendError(kSyntaxErr);
return cntx->SendError(kSyntaxErr);
else
with_values = true;
}
@ -1133,13 +1138,14 @@ void HSetFamily::HRandField(CmdArgList args, ConnectionContext* cntx) {
return str_vec;
};
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
OpResult<StringVec> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
if (result) {
(*cntx)->SendStringArr(*result);
rb->SendStringArr(*result);
} else if (result.status() == OpStatus::KEY_NOTFOUND) {
(*cntx)->SendNull();
rb->SendNull();
} else {
(*cntx)->SendError(result.status());
rb->SendError(result.status());
}
}

View file

@ -98,20 +98,21 @@ JsonExpression ParseJsonPath(string_view path, error_code* ec) {
template <typename T>
void PrintOptVec(ConnectionContext* cntx, const OpResult<vector<optional<T>>>& result) {
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
if (result->empty()) {
(*cntx)->SendNullArray();
rb->SendNullArray();
} else {
(*cntx)->StartArray(result->size());
rb->StartArray(result->size());
for (auto& it : *result) {
if (it.has_value()) {
if constexpr (is_floating_point_v<T>) {
(*cntx)->SendDouble(*it);
rb->SendDouble(*it);
} else {
static_assert(is_integral_v<T>, "Integral required.");
(*cntx)->SendLong(*it);
rb->SendLong(*it);
}
} else {
(*cntx)->SendNull();
rb->SendNull();
}
}
}
@ -362,30 +363,30 @@ size_t CountJsonFields(const JsonType& j) {
return res;
}
void SendJsonValue(ConnectionContext* cntx, const JsonType& j) {
void SendJsonValue(RedisReplyBuilder* rb, const JsonType& j) {
if (j.is_double()) {
(*cntx)->SendDouble(j.as_double());
rb->SendDouble(j.as_double());
} else if (j.is_number()) {
(*cntx)->SendLong(j.as_integer<long>());
rb->SendLong(j.as_integer<long>());
} else if (j.is_bool()) {
(*cntx)->SendSimpleString(j.as_bool() ? "true" : "false");
rb->SendSimpleString(j.as_bool() ? "true" : "false");
} else if (j.is_null()) {
(*cntx)->SendNull();
rb->SendNull();
} else if (j.is_string()) {
(*cntx)->SendSimpleString(j.as_string_view());
rb->SendSimpleString(j.as_string_view());
} else if (j.is_object()) {
(*cntx)->StartArray(j.size() + 1);
(*cntx)->SendSimpleString("{");
rb->StartArray(j.size() + 1);
rb->SendSimpleString("{");
for (const auto& item : j.object_range()) {
(*cntx)->StartArray(2);
(*cntx)->SendSimpleString(item.key());
SendJsonValue(cntx, item.value());
rb->StartArray(2);
rb->SendSimpleString(item.key());
SendJsonValue(rb, item.value());
}
} else if (j.is_array()) {
(*cntx)->StartArray(j.size() + 1);
(*cntx)->SendSimpleString("[");
rb->StartArray(j.size() + 1);
rb->SendSimpleString("[");
for (const auto& item : j.array_range()) {
SendJsonValue(cntx, item);
SendJsonValue(rb, item);
}
}
}
@ -1146,7 +1147,7 @@ void JsonFamily::Set(CmdArgList args, ConnectionContext* cntx) {
} else if (absl::EqualsIgnoreCase(operation_opts, "XX")) {
is_xx_condition = true;
} else {
(*cntx)->SendError(kSyntaxErr);
cntx->SendError(kSyntaxErr);
return;
}
}
@ -1157,15 +1158,15 @@ void JsonFamily::Set(CmdArgList args, ConnectionContext* cntx) {
Transaction* trans = cntx->transaction;
OpResult<bool> result = trans->ScheduleSingleHopT(move(cb));
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
if (result) {
if (*result) {
(*cntx)->SendSimpleString("OK");
rb->SendSimpleString("OK");
} else {
(*cntx)->SendNull();
rb->SendNull();
}
} else {
(*cntx)->SendError(result.status());
rb->SendError(result.status());
}
}
@ -1181,7 +1182,7 @@ void JsonFamily::Resp(CmdArgList args, ConnectionContext* cntx) {
if (ec) {
VLOG(1) << "Invalid JSONPath syntax: " << ec.message();
(*cntx)->SendError(kSyntaxErr);
cntx->SendError(kSyntaxErr);
return;
}
@ -1192,13 +1193,14 @@ void JsonFamily::Resp(CmdArgList args, ConnectionContext* cntx) {
Transaction* trans = cntx->transaction;
OpResult<vector<JsonType>> result = trans->ScheduleSingleHopT(move(cb));
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
if (result) {
(*cntx)->StartArray(result->size());
rb->StartArray(result->size());
for (const auto& it : *result) {
SendJsonValue(cntx, it);
SendJsonValue(rb, it);
}
} else {
(*cntx)->SendError(result.status());
rb->SendError(result.status());
}
}
@ -1208,22 +1210,23 @@ void JsonFamily::Debug(CmdArgList args, ConnectionContext* cntx) {
// The 'MEMORY' sub-command is not supported yet, calling to operation function should be added
// here.
if (absl::EqualsIgnoreCase(command, "help")) {
(*cntx)->StartArray(2);
(*cntx)->SendSimpleString(
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->StartArray(2);
rb->SendSimpleString(
"JSON.DEBUG FIELDS <key> <path> - report number of fields in the JSON element.");
(*cntx)->SendSimpleString("JSON.DEBUG HELP - print help message.");
rb->SendSimpleString("JSON.DEBUG HELP - print help message.");
return;
} else if (absl::EqualsIgnoreCase(command, "fields")) {
func = &OpFields;
} else {
(*cntx)->SendError(facade::UnknownSubCmd(command, "JSON.DEBUG"), facade::kSyntaxErrType);
cntx->SendError(facade::UnknownSubCmd(command, "JSON.DEBUG"), facade::kSyntaxErrType);
return;
}
if (args.size() < 3) {
(*cntx)->SendError(facade::WrongNumArgsError(cntx->cid->name()), facade::kSyntaxErrType);
cntx->SendError(facade::WrongNumArgsError(cntx->cid->name()), facade::kSyntaxErrType);
return;
}
@ -1234,7 +1237,7 @@ void JsonFamily::Debug(CmdArgList args, ConnectionContext* cntx) {
if (ec) {
VLOG(1) << "Invalid JSONPath syntax: " << ec.message();
(*cntx)->SendError(kSyntaxErr);
cntx->SendError(kSyntaxErr);
return;
}
@ -1248,7 +1251,7 @@ void JsonFamily::Debug(CmdArgList args, ConnectionContext* cntx) {
if (result) {
PrintOptVec(cntx, result);
} else {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
}
@ -1261,7 +1264,7 @@ void JsonFamily::MGet(CmdArgList args, ConnectionContext* cntx) {
if (ec) {
VLOG(1) << "Invalid JSONPath syntax: " << ec.message();
(*cntx)->SendError(kSyntaxErr);
cntx->SendError(kSyntaxErr);
return;
}
@ -1298,12 +1301,13 @@ void JsonFamily::MGet(CmdArgList args, ConnectionContext* cntx) {
}
}
(*cntx)->StartArray(results.size());
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->StartArray(results.size());
for (auto& it : results) {
if (!it) {
(*cntx)->SendNull();
rb->SendNull();
} else {
(*cntx)->SendBulkString(*it);
rb->SendBulkString(*it);
}
}
}
@ -1317,18 +1321,18 @@ void JsonFamily::ArrIndex(CmdArgList args, ConnectionContext* cntx) {
if (ec) {
VLOG(1) << "Invalid JSONPath syntax: " << ec.message();
(*cntx)->SendError(kSyntaxErr);
cntx->SendError(kSyntaxErr);
return;
}
optional<JsonType> search_value = JsonFromString(ArgS(args, 2));
if (!search_value) {
(*cntx)->SendError(kSyntaxErr);
cntx->SendError(kSyntaxErr);
return;
}
if (search_value->is_object() || search_value->is_array()) {
(*cntx)->SendError(kWrongTypeErr);
cntx->SendError(kWrongTypeErr);
return;
}
@ -1336,7 +1340,7 @@ void JsonFamily::ArrIndex(CmdArgList args, ConnectionContext* cntx) {
if (args.size() >= 4) {
if (!absl::SimpleAtoi(ArgS(args, 3), &start_index)) {
VLOG(1) << "Failed to convert the start index to numeric" << ArgS(args, 3);
(*cntx)->SendError(kInvalidIntErr);
cntx->SendError(kInvalidIntErr);
return;
}
}
@ -1345,7 +1349,7 @@ void JsonFamily::ArrIndex(CmdArgList args, ConnectionContext* cntx) {
if (args.size() >= 5) {
if (!absl::SimpleAtoi(ArgS(args, 4), &end_index)) {
VLOG(1) << "Failed to convert the stop index to numeric" << ArgS(args, 4);
(*cntx)->SendError(kInvalidIntErr);
cntx->SendError(kInvalidIntErr);
return;
}
}
@ -1361,7 +1365,7 @@ void JsonFamily::ArrIndex(CmdArgList args, ConnectionContext* cntx) {
if (result) {
PrintOptVec(cntx, result);
} else {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
}
@ -1372,7 +1376,7 @@ void JsonFamily::ArrInsert(CmdArgList args, ConnectionContext* cntx) {
if (!absl::SimpleAtoi(ArgS(args, 2), &index)) {
VLOG(1) << "Failed to convert the following value to numeric: " << ArgS(args, 2);
(*cntx)->SendError(kInvalidIntErr);
cntx->SendError(kInvalidIntErr);
return;
}
@ -1380,7 +1384,7 @@ void JsonFamily::ArrInsert(CmdArgList args, ConnectionContext* cntx) {
for (size_t i = 3; i < args.size(); i++) {
optional<JsonType> val = JsonFromString(ArgS(args, i));
if (!val) {
(*cntx)->SendError(kSyntaxErr);
cntx->SendError(kSyntaxErr);
return;
}
@ -1396,7 +1400,7 @@ void JsonFamily::ArrInsert(CmdArgList args, ConnectionContext* cntx) {
if (result) {
PrintOptVec(cntx, result);
} else {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
}
@ -1407,7 +1411,7 @@ void JsonFamily::ArrAppend(CmdArgList args, ConnectionContext* cntx) {
for (size_t i = 2; i < args.size(); ++i) {
optional<JsonType> converted_val = JsonFromString(ArgS(args, i));
if (!converted_val) {
(*cntx)->SendError(kSyntaxErr);
cntx->SendError(kSyntaxErr);
return;
}
append_values.emplace_back(converted_val);
@ -1422,7 +1426,7 @@ void JsonFamily::ArrAppend(CmdArgList args, ConnectionContext* cntx) {
if (result) {
PrintOptVec(cntx, result);
} else {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
}
@ -1434,18 +1438,18 @@ void JsonFamily::ArrTrim(CmdArgList args, ConnectionContext* cntx) {
if (!absl::SimpleAtoi(ArgS(args, 2), &start_index)) {
VLOG(1) << "Failed to parse array start index";
(*cntx)->SendError(kInvalidIntErr);
cntx->SendError(kInvalidIntErr);
return;
}
if (!absl::SimpleAtoi(ArgS(args, 3), &stop_index)) {
VLOG(1) << "Failed to parse array stop index";
(*cntx)->SendError(kInvalidIntErr);
cntx->SendError(kInvalidIntErr);
return;
}
if (stop_index < 0) {
(*cntx)->SendError(kInvalidIntErr);
cntx->SendError(kInvalidIntErr);
return;
}
@ -1458,7 +1462,7 @@ void JsonFamily::ArrTrim(CmdArgList args, ConnectionContext* cntx) {
if (result) {
PrintOptVec(cntx, result);
} else {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
}
@ -1479,7 +1483,7 @@ void JsonFamily::ArrPop(CmdArgList args, ConnectionContext* cntx) {
if (ec) {
VLOG(1) << "Invalid JSONPath syntax: " << ec.message();
(*cntx)->SendError(kSyntaxErr);
cntx->SendError(kSyntaxErr);
return;
}
@ -1489,17 +1493,18 @@ void JsonFamily::ArrPop(CmdArgList args, ConnectionContext* cntx) {
Transaction* trans = cntx->transaction;
OpResult<vector<OptString>> result = trans->ScheduleSingleHopT(move(cb));
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
if (result) {
(*cntx)->StartArray(result->size());
rb->StartArray(result->size());
for (auto& it : *result) {
if (!it) {
(*cntx)->SendNull();
rb->SendNull();
} else {
(*cntx)->SendSimpleString(*it);
rb->SendSimpleString(*it);
}
}
} else {
(*cntx)->SendError(result.status());
rb->SendError(result.status());
}
}
@ -1515,9 +1520,9 @@ void JsonFamily::Clear(CmdArgList args, ConnectionContext* cntx) {
OpResult<long> result = trans->ScheduleSingleHopT(move(cb));
if (result) {
(*cntx)->SendLong(*result);
cntx->SendLong(*result);
} else {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
}
@ -1540,7 +1545,7 @@ void JsonFamily::StrAppend(CmdArgList args, ConnectionContext* cntx) {
if (result) {
PrintOptVec(cntx, result);
} else {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
}
@ -1553,7 +1558,7 @@ void JsonFamily::ObjKeys(CmdArgList args, ConnectionContext* cntx) {
if (ec) {
VLOG(1) << "Invalid JSONPath syntax: " << ec.message();
(*cntx)->SendError(kSyntaxErr);
cntx->SendError(kSyntaxErr);
return;
}
@ -1563,18 +1568,18 @@ void JsonFamily::ObjKeys(CmdArgList args, ConnectionContext* cntx) {
Transaction* trans = cntx->transaction;
OpResult<vector<StringVec>> result = trans->ScheduleSingleHopT(move(cb));
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
if (result) {
(*cntx)->StartArray(result->size());
rb->StartArray(result->size());
for (auto& it : *result) {
if (it.empty()) {
(*cntx)->SendNullArray();
rb->SendNullArray();
} else {
(*cntx)->SendStringArr(it);
rb->SendStringArr(it);
}
}
} else {
(*cntx)->SendError(result.status());
rb->SendError(result.status());
}
}
@ -1591,7 +1596,7 @@ void JsonFamily::Del(CmdArgList args, ConnectionContext* cntx) {
Transaction* trans = cntx->transaction;
OpResult<long> result = trans->ScheduleSingleHopT(move(cb));
(*cntx)->SendLong(*result);
cntx->SendLong(*result);
}
void JsonFamily::NumIncrBy(CmdArgList args, ConnectionContext* cntx) {
@ -1601,7 +1606,7 @@ void JsonFamily::NumIncrBy(CmdArgList args, ConnectionContext* cntx) {
double dnum;
if (!ParseDouble(num, &dnum)) {
(*cntx)->SendError(kWrongTypeErr);
cntx->SendError(kWrongTypeErr);
return;
}
@ -1613,9 +1618,9 @@ void JsonFamily::NumIncrBy(CmdArgList args, ConnectionContext* cntx) {
OpResult<string> result = trans->ScheduleSingleHopT(move(cb));
if (result) {
(*cntx)->SendSimpleString(*result);
cntx->SendSimpleString(*result);
} else {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
}
@ -1626,7 +1631,7 @@ void JsonFamily::NumMultBy(CmdArgList args, ConnectionContext* cntx) {
double dnum;
if (!ParseDouble(num, &dnum)) {
(*cntx)->SendError(kWrongTypeErr);
cntx->SendError(kWrongTypeErr);
return;
}
@ -1638,9 +1643,9 @@ void JsonFamily::NumMultBy(CmdArgList args, ConnectionContext* cntx) {
OpResult<string> result = trans->ScheduleSingleHopT(move(cb));
if (result) {
(*cntx)->SendSimpleString(*result);
cntx->SendSimpleString(*result);
} else {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
}
@ -1658,7 +1663,7 @@ void JsonFamily::Toggle(CmdArgList args, ConnectionContext* cntx) {
if (result) {
PrintOptVec(cntx, result);
} else {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
}
@ -1671,7 +1676,7 @@ void JsonFamily::Type(CmdArgList args, ConnectionContext* cntx) {
if (ec) {
VLOG(1) << "Invalid JSONPath syntax: " << ec.message();
(*cntx)->SendError(kSyntaxErr);
cntx->SendError(kSyntaxErr);
return;
}
@ -1681,19 +1686,19 @@ void JsonFamily::Type(CmdArgList args, ConnectionContext* cntx) {
Transaction* trans = cntx->transaction;
OpResult<vector<string>> result = trans->ScheduleSingleHopT(move(cb));
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
if (result) {
if (result->empty()) {
// When vector is empty, the path doesn't exist in the corresponding json.
(*cntx)->SendNull();
rb->SendNull();
} else {
(*cntx)->SendStringArr(*result);
rb->SendStringArr(*result);
}
} else {
if (result.status() == OpStatus::KEY_NOTFOUND) {
(*cntx)->SendNullArray();
rb->SendNullArray();
} else {
(*cntx)->SendError(result.status());
rb->SendError(result.status());
}
}
}
@ -1707,7 +1712,7 @@ void JsonFamily::ArrLen(CmdArgList args, ConnectionContext* cntx) {
if (ec) {
VLOG(1) << "Invalid JSONPath syntax: " << ec.message();
(*cntx)->SendError(kSyntaxErr);
cntx->SendError(kSyntaxErr);
return;
}
@ -1721,7 +1726,7 @@ void JsonFamily::ArrLen(CmdArgList args, ConnectionContext* cntx) {
if (result) {
PrintOptVec(cntx, result);
} else {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
}
@ -1734,7 +1739,7 @@ void JsonFamily::ObjLen(CmdArgList args, ConnectionContext* cntx) {
if (ec) {
VLOG(1) << "Invalid JSONPath syntax: " << ec.message();
(*cntx)->SendError(kSyntaxErr);
cntx->SendError(kSyntaxErr);
return;
}
@ -1748,7 +1753,7 @@ void JsonFamily::ObjLen(CmdArgList args, ConnectionContext* cntx) {
if (result) {
PrintOptVec(cntx, result);
} else {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
}
@ -1761,7 +1766,7 @@ void JsonFamily::StrLen(CmdArgList args, ConnectionContext* cntx) {
if (ec) {
VLOG(1) << "Invalid JSONPath syntax: " << ec.message();
(*cntx)->SendError(kSyntaxErr);
cntx->SendError(kSyntaxErr);
return;
}
@ -1775,7 +1780,7 @@ void JsonFamily::StrLen(CmdArgList args, ConnectionContext* cntx) {
if (result) {
PrintOptVec(cntx, result);
} else {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
}
@ -1812,7 +1817,7 @@ void JsonFamily::Get(CmdArgList args, ConnectionContext* cntx) {
expr = ParseJsonPath(expr_str, &ec);
if (ec) {
LOG(WARNING) << "path '" << expr_str << "': Invalid JSONPath syntax: " << ec.message();
return (*cntx)->SendError(kSyntaxErr);
return cntx->SendError(kSyntaxErr);
}
}
@ -1820,7 +1825,7 @@ void JsonFamily::Get(CmdArgList args, ConnectionContext* cntx) {
}
if (auto err = parser.Error(); err)
return (*cntx)->SendError(err->MakeReply());
return cntx->SendError(err->MakeReply());
bool should_format = (indent || new_line || space);
auto cb = [&](Transaction* t, EngineShard* shard) {
@ -1829,14 +1834,14 @@ void JsonFamily::Get(CmdArgList args, ConnectionContext* cntx) {
Transaction* trans = cntx->transaction;
OpResult<string> result = trans->ScheduleSingleHopT(move(cb));
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
if (result) {
(*cntx)->SendBulkString(*result);
rb->SendBulkString(*result);
} else {
if (result == facade::OpStatus::KEY_NOTFOUND) {
(*cntx)->SendNull(); // Match Redis
rb->SendNull(); // Match Redis
} else {
(*cntx)->SendError(result.status());
rb->SendError(result.status());
}
}
}

View file

@ -754,17 +754,18 @@ void MoveGeneric(ConnectionContext* cntx, string_view src, string_view dest, Lis
result = MoveTwoShards(cntx->transaction, src, dest, src_dir, dest_dir, true);
}
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
if (result) {
return (*cntx)->SendBulkString(*result);
return rb->SendBulkString(*result);
}
switch (result.status()) {
case OpStatus::KEY_NOTFOUND:
(*cntx)->SendNull();
rb->SendNull();
break;
default:
(*cntx)->SendError(result.status());
rb->SendError(result.status());
break;
}
}
@ -783,27 +784,28 @@ void BRPopLPush(CmdArgList args, ConnectionContext* cntx) {
float timeout;
if (!absl::SimpleAtof(timeout_str, &timeout)) {
return (*cntx)->SendError("timeout is not a float or out of range");
return cntx->SendError("timeout is not a float or out of range");
}
if (timeout < 0) {
return (*cntx)->SendError("timeout is negative");
return cntx->SendError("timeout is negative");
}
BPopPusher bpop_pusher(src, dest, ListDir::RIGHT, ListDir::LEFT);
OpResult<string> op_res = bpop_pusher.Run(cntx->transaction, unsigned(timeout * 1000));
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
if (op_res) {
return (*cntx)->SendBulkString(*op_res);
return rb->SendBulkString(*op_res);
}
switch (op_res.status()) {
case OpStatus::TIMED_OUT:
return (*cntx)->SendNull();
return rb->SendNull();
break;
default:
return (*cntx)->SendError(op_res.status());
return rb->SendError(op_res.status());
break;
}
}
@ -815,11 +817,11 @@ void BLMove(CmdArgList args, ConnectionContext* cntx) {
float timeout;
if (!absl::SimpleAtof(timeout_str, &timeout)) {
return (*cntx)->SendError("timeout is not a float or out of range");
return cntx->SendError("timeout is not a float or out of range");
}
if (timeout < 0) {
return (*cntx)->SendError("timeout is negative");
return cntx->SendError("timeout is negative");
}
ToUpper(&args[2]);
@ -828,23 +830,24 @@ void BLMove(CmdArgList args, ConnectionContext* cntx) {
optional<ListDir> src_dir = ParseDir(ArgS(args, 2));
optional<ListDir> dest_dir = ParseDir(ArgS(args, 3));
if (!src_dir || !dest_dir) {
return (*cntx)->SendError(kSyntaxErr);
return cntx->SendError(kSyntaxErr);
}
BPopPusher bpop_pusher(src, dest, *src_dir, *dest_dir);
OpResult<string> op_res = bpop_pusher.Run(cntx->transaction, unsigned(timeout * 1000));
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
if (op_res) {
return (*cntx)->SendBulkString(*op_res);
return rb->SendBulkString(*op_res);
}
switch (op_res.status()) {
case OpStatus::TIMED_OUT:
return (*cntx)->SendNull();
return rb->SendNull();
break;
default:
return (*cntx)->SendError(op_res.status());
return rb->SendError(op_res.status());
break;
}
}
@ -954,11 +957,11 @@ void ListFamily::LLen(CmdArgList args, ConnectionContext* cntx) {
auto cb = [&](Transaction* t, EngineShard* shard) { return OpLen(t->GetOpArgs(shard), key); };
OpResult<uint32_t> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
if (result) {
(*cntx)->SendLong(result.value());
cntx->SendLong(result.value());
} else if (result.status() == OpStatus::KEY_NOTFOUND) {
(*cntx)->SendLong(0);
cntx->SendLong(0);
} else {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
}
@ -976,18 +979,18 @@ void ListFamily::LPos(CmdArgList args, ConnectionContext* cntx) {
const auto& arg_v = ArgS(args, i);
if (arg_v == "RANK") {
if (!absl::SimpleAtoi(ArgS(args, (i + 1)), &rank) || rank == 0) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
}
if (arg_v == "COUNT") {
if (!absl::SimpleAtoi(ArgS(args, (i + 1)), &count)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
skip_count = false;
}
if (arg_v == "MAXLEN") {
if (!absl::SimpleAtoi(ArgS(args, (i + 1)), &max_len)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
}
}
@ -1000,23 +1003,24 @@ void ListFamily::LPos(CmdArgList args, ConnectionContext* cntx) {
OpResult<vector<uint32_t>> result = trans->ScheduleSingleHopT(std::move(cb));
if (result.status() == OpStatus::WRONG_TYPE) {
return (*cntx)->SendError(result.status());
return cntx->SendError(result.status());
} else if (result.status() == OpStatus::INVALID_VALUE) {
return (*cntx)->SendError(result.status());
return cntx->SendError(result.status());
}
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
if (skip_count) {
if (result->empty()) {
(*cntx)->SendNull();
rb->SendNull();
} else {
(*cntx)->SendLong((*result)[0]);
rb->SendLong((*result)[0]);
}
} else {
SinkReplyBuilder::ReplyAggregator agg(cntx->reply_builder());
(*cntx)->StartArray(result->size());
rb->StartArray(result->size());
const auto& array = result.value();
for (const auto& v : array) {
(*cntx)->SendLong(v);
rb->SendLong(v);
}
}
}
@ -1026,7 +1030,7 @@ void ListFamily::LIndex(CmdArgList args, ConnectionContext* cntx) {
std::string_view index_str = ArgS(args, 1);
int32_t index;
if (!absl::SimpleAtoi(index_str, &index)) {
(*cntx)->SendError(kInvalidIntErr);
cntx->SendError(kInvalidIntErr);
return;
}
@ -1034,13 +1038,14 @@ void ListFamily::LIndex(CmdArgList args, ConnectionContext* cntx) {
return OpIndex(t->GetOpArgs(shard), key, index);
};
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
OpResult<string> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
if (result) {
(*cntx)->SendBulkString(result.value());
rb->SendBulkString(result.value());
} else if (result.status() == OpStatus::WRONG_TYPE) {
(*cntx)->SendError(result.status());
rb->SendError(result.status());
} else {
(*cntx)->SendNull();
rb->SendNull();
}
}
@ -1058,7 +1063,7 @@ void ListFamily::LInsert(CmdArgList args, ConnectionContext* cntx) {
} else if (param == "BEFORE") {
where = LIST_HEAD;
} else {
return (*cntx)->SendError(kSyntaxErr);
return cntx->SendError(kSyntaxErr);
}
auto cb = [&](Transaction* t, EngineShard* shard) {
@ -1067,10 +1072,10 @@ void ListFamily::LInsert(CmdArgList args, ConnectionContext* cntx) {
OpResult<int> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
if (result) {
return (*cntx)->SendLong(result.value());
return cntx->SendLong(result.value());
}
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
void ListFamily::LTrim(CmdArgList args, ConnectionContext* cntx) {
@ -1080,7 +1085,7 @@ void ListFamily::LTrim(CmdArgList args, ConnectionContext* cntx) {
int32_t start, end;
if (!absl::SimpleAtoi(s_str, &start) || !absl::SimpleAtoi(e_str, &end)) {
(*cntx)->SendError(kInvalidIntErr);
cntx->SendError(kInvalidIntErr);
return;
}
@ -1088,7 +1093,7 @@ void ListFamily::LTrim(CmdArgList args, ConnectionContext* cntx) {
return OpTrim(t->GetOpArgs(shard), key, start, end);
};
cntx->transaction->ScheduleSingleHop(std::move(cb));
(*cntx)->SendOk();
cntx->SendOk();
}
void ListFamily::LRange(CmdArgList args, ConnectionContext* cntx) {
@ -1098,7 +1103,7 @@ void ListFamily::LRange(CmdArgList args, ConnectionContext* cntx) {
int32_t start, end;
if (!absl::SimpleAtoi(s_str, &start) || !absl::SimpleAtoi(e_str, &end)) {
(*cntx)->SendError(kInvalidIntErr);
cntx->SendError(kInvalidIntErr);
return;
}
@ -1108,10 +1113,11 @@ void ListFamily::LRange(CmdArgList args, ConnectionContext* cntx) {
auto res = cntx->transaction->ScheduleSingleHopT(std::move(cb));
if (!res && res.status() != OpStatus::KEY_NOTFOUND) {
return (*cntx)->SendError(res.status());
return cntx->SendError(res.status());
}
(*cntx)->SendStringArr(*res);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->SendStringArr(*res);
}
// lrem key 5 foo, will remove foo elements from the list if exists at most 5 times.
@ -1122,7 +1128,7 @@ void ListFamily::LRem(CmdArgList args, ConnectionContext* cntx) {
int32_t count;
if (!absl::SimpleAtoi(index_str, &count)) {
(*cntx)->SendError(kInvalidIntErr);
cntx->SendError(kInvalidIntErr);
return;
}
@ -1131,9 +1137,9 @@ void ListFamily::LRem(CmdArgList args, ConnectionContext* cntx) {
};
OpResult<uint32_t> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
if (result) {
(*cntx)->SendLong(result.value());
cntx->SendLong(result.value());
} else {
(*cntx)->SendLong(0);
cntx->SendLong(0);
}
}
@ -1144,7 +1150,7 @@ void ListFamily::LSet(CmdArgList args, ConnectionContext* cntx) {
int32_t count;
if (!absl::SimpleAtoi(index_str, &count)) {
(*cntx)->SendError(kInvalidIntErr);
cntx->SendError(kInvalidIntErr);
return;
}
@ -1153,9 +1159,9 @@ void ListFamily::LSet(CmdArgList args, ConnectionContext* cntx) {
};
OpResult<void> result = cntx->transaction->ScheduleSingleHop(std::move(cb));
if (result) {
(*cntx)->SendOk();
cntx->SendOk();
} else {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
}
@ -1179,7 +1185,7 @@ void ListFamily::LMove(CmdArgList args, ConnectionContext* cntx) {
optional<ListDir> src_dir = ParseDir(src_dir_str);
optional<ListDir> dest_dir = ParseDir(dest_dir_str);
if (!src_dir || !dest_dir) {
return (*cntx)->SendError(kSyntaxErr);
return cntx->SendError(kSyntaxErr);
}
MoveGeneric(cntx, src, dest, *src_dir, *dest_dir);
@ -1191,10 +1197,10 @@ void ListFamily::BPopGeneric(ListDir dir, CmdArgList args, ConnectionContext* cn
float timeout;
auto timeout_str = ArgS(args, args.size() - 1);
if (!absl::SimpleAtof(timeout_str, &timeout)) {
return (*cntx)->SendError("timeout is not a float or out of range");
return cntx->SendError("timeout is not a float or out of range");
}
if (timeout < 0) {
return (*cntx)->SendError("timeout is negative");
return cntx->SendError("timeout is negative");
}
VLOG(1) << "BPop timeout(" << timeout << ")";
@ -1209,23 +1215,24 @@ void ListFamily::BPopGeneric(ListDir dir, CmdArgList args, ConnectionContext* cn
OpResult<string> popped_key = container_utils::RunCbOnFirstNonEmptyBlocking(
transaction, OBJ_LIST, move(cb), unsigned(timeout * 1000));
cntx->conn_state.is_blocking = false;
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
if (popped_key) {
DVLOG(1) << "BPop " << transaction->DebugId() << " popped from key " << popped_key; // key.
std::string_view str_arr[2] = {*popped_key, popped_value};
return (*cntx)->SendStringArr(str_arr);
return rb->SendStringArr(str_arr);
}
DVLOG(1) << "result for " << transaction->DebugId() << " is " << popped_key.status();
switch (popped_key.status()) {
case OpStatus::WRONG_TYPE:
return (*cntx)->SendError(kWrongTypeErr);
return rb->SendError(kWrongTypeErr);
case OpStatus::TIMED_OUT:
return (*cntx)->SendNullArray();
return rb->SendNullArray();
default:
LOG(ERROR) << "Unexpected error " << popped_key.status();
}
return (*cntx)->SendNullArray();
return rb->SendNullArray();
}
void ListFamily::PushGeneric(ListDir dir, bool skip_notexists, CmdArgList args,
@ -1242,10 +1249,10 @@ void ListFamily::PushGeneric(ListDir dir, bool skip_notexists, CmdArgList args,
OpResult<uint32_t> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
if (result) {
return (*cntx)->SendLong(result.value());
return cntx->SendLong(result.value());
}
return (*cntx)->SendError(result.status());
return cntx->SendError(result.status());
}
void ListFamily::PopGeneric(ListDir dir, CmdArgList args, ConnectionContext* cntx) {
@ -1255,16 +1262,16 @@ void ListFamily::PopGeneric(ListDir dir, CmdArgList args, ConnectionContext* cnt
if (args.size() > 1) {
if (args.size() > 2) {
return (*cntx)->SendError(WrongNumArgsError(cntx->cid->name()));
return cntx->SendError(WrongNumArgsError(cntx->cid->name()));
}
string_view count_s = ArgS(args, 1);
if (!absl::SimpleAtoi(count_s, &count)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
if (count < 0) {
return (*cntx)->SendError(kUintErr);
return cntx->SendError(kUintErr);
}
return_arr = true;
}
@ -1274,27 +1281,27 @@ void ListFamily::PopGeneric(ListDir dir, CmdArgList args, ConnectionContext* cnt
};
OpResult<StringVec> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
switch (result.status()) {
case OpStatus::KEY_NOTFOUND:
return (*cntx)->SendNull();
return rb->SendNull();
case OpStatus::WRONG_TYPE:
return (*cntx)->SendError(kWrongTypeErr);
return rb->SendError(kWrongTypeErr);
default:;
}
if (return_arr) {
if (result->empty()) {
(*cntx)->SendNullArray();
rb->SendNullArray();
} else {
(*cntx)->StartArray(result->size());
rb->StartArray(result->size());
for (const auto& k : *result) {
(*cntx)->SendBulkString(k);
rb->SendBulkString(k);
}
}
} else {
DCHECK_EQ(1u, result->size());
(*cntx)->SendBulkString(result->front());
rb->SendBulkString(result->front());
}
}

View file

@ -1115,7 +1115,7 @@ void Service::DispatchCommand(CmdArgList args, facade::ConnectionContext* cntx)
dfly_cntx->transaction->InitByArgs(dfly_cntx->conn_state.db_index, args_no_cmd);
if (status != OpStatus::OK)
return (*cntx)->SendError(status);
return cntx->SendError(status);
}
} else {
DCHECK(dfly_cntx->transaction == nullptr);
@ -1126,7 +1126,7 @@ void Service::DispatchCommand(CmdArgList args, facade::ConnectionContext* cntx)
if (!dist_trans->IsMulti()) { // Multi command initialize themself based on their mode.
if (auto st = dist_trans->InitByArgs(dfly_cntx->conn_state.db_index, args_no_cmd);
st != OpStatus::OK)
return (*cntx)->SendError(st);
return cntx->SendError(st);
}
dfly_cntx->transaction = dist_trans.get();
@ -1184,7 +1184,7 @@ bool Service::InvokeCmd(const CommandId* cid, CmdArgList tail_args, ConnectionCo
DCHECK(!cid->Validate(tail_args));
if (auto err = VerifyCommandExecution(cid, cntx); err) {
(*cntx)->SendError(std::move(*err));
cntx->SendError(std::move(*err));
return true; // return false only for internal error aborts
}
@ -1462,7 +1462,7 @@ absl::flat_hash_map<std::string, unsigned> Service::UknownCmdMap() const {
void Service::Quit(CmdArgList args, ConnectionContext* cntx) {
if (cntx->protocol() == facade::Protocol::REDIS)
(*cntx)->SendOk();
cntx->SendOk();
using facade::SinkReplyBuilder;
SinkReplyBuilder* builder = cntx->reply_builder();
@ -1474,11 +1474,11 @@ void Service::Quit(CmdArgList args, ConnectionContext* cntx) {
void Service::Multi(CmdArgList args, ConnectionContext* cntx) {
if (cntx->conn_state.exec_info.IsCollecting()) {
return (*cntx)->SendError("MULTI calls can not be nested");
return cntx->SendError("MULTI calls can not be nested");
}
cntx->conn_state.exec_info.state = ConnectionState::ExecInfo::EXEC_COLLECT;
// TODO: to protect against huge exec transactions.
return (*cntx)->SendOk();
return cntx->SendOk();
}
void Service::Watch(CmdArgList args, ConnectionContext* cntx) {
@ -1486,7 +1486,7 @@ void Service::Watch(CmdArgList args, ConnectionContext* cntx) {
// Skip if EXEC will already fail due previous WATCH.
if (exec_info.watched_dirty.load(memory_order_relaxed)) {
return (*cntx)->SendOk();
return cntx->SendOk();
}
atomic_uint32_t keys_existed = 0;
@ -1508,12 +1508,12 @@ void Service::Watch(CmdArgList args, ConnectionContext* cntx) {
exec_info.watched_keys.emplace_back(cntx->db_index(), ArgS(args, i));
}
return (*cntx)->SendOk();
return cntx->SendOk();
}
void Service::Unwatch(CmdArgList args, ConnectionContext* cntx) {
UnwatchAllKeys(cntx);
return (*cntx)->SendOk();
return cntx->SendOk();
}
template <typename F> void WithReplies(CapturingReplyBuilder* crb, ConnectionContext* cntx, F&& f) {
@ -1593,14 +1593,15 @@ void Service::CallFromScript(ConnectionContext* cntx, Interpreter::CallArgs& ca)
void Service::Eval(CmdArgList args, ConnectionContext* cntx) {
string_view body = ArgS(args, 0);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
if (body.empty()) {
return (*cntx)->SendNull();
return rb->SendNull();
}
BorrowedInterpreter interpreter{cntx};
auto res = server_family_.script_mgr()->Insert(body, interpreter);
if (!res)
return (*cntx)->SendError(res.error().Format(), facade::kScriptErrType);
return rb->SendError(res.error().Format(), facade::kScriptErrType);
string sha{std::move(res.value())};
@ -1677,7 +1678,7 @@ optional<bool> StartMultiEval(DbIndex dbid, CmdArgList keys, ScriptMgr::ScriptPa
string err = StrCat(
"Multi mode conflict when running eval in multi transaction. Multi mode is: ", multi_mode,
" eval mode is: ", script_mode);
(*cntx)->SendError(err);
cntx->SendError(err);
return nullopt;
}
return false;
@ -1758,12 +1759,12 @@ void Service::EvalInternal(CmdArgList args, const EvalArgs& eval_args, Interpret
// Sanitizing the input to avoid code injection.
if (eval_args.sha.size() != 40 || !IsSHA(eval_args.sha)) {
return (*cntx)->SendError(facade::kScriptNotFound);
return cntx->SendError(facade::kScriptNotFound);
}
auto params = LoadScipt(eval_args.sha, server_family_.script_mgr(), interpreter);
if (!params)
return (*cntx)->SendError(facade::kScriptNotFound);
return cntx->SendError(facade::kScriptNotFound);
string error;
@ -1854,7 +1855,7 @@ void Service::EvalInternal(CmdArgList args, const EvalArgs& eval_args, Interpret
if (result == Interpreter::RUN_ERR) {
string resp = StrCat("Error running script (call to ", eval_args.sha, "): ", error);
return (*cntx)->SendError(resp, facade::kScriptErrType);
return cntx->SendError(resp, facade::kScriptErrType);
}
CHECK(result == Interpreter::RUN_OK);
@ -1862,14 +1863,14 @@ void Service::EvalInternal(CmdArgList args, const EvalArgs& eval_args, Interpret
SinkReplyBuilder::ReplyAggregator agg(cntx->reply_builder());
EvalSerializer ser{static_cast<RedisReplyBuilder*>(cntx->reply_builder())};
if (!interpreter->IsResultSafe()) {
(*cntx)->SendError("reached lua stack limit");
cntx->SendError("reached lua stack limit");
} else {
interpreter->SerializeResult(&ser);
}
}
void Service::Discard(CmdArgList args, ConnectionContext* cntx) {
RedisReplyBuilder* rb = (*cntx).operator->();
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
if (!cntx->conn_state.exec_info.IsCollecting()) {
return rb->SendError("DISCARD without MULTI");
@ -1976,7 +1977,7 @@ void StartMultiExec(DbIndex dbid, Transaction* trans, ConnectionState::ExecInfo*
}
void Service::Exec(CmdArgList args, ConnectionContext* cntx) {
RedisReplyBuilder* rb = (*cntx).operator->();
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
absl::Cleanup exec_clear = [&cntx] { MultiCleanup(cntx); };
@ -2047,7 +2048,7 @@ void Service::Exec(CmdArgList args, ConnectionContext* cntx) {
if (scmd.Cid()->IsTransactional()) {
OpStatus st = cntx->transaction->InitByArgs(cntx->conn_state.db_index, args);
if (st != OpStatus::OK) {
(*cntx)->SendError(st);
cntx->SendError(st);
break;
}
}
@ -2120,7 +2121,7 @@ void Service::Publish(CmdArgList args, ConnectionContext* cntx) {
shard_set->pool()->DispatchBrief(std::move(cb));
}
(*cntx)->SendLong(num_published);
cntx->SendLong(num_published);
}
void Service::Subscribe(CmdArgList args, ConnectionContext* cntx) {
@ -2154,34 +2155,35 @@ void Service::Function(CmdArgList args, ConnectionContext* cntx) {
string_view sub_cmd = ArgS(args, 0);
if (sub_cmd == "FLUSH") {
return (*cntx)->SendOk();
return cntx->SendOk();
}
string err = UnknownSubCmd(sub_cmd, "FUNCTION");
return (*cntx)->SendError(err, kSyntaxErrType);
return cntx->SendError(err, kSyntaxErrType);
}
void Service::PubsubChannels(string_view pattern, ConnectionContext* cntx) {
(*cntx)->SendStringArr(ServerState::tlocal()->channel_store()->ListChannels(pattern));
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->SendStringArr(ServerState::tlocal()->channel_store()->ListChannels(pattern));
}
void Service::PubsubPatterns(ConnectionContext* cntx) {
size_t pattern_count = ServerState::tlocal()->channel_store()->PatternCount();
(*cntx)->SendLong(pattern_count);
cntx->SendLong(pattern_count);
}
void Service::Monitor(CmdArgList args, ConnectionContext* cntx) {
VLOG(1) << "starting monitor on this connection: " << cntx->conn()->GetClientId();
// we are registering the current connection for all threads so they will be aware of
// this connection, to send to it any command
(*cntx)->SendOk();
cntx->SendOk();
cntx->ChangeMonitor(true /* start */);
}
void Service::Pubsub(CmdArgList args, ConnectionContext* cntx) {
if (args.size() < 1) {
(*cntx)->SendError(WrongNumArgsError(cntx->cid->name()));
cntx->SendError(WrongNumArgsError(cntx->cid->name()));
return;
}
@ -2198,7 +2200,8 @@ void Service::Pubsub(CmdArgList args, ConnectionContext* cntx) {
"HELP",
"\tPrints this help."};
(*cntx)->SendSimpleStrArr(help_arr);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->SendSimpleStrArr(help_arr);
return;
}
@ -2212,7 +2215,7 @@ void Service::Pubsub(CmdArgList args, ConnectionContext* cntx) {
} else if (subcmd == "NUMPAT") {
PubsubPatterns(cntx);
} else {
(*cntx)->SendError(UnknownSubCmd(subcmd, "PUBSUB"));
cntx->SendError(UnknownSubCmd(subcmd, "PUBSUB"));
}
}
@ -2224,28 +2227,29 @@ void Service::Command(CmdArgList args, ConnectionContext* cntx) {
}
});
auto serialize_command = [&cntx](string_view name, const CommandId& cid) {
(*cntx)->StartArray(6);
(*cntx)->SendSimpleString(cid.name());
(*cntx)->SendLong(cid.arity());
(*cntx)->StartArray(CommandId::OptCount(cid.opt_mask()));
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
auto serialize_command = [&rb](string_view name, const CommandId& cid) {
rb->StartArray(6);
rb->SendSimpleString(cid.name());
rb->SendLong(cid.arity());
rb->StartArray(CommandId::OptCount(cid.opt_mask()));
for (uint32_t i = 0; i < 32; ++i) {
unsigned obit = (1u << i);
if (cid.opt_mask() & obit) {
const char* name = CO::OptName(CO::CommandOpt{obit});
(*cntx)->SendSimpleString(name);
rb->SendSimpleString(name);
}
}
(*cntx)->SendLong(cid.first_key_pos());
(*cntx)->SendLong(cid.last_key_pos());
(*cntx)->SendLong(cid.opt_mask() & CO::INTERLEAVED_KEYS ? 2 : 1);
rb->SendLong(cid.first_key_pos());
rb->SendLong(cid.last_key_pos());
rb->SendLong(cid.opt_mask() & CO::INTERLEAVED_KEYS ? 2 : 1);
};
// If no arguments are specified, reply with all commands
if (args.empty()) {
(*cntx)->StartArray(cmd_cnt);
rb->StartArray(cmd_cnt);
registry_.Traverse([&](string_view name, const CommandId& cid) {
if (cid.opt_mask() & CO::HIDDEN)
return;
@ -2259,7 +2263,7 @@ void Service::Command(CmdArgList args, ConnectionContext* cntx) {
// COUNT
if (subcmd == "COUNT") {
return (*cntx)->SendLong(cmd_cnt);
return cntx->SendLong(cmd_cnt);
}
// INFO [cmd]
@ -2268,16 +2272,16 @@ void Service::Command(CmdArgList args, ConnectionContext* cntx) {
string_view cmd = ArgS(args, 1);
if (const auto* cid = registry_.Find(cmd); cid) {
(*cntx)->StartArray(1);
rb->StartArray(1);
serialize_command(cmd, *cid);
} else {
(*cntx)->SendNull();
rb->SendNull();
}
return;
}
return (*cntx)->SendError(kSyntaxErr, kSyntaxErrType);
return cntx->SendError(kSyntaxErr, kSyntaxErrType);
}
VarzValue::Map Service::GetVarzStats() {

View file

@ -99,7 +99,8 @@ void MemoryCmd::Run(CmdArgList args) {
"DECOMMIT",
" Force decommit the memory freed by the server back to OS.",
};
return (*cntx_)->SendSimpleStrArr(help_arr);
auto* rb = static_cast<RedisReplyBuilder*>(cntx_->reply_builder());
return rb->SendSimpleStrArr(help_arr);
};
if (sub_cmd == "STATS") {
@ -116,7 +117,7 @@ void MemoryCmd::Run(CmdArgList args) {
mi_heap_collect(ServerState::tlocal()->data_heap(), true);
mi_heap_collect(mi_heap_get_backing(), true);
});
return (*cntx_)->SendSimpleString("OK");
return cntx_->SendSimpleString("OK");
}
if (sub_cmd == "MALLOC-STATS") {
@ -132,7 +133,7 @@ void MemoryCmd::Run(CmdArgList args) {
}
if (args.size() > tid_indx && !absl::SimpleAtoi(ArgS(args, tid_indx), &tid)) {
return (*cntx_)->SendError(kInvalidIntErr);
return cntx_->SendError(kInvalidIntErr);
}
}
@ -147,11 +148,12 @@ void MemoryCmd::Run(CmdArgList args) {
string res = shard_set->pool()->at(tid)->AwaitBrief([=] { return MallocStats(backing, tid); });
return (*cntx_)->SendBulkString(res);
auto* rb = static_cast<RedisReplyBuilder*>(cntx_->reply_builder());
return rb->SendBulkString(res);
}
string err = UnknownSubCmd(sub_cmd, "MEMORY");
return (*cntx_)->SendError(err, kSyntaxErrType);
return cntx_->SendError(err, kSyntaxErrType);
}
namespace {
@ -270,10 +272,11 @@ void MemoryCmd::Stats() {
// Serialization stats, including both replication-related serialization and saving to RDB files.
stats.push_back({"serialization", serialization_memory.load()});
(*cntx_)->StartCollection(stats.size(), RedisReplyBuilder::MAP);
auto* rb = static_cast<RedisReplyBuilder*>(cntx_->reply_builder());
rb->StartCollection(stats.size(), RedisReplyBuilder::MAP);
for (const auto& [k, v] : stats) {
(*cntx_)->SendBulkString(k);
(*cntx_)->SendLong(v);
rb->SendBulkString(k);
rb->SendLong(v);
}
}
@ -292,7 +295,7 @@ void MemoryCmd::Usage(std::string_view key) {
if (memory_usage < 0)
return cntx_->SendError(kKeyNotFoundErr);
(*cntx_)->SendLong(memory_usage);
cntx_->SendLong(memory_usage);
}
} // namespace dfly

View file

@ -118,7 +118,7 @@ bool MultiCommandSquasher::ExecuteStandalone(StoredCmd* cmd) {
if (verify_commands_) {
if (auto err = service_->VerifyCommandState(cmd->Cid(), args, *cntx_); err) {
(*cntx_)->SendError(move(*err));
cntx_->SendError(move(*err));
return !error_abort_;
}
}

View file

@ -84,11 +84,11 @@ error_code Replica::Start(ConnectionContext* cntx) {
auto check_connection_error = [this, &cntx](error_code ec, const char* msg) -> error_code {
if (cntx_.IsCancelled()) {
(*cntx)->SendError("replication cancelled");
cntx->SendError("replication cancelled");
return std::make_error_code(errc::operation_canceled);
}
if (ec) {
(*cntx)->SendError(absl::StrCat(msg, ec.message()));
cntx->SendError(absl::StrCat(msg, ec.message()));
cntx_.Cancel();
}
return ec;
@ -118,7 +118,7 @@ error_code Replica::Start(ConnectionContext* cntx) {
// 4. Spawn main coordination fiber.
sync_fb_ = fb2::Fiber("main_replication", &Replica::MainReplicationFb, this);
(*cntx)->SendOk();
cntx->SendOk();
return {};
}
@ -128,7 +128,7 @@ void Replica::EnableReplication(ConnectionContext* cntx) {
state_mask_.store(R_ENABLED); // set replica state to enabled
sync_fb_ = MakeFiber(&Replica::MainReplicationFb, this); // call replication fiber
(*cntx)->SendOk();
cntx->SendOk();
}
void Replica::Stop() {

View file

@ -76,7 +76,8 @@ void ScriptMgr::Run(CmdArgList args, ConnectionContext* cntx) {
" Prints latency histograms in usec for every called function.",
"HELP"
" Prints this help."};
return (*cntx)->SendSimpleStrArr(kHelp);
auto rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
return rb->SendSimpleStrArr(kHelp);
}
if (subcmd == "EXISTS" && args.size() > 1)
@ -96,7 +97,7 @@ void ScriptMgr::Run(CmdArgList args, ConnectionContext* cntx) {
string err = absl::StrCat("Unknown subcommand or wrong number of arguments for '", subcmd,
"'. Try SCRIPT HELP.");
cntx->reply_builder()->SendError(err, kSyntaxErrType);
cntx->SendError(err, kSyntaxErrType);
}
void ScriptMgr::ExistsCmd(CmdArgList args, ConnectionContext* cntx) const {
@ -107,20 +108,21 @@ void ScriptMgr::ExistsCmd(CmdArgList args, ConnectionContext* cntx) const {
}
}
(*cntx)->StartArray(res.size());
auto rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->StartArray(res.size());
for (uint8_t v : res) {
(*cntx)->SendLong(v);
rb->SendLong(v);
}
return;
}
void ScriptMgr::LoadCmd(CmdArgList args, ConnectionContext* cntx) {
string_view body = ArgS(args, 1);
auto rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
if (body.empty()) {
char sha[41];
Interpreter::FuncSha1(body, sha);
return (*cntx)->SendBulkString(sha);
return rb->SendBulkString(sha);
}
ServerState* ss = ServerState::tlocal();
@ -129,12 +131,12 @@ void ScriptMgr::LoadCmd(CmdArgList args, ConnectionContext* cntx) {
auto res = Insert(body, interpreter);
if (!res)
return (*cntx)->SendError(res.error().Format());
return rb->SendError(res.error().Format());
// Schedule empty callback inorder to journal command via transaction framework.
cntx->transaction->ScheduleSingleHop([](auto* t, auto* shard) { return OpStatus::OK; });
return (*cntx)->SendBulkString(res.value());
return rb->SendBulkString(res.value());
}
void ScriptMgr::ConfigCmd(CmdArgList args, ConnectionContext* cntx) {
@ -144,7 +146,7 @@ void ScriptMgr::ConfigCmd(CmdArgList args, ConnectionContext* cntx) {
for (auto flag : args.subspan(2)) {
if (auto err = ScriptParams::ApplyFlags(facade::ToSV(flag), &data); err)
return (*cntx)->SendError("Invalid config format: " + err.Format());
return cntx->SendError("Invalid config format: " + err.Format());
}
UpdateScriptCaches(key, data);
@ -152,18 +154,19 @@ void ScriptMgr::ConfigCmd(CmdArgList args, ConnectionContext* cntx) {
// Schedule empty callback inorder to journal command via transaction framework.
cntx->transaction->ScheduleSingleHop([](auto* t, auto* shard) { return OpStatus::OK; });
return (*cntx)->SendOk();
return cntx->SendOk();
}
void ScriptMgr::ListCmd(ConnectionContext* cntx) const {
vector<pair<string, ScriptData>> scripts = GetAll();
(*cntx)->StartArray(scripts.size());
auto rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->StartArray(scripts.size());
for (const auto& [sha, data] : scripts) {
(*cntx)->StartArray(data.orig_body.empty() ? 2 : 3);
(*cntx)->SendBulkString(sha);
(*cntx)->SendBulkString(data.body);
rb->StartArray(data.orig_body.empty() ? 2 : 3);
rb->SendBulkString(sha);
rb->SendBulkString(data.body);
if (!data.orig_body.empty())
(*cntx)->SendBulkString(data.orig_body);
rb->SendBulkString(data.orig_body);
}
}
@ -180,11 +183,12 @@ void ScriptMgr::LatencyCmd(ConnectionContext* cntx) const {
mu.unlock();
});
(*cntx)->StartArray(result.size());
auto rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->StartArray(result.size());
for (const auto& k_v : result) {
(*cntx)->StartArray(2);
(*cntx)->SendBulkString(k_v.first);
(*cntx)->SendBulkString(k_v.second.ToString());
rb->StartArray(2);
rb->SendBulkString(k_v.first);
rb->SendBulkString(k_v.second.ToString());
}
}

View file

@ -91,7 +91,7 @@ optional<search::Schema> ParseSchemaOrReply(DocIndex::DataType type, CmdArgParse
// Verify json path is correct
if (type == DocIndex::JSON && !IsValidJsonPath(field)) {
(*cntx)->SendError("Bad json path: " + string{field});
cntx->SendError("Bad json path: " + string{field});
return nullopt;
}
@ -105,7 +105,7 @@ optional<search::Schema> ParseSchemaOrReply(DocIndex::DataType type, CmdArgParse
string_view type_str = parser.Next();
auto type = ParseSearchFieldType(type_str);
if (!type) {
(*cntx)->SendError("Invalid field type: " + string{type_str});
cntx->SendError("Invalid field type: " + string{type_str});
return nullopt;
}
@ -114,7 +114,7 @@ optional<search::Schema> ParseSchemaOrReply(DocIndex::DataType type, CmdArgParse
if (*type == search::SchemaField::VECTOR) {
auto vector_params = ParseVectorParams(&parser);
if (!parser.HasError() && vector_params.dim == 0) {
(*cntx)->SendError("Knn vector dimension cannot be zero");
cntx->SendError("Knn vector dimension cannot be zero");
return nullopt;
}
params = std::move(vector_params);
@ -148,7 +148,7 @@ optional<search::Schema> ParseSchemaOrReply(DocIndex::DataType type, CmdArgParse
schema.field_names[field_info.short_name] = field_ident;
if (auto err = parser.Error(); err) {
(*cntx)->SendError(err->MakeReply());
cntx->SendError(err->MakeReply());
return nullopt;
}
@ -206,7 +206,7 @@ optional<SearchParams> ParseSearchParamsOrReply(CmdArgParser parser, ConnectionC
}
if (auto err = parser.Error(); err) {
(*cntx)->SendError(err->MakeReply());
cntx->SendError(err->MakeReply());
return nullopt;
}
@ -214,11 +214,12 @@ optional<SearchParams> ParseSearchParamsOrReply(CmdArgParser parser, ConnectionC
}
void SendSerializedDoc(const SerializedSearchDoc& doc, ConnectionContext* cntx) {
(*cntx)->SendBulkString(doc.key);
(*cntx)->StartCollection(doc.values.size(), RedisReplyBuilder::MAP);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->SendBulkString(doc.key);
rb->StartCollection(doc.values.size(), RedisReplyBuilder::MAP);
for (const auto& [k, v] : doc.values) {
(*cntx)->SendBulkString(k);
(*cntx)->SendBulkString(v);
rb->SendBulkString(k);
rb->SendBulkString(v);
}
}
@ -236,8 +237,9 @@ void ReplyWithResults(const SearchParams& params, absl::Span<SearchResult> resul
bool ids_only = params.IdsOnly();
size_t reply_size = ids_only ? (result_count + 1) : (result_count * 2 + 1);
(*cntx)->StartArray(reply_size);
(*cntx)->SendLong(total_count);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->StartArray(reply_size);
rb->SendLong(total_count);
size_t sent = 0;
size_t to_skip = params.limit_offset;
@ -253,7 +255,7 @@ void ReplyWithResults(const SearchParams& params, absl::Span<SearchResult> resul
return;
if (ids_only)
(*cntx)->SendBulkString(serialized_doc.key);
rb->SendBulkString(serialized_doc.key);
else
SendSerializedDoc(serialized_doc, cntx);
}
@ -291,12 +293,12 @@ void ReplySorted(search::AggregationInfo agg, const SearchParams& params,
agg.alias = "";
facade::SinkReplyBuilder::ReplyAggregator agg_reply{cntx->reply_builder()};
(*cntx)->StartArray(reply_size);
(*cntx)->SendLong(min(total, agg_limit));
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->StartArray(reply_size);
rb->SendLong(min(total, agg_limit));
for (auto* doc : absl::MakeSpan(docs).subspan(start_idx, result_count)) {
if (ids_only) {
(*cntx)->SendBulkString(doc->key);
rb->SendBulkString(doc->key);
continue;
}
@ -325,7 +327,7 @@ void SearchFamily::FtCreate(CmdArgList args, ConnectionContext* cntx) {
// PREFIX count prefix [prefix ...]
if (parser.Check("PREFIX").ExpectTail(2)) {
if (size_t num = parser.Next<size_t>(); num != 1)
return (*cntx)->SendError("Multiple prefixes are not supported");
return cntx->SendError("Multiple prefixes are not supported");
index.prefix = string(parser.Next());
continue;
}
@ -344,7 +346,7 @@ void SearchFamily::FtCreate(CmdArgList args, ConnectionContext* cntx) {
}
if (auto err = parser.Error(); err)
return (*cntx)->SendError(err->MakeReply());
return cntx->SendError(err->MakeReply());
cntx->transaction->Schedule();
@ -362,7 +364,7 @@ void SearchFamily::FtCreate(CmdArgList args, ConnectionContext* cntx) {
if (exists_cnt.load(memory_order_relaxed) > 0) {
cntx->transaction->Conclude();
return (*cntx)->SendError("Index already exists");
return cntx->SendError("Index already exists");
}
auto idx_ptr = make_shared<DocIndex>(move(index));
@ -373,7 +375,7 @@ void SearchFamily::FtCreate(CmdArgList args, ConnectionContext* cntx) {
},
true);
(*cntx)->SendOk();
cntx->SendOk();
}
void SearchFamily::FtDropIndex(CmdArgList args, ConnectionContext* cntx) {
@ -389,8 +391,8 @@ void SearchFamily::FtDropIndex(CmdArgList args, ConnectionContext* cntx) {
DCHECK(num_deleted == 0u || num_deleted == shard_set->size());
if (num_deleted == 0u)
return (*cntx)->SendError("-Unknown Index name");
return (*cntx)->SendOk();
return cntx->SendError("-Unknown Index name");
return cntx->SendOk();
}
void SearchFamily::FtInfo(CmdArgList args, ConnectionContext* cntx) {
@ -411,7 +413,7 @@ void SearchFamily::FtInfo(CmdArgList args, ConnectionContext* cntx) {
DCHECK(num_notfound == 0u || num_notfound == shard_set->size());
if (num_notfound > 0u)
return (*cntx)->SendError("Unknown Index name");
return cntx->SendError("Unknown Index name");
DCHECK(infos.front().base_index.schema.fields.size() ==
infos.back().base_index.schema.fields.size());
@ -423,22 +425,23 @@ void SearchFamily::FtInfo(CmdArgList args, ConnectionContext* cntx) {
const auto& info = infos.front();
const auto& schema = info.base_index.schema;
(*cntx)->StartCollection(4, RedisReplyBuilder::MAP);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->StartCollection(4, RedisReplyBuilder::MAP);
(*cntx)->SendSimpleString("index_name");
(*cntx)->SendSimpleString(idx_name);
rb->SendSimpleString("index_name");
rb->SendSimpleString(idx_name);
(*cntx)->SendSimpleString("index_definition");
rb->SendSimpleString("index_definition");
{
(*cntx)->StartCollection(2, RedisReplyBuilder::MAP);
(*cntx)->SendSimpleString("key_type");
(*cntx)->SendSimpleString(info.base_index.type == DocIndex::JSON ? "JSON" : "HASH");
(*cntx)->SendSimpleString("prefix");
(*cntx)->SendSimpleString(info.base_index.prefix);
rb->StartCollection(2, RedisReplyBuilder::MAP);
rb->SendSimpleString("key_type");
rb->SendSimpleString(info.base_index.type == DocIndex::JSON ? "JSON" : "HASH");
rb->SendSimpleString("prefix");
rb->SendSimpleString(info.base_index.prefix);
}
(*cntx)->SendSimpleString("attributes");
(*cntx)->StartArray(schema.fields.size());
rb->SendSimpleString("attributes");
rb->StartArray(schema.fields.size());
for (const auto& [field_ident, field_info] : schema.fields) {
vector<string> info;
@ -453,11 +456,11 @@ void SearchFamily::FtInfo(CmdArgList args, ConnectionContext* cntx) {
if (field_info.flags & search::SchemaField::SORTABLE)
info.push_back("SORTABLE");
(*cntx)->SendSimpleStrArr(info);
rb->SendSimpleStrArr(info);
}
(*cntx)->SendSimpleString("num_docs");
(*cntx)->SendLong(total_num_docs);
rb->SendSimpleString("num_docs");
rb->SendLong(total_num_docs);
}
void SearchFamily::FtList(CmdArgList args, ConnectionContext* cntx) {
@ -470,8 +473,8 @@ void SearchFamily::FtList(CmdArgList args, ConnectionContext* cntx) {
names = es->search_indices()->GetIndexNames();
return OpStatus::OK;
});
(*cntx)->SendStringArr(names);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->SendStringArr(names);
}
void SearchFamily::FtSearch(CmdArgList args, ConnectionContext* cntx) {
@ -485,7 +488,7 @@ void SearchFamily::FtSearch(CmdArgList args, ConnectionContext* cntx) {
search::SearchAlgorithm search_algo;
search::SortOption* sort_opt = params->sort_option.has_value() ? &*params->sort_option : nullptr;
if (!search_algo.Init(query_str, &params->query_params, sort_opt))
return (*cntx)->SendError("Query syntax error");
return cntx->SendError("Query syntax error");
// Because our coordinator thread may not have a shard, we can't check ahead if the index exists.
atomic<bool> index_not_found{false};
@ -500,11 +503,11 @@ void SearchFamily::FtSearch(CmdArgList args, ConnectionContext* cntx) {
});
if (index_not_found.load())
return (*cntx)->SendError(string{index_name} + ": no such index");
return cntx->SendError(string{index_name} + ": no such index");
for (const auto& res : docs) {
if (res.error)
return (*cntx)->SendError(std::move(*res.error));
return cntx->SendError(*res.error);
}
if (auto agg = search_algo.HasAggregation(); agg)
@ -524,7 +527,7 @@ void SearchFamily::FtProfile(CmdArgList args, ConnectionContext* cntx) {
search::SearchAlgorithm search_algo;
search::SortOption* sort_opt = params->sort_option.has_value() ? &*params->sort_option : nullptr;
if (!search_algo.Init(query_str, &params->query_params, sort_opt))
return (*cntx)->SendError("Query syntax error");
return cntx->SendError("Query syntax error");
search_algo.EnableProfiling();
@ -552,24 +555,24 @@ void SearchFamily::FtProfile(CmdArgList args, ConnectionContext* cntx) {
});
auto took = absl::Now() - start;
(*cntx)->StartArray(results.size() + 1);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->StartArray(results.size() + 1);
// General stats
(*cntx)->StartCollection(3, RedisReplyBuilder::MAP);
(*cntx)->SendBulkString("took");
(*cntx)->SendLong(absl::ToInt64Microseconds(took));
(*cntx)->SendBulkString("hits");
(*cntx)->SendLong(total_docs);
(*cntx)->SendBulkString("serialized");
(*cntx)->SendLong(total_serialized);
rb->StartCollection(3, RedisReplyBuilder::MAP);
rb->SendBulkString("took");
rb->SendLong(absl::ToInt64Microseconds(took));
rb->SendBulkString("hits");
rb->SendLong(total_docs);
rb->SendBulkString("serialized");
rb->SendLong(total_serialized);
// Per-shard stats
for (const auto& [profile, shard_took] : results) {
(*cntx)->StartCollection(2, RedisReplyBuilder::MAP);
(*cntx)->SendBulkString("took");
(*cntx)->SendLong(absl::ToInt64Microseconds(shard_took));
(*cntx)->SendBulkString("tree");
rb->StartCollection(2, RedisReplyBuilder::MAP);
rb->SendBulkString("took");
rb->SendLong(absl::ToInt64Microseconds(shard_took));
rb->SendBulkString("tree");
for (size_t i = 0; i < profile.events.size(); i++) {
const auto& event = profile.events[i];
@ -583,13 +586,13 @@ void SearchFamily::FtProfile(CmdArgList args, ConnectionContext* cntx) {
}
if (children > 0)
(*cntx)->StartArray(2);
rb->StartArray(2);
(*cntx)->SendSimpleString(
rb->SendSimpleString(
absl::StrFormat("t=%-10u n=%-10u %s", event.micros, event.num_processed, event.descr));
if (children > 0)
(*cntx)->StartArray(children);
rb->StartArray(children);
}
}
}

View file

@ -207,13 +207,13 @@ void SlowLogGet(dfly::CmdArgList args, dfly::ConnectionContext* cntx, dfly::Serv
size_t requested_slow_log_length = UINT32_MAX;
size_t argc = args.size();
if (argc >= 3) {
(*cntx)->SendError(facade::UnknownSubCmd(sub_cmd, "SLOWLOG"), facade::kSyntaxErrType);
cntx->SendError(facade::UnknownSubCmd(sub_cmd, "SLOWLOG"), facade::kSyntaxErrType);
return;
} else if (argc == 2) {
string_view length = facade::ArgS(args, 1);
int64_t num;
if ((!absl::SimpleAtoi(length, &num)) || (num < -1)) {
(*cntx)->SendError("count should be greater than or equal to -1");
cntx->SendError("count should be greater than or equal to -1");
return;
}
if (num >= 0) {
@ -239,40 +239,41 @@ void SlowLogGet(dfly::CmdArgList args, dfly::ConnectionContext* cntx, dfly::Serv
requested_slow_log_length = std::min(merged_slow_log.size(), requested_slow_log_length);
(*cntx)->StartArray(requested_slow_log_length);
auto* rb = static_cast<facade::RedisReplyBuilder*>(cntx->reply_builder());
rb->StartArray(requested_slow_log_length);
for (size_t i = 0; i < requested_slow_log_length; ++i) {
const auto& entry = merged_slow_log[i].first;
const auto& args = entry.cmd_args;
(*cntx)->StartArray(6);
rb->StartArray(6);
(*cntx)->SendLong(entry.entry_id * service.proactor_pool().size() + merged_slow_log[i].second);
(*cntx)->SendLong(entry.unix_timestamp / 1000000000);
(*cntx)->SendLong(entry.execution_time_micro);
rb->SendLong(entry.entry_id * service.proactor_pool().size() + merged_slow_log[i].second);
rb->SendLong(entry.unix_timestamp / 1000000000);
rb->SendLong(entry.execution_time_micro);
// if we truncated the args, there is one pseudo-element containing the number of truncated
// args that we must add, so the result length is increased by 1
size_t len = args.size() + int(args.size() < entry.original_length);
(*cntx)->StartArray(len);
rb->StartArray(len);
for (const auto& arg : args) {
if (arg.second > 0) {
auto suffix = absl::StrCat("... (", arg.second, " more bytes)");
auto cmd_arg = arg.first.substr(0, dfly::kMaximumSlowlogArgLength - suffix.length());
(*cntx)->SendBulkString(absl::StrCat(cmd_arg, suffix));
rb->SendBulkString(absl::StrCat(cmd_arg, suffix));
} else {
(*cntx)->SendBulkString(arg.first);
rb->SendBulkString(arg.first);
}
}
// if we truncated arguments - add a special string to indicate that.
if (args.size() < entry.original_length) {
(*cntx)->SendBulkString(
rb->SendBulkString(
absl::StrCat("... (", entry.original_length - args.size(), " more arguments)"));
}
(*cntx)->SendBulkString(entry.client_ip);
(*cntx)->SendBulkString(entry.client_name);
rb->SendBulkString(entry.client_ip);
rb->SendBulkString(entry.client_name);
}
return;
}
@ -1114,7 +1115,7 @@ void ServerFamily::DbSize(CmdArgList args, ConnectionContext* cntx) {
},
[](ShardId) { return true; });
return (*cntx)->SendLong(num_keys.load(memory_order_relaxed));
return cntx->SendLong(num_keys.load(memory_order_relaxed));
}
void ServerFamily::BreakOnShutdown() {
@ -1157,18 +1158,18 @@ void ServerFamily::FlushDb(CmdArgList args, ConnectionContext* cntx) {
void ServerFamily::FlushAll(CmdArgList args, ConnectionContext* cntx) {
if (args.size() > 1) {
(*cntx)->SendError(kSyntaxErr);
cntx->SendError(kSyntaxErr);
return;
}
DCHECK(cntx->transaction);
Drakarys(cntx->transaction, DbSlice::kDbAll);
(*cntx)->SendOk();
cntx->SendOk();
}
void ServerFamily::Auth(CmdArgList args, ConnectionContext* cntx) {
if (args.size() > 2) {
return (*cntx)->SendError(kSyntaxErr);
return cntx->SendError(kSyntaxErr);
}
// non admin port auth
@ -1185,16 +1186,16 @@ void ServerFamily::Auth(CmdArgList args, ConnectionContext* cntx) {
cntx->acl_categories = cred.acl_categories;
cntx->acl_commands = cred.acl_commands;
cntx->authenticated = true;
return (*cntx)->SendOk();
return cntx->SendOk();
}
auto& log = ServerState::tlocal()->acl_log;
using Reason = acl::AclLog::Reason;
log.Add(*cntx, "AUTH", Reason::AUTH, std::string(username));
return (*cntx)->SendError(facade::kAuthRejected);
return cntx->SendError(facade::kAuthRejected);
}
if (!cntx->req_auth) {
return (*cntx)->SendError(
return cntx->SendError(
"AUTH <password> called without any password configured for "
"admin port. Are you sure your configuration is correct?");
}
@ -1202,9 +1203,9 @@ void ServerFamily::Auth(CmdArgList args, ConnectionContext* cntx) {
string_view pass = ArgS(args, 0);
if (pass == GetPassword()) {
cntx->authenticated = true;
(*cntx)->SendOk();
cntx->SendOk();
} else {
(*cntx)->SendError(facade::kAuthRejected);
cntx->SendError(facade::kAuthRejected);
}
}
@ -1224,37 +1225,37 @@ void ServerFamily::Client(CmdArgList args, ConnectionContext* cntx) {
}
if (sub_cmd == "SETINFO") {
return (*cntx)->SendOk();
return cntx->SendOk();
}
LOG_FIRST_N(ERROR, 10) << "Subcommand " << sub_cmd << " not supported";
return (*cntx)->SendError(UnknownSubCmd(sub_cmd, "CLIENT"), kSyntaxErrType);
return cntx->SendError(UnknownSubCmd(sub_cmd, "CLIENT"), kSyntaxErrType);
}
void ServerFamily::ClientSetName(CmdArgList args, ConnectionContext* cntx) {
if (args.size() == 1) {
cntx->conn()->SetName(string{ArgS(args, 0)});
return (*cntx)->SendOk();
return cntx->SendOk();
} else {
return (*cntx)->SendError(facade::kSyntaxErr);
return cntx->SendError(facade::kSyntaxErr);
}
}
void ServerFamily::ClientGetName(CmdArgList args, ConnectionContext* cntx) {
if (!args.empty()) {
return (*cntx)->SendError(facade::kSyntaxErr);
return cntx->SendError(facade::kSyntaxErr);
}
auto name = cntx->conn()->GetName();
if (!name.empty()) {
return (*cntx)->SendBulkString(name);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
if (auto name = cntx->conn()->GetName(); !name.empty()) {
return rb->SendBulkString(name);
} else {
return (*cntx)->SendNull();
return rb->SendNull();
}
}
void ServerFamily::ClientList(CmdArgList args, ConnectionContext* cntx) {
if (!args.empty()) {
return (*cntx)->SendError(facade::kSyntaxErr);
return cntx->SendError(facade::kSyntaxErr);
}
vector<string> client_info;
@ -1275,7 +1276,8 @@ void ServerFamily::ClientList(CmdArgList args, ConnectionContext* cntx) {
string result = absl::StrJoin(client_info, "\n");
result.append("\n");
return (*cntx)->SendBulkString(result);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
return rb->SendBulkString(result);
}
void ServerFamily::ClientPause(CmdArgList args, ConnectionContext* cntx) {
@ -1287,7 +1289,7 @@ void ServerFamily::ClientPause(CmdArgList args, ConnectionContext* cntx) {
pause_state = parser.ToUpper().Switch("WRITE", ClientPause::WRITE, "ALL", ClientPause::ALL);
}
if (auto err = parser.Error(); err) {
return (*cntx)->SendError(err->MakeReply());
return cntx->SendError(err->MakeReply());
}
// Set global pause state and track commands that are running when the pause state is flipped.
@ -1309,7 +1311,7 @@ void ServerFamily::ClientPause(CmdArgList args, ConnectionContext* cntx) {
service_.proactor_pool().Await([pause_state](util::ProactorBase* pb) {
ServerState::tlocal()->SetPauseState(pause_state, false);
});
return (*cntx)->SendError("Failed to pause all running clients");
return cntx->SendError("Failed to pause all running clients");
}
// We should not expire/evict keys while clients are puased.
@ -1336,7 +1338,7 @@ void ServerFamily::ClientPause(CmdArgList args, ConnectionContext* cntx) {
}
}).Detach();
(*cntx)->SendOk();
cntx->SendOk();
}
void ServerFamily::Config(CmdArgList args, ConnectionContext* cntx) {
@ -1345,7 +1347,7 @@ void ServerFamily::Config(CmdArgList args, ConnectionContext* cntx) {
if (sub_cmd == "SET") {
if (args.size() != 3) {
return (*cntx)->SendError(WrongNumArgsError("config|set"));
return cntx->SendError(WrongNumArgsError("config|set"));
}
ToLower(&args[1]);
@ -1356,19 +1358,19 @@ void ServerFamily::Config(CmdArgList args, ConnectionContext* cntx) {
const char kErrPrefix[] = "CONFIG SET failed (possibly related to argument '";
switch (result) {
case ConfigRegistry::SetResult::OK:
return (*cntx)->SendOk();
return cntx->SendOk();
case ConfigRegistry::SetResult::UNKNOWN:
return (*cntx)->SendError(
return cntx->SendError(
absl::StrCat("Unknown option or number of arguments for CONFIG SET - '", param, "'"),
kConfigErrType);
case ConfigRegistry::SetResult::READONLY:
return (*cntx)->SendError(
absl::StrCat(kErrPrefix, param, "') - can't set immutable config"), kConfigErrType);
return cntx->SendError(absl::StrCat(kErrPrefix, param, "') - can't set immutable config"),
kConfigErrType);
case ConfigRegistry::SetResult::INVALID:
return (*cntx)->SendError(absl::StrCat(kErrPrefix, param, "') - argument can not be set"),
kConfigErrType);
return cntx->SendError(absl::StrCat(kErrPrefix, param, "') - argument can not be set"),
kConfigErrType);
}
ABSL_UNREACHABLE();
}
@ -1390,8 +1392,8 @@ void ServerFamily::Config(CmdArgList args, ConnectionContext* cntx) {
res.push_back(flag->CurrentValue());
}
}
return (*cntx)->SendStringArr(res, RedisReplyBuilder::MAP);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
return rb->SendStringArr(res, RedisReplyBuilder::MAP);
}
if (sub_cmd == "RESETSTAT") {
@ -1404,9 +1406,9 @@ void ServerFamily::Config(CmdArgList args, ConnectionContext* cntx) {
stats.pipelined_cmd_cnt = 0;
});
return (*cntx)->SendOk();
return cntx->SendOk();
} else {
return (*cntx)->SendError(UnknownSubCmd(sub_cmd, "CONFIG"), kSyntaxErrType);
return cntx->SendError(UnknownSubCmd(sub_cmd, "CONFIG"), kSyntaxErrType);
}
}
@ -1433,7 +1435,7 @@ void ServerFamily::Save(CmdArgList args, ConnectionContext* cntx) {
string err_detail;
bool new_version = absl::GetFlag(FLAGS_df_snapshot_format);
if (args.size() > 2) {
return (*cntx)->SendError(kSyntaxErr);
return cntx->SendError(kSyntaxErr);
}
if (args.size() >= 1) {
@ -1444,7 +1446,7 @@ void ServerFamily::Save(CmdArgList args, ConnectionContext* cntx) {
} else if (sub_cmd == "RDB") {
new_version = false;
} else {
return (*cntx)->SendError(UnknownSubCmd(sub_cmd, "SAVE"), kSyntaxErrType);
return cntx->SendError(UnknownSubCmd(sub_cmd, "SAVE"), kSyntaxErrType);
}
}
@ -1455,9 +1457,9 @@ void ServerFamily::Save(CmdArgList args, ConnectionContext* cntx) {
GenericError ec = DoSave(new_version, basename, cntx->transaction);
if (ec) {
(*cntx)->SendError(ec.Format());
cntx->SendError(ec.Format());
} else {
(*cntx)->SendOk();
cntx->SendOk();
}
}
@ -1539,7 +1541,7 @@ Metrics ServerFamily::GetMetrics() const {
void ServerFamily::Info(CmdArgList args, ConnectionContext* cntx) {
if (args.size() > 1) {
return (*cntx)->SendError(kSyntaxErr);
return cntx->SendError(kSyntaxErr);
}
string_view section;
@ -1824,8 +1826,8 @@ void ServerFamily::Info(CmdArgList args, ConnectionContext* cntx) {
if (should_enter("CLUSTER")) {
append("cluster_enabled", ClusterConfig::IsEnabledOrEmulated());
}
(*cntx)->SendBulkString(info);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->SendBulkString(info);
}
void ServerFamily::Hello(CmdArgList args, ConnectionContext* cntx) {
@ -1842,7 +1844,7 @@ void ServerFamily::Hello(CmdArgList args, ConnectionContext* cntx) {
is_resp3 = proto_version == "3";
bool valid_proto_version = proto_version == "2" || is_resp3;
if (!valid_proto_version) {
(*cntx)->SendError(UnknownCmd("HELLO", args));
cntx->SendError(UnknownCmd("HELLO", args));
return;
}
@ -1859,7 +1861,7 @@ void ServerFamily::Hello(CmdArgList args, ConnectionContext* cntx) {
clientname = ArgS(args, i + 1);
i += 1;
} else {
(*cntx)->SendError(kSyntaxErr);
cntx->SendError(kSyntaxErr);
return;
}
}
@ -1869,13 +1871,13 @@ void ServerFamily::Hello(CmdArgList args, ConnectionContext* cntx) {
if (username == "default" && password == GetPassword()) {
cntx->authenticated = true;
} else {
(*cntx)->SendError(facade::kAuthRejected);
cntx->SendError(facade::kAuthRejected);
return;
}
}
if (cntx->req_auth && !cntx->authenticated) {
(*cntx)->SendError(
cntx->SendError(
"-NOAUTH HELLO must be called with the client already "
"authenticated, otherwise the HELLO <proto> AUTH <user> <pass> "
"option can be used to authenticate the client and "
@ -1887,30 +1889,31 @@ void ServerFamily::Hello(CmdArgList args, ConnectionContext* cntx) {
cntx->conn()->SetName(string{clientname});
}
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
int proto_version = 2;
if (is_resp3) {
proto_version = 3;
(*cntx)->SetResp3(true);
rb->SetResp3(true);
} else {
// Issuing hello 2 again is valid and should switch back to RESP2
(*cntx)->SetResp3(false);
rb->SetResp3(false);
}
(*cntx)->StartCollection(7, RedisReplyBuilder::MAP);
(*cntx)->SendBulkString("server");
(*cntx)->SendBulkString("redis");
(*cntx)->SendBulkString("version");
(*cntx)->SendBulkString(kRedisVersion);
(*cntx)->SendBulkString("dragonfly_version");
(*cntx)->SendBulkString(GetVersion());
(*cntx)->SendBulkString("proto");
(*cntx)->SendLong(proto_version);
(*cntx)->SendBulkString("id");
(*cntx)->SendLong(cntx->conn()->GetClientId());
(*cntx)->SendBulkString("mode");
(*cntx)->SendBulkString("standalone");
(*cntx)->SendBulkString("role");
(*cntx)->SendBulkString((*ServerState::tlocal()).is_master ? "master" : "slave");
rb->StartCollection(7, RedisReplyBuilder::MAP);
rb->SendBulkString("server");
rb->SendBulkString("redis");
rb->SendBulkString("version");
rb->SendBulkString(kRedisVersion);
rb->SendBulkString("dragonfly_version");
rb->SendBulkString(GetVersion());
rb->SendBulkString("proto");
rb->SendLong(proto_version);
rb->SendBulkString("id");
rb->SendLong(cntx->conn()->GetClientId());
rb->SendBulkString("mode");
rb->SendBulkString("standalone");
rb->SendBulkString("role");
rb->SendBulkString((*ServerState::tlocal()).is_master ? "master" : "slave");
}
void ServerFamily::ReplicaOfInternal(string_view host, string_view port_sv, ConnectionContext* cntx,
@ -1933,12 +1936,12 @@ void ServerFamily::ReplicaOfInternal(string_view host, string_view port_sv, Conn
GlobalState::ACTIVE)
<< "Server is set to replica no one, yet state is not active!";
return (*cntx)->SendOk();
return cntx->SendOk();
}
uint32_t port;
if (!absl::SimpleAtoi(port_sv, &port) || port < 1 || port > 65535) {
(*cntx)->SendError(kInvalidIntErr);
cntx->SendError(kInvalidIntErr);
return;
}
@ -1946,7 +1949,7 @@ void ServerFamily::ReplicaOfInternal(string_view host, string_view port_sv, Conn
if (auto new_state = service_.SwitchState(GlobalState::ACTIVE, GlobalState::LOADING);
new_state.first != GlobalState::LOADING) {
LOG(WARNING) << GlobalStateName(new_state.first) << " in progress, ignored";
(*cntx)->SendError("Invalid state");
cntx->SendError("Invalid state");
return;
}
@ -2014,37 +2017,37 @@ void ServerFamily::ReplTakeOver(CmdArgList args, ConnectionContext* cntx) {
auto timeout_sec = parser.Next<float>();
if (timeout_sec < 0) {
return (*cntx)->SendError("timeout is negative");
return cntx->SendError("timeout is negative");
}
bool save_flag = static_cast<bool>(parser.Check("SAVE").IgnoreCase());
if (parser.HasNext())
return (*cntx)->SendError(absl::StrCat("Unsupported option:", string_view(parser.Next())));
return cntx->SendError(absl::StrCat("Unsupported option:", string_view(parser.Next())));
if (auto err = parser.Error(); err)
return (*cntx)->SendError(err->MakeReply());
return cntx->SendError(err->MakeReply());
if (ServerState::tlocal()->is_master)
return (*cntx)->SendError("Already a master instance");
return cntx->SendError("Already a master instance");
auto repl_ptr = replica_;
CHECK(repl_ptr);
auto info = replica_->GetInfo();
if (!info.full_sync_done) {
return (*cntx)->SendError("Full sync not done");
return cntx->SendError("Full sync not done");
}
std::error_code ec = replica_->TakeOver(ArgS(args, 0), save_flag);
if (ec)
return (*cntx)->SendError("Couldn't execute takeover");
return cntx->SendError("Couldn't execute takeover");
LOG(INFO) << "Takeover successful, promoting this instance to master.";
service_.proactor_pool().AwaitFiberOnAll(
[&](util::ProactorBase* pb) { ServerState::tlocal()->is_master = true; });
replica_->Stop();
replica_.reset();
return (*cntx)->SendOk();
return cntx->SendOk();
}
void ServerFamily::ReplConf(CmdArgList args, ConnectionContext* cntx) {
@ -2070,17 +2073,18 @@ void ServerFamily::ReplConf(CmdArgList args, ConnectionContext* cntx) {
cntx->replica_conn = true;
// The response for 'capa dragonfly' is: <masterid> <syncid> <numthreads> <version>
(*cntx)->StartArray(4);
(*cntx)->SendSimpleString(master_id_);
(*cntx)->SendSimpleString(sync_id);
(*cntx)->SendLong(replica_info->flows.size());
(*cntx)->SendLong(unsigned(DflyVersion::CURRENT_VER));
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->StartArray(4);
rb->SendSimpleString(master_id_);
rb->SendSimpleString(sync_id);
rb->SendLong(replica_info->flows.size());
rb->SendLong(unsigned(DflyVersion::CURRENT_VER));
return;
}
} else if (cmd == "LISTENING-PORT") {
uint32_t replica_listening_port;
if (!absl::SimpleAtoi(arg, &replica_listening_port)) {
(*cntx)->SendError(kInvalidIntErr);
cntx->SendError(kInvalidIntErr);
return;
}
cntx->conn_state.replication_info.repl_listening_port = replica_listening_port;
@ -2092,7 +2096,7 @@ void ServerFamily::ReplConf(CmdArgList args, ConnectionContext* cntx) {
} else if (cmd == "CLIENT-VERSION" && args.size() == 2) {
unsigned version;
if (!absl::SimpleAtoi(arg, &version)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
dfly_cmd_->SetDflyClientVersion(cntx, DflyVersion(version));
} else if (cmd == "ACK" && args.size() == 2) {
@ -2118,43 +2122,44 @@ void ServerFamily::ReplConf(CmdArgList args, ConnectionContext* cntx) {
}
}
(*cntx)->SendOk();
cntx->SendOk();
return;
err:
LOG(ERROR) << "Error in receiving command: " << args;
(*cntx)->SendError(kSyntaxErr);
cntx->SendError(kSyntaxErr);
}
void ServerFamily::Role(CmdArgList args, ConnectionContext* cntx) {
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
ServerState& etl = *ServerState::tlocal();
if (etl.is_master) {
(*cntx)->StartArray(2);
(*cntx)->SendBulkString("master");
rb->StartArray(2);
rb->SendBulkString("master");
auto vec = dfly_cmd_->GetReplicasRoleInfo();
(*cntx)->StartArray(vec.size());
rb->StartArray(vec.size());
for (auto& data : vec) {
(*cntx)->StartArray(3);
(*cntx)->SendBulkString(data.address);
(*cntx)->SendBulkString(absl::StrCat(data.listening_port));
(*cntx)->SendBulkString(data.state);
rb->StartArray(3);
rb->SendBulkString(data.address);
rb->SendBulkString(absl::StrCat(data.listening_port));
rb->SendBulkString(data.state);
}
} else {
unique_lock lk{replicaof_mu_};
Replica::Info rinfo = replica_->GetInfo();
(*cntx)->StartArray(4);
(*cntx)->SendBulkString("replica");
(*cntx)->SendBulkString(rinfo.host);
(*cntx)->SendBulkString(absl::StrCat(rinfo.port));
rb->StartArray(4);
rb->SendBulkString("replica");
rb->SendBulkString(rinfo.host);
rb->SendBulkString(absl::StrCat(rinfo.port));
if (rinfo.full_sync_done) {
(*cntx)->SendBulkString("stable_sync");
rb->SendBulkString("stable_sync");
} else if (rinfo.full_sync_in_progress) {
(*cntx)->SendBulkString("full_sync");
rb->SendBulkString("full_sync");
} else if (rinfo.master_link_established) {
(*cntx)->SendBulkString("preparation");
rb->SendBulkString("preparation");
} else {
(*cntx)->SendBulkString("connecting");
rb->SendBulkString("connecting");
}
}
}
@ -2179,24 +2184,25 @@ void ServerFamily::LastSave(CmdArgList args, ConnectionContext* cntx) {
lock_guard lk(save_mu_);
save_time = last_save_info_->save_time;
}
(*cntx)->SendLong(save_time);
cntx->SendLong(save_time);
}
void ServerFamily::Latency(CmdArgList args, ConnectionContext* cntx) {
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
ToUpper(&args[0]);
string_view sub_cmd = ArgS(args, 0);
if (sub_cmd == "LATEST") {
return (*cntx)->SendEmptyArray();
return rb->SendEmptyArray();
}
LOG_FIRST_N(ERROR, 10) << "Subcommand " << sub_cmd << " not supported";
(*cntx)->SendError(kSyntaxErr);
cntx->SendError(kSyntaxErr);
}
void ServerFamily::ShutdownCmd(CmdArgList args, ConnectionContext* cntx) {
if (args.size() > 1) {
(*cntx)->SendError(kSyntaxErr);
cntx->SendError(kSyntaxErr);
return;
}
@ -2206,7 +2212,7 @@ void ServerFamily::ShutdownCmd(CmdArgList args, ConnectionContext* cntx) {
} else if (absl::EqualsIgnoreCase(sub_cmd, "NOSAVE")) {
save_on_shutdown_ = false;
} else {
(*cntx)->SendError(kSyntaxErr);
cntx->SendError(kSyntaxErr);
return;
}
}
@ -2215,7 +2221,7 @@ void ServerFamily::ShutdownCmd(CmdArgList args, ConnectionContext* cntx) {
[](ProactorBase* pb) { ServerState::tlocal()->EnterLameDuck(); });
CHECK_NOTNULL(acceptor_)->Stop();
(*cntx)->SendOk();
cntx->SendOk();
}
void ServerFamily::SyncGeneric(std::string_view repl_master_id, uint64_t offs,
@ -2223,7 +2229,7 @@ void ServerFamily::SyncGeneric(std::string_view repl_master_id, uint64_t offs,
if (cntx->async_dispatch) {
// SYNC is a special command that should not be sent in batch with other commands.
// It should be the last command since afterwards the server just dumps the replication data.
(*cntx)->SendError("Can not sync in pipeline mode");
cntx->SendError("Can not sync in pipeline mode");
return;
}
@ -2255,7 +2261,8 @@ void ServerFamily::SlowLog(CmdArgList args, ConnectionContext* cntx) {
"HELP",
" Prints this help.",
};
(*cntx)->SendSimpleStrArr(help);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->SendSimpleStrArr(help);
return;
}
@ -2265,41 +2272,42 @@ void ServerFamily::SlowLog(CmdArgList args, ConnectionContext* cntx) {
lengths[index] = ServerState::tlocal()->GetSlowLog().Length();
});
int sum = std::accumulate(lengths.begin(), lengths.end(), 0);
return (*cntx)->SendLong(sum);
return cntx->SendLong(sum);
}
if (sub_cmd == "RESET") {
service_.proactor_pool().AwaitFiberOnAll(
[](auto index, auto* context) { ServerState::tlocal()->GetSlowLog().Reset(); });
return (*cntx)->SendOk();
return cntx->SendOk();
}
if (sub_cmd == "GET") {
return SlowLogGet(args, cntx, service_, sub_cmd);
}
(*cntx)->SendError(UnknownSubCmd(sub_cmd, "SLOWLOG"), kSyntaxErrType);
cntx->SendError(UnknownSubCmd(sub_cmd, "SLOWLOG"), kSyntaxErrType);
}
void ServerFamily::Module(CmdArgList args, ConnectionContext* cntx) {
ToUpper(&args[0]);
if (ArgS(args, 0) != "LIST")
return (*cntx)->SendError(kSyntaxErr);
return cntx->SendError(kSyntaxErr);
(*cntx)->StartArray(2);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->StartArray(2);
// Json
(*cntx)->StartCollection(2, RedisReplyBuilder::MAP);
(*cntx)->SendSimpleString("name");
(*cntx)->SendSimpleString("ReJSON");
(*cntx)->SendSimpleString("ver");
(*cntx)->SendLong(20'000);
rb->StartCollection(2, RedisReplyBuilder::MAP);
rb->SendSimpleString("name");
rb->SendSimpleString("ReJSON");
rb->SendSimpleString("ver");
rb->SendLong(20'000);
// Search
(*cntx)->StartCollection(2, RedisReplyBuilder::MAP);
(*cntx)->SendSimpleString("name");
(*cntx)->SendSimpleString("search");
(*cntx)->SendSimpleString("ver");
(*cntx)->SendLong(20'000); // we target v2
rb->StartCollection(2, RedisReplyBuilder::MAP);
rb->SendSimpleString("name");
rb->SendSimpleString("search");
rb->SendSimpleString("ver");
rb->SendLong(20'000); // we target v2
}
#define HFUNC(x) SetHandler(HandlerFunc(this, &ServerFamily::x))

View file

@ -1083,10 +1083,10 @@ void SAdd(CmdArgList args, ConnectionContext* cntx) {
OpResult<uint32_t> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
if (result) {
return (*cntx)->SendLong(result.value());
return cntx->SendLong(result.value());
}
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
void SIsMember(CmdArgList args, ConnectionContext* cntx) {
@ -1107,9 +1107,9 @@ void SIsMember(CmdArgList args, ConnectionContext* cntx) {
OpResult<void> result = cntx->transaction->ScheduleSingleHop(std::move(cb));
switch (result.status()) {
case OpStatus::OK:
return (*cntx)->SendLong(1);
return cntx->SendLong(1);
default:
return (*cntx)->SendLong(0);
return cntx->SendLong(0);
}
}
@ -1134,14 +1134,15 @@ void SMIsMember(CmdArgList args, ConnectionContext* cntx) {
return find_res.status();
};
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
OpResult<void> result = cntx->transaction->ScheduleSingleHop(std::move(cb));
if (result == OpStatus::KEY_NOTFOUND) {
memberships.assign(vals.size(), "0");
return (*cntx)->SendStringArr(memberships);
return rb->SendStringArr(memberships);
} else if (result == OpStatus::OK) {
return (*cntx)->SendStringArr(memberships);
return rb->SendStringArr(memberships);
}
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
void SMove(CmdArgList args, ConnectionContext* cntx) {
@ -1156,11 +1157,11 @@ void SMove(CmdArgList args, ConnectionContext* cntx) {
OpResult<unsigned> result = mover.Commit(cntx->transaction);
if (!result) {
return (*cntx)->SendError(result.status());
return cntx->SendError(result.status());
return;
}
(*cntx)->SendLong(result.value());
cntx->SendLong(result.value());
}
void SRem(CmdArgList args, ConnectionContext* cntx) {
@ -1178,11 +1179,11 @@ void SRem(CmdArgList args, ConnectionContext* cntx) {
switch (result.status()) {
case OpStatus::WRONG_TYPE:
return (*cntx)->SendError(kWrongTypeErr);
return cntx->SendError(kWrongTypeErr);
case OpStatus::OK:
return (*cntx)->SendLong(result.value());
return cntx->SendLong(result.value());
default:
return (*cntx)->SendLong(0);
return cntx->SendLong(0);
}
}
@ -1202,11 +1203,11 @@ void SCard(CmdArgList args, ConnectionContext* cntx) {
switch (result.status()) {
case OpStatus::OK:
return (*cntx)->SendLong(result.value());
return cntx->SendLong(result.value());
case OpStatus::WRONG_TYPE:
return (*cntx)->SendError(kWrongTypeErr);
return cntx->SendError(kWrongTypeErr);
default:
return (*cntx)->SendLong(0);
return cntx->SendLong(0);
}
}
@ -1216,7 +1217,7 @@ void SPop(CmdArgList args, ConnectionContext* cntx) {
if (args.size() > 1) {
string_view arg = ArgS(args, 1);
if (!absl::SimpleAtoi(arg, &count)) {
(*cntx)->SendError(kInvalidIntErr);
cntx->SendError(kInvalidIntErr);
return;
}
}
@ -1225,22 +1226,23 @@ void SPop(CmdArgList args, ConnectionContext* cntx) {
return OpPop(t->GetOpArgs(shard), key, count);
};
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
OpResult<StringVec> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
if (result || result.status() == OpStatus::KEY_NOTFOUND) {
if (args.size() == 1) { // SPOP key
if (result.status() == OpStatus::KEY_NOTFOUND) {
(*cntx)->SendNull();
rb->SendNull();
} else {
DCHECK_EQ(1u, result.value().size());
(*cntx)->SendBulkString(result.value().front());
rb->SendBulkString(result.value().front());
}
} else { // SPOP key cnt
(*cntx)->SendStringArr(*result, RedisReplyBuilder::SET);
rb->SendStringArr(*result, RedisReplyBuilder::SET);
}
return;
}
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
void SDiff(CmdArgList args, ConnectionContext* cntx) {
@ -1263,7 +1265,7 @@ void SDiff(CmdArgList args, ConnectionContext* cntx) {
cntx->transaction->ScheduleSingleHop(std::move(cb));
ResultSetView rsv = DiffResultVec(result_set, src_shard);
if (!rsv) {
(*cntx)->SendError(rsv.status());
cntx->SendError(rsv.status());
return;
}
@ -1271,7 +1273,8 @@ void SDiff(CmdArgList args, ConnectionContext* cntx) {
if (cntx->conn_state.script_info) { // sort under script
sort(arr.begin(), arr.end());
}
(*cntx)->SendStringArr(arr, RedisReplyBuilder::SET);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->SendStringArr(arr, RedisReplyBuilder::SET);
}
void SDiffStore(CmdArgList args, ConnectionContext* cntx) {
@ -1311,7 +1314,7 @@ void SDiffStore(CmdArgList args, ConnectionContext* cntx) {
ResultSetView rsv = DiffResultVec(result_set, src_shard);
if (!rsv) {
cntx->transaction->Conclude();
(*cntx)->SendError(rsv.status());
cntx->SendError(rsv.status());
return;
}
@ -1325,7 +1328,7 @@ void SDiffStore(CmdArgList args, ConnectionContext* cntx) {
};
cntx->transaction->Execute(std::move(store_cb), true);
(*cntx)->SendLong(result.size());
cntx->SendLong(result.size());
}
void SMembers(CmdArgList args, ConnectionContext* cntx) {
@ -1339,9 +1342,10 @@ void SMembers(CmdArgList args, ConnectionContext* cntx) {
if (cntx->conn_state.script_info) { // sort under script
sort(svec.begin(), svec.end());
}
(*cntx)->SendStringArr(*result, RedisReplyBuilder::SET);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->SendStringArr(*result, RedisReplyBuilder::SET);
} else {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
}
@ -1353,10 +1357,10 @@ void SRandMember(CmdArgList args, ConnectionContext* cntx) {
int count = is_count ? parser.Next<int>() : 1;
if (parser.HasNext())
return (*cntx)->SendError(WrongNumArgsError("SRANDMEMBER"));
return cntx->SendError(WrongNumArgsError("SRANDMEMBER"));
if (auto err = parser.Error(); err)
return (*cntx)->SendError(err->MakeReply());
return cntx->SendError(err->MakeReply());
const unsigned ucount = std::abs(count);
@ -1385,7 +1389,7 @@ void SRandMember(CmdArgList args, ConnectionContext* cntx) {
};
OpResult<StringVec> result = cntx->transaction->ScheduleSingleHopT(cb);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
if (result) {
if (count < 0 && !result->empty()) {
for (auto i = result->size(); i < ucount; ++i) {
@ -1393,15 +1397,15 @@ void SRandMember(CmdArgList args, ConnectionContext* cntx) {
result->push_back(result->front());
}
}
(*cntx)->SendStringArr(*result, RedisReplyBuilder::SET);
rb->SendStringArr(*result, RedisReplyBuilder::SET);
} else if (result.status() == OpStatus::KEY_NOTFOUND) {
if (is_count) {
(*cntx)->SendStringArr(StringVec(), RedisReplyBuilder::SET);
rb->SendStringArr(StringVec(), RedisReplyBuilder::SET);
} else {
(*cntx)->SendNull();
rb->SendNull();
}
} else {
(*cntx)->SendError(result.status());
rb->SendError(result.status());
}
}
@ -1421,9 +1425,10 @@ void SInter(CmdArgList args, ConnectionContext* cntx) {
if (cntx->conn_state.script_info) { // sort under script
sort(arr.begin(), arr.end());
}
(*cntx)->SendStringArr(arr, RedisReplyBuilder::SET);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->SendStringArr(arr, RedisReplyBuilder::SET);
} else {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
}
@ -1451,7 +1456,7 @@ void SInterStore(CmdArgList args, ConnectionContext* cntx) {
OpResult<SvArray> result = InterResultVec(result_set, inter_shard_cnt.load(memory_order_relaxed));
if (!result) {
cntx->transaction->Conclude();
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
return;
}
@ -1464,20 +1469,20 @@ void SInterStore(CmdArgList args, ConnectionContext* cntx) {
};
cntx->transaction->Execute(std::move(store_cb), true);
(*cntx)->SendLong(result->size());
cntx->SendLong(result->size());
}
void SInterCard(CmdArgList args, ConnectionContext* cntx) {
unsigned num_keys;
if (!absl::SimpleAtoi(ArgS(args, 0), &num_keys))
return (*cntx)->SendError(kSyntaxErr);
return cntx->SendError(kSyntaxErr);
unsigned limit = 0;
if (args.size() == (num_keys + 3) && ArgS(args, 1 + num_keys) == "LIMIT") {
if (!absl::SimpleAtoi(ArgS(args, num_keys + 2), &limit))
return (*cntx)->SendError("limit can't be negative");
return cntx->SendError("limit can't be negative");
} else if (args.size() > (num_keys + 1))
return (*cntx)->SendError(kSyntaxErr);
return cntx->SendError(kSyntaxErr);
ResultStringVec result_set(shard_set->size(), OpStatus::SKIPPED);
auto cb = [&](Transaction* t, EngineShard* shard) {
@ -1489,7 +1494,7 @@ void SInterCard(CmdArgList args, ConnectionContext* cntx) {
OpResult<SvArray> result =
InterResultVec(result_set, cntx->transaction->GetUniqueShardCnt(), limit);
return (*cntx)->SendLong(result->size());
return cntx->SendLong(result->size());
}
void SUnion(CmdArgList args, ConnectionContext* cntx) {
@ -1509,9 +1514,10 @@ void SUnion(CmdArgList args, ConnectionContext* cntx) {
if (cntx->conn_state.script_info) { // sort under script
sort(arr.begin(), arr.end());
}
(*cntx)->SendStringArr(arr, RedisReplyBuilder::SET);
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->SendStringArr(arr, RedisReplyBuilder::SET);
} else {
(*cntx)->SendError(unionset.status());
cntx->SendError(unionset.status());
}
}
@ -1538,7 +1544,7 @@ void SUnionStore(CmdArgList args, ConnectionContext* cntx) {
ResultSetView unionset = UnionResultVec(result_set);
if (!unionset) {
cntx->transaction->Conclude();
(*cntx)->SendError(unionset.status());
cntx->SendError(unionset.status());
return;
}
@ -1553,7 +1559,7 @@ void SUnionStore(CmdArgList args, ConnectionContext* cntx) {
};
cntx->transaction->Execute(std::move(store_cb), true);
(*cntx)->SendLong(result.size());
cntx->SendLong(result.size());
}
void SScan(CmdArgList args, ConnectionContext* cntx) {
@ -1563,19 +1569,19 @@ void SScan(CmdArgList args, ConnectionContext* cntx) {
uint64_t cursor = 0;
if (!absl::SimpleAtoi(token, &cursor)) {
return (*cntx)->SendError("invalid cursor");
return cntx->SendError("invalid cursor");
}
// SSCAN key cursor [MATCH pattern] [COUNT count]
if (args.size() > 6) {
DVLOG(1) << "got " << args.size() << " this is more than it should be";
return (*cntx)->SendError(kSyntaxErr);
return cntx->SendError(kSyntaxErr);
}
OpResult<ScanOpts> ops = ScanOpts::TryFrom(args.subspan(2));
if (!ops) {
DVLOG(1) << "SScan invalid args - return " << ops << " to the user";
return (*cntx)->SendError(ops.status());
return cntx->SendError(ops.status());
}
ScanOpts scan_op = ops.value();
@ -1584,16 +1590,17 @@ void SScan(CmdArgList args, ConnectionContext* cntx) {
return OpScan(t->GetOpArgs(shard), key, &cursor, scan_op);
};
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
OpResult<StringVec> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
if (result.status() != OpStatus::WRONG_TYPE) {
(*cntx)->StartArray(2);
(*cntx)->SendBulkString(absl::StrCat(cursor));
(*cntx)->StartArray(result->size()); // Within scan the return page is of type array
rb->StartArray(2);
rb->SendBulkString(absl::StrCat(cursor));
rb->StartArray(result->size()); // Within scan the return page is of type array
for (const auto& k : *result) {
(*cntx)->SendBulkString(k);
rb->SendBulkString(k);
}
} else {
(*cntx)->SendError(result.status());
rb->SendError(result.status());
}
}
@ -1605,7 +1612,7 @@ void SAddEx(CmdArgList args, ConnectionContext* cntx) {
constexpr uint32_t kMaxTtl = (1UL << 26);
if (!absl::SimpleAtoi(ttl_str, &ttl_sec) || ttl_sec == 0 || ttl_sec > kMaxTtl) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
vector<string_view> vals(args.size() - 2);
@ -1621,10 +1628,10 @@ void SAddEx(CmdArgList args, ConnectionContext* cntx) {
OpResult<uint32_t> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
if (result) {
return (*cntx)->SendLong(result.value());
return cntx->SendLong(result.value());
}
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
}
} // namespace

File diff suppressed because it is too large Load diff

View file

@ -791,11 +791,12 @@ void StringFamily::Set(CmdArgList args, ConnectionContext* cntx) {
const auto result{SetGeneric(cntx, sparams, key, value, true)};
if (sparams.flags & SetCmd::SET_GET) {
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
// When SET_GET is used, the reply is not affected by whether anything was set.
if (result->has_value()) {
(*cntx)->SendBulkString(result->value());
rb->SendBulkString(result->value());
} else {
(*cntx)->SendNull();
rb->SendNull();
}
return;
}
@ -853,17 +854,18 @@ void StringFamily::Get(CmdArgList args, ConnectionContext* cntx) {
Transaction* trans = cntx->transaction;
OpResult<string> result = trans->ScheduleSingleHopT(std::move(cb));
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
if (result) {
DVLOG(1) << "GET " << trans->DebugId() << ": " << key << " " << result.value();
(*cntx)->SendBulkString(*result);
rb->SendBulkString(*result);
} else {
switch (result.status()) {
case OpStatus::WRONG_TYPE:
(*cntx)->SendError(kWrongTypeErr);
rb->SendError(kWrongTypeErr);
break;
default:
DVLOG(1) << "GET " << key << " nil";
(*cntx)->SendNull();
rb->SendNull();
}
}
}
@ -881,17 +883,18 @@ void StringFamily::GetDel(CmdArgList args, ConnectionContext* cntx) {
Transaction* trans = cntx->transaction;
OpResult<string> result = trans->ScheduleSingleHopT(std::move(cb));
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
if (result) {
DVLOG(1) << "GET " << trans->DebugId() << ": " << key << " " << result.value();
(*cntx)->SendBulkString(*result);
rb->SendBulkString(*result);
} else {
switch (result.status()) {
case OpStatus::WRONG_TYPE:
(*cntx)->SendError(kWrongTypeErr);
rb->SendError(kWrongTypeErr);
break;
default:
DVLOG(1) << "GET " << key << " nil";
(*cntx)->SendNull();
rb->SendNull();
}
}
}
@ -912,16 +915,17 @@ void StringFamily::GetSet(CmdArgList args, ConnectionContext* cntx) {
OpStatus status = cntx->transaction->ScheduleSingleHop(std::move(cb));
if (status != OpStatus::OK) {
(*cntx)->SendError(status);
cntx->SendError(status);
return;
}
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
if (prev_val) {
(*cntx)->SendBulkString(*prev_val);
rb->SendBulkString(*prev_val);
return;
}
return (*cntx)->SendNull();
return rb->SendNull();
}
void StringFamily::GetEx(CmdArgList args, ConnectionContext* cntx) {
@ -938,16 +942,16 @@ void StringFamily::GetEx(CmdArgList args, ConnectionContext* cntx) {
if (cur_arg == "EX" || cur_arg == "PX" || cur_arg == "EXAT" || cur_arg == "PXAT") {
i++;
if (i >= args.size()) {
return (*cntx)->SendError(kSyntaxErr);
return cntx->SendError(kSyntaxErr);
}
string_view ex = ArgS(args, i);
if (!absl::SimpleAtoi(ex, &int_arg)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
if (int_arg <= 0) {
return (*cntx)->SendError(InvalidExpireTime("getex"));
return cntx->SendError(InvalidExpireTime("getex"));
}
if (cur_arg == "EXAT" || cur_arg == "PXAT") {
@ -963,7 +967,7 @@ void StringFamily::GetEx(CmdArgList args, ConnectionContext* cntx) {
} else if (cur_arg == "PERSIST") {
exp_params.persist = true;
} else {
return (*cntx)->SendError(kSyntaxErr);
return cntx->SendError(kSyntaxErr);
}
}
@ -989,16 +993,17 @@ void StringFamily::GetEx(CmdArgList args, ConnectionContext* cntx) {
OpResult<string> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
if (result)
return (*cntx)->SendBulkString(*result);
return rb->SendBulkString(*result);
switch (result.status()) {
case OpStatus::WRONG_TYPE:
(*cntx)->SendError(kWrongTypeErr);
rb->SendError(kWrongTypeErr);
break;
default:
DVLOG(1) << "GET " << key << " nil";
(*cntx)->SendNull();
rb->SendNull();
}
}
@ -1013,7 +1018,7 @@ void StringFamily::IncrBy(CmdArgList args, ConnectionContext* cntx) {
int64_t val;
if (!absl::SimpleAtoi(sval, &val)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
return IncrByGeneric(key, val, cntx);
}
@ -1024,7 +1029,7 @@ void StringFamily::IncrByFloat(CmdArgList args, ConnectionContext* cntx) {
double val;
if (!absl::SimpleAtod(sval, &val)) {
return (*cntx)->SendError(kInvalidFloatErr);
return cntx->SendError(kInvalidFloatErr);
}
auto cb = [&](Transaction* t, EngineShard* shard) {
@ -1036,7 +1041,7 @@ void StringFamily::IncrByFloat(CmdArgList args, ConnectionContext* cntx) {
DVLOG(2) << "IncrByGeneric " << key << "/" << result.value();
if (!result) {
return (*cntx)->SendError(result.status());
return cntx->SendError(result.status());
}
builder->SendDouble(result.value());
@ -1053,10 +1058,10 @@ void StringFamily::DecrBy(CmdArgList args, ConnectionContext* cntx) {
int64_t val;
if (!absl::SimpleAtoi(sval, &val)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
if (val == INT64_MIN) {
return (*cntx)->SendError(kIncrOverflow);
return cntx->SendError(kIncrOverflow);
}
return IncrByGeneric(key, -val, cntx);
@ -1114,9 +1119,9 @@ void StringFamily::ExtendGeneric(CmdArgList args, bool prepend, ConnectionContex
OpResult<uint32_t> result = cntx->transaction->ScheduleSingleHopT(std::move(cb));
if (!result)
return (*cntx)->SendError(result.status());
return cntx->SendError(result.status());
else
return (*cntx)->SendLong(result.value());
return cntx->SendLong(result.value());
}
DCHECK(cntx->protocol() == Protocol::MEMCACHE);
@ -1142,11 +1147,11 @@ void StringFamily::SetExGeneric(bool seconds, CmdArgList args, ConnectionContext
int32_t unit_vals;
if (!absl::SimpleAtoi(ex, &unit_vals)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
if (unit_vals < 1 || unit_vals >= kMaxExpireDeadlineSec) {
return (*cntx)->SendError(InvalidExpireTime(cntx->cid->name()));
return cntx->SendError(InvalidExpireTime(cntx->cid->name()));
}
SetCmd::SetParams sparams;
@ -1163,7 +1168,7 @@ void StringFamily::SetExGeneric(bool seconds, CmdArgList args, ConnectionContext
OpResult<void> result = cntx->transaction->ScheduleSingleHop(std::move(cb));
return (*cntx)->SendError(result.status());
return cntx->SendError(result.status());
}
void StringFamily::MGet(CmdArgList args, ConnectionContext* cntx) {
@ -1241,9 +1246,9 @@ void StringFamily::MSet(CmdArgList args, ConnectionContext* cntx) {
OpStatus status = transaction->ScheduleSingleHop(std::move(cb));
if (status == OpStatus::OK) {
(*cntx)->SendOk();
cntx->SendOk();
} else {
(*cntx)->SendError(status);
cntx->SendError(status);
}
}
@ -1280,7 +1285,7 @@ void StringFamily::MSetNx(CmdArgList args, ConnectionContext* cntx) {
transaction->Execute(std::move(epilog_cb), true);
(*cntx)->SendLong(to_skip ? 0 : 1);
cntx->SendLong(to_skip ? 0 : 1);
}
void StringFamily::StrLen(CmdArgList args, ConnectionContext* cntx) {
@ -1298,9 +1303,9 @@ void StringFamily::StrLen(CmdArgList args, ConnectionContext* cntx) {
OpResult<size_t> result = trans->ScheduleSingleHopT(std::move(cb));
if (result.status() == OpStatus::WRONG_TYPE) {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
} else {
(*cntx)->SendLong(result.value());
cntx->SendLong(result.value());
}
}
@ -1311,7 +1316,7 @@ void StringFamily::GetRange(CmdArgList args, ConnectionContext* cntx) {
int32_t start, end;
if (!absl::SimpleAtoi(from, &start) || !absl::SimpleAtoi(to, &end)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
auto cb = [&](Transaction* t, EngineShard* shard) {
@ -1322,9 +1327,10 @@ void StringFamily::GetRange(CmdArgList args, ConnectionContext* cntx) {
OpResult<string> result = trans->ScheduleSingleHopT(std::move(cb));
if (result.status() == OpStatus::WRONG_TYPE) {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
} else {
(*cntx)->SendBulkString(result.value());
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->SendBulkString(result.value());
}
}
@ -1335,16 +1341,16 @@ void StringFamily::SetRange(CmdArgList args, ConnectionContext* cntx) {
int32_t start;
if (!absl::SimpleAtoi(offset, &start)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
if (start < 0) {
return (*cntx)->SendError("offset is out of range");
return cntx->SendError("offset is out of range");
}
size_t min_size = start + value.size();
if (min_size > kMaxStrLen) {
return (*cntx)->SendError("string exceeds maximum allowed size");
return cntx->SendError("string exceeds maximum allowed size");
}
auto cb = [&](Transaction* t, EngineShard* shard) -> OpResult<uint32_t> {
@ -1355,9 +1361,9 @@ void StringFamily::SetRange(CmdArgList args, ConnectionContext* cntx) {
OpResult<uint32_t> result = trans->ScheduleSingleHopT(std::move(cb));
if (result.status() == OpStatus::WRONG_TYPE) {
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
} else {
(*cntx)->SendLong(result.value());
cntx->SendLong(result.value());
}
}
@ -1381,21 +1387,21 @@ void StringFamily::ClThrottle(CmdArgList args, ConnectionContext* cntx) {
uint64_t max_burst;
const string_view max_burst_str = ArgS(args, 1);
if (!absl::SimpleAtoi(max_burst_str, &max_burst)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
// Emit count of tokens per period
uint64_t count;
const string_view count_str = ArgS(args, 2);
if (!absl::SimpleAtoi(count_str, &count)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
// Period of emitting count of tokens
uint64_t period;
const string_view period_str = ArgS(args, 3);
if (!absl::SimpleAtoi(period_str, &period)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
// Apply quantity of tokens now
@ -1404,22 +1410,22 @@ void StringFamily::ClThrottle(CmdArgList args, ConnectionContext* cntx) {
const string_view quantity_str = ArgS(args, 4);
if (!absl::SimpleAtoi(quantity_str, &quantity)) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
}
if (max_burst > INT64_MAX - 1) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
const int64_t limit = max_burst + 1;
if (period > UINT64_MAX / 1000 || count == 0 || period * 1000 / count > INT64_MAX) {
return (*cntx)->SendError(kInvalidIntErr);
return cntx->SendError(kInvalidIntErr);
}
const int64_t emission_interval_ms = period * 1000 / count;
if (emission_interval_ms == 0) {
return (*cntx)->SendError("zero rates are not supported");
return cntx->SendError("zero rates are not supported");
}
auto cb = [&](Transaction* t, EngineShard* shard) -> OpResult<array<int64_t, 5>> {
@ -1430,7 +1436,8 @@ void StringFamily::ClThrottle(CmdArgList args, ConnectionContext* cntx) {
OpResult<array<int64_t, 5>> result = trans->ScheduleSingleHopT(std::move(cb));
if (result) {
(*cntx)->StartArray(result->size());
auto* rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
rb->StartArray(result->size());
auto& array = result.value();
int64_t retry_after_s = array[3] / 1000;
@ -1446,22 +1453,22 @@ void StringFamily::ClThrottle(CmdArgList args, ConnectionContext* cntx) {
array[4] = reset_after_s;
for (const auto& v : array) {
(*cntx)->SendLong(v);
rb->SendLong(v);
}
} else {
switch (result.status()) {
case OpStatus::WRONG_TYPE:
(*cntx)->SendError(kWrongTypeErr);
cntx->SendError(kWrongTypeErr);
break;
case OpStatus::INVALID_INT:
case OpStatus::INVALID_VALUE:
(*cntx)->SendError(kInvalidIntErr);
cntx->SendError(kInvalidIntErr);
break;
case OpStatus::OUT_OF_MEMORY:
(*cntx)->SendError(kOutOfMemory);
cntx->SendError(kOutOfMemory);
break;
default:
(*cntx)->SendError(result.status());
cntx->SendError(result.status());
break;
}
}

353
src/server/zset_family.cc Executable file → Normal file

File diff suppressed because it is too large Load diff