This is an automated email from the ASF dual-hosted git repository. yiguolei pushed a commit to branch branch-4.2 in repository https://gitbox.apache.org/repos/asf/doris.git
commit 8ca8dc9c725562e5d469809ce1f108800596d7aa Author: hui lai <[email protected]> AuthorDate: Thu Sep 10 09:29:07 2026 +0800 branch-4.1: [fix](be) Initialize bthread context key before first use (#67722) ### What problem does this PR solve? Backport #67580 to branch-4.1. A bthread could create its ThreadContext before its key was initialized. Later key creation changed the key version, causing context lookup to return null and scoped memory-tracker cleanup to crash. Initialize the key once before first use and retain it for the process lifetime. The conflict in thread_context.cpp was resolved by retaining the branch-4.1 function layout. The added and removed lines match the original PR. ### Release note Fix a potential BE crash during scoped memory-tracker cleanup caused by bthread context key initialization. ### Check List (For Author) - Test: Compilation and tests skipped as requested. clang-format 16 and git diff --check passed. - Behavior changed: Yes; initialize the bthread context key before first use and preserve its process lifetime. - Does this need documentation: No. --- be/src/runtime/thread_context.cpp | 18 ++++++++++++++++++ be/src/runtime/thread_context.h | 5 +++++ be/src/service/internal_service.cpp | 8 -------- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/be/src/runtime/thread_context.cpp b/be/src/runtime/thread_context.cpp index 83f38369d6c..9443625ab3e 100644 --- a/be/src/runtime/thread_context.cpp +++ b/be/src/runtime/thread_context.cpp @@ -17,6 +17,8 @@ #include "runtime/thread_context.h" +#include <mutex> + #include "common/signal_handler.h" #include "runtime/query_context.h" #include "runtime/runtime_state.h" @@ -24,6 +26,22 @@ namespace doris { class MemTracker; +bthread_key_t btls_key; + +namespace { + +void thread_context_deleter(void* data) { + delete static_cast<ThreadContext*>(data); +} + +} // namespace + +void init_thread_context_btls_key() { + static std::once_flag btls_key_once; + std::call_once(btls_key_once, + []() { CHECK_EQ(0, bthread_key_create(&btls_key, thread_context_deleter)); }); +} + void AttachTask::init(const std::shared_ptr<ResourceContext>& rc) { // Validate the ResourceContext chain before mutating any thread-local // or signal state. If any link is null we throw immediately, so the diff --git a/be/src/runtime/thread_context.h b/be/src/runtime/thread_context.h index 332cd0f6545..c0168daceb2 100644 --- a/be/src/runtime/thread_context.h +++ b/be/src/runtime/thread_context.h @@ -140,6 +140,10 @@ class SwitchResourceContext; extern bthread_key_t btls_key; +// Initialize btls_key exactly once before it is used by any thread context. The key has +// process lifetime so an existing bthread context never becomes invalid while the BE is running. +void init_thread_context_btls_key(); + static std::string NO_THREAD_CONTEXT_MSG = "Current thread not exist ThreadContext, usually after the thread is started, using " "SCOPED_ATTACH_TASK macro to create a ThreadContext and bind a Task."; @@ -224,6 +228,7 @@ private: class ThreadLocalHandle { public: static void create_thread_local_if_not_exits() { + init_thread_context_btls_key(); if (bthread_self() == 0) { if (!pthread_context_ptr_init) { thread_context_ptr = new ThreadContext(); diff --git a/be/src/service/internal_service.cpp b/be/src/service/internal_service.cpp index 673001aa987..96142dae0b6 100644 --- a/be/src/service/internal_service.cpp +++ b/be/src/service/internal_service.cpp @@ -167,12 +167,6 @@ DEFINE_GAUGE_METRIC_PROTOTYPE_2ARG(arrow_flight_work_max_threads, MetricUnit::NO static bvar::LatencyRecorder g_process_remote_fetch_rowsets_latency("process_remote_fetch_rowsets"); -bthread_key_t btls_key; - -static void thread_context_deleter(void* d) { - delete static_cast<ThreadContext*>(d); -} - static int32_t resolved_brpc_peer_fetch_pool_threads() { return config::brpc_peer_fetch_pool_threads != -1 ? config::brpc_peer_fetch_pool_threads : std::max(64, CpuInfo::num_cores() * 2); @@ -293,7 +287,6 @@ PInternalService::PInternalService(ExecEnv* exec_env) _exec_env->load_stream_mgr()->set_heavy_work_pool(&_heavy_work_pool); - CHECK_EQ(0, bthread_key_create(&btls_key, thread_context_deleter)); CHECK_EQ(0, bthread_key_create(&AsyncIO::btls_io_ctx_key, AsyncIO::io_ctx_key_deleter)); } @@ -322,7 +315,6 @@ PInternalService::~PInternalService() { DEREGISTER_HOOK_METRIC(arrow_flight_work_pool_max_queue_size); DEREGISTER_HOOK_METRIC(arrow_flight_work_max_threads); - CHECK_EQ(0, bthread_key_delete(btls_key)); CHECK_EQ(0, bthread_key_delete(AsyncIO::btls_io_ctx_key)); } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
