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 ee69364d feat(config): add compaction-checker-cron to extend original 
compaction-checker-range (#2383)
ee69364d is described below

commit ee69364df483badcb53bf0feac98391c18a2ffe3
Author: Twice <[email protected]>
AuthorDate: Sun Jun 30 12:15:11 2024 +0900

    feat(config): add compaction-checker-cron to extend original 
compaction-checker-range (#2383)
---
 kvrocks.conf               | 20 ++++++++++++++------
 src/common/cron.cc         |  2 ++
 src/common/cron.h          | 12 +++++++-----
 src/config/config.cc       | 23 +++++++++++------------
 src/config/config.h        | 11 ++---------
 src/server/server.cc       | 12 +++++++-----
 tests/cppunit/cron_test.cc | 40 ++++++++++++++++++++++++++++++++++++++++
 7 files changed, 83 insertions(+), 37 deletions(-)

diff --git a/kvrocks.conf b/kvrocks.conf
index a5f20f09..66715028 100644
--- a/kvrocks.conf
+++ b/kvrocks.conf
@@ -492,15 +492,23 @@ profiling-sample-record-threshold-ms 100
 ################################## CRON ###################################
 
 # Compact Scheduler, auto compact at schedule time
-# Time expression format is the same as crontab (currently only support *, int 
and */int)
-# e.g. compact-cron 0 3 * * * 0 4 * * *
+# Time expression format is the same as crontab (supported cron syntax: *, n, 
*/n, `1,3-6,9,11`)
+# e.g. compact-cron 0 3,4 * * *
 # would compact the db at 3am and 4am everyday
 # compact-cron 0 3 * * *
 
 # The hour range that compaction checker would be active
 # e.g. compaction-checker-range 0-7 means compaction checker would be worker 
between
 # 0-7am every day.
-compaction-checker-range 0-7
+# WARNING: this config option is deprecated and will be removed,
+# please use compaction-checker-cron instead
+# compaction-checker-range 0-7
+
+# The time pattern that compaction checker would be active
+# Time expression format is the same as crontab (supported cron syntax: *, n, 
*/n, `1,3-6,9,11`)
+# e.g. compaction-checker-cron * 0-7 * * * means compaction checker would be 
worker between
+# 0-7am every day.
+compaction-checker-cron * 0-7 * * *
 
 # When the compaction checker is triggered, the db will periodically pick the 
SST file
 # with the highest "deleted percentage" (i.e. the percentage of deleted keys 
in the SST 
@@ -515,14 +523,14 @@ compaction-checker-range 0-7
 # force-compact-file-min-deleted-percentage 10
 
 # Bgsave scheduler, auto bgsave at scheduled time
-# Time expression format is the same as crontab (currently only support *, int 
and */int)
-# e.g. bgsave-cron 0 3 * * * 0 4 * * *
+# Time expression format is the same as crontab (supported cron syntax: *, n, 
*/n, `1,3-6,9,11`)
+# e.g. bgsave-cron 0 3,4 * * *
 # would bgsave the db at 3am and 4am every day
 
 # Kvrocks doesn't store the key number directly. It needs to scan the DB and
 # then retrieve the key number by using the dbsize scan command.
 # The Dbsize scan scheduler auto-recalculates the estimated keys at scheduled 
time.
-# Time expression format is the same as crontab (currently only support *, int 
and */int)
+# Time expression format is the same as crontab (supported cron syntax: *, n, 
*/n, `1,3-6,9,11`)
 # e.g. dbsize-scan-cron 0 * * * *
 # would recalculate the keyspace infos of the db every hour.
 
diff --git a/src/common/cron.cc b/src/common/cron.cc
index 26db65f3..041ffe16 100644
--- a/src/common/cron.cc
+++ b/src/common/cron.cc
@@ -55,6 +55,8 @@ StatusOr<CronScheduler> CronScheduler::Parse(std::string_view 
minute, std::strin
   return st;
 }
 
