You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by yi...@apache.org on 2026/05/06 11:47:22 UTC

(doris) branch master updated: [fix](tool) Fix meta_tool coredump and dead loop issues (#61509)

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

yiguolei 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 35c6887064f [fix](tool) Fix meta_tool coredump and dead loop issues (#61509)
35c6887064f is described below

commit 35c6887064fc855ba5f03c68dcdd0cb730dca005
Author: Wen Zhenghu <we...@gmail.com>
AuthorDate: Wed May 6 19:47:13 2026 +0800

    [fix](tool) Fix meta_tool coredump and dead loop issues (#61509)
    
    ### What problem does this PR solve?
    
    related issue:https://github.com/apache/doris/issues/61447
    
    ## Proposed changes
    
    This PR fixes several bugs in the offline tool `meta_tool`, including
    coredumps caused by uninitialized ExecEnv components and a dead loop
    when loading tablet meta.
    
    1. **Fix coredump in offline commands**:
    - For lightweight commands (`show_meta`, `batch_delete_meta`,
    `show_segment_footer`, `show_segment_data`): These do not require a full
    StorageEngine environment but still rely on basic components like
    `TabletSchemaCache`, `TabletColumnObjectPool`, and `MemTracker`. This PR
    introduces a lightweight initialization function
    `init_common_components()` for them to prevent coredumps caused by null
    pointer dereferences.
    - For engine-level commands (`get_meta`, `load_meta`, `delete_meta`):
    These commands initialize a `StorageEngine` and `DataDir` instance to
    read/write RocksDB. The PR ensures that they correctly load
    configurations from `be.conf` (via `DORIS_HOME`) and also call
    `init_common_components()` to guarantee that both the global settings
    (e.g., memory limits, thread pools) and the ExecEnv components are
    properly set up before the engine starts.
    
    2. **Fix dead loop in `load_meta`**:
    The `TabletMetaManager::load_json_meta` function previously used
    `infile.getline()` in a `while(!infile.eof())` loop. If the file cannot
    be opened or an error occurs, the `failbit` is set but not the `eofbit`,
    causing an infinite loop. This has been fixed by reading the file
    content safely using `std::istreambuf_iterator` and adding an
    `is_open()` check.
    
    
    ### Check List (For Author)
    
    - Test <!-- At least one of them must be included. -->
        - [ ] Regression test
        - [ ] Unit Test
        - [x] Manual test (add detailed scripts or steps below)
        - [ ] No need to test or manual test. Explain why:
    - [ ] This is a refactor/code format and no logic has been changed.
            - [ ] Previous test can cover this change.
            - [ ] No code files have been changed.
            - [ ] Other reason <!-- Add your reason?  -->
    
    - Behavior changed:
        - [x] No.
        - [ ] Yes. <!-- Explain the behavior change -->
    
    - Does this need documentation?
        - [x] No.
    - [ ] Yes. <!-- Add document PR link here. eg:
    https://github.com/apache/doris-website/pull/1214 -->
    
    ### Check List (For Reviewer who merge this PR)
    
    - [ ] Confirm the release note
    - [ ] Confirm test cases
    - [ ] Confirm document
    - [ ] Add branch pick label <!-- Add branch pick label that this PR
    should merge into -->
---
 be/src/runtime/exec_env.h                          | 14 +++--
 be/src/storage/tablet/tablet_meta_manager.cpp      | 10 ++--
 be/src/tools/meta_tool.cpp                         | 69 ++++++++++++++++++++--
 .../storage/tablet/tablet_meta_manager_test.cpp    |  6 ++
 4 files changed, 83 insertions(+), 16 deletions(-)

diff --git a/be/src/runtime/exec_env.h b/be/src/runtime/exec_env.h
index 0daba28e494..d915fbc5721 100644
--- a/be/src/runtime/exec_env.h
+++ b/be/src/runtime/exec_env.h
@@ -331,13 +331,8 @@ public:
             segment_v2::InvertedIndexQueryCache* inverted_index_query_cache) {
         _inverted_index_query_cache = inverted_index_query_cache;
     }
-    void set_cache_manager(CacheManager* cm) { this->_cache_manager = cm; }
     void set_process_profile(ProcessProfile* pp) { this->_process_profile = pp; }
-    void set_tablet_schema_cache(TabletSchemaCache* c) { this->_tablet_schema_cache = c; }
     void set_delete_bitmap_agg_cache(DeleteBitmapAggCache* c) { _delete_bitmap_agg_cache = c; }
-    void set_tablet_column_object_pool(TabletColumnObjectPool* c) {
-        this->_tablet_column_object_pool = c;
-    }
     void set_storage_page_cache(StoragePageCache* c) { this->_storage_page_cache = c; }
     void set_ann_index_ivf_list_cache(AnnIndexIVFListCache* c) {
         this->_ann_index_ivf_list_cache = c;
@@ -365,6 +360,15 @@ public:
         _file_cache_open_fd_cache = std::move(fd_cache);
     }
 #endif
+    // WARN: The following setter methods are intended for use in test code and
+    // offline tools (like meta_tool) ONLY. They should NOT be called in the
+    // production environment to avoid thread safety issues and undefined behaviors.
+    void set_cache_manager(CacheManager* cm) { this->_cache_manager = cm; }
+    void set_tablet_schema_cache(TabletSchemaCache* c) { this->_tablet_schema_cache = c; }
+    void set_tablet_column_object_pool(TabletColumnObjectPool* c) {
+        this->_tablet_column_object_pool = c;
+    }
+
     LoadStreamMapPool* load_stream_map_pool() { return _load_stream_map_pool.get(); }
 
     DeltaWriterV2Pool* delta_writer_v2_pool() { return _delta_writer_v2_pool.get(); }
diff --git a/be/src/storage/tablet/tablet_meta_manager.cpp b/be/src/storage/tablet/tablet_meta_manager.cpp
index 8de25fa645f..e6d10c28665 100644
--- a/be/src/storage/tablet/tablet_meta_manager.cpp
+++ b/be/src/storage/tablet/tablet_meta_manager.cpp
@@ -147,12 +147,12 @@ Status TabletMetaManager::traverse_headers(
 
 Status TabletMetaManager::load_json_meta(DataDir* store, const std::string& meta_path) {
     std::ifstream infile(meta_path);
-    char buffer[102400];
-    std::string json_meta;
-    while (!infile.eof()) {
-        infile.getline(buffer, 102400);
-        json_meta = json_meta + buffer;
+    if (!infile.is_open()) {
+        return Status::InternalError("Failed to open file {}", meta_path);
     }
+
+    std::string json_meta((std::istreambuf_iterator<char>(infile)),
+                          std::istreambuf_iterator<char>());
     boost::algorithm::trim(json_meta);
     TabletMetaPB tablet_meta_pb;
     std::string error;
diff --git a/be/src/tools/meta_tool.cpp b/be/src/tools/meta_tool.cpp
index c4f7595678c..6f3a21688d1 100644
--- a/be/src/tools/meta_tool.cpp
+++ b/be/src/tools/meta_tool.cpp
@@ -30,6 +30,7 @@
 #include <sstream>
 #include <string>
 
+#include "common/logging.h"
 #include "common/status.h"
 #include "core/assert_cast.h"
 #include "core/column/column.h"
@@ -46,6 +47,7 @@
 #include "io/fs/local_file_system.h"
 #include "json2pb/pb_to_json.h"
 #include "runtime/exec_env.h"
+#include "runtime/memory/cache_manager.h"
 #include "runtime/memory/mem_tracker_limiter.h"
 #include "storage/data_dir.h"
 #include "storage/olap_common.h"
@@ -54,9 +56,11 @@
 #include "storage/segment/encoding_info.h"
 #include "storage/segment/page_pointer.h"
 #include "storage/storage_engine.h"
+#include "storage/tablet/tablet_column_object_pool.h"
 #include "storage/tablet/tablet_meta.h"
 #include "storage/tablet/tablet_meta_manager.h"
 #include "storage/tablet/tablet_schema.h"
+#include "storage/tablet/tablet_schema_cache.h"
 #include "storage/types.h"
 #include "util/coding.h"
 
@@ -101,7 +105,7 @@ std::string get_usage(const std::string& progname) {
     ss << "./meta_tool --operation=delete_meta "
           "--root_path=/path/to/storage/path --tablet_id=tabletid "
           "--schema_hash=schemahash\n";
-    ss << "./meta_tool --operation=delete_meta --tablet_file=file_path\n";
+    ss << "./meta_tool --operation=batch_delete_meta --tablet_file=file_path\n";
     ss << "./meta_tool --operation=show_meta --pb_meta_path=path\n";
     ss << "./meta_tool --operation=show_segment_footer --file=/path/to/segment/file\n";
     ss << "./meta_tool --operation=show_segment_data --file=/path/to/segment/file\n";
@@ -132,9 +136,13 @@ void get_meta(DataDir* data_dir) {
     std::string value;
     Status s =
             TabletMetaManager::get_json_meta(data_dir, FLAGS_tablet_id, FLAGS_schema_hash, &value);
-    if (s.is<doris::ErrorCode::META_KEY_NOT_FOUND>()) {
-        std::cout << "no tablet meta for tablet_id:" << FLAGS_tablet_id
-                  << ", schema_hash:" << FLAGS_schema_hash << std::endl;
+    if (!s.ok()) {
+        if (s.is<doris::ErrorCode::META_KEY_NOT_FOUND>()) {
+            std::cout << "no tablet meta for tablet_id:" << FLAGS_tablet_id
+                      << ", schema_hash:" << FLAGS_schema_hash << std::endl;
+        } else {
+            std::cout << "get meta failed: " << s.to_string() << std::endl;
+        }
         return;
     }
     std::cout << value << std::endl;
@@ -177,8 +185,8 @@ Status init_data_dir(StorageEngine& engine, const std::string& dir, std::unique_
     }
     res = p->init();
     if (!res.ok()) {
-        std::cout << "data_dir load failed" << std::endl;
-        return Status::InternalError("data_dir load failed");
+        std::cout << "data_dir load failed: " << res.to_string() << std::endl;
+        return res;
     }
 
     p.swap(*ret);
@@ -908,6 +916,32 @@ void show_segment_data(const std::string& file_name) {
     }
 }
 
+void init_common_components() {
+    // init meta_tool.log to current dir
+    if (doris::config::sys_log_dir == "") {
+        doris::config::sys_log_dir = ".";
+    }
+    if (doris::config::sys_log_level == "") {
+        doris::config::sys_log_level = "INFO";
+    }
+    if (doris::config::sys_log_roll_mode == "") {
+        doris::config::sys_log_roll_mode = "SIZE-MB-1024";
+    }
+    FLAGS_log_dir = doris::config::sys_log_dir;
+    if (!doris::init_glog("meta_tool")) {
+        fprintf(stderr, "init glog failed.\n");
+    }
+
+    doris::ExecEnv::GetInstance()->init_mem_tracker();
+    doris::ExecEnv::GetInstance()->set_cache_manager(doris::CacheManager::create_global_instance());
+    doris::ExecEnv::GetInstance()->set_tablet_schema_cache(
+            doris::TabletSchemaCache::create_global_schema_cache(
+                    doris::config::tablet_schema_cache_capacity));
+    doris::ExecEnv::GetInstance()->set_tablet_column_object_pool(
+            doris::TabletColumnObjectPool::create_global_column_cache(
+                    doris::config::tablet_schema_cache_capacity));
+}
+
 void gen_empty_segment() {
     std::string output_path = FLAGS_output_path.empty() ? "." : FLAGS_output_path;
 
@@ -1029,6 +1063,7 @@ int main(int argc, char** argv) {
     google::ParseCommandLineFlags(&argc, &argv, true);
 
     if (FLAGS_operation == "show_meta") {
+        init_common_components();
         show_meta();
     } else if (FLAGS_operation == "batch_delete_meta") {
         std::string tablet_file;
@@ -1040,18 +1075,21 @@ int main(int argc, char** argv) {
             return -1;
         }
 
+        init_common_components();
         batch_delete_meta(tablet_file);
     } else if (FLAGS_operation == "show_segment_footer") {
         if (FLAGS_file == "") {
             std::cout << "no file flag for show dict" << std::endl;
             return -1;
         }
+        init_common_components();
         show_segment_footer(FLAGS_file);
     } else if (FLAGS_operation == "show_segment_data") {
         if (FLAGS_file == "") {
             std::cout << "no file flag for show_segment_data" << std::endl;
             return -1;
         }
+        init_common_components();
         show_segment_data(FLAGS_file);
     } else if (FLAGS_operation == "gen_empty_segment") {
         gen_empty_segment();
@@ -1063,6 +1101,25 @@ int main(int argc, char** argv) {
             return -1;
         }
 
+        if (getenv("DORIS_HOME") == nullptr) {
+            fprintf(stderr, "you need set DORIS_HOME environment variable.\n");
+            exit(-1);
+        }
+
+        std::string conffile = std::string(getenv("DORIS_HOME")) + "/conf/be.conf";
+        if (!doris::config::init(conffile.c_str(), true, true, true)) {
+            fprintf(stderr, "error read config file. \n");
+            return -1;
+        }
+
+        std::string custom_conffile = doris::config::custom_config_dir + "/be_custom.conf";
+        if (!doris::config::init(custom_conffile.c_str(), true, false, false)) {
+            fprintf(stderr, "error read custom config file. \n");
+            return -1;
+        }
+
+        init_common_components();
+
         StorageEngine engine(doris::EngineOptions {});
         std::unique_ptr<DataDir> data_dir;
         Status st = init_data_dir(engine, FLAGS_root_path, &data_dir);
diff --git a/be/test/storage/tablet/tablet_meta_manager_test.cpp b/be/test/storage/tablet/tablet_meta_manager_test.cpp
index f5fee8a21cc..34f9641aebe 100644
--- a/be/test/storage/tablet/tablet_meta_manager_test.cpp
+++ b/be/test/storage/tablet/tablet_meta_manager_test.cpp
@@ -113,6 +113,12 @@ TEST_F(TabletMetaManagerTest, TestLoad) {
     // EXPECT_EQ(_json_header, json_meta_read);
 }
 
+TEST_F(TabletMetaManagerTest, TestLoadFailed) {
+    Status s = TabletMetaManager::load_json_meta(_data_dir, "/path/to/non_existent_file.json");
+    EXPECT_FALSE(s.ok());
+    EXPECT_TRUE(s.is<ErrorCode::INTERNAL_ERROR>());
+}
+
 TEST_F(TabletMetaManagerTest, TestDeleteBitmapEncode) {
     TTabletId tablet_id = 1234;
     int64_t version = 456;


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org