Coverage Report

Created: 2026-09-02 17:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/root/doris/cloud/src/common/util.cpp
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
// clang-format off
19
#include "util.h"
20
21
#include <bthread/butex.h>
22
#include <butil/iobuf.h>
23
#include <google/protobuf/util/json_util.h>
24
#include <google/protobuf/util/field_mask_util.h>
25
26
// FIXME: we should not rely other modules that may rely on this common module
27
#include "common/logging.h"
28
#include "common/config.h"
29
#include "meta-store/keys.h"
30
#include "meta-store/codec.h"
31
#include "meta-store/txn_kv.h"
32
#include "meta-store/txn_kv_error.h"
33
34
#include <iomanip>
35
#include <sstream>
36
#include <unordered_map>
37
#include <variant>
38
// clang-format on
39
40
namespace doris::cloud {
41
42
/**
43
 * This is a naïve implementation of hex, DONOT use it on retical path.
44
 */
45
974k
std::string hex(std::string_view str) {
46
974k
    std::stringstream ss;
47
60.3M
    for (auto& i : str) {
48
60.3M
        ss << std::hex << std::setw(2) << std::setfill('0') << ((int16_t)i & 0xff);
49
60.3M
    }
50
974k
    return ss.str();
51
974k
}
52
53
/**
54
 * This is a naïve implementation of unhex.
55
 */
56
631
std::string unhex(std::string_view hex_str) {
57
    // clang-format off
58
631
    const static std::unordered_map<char, char> table = {
59
631
            {'0', 0},  {'1', 1},  {'2', 2},  {'3', 3},  {'4', 4}, 
60
631
            {'5', 5},  {'6', 6},  {'7', 7},  {'8', 8},  {'9', 9}, 
61
631
            {'a', 10}, {'b', 11}, {'c', 12}, {'d', 13}, {'e', 14}, {'f', 15},
62
631
            {'A', 10}, {'B', 11}, {'C', 12}, {'D', 13}, {'E', 14}, {'F', 15}};
63
631
    [[maybe_unused]] static int8_t lut[std::max({'9', 'f', 'F'}) + 1];
64
631
    lut[(int)'0'] = 0; lut[(int)'1'] = 1; lut[(int)'2'] = 2; lut[(int)'3'] = 3; lut[(int)'4'] = 4; lut[(int)'5'] = 5; lut[(int)'6'] = 6; lut[(int)'7'] = 7; lut[(int)'8'] = 8; lut[(int)'9'] = 9;
65
631
    lut[(int)'a'] = 10; lut[(int)'b'] = 11; lut[(int)'c'] = 12; lut[(int)'d'] = 13; lut[(int)'e'] = 14; lut[(int)'f'] = 15;
66
631
    lut[(int)'A'] = 10; lut[(int)'B'] = 11; lut[(int)'C'] = 12; lut[(int)'D'] = 13; lut[(int)'E'] = 14; lut[(int)'F'] = 15;
67
    // clang-format on
68
631
    size_t len = hex_str.length();
69
631
    len &= ~0x01UL;
70
631
    std::string buf(len >> 1, '\0');
71
17.7k
    for (size_t i = 0; i < len; ++i) {
72
17.0k
        const auto it = table.find(hex_str[i]);
73
17.0k
        if (it == table.end()) break;
74
17.0k
        buf[i >> 1] |= i & 0x1 ? (it->second & 0x0f) : (it->second & 0x0f) << 4;
75
17.0k
    }
76
631
    return buf;
77
631
}
78
79
static std::string explain_fields(std::string_view text, const std::vector<std::string>& fields,
80
63
                                  const std::vector<int>& pos, bool unicode = false) {
81
63
    if (fields.size() != pos.size() || fields.size() == 0 || pos.size() == 0) {
82
0
        return std::string(text.data(), text.size());
83
0
    }
84
63
    size_t last_hyphen_pos = pos.back() + 1;
85
63
    std::stringstream ss;
86
63
    std::string blank_line(last_hyphen_pos + 1, ' ');
87
88
    // clang-format off
89
63
    static const std::string hyphen("\xe2\x94\x80"); // ─ e2 94 80
90
63
    static const std::string bar   ("\xe2\x94\x82"); // │ e2 94 82
91
63
    static const std::string angle ("\xe2\x94\x8c"); // ┌ e2 94 8c
92
63
    static const std::string arrow ("\xe2\x96\xbc"); // ▼ e2 96 bc
93
    // clang-format on
94
95
    // Each line with hyphens
96
432
    for (size_t i = 0; i < fields.size(); ++i) {
97
369
        std::string line = blank_line;
98
369
        line[pos[i]] = '/';
99
369
        int nbar = i;
100
1.32k
        for (size_t j = 0; j < i; ++j) {
101
959
            line[pos[j]] = '|';
102
959
        }
103
369
        int nhyphen = 0;
104
21.0k
        for (size_t j = pos[i] + 1; j <= last_hyphen_pos; ++j) {
105
20.6k
            line[j] = '-';
106
20.6k
            ++nhyphen;
107
20.6k
        }
108
109
369
        if (unicode) {
110
351
            int i = line.size();
111
351
            line.resize(line.size() + 2 * (1 /*angle*/ + nbar + nhyphen), ' ');
112
351
            int j = line.size();
113
35.2k
            while (--i >= 0) {
114
34.8k
                if (line[i] == '-') {
115
19.7k
                    line[--j] = hyphen[2];
116
19.7k
                    line[--j] = hyphen[1];
117
19.7k
                    line[--j] = hyphen[0];
118
19.7k
                } else if (line[i] == '|') {
119
914
                    line[--j] = bar[2];
120
914
                    line[--j] = bar[1];
121
914
                    line[--j] = bar[0];
122
14.2k
                } else if (line[i] == '/') {
123
351
                    line[--j] = angle[2];
124
351
                    line[--j] = angle[1];
125
351
                    line[--j] = angle[0];
126
13.9k
                } else {
127
13.9k
                    --j;
128
13.9k
                    continue;
129
13.9k
                }
130
20.9k
                line[i] = i != j ? ' ' : line[i]; // Replace if needed
131
20.9k
            }
132
351
        }
133
134
369
        ss << line << " " << i << ". " << fields[i] << "\n";
135
369
    }
136
137
    // Mark position indicator
138
63
    std::string line = blank_line;
139
432
    for (size_t i = 0; i < fields.size(); ++i) {
140
369
        line[pos[i]] = '|';
141
369
    }
142
143
63
    if (unicode) {
144
60
        int i = line.size();
145
60
        line.resize(line.size() + 2 * fields.size(), ' ');
146
60
        int j = line.size();
147
5.58k
        while (--i >= 0) {
148
5.52k
            if (line[i] != '|') {
149
5.17k
                --j;
150
5.17k
                continue;
151
5.17k
            }
152
351
            line[--j] = bar[2];
153
351
            line[--j] = bar[1];
154
351
            line[--j] = bar[0];
155
351
            line[i] = i != j ? ' ' : line[i]; // Replace if needed
156
351
        }
157
60
    }
158
159
63
    ss << line << "\n";
160
161
63
    line = blank_line;
162
432
    for (size_t i = 0; i < fields.size(); ++i) {
163
369
        line[pos[i]] = 'v';
164
369
    }
165
166
63
    if (unicode) {
167
60
        int i = line.size();
168
60
        line.resize(line.size() + 2 * fields.size(), ' ');
169
60
        int j = line.size();
170
5.58k
        while (--i >= 0) {
171
5.52k
            if (line[i] != 'v') {
172
5.17k
                --j;
173
5.17k
                continue;
174
5.17k
            }
175
351
            line[--j] = arrow[2];
176
351
            line[--j] = arrow[1];
177
351
            line[--j] = arrow[0];
178
351
            line[i] = i != j ? ' ' : line[i]; // Replace if needed
179
351
        }
180
60
    }
181
182
63
    ss << line << "\n";
183
184
    // Original text to explain
185
63
    ss << text << "\n";
186
187
63
    return ss.str();
188
63
}
189
190
63
std::string prettify_key(std::string_view key_hex, bool unicode) {
191
    // Decoded result container
192
    //                                    val                  tag  pos
193
    //                     .---------------^----------------.  .^.  .^.
194
63
    std::vector<std::tuple<std::variant<int64_t, std::string>, int, int>> fields;
195
63
    std::string unhex_key = unhex(key_hex);
196
63
    int key_space = unhex_key[0];
197
63
    std::string_view key_copy = unhex_key;
198
63
    key_copy.remove_prefix(1); // Remove the first key space byte
199
63
    int ret = decode_key(&key_copy, &fields);
200
63
    if (ret != 0) return "";
201
202
63
    std::vector<std::string> fields_str;
203
63
    std::vector<int> fields_pos;
204
63
    fields_str.reserve(fields.size() + 1);
205
63
    fields_pos.reserve(fields.size() + 1);
206
    // Key space byte
207
63
    fields_str.push_back("key space: " + std::to_string(key_space));
208
63
    fields_pos.push_back(0);
209
210
306
    for (auto& i : fields) {
211
306
        if (std::get<1>(i) == EncodingTag::BYTES_TAG) {
212
200
            fields_str.emplace_back(std::get<std::string>(std::get<0>(i)));
213
200
        } else if (std::get<1>(i) == EncodingTag::VERSIONSTAMP_TAG) {
214
2
            fields_str.emplace_back("versionstamp: " + std::get<std::string>(std::get<0>(i)));
215
104
        } else {
216
104
            fields_str.emplace_back(std::to_string(std::get<int64_t>(std::get<0>(i))));
217
104
        }
218
306
        fields_pos.push_back((std::get<2>(i) + 1) * 2);
219
306
    }
220
221
63
    return explain_fields(key_hex, fields_str, fields_pos, unicode);
222
63
}
223
224
2.50k
std::string proto_to_json(const ::google::protobuf::Message& msg, bool add_whitespace) {
225
2.50k
    std::string json;
226
2.50k
    google::protobuf::util::JsonPrintOptions opts;
227
2.50k
    opts.add_whitespace = add_whitespace;
228
2.50k
    opts.preserve_proto_field_names = true;
229
2.50k
    google::protobuf::util::MessageToJsonString(msg, &json, opts);
230
2.50k
    return json;
231
2.50k
}
232
233
139k
TxnErrorCode key_exists(Transaction* txn, std::string_view key, bool snapshot) {
234
139k
    std::string end_key {key};
235
139k
    encode_int64(INT64_MAX, &end_key);
236
139k
    std::unique_ptr<RangeGetIterator> it;
237
139k
    TxnErrorCode err = txn->get(key, end_key, &it, snapshot, 1);
238
139k
    if (err != TxnErrorCode::TXN_OK) {
239
120
        return err;
240
120
    }
241
139k
    return it->has_next() ? TxnErrorCode::TXN_OK : TxnErrorCode::TXN_KEY_NOT_FOUND;
242
139k
}
243
244
} // namespace doris::cloud