Coverage Report

Created: 2026-05-17 03:05

/root/doris/cloud/src/common/configbase.cpp
Line
Count
Source (jump to first uncovered line)
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
#include <fmt/core.h>
19
#include <rapidjson/document.h>
20
#include <rapidjson/stringbuffer.h>
21
#include <rapidjson/writer.h>
22
23
#include <algorithm>
24
#include <cerrno>
25
#include <cstring>
26
#include <filesystem>
27
#include <fstream>
28
#include <iostream>
29
#include <list>
30
#include <map>
31
#include <mutex>
32
#include <shared_mutex>
33
#include <sstream>
34
#include <utility>
35
36
#define __IN_CONFIGBASE_CPP__
37
#include "common/config.h"
38
#undef __IN_CONFIGBASE_CPP__
39
40
namespace doris::cloud::config {
41
42
std::map<std::string, Register::Field>* Register::_s_field_map = nullptr;
43
std::map<std::string, std::function<bool()>>* RegisterConfValidator::_s_field_validator = nullptr;
44
std::map<std::string, std::string>* full_conf_map = nullptr;
45
std::shared_mutex mutable_string_config_lock;
46
std::mutex conf_persist_lock;
47
48
// trim string
49
4.86k
std::string& trim(std::string& s) {
50
    // rtrim
51
4.86k
    s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char c) { return !std::isspace(c); })
52
4.86k
                    .base(),
53
4.86k
            s.end());
54
    // ltrim
55
4.86k
    s.erase(s.begin(),
56
4.86k
            std::find_if(s.begin(), s.end(), [](unsigned char c) { return !std::isspace(c); }));
57
4.86k
    return s;
