Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat:Subcommands support separate command id #24

Merged
merged 3 commits into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 25 additions & 2 deletions src/base_cmd.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@ bool BaseCmd::HasFlag(uint32_t flag) const { return flag_ & flag; }
void BaseCmd::SetFlag(uint32_t flag) { flag_ |= flag; }
void BaseCmd::ResetFlag(uint32_t flag) { flag_ &= ~flag; }
bool BaseCmd::HasSubCommand() const { return false; }
std::vector<std::string> BaseCmd::SubCommand() const { return {}; }
int8_t BaseCmd::SubCmdIndex(const std::string& cmdName) { return -1; }
BaseCmd* BaseCmd::GetSubCmd(const std::string& cmdName) { return nullptr; }
uint32_t BaseCmd::AclCategory() const { return aclCategory_; }
void BaseCmd::AddAclCategory(uint32_t aclCategory) { aclCategory_ |= aclCategory; }
std::string BaseCmd::Name() const { return name_; }
Expand All @@ -58,4 +57,28 @@ std::string BaseCmd::Name() const { return name_; }
// std::shared_ptr<std::string> BaseCommand::GetResp() { return resp_.lock(); }
uint32_t BaseCmd::GetCmdId() const { return cmdId_; }

// BaseCmdGroup
BaseCmdGroup::BaseCmdGroup(const std::string& name, uint32_t flag) : BaseCmdGroup(name, -2, flag) {}
BaseCmdGroup::BaseCmdGroup(const std::string& name, int16_t arity, uint32_t flag) : BaseCmd(name, arity, flag, 0) {}

void BaseCmdGroup::AddSubCmd(std::unique_ptr<BaseCmd> cmd) { subCmds_[cmd->Name()] = std::move(cmd); }

BaseCmd* BaseCmdGroup::GetSubCmd(const std::string& cmdName) {
auto subCmd = subCmds_.find(cmdName);
if (subCmd == subCmds_.end()) {
return nullptr;
}
return subCmd->second.get();
}

bool BaseCmdGroup::DoInitial(CmdContext& ctx) {
ctx.subCmd_ = ctx.argv_[1];
std::transform(ctx.argv_[1].begin(), ctx.argv_[1].end(), ctx.subCmd_.begin(), ::tolower);
if (!subCmds_.contains(ctx.subCmd_)) {
ctx.SetRes(CmdRes::kSyntaxErr, ctx.argv_[0] + " unknown subcommand for '" + ctx.subCmd_ + "'");
return false;
}
return true;
}

} // namespace pikiwidb
31 changes: 24 additions & 7 deletions src/base_cmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
* of patent rights can be found in the PATENTS file in the same directory.
*/

#ifndef PIKIWIDB_SRC_BASE_CMD_H
#define PIKIWIDB_SRC_BASE_CMD_H
#pragma once

