Coverage Report

Created: 2026-08-18 13:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/util/bvar_windowed_adder.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 <bthread/mutex.h>
21
#include <bvar/bvar.h>
22
#include <bvar/multi_dimension.h>
23
#include <bvar/window.h>
24
25
#include <cstdint>
26
#include <list>
27
#include <map>
28
#include <memory>
29
#include <mutex>
30
#include <string>
31
#include <utility>
32
#include <vector>
33
34
namespace doris {
35
36
// Shared window spans (seconds) for multi-window metrics.
37
// bvar::Window enforces MAX_SECONDS_LIMIT = 3600, so the longest window is 1h.
38
inline constexpr int WINDOW_5M = 300;
39
inline constexpr int WINDOW_30M = 1800;
40
inline constexpr int WINDOW_1H = 3600;
41
42
/**
43
 * Multi-dimension windowed adder.
44
 *
45
 * For each dimension value combination (e.g., job_id), automatically creates:
46
 *   - A bvar::Adder (cumulative counter managed by MultiDimension)
47
 *   - Multiple bvar::Window instances (sliding window views at different time scales)
48
 *
49
 * Windows are lazily created on first write to a dimension value.
50
 *
51
 * @example
52
 *   MBvarWindowedAdder requested_seg_num(
53
 *       "warmup_ed_requested_segment_num",
54
 *       {"job_id"},
55
 *       {300, 1800, 7200}
56
 *   );
57
 *   requested_seg_num.put({"13419"}, 1);
58
 */
59
class MBvarWindowedAdder {
60
public:
61
    MBvarWindowedAdder(const std::string& name, const std::initializer_list<std::string>& dim_names,
62
                       std::vector<int> window_seconds, bool expose = true)
63
21
            : name_(name),
64
21
              window_seconds_(std::move(window_seconds)),
65
21
              md_total_(std::list<std::string>(dim_names)),
66
21
              expose_(expose) {
67
21
        if (expose_) {
68
9
            md_total_.expose(name_ + "_total");
69
9
        }
70
21
    }
71
72
12
    void put(const std::initializer_list<std::string>& dim_values, int64_t value) {
73
12
        auto* adder = md_total_.get_stats(std::list<std::string>(dim_values));
74
12
        if (!adder) return;
75
12
        ensure_windows(dim_values, adder);
76
12
        *adder << value;
77
12
    }
78
79
    /** Get the current window value for the specified dimension and window index. */
80
    int64_t get_window_value(const std::initializer_list<std::string>& dim_values,
81
8
                             size_t window_idx) {
82
8
        std::lock_guard<bthread::Mutex> lock(mutex_);
83
8
        auto it = dims_.find(make_key(dim_values));
84
8
        if (it == dims_.end() || window_idx >= it->second.windows.size()) {
85
4
            return 0;
86
4
        }
87
4
        return it->second.windows[window_idx]->get_value();
88
8
    }
89
90
    /** Overload accepting a pre-built key string (e.g., "job_id,table_id"). */
91
4
    int64_t get_window_value(const std::string& dim_key, size_t window_idx) {
92
4
        std::lock_guard<bthread::Mutex> lock(mutex_);
93
4
        auto it = dims_.find(dim_key);
94
4
        if (it == dims_.end() || window_idx >= it->second.windows.size()) {
95
2
            return 0;
96
2
        }
97
2
        return it->second.windows[window_idx]->get_value();
98
4
    }
99
100
    /** List all dimension key strings that have been seen. */
101
4
    std::vector<std::string> list_dimensions() const {
102
4
        std::lock_guard<bthread::Mutex> lock(mutex_);
103
4
        std::vector<std::string> result;
104
4
        result.reserve(dims_.size());
105
5
        for (auto& [key, _] : dims_) {
106
5
            result.push_back(key);
107
5
        }
108
4
        return result;
109
4
    }
110
111
0
    void hide() {
112
0
        std::lock_guard<bthread::Mutex> lock(mutex_);
113
0
        if (!expose_) {
114
0
            return;
115
0
        }
116
0
        expose_ = false;
117
0
        md_total_.hide();
118
0
        for (auto& [_, entry] : dims_) {
119
0
            for (auto& window : entry.windows) {
120
0
                window->hide();
121
0
            }
122
0
        }
123
0
    }
124
125
private:
126
    struct DimEntry {
127
        bvar::Adder<int64_t>* adder; // owned by MultiDimension
128
        std::vector<std::unique_ptr<bvar::Window<bvar::Adder<int64_t>>>> windows;
129
    };
130
131
    void ensure_windows(const std::initializer_list<std::string>& dim_values,
132
12
                        bvar::Adder<int64_t>* adder) {
133
12
        std::string key = make_key(dim_values);
134
12
        std::lock_guard<bthread::Mutex> lock(mutex_);
135
12
        if (dims_.count(key)) return;
136
9
        DimEntry entry;
137
9
        entry.adder = adder;
138
11
        for (int ws : window_seconds_) {
139
11
            if (expose_) {
140
11
                std::string wname = name_ + "_" + std::to_string(ws) + "s_" + key;
141
11
                entry.windows.emplace_back(
142
11
                        std::make_unique<bvar::Window<bvar::Adder<int64_t>>>(wname, adder, ws));
143
11
            } else {
144
0
                entry.windows.emplace_back(
145
0
                        std::make_unique<bvar::Window<bvar::Adder<int64_t>>>(adder, ws));
146
0
            }
147
11
        }
148
9
        dims_[key] = std::move(entry);
149
9
    }
150
151
20
    static std::string make_key(const std::initializer_list<std::string>& dim_values) {
152
20
        std::string result;
153
21
        for (auto& v : dim_values) {
154
21
            if (!result.empty()) result += ",";
155
21
            result += v;
156
21
        }
157
20
        return result;
158
20
    }
159
160
    std::string name_;
161
    std::vector<int> window_seconds_;
162
    bvar::MultiDimension<bvar::Adder<int64_t>> md_total_;
163
    bool expose_;
164
    mutable bthread::Mutex mutex_;
165
    std::map<std::string, DimEntry> dims_;
166
};
167
168
} // namespace doris