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

hulk 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 859953b84 feat(config): allow to configure the 
rocksdb.sst_file_delete_rate_bytes_per_sec (#3040)
859953b84 is described below

commit 859953b84fcb6ef3967414b33c9fa233b660038f
Author: sryan yuan <[email protected]>
AuthorDate: Fri Jun 27 16:41:29 2025 +0800

    feat(config): allow to configure the 
rocksdb.sst_file_delete_rate_bytes_per_sec (#3040)
---
 kvrocks.conf                            | 11 +++++++++++
 src/config/config.cc                    |  8 ++++++++
 src/config/config.h                     |  1 +
 src/storage/storage.cc                  |  7 ++++++-
 src/storage/storage.h                   |  2 ++
 tests/cppunit/config_test.cc            |  1 +
 tests/gocase/unit/config/config_test.go | 24 ++++++++++++++++++++++++
 7 files changed, 53 insertions(+), 1 deletion(-)

diff --git a/kvrocks.conf b/kvrocks.conf
index 25172cb88..96e9b05bc 100644
--- a/kvrocks.conf
+++ b/kvrocks.conf
@@ -1066,5 +1066,16 @@ rocksdb.partition_filters yes
 # Default: 0
 rocksdb.max_compaction_bytes 0
 
+# Set the delete rate limit in bytes per second for SST files deletion.
+# zero means disable delete rate limiting and delete files immediately.
+# In scenarios involving frequent database iterations (e.g., HGETALL, SCAN) 
obsolete WAL files 
+# may be deleted synchronously, causing latency spikes. Enabling this option 
activates a 
+# controlled slow deletion mechanism, which also resolves WAL deletion latency 
issues when
+# an iterator is released.
+# see https://github.com/facebook/rocksdb/wiki/Slow-Deletion
+#
+# Default: 0
+rocksdb.sst_file_delete_rate_bytes_per_sec 0
+
 ################################ NAMESPACE 
#####################################
 # namespace.test change.me
diff --git a/src/config/config.cc b/src/config/config.cc
index 24a9a2582..1e561fe6d 100644
--- a/src/config/config.cc
+++ b/src/config/config.cc
@@ -302,6 +302,8 @@ Config::Config() {
       {"rocksdb.avoid_unnecessary_blocking_io", true, new 
YesNoField(&rocks_db.avoid_unnecessary_blocking_io, true)},
       {"rocksdb.partition_filters", true, new 
YesNoField(&rocks_db.partition_filters, true)},
       {"rocksdb.max_compaction_bytes", false, new 
Int64Field(&rocks_db.max_compaction_bytes, 0, 0, INT64_MAX)},
+      {"rocksdb.sst_file_delete_rate_bytes_per_sec", false,
+       new Int64Field(&rocks_db.sst_file_delete_rate_bytes_per_sec, 0, 0, 
INT64_MAX)},
 
       /* rocksdb write options */
       {"rocksdb.write_options.sync", true, new 
YesNoField(&rocks_db.write_options.sync, false)},
@@ -720,6 +722,12 @@ void Config::initFieldCallback() {
          }
          return 
srv->storage->SetOptionForAllColumnFamilies(TrimRocksDbPrefix(k), v);
        }},
+      {"rocksdb.sst_file_delete_rate_bytes_per_sec",
+       [this](Server *srv, [[maybe_unused]] const std::string &k, 
[[maybe_unused]] const std::string &v) -> Status {
+         if (!srv) return Status::OK();
+         
srv->storage->SetSstFileDeleteRateBytesPerSecond(rocks_db.sst_file_delete_rate_bytes_per_sec);
+         return Status::OK();
+       }},
       {"rocksdb.max_open_files", set_db_option_cb},
       {"rocksdb.stats_dump_period_sec", set_db_option_cb},
       {"rocksdb.delayed_write_rate", set_db_option_cb},
diff --git a/src/config/config.h b/src/config/config.h
index 0b95b81ac..2dd415732 100644
--- a/src/config/config.h
+++ b/src/config/config.h
@@ -238,6 +238,7 @@ struct Config {
     bool avoid_unnecessary_blocking_io = true;
     bool partition_filters;
     int64_t max_compaction_bytes;
+    int64_t sst_file_delete_rate_bytes_per_sec = 0;
 
     struct WriteOptions {
       bool sync;
diff --git a/src/storage/storage.cc b/src/storage/storage.cc
index 47afc5bf2..96eb931f3 100644
--- a/src/storage/storage.cc
+++ b/src/storage/storage.cc
@@ -194,7 +194,8 @@ rocksdb::Options Storage::InitRocksDBOptions() {
   options.max_total_wal_size = 
static_cast<uint64_t>(config_->rocks_db.max_total_wal_size * MiB);
   options.listeners.emplace_back(new EventListener(this));
   options.dump_malloc_stats = config_->rocks_db.dump_malloc_stats;
-  sst_file_manager_ = 
std::shared_ptr<rocksdb::SstFileManager>(rocksdb::NewSstFileManager(rocksdb::Env::Default()));
+  sst_file_manager_ = 
std::shared_ptr<rocksdb::SstFileManager>(rocksdb::NewSstFileManager(
+      rocksdb::Env::Default(), nullptr, "", 
config_->rocks_db.sst_file_delete_rate_bytes_per_sec));
   options.sst_file_manager = sst_file_manager_;
   int64_t max_io_mb = kIORateLimitMaxMb;
   if (config_->max_io_mb > 0) max_io_mb = config_->max_io_mb;
@@ -922,6 +923,10 @@ uint64_t Storage::GetTotalSize(const std::string &ns) {
   return total_size;
 }
 
+void Storage::SetSstFileDeleteRateBytesPerSecond(int64_t delete_rate) {
+  sst_file_manager_->SetDeleteRateBytesPerSecond(delete_rate);
+}
+
 void Storage::CheckDBSizeLimit() {
   bool limit_reached = false;
   if (config_->max_db_size > 0) {
diff --git a/src/storage/storage.h b/src/storage/storage.h
index 76b501a63..8ef807eca 100644
--- a/src/storage/storage.h
+++ b/src/storage/storage.h
@@ -31,6 +31,7 @@
 #include <atomic>
 #include <cinttypes>
 #include <cstddef>
+#include <cstdint>
 #include <memory>
 #include <shared_mutex>
 #include <string>
@@ -284,6 +285,7 @@ class Storage {
   LockManager *GetLockManager() { return &lock_mgr_; }
   void PurgeOldBackups(uint32_t num_backups_to_keep, uint32_t 
backup_max_keep_hours);
   uint64_t GetTotalSize(const std::string &ns = kDefaultNamespace);
+  void SetSstFileDeleteRateBytesPerSecond(int64_t delete_rate);
   void CheckDBSizeLimit();
   bool ReachedDBSizeLimit() { return db_size_limit_reached_; }
   void SetDBSizeLimit(bool limit) { db_size_limit_reached_ = limit; }
diff --git a/tests/cppunit/config_test.cc b/tests/cppunit/config_test.cc
index 301c373ab..84c4cc385 100644
--- a/tests/cppunit/config_test.cc
+++ b/tests/cppunit/config_test.cc
@@ -84,6 +84,7 @@ TEST(Config, GetAndSet) {
       {"rocksdb.level_compaction_dynamic_level_bytes", "yes"},
       {"rocksdb.max_background_jobs", "4"},
       {"rocksdb.compression_start_level", "2"},
+      {"rocksdb.sst_file_delete_rate_bytes_per_sec", "0"},
   };
   std::vector<std::string> values;
   for (const auto &iter : mutable_cases) {
diff --git a/tests/gocase/unit/config/config_test.go 
b/tests/gocase/unit/config/config_test.go
index 4d4636187..3287318ea 100644
--- a/tests/gocase/unit/config/config_test.go
+++ b/tests/gocase/unit/config/config_test.go
@@ -371,3 +371,27 @@ func TestConfigRocksDBOptions(t *testing.T) {
                require.EqualValues(t, "1073741824", result[parameter])
        })
 }
+
+func TestConfigSstFileDeleteRateBytesPerSec(t *testing.T) {
+       t.Parallel()
+       srv := util.StartServer(t, map[string]string{})
+       defer srv.Close()
+
+       cli := srv.NewClient()
+       defer func() { require.NoError(t, cli.Close()) }()
+
+       t.Run("Get and Set rocksdb.sst_file_delete_rate_bytes_per_sec", func(t 
*testing.T) {
+               ctx := context.Background()
+               parameter := "rocksdb.sst_file_delete_rate_bytes_per_sec"
+               result, err := cli.ConfigGet(ctx, parameter).Result()
+               require.NoError(t, err)
+               require.EqualValues(t, "0", result[parameter])
+
+               util.ErrorRegexp(t, cli.ConfigSet(ctx, parameter, "-1").Err(), 
".*out of numeric range")
+
+               require.NoError(t, cli.ConfigSet(ctx, parameter, 
"1073741824").Err())
+               result, err = cli.ConfigGet(ctx, parameter).Result()
+               require.NoError(t, err)
+               require.EqualValues(t, "1073741824", result[parameter])
+       })
+}

Reply via email to