Coverage Report

Created: 2025-09-10 18:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/root/doris/be/src/util/debug_points.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#pragma once
19
20
#include <any>
21
#include <atomic>
22
#include <boost/lexical_cast.hpp>
23
#include <chrono>
24
#include <functional>
25
#include <map>
26
#include <memory>
27
#include <thread>
28
#include <type_traits>
29
30
#include "common/atomic_shared_ptr.h"
31
#include "common/compiler_util.h"
32
#include "common/config.h"
33
#include "fmt/format.h"
34
35
// more usage can see 'util/debug_points_test.cpp'
36
// using {} around code, to avoid duplicate variable name
37
#define DBUG_EXECUTE_IF(debug_point_name, code)                               \
38
10.7M
    if (UNLIKELY(config::enable_debug_points)) {                              \
39
182k
        auto dp = DebugPoints::instance()->get_debug_point(debug_point_name); \
40
182k
        if (dp) {                                                             \
41
57
            [[maybe_unused]] auto DP_NAME = debug_point_name;                 \
42
57
            code;                                                             \
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvEN30InvertedIndexColumnWriterEmpty4initEv
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvEN30InvertedIndexColumnWriterEmpty10add_valuesENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEPKvm
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvEN30InvertedIndexColumnWriterEmpty16add_array_valuesEmPKNS_15CollectionValueEm
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvEN30InvertedIndexColumnWriterEmpty16add_array_valuesEmPKvPKhS6_m
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvEN30InvertedIndexColumnWriterEmpty9add_nullsEj
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvEN30InvertedIndexColumnWriterEmpty15add_array_nullsEPKhm
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvEN30InvertedIndexColumnWriterEmpty6finishEv
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvENK30InvertedIndexColumnWriterEmpty4sizeEv
Unexecuted instantiation: column_writer.cpp:_ZZN5doris10segment_v218ScalarColumnWriter4initEvEN30InvertedIndexColumnWriterEmpty14close_on_errorEv
43
0
        }                                                                     \
44
182k
    }
45
46
// define some common debug actions
47
// usage example: DBUG_EXECUTE_IF("xxx", DBUG_BLOCK);
48
#define DBUG_BLOCK                                                      \
49
    {                                                                   \
50
        LOG(INFO) << "start debug block " << DP_NAME;                   \
51
        while (DebugPoints::instance()->is_enable(DP_NAME)) {           \
52
            std::this_thread::sleep_for(std::chrono::milliseconds(10)); \
53
        }                                                               \
54
        LOG(INFO) << "end debug block " << DP_NAME;                     \
55
    }
56
57
// DBUG_RUN_CALLBACK is usually use in be ut, to exchange local variable between the injected code and callback code.
58
// usage example: DBUG_EXECUTE_IF("xxx", DBUG_RUN_CALLBACK(yyy,...));
59
#define DBUG_RUN_CALLBACK(...)             \
60
    do {                                   \
61
        dp->execute_callback(__VA_ARGS__); \
62
    } while (0)