#include <atomic>
#include <map>
#include <memory>
#include <span>
#include <string>
Expand Down Expand Up @@ -159,9 +159,8 @@ class BaseCmd : public std::enable_shared_from_this<BaseCmd> {
// then these functions do not need to be implemented.
// If it is a subcommand, you need to implement these functions
// e.g: CmdConfig is a subcommand, and the subcommand is set and get
virtual bool HasSubCommand() const; // The command is there a sub command
virtual std::vector<std::string> SubCommand() const; // Get command is there a sub command
virtual int8_t SubCmdIndex(const std::string& cmdName); // if the command no subCommand,return -1;
virtual bool HasSubCommand() const; // The command is there a sub command
virtual BaseCmd* GetSubCmd(const std::string& cmdName);

uint32_t AclCategory() const;
void AddAclCategory(uint32_t aclCategory);
Expand All @@ -186,7 +185,6 @@ class BaseCmd : public std::enable_shared_from_this<BaseCmd> {
std::string name_;
int16_t arity_ = 0;
uint32_t flag_ = 0;
std::vector<std::string> subCmdName_; // sub command name, may be empty

// CmdRes res_;
// std::string dbName_;
Expand All @@ -207,5 +205,24 @@ class BaseCmd : public std::enable_shared_from_this<BaseCmd> {
// BaseCmd& operator=(const BaseCmd&);
};

class BaseCmdGroup : public BaseCmd {
public:
BaseCmdGroup(const std::string& name, uint32_t flag);
BaseCmdGroup(const std::string& name, int16_t arity, uint32_t flag);

~BaseCmdGroup() override = default;

void AddSubCmd(std::unique_ptr<BaseCmd> cmd);
BaseCmd* GetSubCmd(const std::string& cmdName) override;

// group cmd this function will not be called
void DoCmd(CmdContext& ctx) override{};

// group cmd this function will not be called
bool DoInitial(CmdContext& ctx) override;

private:
std::map<std::string, std::unique_ptr<BaseCmd>> subCmds_;
};

} // namespace pikiwidb
#endif // PIKIWIDB_SRC_BASE_CMD_H
32 changes: 19 additions & 13 deletions src/client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ int PClient::handlePacket(pikiwidb::TcpConnection* obj, const char* start, int b
const PCommandInfo* info = PCommandTable::GetCommandInfo(cmd);

if (!info) { // 如果这个命令不存在,那么就走新的命令处理流程
handlePacketNew(obj, params, cmd);
handlePacketNew(params, cmd);
return static_cast<int>(ptr - start);
}

Expand Down Expand Up @@ -241,26 +241,32 @@ int PClient::handlePacket(pikiwidb::TcpConnection* obj, const char* start, int b

// 为了兼容老的命令处理流程,新的命令处理流程在这里
// 后面可以把client这个类重构,完整的支持新的命令处理流程
int PClient::handlePacketNew(pikiwidb::TcpConnection* obj, const std::vector<std::string>& params,
const std::string& cmd) {
auto cmdPtr = g_pikiwidb->GetCmdTableManager().GetCommand(cmd);
int PClient::handlePacketNew(const std::vector<std::string>& params, const std::string& cmd) {
CmdContext ctx;
ctx.client_ = this;
// 因为 params 是一个引用,不能直接传给 ctx.argv_,所以需要拷贝一份,后面可以优化
std::vector<std::string> argv = params;
ctx.argv_ = argv;

auto [cmdPtr, ret] = g_pikiwidb->GetCmdTableManager().GetCommand(cmd, ctx);

if (!cmdPtr) {
ReplyError(PError_unknowCmd, &reply_);
if (ret == CmdRes::kInvalidParameter) {
ctx.SetRes(CmdRes::kInvalidParameter);
} else {
ctx.SetRes(CmdRes::kSyntaxErr, "unknown command '" + cmd + "'");
}
reply_.PushData(ctx.message().data(), ctx.message().size());
return 0;
}

if (!cmdPtr->CheckArg(params.size())) {
ReplyError(PError_param, &reply_);
if (cmdPtr->CheckArg(params.size())) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (cmdPtr->CheckArg(params.size())) {
if (!cmdPtr->CheckArg(params.size())) {

这里的判断条件应该是反了

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

对,这里是判断错了

ctx.SetRes(CmdRes::kSyntaxErr, "wrong number of arguments for '" + cmd + "' command");
reply_.PushData(ctx.message().data(), ctx.message().size());
return 0;
}

CmdContext ctx;
ctx.client_ = this;
// 因为 params 是一个引用,不能直接传给 ctx.argv_,所以需要拷贝一份,后面可以优化
std::vector<std::string> argv = params;
ctx.argv_ = argv;

//execute a specific command
cmdPtr->Execute(ctx);

reply_.PushData(ctx.message().data(), ctx.message().size());
Expand Down
2 changes: 1 addition & 1 deletion src/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ class PClient : public std::enable_shared_from_this<PClient> {
private:
std::shared_ptr<TcpConnection> getTcpConnection() const { return tcp_connection_.lock(); }
int handlePacket(pikiwidb::TcpConnection*, const char*, int);
int handlePacketNew(pikiwidb::TcpConnection* obj, const std::vector<std::string>& params, const std::string& cmd);
int handlePacketNew(const std::vector<std::string>& params, const std::string& cmd);
int processInlineCmd(const char*, size_t, std::vector<PString>&);
void reset();
bool isPeerMaster() const;
Expand Down
42 changes: 9 additions & 33 deletions src/cmd_admin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,48 +9,24 @@

namespace pikiwidb {

CmdConfig::CmdConfig(const std::string& name, int arity) : BaseCmd(name, arity, CmdFlagsAdmin, AclCategoryAdmin) {
CmdConfig::CmdConfig(const std::string& name, int arity) : BaseCmdGroup(name, CmdFlagsAdmin, AclCategoryAdmin) {
subCmd_ = {"set", "get"};
}

bool CmdConfig::HasSubCommand() const { return true; }

std::vector<std::string> CmdConfig::SubCommand() const { return subCmd_; }
CmdConfigGet::CmdConfigGet(const std::string& name, int16_t arity)
: BaseCmd(name, arity, CmdFlagsAdmin | CmdFlagsWrite, AclCategoryAdmin) {}

int8_t CmdConfig::SubCmdIndex(const std::string& cmdName) {
for (size_t i = 0; i < subCmd_.size(); i++) {
if (subCmd_[i] == cmdName) {
return i;
}
}
return -1;
}
bool CmdConfigGet::DoInitial(CmdContext& ctx) { return true; }

bool CmdConfig::DoInitial(pikiwidb::CmdContext& ctx) {
ctx.subCmd_ = ctx.argv_[1];
std::transform(ctx.argv_[1].begin(), ctx.argv_[1].end(), ctx.subCmd_.begin(), ::tolower);
if (ctx.subCmd_ == subCmd_[0] || ctx.subCmd_ == subCmd_[1]) {
if (ctx.argv_.size() < 3) {
ctx.SetRes(CmdRes::kInvalidParameter, "config " + ctx.subCmd_);
return false;
}
}

return true;
}
void CmdConfigGet::DoCmd(CmdContext& ctx) { ctx.AppendString("config cmd in development"); }

void CmdConfig::DoCmd(pikiwidb::CmdContext& ctx) {
if (ctx.subCmd_ == subCmd_[0]) {
Set(ctx);
} else if (ctx.subCmd_ == subCmd_[1]) {
Get(ctx);
} else {
ctx.SetRes(CmdRes::kSyntaxErr, "config error");
}
}
CmdConfigSet::CmdConfigSet(const std::string& name, int16_t arity)
: BaseCmd(name, arity, CmdFlagsAdmin, AclCategoryAdmin) {}

void CmdConfig::Get(CmdContext& ctx) { ctx.AppendString("config cmd in development"); }
bool CmdConfigSet::DoInitial(CmdContext& ctx) { return true; }

void CmdConfig::Set(CmdContext& ctx) { ctx.AppendString("config cmd in development"); }
void CmdConfigSet::DoCmd(CmdContext& ctx) { ctx.AppendString("config cmd in development"); }

} // namespace pikiwidb
31 changes: 24 additions & 7 deletions src/cmd_admin.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,41 @@

namespace pikiwidb {

class CmdConfig : public BaseCmd {
class CmdConfig : public BaseCmdGroup {
public:
CmdConfig(const std::string& name, int arity);

bool HasSubCommand() const override;
std::vector<std::string> SubCommand() const override;
int8_t SubCmdIndex(const std::string& cmdName) override;

protected:
bool DoInitial(CmdContext& ctx) override;
bool DoInitial(CmdContext& ctx) override { return true; };

private:
std::vector<std::string> subCmd_;

void DoCmd(CmdContext& ctx) override;
void DoCmd(CmdContext& ctx) override{};
};

class CmdConfigGet : public BaseCmd {
public:
CmdConfigGet(const std::string& name, int16_t arity);

protected:
bool DoInitial(CmdContext& ctx) override;

private:
void DoCmd(pikiwidb::CmdContext& ctx) override;
};

class CmdConfigSet : public BaseCmd {
public:
CmdConfigSet(const std::string& name, int16_t arity);

void Get(CmdContext& ctx);
void Set(CmdContext& ctx);
protected:
bool DoInitial(CmdContext& ctx) override;

private:
void DoCmd(pikiwidb::CmdContext& ctx) override;
};

} // namespace pikiwidb
4 changes: 2 additions & 2 deletions src/cmd_kv.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

namespace pikiwidb {

GetCmd::GetCmd(const std::string& name, int arity)
GetCmd::GetCmd(const std::string& name, int16_t arity)
: BaseCmd(name, arity, CmdFlagsReadonly, AclCategoryRead | AclCategoryString) {}

bool GetCmd::DoInitial(CmdContext& ctx) {
Expand All @@ -34,7 +34,7 @@ void GetCmd::DoCmd(CmdContext& ctx) {
ctx.AppendString(reply);
}

SetCmd::SetCmd(const std::string& name, int arity)
SetCmd::SetCmd(const std::string& name, int16_t arity)
: BaseCmd(name, arity, CmdFlagsWrite, AclCategoryWrite | AclCategoryString) {}

bool SetCmd::DoInitial(CmdContext& ctx) {
Expand Down
4 changes: 2 additions & 2 deletions src/cmd_kv.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace pikiwidb {

class GetCmd : public BaseCmd {
public:
GetCmd(const std::string &name, int arity);
GetCmd(const std::string &name, int16_t arity);

protected:
bool DoInitial(CmdContext &ctx) override;
Expand All @@ -25,7 +25,7 @@ class GetCmd : public BaseCmd {

class SetCmd : public BaseCmd {
public:
SetCmd(const std::string &name, int arity);
SetCmd(const std::string &name, int16_t arity);

protected:
bool DoInitial(CmdContext &ctx) override;
Expand Down
18 changes: 14 additions & 4 deletions src/cmd_table_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ void CmdTableManager::InitCmdTable() {
std::unique_lock wl(mutex_);

// admin
std::unique_ptr<BaseCmd> configPtr = std::make_unique<CmdConfig>(kCmdNameConfig, -2);
auto configPtr = std::make_unique<CmdConfig>(kCmdNameConfig, -2);
configPtr->AddSubCmd(std::make_unique<CmdConfigGet>("get", -3));
configPtr->AddSubCmd(std::make_unique<CmdConfigSet>("set", -4));

cmds_->insert(std::make_pair(kCmdNameConfig, std::move(configPtr)));

// kv
Expand All @@ -31,15 +34,22 @@ void CmdTableManager::InitCmdTable() {
cmds_->insert(std::make_pair(kCmdNameSet, std::move(setPtr)));
}

BaseCmd* CmdTableManager::GetCommand(const std::string& cmdName) {
std::pair<BaseCmd*, CmdRes::CmdRet> CmdTableManager::GetCommand(const std::string& cmdName, CmdContext& ctx) {
std::shared_lock rl(mutex_);

auto cmd = cmds_->find(cmdName);

if (cmd == cmds_->end()) {
return nullptr;
return std::pair(nullptr, CmdRes::kSyntaxErr);
}

if (cmd->second->HasSubCommand()) {
if (ctx.argv_.size() < 2) {
return std::pair(nullptr, CmdRes::kInvalidParameter);
}
return std::pair(cmd->second->GetSubCmd(ctx.argv_[1]), CmdRes::kSyntaxErr);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里没太明白逻辑,当没有subcommand时,状态应该返回kSyntaxErr吗?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

在调用GetCommand的地方会判断,如果有子命令,但是返回的是null, 状态是kSyntaxErr, 如果返回的指针不是null, 这个状态会被忽略

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

好嘞,谢谢~

}
return cmd->second.get();
return std::pair(cmd->second.get(), CmdRes::kSyntaxErr);
}

bool CmdTableManager::CmdExist(const std::string& cmd) const {
Expand Down
2 changes: 1 addition & 1 deletion src/cmd_table_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class CmdTableManager {

public:
void InitCmdTable();
BaseCmd* GetCommand(const std::string& cmdName);
std::pair<BaseCmd*,CmdRes::CmdRet> GetCommand(const std::string& cmdName, CmdContext& ctx);
// uint32_t DistributeKey(const std::string& key, uint32_t slot_num);
bool CmdExist(const std::string& cmd) const;
uint32_t GetCmdId();
Expand Down