From 10dcee7508e25e554ac7ace9df49081b7c166d29 Mon Sep 17 00:00:00 2001 From: Admin <62771363+GoDeskio@users.noreply.github.com> Date: Sun, 1 Nov 2026 01:47:23 +0800 Subject: [PATCH] CMO: disk-first plan on Kvrocks (#25) --- tools/diskplan/diskplan.py | 37 +++++++++++++++++++++++++++++++++ tools/diskplan/test_diskplan.py | 25 ++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 tools/diskplan/diskplan.py create mode 100644 tools/diskplan/test_diskplan.py diff --git a/tools/diskplan/diskplan.py b/tools/diskplan/diskplan.py new file mode 100644 index 00000000000..f16481873f6 --- /dev/null +++ b/tools/diskplan/diskplan.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +"""Disk-first plan backed by Apache Kvrocks (plan item 25). + +For datasets bigger than RAM we offer a plan that runs Apache Kvrocks +(Apache-2.0, RocksDB on NVMe, Redis protocol) instead of Valkey. We use the +upstream image as-is; this module renders its config from a plan size and +lists the commands that differ so the proxy can reject them clearly. +""" +import re + +PLANS = { # disk GB -> (rocksdb block cache MB, worker threads) + 50: (512, 4), 200: (2048, 8), 1000: (8192, 16), +} +# Valkey features Kvrocks does not support (proxy answers with a clear error). +UNSUPPORTED = {"MODULE", "FUNCTION", "FT.CREATE", "FT.SEARCH", "JSON.SET", "BF.ADD", "WAITAOF", "SWAPDB"} + + +def config(disk_gb, password_file="/run/secrets/kvrocks.conf", tls=True): + if disk_gb not in PLANS: + raise ValueError("plan sizes: %s" % sorted(PLANS)) + cache, workers = PLANS[disk_gb] + lines = ["bind 0.0.0.0", "dir /data", "workers %d" % workers, + "rocksdb.block_cache_size %d" % cache, + "rocksdb.compression zstd", + "max-backup-to-keep 1", + "include %s" % password_file] # holds `requirepass`; never inline secrets + lines += ["port 0", "tls-port 6380", "tls-cert-file /tls/server.crt", + "tls-key-file /tls/server.key", "tls-ca-cert-file /tls/ca.crt"] if tls else ["port 6379"] + return "\n".join(lines) + "\n" + + +def check_command(argv): + """Return None if allowed on the disk plan, else an error string for the client.""" + name = argv[0].upper() if argv else "" + if name in UNSUPPORTED or re.match(r"^(FT|JSON|BF|CF|TS)\.", name): + return "ERR %s is not available on the disk plan" % name + return None diff --git a/tools/diskplan/test_diskplan.py b/tools/diskplan/test_diskplan.py new file mode 100644 index 00000000000..49f1f59656a --- /dev/null +++ b/tools/diskplan/test_diskplan.py @@ -0,0 +1,25 @@ +import unittest +import diskplan as D + + +class T(unittest.TestCase): + def test_config(self): + c = D.config(200) + self.assertIn("rocksdb.block_cache_size 2048", c) + self.assertIn("tls-port 6380", c) + self.assertIn("port 0", c) + self.assertNotIn("requirepass", c) + self.assertIn("port 6379", D.config(50, tls=False)) + with self.assertRaises(ValueError): + D.config(7) + + def test_commands(self): + self.assertIsNone(D.check_command(["GET", "k"])) + self.assertIsNone(D.check_command(["hset", "h", "f", "v"])) + self.assertIn("not available", D.check_command(["ft.search", "i", "*"])) + self.assertIn("not available", D.check_command(["TS.ADD", "k", "*", "1"])) + self.assertIn("not available", D.check_command(["MODULE", "LIST"])) + + +if __name__ == "__main__": + unittest.main()