63
64
// example of debug point with callback.
65
//
66
// void demo_callback() {
67
//     int a = 0;
68
//
69
//     DBUG_EXECUTE_IF("set_a", DBUG_RUN_CALLBACK(&a));
70
//     DBUG_EXECUTE_IF("get_a", DBUG_RUN_CALLBACK(a));
71
// }
72
//
73
// TEST(DebugPointsTest, Callback) {
74
//     config::enable_debug_points = true;
75
//     DebugPoints::instance()->clear();
76
//
77
//     int got_a = 0;
78
//
79
//     std::function<void(int*)> set_handler = [](int* a) { *a = 1000; };
80
//     std::function<void(int)> get_handler = [&got_a](int a) { got_a = a; };
81
//     DebugPoints::instance()->add_with_callback("set_a", set_handler);
82
//     DebugPoints::instance()->add_with_callback("get_a", get_handler);
83
//
84
//     demo_callback();
85
//
86
//     EXPECT_EQ(1000, got_a);
87
// }
88
89
namespace doris {
90
91
struct DebugPoint {
92
    std::atomic<int64_t> execute_num {0};
93
    int64_t execute_limit = -1;
94
    int64_t expire_ms = -1;
95
96
    std::map<std::string, std::string> params;
97
98
    // Usually `callback` use in be ut, to exchange local variable between callback code and injected code,
99
    // or change with different injected handlers.
100
    // test/util/debug_points_test.cpp#Callback give a example.
101
    std::any callback;
102
103
    template <typename T>
104
17
    T param(const std::string& key, T default_value = T()) {
105
17
        auto it = params.find(key);
106
17
        if (it == params.end()) {
107
4
            return default_value;
108
4
        }
109
13
        if constexpr (std::is_same_v<T, bool>) {
110
2
            if (it->second == "true") {
111
1
                return true;
112
1
            }
113
1
            if (it->second == "false") {
114
1
                return false;
115
1
            }
116
0
            return boost::lexical_cast<T>(it->second);
117
7
        } else if constexpr (std::is_arithmetic_v<T>) {
118
7
            return boost::lexical_cast<T>(it->second);
119
7
        } else if constexpr (std::is_same_v<T, const char*>) {
120
1
            return it->second.c_str();
121
3
        } else {
122
3
            static_assert(std::is_same_v<T, std::string>);
123
3
            return it->second;
124
3
        }
125
13
    }
_ZN5doris10DebugPoint5paramIiEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES2_
Line
Count
Source
104
5
    T param(const std::string& key, T default_value = T()) {
105
5
        auto it = params.find(key);
106
5
        if (it == params.end()) {
107
1
            return default_value;
108
1
        }
109
        if constexpr (std::is_same_v<T, bool>) {
110
            if (it->second == "true") {
111
                return true;
112
            }
113
            if (it->second == "false") {
114
                return false;
115
            }
116
            return boost::lexical_cast<T>(it->second);
117
4
        } else if constexpr (std::is_arithmetic_v<T>) {
118
4
            return boost::lexical_cast<T>(it->second);
119
        } else if constexpr (std::is_same_v<T, const char*>) {
120
            return it->second.c_str();
121
        } else {
122
            static_assert(std::is_same_v<T, std::string>);
123
            return it->second;
124
        }
125
4
    }
_ZN5doris10DebugPoint5paramINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEET_RKS7_S8_
Line
Count
Source
104
3
    T param(const std::string& key, T default_value = T()) {
105
3
        auto it = params.find(key);
106
3
        if (it == params.end()) {
107
0
            return default_value;
108
0
        }
109
        if constexpr (std::is_same_v<T, bool>) {
110
            if (it->second == "true") {
111
                return true;
112
            }
113
            if (it->second == "false") {
114
                return false;
115
            }
116
            return boost::lexical_cast<T>(it->second);
117
        } else if constexpr (std::is_arithmetic_v<T>) {
118
            return boost::lexical_cast<T>(it->second);
119
        } else if constexpr (std::is_same_v<T, const char*>) {
120
            return it->second.c_str();
121
3
        } else {
122
3
            static_assert(std::is_same_v<T, std::string>);
123
3
            return it->second;
124
3
        }
125
3
    }
_ZN5doris10DebugPoint5paramIPKcEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES4_
Line
Count
Source
104
2
    T param(const std::string& key, T default_value = T()) {
105
2
        auto it = params.find(key);
106
2
        if (it == params.end()) {
107
1
            return default_value;
108
1
        }
109
        if constexpr (std::is_same_v<T, bool>) {
110
            if (it->second == "true") {
111
                return true;
112
            }
113
            if (it->second == "false") {
114
                return false;
115
            }
116
            return boost::lexical_cast<T>(it->second);
117
        } else if constexpr (std::is_arithmetic_v<T>) {
118
            return boost::lexical_cast<T>(it->second);
119
1
        } else if constexpr (std::is_same_v<T, const char*>) {
120
1
            return it->second.c_str();
121
        } else {
122
            static_assert(std::is_same_v<T, std::string>);
123
            return it->second;
124
        }
125
1
    }
_ZN5doris10DebugPoint5paramIdEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES2_
Line
Count
Source
104
3
    T param(const std::string& key, T default_value = T()) {
105
3
        auto it = params.find(key);
106
3
        if (it == params.end()) {
107
0
            return default_value;
108
0
        }
109
        if constexpr (std::is_same_v<T, bool>) {
110
            if (it->second == "true") {
111
                return true;
112
            }
113
            if (it->second == "false") {
114
                return false;
115
            }
116
            return boost::lexical_cast<T>(it->second);
117
3
        } else if constexpr (std::is_arithmetic_v<T>) {
118
3
            return boost::lexical_cast<T>(it->second);
119
        } else if constexpr (std::is_same_v<T, const char*>) {
120
            return it->second.c_str();
121
        } else {
122
            static_assert(std::is_same_v<T, std::string>);
123
            return it->second;
124
        }
125
3
    }
_ZN5doris10DebugPoint5paramIbEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES2_
Line
Count
Source
104
2
    T param(const std::string& key, T default_value = T()) {
105
2
        auto it = params.find(key);
106
2
        if (it == params.end()) {
107
0
            return default_value;
108
0
        }
109
2
        if constexpr (std::is_same_v<T, bool>) {
110
2
            if (it->second == "true") {
111
1
                return true;
112
1
            }
113
1
            if (it->second == "false") {
114
1
                return false;
115
1
            }
116
0
            return boost::lexical_cast<T>(it->second);
117
        } else if constexpr (std::is_arithmetic_v<T>) {
118
            return boost::lexical_cast<T>(it->second);
119
        } else if constexpr (std::is_same_v<T, const char*>) {
120
            return it->second.c_str();
121
        } else {
122
            static_assert(std::is_same_v<T, std::string>);
123
            return it->second;
124
        }
125
2
    }
_ZN5doris10DebugPoint5paramIlEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES2_
Line
Count
Source
104
2
    T param(const std::string& key, T default_value = T()) {
105
2
        auto it = params.find(key);
106
2
        if (it == params.end()) {
107
2
            return default_value;
108
2
        }
109
        if constexpr (std::is_same_v<T, bool>) {
110
            if (it->second == "true") {
111
                return true;
112
            }
113
            if (it->second == "false") {
114
                return false;
115
            }
116
            return boost::lexical_cast<T>(it->second);
117
0
        } else if constexpr (std::is_arithmetic_v<T>) {
118
0
            return boost::lexical_cast<T>(it->second);
119
        } else if constexpr (std::is_same_v<T, const char*>) {
120
            return it->second.c_str();
121
        } else {
122
            static_assert(std::is_same_v<T, std::string>);
123
            return it->second;
124
        }
125
0
    }
126
127
    template <typename... ARGS>
128
2
    void execute_callback(ARGS... args) {
129
2
        if (!callback.has_value()) {
130
0
            throw std::invalid_argument("No set callback");
131
0
        }
132
133
2
        auto func = std::any_cast<std::function<void(ARGS...)>>(callback);
134
2
        func(args...);
135
2
    }
_ZN5doris10DebugPoint16execute_callbackIJPiEEEvDpT_
Line
Count
Source
128
1
    void execute_callback(ARGS... args) {
129
1
        if (!callback.has_value()) {
130
0
            throw std::invalid_argument("No set callback");
131
0
        }
132
133
1
        auto func = std::any_cast<std::function<void(ARGS...)>>(callback);
134
1
        func(args...);
135
1
    }
_ZN5doris10DebugPoint16execute_callbackIJiEEEvDpT_
Line
Count
Source
128
1
    void execute_callback(ARGS... args) {
129
1
        if (!callback.has_value()) {
130
0
            throw std::invalid_argument("No set callback");
131
0
        }
132
133
1
        auto func = std::any_cast<std::function<void(ARGS...)>>(callback);
134
1
        func(args...);
135
1
    }
136
};
137
138
class DebugPoints {
139
public:
140
    bool is_enable(const std::string& name);
141
    std::shared_ptr<DebugPoint> get_debug_point(const std::string& name);
142
    void remove(const std::string& name);
143
    void clear();
144
145
    // if not enable debug point or its params not contains `key`, then return `default_value`
146
    // url: /api/debug_point/add/name?k1=v1&k2=v2&...
147
    template <typename T>
148
    T get_debug_param_or_default(const std::string& name, const std::string& key,
149
6
                                 const T& default_value) {
150
6
        auto debug_point = get_debug_point(name);
151
6
        return debug_point ? debug_point->param(key, default_value) : default_value;
152
6
    }
_ZN5doris11DebugPoints26get_debug_param_or_defaultIdEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESA_RKS2_
Line
Count
Source
149
1
                                 const T& default_value) {
150
1
        auto debug_point = get_debug_point(name);
151
1
        return debug_point ? debug_point->param(key, default_value) : default_value;
152
1
    }
_ZN5doris11DebugPoints26get_debug_param_or_defaultIiEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESA_RKS2_
Line
Count
Source
149
4
                                 const T& default_value) {
150
4
        auto debug_point = get_debug_point(name);
151
4
        return debug_point ? debug_point->param(key, default_value) : default_value;
152
4
    }
