This is an automated email from the ASF dual-hosted git repository.
morrysnow pushed a commit to branch branch-3.1
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-3.1 by this push:
new 9bb9bc08cd6 branch-3.1: [tool](filecache) add debugging facilities for
lru dump #54412 (#58871)
9bb9bc08cd6 is described below
commit 9bb9bc08cd69a28848923bdac79a0f79be36923f
Author: zhengyu <[email protected]>
AuthorDate: Wed Dec 10 12:15:04 2025 +0800
branch-3.1: [tool](filecache) add debugging facilities for lru dump #54412
(#58871)
picked from #54412
Signed-off-by: zhengyu <[email protected]>
Signed-off-by: freemandealer <[email protected]>
---
be/CMakeLists.txt | 3 +
be/src/http/action/file_cache_action.cpp | 3 +
be/src/io/CMakeLists.txt | 25 +++
be/src/io/cache/block_file_cache.cpp | 21 +-
be/src/io/cache/block_file_cache.h | 4 +-
be/src/io/cache/block_file_cache_factory.cpp | 6 +
be/src/io/cache/block_file_cache_factory.h | 5 +
be/src/io/cache/cache_lru_dumper.cpp | 53 ++++-
be/src/io/cache/cache_lru_dumper.h | 17 +-
be/src/io/cache/cached_remote_file_reader.cpp | 7 +
be/src/io/cache/file_cache_lru_tool.cpp | 233 +++++++++++++++++++++
build.sh | 6 +
.../suites/demo_p0/test_lru_persist.groovy | 37 +++-
13 files changed, 403 insertions(+), 17 deletions(-)
diff --git a/be/CMakeLists.txt b/be/CMakeLists.txt
index de46bcfeb8b..0c06094d227 100644
--- a/be/CMakeLists.txt
+++ b/be/CMakeLists.txt
@@ -142,6 +142,9 @@ option(WITH_MYSQL "Support access MySQL" ON)
option(BUILD_FS_BENCHMARK "ON for building fs benchmark tool or OFF for not"
OFF)
message(STATUS "build fs benchmark tool: ${BUILD_FS_BENCHMARK}")
+option(BUILD_FILE_CACHE_LRU_TOOL "ON for building file cache lru tool or OFF
for not" OFF)
+message(STATUS "build file cache lru tool: ${BUILD_FILE_CACHE_LRU_TOOL}")
+
set(CMAKE_SKIP_RPATH TRUE)
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_STATIC_RUNTIME ON)
diff --git a/be/src/http/action/file_cache_action.cpp
b/be/src/http/action/file_cache_action.cpp
index 4b9310435a2..882dc895480 100644
--- a/be/src/http/action/file_cache_action.cpp
+++ b/be/src/http/action/file_cache_action.cpp
@@ -54,6 +54,7 @@ constexpr static std::string_view CAPACITY = "capacity";
constexpr static std::string_view RELEASE = "release";
constexpr static std::string_view BASE_PATH = "base_path";
constexpr static std::string_view RELEASED_ELEMENTS = "released_elements";
+constexpr static std::string_view DUMP = "dump";
constexpr static std::string_view VALUE = "value";
Status FileCacheAction::_handle_header(HttpRequest* req, std::string*
json_metrics) {
@@ -132,6 +133,8 @@ Status FileCacheAction::_handle_header(HttpRequest* req,
std::string* json_metri
*json_metrics = json.ToString();
}
}
+ } else if (operation == DUMP) {
+ io::FileCacheFactory::instance()->dump_all_caches();
} else {
st = Status::InternalError("invalid operation: {}", operation);
}
diff --git a/be/src/io/CMakeLists.txt b/be/src/io/CMakeLists.txt
index dbd52e3560d..b71ff8ad0f3 100644
--- a/be/src/io/CMakeLists.txt
+++ b/be/src/io/CMakeLists.txt
@@ -63,3 +63,28 @@ if (${BUILD_FS_BENCHMARK} STREQUAL "ON")
)
endif()
+
+if (${BUILD_FILE_CACHE_LRU_TOOL} STREQUAL "ON")
+ add_executable(file_cache_lru_tool
+ cache/file_cache_lru_tool.cpp
+ )
+
+ pch_reuse(file_cache_lru_tool)
+
+ # This permits libraries loaded by dlopen to link to the symbols in the
program.
+ set_target_properties(file_cache_lru_tool PROPERTIES ENABLE_EXPORTS 1)
+
+ target_link_libraries(file_cache_lru_tool
+ ${DORIS_LINK_LIBS}
+ )
+
+ install(DIRECTORY DESTINATION ${OUTPUT_DIR}/lib/)
+ install(TARGETS file_cache_lru_tool DESTINATION ${OUTPUT_DIR}/lib/)
+
+ add_custom_command(TARGET file_cache_lru_tool POST_BUILD
+ COMMAND ${CMAKE_OBJCOPY} --only-keep-debug
$<TARGET_FILE:file_cache_lru_tool> $<TARGET_FILE:file_cache_lru_tool>.dbg
+ COMMAND ${CMAKE_STRIP} --strip-debug --strip-unneeded
$<TARGET_FILE:file_cache_lru_tool>
+ COMMAND ${CMAKE_OBJCOPY}
--add-gnu-debuglink=$<TARGET_FILE:file_cache_lru_tool>.dbg
$<TARGET_FILE:file_cache_lru_tool>
+ )
+
+endif()
diff --git a/be/src/io/cache/block_file_cache.cpp
b/be/src/io/cache/block_file_cache.cpp
index 6b2741368c4..9e1c275060a 100644
--- a/be/src/io/cache/block_file_cache.cpp
+++ b/be/src/io/cache/block_file_cache.cpp
@@ -2379,6 +2379,18 @@ void BlockFileCache::run_background_lru_log_replay() {
}
}
+void BlockFileCache::dump_lru_queues(bool force) {
+ std::unique_lock dump_lock(_dump_lru_queues_mtx);
+ if (config::file_cache_background_lru_dump_tail_record_num > 0 &&
+ !ExecEnv::GetInstance()->get_is_upgrading()) {
+ _lru_dumper->dump_queue("disposable", force);
+ _lru_dumper->dump_queue("normal", force);
+ _lru_dumper->dump_queue("index", force);
+ _lru_dumper->dump_queue("ttl", force);
+ _lru_dumper->set_first_dump_done();
+ }
+}
+
void BlockFileCache::run_background_lru_dump() {
Thread::set_self_name("run_background_lru_dump");
while (!_close) {
@@ -2390,14 +2402,7 @@ void BlockFileCache::run_background_lru_dump() {
break;
}
}
-
- if (config::file_cache_background_lru_dump_tail_record_num > 0 &&
- !ExecEnv::GetInstance()->get_is_upgrading()) {
- _lru_dumper->dump_queue("disposable");
- _lru_dumper->dump_queue("normal");
- _lru_dumper->dump_queue("index");
- _lru_dumper->dump_queue("ttl");
- }
+ dump_lru_queues(false);
}
}
diff --git a/be/src/io/cache/block_file_cache.h
b/be/src/io/cache/block_file_cache.h
index b200ec84f48..512de17b52e 100644
--- a/be/src/io/cache/block_file_cache.h
+++ b/be/src/io/cache/block_file_cache.h
@@ -207,6 +207,8 @@ public:
std::string dump_structure(const UInt128Wrapper& hash);
std::string dump_single_cache_type(const UInt128Wrapper& hash, size_t
offset);
+ void dump_lru_queues(bool force);
+
[[nodiscard]] size_t get_used_cache_size(FileCacheType type) const;
[[nodiscard]] size_t get_file_blocks_num(FileCacheType type) const;
@@ -565,7 +567,7 @@ private:
// so join this async load thread first
std::unique_ptr<FileCacheStorage> _storage;
std::shared_ptr<bvar::LatencyRecorder> _lru_dump_latency_us;
-
+ std::mutex _dump_lru_queues_mtx;
moodycamel::ConcurrentQueue<FileBlockSPtr> _need_update_lru_blocks;
};
diff --git a/be/src/io/cache/block_file_cache_factory.cpp
b/be/src/io/cache/block_file_cache_factory.cpp
index 2d7f4eb49fd..a83a81749e2 100644
--- a/be/src/io/cache/block_file_cache_factory.cpp
+++ b/be/src/io/cache/block_file_cache_factory.cpp
@@ -220,6 +220,12 @@ std::string FileCacheFactory::clear_file_caches(bool sync)
{
return ss.str();
}
+void FileCacheFactory::dump_all_caches() {
+ for (const auto& cache : _caches) {
+ cache->dump_lru_queues(true);
+ }
+}
+
std::vector<std::string> FileCacheFactory::get_base_paths() {
std::vector<std::string> paths;
for (const auto& pair : _path_to_cache) {
diff --git a/be/src/io/cache/block_file_cache_factory.h
b/be/src/io/cache/block_file_cache_factory.h
index 30d69dc15ca..837feac7f68 100644
--- a/be/src/io/cache/block_file_cache_factory.h
+++ b/be/src/io/cache/block_file_cache_factory.h
@@ -84,6 +84,11 @@ public:
*/
std::string clear_file_caches(bool sync);
+ /**
+ * dump lru queue info for all file cache instances
+ */
+ void dump_all_caches();
+
std::vector<std::string> get_base_paths();
/**
diff --git a/be/src/io/cache/cache_lru_dumper.cpp
b/be/src/io/cache/cache_lru_dumper.cpp
index cb8e6a2059d..0c0375883da 100644
--- a/be/src/io/cache/cache_lru_dumper.cpp
+++ b/be/src/io/cache/cache_lru_dumper.cpp
@@ -230,10 +230,55 @@ Status CacheLRUDumper::finalize_dump(std::ofstream& out,
size_t entry_num,
out.close();
+ if (_is_first_dump) [[unlikely]] {
+ // we back up two dumps (one for last before be restart, one for first
after be restart)
+ // for later debug the restore process
+ try {
+ if (std::filesystem::exists(final_filename)) {
+ std::string backup_filename = final_filename + "_" +
_start_time + "_last";
+ std::rename(final_filename.c_str(), backup_filename.c_str());
+ }
+ std::string timestamped_filename = final_filename + "_" +
_start_time;
+ std::filesystem::copy_file(tmp_filename, timestamped_filename);
+
+ std::filesystem::path dir =
std::filesystem::path(final_filename).parent_path();
+ std::string prefix =
std::filesystem::path(final_filename).filename().string();
+ uint64_t total_size = 0;
+ std::vector<std::pair<std::filesystem::path,
std::filesystem::file_time_type>> files;
+ for (const auto& entry : std::filesystem::directory_iterator(dir))
{
+ if (entry.path().filename().string().find(prefix) == 0) {
+ total_size += entry.file_size();
+ files.emplace_back(entry.path(), entry.last_write_time());
+ }
+ }
+ if (total_size > 5ULL * 1024 * 1024 * 1024) {
+ // delete oldest two files
+ std::sort(files.begin(), files.end(),
+ [](const auto& a, const auto& b) { return a.second <
b.second; });
+ if (!files.empty()) {
+ auto remove_file = [](const std::filesystem::path&
file_path) {
+ std::error_code ec;
+ bool removed = std::filesystem::remove(file_path, ec);
+ LOG(INFO) << "Remove " << (removed ? "succeeded" :
"failed")
+ << " for file: " << file_path
+ << (ec ? ", error: " + ec.message() : "");
+ return removed;
+ };
+
+ remove_file(files[0].first);
+ if (files.size() > 1) {
+ remove_file(files[1].first);
+ }
+ }
+ }
+ } catch (const std::filesystem::filesystem_error& e) {
+ LOG(WARNING) << "failed to handle first dump case: " << e.what();
+ }
+ }
+
// Rename tmp to formal file
try {
std::rename(tmp_filename.c_str(), final_filename.c_str());
- std::remove(tmp_filename.c_str());
file_size = std::filesystem::file_size(final_filename);
} catch (const std::filesystem::filesystem_error& e) {
LOG(WARNING) << "failed to rename " << tmp_filename << " to " <<
final_filename
@@ -247,10 +292,10 @@ Status CacheLRUDumper::finalize_dump(std::ofstream& out,
size_t entry_num,
return Status::OK();
}
-void CacheLRUDumper::dump_queue(const std::string& queue_name) {
+void CacheLRUDumper::dump_queue(const std::string& queue_name, bool force) {
FileCacheType type = string_to_cache_type(queue_name);
- if (_recorder->get_lru_queue_update_cnt_from_last_dump(type) >
- config::file_cache_background_lru_dump_update_cnt_threshold) {
+ if (force || _recorder->get_lru_queue_update_cnt_from_last_dump(type) >
+
config::file_cache_background_lru_dump_update_cnt_threshold) {
LRUQueue& queue = _recorder->get_shadow_queue(type);
do_dump_queue(queue, queue_name);
_recorder->reset_lru_queue_update_cnt_from_last_dump(type);
diff --git a/be/src/io/cache/cache_lru_dumper.h
b/be/src/io/cache/cache_lru_dumper.h
index 801ed577de2..d9addff614c 100644
--- a/be/src/io/cache/cache_lru_dumper.h
+++ b/be/src/io/cache/cache_lru_dumper.h
@@ -17,8 +17,10 @@
#pragma once
+#include <chrono>
#include <cstdint>
#include <cstring>
+#include <ctime>
#include <filesystem>
#include <fstream>
#include <iostream>
@@ -38,11 +40,19 @@ class LRUQueueRecorder;
class CacheLRUDumper {
public:
CacheLRUDumper(BlockFileCache* mgr, LRUQueueRecorder* recorder)
- : _mgr(mgr), _recorder(recorder) {};
- void dump_queue(const std::string& queue_name);
+ : _mgr(mgr), _recorder(recorder) {
+ auto now = std::chrono::system_clock::now();
+ auto in_time_t = std::chrono::system_clock::to_time_t(now);
+ std::stringstream ss;
+ ss << std::put_time(std::localtime(&in_time_t), "%Y%m%d%H%M%S");
+ _start_time = ss.str();
+ };
+
+ void dump_queue(const std::string& queue_name, bool force);
void restore_queue(LRUQueue& queue, const std::string& queue_name,
std::lock_guard<std::mutex>& cache_lock);
void remove_lru_dump_files();
+ void set_first_dump_done() { _is_first_dump = false; }
private:
void do_dump_queue(LRUQueue& queue, const std::string& queue_name);
@@ -79,5 +89,8 @@ private:
BlockFileCache* _mgr;
LRUQueueRecorder* _recorder;
+
+ std::string _start_time;
+ bool _is_first_dump = true;
};
} // namespace doris::io
\ No newline at end of file
diff --git a/be/src/io/cache/cached_remote_file_reader.cpp
b/be/src/io/cache/cached_remote_file_reader.cpp
index 9bde202a3d6..37fefe3d79a 100644
--- a/be/src/io/cache/cached_remote_file_reader.cpp
+++ b/be/src/io/cache/cached_remote_file_reader.cpp
@@ -389,6 +389,9 @@ Status CachedRemoteFileReader::read_at_impl(size_t offset,
Slice result, size_t*
for (auto& block : holder.file_blocks) {
switch (block->state()) {
case FileBlock::State::EMPTY:
+ VLOG_DEBUG << fmt::format("Block EMPTY path={} hash={}:{}:{}
offset={} cache_path={}",
+ path().native(),
_cache_hash.to_string(), _cache_hash.high(),
+ _cache_hash.low(), block->offset(),
block->get_cache_file());
block->get_or_set_downloader();
if (block->is_downloader()) {
empty_blocks.push_back(block);
@@ -397,6 +400,10 @@ Status CachedRemoteFileReader::read_at_impl(size_t offset,
Slice result, size_t*
stats.hit_cache = false;
break;
case FileBlock::State::SKIP_CACHE:
+ VLOG_DEBUG << fmt::format(
+ "Block SKIP_CACHE path={} hash={}:{}:{} offset={}
cache_path={}",
+ path().native(), _cache_hash.to_string(),
_cache_hash.high(), _cache_hash.low(),
+ block->offset(), block->get_cache_file());
empty_blocks.push_back(block);
stats.hit_cache = false;
stats.skip_cache = true;
diff --git a/be/src/io/cache/file_cache_lru_tool.cpp
b/be/src/io/cache/file_cache_lru_tool.cpp
new file mode 100644
index 00000000000..a6e133c7a56
--- /dev/null
+++ b/be/src/io/cache/file_cache_lru_tool.cpp
@@ -0,0 +1,233 @@
+// 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 <gflags/gflags.h>
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+
+#include "common/status.h"
+#include "gen_cpp/file_cache.pb.h"
+#include "io/cache/cache_lru_dumper.h"
+#include "io/cache/file_cache_common.h"
+#include "io/cache/lru_queue_recorder.h"
+#include "util/coding.h"
+#include "util/crc32c.h"
+
+using namespace doris;
+
+DEFINE_string(filename, "", "dump file name");
+
+std::string get_usage(const std::string& progname) {
+ std::stringstream ss;
+ ss << progname << " is the Doris BE file cache lru tool for examing dumped
content.\n";
+
+ ss << "Usage:\n";
+ ss << progname << " --filename [filename]\n";
+ ss << "\nExample:\n";
+ ss << progname << " --filename ./lru_dump_ttl.tail\n";
+ return ss.str();
+}
+
+Status check_ifstream_status(std::ifstream& in, std::string& filename) {
+ if (!in.good()) {
+ std::ios::iostate state = in.rdstate();
+ std::stringstream err_msg;
+ if (state & std::ios::eofbit) {
+ err_msg << "End of file reached.";
+ }
+ if (state & std::ios::failbit) {
+ err_msg << "Input/output operation failed, err_code: " <<
strerror(errno);
+ }
+ if (state & std::ios::badbit) {
+ err_msg << "Serious I/O error occurred, err_code: " <<
strerror(errno);
+ }
+ in.close();
+ std::string warn_msg = std::string(
+ fmt::format("dump lru reading failed, file={}, {}", filename,
err_msg.str()));
+ std::cerr << warn_msg << std::endl;
+ return Status::InternalError<false>(warn_msg);
+ }
+
+ return Status::OK();
+}
+
+struct Footer {
+ size_t meta_offset;
+ uint32_t checksum;
+ uint8_t version;
+ char magic[3];
+
+ std::string serialize_as_string() const;
+ bool deserialize_from_string(const std::string& data) {
+ DCHECK(data.size() == sizeof(Footer));
+
+ const char* ptr = data.data();
+
+ // Deserialize meta_offset (convert from little-endian)
+ uint64_t meta_offset_le;
+ std::memcpy(&meta_offset_le, ptr, sizeof(meta_offset_le));
+ meta_offset =
decode_fixed64_le(reinterpret_cast<uint8_t*>(&meta_offset_le));
+ ptr += sizeof(meta_offset_le);
+
+ // Deserialize checksum (convert from little-endian)
+ uint32_t checksum_le;
+ std::memcpy(&checksum_le, ptr, sizeof(checksum_le));
+ checksum = decode_fixed32_le(reinterpret_cast<uint8_t*>(&checksum_le));
+ ptr += sizeof(checksum_le);
+
+ version = *((uint8_t*)ptr);
+ ptr += sizeof(version);
+
+ // Deserialize magic
+ std::memcpy(magic, ptr, sizeof(magic));
+
+ return true;
+ }
+} __attribute__((packed));
+
+Status parse_dump_footer(std::ifstream& in, std::string& filename, size_t&
entry_num,
+ doris::io::cache::LRUDumpMetaPb& parse_meta,
+ doris::io::cache::LRUDumpEntryGroupPb&
current_parse_group) {
+ size_t file_size = std::filesystem::file_size(filename);
+
+ // Read footer
+ Footer footer;
+ size_t footer_size = sizeof(footer);
+ if (file_size < footer_size) {
+ std::string warn_msg = std::string(fmt::format(
+ "LRU dump file too small to contain footer, file={}, skip
restore", filename));
+ std::cerr << warn_msg << std::endl;
+ return Status::InternalError<false>(warn_msg);
+ }
+
+ in.seekg(-footer_size, std::ios::end);
+ std::string footer_str(footer_size, '\0');
+ in.read(&footer_str[0], footer_size);
+ RETURN_IF_ERROR(check_ifstream_status(in, filename));
+
+ if (!footer.deserialize_from_string(footer_str)) {
+ std::string warn_msg = std::string(
+ fmt::format("Failed to deserialize footer, file={}, skip
restore", filename));
+ std::cerr << warn_msg << std::endl;
+ return Status::InternalError<false>(warn_msg);
+ }
+
+ // Validate footer
+ if (footer.version != 1 || std::string(footer.magic, 3) != "DOR") {
+ std::string warn_msg = std::string(fmt::format(
+ "LRU dump file invalid footer format, file={}, skip restore",
filename));
+ std::cerr << warn_msg << std::endl;
+ return Status::InternalError<false>(warn_msg);
+ }
+
+ // Read meta
+ in.seekg(footer.meta_offset, std::ios::beg);
+ size_t meta_size = file_size - footer.meta_offset - footer_size;
+ if (meta_size <= 0) {
+ std::string warn_msg = std::string(
+ fmt::format("LRU dump file invalid meta size, file={}, skip
restore", filename));
+ std::cerr << warn_msg << std::endl;
+ return Status::InternalError<false>(warn_msg);
+ }
+ std::string meta_serialized(meta_size, '\0');
+ in.read(&meta_serialized[0], meta_serialized.size());
+ RETURN_IF_ERROR(check_ifstream_status(in, filename));
+ parse_meta.Clear();
+ current_parse_group.Clear();
+ if (!parse_meta.ParseFromString(meta_serialized)) {
+ std::string warn_msg = std::string(
+ fmt::format("LRU dump file meta parse failed, file={}, skip
restore", filename));
+ std::cerr << warn_msg << std::endl;
+ return Status::InternalError<false>(warn_msg);
+ }
+ std::cout << "parse meta: " << parse_meta.DebugString() << std::endl;
+
+ entry_num = parse_meta.entry_num();
+ return Status::OK();
+}
+
+Status parse_one_lru_entry(std::ifstream& in, std::string& filename,
io::UInt128Wrapper& hash,
+ size_t& offset, size_t& size,
+ doris::io::cache::LRUDumpMetaPb& parse_meta,
+ doris::io::cache::LRUDumpEntryGroupPb&
current_parse_group) {
+ // Read next group if current is empty
+ if (current_parse_group.entries_size() == 0) {
+ if (parse_meta.group_offset_size_size() == 0) {
+ return Status::EndOfFile("No more entries");
+ }
+
+ auto group_info = parse_meta.group_offset_size(0);
+ in.seekg(group_info.offset(), std::ios::beg);
+ std::string group_serialized(group_info.size(), '\0');
+ in.read(&group_serialized[0], group_serialized.size());
+ RETURN_IF_ERROR(check_ifstream_status(in, filename));
+ uint32_t checksum = crc32c::Value(group_serialized.data(),
group_serialized.size());
+ if (checksum != group_info.checksum()) {
+ std::string warn_msg =
+ fmt::format("restore lru failed as checksum not match,
file={}", filename);
+ std::cerr << warn_msg << std::endl;
+ return Status::InternalError(warn_msg);
+ }
+ if (!current_parse_group.ParseFromString(group_serialized)) {
+ std::string warn_msg =
+ fmt::format("restore lru failed to parse group, file={}",
filename);
+ std::cerr << warn_msg << std::endl;
+ return Status::InternalError(warn_msg);
+ }
+
+ // Remove processed group info
+
parse_meta.mutable_group_offset_size()->erase(parse_meta.group_offset_size().begin());
+ }
+
+ // Get next entry from current group
+ std::cout << "After deserialization: " <<
current_parse_group.DebugString() << std::endl;
+ auto entry = current_parse_group.entries(0);
+ hash = io::UInt128Wrapper((static_cast<uint128_t>(entry.hash().high()) <<
64) |
+ entry.hash().low());
+ offset = entry.offset();
+ size = entry.size();
+
+ std::cout << hash.to_string() << " " << offset << " " << size << std::endl;
+
+ // Remove processed entry
+
current_parse_group.mutable_entries()->erase(current_parse_group.entries().begin());
+ return Status::OK();
+}
+
+int main(int argc, char** argv) {
+ std::string usage = get_usage(argv[0]);
+ gflags::SetUsageMessage(usage);
+ google::ParseCommandLineFlags(&argc, &argv, true);
+
+ std::ifstream in(FLAGS_filename, std::ios::binary);
+ size_t entry_num;
+ doris::io::cache::LRUDumpMetaPb parse_meta;
+ doris::io::cache::LRUDumpEntryGroupPb current_parse_group;
+ auto s = parse_dump_footer(in, FLAGS_filename, entry_num, parse_meta,
current_parse_group);
+
+ in.seekg(0, std::ios::beg);
+ io::UInt128Wrapper hash;
+ size_t offset, size;
+ for (int i = 0; i < entry_num; ++i) {
+ EXIT_IF_ERROR(parse_one_lru_entry(in, FLAGS_filename, hash, offset,
size, parse_meta,
+ current_parse_group));
+ }
+
+ return 0;
+}
diff --git a/build.sh b/build.sh
index 543e03c2de3..fa80905d1ba 100755
--- a/build.sh
+++ b/build.sh
@@ -604,10 +604,15 @@ if [[ "${BUILD_BE}" -eq 1 ]]; then
BUILD_FS_BENCHMARK=OFF
fi
+ if [[ -z "${BUILD_FILE_CACHE_LRU_TOOL}" ]]; then
+ BUILD_FILE_CACHE_LRU_TOOL=OFF
+ fi
+
echo "-- Make program: ${MAKE_PROGRAM}"
echo "-- Use ccache: ${CMAKE_USE_CCACHE}"
echo "-- Extra cxx flags: ${EXTRA_CXX_FLAGS:-}"
echo "-- Build fs benchmark tool: ${BUILD_FS_BENCHMARK}"
+ echo "-- Build file cache lru tool: ${BUILD_FILE_CACHE_LRU_TOOL}"
mkdir -p "${CMAKE_BUILD_DIR}"
cd "${CMAKE_BUILD_DIR}"
@@ -619,6 +624,7 @@ if [[ "${BUILD_BE}" -eq 1 ]]; then
-DENABLE_CACHE_LOCK_DEBUG="${ENABLE_CACHE_LOCK_DEBUG}" \
-DMAKE_TEST=OFF \
-DBUILD_FS_BENCHMARK="${BUILD_FS_BENCHMARK}" \
+ -DBUILD_FILE_CACHE_LRU_TOOL="${BUILD_FILE_CACHE_LRU_TOOL}" \
${CMAKE_USE_CCACHE:+${CMAKE_USE_CCACHE}} \
-DWITH_MYSQL="${WITH_MYSQL}" \
-DUSE_LIBCPP="${USE_LIBCPP}" \
diff --git a/regression-test/suites/demo_p0/test_lru_persist.groovy
b/regression-test/suites/demo_p0/test_lru_persist.groovy
index 249faadeeda..d039c74c5c5 100644
--- a/regression-test/suites/demo_p0/test_lru_persist.groovy
+++ b/regression-test/suites/demo_p0/test_lru_persist.groovy
@@ -46,7 +46,6 @@ import org.apache.doris.regression.suite.ClusterOptions
suite('test_lru_persist', 'docker') {
def options = new ClusterOptions()
-
options.feNum = 1
options.beNum = 1
options.msNum = 1
@@ -90,5 +89,39 @@ suite('test_lru_persist', 'docker') {
logger.info("normalAfter: ${normalAfter}")
assert normalBefore == normalAfter
+
+ // remove dump file
+ def rm_dump_ret = "rm -rf
${cachePath}/lru_dump_normal.tail".execute().text.trim()
+ cluster.startBackends(1)
+ sleep(5000)
+ def show_backend_ret = sql '''show backends'''
+ try {
+ logger.info("Backend details: ${show_backend_ret.toString()}")
+ if(show_backend_ret.size() > 0 && show_backend_ret[0].size() > 0) {
+ logger.info("alive: ${show_backend_ret[0][9].toString()}")
+ }
+ assert show_backend_ret[0][9].toString() == "true"
+ } catch(Exception e) {
+ logger.error("Failed to log backend info: ${e.message}")
+ }
+
+ sql '''select count(*) from tb1'''
+
+ sleep(10000)
+ cluster.stopBackends(1)
+
+ def rm_data_ret = new File(cachePath).eachFile { file ->
+ if (!file.name.startsWith("lru_") && file.name != "version" &&
file.name != "." && file.name != "..") {
+ if (file.isDirectory()) {
+ file.deleteDir()
+ } else {
+ file.delete()
+ }
+ }
+ }
+ cluster.startBackends(1)
+ sleep(5000)
+
+ sql '''select count(*) from tb1'''
}
-}
+}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]