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

yiguolei pushed a commit to branch branch-4.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-4.1 by this push:
     new 4d153779a42 branch-4.1: [fix](filecache) Disable sync file cache clear 
in http api(pick#64321) (#64461)
4d153779a42 is described below

commit 4d153779a42e25f25c4d93d02d9b09bdb0657806
Author: zhengyu <[email protected]>
AuthorDate: Tue Jun 16 18:13:41 2026 +0800

    branch-4.1: [fix](filecache) Disable sync file cache clear in http 
api(pick#64321) (#64461)
    
    Pick from https://github.com/apache/doris/pull/64321
---
 be/src/service/http/action/file_cache_action.cpp |  12 +-
 be/test/service/http/file_cache_action_test.cpp  | 192 +++++++++++++++++++++++
 2 files changed, 202 insertions(+), 2 deletions(-)

diff --git a/be/src/service/http/action/file_cache_action.cpp 
b/be/src/service/http/action/file_cache_action.cpp
index 4791e5ddd94..f8794982689 100644
--- a/be/src/service/http/action/file_cache_action.cpp
+++ b/be/src/service/http/action/file_cache_action.cpp
@@ -57,6 +57,8 @@ constexpr static std::string_view RELEASED_ELEMENTS = 
"released_elements";
 constexpr static std::string_view DUMP = "dump";
 constexpr static std::string_view VALUE = "value";
 constexpr static std::string_view RELOAD = "reload";
+constexpr static std::string_view SYNC_CLEAR_UNSUPPORTED_MSG =
+        "sync clear_file_cache is no longer supported in http api, running 
async clear instead";
 
 Status FileCacheAction::_handle_header(HttpRequest* req, std::string* 
json_metrics) {
     const std::string header_json(HEADER_JSON);
@@ -83,11 +85,17 @@ Status FileCacheAction::_handle_header(HttpRequest* req, 
std::string* json_metri
         const std::string& sync = req->param(std::string(SYNC));
         const std::string& segment_path = req->param(std::string(VALUE));
         if (segment_path.empty()) {
-            io::FileCacheFactory::instance()->clear_file_caches(to_lower(sync) 
== "true");
+            io::FileCacheFactory::instance()->clear_file_caches(false);
         } else {
             io::UInt128Wrapper hash = io::BlockFileCache::hash(segment_path);
             io::BlockFileCache* cache = 
io::FileCacheFactory::instance()->get_by_path(hash);
-            cache->remove_if_cached(hash);
+            cache->remove_if_cached_async(hash);
+        }
+        if (to_lower(sync) == "true") {
+            EasyJson json;
+            json["status"] = "OK";
+            json["msg"] = std::string(SYNC_CLEAR_UNSUPPORTED_MSG);
+            *json_metrics = json.ToString();
         }
     } else if (operation == RESET) {
         std::string capacity = req->param(std::string(CAPACITY));
diff --git a/be/test/service/http/file_cache_action_test.cpp 
b/be/test/service/http/file_cache_action_test.cpp
new file mode 100644
index 00000000000..a53e36145f1
--- /dev/null
+++ b/be/test/service/http/file_cache_action_test.cpp
@@ -0,0 +1,192 @@
+// 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.
+
+#include "service/http/action/file_cache_action.h"
+
+#include <event2/event.h>
+#include <event2/http.h>
+#include <gtest/gtest.h>
+
+#include <chrono>
+#include <filesystem>
+#include <memory>
+#include <string_view>
+#include <thread>
+
+#include "common/config.h"
+#include "io/cache/block_file_cache.h"
+#include "io/cache/block_file_cache_factory.h"
+#include "io/cache/file_cache_common.h"
+#include "runtime/exec_env.h"
+#include "service/http/http_request.h"
+#include "util/slice.h"
+
+namespace doris {
+
+class FileCacheActionTest : public testing::Test {
+public:
+    FileCacheActionTest() : _action(nullptr) {}
+    ~FileCacheActionTest() override = default;
+
+    static void SetUpTestSuite() {
+        if (doris::ExecEnv::GetInstance()->file_cache_factory() == nullptr) {
+            _suite_factory = std::make_unique<doris::io::FileCacheFactory>();
+            doris::ExecEnv::GetInstance()->_file_cache_factory = 
_suite_factory.get();
+        }
+
+        if (!doris::ExecEnv::GetInstance()->_file_cache_open_fd_cache) {
+            doris::ExecEnv::GetInstance()->_file_cache_open_fd_cache =
+                    std::make_unique<doris::io::FDCache>();
+        }
+    }
+    static void TearDownTestSuite() {
+        if (doris::ExecEnv::GetInstance()->file_cache_factory() != nullptr) {
+            doris::io::FileCacheFactory::instance()->clear_file_caches(true);
+        }
+        _suite_factory.reset(nullptr);
+        
doris::ExecEnv::GetInstance()->_file_cache_open_fd_cache.reset(nullptr);
+    }
+
+    void SetUp() override {
+        _event_base = event_base_new();
+        _evhttp_req = evhttp_request_new(nullptr, nullptr);
+        _action = std::make_unique<FileCacheAction>(nullptr);
+
+        ASSERT_NE(doris::ExecEnv::GetInstance()->file_cache_factory(), 
nullptr);
+        reset_file_cache_factory();
+
+        _base_path = "/tmp/file_cache_action_ut_" + std::to_string(getpid());
+        (void)std::filesystem::create_directories(_base_path);
+        doris::io::FileCacheSettings settings;
+        settings.storage = "memory";
+        settings.capacity = 1024 * 1024;          // 1MB
+        settings.max_file_block_size = 64 * 1024; // 64KB
+        settings.query_queue_size = 1024 * 1024;
+        settings.query_queue_elements = 16;
+        auto cache = std::make_unique<doris::io::BlockFileCache>(_base_path, 
settings);
+        ASSERT_TRUE(cache->initialize());
+        for (int i = 0; i < 1000; ++i) {
+            if (cache->get_async_open_success()) break;
+            std::this_thread::sleep_for(std::chrono::milliseconds(1));
+        }
+        auto* raw = cache.get();
+        auto* factory = doris::io::FileCacheFactory::instance();
+        factory->_caches.emplace_back(std::move(cache));
+        factory->_path_to_cache[_base_path] = raw;
+        _cache = raw;
+    }
+
+    void TearDown() override {
+        if (_evhttp_req != nullptr) {
+            evhttp_request_free(_evhttp_req);
+        }
+
+        if (_event_base != nullptr) {
+            event_base_free(_event_base);
+        }
+
+        if (doris::ExecEnv::GetInstance()->file_cache_factory() != nullptr) {
+            reset_file_cache_factory();
+        }
+    }
+
+protected:
+    evhttp_request* _evhttp_req = nullptr;
+    event_base* _event_base = nullptr;
+    std::unique_ptr<FileCacheAction> _action;
+    std::string _base_path;
+    doris::io::BlockFileCache* _cache = nullptr;
+
+    inline static std::unique_ptr<doris::io::FileCacheFactory> _suite_factory;
+
+    void reset_file_cache_factory() {
+        auto* factory = doris::io::FileCacheFactory::instance();
+        factory->clear_file_caches(true);
+        factory->_caches.clear();
+        factory->_path_to_cache.clear();
+        factory->_capacity = 0;
+        _cache = nullptr;
+    }
+
+    void cache_file_block(const std::string& file_path) {
+        auto hash = doris::io::BlockFileCache::hash(file_path);
+        doris::io::CacheContext context;
+        doris::io::ReadStatistics stats;
+        context.cache_type = doris::io::FileCacheType::NORMAL;
+        context.stats = &stats;
+
+        auto holder = _cache->get_or_set(hash, 0, 4, context);
+        ASSERT_EQ(holder.file_blocks.size(), 1);
+        auto& block = holder.file_blocks.front();
+        ASSERT_EQ(block->get_or_set_downloader(), 
doris::io::FileBlock::get_caller_id());
+        std::string data = "data";
+        ASSERT_TRUE(block->append(Slice(data.data(), data.size())).ok());
+        ASSERT_TRUE(block->finalize().ok());
+        ASSERT_EQ(_cache->_cur_cache_size, 4);
+    }
+};
+
+TEST_F(FileCacheActionTest, clear_defaults_to_async) {
+    cache_file_block("clear_defaults_to_async.dat");
+    HttpRequest req(_evhttp_req);
+    std::string json_metrics;
+
+    req._params["op"] = "clear";
+
+    Status status = _action->_handle_header(&req, &json_metrics);
+
+    EXPECT_TRUE(status.ok());
+    EXPECT_TRUE(json_metrics.empty());
+    EXPECT_EQ(_cache->_cur_cache_size, 0);
+}
+
+TEST_F(FileCacheActionTest, clear_sync_true_runs_async_and_warns) {
+    cache_file_block("clear_sync_true_runs_async_and_warns.dat");
+    HttpRequest req(_evhttp_req);
+    std::string json_metrics;
+
+    req._params["op"] = "clear";
+    req._params["sync"] = "true";
+
+    Status status = _action->_handle_header(&req, &json_metrics);
+
+    EXPECT_TRUE(status.ok());
+    EXPECT_EQ(json_metrics,
+              "{\"status\":\"OK\",\"msg\":\"sync clear_file_cache is no longer 
supported in "
+              "http api, running async clear instead\"}");
+    EXPECT_EQ(_cache->_cur_cache_size, 0);
+}
+
+TEST_F(FileCacheActionTest, clear_value_uses_async_remove) {
+    constexpr std::string_view file_path = "clear_value_uses_async_remove.dat";
+    cache_file_block(std::string(file_path));
+    auto hash = doris::io::BlockFileCache::hash(std::string(file_path));
+    HttpRequest req(_evhttp_req);
+    std::string json_metrics;
+
+    req._params["op"] = "clear";
+    req._params["value"] = std::string(file_path);
+
+    Status status = _action->_handle_header(&req, &json_metrics);
+
+    EXPECT_TRUE(status.ok());
+    EXPECT_TRUE(json_metrics.empty());
+    EXPECT_EQ(_cache->_cur_cache_size, 0);
+    EXPECT_TRUE(_cache->get_blocks_by_key(hash).empty());
+}
+
+} // namespace doris


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to