_ZN5doris11DebugPoints26get_debug_param_or_defaultINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEET_RKS7_SA_RKS8_
Line
Count
Source
149
1
                                 const T& default_value) {
150
1
        auto debug_point = get_debug_point(name);
151
1
        return debug_point ? debug_point->param(key, default_value) : default_value;
152
1
    }
Unexecuted instantiation: _ZN5doris11DebugPoints26get_debug_param_or_defaultIlEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESA_RKS2_
153
154
    // url: /api/debug_point/add/name?value=v
155
    template <typename T>
156
3
    T get_debug_param_or_default(const std::string& name, const T& default_value) {
157
3
        return get_debug_param_or_default(name, "value", default_value);
158
3
    }
_ZN5doris11DebugPoints26get_debug_param_or_defaultIiEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS2_
Line
Count
Source
156
2
    T get_debug_param_or_default(const std::string& name, const T& default_value) {
157
2
        return get_debug_param_or_default(name, "value", default_value);
158
2
    }
_ZN5doris11DebugPoints26get_debug_param_or_defaultINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEET_RKS7_RKS8_
Line
Count
Source
156
1
    T get_debug_param_or_default(const std::string& name, const T& default_value) {
157
1
        return get_debug_param_or_default(name, "value", default_value);
158
1
    }
