Skip to content

Commit

Permalink
feat:Subcommands support separate command id (#24)
Browse files Browse the repository at this point in the history
* feat:Subcommands support separate command ids

* fix spelling error,optimize GetCommand function return value

* fix check params number error
  • Loading branch information
lqxhub authored Nov 2, 2023
1 parent ad3dca9 commit e05878d
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 71 deletions.
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
30 changes: 18 additions & 12 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_);
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 @@ -103,7 +103,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);
}
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

0 comments on commit e05878d

Please sign in to comment.