Skip to content

Commit fa0e637

Browse files
committed
chore: introduce ParsedArguments class
Currently we use ArgSlice, CmdArgList everywhere where we want a span on string_views. As a result, it's very hard to understand the requirements from the passed classes. This PR introduces a new ParsedArguments class and reduces the API surface for the passed object. Make sure to unwind ParsedArguments to ArgSlice only when we start executing the command. We will clean-up redundant aliases in the futures. Signed-off-by: Roman Gershman <[email protected]>
1 parent 921cb68 commit fa0e637

File tree

13 files changed

+78
-47
lines changed

13 files changed

+78
-47
lines changed

src/facade/cmd_arg_parser.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ struct CmdArgParser {
5656
};
5757

5858
public:
59-
CmdArgParser(CmdArgList args) : args_{args} {
59+
CmdArgParser(ArgSlice args) : args_{args} {
6060
}
6161

6262
// Debug asserts sure error was consumed
@@ -159,7 +159,7 @@ struct CmdArgParser {
159159
}
160160

161161
// Return remaining arguments
162-
CmdArgList Tail() const {
162+
ArgSlice Tail() const {
163163
return args_.subspan(cur_i_);
164164
}
165165

@@ -168,7 +168,7 @@ struct CmdArgParser {
168168
return cur_i_ < args_.size() && !error_;
169169
}
170170

171-
bool HasError() {
171+
bool HasError() const {
172172
return error_.type != ErrorType::NO_ERROR;
173173
}
174174

@@ -275,7 +275,7 @@ struct CmdArgParser {
275275

276276
private:
277277
size_t cur_i_ = 0;
278-
CmdArgList args_;
278+
ArgSlice args_;
279279

280280
ErrorInfo error_;
281281
};

src/facade/command_id.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,14 @@
44

55
#pragma once
66

7+
#include <cstdint>
8+
#include <string>
79
#include <string_view>
810

9-
#include "facade/facade_types.h"
10-
1111
namespace facade {
1212

1313
class CommandId {
1414
public:
15-
using CmdArgList = facade::CmdArgList;
16-
1715
/**
1816
* @brief Construct a new Command Id object
1917
*

src/facade/dragonfly_connection.cc

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -558,8 +558,7 @@ void Connection::AsyncOperations::operator()(Connection::PipelineMessage& msg) {
558558
DVLOG(2) << "Dispatching pipeline: " << ToSV(msg.args.front());
559559

560560
++self->local_stats_.cmds;
561-
self->service_->DispatchCommand(CmdArgList{msg.args.data(), msg.args.size()},
562-
self->reply_builder_.get(), self->cc_.get());
561+
self->service_->DispatchCommand({msg.args}, self->reply_builder_.get(), self->cc_.get());
563562

564563
self->last_interaction_ = time(nullptr);
565564
self->skip_next_squashing_ = false;
@@ -1219,7 +1218,7 @@ Connection::ParserStatus Connection::ParseRedis(unsigned max_busy_cycles) {
12191218

12201219
auto dispatch_sync = [this] {
12211220
RespExpr::VecToArgList(tmp_parse_args_, &tmp_cmd_vec_);
1222-
service_->DispatchCommand(absl::MakeSpan(tmp_cmd_vec_), reply_builder_.get(), cc_.get());
1221+
service_->DispatchCommand({tmp_cmd_vec_}, reply_builder_.get(), cc_.get());
12231222
};
12241223

12251224
auto dispatch_async = [this]() -> MessageHandle { return {FromArgs(tmp_parse_args_)}; };
@@ -1536,7 +1535,7 @@ void Connection::SquashPipeline() {
15361535
DCHECK_EQ(dispatch_q_.size(), pending_pipeline_cmd_cnt_);
15371536
DCHECK_EQ(reply_builder_->GetProtocol(), Protocol::REDIS); // Only Redis is supported.
15381537

1539-
vector<ArgSlice> squash_cmds;
1538+
vector<ParsedArgs> squash_cmds;
15401539
squash_cmds.reserve(dispatch_q_.size());
15411540

15421541
uint64_t start = CycleClock::Now();
@@ -1546,7 +1545,7 @@ void Connection::SquashPipeline() {
15461545
<< msg.handle.index() << " on " << DebugInfo();
15471546

15481547
auto& pmsg = get<PipelineMessagePtr>(msg.handle);
1549-
squash_cmds.emplace_back(absl::MakeSpan(pmsg->args));
1548+
squash_cmds.emplace_back(ParsedArgs(pmsg->args));
15501549
if (squash_cmds.size() >= pipeline_squash_limit_cached) {
15511550
// We reached the limit of commands to squash, so we dispatch them.
15521551
break;

src/facade/facade_types.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,37 @@ using CmdArgVec = std::vector<std::string_view>;
4141
using ArgSlice = absl::Span<const std::string_view>;
4242
using OwnedArgSlice = absl::Span<const std::string>;
4343

44+
class ParsedArgs {
45+
public:
46+
ParsedArgs() = default;
47+
48+
ParsedArgs(ArgSlice args) : args_(args) { // NOLINT google-explicit-constructor
49+
}
50+
51+
size_t size() const {
52+
return args_.size();
53+
}
54+
55+
bool empty() const {
56+
return args_.empty();
57+
}
58+
59+
ParsedArgs Tail() const {
60+
return ParsedArgs{args_.subspan(1)};
61+
}
62+
63+
std::string_view Front() const {
64+
return args_.front();
65+
}
66+
67+
ArgSlice ToSlice() const {
68+
return args_;
69+
}
70+
71+
private:
72+
absl::Span<const std::string_view> args_;
73+
};
74+
4475
inline std::string_view ToSV(std::string_view slice) {
4576
return slice;
4677
}

src/facade/ok_main.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ namespace {
2222

2323
class OkService : public ServiceInterface {
2424
public:
25-
DispatchResult DispatchCommand(ArgSlice args, SinkReplyBuilder* builder,
25+
DispatchResult DispatchCommand(ParsedArgs args, SinkReplyBuilder* builder,
2626
ConnectionContext* cntx) final {
2727
builder->SendOk();
2828
return DispatchResult::OK;
2929
}
3030

31-
DispatchManyResult DispatchManyCommands(absl::Span<ArgSlice> args_lists,
31+
DispatchManyResult DispatchManyCommands(absl::Span<ParsedArgs> args_lists,
3232
SinkReplyBuilder* builder,
3333
ConnectionContext* cntx) final {
3434
for (auto args : args_lists)

src/facade/service_interface.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ class ServiceInterface {
3636
virtual ~ServiceInterface() {
3737
}
3838

39-
virtual DispatchResult DispatchCommand(ArgSlice args, SinkReplyBuilder* builder,
39+
virtual DispatchResult DispatchCommand(ParsedArgs args, SinkReplyBuilder* builder,
4040
ConnectionContext* cntx) = 0;
4141

42-
virtual DispatchManyResult DispatchManyCommands(absl::Span<ArgSlice> commands,
42+
virtual DispatchManyResult DispatchManyCommands(absl::Span<ParsedArgs> commands,
4343
SinkReplyBuilder* builder,
4444
ConnectionContext* cntx) = 0;
4545

src/server/command_registry.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -325,17 +325,17 @@ CommandRegistry::FamiliesVec CommandRegistry::GetFamilies() {
325325
return std::move(family_of_commands_);
326326
}
327327

328-
std::pair<const CommandId*, ArgSlice> CommandRegistry::FindExtended(string_view cmd,
329-
ArgSlice tail_args) const {
328+
std::pair<const CommandId*, ParsedArgs> CommandRegistry::FindExtended(string_view cmd,
329+
ParsedArgs tail_args) const {
330330
if (cmd == RenamedOrOriginal("ACL"sv)) {
331331
if (tail_args.empty()) {
332332
return {Find(cmd), {}};
333333
}
334334

335-
auto second_cmd = absl::AsciiStrToUpper(ArgS(tail_args, 0));
335+
auto second_cmd = absl::AsciiStrToUpper(tail_args.Front());
336336
string full_cmd = absl::StrCat(cmd, " ", second_cmd);
337337

338-
return {Find(full_cmd), tail_args.subspan(1)};
338+
return {Find(full_cmd), tail_args.Tail()};
339339
}
340340

341341
const CommandId* res = Find(cmd);
@@ -344,7 +344,7 @@ std::pair<const CommandId*, ArgSlice> CommandRegistry::FindExtended(string_view
344344

345345
// A workaround for XGROUP HELP that does not fit our static taxonomy of commands.
346346
if (tail_args.size() == 1 && res->name() == "XGROUP") {
347-
if (absl::EqualsIgnoreCase(ArgS(tail_args, 0), "HELP")) {
347+
if (absl::EqualsIgnoreCase(tail_args.Front(), "HELP")) {
348348
res = Find("_XGROUP_HELP");
349349
}
350350
}

src/server/command_registry.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include "base/function2.hpp"
1616
#include "facade/command_id.h"
17+
#include "facade/facade_types.h"
1718

1819
namespace facade {
1920
class SinkReplyBuilder;
@@ -107,6 +108,8 @@ template <typename T> class MoveOnly {
107108

108109
class CommandId : public facade::CommandId {
109110
public:
111+
using CmdArgList = facade::CmdArgList;
112+
110113
// NOTICE: name must be a literal string, otherwise metrics break! (see cmd_stats_map in
111114
// server_state.h)
112115
CommandId(const char* name, uint32_t mask, int8_t arity, int8_t first_key, int8_t last_key,
@@ -251,8 +254,8 @@ class CommandRegistry {
251254
using FamiliesVec = std::vector<std::vector<std::string>>;
252255
FamiliesVec GetFamilies();
253256

254-
std::pair<const CommandId*, facade::ArgSlice> FindExtended(std::string_view cmd,
255-
facade::ArgSlice tail_args) const;
257+
std::pair<const CommandId*, facade::ParsedArgs> FindExtended(std::string_view cmd,
258+
facade::ParsedArgs tail_args) const;
256259

257260
absl::flat_hash_map<std::string, hdr_histogram*> LatencyMap() const;
258261

src/server/http_api.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ void HttpAPI(const http::QueryArgs& args, HttpRequest&& req, Service* service,
198198
facade::CapturingReplyBuilder reply_builder;
199199

200200
// TODO: to finish this.
201-
service->DispatchCommand(absl::MakeSpan(cmd_slices), &reply_builder, context);
201+
service->DispatchCommand({cmd_slices}, &reply_builder, context);
202202
facade::CapturingReplyBuilder::Payload payload = reply_builder.Take();
203203

204204
auto response = http::MakeStringResponse();

src/server/main_service.cc

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,16 +1423,16 @@ std::optional<ErrorReply> Service::VerifyCommandState(const CommandId* cid, CmdA
14231423
return VerifyConnectionAclStatus(cid, &dfly_cntx, "has no ACL permissions", tail_args);
14241424
}
14251425

1426-
DispatchResult Service::DispatchCommand(ArgSlice args, SinkReplyBuilder* builder,
1426+
DispatchResult Service::DispatchCommand(facade::ParsedArgs args, SinkReplyBuilder* builder,
14271427
facade::ConnectionContext* cntx) {
14281428
DCHECK(!args.empty());
14291429
DCHECK_NE(0u, shard_set->size()) << "Init was not called";
14301430

14311431
absl::Cleanup clear_last_error([builder]() { builder->ConsumeLastError(); });
14321432
ServerState& etl = *ServerState::tlocal();
14331433

1434-
string cmd = absl::AsciiStrToUpper(args[0]);
1435-
const auto [cid, args_no_cmd] = registry_.FindExtended(cmd, args.subspan(1));
1434+
string cmd = absl::AsciiStrToUpper(args.Front());
1435+
const auto [cid, args_no_cmd] = registry_.FindExtended(cmd, args.Tail());
14361436

14371437
if (cid == nullptr) {
14381438
builder->SendError(ReportUnknownCmd(cmd));
@@ -1446,7 +1446,7 @@ DispatchResult Service::DispatchCommand(ArgSlice args, SinkReplyBuilder* builder
14461446

14471447
if (VLOG_IS_ON(2) && cntx->conn() /* no owner in replica context */) {
14481448
LOG(INFO) << "Got (" << cntx->conn()->GetClientId() << "): " << (under_script ? "LUA " : "")
1449-
<< args << " in dbid=" << dfly_cntx->conn_state.db_index;
1449+
<< args.ToSlice() << " in dbid=" << dfly_cntx->conn_state.db_index;
14501450
}
14511451

14521452
// Don't interrupt running multi commands or admin connections.
@@ -1460,7 +1460,8 @@ DispatchResult Service::DispatchCommand(ArgSlice args, SinkReplyBuilder* builder
14601460
cntx->paused = false;
14611461
}
14621462

1463-
if (auto err = VerifyCommandState(cid, args_no_cmd, *dfly_cntx); err) {
1463+
auto tail_args = args_no_cmd.ToSlice();
1464+
if (auto err = VerifyCommandState(cid, tail_args, *dfly_cntx); err) {
14641465
LOG_IF(WARNING, cntx->replica_conn || !cntx->conn() /* no owner in replica context */)
14651466
<< "VerifyCommandState error: " << err->ToSv();
14661467
if (auto& exec_info = dfly_cntx->conn_state.exec_info; exec_info.IsCollecting())
@@ -1469,7 +1470,7 @@ DispatchResult Service::DispatchCommand(ArgSlice args, SinkReplyBuilder* builder
14691470
// We need to skip this because ACK's should not be replied to
14701471
// Bonus points because this allows to continue replication with ACL users who got
14711472
// their access revoked and reinstated
1472-
if (cid->name() == "REPLCONF" && absl::EqualsIgnoreCase(ArgS(args_no_cmd, 0), "ACK")) {
1473+
if (cid->name() == "REPLCONF" && absl::EqualsIgnoreCase(args_no_cmd.Front(), "ACK")) {
14731474
server_family_.GetDflyCmd()->OnClose(dfly_cntx->conn_state.replication_info.repl_session_id);
14741475
return DispatchResult::ERROR;
14751476
}
@@ -1486,7 +1487,7 @@ DispatchResult Service::DispatchCommand(ArgSlice args, SinkReplyBuilder* builder
14861487
// TODO: protect against aggregating huge transactions.
14871488
auto& exec_info = dfly_cntx->conn_state.exec_info;
14881489
const size_t old_size = exec_info.GetStoredCmdBytes();
1489-
exec_info.AddStoredCmd(cid, true, args_no_cmd);
1490+
exec_info.AddStoredCmd(cid, true, tail_args);
14901491
etl.stats.stored_cmd_bytes += exec_info.GetStoredCmdBytes() - old_size;
14911492
if (cid->IsWriteOnly()) {
14921493
exec_info.is_write = true;
@@ -1503,7 +1504,7 @@ DispatchResult Service::DispatchCommand(ArgSlice args, SinkReplyBuilder* builder
15031504
if (cid->IsTransactional()) {
15041505
dfly_cntx->transaction->MultiSwitchCmd(cid);
15051506
OpStatus status = dfly_cntx->transaction->InitByArgs(
1506-
dfly_cntx->ns, dfly_cntx->conn_state.db_index, args_no_cmd);
1507+
dfly_cntx->ns, dfly_cntx->conn_state.db_index, tail_args);
15071508

15081509
if (status != OpStatus::OK) {
15091510
builder->SendError(status);
@@ -1519,7 +1520,7 @@ DispatchResult Service::DispatchCommand(ArgSlice args, SinkReplyBuilder* builder
15191520
if (!dist_trans->IsMulti()) { // Multi command initialize themself based on their mode.
15201521
CHECK(dfly_cntx->ns != nullptr);
15211522
if (auto st =
1522-
dist_trans->InitByArgs(dfly_cntx->ns, dfly_cntx->conn_state.db_index, args_no_cmd);
1523+
dist_trans->InitByArgs(dfly_cntx->ns, dfly_cntx->conn_state.db_index, tail_args);
15231524
st != OpStatus::OK) {
15241525
builder->SendError(st);
15251526
return DispatchResult::ERROR;
@@ -1535,8 +1536,7 @@ DispatchResult Service::DispatchCommand(ArgSlice args, SinkReplyBuilder* builder
15351536

15361537
dfly_cntx->cid = cid;
15371538

1538-
auto res =
1539-
InvokeCmd(cid, args_no_cmd, CommandContext{dfly_cntx->transaction, builder, dfly_cntx});
1539+
auto res = InvokeCmd(cid, tail_args, CommandContext{dfly_cntx->transaction, builder, dfly_cntx});
15401540
if ((res != DispatchResult::OK) && (res != DispatchResult::OOM)) {
15411541
builder->SendError("Internal Error");
15421542
builder->CloseConnection();
@@ -1722,7 +1722,7 @@ DispatchResult Service::InvokeCmd(const CommandId* cid, CmdArgList tail_args,
17221722
return res;
17231723
}
17241724

1725-
DispatchManyResult Service::DispatchManyCommands(absl::Span<CmdArgList> args_list,
1725+
DispatchManyResult Service::DispatchManyCommands(absl::Span<facade::ParsedArgs> args_list,
17261726
SinkReplyBuilder* builder,
17271727
facade::ConnectionContext* cntx) {
17281728
ConnectionContext* dfly_cntx = static_cast<ConnectionContext*>(cntx);
@@ -1768,9 +1768,9 @@ DispatchManyResult Service::DispatchManyCommands(absl::Span<CmdArgList> args_lis
17681768
stored_cmds.clear();
17691769
};
17701770

1771-
for (auto args : args_list) {
1772-
string cmd = absl::AsciiStrToUpper(ArgS(args, 0));
1773-
const auto [cid, tail_args] = registry_.FindExtended(cmd, args.subspan(1));
1771+
for (const auto& args : args_list) {
1772+
string cmd = absl::AsciiStrToUpper(args.Front());
1773+
const auto [cid, tail_args] = registry_.FindExtended(cmd, args.Tail());
17741774

17751775
// MULTI...EXEC commands need to be collected into a single context, so squashing is not
17761776
// possible
@@ -1787,7 +1787,7 @@ DispatchManyResult Service::DispatchManyCommands(absl::Span<CmdArgList> args_lis
17871787

17881788
if (!is_multi && !is_eval && !is_blocking && cid != nullptr) {
17891789
stored_cmds.reserve(args_list.size());
1790-
stored_cmds.emplace_back(cid, false /* do not deep-copy commands*/, tail_args);
1790+
stored_cmds.emplace_back(cid, false /* do not deep-copy commands*/, tail_args.ToSlice());
17911791
continue;
17921792
}
17931793

@@ -1945,7 +1945,7 @@ void Service::DispatchMC(const MemcacheParser::Command& cmd, std::string_view va
19451945
}
19461946
}
19471947

1948-
DispatchCommand(CmdArgList{args}, mc_builder, cntx);
1948+
DispatchCommand(ParsedArgs{args}, mc_builder, cntx);
19491949

19501950
// Reset back.
19511951
dfly_cntx->conn_state.memcache_flag = 0;

0 commit comments

Comments
 (0)