Coverage Report

Created: 2026-11-06 15:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/storage/utils.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
// IWYU pragma: no_include <bthread/errno.h>
21
#include <errno.h> // IWYU pragma: keep
22
#include <limits.h>
23
#include <stdint.h>
24
#include <sys/time.h>
25
26
#include <cstddef>
27
#include <cstdio>
28
#include <cstdlib>
29
#include <iterator>
30
#include <limits>
31
#include <string>
32
#include <vector>
33
34
#include "common/status.h"
35
#include "storage/olap_common.h"
36
37
namespace doris {
38
static const std::string DELETE_SIGN = "__DORIS_DELETE_SIGN__";
39
static const std::string WHERE_SIGN = "__DORIS_WHERE_SIGN__";
40
static const std::string VERSION_COL = "__DORIS_VERSION_COL__";
41
static const std::string SKIP_BITMAP_COL = "__DORIS_SKIP_BITMAP_COL__";
42
static const std::string SEQUENCE_COL = "__DORIS_SEQUENCE_COL__";
43
static const std::string COMMIT_TSO_COL = "__DORIS_COMMIT_TSO_COL__";
44
static const std::string ROW_LSN_COL = "__DORIS_ROW_LSN_COL__";
45
static const std::string TTL_COL = "__DORIS_TTL_COL__";
46
// ATTN(changelog-rename): formerly "__DORIS_BINLOG_TSO__"
47
static const std::string CHANGELOG_TSO_COL = "__DORIS_CHANGELOG_TSO__";
48
// ATTN(changelog-rename): formerly "__DORIS_BINLOG_LSN__"
49
static const std::string CHANGELOG_LSN_COL = "__DORIS_CHANGELOG_LSN__";
50
// ATTN(changelog-rename): formerly "__DORIS_BINLOG_OP__"
51
static const std::string CHANGELOG_OP_COL = "__DORIS_CHANGELOG_OP__";
52
53
// 用来加速运算
54
const static int32_t g_power_table[] = {1,      10,      100,      1000,      10000,
55
                                        100000, 1000000, 10000000, 100000000, 1000000000};
56
57
// 计时工具,用于确定一段代码执行的时间,用于性能调优
58
class OlapStopWatch {
59
public:
60
231
    uint64_t get_elapse_time_us() const {
61
231
        struct timeval now;
62
231
        gettimeofday(&now, nullptr);
63
231
        return (uint64_t)((now.tv_sec - _begin_time.tv_sec) * 1e6 +
64
231
                          (now.tv_usec - _begin_time.tv_usec));
65
231
    }
66
67
111
    double get_elapse_second() const { return get_elapse_time_us() / 1000000.0; }
68
69
180
    void reset() { gettimeofday(&_begin_time, nullptr); }
70
71
180
    OlapStopWatch() { reset(); }
72
73
private:
74
    struct timeval _begin_time; // 起始时间戳
75
};
76
77
// @brief 切分字符串
78
// @param base 原串
79
// @param separator 分隔符
80
// @param result 切分结果
81
template <typename Str, typename T>
82
21
Status split_string(const Str& base, const T separator, std::vector<std::string>* result) {
83
21
    if (!result) {
84
0
        return Status::Error<ErrorCode::INVALID_ARGUMENT>("split_string meet nullptr result input");
85
0
    }
86
87
    // 处理base为空的情况
88
    // 在删除功能中,当varchar类型列的过滤条件为空时,会出现这种情况
89
21
    if (base.size() == 0) {
90
0
        result->push_back("");
91
0
        return Status::OK();
92
0
    }
93
94
21
    size_t offset = 0;
95
59
    while (offset < base.length()) {
96
59
        size_t next = base.find(separator, offset);
97
59
        if (next == std::string::npos) {
98
21
            result->emplace_back(base.substr(offset));
99
21
            break;
100
38
        } else {
101
38
            result->emplace_back(base.substr(offset, next - offset));
102
38
            offset = next + 1;
103
38
        }
104
59
    }
105
106
21
    return Status::OK();
107
21
}
_ZN5doris12split_stringISt17basic_string_viewIcSt11char_traitsIcEEcEENS_6StatusERKT_T0_PSt6vectorINSt7__cxx1112basic_stringIcS3_SaIcEEESaISE_EE
Line
Count
Source
82
17
Status split_string(const Str& base, const T separator, std::vector<std::string>* result) {
83
17
    if (!result) {
84
0
        return Status::Error<ErrorCode::INVALID_ARGUMENT>("split_string meet nullptr result input");
85
0
    }
86
87
    // 处理base为空的情况
88
    // 在删除功能中,当varchar类型列的过滤条件为空时,会出现这种情况
89
17
    if (base.size() == 0) {
90
0
        result->push_back("");
91
0
        return Status::OK();
92
0
    }
93
94
17
    size_t offset = 0;
95
51
    while (offset < base.length()) {
96
51
        size_t next = base.find(separator, offset);
97
51
        if (next == std::string::npos) {
98
17
            result->emplace_back(base.substr(offset));
99
17
            break;
100
34
        } else {
101
34
            result->emplace_back(base.substr(offset, next - offset));
102
34
            offset = next + 1;
103
34
        }
104
51
    }
105
106
17
    return Status::OK();
107
17
}
_ZN5doris12split_stringINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEcEENS_6StatusERKT_T0_PSt6vectorIS6_SaIS6_EE
Line
Count
Source
82
4
Status split_string(const Str& base, const T separator, std::vector<std::string>* result) {
83
4
    if (!result) {
84
0
        return Status::Error<ErrorCode::INVALID_ARGUMENT>("split_string meet nullptr result input");
85
0
    }
86
87
    // 处理base为空的情况
88
    // 在删除功能中,当varchar类型列的过滤条件为空时,会出现这种情况
89
4
    if (base.size() == 0) {
90
0
        result->push_back("");
91
0
        return Status::OK();
92
0
    }
93
94
4
    size_t offset = 0;
95
8
    while (offset < base.length()) {
96
8
        size_t next = base.find(separator, offset);
97
8
        if (next == std::string::npos) {
98
4
            result->emplace_back(base.substr(offset));
99
4
            break;
100
4
        } else {
101
4
            result->emplace_back(base.substr(offset, next - offset));
102
4
            offset = next + 1;
103
4
        }
104
8
    }
105
106
4
    return Status::OK();
107
4
}
108
109
uint32_t olap_adler32_init();
110
uint32_t olap_adler32(uint32_t adler, const char* buf, size_t len);
111
112
// 获取系统当前时间,并将时间转换为字符串
113
Status gen_timestamp_string(std::string* out_string);
114
115
Status check_datapath_rw(const std::string& path);
116
117
Status read_write_test_file(const std::string& test_file_path);
118
119
// 打印Errno
120
class Errno {
121
public:
122
    // 返回Errno对应的错误信息,线程安全
123
    static const char* str();
124
    static const char* str(int no);
125
    static int no();
126
127
private:
128
    static const int BUF_SIZE = 256;
129
    static __thread char _buf[BUF_SIZE];
130
};
131
132
// 检查int8_t, int16_t, int32_t, int64_t的值是否溢出
133
template <typename T>
134
89
bool valid_signed_number(const std::string& value_str) {
135
89
    char* endptr = nullptr;
136
89
    errno = 0;
137
89
    int64_t value = strtol(value_str.c_str(), &endptr, 10);
138
139
89
    if ((errno == ERANGE && (value == LONG_MAX || value == LONG_MIN)) ||
140
89
        (errno != 0 && value == 0) || endptr == value_str || *endptr != '\0') {
141
2
        return false;
142
2
    }
143
144
87
    if (value < std::numeric_limits<T>::min() || value > std::numeric_limits<T>::max()) {
145
6
        return false;
146
6
    }
147
148
81
    return true;
149
87
}
_ZN5doris19valid_signed_numberIlEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Line
Count
Source
134
11
bool valid_signed_number(const std::string& value_str) {
135
11
    char* endptr = nullptr;
136
11
    errno = 0;
137
11
    int64_t value = strtol(value_str.c_str(), &endptr, 10);
138
139
11
    if ((errno == ERANGE && (value == LONG_MAX || value == LONG_MIN)) ||
140
11
        (errno != 0 && value == 0) || endptr == value_str || *endptr != '\0') {
141
2
        return false;
142
2
    }
143
144
9
    if (value < std::numeric_limits<T>::min() || value > std::numeric_limits<T>::max()) {
145
0
        return false;
146
0
    }
147
148
9
    return true;
149
9
}
_ZN5doris19valid_signed_numberIaEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Line
Count
Source
134
11
bool valid_signed_number(const std::string& value_str) {
135
11
    char* endptr = nullptr;
136
11
    errno = 0;
137
11
    int64_t value = strtol(value_str.c_str(), &endptr, 10);
138
139
11
    if ((errno == ERANGE && (value == LONG_MAX || value == LONG_MIN)) ||
140
11
        (errno != 0 && value == 0) || endptr == value_str || *endptr != '\0') {
141
0
        return false;
142
0
    }
143
144
11
    if (value < std::numeric_limits<T>::min() || value > std::numeric_limits<T>::max()) {
145
2
        return false;
146
2
    }
147
148
9
    return true;
149
11
}
_ZN5doris19valid_signed_numberIsEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Line
Count
Source
134
13
bool valid_signed_number(const std::string& value_str) {
135
13
    char* endptr = nullptr;
136
13
    errno = 0;
137
13
    int64_t value = strtol(value_str.c_str(), &endptr, 10);
138
139
13
    if ((errno == ERANGE && (value == LONG_MAX || value == LONG_MIN)) ||
140
13
        (errno != 0 && value == 0) || endptr == value_str || *endptr != '\0') {
141
0
        return false;
142
0
    }
143
144
13
    if (value < std::numeric_limits<T>::min() || value > std::numeric_limits<T>::max()) {
145
2
        return false;
146
2
    }
147
148
11
    return true;
149
13
}
_ZN5doris19valid_signed_numberIiEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Line
Count
Source
134
54
bool valid_signed_number(const std::string& value_str) {
135
54
    char* endptr = nullptr;
136
54
    errno = 0;
137
54
    int64_t value = strtol(value_str.c_str(), &endptr, 10);
138
139
54
    if ((errno == ERANGE && (value == LONG_MAX || value == LONG_MIN)) ||
140
54
        (errno != 0 && value == 0) || endptr == value_str || *endptr != '\0') {
141
0
        return false;
142
0
    }
143
144
54
    if (value < std::numeric_limits<T>::min() || value > std::numeric_limits<T>::max()) {
145
2
        return false;
146
2
    }
147
148
52
    return true;
149
54
}
150
151
template <>
152
bool valid_signed_number<int128_t>(const std::string& value_str);
153
154
// 检查uint8_t, uint16_t, uint32_t, uint64_t的值是否溢出
155
template <typename T>
156
0
bool valid_unsigned_number(const std::string& value_str) {
157
0
    if (value_str[0] == '-') {
158
0
        return false;
159
0
    }
160
161
0
    char* endptr = nullptr;
162
0
    errno = 0;
163
0
    uint64_t value = strtoul(value_str.c_str(), &endptr, 10);
164
165
0
    if ((errno == ERANGE && (value == ULONG_MAX)) || (errno != 0 && value == 0) ||
166
0
        endptr == value_str || *endptr != '\0') {
167
0
        return false;
168
0
    }
169
170
0
    if (value < std::numeric_limits<T>::min() || value > std::numeric_limits<T>::max()) {
171
0
        return false;
172
0
    }
173
174
0
    return true;
175
0
}
Unexecuted instantiation: _ZN5doris21valid_unsigned_numberIhEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Unexecuted instantiation: _ZN5doris21valid_unsigned_numberItEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Unexecuted instantiation: _ZN5doris21valid_unsigned_numberIjEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Unexecuted instantiation: _ZN5doris21valid_unsigned_numberImEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
176
177
bool valid_decimal(const std::string& value_str, const uint32_t precision, const uint32_t frac);
178
179
// Validate date/datetime format and fractional-second scale roughly.
180
bool valid_datetime(const std::string& value_str, const uint32_t scale);
181
182
bool valid_bool(const std::string& value_str);
183
184
bool valid_ipv4(const std::string& value_str);
185
186
bool valid_ipv6(const std::string& value_str);
187
188
bool valid_uuid(const std::string& value_str);
189
190
39.9k
constexpr bool is_string_type(const FieldType& field_type) {
191
39.9k
    return field_type == FieldType::OLAP_FIELD_TYPE_VARCHAR ||
192
39.9k
           field_type == FieldType::OLAP_FIELD_TYPE_CHAR ||
193
39.9k
           field_type == FieldType::OLAP_FIELD_TYPE_STRING;
194
39.9k
}
195
196
// Util used to get string name of thrift enum item
197
#define EnumToString(enum_type, index, out)                   \
198
4.11k
    do {                                                      \
199
4.11k
        auto it = _##enum_type##_VALUES_TO_NAMES.find(index); \
200
4.11k
        if (it == _##enum_type##_VALUES_TO_NAMES.end()) {     \
201
0
            out = "NULL";                                     \
202
4.11k
        } else {                                              \
203
4.11k
            out = it->second;                                 \
204
4.11k
        }                                                     \
205
4.11k
    } while (0)
206
207
struct RowLocation {
208
4.86M
    RowLocation() : segment_id(0), row_id(0) {}
209
7
    RowLocation(uint32_t sid, uint32_t rid) : segment_id(sid), row_id(rid) {}
210
    RowLocation(RowsetId rsid, uint32_t sid, uint32_t rid)
211
7.69M
            : rowset_id(rsid), segment_id(sid), row_id(rid) {}
212
    RowsetId rowset_id;
213
    uint32_t segment_id;
214
    uint32_t row_id;
215
216
4
    bool operator==(const RowLocation& rhs) const {
217
4
        return rowset_id == rhs.rowset_id && segment_id == rhs.segment_id && row_id == rhs.row_id;
218
4
    }
219
220
9
    bool operator<(const RowLocation& rhs) const {
221
9
        if (rowset_id != rhs.rowset_id) {
222
0
            return rowset_id < rhs.rowset_id;
223
9
        } else if (segment_id != rhs.segment_id) {
224
0
            return segment_id < rhs.segment_id;
225
9
        } else {
226
9
            return row_id < rhs.row_id;
227
9
        }
228
9
    }
229
};
230
using RowLocationSet = std::set<RowLocation>;
231
using RowLocationPairList = std::list<std::pair<RowLocation, RowLocation>>;
232
233
// Wire-protocol values: never reorder or reuse an existing value. A new value may use a new
234
// encoded structure and size, provided its decoder keeps supporting all older values.
235
enum class ROW_VERSION : uint8_t {
236
    // The row ID is a uint32 ordinal local to the FileMapping identified by file_id.
237
    FILE_LOCAL_ROW_ID = 0,
238
    // The row ID is an opaque uint64 ID in a fixed Lance dataset snapshot.
239
    LANCE_DATASET_ROW_ID = 1,
240
};
241
242
/*
243
 * A serialized global row location has a fixed size of 24 bytes. The version determines how the
244
 * bytes at offsets 4..7 and 16..23 must be interpreted:
245
 *
246
 * FILE_LOCAL_ROW_ID (version = 0), used by Doris, Parquet, and ORC:
247
 *
248
 *   byte offset   0        1..7             8..15          16..19      20..23
249
 *               +--------+----------------+---------------+-----------+-----------+
250
 *               | ver=0  | reserved       | backend_id    | file_id   | row_id    |
251
 *               +--------+----------------+---------------+-----------+-----------+
252
 *                 uint8      7 bytes          int64          uint32      uint32
253
 *
254
 *   row_id is an ordinal local to the FileMapping selected by file_id.
255
 *
256
 * LANCE_DATASET_ROW_ID (version = 1), used by Lance:
257
 *
258
 *   byte offset   0        1..3       4..7          8..15          16..23
259
 *               +--------+----------+-------------+---------------+----------------+
260
 *               | ver=1  | reserved | file_id     | backend_id    | lance_row_id   |
261
 *               +--------+----------+-------------+---------------+----------------+
262
 *                 uint8     3 bytes     uint32        int64           uint64
263
 *
264
 *   lance_row_id is an opaque row ID in the fixed dataset snapshot recorded by the FileMapping.
265
 *
266
 * The first union reuses four bytes that are padding in version 0 as Lance's file_id in version 1.
267
 * The second union reuses the original {uint32 file_id, uint32 row_id} payload as one uint64 Lance
268
 * row ID. Therefore, always check version before reading either union.
269
 */
270
struct GlobalRowLoacationV2 {
271
    static constexpr uint8_t VERSION = static_cast<uint8_t>(ROW_VERSION::FILE_LOCAL_ROW_ID);
272
273
    struct FileLocalRowId {
274
        uint32_t file_id;
275
        uint32_t row_id;
276
    };
277
278
    GlobalRowLoacationV2(uint8_t ver, uint64_t bid, uint32_t fid, uint32_t rid)
279
558
            : version(ver),
280
558
              reserved_for_file_local(0),
281
558
              backend_id(bid),
282
558
              file_local {.file_id = fid, .row_id = rid} {}
283
    GlobalRowLoacationV2(ROW_VERSION ver, uint64_t bid, uint32_t fid, uint64_t rid)
284
21
            : version(static_cast<uint8_t>(ver)),
285
21
              lance_file_id(fid),
286
21
              backend_id(bid),
287
21
              lance_row_id(rid) {}
288
289
    uint8_t version;
290
    uint8_t reserved_before_file_id[3] {};
291
    union {
292
        // version 0: offsets 4..7 remain reserved, preserving the original V2 layout.
293
        uint32_t reserved_for_file_local;
294
        // version 1: offsets 4..7 identify the FileMapping for lance_row_id.
295
        uint32_t lance_file_id;
296
    };
297
    int64_t backend_id;
298
    union {
299
        // version 0: file_id is at offset 16 and its uint32 row ordinal is at offset 20.
300
        FileLocalRowId file_local;
301
        // version 1: offsets 16..23 are one opaque uint64 Lance row ID.
302
        uint64_t lance_row_id;
303
    };
304
};
305
306
static_assert(sizeof(GlobalRowLoacationV2) == 24);
307
static_assert(sizeof(GlobalRowLoacationV2::FileLocalRowId) == 8);
308
static_assert(offsetof(GlobalRowLoacationV2, version) == 0);
309
static_assert(offsetof(GlobalRowLoacationV2, reserved_before_file_id) == 1);
310
static_assert(offsetof(GlobalRowLoacationV2, reserved_for_file_local) == 4);
311
static_assert(offsetof(GlobalRowLoacationV2, lance_file_id) == 4);
312
static_assert(offsetof(GlobalRowLoacationV2, backend_id) == 8);
313
static_assert(offsetof(GlobalRowLoacationV2, file_local) == 16);
314
static_assert(offsetof(GlobalRowLoacationV2::FileLocalRowId, file_id) == 0);
315
static_assert(offsetof(GlobalRowLoacationV2::FileLocalRowId, row_id) == 4);
316
static_assert(offsetof(GlobalRowLoacationV2, lance_row_id) == 16);
317
318
} // namespace doris