This is an automated email from the ASF dual-hosted git repository.

twice pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/kvrocks.git


The following commit(s) were added to refs/heads/unstable by this push:
     new 5fccd57c feat(cmd): make key range fields private in CommandAttributes 
(#2621)
5fccd57c is described below

commit 5fccd57c66bc8f0e4138924fe6a0148931e5650f
Author: Twice <[email protected]>
AuthorDate: Thu Oct 24 23:09:05 2024 +0800

    feat(cmd): make key range fields private in CommandAttributes (#2621)
---
 src/cluster/cluster.cc     | 12 +++----
 src/commands/cmd_server.cc | 12 +++----
 src/commands/commander.cc  | 52 ++++++++++++-----------------
 src/commands/commander.h   | 83 +++++++++++++++++++++++++++++-----------------
 src/common/string_util.h   |  3 +-
 src/server/server.cc       | 24 ++------------
 6 files changed, 90 insertions(+), 96 deletions(-)

diff --git a/src/cluster/cluster.cc b/src/cluster/cluster.cc
index 16e72b62..c4dd9b8c 100644
--- a/src/cluster/cluster.cc
+++ b/src/cluster/cluster.cc
@@ -832,16 +832,16 @@ bool Cluster::IsWriteForbiddenSlot(int slot) const {
 
 Status Cluster::CanExecByMySelf(const redis::CommandAttributes *attributes, 
const std::vector<std::string> &cmd_tokens,
                                 redis::Connection *conn, lua::ScriptRunCtx 
*script_run_ctx) {
-  std::vector<int> keys_indexes;
+  std::vector<int> key_indexes;
 
-  // No keys
-  if (auto s = redis::CommandTable::GetKeysFromCommand(attributes, cmd_tokens, 
&keys_indexes); !s.IsOK())
-    return Status::OK();
+  auto s = redis::CommandTable::GetKeysFromCommand(attributes, cmd_tokens);
+  if (!s) return Status::OK();
+  key_indexes = *s;
 
-  if (keys_indexes.empty()) return Status::OK();
+  if (key_indexes.empty()) return Status::OK();
 
   int slot = -1;
-  for (auto i : keys_indexes) {
+  for (auto i : key_indexes) {
     if (i >= static_cast<int>(cmd_tokens.size())) break;
 
     int cur_slot = GetSlotIdFromKey(cmd_tokens[i]);
diff --git a/src/commands/cmd_server.cc b/src/commands/cmd_server.cc
index 260edca1..725b28d0 100644
--- a/src/commands/cmd_server.cc
+++ b/src/commands/cmd_server.cc
@@ -676,18 +676,16 @@ class CommandCommand : public Commander {
           return {Status::RedisUnknownCmd, "Invalid command specified"};
         }
 
-        std::vector<int> keys_indexes;
-        auto s = CommandTable::GetKeysFromCommand(
-            cmd_iter->second, std::vector<std::string>(args_.begin() + 2, 
args_.end()), &keys_indexes);
-        if (!s.IsOK()) return s;
+        auto key_indexes = GET_OR_RET(CommandTable::GetKeysFromCommand(
+            cmd_iter->second, std::vector<std::string>(args_.begin() + 2, 
args_.end())));
 
-        if (keys_indexes.size() == 0) {
+        if (key_indexes.size() == 0) {
           return {Status::RedisExecErr, "Invalid arguments specified for 
command"};
         }
 
         std::vector<std::string> keys;
-        keys.reserve(keys_indexes.size());
-        for (const auto &key_index : keys_indexes) {
+        keys.reserve(key_indexes.size());
+        for (const auto &key_index : key_indexes) {
           keys.emplace_back(args_[key_index + 2]);
         }
         *output = conn->MultiBulkString(keys);
diff --git a/src/commands/commander.cc b/src/commands/commander.cc
index ecab960f..063b1c46 100644
--- a/src/commands/commander.cc
+++ b/src/commands/commander.cc
@@ -50,9 +50,10 @@ std::string CommandTable::GetCommandInfo(const 
CommandAttributes *command_attrib
   command_flags.append(redis::MultiLen(1));
   command_flags.append(redis::BulkString(command_attributes->InitialFlags() & 
kCmdWrite ? "write" : "readonly"));
   command.append(command_flags);
-  command.append(redis::Integer(command_attributes->key_range.first_key));
-  command.append(redis::Integer(command_attributes->key_range.last_key));
-  command.append(redis::Integer(command_attributes->key_range.key_step));
+  auto key_range = command_attributes->InitialKeyRange().ValueOr({0, 0, 0});
+  command.append(redis::Integer(key_range.first_key));
+  command.append(redis::Integer(key_range.last_key));
+  command.append(redis::Integer(key_range.key_step));
   return command;
 }
 
@@ -79,40 +80,31 @@ void CommandTable::GetCommandsInfo(std::string *info, const 
std::vector<std::str
   }
 }
 
-void DumpKeyRange(std::vector<int> &keys_index, int argc, const 
CommandKeyRange &range) {
-  auto last = range.last_key;
-  if (last < 0) last = argc + last;
-
-  for (int i = range.first_key; i <= last; i += range.key_step) {
-    keys_index.emplace_back(i);
-  }
-}
-
-Status CommandTable::GetKeysFromCommand(const CommandAttributes *attributes, 
const std::vector<std::string> &cmd_tokens,
-                                        std::vector<int> *keys_index) {
-  if (attributes->key_range.first_key == 0) {
-    return {Status::NotOK, "The command has no key arguments"};
-  }
-
+StatusOr<std::vector<int>> CommandTable::GetKeysFromCommand(const 
CommandAttributes *attributes,
+                                                            const 
std::vector<std::string> &cmd_tokens) {
   int argc = static_cast<int>(cmd_tokens.size());
 
-  if ((attributes->arity > 0 && attributes->arity != argc) || argc < 
-attributes->arity) {
+  if (!attributes->CheckArity(argc)) {
     return {Status::NotOK, "Invalid number of arguments specified for 
command"};
   }
 
-  if (attributes->key_range.first_key > 0) {
-    DumpKeyRange(*keys_index, argc, attributes->key_range);
-  } else if (attributes->key_range.first_key == -1) {
-    DumpKeyRange(*keys_index, argc, attributes->key_range_gen(cmd_tokens));
-  } else if (attributes->key_range.first_key == -2) {
-    for (const auto &range : attributes->key_range_vec_gen(cmd_tokens)) {
-      DumpKeyRange(*keys_index, argc, range);
-    }
-  } else {
-    return {Status::NotOK, "The key range specification is invalid"};
+  Status status;
+  std::vector<int> key_indexes;
+
+  attributes->ForEachKeyRange(
+      [&](const std::vector<std::string> &, CommandKeyRange key_range) {
+        key_range.ForEachKeyIndex([&](int i) { key_indexes.push_back(i); }, 
cmd_tokens.size());
+      },
+      cmd_tokens,
+      [&](const auto &) {
+        status = {Status::NotOK, "The command has no key arguments"};
+      });
+
+  if (!status) {
+    return status;
   }
 
-  return Status::OK();
+  return key_indexes;
 }
 
 bool CommandTable::IsExists(const std::string &name) {
diff --git a/src/commands/commander.h b/src/commands/commander.h
index 3c09fe87..87efdb01 100644
--- a/src/commands/commander.h
+++ b/src/commands/commander.h
@@ -141,9 +141,18 @@ struct CommandKeyRange {
   template <typename F>
   void ForEachKey(F &&f, const std::vector<std::string> &args) const {
     for (size_t i = first_key; last_key > 0 ? i <= size_t(last_key) : i <= 
args.size() + last_key; i += key_step) {
+      if (i >= args.size()) continue;
       std::forward<F>(f)(args[i]);
     }
   }
+
+  template <typename F>
+  void ForEachKeyIndex(F &&f, size_t arg_size) const {
+    for (size_t i = first_key; last_key > 0 ? i <= size_t(last_key) : i <= 
arg_size + last_key; i += key_step) {
+      if (i >= arg_size) continue;
+      std::forward<F>(f)(i);
+    }
+  }
 };
 
 using CommandKeyRangeGen = std::function<CommandKeyRange(const 
std::vector<std::string> &)>;
@@ -161,20 +170,20 @@ struct CommandAttributes {
       : name(std::move(name)),
         arity(arity),
         category(category),
-        key_range{0, 0, 0},
         factory(std::move(factory)),
         flags_(flags),
-        flag_gen_(std::move(flag_gen)) {}
+        flag_gen_(std::move(flag_gen)),
+        key_range_{0, 0, 0} {}
 
   CommandAttributes(std::string name, int arity, CommandCategory category, 
uint64_t flags, AdditionalFlagGen flag_gen,
                     CommandKeyRange key_range, CommanderFactory factory)
       : name(std::move(name)),
         arity(arity),
         category(category),
-        key_range(key_range),
         factory(std::move(factory)),
         flags_(flags),
-        flag_gen_(std::move(flag_gen)) {
+        flag_gen_(std::move(flag_gen)),
+        key_range_(key_range) {
     if (key_range.first_key <= 0 || key_range.key_step <= 0 ||
         (key_range.last_key >= 0 && key_range.last_key < key_range.first_key)) 
{
       std::cout << fmt::format("Encountered invalid key range in command {}", 
this->name) << std::endl;
@@ -187,22 +196,22 @@ struct CommandAttributes {
       : name(std::move(name)),
         arity(arity),
         category(category),
-        key_range{-1, 0, 0},
-        key_range_gen(std::move(key_range)),
         factory(std::move(factory)),
         flags_(flags),
-        flag_gen_(std::move(flag_gen)) {}
+        flag_gen_(std::move(flag_gen)),
+        key_range_{-1, 0, 0},
+        key_range_gen_(std::move(key_range)) {}
 
   CommandAttributes(std::string name, int arity, CommandCategory category, 
uint64_t flags, AdditionalFlagGen flag_gen,
                     CommandKeyRangeVecGen key_range, CommanderFactory factory)
       : name(std::move(name)),
         arity(arity),
         category(category),
-        key_range{-2, 0, 0},
-        key_range_vec_gen(std::move(key_range)),
         factory(std::move(factory)),
         flags_(flags),
-        flag_gen_(std::move(flag_gen)) {}
+        flag_gen_(std::move(flag_gen)),
+        key_range_{-2, 0, 0},
+        key_range_vec_gen_(std::move(key_range)) {}
 
   // command name
   std::string name;
@@ -215,16 +224,6 @@ struct CommandAttributes {
   // category of this command, e.g. key, string, hash
   CommandCategory category;
 
-  // static determined key range
-  // if key_range.first_key == 0, there's no key in this command args
-  CommandKeyRange key_range;
-
-  // if key_range.first_key == -1, key_range_gen is used instead
-  CommandKeyRangeGen key_range_gen;
-
-  // if key_range.first_key == -2, key_range_vec_gen is used instead
-  CommandKeyRangeVecGen key_range_vec_gen;
-
   // commander object generator
   CommanderFactory factory;
 
@@ -240,33 +239,57 @@ struct CommandAttributes {
     return !((arity > 0 && cmd_size != arity) || (arity < 0 && cmd_size < 
-arity));
   }
 
-  template <typename F>
-  void ForEachKeyRange(F &&f, const std::vector<std::string> &args) const {
-    if (key_range.first_key > 0) {
-      std::forward<F>(f)(args, key_range);
-    } else if (key_range.first_key == -1) {
-      redis::CommandKeyRange range = key_range_gen(args);
+  StatusOr<CommandKeyRange> InitialKeyRange() const {
+    if (key_range_.first_key >= 0) return key_range_;
+    return {Status::NotOK, "key range is unavailable without command 
arguments"};
+  }
+
+  template <typename F, typename G>
+  void ForEachKeyRange(F &&f, const std::vector<std::string> &args, G &&g) 
const {
+    if (key_range_.first_key > 0) {
+      std::forward<F>(f)(args, key_range_);
+    } else if (key_range_.first_key == -1) {
+      redis::CommandKeyRange range = key_range_gen_(args);
 
       if (range.first_key > 0) {
         std::forward<F>(f)(args, range);
       }
-    } else if (key_range.first_key == -2) {
-      std::vector<redis::CommandKeyRange> vec_range = key_range_vec_gen(args);
+    } else if (key_range_.first_key == -2) {
+      std::vector<redis::CommandKeyRange> vec_range = key_range_vec_gen_(args);
 
       for (const auto &range : vec_range) {
         if (range.first_key > 0) {
           std::forward<F>(f)(args, range);
         }
       }
+    } else if (key_range_.first_key == 0) {
+      // otherwise, if there's no key inside the command arguments
+      // e.g. FLUSHALL, with "write" flag but no key specified
+      std::forward<G>(g)(args);
     }
   }
 
+  template <typename F>
+  void ForEachKeyRange(F &&f, const std::vector<std::string> &args) const {
+    ForEachKeyRange(std::forward<F>(f), args, [](const auto &) {});
+  }
+
  private:
   // bitmap of enum CommandFlags
   uint64_t flags_;
 
   // additional flags regarding to dynamic command arguments
   AdditionalFlagGen flag_gen_;
+
+  // static determined key range
+  // if key_range.first_key == 0, there's no key in this command args
+  CommandKeyRange key_range_;
+
+  // if key_range.first_key == -1, key_range_gen is used instead
+  CommandKeyRangeGen key_range_gen_;
+
+  // if key_range.first_key == -2, key_range_vec_gen is used instead
+  CommandKeyRangeVecGen key_range_vec_gen_;
 };
 
 using CommandMap = std::map<std::string, const CommandAttributes *>;
@@ -374,8 +397,8 @@ struct CommandTable {
   static void GetAllCommandsInfo(std::string *info);
   static void GetCommandsInfo(std::string *info, const 
std::vector<std::string> &cmd_names);
   static std::string GetCommandInfo(const CommandAttributes 
*command_attributes);
-  static Status GetKeysFromCommand(const CommandAttributes *attributes, const 
std::vector<std::string> &cmd_tokens,
-                                   std::vector<int> *keys_indexes);
+  static StatusOr<std::vector<int>> GetKeysFromCommand(const CommandAttributes 
*attributes,
+                                                       const 
std::vector<std::string> &cmd_tokens);
 
   static size_t Size();
   static bool IsExists(const std::string &name);
diff --git a/src/common/string_util.h b/src/common/string_util.h
index ac3b2904..2dcb1080 100644
--- a/src/common/string_util.h
+++ b/src/common/string_util.h
@@ -41,8 +41,7 @@ std::string EscapeString(std::string_view s);
 std::string StringNext(std::string s);
 
 template <typename T, typename F>
-std::string StringJoin(
-    const T &con, F &&f = [](const auto &v) -> decltype(auto) { return v; }, 
std::string_view sep = ", ") {
+std::string StringJoin(const T &con, F &&f, std::string_view sep = ", ") {
   std::string res;
   bool is_first = true;
   for (const auto &v : con) {
diff --git a/src/server/server.cc b/src/server/server.cc
index f20b6824..1de5534d 100644
--- a/src/server/server.cc
+++ b/src/server/server.cc
@@ -1984,27 +1984,9 @@ void Server::updateAllWatchedKeys() {
 
 void Server::UpdateWatchedKeysFromArgs(const std::vector<std::string> &args, 
const redis::CommandAttributes &attr) {
   if ((attr.GenerateFlags(args) & redis::kCmdWrite) && watched_key_size_ > 0) {
-    if (attr.key_range.first_key > 0) {
-      updateWatchedKeysFromRange(args, attr.key_range);
-    } else if (attr.key_range.first_key == -1) {
-      redis::CommandKeyRange range = attr.key_range_gen(args);
-
-      if (range.first_key > 0) {
-        updateWatchedKeysFromRange(args, range);
-      }
-    } else if (attr.key_range.first_key == -2) {
-      std::vector<redis::CommandKeyRange> vec_range = 
attr.key_range_vec_gen(args);
-
-      for (const auto &range : vec_range) {
-        if (range.first_key > 0) {
-          updateWatchedKeysFromRange(args, range);
-        }
-      }
-
-    } else {
-      // support commands like flushdb (write flag && key range {0,0,0})
-      updateAllWatchedKeys();
-    }
+    attr.ForEachKeyRange([this](const std::vector<std::string> &args,
+                                redis::CommandKeyRange range) { 
updateWatchedKeysFromRange(args, range); },
+                         args, [this](const std::vector<std::string> &) { 
updateAllWatchedKeys(); });
   }
 }
 

Reply via email to