diff --git a/src/Command.cpp b/src/Command.cpp index 0b5df05..5821613 100644 --- a/src/Command.cpp +++ b/src/Command.cpp @@ -10,7 +10,7 @@ #include "String.h" #include "Command.h" -const Command Command::CmdPool[Sentinel] = { +Command Command::CmdPool[AvailableCommands] = { {None, "", 0, MaxArgs, Read}, {Ping, "ping", 1, 2, Read}, {PingServ, "ping", 1, 2, Inner}, @@ -171,11 +171,14 @@ const Command Command::CmdPool[Sentinel] = { {SubMsg, "\000SubMsg", 0, 0, Admin} }; +int Command::Sentinel = Command::MaxCommands; Command::CommandMap Command::CmdMap; + void Command::init() { int type = 0; - for (auto& i : CmdPool) { + for (auto j = 0; j < MaxCommands; j++) { + const auto& i = CmdPool[j]; if (i.type != type) { Throw(InitFail, "command %s unmatch the index in commands table", i.name); } @@ -187,3 +190,12 @@ void Command::init() } } +void Command::addCustomCommand(const Command *p) { + if (nullptr != find(p->name)) { + Throw(InitFail, "custom command %s is duplicated", p->name); + } + CmdPool[Sentinel] = *p; + CmdMap[p->name] = &CmdPool[Sentinel]; + Sentinel++; +} + diff --git a/src/Command.h b/src/Command.h index eb15709..5555621 100644 --- a/src/Command.h +++ b/src/Command.h @@ -8,6 +8,7 @@ #define _PREDIXY_COMMAND_H_ #include +#include #include "Exception.h" #include "HashFunc.h" @@ -189,7 +190,8 @@ public: Unsubscribe, SubMsg, - Sentinel + MaxCommands, + AvailableCommands = MaxCommands + 128, }; enum Mode { @@ -242,6 +244,7 @@ public: if (cursor < Sentinel) { return &CmdPool[cursor++]; } + return nullptr; } static const Command* find(const String& cmd) @@ -249,9 +252,11 @@ public: auto it = CmdMap.find(cmd); return it == CmdMap.end() ? nullptr : it->second; } + static void addCustomCommand(const Command *pc); + static int Sentinel; private: static const int MaxArgs = 100000000; - static const Command CmdPool[Sentinel]; + static Command CmdPool[]; class H { public: diff --git a/src/Conf.cpp b/src/Conf.cpp index f5325fa..ff38ee1 100644 --- a/src/Conf.cpp +++ b/src/Conf.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include "LogFileSink.h" #include "ServerPool.h" @@ -32,6 +33,15 @@ bool ServerConf::parse(ServerConf& s, const char* str) return !s.addr.empty(); } +void CustomCommandConf::init(CustomCommandConf&c, const char* name, const int type) { + c.name = name; + c.cmd.type = (Command::Type)type; + c.cmd.name = c.name.c_str(); + c.cmd.minArgs = 1; + c.cmd.maxArgs = 1; + c.cmd.mode = Command::Write; +} + Conf::Conf(): mBind("0.0.0.0:7617"), mWorkerThreads(1), @@ -157,6 +167,8 @@ void Conf::setGlobal(const ConfParser::Node* node) sentinelServerPool = p; } else if (strcasecmp(p->key.c_str(), "DataCenter") == 0) { dataCenter = p; + } else if (strcasecmp(p->key.c_str(), "CustomCommand") == 0) { + setCustomCommand(p); } else { Throw(UnknownKey, "%s:%d unknown key %s", p->file, p->line, p->key.c_str()); } @@ -358,6 +370,73 @@ void Conf::setDataCenter(const ConfParser::Node* node) } } +void Conf::setCustomCommand(const ConfParser::Node* node) +{ + if (!node->sub) { + Throw(InvalidValue, "%s:%d CustomCommand require scope value", node->file, node->line); + } + for (auto p = node->sub; p; p = p->next) { + if (Command::Sentinel >= Command::AvailableCommands) { + Throw(InvalidValue, "%s:%d Too many custom commands", node->file, node->line); + } + mCustomCommands.push_back(CustomCommandConf{}); + auto& cc = mCustomCommands.back(); + CustomCommandConf::init(cc, p->key.c_str(), Command::Sentinel); + auto s = p->sub; + if (!s) { + Throw(InvalidValue, "%s:%d CustomCommand.Command require scope value", + node->file, node->line); + } + for (;s ; s = s->next) { + setInt(cc.cmd.minArgs, "minArgs", s, 1); + setInt(cc.cmd.maxArgs, "maxArgs", s, 1, 9999); + setCommandMode(cc.cmd.mode, "mode", s); + } + Command::addCustomCommand(&cc.cmd); + } +} + +bool Conf::setCommandMode(int& mode, const char* name, const ConfParser::Node* n, const int defaultMode) +{ + if (strcasecmp(name, n->key.c_str()) == 0) { + if (n->val.size() == 0) { + mode = defaultMode; + } else { + mode = Command::Unknown; + } + std::string mask; + std::istringstream is(n->val); + while (std::getline(is, mask, ',')) { + if ((strcasecmp(mask.c_str(), "Write") == 0)) { + mode |= Command::Write; + } else if ((strcasecmp(mask.c_str(), "Read") == 0)) { + mode |= Command::Read; + } else if ((strcasecmp(mask.c_str(), "Admin") == 0)) { + mode |= Command::Admin; + } else if ((strcasecmp(mask.c_str(), "Private") == 0)) { + mode |= Command::Private; + } else if ((strcasecmp(mask.c_str(), "NoKey") == 0)) { + mode |= Command::NoKey; + } else if ((strcasecmp(mask.c_str(), "MultiKey") == 0)) { + mode |= Command::MultiKey; + } else if ((strcasecmp(mask.c_str(), "SMultiKey") == 0)) { + mode |= Command::SMultiKey; + } else if ((strcasecmp(mask.c_str(), "MultiKeyVal") == 0)) { + mode |= Command::MultiKeyVal; + } else if ((strcasecmp(mask.c_str(), "KeyAt2") == 0)) { + mode |= Command::KeyAt2; + } else if ((strcasecmp(mask.c_str(), "KeyAt3") == 0)) { + mode |= Command::KeyAt3; + } else { + Throw(InvalidValue, "%s:%d %s %s is not an mode", + n->file, n->line, name, n->val.c_str()); + } + } + return true; + } + return false; +} + void Conf::setDC(DCConf& dc, const ConfParser::Node* node) { if (!node->sub) { diff --git a/src/Conf.h b/src/Conf.h index 04e9a17..1b9e002 100644 --- a/src/Conf.h +++ b/src/Conf.h @@ -19,6 +19,7 @@ #include "Distribution.h" #include "ConfParser.h" #include "Auth.h" +#include "Command.h" struct AuthConf { @@ -89,10 +90,18 @@ struct DCConf struct LatencyMonitorConf { std::string name; - std::bitset cmds; + std::bitset cmds; std::vector timeSpan;//us }; +struct CustomCommandConf +{ + std::string name; + Command cmd; + + static void init(CustomCommandConf &c, const char* name, const int type); +}; + class Conf { public: @@ -201,6 +210,8 @@ private: void setDC(DCConf& dc, const ConfParser::Node* n); void setReadPolicy(ReadPolicyConf& c, const ConfParser::Node* n); void setLatencyMonitor(LatencyMonitorConf& m, const ConfParser::Node* n); + void setCustomCommand(const ConfParser::Node* n); + bool setCommandMode(int& mode, const char* name, const ConfParser::Node* n, const int defaultMode = Command::Write); private: std::string mName; std::string mBind; @@ -220,6 +231,7 @@ private: std::vector mDCConfs; std::string mLocalDC; std::vector mLatencyMonitors; + std::vector mCustomCommands; }; diff --git a/src/LatencyMonitor.h b/src/LatencyMonitor.h index 866a400..55dc3a3 100644 --- a/src/LatencyMonitor.h +++ b/src/LatencyMonitor.h @@ -98,7 +98,7 @@ public: Buffer* output(Buffer* buf) const; private: String mName; - const std::bitset* mCmds; + const std::bitset* mCmds; std::vector mTimeSpan; TimeSpan mLast; };