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:
parent
1900e499ba
commit
33d0879416
26 changed files with 1424 additions and 1314 deletions
|
@ -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_);
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.";
|
||||
|
|
|
@ -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),
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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},
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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, ¶ms->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, ¶ms->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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,18 +1358,18 @@ 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"),
|
||||
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))
|
||||
|
|
|
@ -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
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
351
src/server/zset_family.cc
Executable file → Normal file
351
src/server/zset_family.cc
Executable file → Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue