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

Introduce command register mechanism to allow splitting command definition to multiple TUs #1140

Merged
merged 3 commits into from
Nov 26, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
120 changes: 36 additions & 84 deletions src/commands/redis_cmd.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6262,31 +6262,7 @@ class CommandXTrim : public Commander {
StreamTrimStrategy strategy_ = StreamTrimStrategy::None;
};

template <typename T>
auto MakeCmdAttr(const std::string &name, int arity, const std::string &description, int first_key, int last_key,
int key_step) {
CommandAttributes attr{
name, arity,
description, 0,
first_key, last_key,
key_step, []() -> std::unique_ptr<Commander> { return std::unique_ptr<Commander>(new T()); }};

for (const auto &flag : Util::Split(attr.description, " ")) {
if (flag == "write") attr.flags |= kCmdWrite;
if (flag == "read-only") attr.flags |= kCmdReadOnly;
if (flag == "replication") attr.flags |= kCmdReplication;
if (flag == "pub-sub") attr.flags |= kCmdPubSub;
if (flag == "ok-loading") attr.flags |= kCmdLoading;
if (flag == "exclusive") attr.flags |= kCmdExclusive;
if (flag == "multi") attr.flags |= kCmdMulti;
if (flag == "no-multi") attr.flags |= kCmdNoMulti;
if (flag == "no-script") attr.flags |= kCmdNoScript;
}

return attr;
}

const CommandAttributes redisCommandTable[]{
REDIS_REGISTER_COMMANDS(
MakeCmdAttr<CommandAuth>("auth", 2, "read-only ok-loading", 0, 0, 0),
MakeCmdAttr<CommandPing>("ping", -1, "read-only", 0, 0, 0),
MakeCmdAttr<CommandSelect>("select", 2, "read-only", 0, 0, 0),
Expand All @@ -6312,8 +6288,7 @@ const CommandAttributes redisCommandTable[]{
MakeCmdAttr<CommandDisk>("disk", 3, "read-only", 0, 0, 0),
MakeCmdAttr<CommandHello>("hello", -1, "read-only ok-loading", 0, 0, 0),

MakeCmdAttr<CommandTTL>("ttl", 2, "read-only", 1, 1, 1),
MakeCmdAttr<CommandPTTL>("pttl", 2, "read-only", 1, 1, 1),
MakeCmdAttr<CommandTTL>("ttl", 2, "read-only", 1, 1, 1), MakeCmdAttr<CommandPTTL>("pttl", 2, "read-only", 1, 1, 1),
git-hulk marked this conversation as resolved.
Show resolved Hide resolved
MakeCmdAttr<CommandType>("type", 2, "read-only", 1, 1, 1),
MakeCmdAttr<CommandObject>("object", 3, "read-only", 2, 2, 1),
MakeCmdAttr<CommandExists>("exists", -2, "read-only", 1, -1, 1),
Expand All @@ -6322,30 +6297,23 @@ const CommandAttributes redisCommandTable[]{
MakeCmdAttr<CommandPExpire>("pexpire", 3, "write", 1, 1, 1),
MakeCmdAttr<CommandExpireAt>("expireat", 3, "write", 1, 1, 1),
MakeCmdAttr<CommandPExpireAt>("pexpireat", 3, "write", 1, 1, 1),
MakeCmdAttr<CommandDel>("del", -2, "write", 1, -1, 1),
MakeCmdAttr<CommandDel>("unlink", -2, "write", 1, -1, 1),
MakeCmdAttr<CommandDel>("del", -2, "write", 1, -1, 1), MakeCmdAttr<CommandDel>("unlink", -2, "write", 1, -1, 1),

MakeCmdAttr<CommandGet>("get", 2, "read-only", 1, 1, 1),
MakeCmdAttr<CommandGetEx>("getex", -2, "write", 1, 1, 1),
MakeCmdAttr<CommandGet>("get", 2, "read-only", 1, 1, 1), MakeCmdAttr<CommandGetEx>("getex", -2, "write", 1, 1, 1),
MakeCmdAttr<CommandStrlen>("strlen", 2, "read-only", 1, 1, 1),
MakeCmdAttr<CommandGetSet>("getset", 3, "write", 1, 1, 1),
MakeCmdAttr<CommandGetRange>("getrange", 4, "read-only", 1, 1, 1),
MakeCmdAttr<CommandGetDel>("getdel", 2, "write", 1, 1, 1),
MakeCmdAttr<CommandSetRange>("setrange", 4, "write", 1, 1, 1),
MakeCmdAttr<CommandMGet>("mget", -2, "read-only", 1, -1, 1),
MakeCmdAttr<CommandAppend>("append", 3, "write", 1, 1, 1),
MakeCmdAttr<CommandSet>("set", -3, "write", 1, 1, 1),
MakeCmdAttr<CommandSetEX>("setex", 4, "write", 1, 1, 1),
MakeCmdAttr<CommandPSetEX>("psetex", 4, "write", 1, 1, 1),
MakeCmdAttr<CommandAppend>("append", 3, "write", 1, 1, 1), MakeCmdAttr<CommandSet>("set", -3, "write", 1, 1, 1),
MakeCmdAttr<CommandSetEX>("setex", 4, "write", 1, 1, 1), MakeCmdAttr<CommandPSetEX>("psetex", 4, "write", 1, 1, 1),
MakeCmdAttr<CommandSetNX>("setnx", 3, "write", 1, 1, 1),
MakeCmdAttr<CommandMSetNX>("msetnx", -3, "write exclusive", 1, -1, 2),
MakeCmdAttr<CommandMSet>("mset", -3, "write", 1, -1, 2),
MakeCmdAttr<CommandIncrBy>("incrby", 3, "write", 1, 1, 1),
MakeCmdAttr<CommandMSet>("mset", -3, "write", 1, -1, 2), MakeCmdAttr<CommandIncrBy>("incrby", 3, "write", 1, 1, 1),
MakeCmdAttr<CommandIncrByFloat>("incrbyfloat", 3, "write", 1, 1, 1),
MakeCmdAttr<CommandIncr>("incr", 2, "write", 1, 1, 1),
MakeCmdAttr<CommandDecrBy>("decrby", 3, "write", 1, 1, 1),
MakeCmdAttr<CommandDecr>("decr", 2, "write", 1, 1, 1),
MakeCmdAttr<CommandCAS>("cas", -4, "write", 1, 1, 1),
MakeCmdAttr<CommandIncr>("incr", 2, "write", 1, 1, 1), MakeCmdAttr<CommandDecrBy>("decrby", 3, "write", 1, 1, 1),
MakeCmdAttr<CommandDecr>("decr", 2, "write", 1, 1, 1), MakeCmdAttr<CommandCAS>("cas", -4, "write", 1, 1, 1),
MakeCmdAttr<CommandCAD>("cad", 3, "write", 1, 1, 1),

MakeCmdAttr<CommandGetBit>("getbit", 3, "read-only", 1, 1, 1),
Expand All @@ -6357,8 +6325,7 @@ const CommandAttributes redisCommandTable[]{
MakeCmdAttr<CommandHGet>("hget", 3, "read-only", 1, 1, 1),
MakeCmdAttr<CommandHIncrBy>("hincrby", 4, "write", 1, 1, 1),
MakeCmdAttr<CommandHIncrByFloat>("hincrbyfloat", 4, "write", 1, 1, 1),
MakeCmdAttr<CommandHMSet>("hset", -4, "write", 1, 1, 1),
MakeCmdAttr<CommandHSetNX>("hsetnx", 4, "write", 1, 1, 1),
MakeCmdAttr<CommandHMSet>("hset", -4, "write", 1, 1, 1), MakeCmdAttr<CommandHSetNX>("hsetnx", 4, "write", 1, 1, 1),
MakeCmdAttr<CommandHDel>("hdel", -3, "write", 1, 1, 1),
MakeCmdAttr<CommandHStrlen>("hstrlen", 3, "read-only", 1, 1, 1),
MakeCmdAttr<CommandHExists>("hexists", 3, "read-only", 1, 1, 1),
Expand All @@ -6371,26 +6338,21 @@ const CommandAttributes redisCommandTable[]{
MakeCmdAttr<CommandHScan>("hscan", -3, "read-only", 1, 1, 1),
MakeCmdAttr<CommandHRange>("hrange", -4, "read-only", 1, 1, 1),

MakeCmdAttr<CommandLPush>("lpush", -3, "write", 1, 1, 1),
MakeCmdAttr<CommandRPush>("rpush", -3, "write", 1, 1, 1),
MakeCmdAttr<CommandLPush>("lpush", -3, "write", 1, 1, 1), MakeCmdAttr<CommandRPush>("rpush", -3, "write", 1, 1, 1),
MakeCmdAttr<CommandLPushX>("lpushx", -3, "write", 1, 1, 1),
MakeCmdAttr<CommandRPushX>("rpushx", -3, "write", 1, 1, 1),
MakeCmdAttr<CommandLPop>("lpop", -2, "write", 1, 1, 1),
MakeCmdAttr<CommandRPushX>("rpushx", -3, "write", 1, 1, 1), MakeCmdAttr<CommandLPop>("lpop", -2, "write", 1, 1, 1),
MakeCmdAttr<CommandRPop>("rpop", -2, "write", 1, 1, 1),
MakeCmdAttr<CommandBLPop>("blpop", -3, "write no-script", 1, -2, 1),
MakeCmdAttr<CommandBRPop>("brpop", -3, "write no-script", 1, -2, 1),
MakeCmdAttr<CommandLRem>("lrem", 4, "write", 1, 1, 1),
MakeCmdAttr<CommandLInsert>("linsert", 5, "write", 1, 1, 1),
MakeCmdAttr<CommandLRem>("lrem", 4, "write", 1, 1, 1), MakeCmdAttr<CommandLInsert>("linsert", 5, "write", 1, 1, 1),
MakeCmdAttr<CommandLRange>("lrange", 4, "read-only", 1, 1, 1),
MakeCmdAttr<CommandLIndex>("lindex", 3, "read-only", 1, 1, 1),
MakeCmdAttr<CommandLTrim>("ltrim", 4, "write", 1, 1, 1),
MakeCmdAttr<CommandLLen>("llen", 2, "read-only", 1, 1, 1),
MakeCmdAttr<CommandLTrim>("ltrim", 4, "write", 1, 1, 1), MakeCmdAttr<CommandLLen>("llen", 2, "read-only", 1, 1, 1),
MakeCmdAttr<CommandLSet>("lset", 4, "write", 1, 1, 1),
MakeCmdAttr<CommandRPopLPUSH>("rpoplpush", 3, "write", 1, 2, 1),
MakeCmdAttr<CommandLMove>("lmove", 5, "write", 1, 2, 1),

MakeCmdAttr<CommandSAdd>("sadd", -3, "write", 1, 1, 1),
MakeCmdAttr<CommandSRem>("srem", -3, "write", 1, 1, 1),
MakeCmdAttr<CommandSAdd>("sadd", -3, "write", 1, 1, 1), MakeCmdAttr<CommandSRem>("srem", -3, "write", 1, 1, 1),
MakeCmdAttr<CommandSCard>("scard", 2, "read-only", 1, 1, 1),
MakeCmdAttr<CommandSMembers>("smembers", 2, "read-only", 1, 1, 1),
MakeCmdAttr<CommandSIsMember>("sismember", 3, "read-only", 1, 1, 1),
Expand All @@ -6406,8 +6368,7 @@ const CommandAttributes redisCommandTable[]{
MakeCmdAttr<CommandSInterStore>("sinterstore", -3, "write", 1, -1, 1),
MakeCmdAttr<CommandSScan>("sscan", -3, "read-only", 1, 1, 1),

MakeCmdAttr<CommandZAdd>("zadd", -4, "write", 1, 1, 1),
MakeCmdAttr<CommandZCard>("zcard", 2, "read-only", 1, 1, 1),
MakeCmdAttr<CommandZAdd>("zadd", -4, "write", 1, 1, 1), MakeCmdAttr<CommandZCard>("zcard", 2, "read-only", 1, 1, 1),
MakeCmdAttr<CommandZCount>("zcount", 4, "read-only", 1, 1, 1),
MakeCmdAttr<CommandZIncrBy>("zincrby", 4, "write", 1, 1, 1),
MakeCmdAttr<CommandZInterStore>("zinterstore", -4, "write", 1, 1, 1),
Expand All @@ -6419,8 +6380,7 @@ const CommandAttributes redisCommandTable[]{
MakeCmdAttr<CommandZRangeByLex>("zrangebylex", -4, "read-only", 1, 1, 1),
MakeCmdAttr<CommandZRevRangeByLex>("zrevrangebylex", -4, "read-only", 1, 1, 1),
MakeCmdAttr<CommandZRangeByScore>("zrangebyscore", -4, "read-only", 1, 1, 1),
MakeCmdAttr<CommandZRank>("zrank", 3, "read-only", 1, 1, 1),
MakeCmdAttr<CommandZRem>("zrem", -3, "write", 1, 1, 1),
MakeCmdAttr<CommandZRank>("zrank", 3, "read-only", 1, 1, 1), MakeCmdAttr<CommandZRem>("zrem", -3, "write", 1, 1, 1),
MakeCmdAttr<CommandZRemRangeByRank>("zremrangebyrank", 4, "write", 1, 1, 1),
MakeCmdAttr<CommandZRemRangeByScore>("zremrangebyscore", -4, "write", 1, 1, 1),
MakeCmdAttr<CommandZRemRangeByLex>("zremrangebylex", 4, "write", 1, 1, 1),
Expand Down Expand Up @@ -6481,37 +6441,29 @@ const CommandAttributes redisCommandTable[]{
MakeCmdAttr<CommandFetchFile>("_fetch_file", 2, "read-only replication no-multi no-script", 0, 0, 0),
MakeCmdAttr<CommandDBName>("_db_name", 1, "read-only replication no-multi", 0, 0, 0),

MakeCmdAttr<CommandXAdd>("xadd", -5, "write", 1, 1, 1),
MakeCmdAttr<CommandXDel>("xdel", -3, "write", 1, 1, 1),
MakeCmdAttr<CommandXAdd>("xadd", -5, "write", 1, 1, 1), MakeCmdAttr<CommandXDel>("xdel", -3, "write", 1, 1, 1),
MakeCmdAttr<CommandXLen>("xlen", 2, "read-only", 1, 1, 1),
MakeCmdAttr<CommandXInfo>("xinfo", -2, "read-only", 0, 0, 0),
MakeCmdAttr<CommandXRange>("xrange", -4, "read-only", 1, 1, 1),
MakeCmdAttr<CommandXRevRange>("xrevrange", -2, "read-only", 0, 0, 0),
MakeCmdAttr<CommandXRead>("xread", -4, "read-only", 0, 0, 0),
MakeCmdAttr<CommandXTrim>("xtrim", -4, "write", 1, 1, 1),
};
MakeCmdAttr<CommandXTrim>("xtrim", -4, "write", 1, 1, 1));

// Original Command table before rename-command directive
const CommandMap original_commands = [] {
CommandMap cmd;

for (const auto &attr : redisCommandTable) {
cmd[attr.name] = &attr;
RegisterToCommandTable::RegisterToCommandTable(std::initializer_list<CommandAttributes> list) {
for (const auto &attr : list) {
command_details::redis_command_table.emplace_back(attr);
command_details::original_commands[attr.name] = &command_details::redis_command_table.back();
command_details::commands[attr.name] = &command_details::redis_command_table.back();
}
}

return cmd;
}();

// Command table after rename-command directive
CommandMap commands = original_commands;

int GetCommandNum() { return std::size(redisCommandTable); }
int GetCommandNum() { return (int)command_details::redis_command_table.size(); }

const CommandMap *GetOriginalCommands() { return &original_commands; }
const CommandMap *GetOriginalCommands() { return &command_details::original_commands; }

CommandMap *GetCommands() { return &commands; }
CommandMap *GetCommands() { return &command_details::commands; }

void ResetCommands() { commands = original_commands; }
void ResetCommands() { command_details::commands = command_details::original_commands; }

std::string GetCommandInfo(const CommandAttributes *command_attributes) {
std::string command, command_flags;
Expand All @@ -6528,8 +6480,8 @@ std::string GetCommandInfo(const CommandAttributes *command_attributes) {
}

void GetAllCommandsInfo(std::string *info) {
info->append(Redis::MultiLen(original_commands.size()));
for (const auto &iter : original_commands) {
info->append(Redis::MultiLen(command_details::original_commands.size()));
for (const auto &iter : command_details::original_commands) {
auto command_attribute = iter.second;
auto command_info = GetCommandInfo(command_attribute);
info->append(command_info);
Expand All @@ -6539,8 +6491,8 @@ void GetAllCommandsInfo(std::string *info) {
void GetCommandsInfo(std::string *info, const std::vector<std::string> &cmd_names) {
info->append(Redis::MultiLen(cmd_names.size()));
for (const auto &cmd_name : cmd_names) {
auto cmd_iter = original_commands.find(Util::ToLower(cmd_name));
if (cmd_iter == original_commands.end()) {
auto cmd_iter = command_details::original_commands.find(Util::ToLower(cmd_name));
if (cmd_iter == command_details::original_commands.end()) {
info->append(Redis::NilString());
} else {
auto command_attribute = cmd_iter->second;
Expand All @@ -6551,8 +6503,8 @@ void GetCommandsInfo(std::string *info, const std::vector<std::string> &cmd_name
}

Status GetKeysFromCommand(const std::string &cmd_name, int argc, std::vector<int> *keys_indexes) {
auto cmd_iter = original_commands.find(Util::ToLower(cmd_name));
if (cmd_iter == original_commands.end()) {
auto cmd_iter = command_details::original_commands.find(Util::ToLower(cmd_name));
if (cmd_iter == command_details::original_commands.end()) {
return {Status::RedisUnknownCmd, "Invalid command specified"};
}

Expand All @@ -6576,7 +6528,7 @@ Status GetKeysFromCommand(const std::string &cmd_name, int argc, std::vector<int
}

bool IsCommandExists(const std::string &name) {
return original_commands.find(Util::ToLower(name)) != original_commands.end();
return command_details::original_commands.find(Util::ToLower(name)) != command_details::original_commands.end();
}

} // namespace Redis
49 changes: 49 additions & 0 deletions src/commands/redis_cmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
#include <rocksdb/types.h>
#include <rocksdb/utilities/backup_engine.h>

#include <deque>
#include <initializer_list>
#include <list>
#include <map>
#include <memory>
Expand All @@ -36,6 +38,7 @@

#include "server/redis_reply.h"
#include "status.h"
#include "util.h"

class Server;

Expand Down Expand Up @@ -102,6 +105,52 @@ struct CommandAttributes {

using CommandMap = std::map<std::string, const CommandAttributes *>;

template <typename T>
auto MakeCmdAttr(const std::string &name, int arity, const std::string &description, int first_key, int last_key,
int key_step) {
CommandAttributes attr{
name, arity,
description, 0,
first_key, last_key,
key_step, []() -> std::unique_ptr<Commander> { return std::unique_ptr<Commander>(new T()); }};

for (const auto &flag : Util::Split(attr.description, " ")) {
if (flag == "write") attr.flags |= kCmdWrite;
if (flag == "read-only") attr.flags |= kCmdReadOnly;
if (flag == "replication") attr.flags |= kCmdReplication;
if (flag == "pub-sub") attr.flags |= kCmdPubSub;
if (flag == "ok-loading") attr.flags |= kCmdLoading;
if (flag == "exclusive") attr.flags |= kCmdExclusive;
if (flag == "multi") attr.flags |= kCmdMulti;
if (flag == "no-multi") attr.flags |= kCmdNoMulti;
if (flag == "no-script") attr.flags |= kCmdNoScript;
}

return attr;
}

struct RegisterToCommandTable {
RegisterToCommandTable(std::initializer_list<CommandAttributes> list);
};

// these variables cannot be put into source files (to ensure init order for multiple TUs)
namespace command_details {
inline std::deque<CommandAttributes> redis_command_table;

// Original Command table before rename-command directive
inline CommandMap original_commands;

// Command table after rename-command directive
inline CommandMap commands;
} // namespace command_details

#define KVROCKS_CONCAT(a, b) a##b // NOLINT
#define KVROCKS_CONCAT2(a, b) KVROCKS_CONCAT(a, b) // NOLINT

// NOLINTNEXTLINE
#define REDIS_REGISTER_COMMANDS(...) \
static RegisterToCommandTable KVROCKS_CONCAT2(register_to_command_table_, __LINE__){__VA_ARGS__};

int GetCommandNum();
CommandMap *GetCommands();
void ResetCommands();
Expand Down