+void Cron::Clear() { schedulers_.clear(); }
+
 Status Cron::SetScheduleTime(const std::vector<std::string> &args) {
   if (args.empty()) {
     schedulers_.clear();
diff --git a/src/common/cron.h b/src/common/cron.h
index b228a69e..ede6231b 100644
--- a/src/common/cron.h
+++ b/src/common/cron.h
@@ -40,7 +40,7 @@ struct CronPattern {
   struct Any {};                                             // *
   using Numbers = std::vector<std::variant<Number, Range>>;  // 1,2,3-6,7
 
-  std::variant<Numbers, Interval, Any> val;
+  std::variant<Any, Numbers, Interval> val;
 
   static StatusOr<CronPattern> Parse(std::string_view str, std::tuple<int, 
int> minmax) {
     if (str == "*") {
@@ -63,10 +63,10 @@ struct CronPattern {
         if (auto pos = num_str.find('-'); pos != num_str.npos) {
           auto l_str = num_str.substr(0, pos);
           auto r_str = num_str.substr(pos + 1);
-          auto l = GET_OR_RET(ParseInt<int>(std::string(num_str.begin(), 
num_str.end()), minmax)
-                                  .Prefixed("an integer is expected before `-` 
in a cron expression"));
-          auto r = GET_OR_RET(ParseInt<int>(std::string(num_str.begin(), 
num_str.end()), minmax)
-                                  .Prefixed("an integer is expected after `-` 
in a cron expression"));
+          auto l = GET_OR_RET(
+              ParseInt<int>(l_str, minmax).Prefixed("an integer is expected 
before `-` in a cron expression"));
+          auto r = GET_OR_RET(
+              ParseInt<int>(r_str, minmax).Prefixed("an integer is expected 
after `-` in a cron expression"));
 
           if (l >= r) {
             return {Status::NotOK, "for pattern `l-r` in cron expression, r 
should be larger than l"};
@@ -160,6 +160,8 @@ class Cron {
   ~Cron() = default;
 
   Status SetScheduleTime(const std::vector<std::string> &args);
+  void Clear();
+
   bool IsTimeMatch(const tm *tm);
   std::string ToString() const;
   bool IsEnabled() const;
diff --git a/src/config/config.cc b/src/config/config.cc
index 3163dd97..4ff8901f 100644
--- a/src/config/config.cc
+++ b/src/config/config.cc
@@ -141,6 +141,7 @@ Config::Config() {
       {"replica-announce-ip", false, new StringField(&replica_announce_ip, 
"")},
       {"replica-announce-port", false, new UInt32Field(&replica_announce_port, 
0, 0, PORT_LIMIT)},
       {"compaction-checker-range", false, new 
StringField(&compaction_checker_range_str_, "")},
+      {"compaction-checker-cron", false, new 
StringField(&compaction_checker_cron_str_, "")},
       {"force-compact-file-age", false, new 
Int64Field(&force_compact_file_age, 2 * 24 * 3600, 60, INT64_MAX)},
       {"force-compact-file-min-deleted-percentage", false,
        new IntField(&force_compact_file_min_deleted_percentage, 10, 1, 100)},
@@ -300,21 +301,19 @@ void Config::initFieldValidator() {
        }},
       {"compaction-checker-range",
        [this](const std::string &k, const std::string &v) -> Status {
+         if (!compaction_checker_cron_str_.empty()) {
+           return {Status::NotOK, "compaction-checker-range cannot be set 
while compaction-checker-cron is set"};
+         }
          if (v.empty()) {
-           compaction_checker_range.start = -1;
-           compaction_checker_range.stop = -1;
+           compaction_checker_cron.Clear();
            return Status::OK();
          }
-         std::vector<std::string> args = util::Split(v, "-");
-         if (args.size() != 2) {
-           return {Status::NotOK, "invalid range format, the range should be 
between 0 and 24"};
-         }
-         auto start = GET_OR_RET(ParseInt<int>(args[0], {0, 24}, 10)),
-              stop = GET_OR_RET(ParseInt<int>(args[1], {0, 24}, 10));
-         if (start > stop) return {Status::NotOK, "invalid range format, start 
should be smaller than stop"};
-         compaction_checker_range.start = start;
-         compaction_checker_range.stop = stop;
-         return Status::OK();
+         return compaction_checker_cron.SetScheduleTime({"*", v, "*", "*", 
"*"});
+       }},
+      {"compaction-checker-cron",
+       [this](const std::string &k, const std::string &v) -> Status {
+         std::vector<std::string> args = util::Split(v, " \t");
+         return compaction_checker_cron.SetScheduleTime(args);
        }},
       {"rename-command",
        [](const std::string &k, const std::string &v) -> Status {
diff --git a/src/config/config.h b/src/config/config.h
index c4bc705b..73936de3 100644
--- a/src/config/config.h
+++ b/src/config/config.h
@@ -57,14 +57,6 @@ constexpr const char *kDefaultNamespace = "__namespace";
 
 enum class BlockCacheType { kCacheTypeLRU = 0, kCacheTypeHCC };
 
-struct CompactionCheckerRange {
- public:
-  int start;
-  int stop;
-
-  bool Enabled() const { return start != -1 || stop != -1; }
-};
-
 struct CLIOptions {
   std::string conf_file;
   std::vector<std::pair<std::string, std::string>> cli_options;
@@ -138,7 +130,7 @@ struct Config {
   Cron compact_cron;
   Cron bgsave_cron;
   Cron dbsize_scan_cron;
-  CompactionCheckerRange compaction_checker_range{-1, -1};
+  Cron compaction_checker_cron;
   int64_t force_compact_file_age;
   int force_compact_file_min_deleted_percentage;
   bool repl_namespace_enabled = false;
@@ -249,6 +241,7 @@ struct Config {
   std::string bgsave_cron_str_;
   std::string dbsize_scan_cron_str_;
   std::string compaction_checker_range_str_;
+  std::string compaction_checker_cron_str_;
   std::string profiling_sample_commands_str_;
   std::map<std::string, std::unique_ptr<ConfigField>> fields_;
   std::vector<std::string> rename_command_;
diff --git a/src/server/server.cc b/src/server/server.cc
index 2da7dfa0..5e3b7f13 100644
--- a/src/server/server.cc
+++ b/src/server/server.cc
@@ -204,16 +204,18 @@ Status Server::Start() {
       if (storage->IsClosing()) continue;
 
       if (!is_loading_ && ++counter % 600 == 0  // check every minute
-          && config_->compaction_checker_range.Enabled()) {
-        auto now_hours = util::GetTimeStamp<std::chrono::hours>();
-        if (now_hours >= config_->compaction_checker_range.start &&
-            now_hours <= config_->compaction_checker_range.stop) {
+          && config_->compaction_checker_cron.IsEnabled()) {
+        auto t_now = static_cast<time_t>(util::GetTimeStamp());
+        std::tm now{};
+        localtime_r(&t_now, &now);
+        if (config_->compaction_checker_cron.IsTimeMatch(&now)) {
           const auto &column_family_list = 
engine::ColumnFamilyConfigs::ListAllColumnFamilies();
           for (auto &column_family : column_family_list) {
             compaction_checker.PickCompactionFilesForCf(column_family);
           }
         }
         // compact once per day
+        auto now_hours = t_now / 3600;
         if (now_hours != 0 && last_compact_date != now_hours / 24) {
           last_compact_date = now_hours / 24;
           compaction_checker.CompactPropagateAndPubSubFiles();
@@ -756,7 +758,7 @@ void Server::cron() {
       std::tm now{};
       localtime_r(&t, &now);
       // disable compaction cron when the compaction checker was enabled
-      if (!config_->compaction_checker_range.Enabled() && 
config_->compact_cron.IsEnabled() &&
+      if (!config_->compaction_checker_cron.IsEnabled() && 
config_->compact_cron.IsEnabled() &&
           config_->compact_cron.IsTimeMatch(&now)) {
         Status s = AsyncCompactDB();
         LOG(INFO) << "[server] Schedule to compact the db, result: " << 
s.Msg();
diff --git a/tests/cppunit/cron_test.cc b/tests/cppunit/cron_test.cc
index 9ce38a5a..bccb5ee2 100644
--- a/tests/cppunit/cron_test.cc
+++ b/tests/cppunit/cron_test.cc
@@ -372,3 +372,43 @@ TEST_F(CronTestWeekDayInterval, ToString) {
   std::string got = cron_->ToString();
   ASSERT_EQ("0 * * * */4", got);
 }
+
+class CronTestNumberAndRange : public testing::Test {
+ protected:
+  explicit CronTestNumberAndRange() {
+    cron_ = std::make_unique<Cron>();
+    std::vector<std::string> schedule{"*", "1,3,6-10,20", "*", "*", "*"};
+    auto s = cron_->SetScheduleTime(schedule);
+    EXPECT_TRUE(s.IsOK());
+  }
+  ~CronTestNumberAndRange() override = default;
+
+  std::unique_ptr<Cron> cron_;
+};
+
+TEST_F(CronTestNumberAndRange, IsTimeMatch) {
+  std::time_t t = std::time(nullptr);
+  std::tm *now = std::localtime(&t);
+  now->tm_hour = 1;
+  ASSERT_TRUE(cron_->IsTimeMatch(now));
+  now->tm_hour = 3;
+  ASSERT_TRUE(cron_->IsTimeMatch(now));
+  now->tm_hour = 6;
+  ASSERT_TRUE(cron_->IsTimeMatch(now));
+  now->tm_hour = 8;
+  ASSERT_TRUE(cron_->IsTimeMatch(now));
+  now->tm_hour = 10;
+  ASSERT_TRUE(cron_->IsTimeMatch(now));
+  now->tm_hour = 20;
+  ASSERT_TRUE(cron_->IsTimeMatch(now));
+  now->tm_hour = 0;
+  ASSERT_FALSE(cron_->IsTimeMatch(now));
+  now->tm_hour = 2;
+  ASSERT_FALSE(cron_->IsTimeMatch(now));
+  now->tm_hour = 5;
+  ASSERT_FALSE(cron_->IsTimeMatch(now));
+  now->tm_hour = 14;
+  ASSERT_FALSE(cron_->IsTimeMatch(now));
+  now->tm_hour = 22;
+  ASSERT_FALSE(cron_->IsTimeMatch(now));
+}

Reply via email to