58
4.86k
}
59
60
// split string by '='
61
114
void splitkv(const std::string& s, std::string& k, std::string& v) {
62
114
    const char sep = '=';
63
114
    int start = 0;
64
114
    int end = 0;
65
114
    if ((end = s.find(sep, start)) != std::string::npos) {
66
114
        k = s.substr(start, end - start);
67
114
        v = s.substr(end + 1);
68
114
    } else {
69
0
        k = s;
70
0
        v = "";
71
0
    }
72
114
}
73
74
// replace env variables
75
4.11k
bool replaceenv(std::string& s) {
76
4.11k
    std::size_t pos = 0;
77
4.11k
    std::size_t start = 0;
78
4.11k
    while ((start = s.find("${", pos)) != std::string::npos) {
79
0
        std::size_t end = s.find("}", start + 2);
80
0
        if (end == std::string::npos) {
81
0
            return false;
82
0
        }
83
0
        std::string envkey = s.substr(start + 2, end - start - 2);
84
0
        const char* envval = std::getenv(envkey.c_str());
85
0
        if (envval == nullptr) {
86
0
            return false;
87
0
        }
88
0
        s.erase(start, end - start + 1);
89
0
        s.insert(start, envval);
90
0
        pos = start + strlen(envval);
91
0
    }
92
4.11k
    return true;
93
4.11k
}
94
95
bool strtox(const std::string& valstr, bool& retval);
96
bool strtox(const std::string& valstr, int16_t& retval);
97
bool strtox(const std::string& valstr, int32_t& retval);
98
bool strtox(const std::string& valstr, int64_t& retval);
99
bool strtox(const std::string& valstr, double& retval);
100
bool strtox(const std::string& valstr, std::string& retval);
101
102
template <typename T>
103
84
bool strtox(const std::string& valstr, std::vector<T>& retval) {
104
84
    std::stringstream ss(valstr);
105
84
    std::string item;
106
84
    T t;
107
84
    while (std::getline(ss, item, ',')) {
108
0
        if (!strtox(trim(item), t)) {
109
0
            return false;
110
0
        }
111
0
        retval.push_back(t);
112
0
    }
113
84
    return true;
114
84
}
Unexecuted instantiation: _ZN5doris5cloud6config6strtoxIbEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERSt6vectorIT_SaISC_EE
Unexecuted instantiation: _ZN5doris5cloud6config6strtoxIsEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERSt6vectorIT_SaISC_EE
Unexecuted instantiation: _ZN5doris5cloud6config6strtoxIiEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERSt6vectorIT_SaISC_EE
Unexecuted instantiation: _ZN5doris5cloud6config6strtoxIlEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERSt6vectorIT_SaISC_EE
Unexecuted instantiation: _ZN5doris5cloud6config6strtoxIdEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERSt6vectorIT_SaISC_EE
_ZN5doris5cloud6config6strtoxINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEbRKS8_RSt6vectorIT_SaISC_EE
Line
Count
Source
103
84
bool strtox(const std::string& valstr, std::vector<T>& retval) {
104
84
    std::stringstream ss(valstr);
105
84
    std::string item;
106
84
    T t;
107
84
    while (std::getline(ss, item, ',')) {
108
0
        if (!strtox(trim(item), t)) {
109
0
            return false;
110
0
        }
111
0
        retval.push_back(t);
112
0
    }
113
84
    return true;
114
84
}
115
116
1.36k
bool strtox(const std::string& valstr, bool& retval) {
117
1.36k
    if (valstr.compare("true") == 0) {
118
589
        retval = true;
119
779
    } else if (valstr.compare("false") == 0) {
120
779
        retval = false;
121
779
    } else {
122
0
        return false;
123
0
    }
124
1.36k
    return true;
125
1.36k
}
126
127
template <typename T>
128
1.77k
bool strtointeger(const std::string& valstr, T& retval) {
129
1.77k
    if (valstr.length() == 0) {
130
0
        return false; // empty-string is only allowed for string type.
131
0
    }
132
1.77k
    char* end;
133
1.77k
    errno = 0;
134
1.77k
    const char* valcstr = valstr.c_str();
135
1.77k
    int64_t ret64 = strtoll(valcstr, &end, 10);
136
1.77k
    if (errno || end != valcstr + strlen(valcstr)) {
137
0
        return false; // bad parse
138
0
    }
139
1.77k
    T tmp = retval;
140
1.77k
    retval = static_cast<T>(ret64);
141
1.77k
    if (retval != ret64) {
142
0
        retval = tmp;
143
0
        return false;
144
0
    }
145
1.77k
    return true;
146
1.77k
}
_ZN5doris5cloud6config12strtointegerIsEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_
Line
Count
Source
128
21
bool strtointeger(const std::string& valstr, T& retval) {
129
21
    if (valstr.length() == 0) {
130
0
        return false; // empty-string is only allowed for string type.
131
0
    }
132
21
    char* end;
133
21
    errno = 0;
134
21
    const char* valcstr = valstr.c_str();
135
21
    int64_t ret64 = strtoll(valcstr, &end, 10);
136
21
    if (errno || end != valcstr + strlen(valcstr)) {
137
0
        return false; // bad parse
138
0
    }
139
21
    T tmp = retval;
140
21
    retval = static_cast<T>(ret64);
141
21
    if (retval != ret64) {
142
0
        retval = tmp;
143
0
        return false;
144
0
    }
145
21
    return true;
146
21
}
_ZN5doris5cloud6config12strtointegerIiEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_
Line
Count
Source
128
966
bool strtointeger(const std::string& valstr, T& retval) {
129
966
    if (valstr.length() == 0) {
130
0
        return false; // empty-string is only allowed for string type.
131
0
    }
132
966
    char* end;
133
966
    errno = 0;
134
966
    const char* valcstr = valstr.c_str();
135
966
    int64_t ret64 = strtoll(valcstr, &end, 10);
136
966
    if (errno || end != valcstr + strlen(valcstr)) {
137
0
        return false; // bad parse
138
0
    }
139
966
    T tmp = retval;
140
966
    retval = static_cast<T>(ret64);
141
966
    if (retval != ret64) {
142
0
        retval = tmp;
143
0
        return false;
144
0
    }
145
966
    return true;
146
966
}
_ZN5doris5cloud6config12strtointegerIlEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_
Line
Count
Source
128
786
bool strtointeger(const std::string& valstr, T& retval) {
129
786
    if (valstr.length() == 0) {
130
0
        return false; // empty-string is only allowed for string type.
131
0
    }
132
786
    char* end;
133
786
    errno = 0;
134
786
    const char* valcstr = valstr.c_str();
135
786
    int64_t ret64 = strtoll(valcstr, &end, 10);
136
786
    if (errno || end != valcstr + strlen(valcstr)) {
137
0
        return false; // bad parse
138
0
    }
139
786
    T tmp = retval;
140
786
    retval = static_cast<T>(ret64);
141
786
    if (retval != ret64) {
142
0
        retval = tmp;
143
0
        return false;
144
0
    }
145
786
    return true;
146
786
}
147
148
21
bool strtox(const std::string& valstr, int16_t& retval) {
149
21
    return strtointeger(valstr, retval);
150
21
}
151
152
966
bool strtox(const std::string& valstr, int32_t& retval) {
153
966
    return strtointeger(valstr, retval);
154
966
}
155
156
786
bool strtox(const std::string& valstr, int64_t& retval) {
157
786
    return strtointeger(valstr, retval);
158
786
}
159
160
0
bool strtox(const std::string& valstr, double& retval) {
161
0
    if (valstr.length() == 0) {
162
0
        return false; // empty-string is only allowed for string type.
163
0
    }
164
0
    char* end = nullptr;
165
0
    errno = 0;
166
0
    const char* valcstr = valstr.c_str();
167
0
    retval = strtod(valcstr, &end);
168
0
    if (errno || end != valcstr + strlen(valcstr)) {
169
0
        return false; // bad parse
170
0
    }
171
0
    return true;
172
0
}
173
174
890
bool strtox(const std::string& valstr, std::string& retval) {
175
890
    retval = valstr;
176
890
    return true;
177
890
}
178
179
template <typename T>
180
4.11k
bool convert(const std::string& value, T& retval) {
181
4.11k
    std::string valstr(value);
182
4.11k
    trim(valstr);
183
4.11k
    if (!replaceenv(valstr)) {
184
0
        return false;
185
0
    }
186
4.11k
    return strtox(valstr, retval);
187
4.11k
}
Unexecuted instantiation: _ZN5doris5cloud6config7convertISt6vectorIbSaIbEEEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_
Unexecuted instantiation: _ZN5doris5cloud6config7convertISt6vectorIsSaIsEEEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_
Unexecuted instantiation: _ZN5doris5cloud6config7convertISt6vectorIiSaIiEEEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_
Unexecuted instantiation: _ZN5doris5cloud6config7convertISt6vectorIlSaIlEEEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_
Unexecuted instantiation: _ZN5doris5cloud6config7convertISt6vectorIdSaIdEEEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_
_ZN5doris5cloud6config7convertISt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS9_EEEEbRKS9_RT_
Line
Count
Source
180
84
bool convert(const std::string& value, T& retval) {
181
84
    std::string valstr(value);
182
84
    trim(valstr);
183
84
    if (!replaceenv(valstr)) {
184
0
        return false;
185
0
    }
186
84
    return strtox(valstr, retval);
187
84
}
_ZN5doris5cloud6config7convertIbEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_
Line
Count
Source
180
1.36k
bool convert(const std::string& value, T& retval) {
181
1.36k
    std::string valstr(value);
182
1.36k
    trim(valstr);
183
1.36k
    if (!replaceenv(valstr)) {
184
0
        return false;
185
0
    }
186
1.36k
    return strtox(valstr, retval);
187
1.36k
}
_ZN5doris5cloud6config7convertIsEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_
Line
Count
Source
180
21
bool convert(const std::string& value, T& retval) {
181
21
    std::string valstr(value);
182
21
    trim(valstr);
183
21
    if (!replaceenv(valstr)) {
184
0
        return false;
185
0
    }
186
21
    return strtox(valstr, retval);
187
21
}
_ZN5doris5cloud6config7convertIiEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_
Line
Count
Source
180
966
bool convert(const std::string& value, T& retval) {
181
966
    std::string valstr(value);
182
966
    trim(valstr);
183
966
    if (!replaceenv(valstr)) {
184
0
        return false;
185
0
    }
186
966
    return strtox(valstr, retval);
187
966
}
_ZN5doris5cloud6config7convertIlEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_
Line
Count
Source
180
786
bool convert(const std::string& value, T& retval) {
181
786
    std::string valstr(value);
182
786
    trim(valstr);
183
786
    if (!replaceenv(valstr)) {
184
0
        return false;
185
0
    }
186
786
    return strtox(valstr, retval);
187
786
}
Unexecuted instantiation: _ZN5doris5cloud6config7convertIdEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_
_ZN5doris5cloud6config7convertINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEbRKS8_RT_
Line
Count
Source
180
890
bool convert(const std::string& value, T& retval) {
181
890
    std::string valstr(value);
182
890
    trim(valstr);
183
890
    if (!replaceenv(valstr)) {
184
0
        return false;
185
0
    }
186
890
    return strtox(valstr, retval);
187
890
}
188
189
// load conf file
190
25
bool Properties::load(const char* conf_file, bool must_exist) {
191
    // if conf_file is null, use the empty props
192
25
    if (conf_file == nullptr) {
193
7
        return true;
194
7
    }
195
196
    // open the conf file
197
18
    std::ifstream input(conf_file);
198
18
    if (!input.is_open()) {
199
0
        if (must_exist) {
200
0
            std::cerr << "config::load() failed to open the file:" << conf_file << std::endl;
201
0
            return false;
202
0
        }
203
0
        return true;
204
0
    }
205
206
    // load properties
207
18
    std::string line;
208
18
    std::string key;
209
18
    std::string value;
210
18
    line.reserve(512);
211
512
    while (input) {
212
        // read one line at a time
213
494
        std::getline(input, line);
214
215
        // remove left and right spaces
216
494
        trim(line);
217
218
        // ignore comments
219
494
        if (line.empty() || line[0] == '#') {
220
380
            continue;
221
380
        }
222
223
        // read key and value
224
114
        splitkv(line, key, value);
225
114
        trim(key);
226
114
        trim(value);
227
228
        // insert into file_conf_map
229
114
        file_conf_map[key] = value;
230
114
    }
231
232
    // close the conf file
233
18
    input.close();
234
235
18
    return true;
236
18
}
237
238
5
bool Properties::dump(const std::string& conffile) {
239
5
    std::string conffile_tmp = conffile + ".tmp";
240
241
5
    if (std::filesystem::exists(conffile)) {
242
        // copy for modify
243
4
        std::ifstream in(conffile, std::ios::binary);
244
4
        std::ofstream out(conffile_tmp, std::ios::binary);
245
4
        out << in.rdbuf();
246
4
        in.close();
247
4
        out.close();
248
4
    }
249
250
5
    std::ofstream file_writer;
251
252
5
    file_writer.open(conffile_tmp, std::ios::out | std::ios::app);
253
254
5
    file_writer << std::endl;
255
256
6
    for (auto const& iter : file_conf_map) {
257
6
        file_writer << iter.first << " = " << iter.second << std::endl;
258
6
    }
259
260
5
    file_writer.close();
261
5
    if (!file_writer.good()) {
262
0
        return false;
263
0
    }
264
265
5
    std::filesystem::rename(conffile_tmp, conffile);
266
5
    return std::filesystem::exists(conffile);
267
5
}
268
269
template <typename T>
270
bool Properties::get_or_default(const char* key, const char* defstr, T& retval,
271
4.10k
                                bool* is_retval_set) const {
272
4.10k
    const auto& it = file_conf_map.find(std::string(key));
273
4.10k
    std::string valstr;
274
4.10k
    if (it == file_conf_map.end()) {
275
3.99k
        if (defstr == nullptr) {
276
            // Not found in conf map, and no default value need to be set, just return
277
0
            *is_retval_set = false;
278
0
            return true;
279
3.99k
        } else {
280
3.99k
            valstr = std::string(defstr);
281
3.99k
        }
282
3.99k
    } else {
283
106
        valstr = it->second;
284
106
    }
285
4.10k
    *is_retval_set = true;
286
4.10k
    return convert(valstr, retval);
287
4.10k
}
_ZNK5doris5cloud6config10Properties14get_or_defaultIbEEbPKcS5_RT_Pb
Line
Count
Source
271
1.36k
                                bool* is_retval_set) const {
272
1.36k
    const auto& it = file_conf_map.find(std::string(key));
273
1.36k
    std::string valstr;
274
1.36k
    if (it == file_conf_map.end()) {
275
1.36k
        if (defstr == nullptr) {
276
            // Not found in conf map, and no default value need to be set, just return
277
0
            *is_retval_set = false;
278
0
            return true;
279
1.36k
        } else {
280
1.36k
            valstr = std::string(defstr);
281
1.36k
        }
282
1.36k
    } else {
283
1
        valstr = it->second;
284
1
    }
285
1.36k
    *is_retval_set = true;
286
1.36k
    return convert(valstr, retval);
287
1.36k
}
_ZNK5doris5cloud6config10Properties14get_or_defaultIsEEbPKcS5_RT_Pb
Line
Count
Source
271
21
                                bool* is_retval_set) const {
272
21
    const auto& it = file_conf_map.find(std::string(key));
273
21
    std::string valstr;
274
21
    if (it == file_conf_map.end()) {
275
21
        if (defstr == nullptr) {
276
            // Not found in conf map, and no default value need to be set, just return
277
0
            *is_retval_set = false;
278
0
            return true;
279
21
        } else {
280
21
            valstr = std::string(defstr);
281
21
        }
282
21
    } else {
283
0
        valstr = it->second;
284
0
    }
285
21
    *is_retval_set = true;
286
21
    return convert(valstr, retval);
287
21
}
_ZNK5doris5cloud6config10Properties14get_or_defaultIiEEbPKcS5_RT_Pb
Line
Count
Source
271
966
                                bool* is_retval_set) const {
272
966
    const auto& it = file_conf_map.find(std::string(key));
273
966
    std::string valstr;
274
966
    if (it == file_conf_map.end()) {
275
938
        if (defstr == nullptr) {
276
            // Not found in conf map, and no default value need to be set, just return
277
0
            *is_retval_set = false;
278
0
            return true;
279
938
        } else {
280
938
            valstr = std::string(defstr);
281
938
        }
282
938
    } else {
283
28
        valstr = it->second;
284
28
    }
285
966
    *is_retval_set = true;
286
966
    return convert(valstr, retval);
287
966
}
_ZNK5doris5cloud6config10Properties14get_or_defaultIlEEbPKcS5_RT_Pb
Line
Count
Source
271
781
                                bool* is_retval_set) const {
272
781
    const auto& it = file_conf_map.find(std::string(key));
273
781
    std::string valstr;
274
781
    if (it == file_conf_map.end()) {
275
763
        if (defstr == nullptr) {
276
            // Not found in conf map, and no default value need to be set, just return
277
0
            *is_retval_set = false;
278
0
            return true;
279
763
        } else {
280
763
            valstr = std::string(defstr);
281
763
        }
282
763
    } else {
283
18
        valstr = it->second;
284
18
    }
285
781
    *is_retval_set = true;
286
781
    return convert(valstr, retval);
287
781
}
Unexecuted instantiation: _ZNK5doris5cloud6config10Properties14get_or_defaultIdEEbPKcS5_RT_Pb
_ZNK5doris5cloud6config10Properties14get_or_defaultINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEbPKcSB_RT_Pb
Line
Count
Source
271
885
                                bool* is_retval_set) const {
272
885
    const auto& it = file_conf_map.find(std::string(key));
273
885
    std::string valstr;
274
885
    if (it == file_conf_map.end()) {
275
826
        if (defstr == nullptr) {
276
            // Not found in conf map, and no default value need to be set, just return
277
0
            *is_retval_set = false;
278
0
            return true;
279
826
        } else {
280
826
            valstr = std::string(defstr);
281
826
        }
282
826
    } else {
283
59
        valstr = it->second;
284
59
    }
285
885
    *is_retval_set = true;
286
885
    return convert(valstr, retval);
287
885
}
Unexecuted instantiation: _ZNK5doris5cloud6config10Properties14get_or_defaultISt6vectorIbSaIbEEEEbPKcS8_RT_Pb
Unexecuted instantiation: _ZNK5doris5cloud6config10Properties14get_or_defaultISt6vectorIsSaIsEEEEbPKcS8_RT_Pb
Unexecuted instantiation: _ZNK5doris5cloud6config10Properties14get_or_defaultISt6vectorIiSaIiEEEEbPKcS8_RT_Pb
Unexecuted instantiation: _ZNK5doris5cloud6config10Properties14get_or_defaultISt6vectorIlSaIlEEEEbPKcS8_RT_Pb
Unexecuted instantiation: _ZNK5doris5cloud6config10Properties14get_or_defaultISt6vectorIdSaIdEEEEbPKcS8_RT_Pb
_ZNK5doris5cloud6config10Properties14get_or_defaultISt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISA_EEEEbPKcSE_RT_Pb
Line
Count
Source
271
84
                                bool* is_retval_set) const {
272
84
    const auto& it = file_conf_map.find(std::string(key));
273
84
    std::string valstr;
274
84
    if (it == file_conf_map.end()) {
275
84
        if (defstr == nullptr) {
276
            // Not found in conf map, and no default value need to be set, just return
277
0
            *is_retval_set = false;
278
0
            return true;
279
84
        } else {
280
84
            valstr = std::string(defstr);
281
84
        }
282
84
    } else {
283
0
        valstr = it->second;
284
0
    }
285
84
    *is_retval_set = true;
286
84
    return convert(valstr, retval);
287
84
}
288
289
0
void Properties::set(const std::string& key, const std::string& val) {
290
0
    file_conf_map.emplace(key, val);
291
0
}
292
293
6
void Properties::set_force(const std::string& key, const std::string& val) {
294
6
    file_conf_map[key] = val;
295
6
}
296
297
template <typename T>
298
84
std::ostream& operator<<(std::ostream& out, const std::vector<T>& v) {
299
84
    size_t last = v.size() - 1;
300
84
    for (size_t i = 0; i < v.size(); ++i) {
301
0
        out << v[i];
302
0
        if (i != last) {
303
0
            out << ", ";
304
0
        }
305
0
    }
306
84
    return out;
307
84
}
Unexecuted instantiation: _ZN5doris5cloud6configlsIbEERSoS3_RKSt6vectorIT_SaIS5_EE
Unexecuted instantiation: _ZN5doris5cloud6configlsIsEERSoS3_RKSt6vectorIT_SaIS5_EE
Unexecuted instantiation: _ZN5doris5cloud6configlsIiEERSoS3_RKSt6vectorIT_SaIS5_EE
Unexecuted instantiation: _ZN5doris5cloud6configlsIlEERSoS3_RKSt6vectorIT_SaIS5_EE
Unexecuted instantiation: _ZN5doris5cloud6configlsIdEERSoS3_RKSt6vectorIT_SaIS5_EE
_ZN5doris5cloud6configlsINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEERSoS9_RKSt6vectorIT_SaISB_EE
Line
Count
Source
298
84
std::ostream& operator<<(std::ostream& out, const std::vector<T>& v) {
299
84
    size_t last = v.size() - 1;
300
84
    for (size_t i = 0; i < v.size(); ++i) {
301
0
        out << v[i];
302
0
        if (i != last) {
303
0
            out << ", ";
304
0
        }
305
0
    }
306
84
    return out;
307
84
}
308
309
#define SET_FIELD(FIELD, TYPE, FILL_CONF_MAP, SET_TO_DEFAULT)                                  \
310
13.7k
    if (strcmp((FIELD).type, #TYPE) == 0) {                                                    \
311
4.09k
        TYPE new_value = TYPE();                                                               \
312
4.09k
        bool is_newval_set = false;                                                            \
313
4.09k
        if (!props.get_or_default((FIELD).name, ((SET_TO_DEFAULT) ? (FIELD).defval : nullptr), \
314
4.09k
                                  new_value, &is_newval_set)) {                                \
315
0
            std::cerr << "config field error: " << (FIELD).name << std::endl;                  \
316
0
            return false;                                                                      \
317
0
        }                                                                                      \
318
4.09k
        if (!is_newval_set) {                                                                  \
319
0
            continue;                                                                          \
320
0
        }                                                                                      \
321
4.09k
        TYPE& ref_conf_value = *reinterpret_cast<TYPE*>((FIELD).storage);                      \
322
4.09k
        TYPE old_value = ref_conf_value;                                                       \
323
4.09k
        ref_conf_value = new_value;                                                            \
324
4.09k
        if (RegisterConfValidator::_s_field_validator != nullptr) {                            \
325
4.09k
            auto validator = RegisterConfValidator::_s_field_validator->find((FIELD).name);    \
326
4.09k
            if (validator != RegisterConfValidator::_s_field_validator->end() &&               \
327
4.09k
                !(validator->second)()) {                                                      \
328
0
                ref_conf_value = old_value;                                                    \
329
0
                std::cerr << "validate " << (FIELD).name << "=" << new_value << " failed"      \
330
0
                          << std::endl;                                                        \
331
0
                return false;                                                                  \
332
0
            }                                                                                  \
333
4.09k
        }                                                                                      \
334
4.09k
        if (FILL_CONF_MAP) {                                                                   \
335
4.09k
            std::ostringstream oss;                                                            \
336
4.09k
            oss << ref_conf_value;                                                             \
337
4.09k
            (*full_conf_map)[(FIELD).name] = oss.str();                                        \
338
4.09k
        }                                                                                      \
339
4.09k
        continue;                                                                              \
340
4.09k
    }
341
342
#define UPDATE_FIELD(FIELD, VALUE, TYPE, PERSIST)                                           \
343
52
    if (strcmp((FIELD).type, #TYPE) == 0) {                                                 \
344
12
        TYPE new_value;                                                                     \
345
12
        if (!convert((VALUE), new_value)) {                                                 \
346
0
            std::cerr << "convert " << VALUE << "as" << #TYPE << "failed";                  \
347
0
            return false;                                                                   \
348
0
        }                                                                                   \
349
12
        TYPE& ref_conf_value = *reinterpret_cast<TYPE*>((FIELD).storage);                   \
350
12
        TYPE old_value = ref_conf_value;                                                    \
351
12
        if (RegisterConfValidator::_s_field_validator != nullptr) {                         \
352
12
            auto validator = RegisterConfValidator::_s_field_validator->find((FIELD).name); \
353
12
            if (validator != RegisterConfValidator::_s_field_validator->end() &&            \
354
12
                !(validator->second)()) {                                                   \
355
0
                ref_conf_value = old_value;                                                 \
356
0
                std::cerr << "validate " << (FIELD).name << "=" << new_value << " failed"   \
357
0
                          << std::endl;                                                     \
358
0
                return false;                                                               \
359
0
            }                                                                               \
360
12
        }                                                                                   \
361
12
        ref_conf_value = new_value;                                                         \
362
12
        if (full_conf_map != nullptr) {                                                     \
363
12
            std::ostringstream oss;                                                         \
364
12
            oss << new_value;                                                               \
365
12
            (*full_conf_map)[(FIELD).name] = oss.str();                                     \
366
12
        }                                                                                   \
367
12
        if (PERSIST) {                                                                      \
368
6
            props.set_force(std::string((FIELD).name), VALUE);                              \
369
6
        }                                                                                   \
370
12
        return true;                                                                        \
371
12
    }
372
373
// init conf fields
374
21
bool init(const char* conf_file, bool fill_conf_map, bool must_exist, bool set_to_default) {
375
21
    Properties props;
376
    // load properties file
377
21
    if (!props.load(conf_file, must_exist)) {
378
0
        return false;
379
0
    }
380
    // fill full_conf_map ?
381
21
    if (fill_conf_map && full_conf_map == nullptr) {
382
21
        full_conf_map = new std::map<std::string, std::string>();
383
21
    }
384
385
    // set conf fields
386
4.09k
    for (const auto& it : *Register::_s_field_map) {
387
4.09k
        SET_FIELD(it.second, bool, fill_conf_map, set_to_default);
388
2.73k
        SET_FIELD(it.second, int16_t, fill_conf_map, set_to_default);
389
2.70k
        SET_FIELD(it.second, int32_t, fill_conf_map, set_to_default);
390
1.74k
        SET_FIELD(it.second, int64_t, fill_conf_map, set_to_default);
391
966
        SET_FIELD(it.second, double, fill_conf_map, set_to_default);
392
966
        SET_FIELD(it.second, std::string, fill_conf_map, set_to_default);
393
84
        SET_FIELD(it.second, std::vector<bool>, fill_conf_map, set_to_default);
394
84
        SET_FIELD(it.second, std::vector<int16_t>, fill_conf_map, set_to_default);
395
84
        SET_FIELD(it.second, std::vector<int32_t>, fill_conf_map, set_to_default);
396
84
        SET_FIELD(it.second, std::vector<int64_t>, fill_conf_map, set_to_default);
397
84
        SET_FIELD(it.second, std::vector<double>, fill_conf_map, set_to_default);
398
84
        SET_FIELD(it.second, std::vector<std::string>, fill_conf_map, set_to_default);
399
0
    }
400
401
21
    return true;
402
21
}
403
404
bool do_set_config(const Register::Field& feild, const std::string& value, bool need_persist,
405
12
                   Properties& props) {
406
12
    UPDATE_FIELD(feild, value, bool, need_persist);
407
10
    UPDATE_FIELD(feild, value, int16_t, need_persist);
408
10
    UPDATE_FIELD(feild, value, int32_t, need_persist);
409
10
    UPDATE_FIELD(feild, value, int64_t, need_persist);
410
5
    UPDATE_FIELD(feild, value, double, need_persist);
411
5
    {
412
        // add lock to ensure thread safe
413
5
        std::unique_lock<std::shared_mutex> lock(mutable_string_config_lock);
414
5
        UPDATE_FIELD(feild, value, std::string, need_persist);
415
0
    }
416
0
    return false;
417
5
}
418
419
std::pair<bool, std::string> set_config(const std::string& field, const std::string& value,
420
14
                                        bool need_persist, Properties& props) {
421
14
    auto it = Register::_s_field_map->find(field);
422
14
    if (it == Register::_s_field_map->end()) {
423
1
        return {false, fmt::format("config field={} not exists", field)};
424
1
    }
425
13
    if (!it->second.valmutable) {
426
1
        return {false, fmt::format("config field={} is immutable", field)};
427
1
    }
428
429
12
    if (!do_set_config(it->second, value, need_persist, props)) {
430
0
        return {false, fmt::format("not supported to modify field={}, value={}", field, value)};
431
0
    }
432
12
    return {true, {}};
433
12
}
434
435
std::pair<bool, std::string> set_config(std::unordered_map<std::string, std::string> field_map,
436
12
                                        bool need_persist, const std::string& custom_conf_path) {
437
12
    Properties props;
438
12
    auto set_conf_closure = [&]() -> std::pair<bool, std::string> {
439
14
        for (const auto& [field, value] : field_map) {
440
14
            if (auto [succ, cause] = set_config(field, value, need_persist, props); !succ) {
441
2
                return {false, std::move(cause)};
442
2
            }
443
14
        }
444
10
        return {true, {}};
445
12
    };
446
447
12
    if (!need_persist) {
448
7
        return set_conf_closure();
449
7
    }
450
451
    // lock to make sure only one thread can modify the conf file
452
5
    std::lock_guard<std::mutex> l(conf_persist_lock);
453
5
    auto [succ, cause] = set_conf_closure();
454
5
    if (!succ) {
455
0
        return {succ, std::move(cause)};
456
0
    }
457
5
    if (props.dump(custom_conf_path)) {
458
5
        return {true, {}};
459
5
    }
460
0
    return {false, fmt::format("dump config modification to custom_conf_path={} "
461
0
                               "failed, plz check config::custom_conf_path and io status",
462
0
                               custom_conf_path)};
463
5
}
464
465
795
std::shared_mutex* get_mutable_string_config_lock() {
466
795
    return &mutable_string_config_lock;
467
795
}
468
469
2
std::string show_config(const std::string& conf_name) {
470
2
    if (full_conf_map == nullptr) {
471
0
        return "";
472
0
    }
473
474
2
    rapidjson::Document doc;
475
2
    doc.SetArray();
476
2
    auto& allocator = doc.GetAllocator();
477
390
    for (auto& [name, field] : *Register::_s_field_map) {
478
390
        if (!conf_name.empty() && name != conf_name) {
479
388
            continue;
480
388
        }
481
2
        auto it = full_conf_map->find(name);
482
2
        std::string value = (it != full_conf_map->end()) ? it->second : "";
483
484
2
        rapidjson::Value item(rapidjson::kArrayType);
485
2
        item.PushBack(rapidjson::Value(name.data(), name.size(), allocator), allocator);
486
2
        item.PushBack(rapidjson::Value(field.type, allocator), allocator);
487
2
        item.PushBack(rapidjson::Value(value.data(), value.size(), allocator), allocator);
488
2
        item.PushBack(field.valmutable, allocator);
489
2
        doc.PushBack(item, allocator);
490
2
    }
491
492
2
    rapidjson::StringBuffer sb;
493
2
    rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
494
2
    doc.Accept(writer);
495
2
    return sb.GetString();
496
2
}
497
498
std::pair<bool, std::string> update_config(const std::string& configs, bool persist,
499
13
                                           const std::string& custom_conf_path) {
500
13
    if (configs.empty()) {
501
2
        return {false, "query param `configs` should not be empty"};
502
2
    }
503
504
11
    std::unordered_map<std::string, std::string> conf_map;
505
11
    std::istringstream ss(configs);
506
11
    std::string conf;
507
23
    while (std::getline(ss, conf, ',')) {
508
13
        auto pos = conf.find('=');
509
13
        if (pos == std::string::npos) {
510
1
            return {false, fmt::format("config {} is invalid", conf)};
511
1
        }
512
12
        std::string key = conf.substr(0, pos);
513
12
        std::string val = conf.substr(pos + 1);
514
12
        trim(key);
515
12
        trim(val);
516
12
        conf_map.emplace(std::move(key), std::move(val));
517
12
    }
518
519
10
    return set_config(std::move(conf_map), persist, custom_conf_path);
520
11
}
521
522
} // namespace doris::cloud::config