159
160
    void add(const std::string& name, std::shared_ptr<DebugPoint> debug_point);
161
162
    // more 'add' functions for convenient use
163
48
    void add(const std::string& name) { add(name, std::make_shared<DebugPoint>()); }
164
    void add_with_params(const std::string& name,
165
3
                         const std::map<std::string, std::string>& params) {
166
3
        auto debug_point = std::make_shared<DebugPoint>();
167
3
        debug_point->params = params;
168
3
        add(name, debug_point);
169
3
    }
170
    template <typename T>
171
2
    void add_with_value(const std::string& name, const T& value) {
172
2
        add_with_params(name, {{"value", fmt::format("{}", value)}});
173
2
    }
_ZN5doris11DebugPoints14add_with_valueIiEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_
Line
Count
Source
171
1
    void add_with_value(const std::string& name, const T& value) {
172
1
        add_with_params(name, {{"value", fmt::format("{}", value)}});
173
1
    }
_ZN5doris11DebugPoints14add_with_valueIA6_cEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_
Line
Count
Source
171
1
    void add_with_value(const std::string& name, const T& value) {
172
1
        add_with_params(name, {{"value", fmt::format("{}", value)}});
173
1
    }
174
175
    template <typename... ARGS>
176
2
    void add_with_callback(const std::string& name, std::function<void(ARGS...)> callback) {
177
2
        auto debug_point = std::make_shared<DebugPoint>();
178
2
        debug_point->callback = callback;
179
2
        add(name, debug_point);
180
2
    }
_ZN5doris11DebugPoints17add_with_callbackIJPiEEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt8functionIFvDpT_EE
Line
Count
Source
176
1
    void add_with_callback(const std::string& name, std::function<void(ARGS...)> callback) {
177
1
        auto debug_point = std::make_shared<DebugPoint>();
178
1
        debug_point->callback = callback;
179
1
        add(name, debug_point);
180
1
    }
_ZN5doris11DebugPoints17add_with_callbackIJiEEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt8functionIFvDpT_EE
Line
Count
Source
176
1
    void add_with_callback(const std::string& name, std::function<void(ARGS...)> callback) {
177
1
        auto debug_point = std::make_shared<DebugPoint>();
178
1
        debug_point->callback = callback;
179
1
        add(name, debug_point);
180
1
    }
181
182
    static DebugPoints* instance();
183
184
private:
185
    DebugPoints();
186
187
    using DebugPointMap = std::map<std::string, std::shared_ptr<DebugPoint>>;
188
189
    // handler(new_debug_points)
190
    void update(std::function<void(DebugPointMap&)>&& handler);
191
192
private:
193
    atomic_shared_ptr<const DebugPointMap> _debug_points;
194
};
195
196
} // namespace doris