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 fe8b4ccac feat(command): add new command to flush the block cache (#3049) fe8b4ccac is described below commit fe8b4ccaca544a5a7214b511a2107fa65ab831ae Author: sryan yuan <sr...@qq.com> AuthorDate: Mon Jul 14 11:57:58 2025 +0800 feat(command): add new command to flush the block cache (#3049) --- src/commands/cmd_server.cc | 15 +++- src/storage/storage.cc | 2 + src/storage/storage.h | 1 + .../unit/flushblockcache/flushblockcache_test.go | 82 ++++++++++++++++++++++ 4 files changed, 99 insertions(+), 1 deletion(-) diff --git a/src/commands/cmd_server.cc b/src/commands/cmd_server.cc index 23e049cdd..fd2245b0f 100644 --- a/src/commands/cmd_server.cc +++ b/src/commands/cmd_server.cc @@ -1527,6 +1527,18 @@ class CommandFlushMemTable : public Commander { rocksdb::FlushOptions flush_options_; }; +class CommandFlushBlockCache : public Commander { + public: + Status Execute([[maybe_unused]] engine::Context &ctx, Server *srv, [[maybe_unused]] Connection *conn, + std::string *output) override { + srv->storage->FlushBlockCache(); + + *output = redis::RESP_OK; + info("FLUSHBLOCKCACHE is triggered and executed successfully"); + return Status::OK(); + } +}; + REDIS_REGISTER_COMMANDS(Server, MakeCmdAttr<CommandAuth>("auth", 2, "read-only ok-loading auth", NO_KEY), MakeCmdAttr<CommandPing>("ping", -1, "read-only", NO_KEY), MakeCmdAttr<CommandSelect>("select", 2, "read-only", NO_KEY), @@ -1570,5 +1582,6 @@ REDIS_REGISTER_COMMANDS(Server, MakeCmdAttr<CommandAuth>("auth", 2, "read-only o MakeCmdAttr<CommandDump>("dump", 2, "read-only", 1, 1, 1), MakeCmdAttr<CommandPollUpdates>("pollupdates", -2, "read-only admin", NO_KEY), MakeCmdAttr<CommandSST>("sst", -3, "write exclusive admin", 1, 1, 1), - MakeCmdAttr<CommandFlushMemTable>("flushmemtable", -1, "exclusive write", NO_KEY), ) + MakeCmdAttr<CommandFlushMemTable>("flushmemtable", -1, "exclusive write", NO_KEY), + MakeCmdAttr<CommandFlushBlockCache>("flushblockcache", 1, "exclusive write", NO_KEY), ) } // namespace redis diff --git a/src/storage/storage.cc b/src/storage/storage.cc index 236e91eb0..e312e5356 100644 --- a/src/storage/storage.cc +++ b/src/storage/storage.cc @@ -843,6 +843,8 @@ rocksdb::Status Storage::ingestSST(rocksdb::ColumnFamilyHandle *cf_handle, return db_->IngestExternalFile(cf_handle, sst_file_names, options); } +void Storage::FlushBlockCache() { shared_block_cache_->EraseUnRefEntries(); } + Status Storage::ReplicaApplyWriteBatch(rocksdb::WriteBatch *batch) { return applyWriteBatch(default_write_opts_, batch); } diff --git a/src/storage/storage.h b/src/storage/storage.h index 3bb4fdf09..b366926e8 100644 --- a/src/storage/storage.h +++ b/src/storage/storage.h @@ -276,6 +276,7 @@ class Storage { const rocksdb::FlushOptions &options); [[nodiscard]] StatusOr<int> IngestSST(const std::string &folder, const rocksdb::IngestExternalFileOptions &ingest_options); + void FlushBlockCache(); rocksdb::DB *GetDB(); bool IsClosing() const { return db_closing_; } diff --git a/tests/gocase/unit/flushblockcache/flushblockcache_test.go b/tests/gocase/unit/flushblockcache/flushblockcache_test.go new file mode 100644 index 000000000..85c8b7fcc --- /dev/null +++ b/tests/gocase/unit/flushblockcache/flushblockcache_test.go @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package flushblockcache + +import ( + "context" + "strconv" + "testing" + + "github.com/apache/kvrocks/tests/gocase/util" + "github.com/redis/go-redis/v9" + "github.com/stretchr/testify/require" +) + +func getBlockCacheSize(rdb *redis.Client) (int64, error) { + value := util.FindInfoEntry(rdb, "block_cache_usage", "rocksdb") + return strconv.ParseInt(value, 10, 64) +} + +func TestFlushBlockCache(t *testing.T) { + configs := map[string]string{} + srv := util.StartServer(t, configs) + defer srv.Close() + + rdb := srv.NewClient() + defer func() { + require.NoError(t, rdb.Close()) + }() + + ctx := context.Background() + + t.Run("flushblockcache", func(t *testing.T) { + _, err := rdb.Do(ctx, "SET", "A", "KVROCKS").Result() + require.NoError(t, err) + _, err = rdb.Do(ctx, "FLUSHMEMTABLE").Result() + require.NoError(t, err) + _, err = rdb.Do(ctx, "GET", "A").Result() + require.NoError(t, err) + initCacheSize, err := getBlockCacheSize(rdb) + require.NoError(t, err) + _, err = rdb.Do(ctx, "FLUSHBLOCKCACHE").Result() + require.NoError(t, err) + cacheSize, err := getBlockCacheSize(rdb) + require.NoError(t, err) + require.Less(t, cacheSize, initCacheSize) + require.Equal(t, "KVROCKS", rdb.Do(ctx, "GET", "A").Val()) + }) +} + +func TestFlushBlockCacheInvalid(t *testing.T) { + srv := util.StartServer(t, map[string]string{}) + defer srv.Close() + + rdb := srv.NewClient() + defer func() { + require.NoError(t, rdb.Close()) + }() + + ctx := context.Background() + + t.Run("invalid arguments", func(t *testing.T) { + _, err := rdb.Do(ctx, "FLUSHBLOCKCACHE", "ARG").Result() + require.Contains(t, err.Error(), "wrong number of arguments") + }) +}