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

freemandealer pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 118f9e661fb [fix](filecache) Disable sync file cache clear in http api 
(#64321)
118f9e661fb is described below

commit 118f9e661fb6afd63c875e6c407fd9a2e8b71f15
Author: zhengyu <[email protected]>
AuthorDate: Wed Jun 10 10:32:00 2026 +0800

    [fix](filecache) Disable sync file cache clear in http api (#64321)
    
    Problem Summary: The file cache HTTP clear endpoint allowed callers to
    request synchronous clear with sync=true. The synchronous clear path is
    kept for unit tests and internal callers, but it is not safe to expose
    through the HTTP API. This change makes the HTTP op=clear endpoint
    always use async clear. The default behavior remains async, and explicit
    sync=true returns a warning message while still running async clear.
    Segment-specific HTTP clear also uses async remove instead of the
    synchronous remove path.
---
 be/src/service/http/action/file_cache_action.cpp | 14 +++-
 be/test/service/http/file_cache_action_test.cpp  | 86 +++++++++++++++++++++++-
 2 files changed, 95 insertions(+), 5 deletions(-)

diff --git a/be/src/service/http/action/file_cache_action.cpp 
b/be/src/service/http/action/file_cache_action.cpp
index 97f46c219f7..2402f1ad572 100644
--- a/be/src/service/http/action/file_cache_action.cpp
+++ b/be/src/service/http/action/file_cache_action.cpp
@@ -59,6 +59,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);
@@ -85,11 +87,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));
@@ -216,4 +224,4 @@ void FileCacheAction::handle(HttpRequest* req) {
     }
 }
 
-} // namespace doris
\ No newline at end of file
+} // namespace doris
diff --git a/be/test/service/http/file_cache_action_test.cpp 
b/be/test/service/http/file_cache_action_test.cpp
index 4c51cb34453..066d07b25e3 100644
--- a/be/test/service/http/file_cache_action_test.cpp
+++ b/be/test/service/http/file_cache_action_test.cpp
@@ -24,6 +24,7 @@
 #include <chrono>
 #include <filesystem>
 #include <memory>
+#include <string_view>
 #include <thread>
 
 #include "common/config.h"
@@ -32,6 +33,7 @@
 #include "io/cache/file_cache_common.h"
 #include "runtime/exec_env.h"
 #include "service/http/http_request.h"
+#include "util/slice.h"
 
 namespace doris {
 
@@ -65,6 +67,7 @@ public:
         _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);
@@ -72,6 +75,8 @@ public:
         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) {
@@ -82,6 +87,7 @@ public:
         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 {
@@ -94,7 +100,7 @@ public:
         }
 
         if (doris::ExecEnv::GetInstance()->file_cache_factory() != nullptr) {
-            doris::io::FileCacheFactory::instance()->clear_file_caches(true);
+            reset_file_cache_factory();
         }
     }
 
@@ -103,8 +109,35 @@ protected:
     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, list_base_paths) {
@@ -160,4 +193,53 @@ TEST_F(FileCacheActionTest, check_consistency_ok) {
     EXPECT_EQ(json_metrics, "null");
 }
 
-} // namespace doris
\ No newline at end of file
+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