1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 
16 #include "db_config.h"
17 
18 #include <algorithm>
19 #include <cstring>
20 #include <functional>
21 #include <memory>
22 
23 #include "doc_errno.h"
24 #include "doc_limit.h"
25 #include "rd_json_object.h"
26 #include "rd_log_print.h"
27 
28 namespace DocumentDB {
29 namespace {
30 constexpr int MIN_REDO_BUFFER_SIZE = 256;
31 constexpr int MAX_REDO_BUFFER_SIZE = 16384;
32 constexpr int MIN_CONNECTION_NUM = 16;
33 constexpr int MAX_CONNECTION_NUM = 1024;
34 constexpr int MIN_BUFFER_POOL_SIZE = 1024;
35 constexpr int MAX_BUFFER_POOL_SIZE = 4 * 1024 * 1024;
36 
37 constexpr const char *DB_CONFIG_PAGESIZE = "pagesize";
38 constexpr const char *DB_CONFIG_REDO_FLUSH_BY_TRX = "redoflushbytrx";
39 constexpr const char *DB_CONFIG_REDO_PUB_BUFF_SIZE = "redopubbufsize";
40 constexpr const char *DB_CONFIG_MAX_CONN_NUM = "maxconnnum";
41 constexpr const char *DB_CONFIG_BUFFER_POOL_SIZE = "bufferpoolsize";
42 constexpr const char *DB_CONFIG_CRC_CHECK_ENABLE = "crccheckenable";
43 constexpr const char *DB_CONFIG_BUFFPOOL_POLICY = "bufferpoolpolicy";
44 constexpr const char *DB_CONFIG_SHARED_MODE = "sharedmodeenable";
45 
46 constexpr const char *DB_CONFIG[] = { DB_CONFIG_PAGESIZE, DB_CONFIG_REDO_FLUSH_BY_TRX,
47     DB_CONFIG_REDO_PUB_BUFF_SIZE, DB_CONFIG_MAX_CONN_NUM, DB_CONFIG_BUFFER_POOL_SIZE, DB_CONFIG_CRC_CHECK_ENABLE,
48     DB_CONFIG_BUFFPOOL_POLICY, DB_CONFIG_SHARED_MODE};
49 
50 template<typename T>
CheckAndGetDBConfig(const JsonObject & config,const std::string & name,const std::function<bool (T)> & checkValid,T & val)51 bool CheckAndGetDBConfig(const JsonObject &config, const std::string &name, const std::function<bool(T)> &checkValid,
52     T &val)
53 {
54     const JsonFieldPath configField = { name };
55     if (!config.IsFieldExists(configField)) {
56         return true;
57     }
58 
59     int errCode = E_OK;
60     ValueObject configValue = config.GetObjectByPath(configField, errCode);
61     if (errCode != E_OK) {
62         GLOGE("Can not find config Value");
63         return errCode;
64     }
65     if (configValue.GetValueType() != ValueObject::ValueType::VALUE_NUMBER) {
66         GLOGE("Check DB config failed, not found or type of %s is not NUMBER.", name.c_str());
67         return false;
68     }
69 
70     if (checkValid && !checkValid(static_cast<T>(configValue.GetIntValue()))) {
71         GLOGE("Check DB config failed, invalid %s value.", name.c_str());
72         return false;
73     }
74 
75     val = static_cast<T>(configValue.GetIntValue());
76     return true;
77 }
78 
CheckPageSizeConfig(const JsonObject & config,int32_t & pageSize)79 bool CheckPageSizeConfig(const JsonObject &config, int32_t &pageSize)
80 {
81     std::function<bool(int32_t)> checkFunction = [](int32_t val) {
82         static const std::vector<int32_t> pageSizeValid = { 4, 8, 16, 32, 64 };
83         return std::find(pageSizeValid.begin(), pageSizeValid.end(), val) != pageSizeValid.end();
84     };
85     return CheckAndGetDBConfig(config, DB_CONFIG_PAGESIZE, checkFunction, pageSize);
86 }
87 
CheckRedoFlushConfig(const JsonObject & config,uint32_t & redoFlush)88 bool CheckRedoFlushConfig(const JsonObject &config, uint32_t &redoFlush)
89 {
90     std::function<bool(uint32_t)> checkFunction = [](uint32_t val) {
91         return val == 0 || val == 1;
92     };
93     return CheckAndGetDBConfig(config, DB_CONFIG_REDO_FLUSH_BY_TRX, checkFunction, redoFlush);
94 }
95 
CheckRedoBufSizeConfig(const JsonObject & config,int32_t pageSize,uint32_t & redoBufSize)96 bool CheckRedoBufSizeConfig(const JsonObject &config, int32_t pageSize, uint32_t &redoBufSize)
97 {
98     std::function<bool(uint32_t)> checkFunction = [pageSize](uint32_t val) {
99         return val >= MIN_REDO_BUFFER_SIZE && val <= MAX_REDO_BUFFER_SIZE &&
100             val > static_cast<uint32_t>(pageSize * 63); // 63: pool size should be 63 times larger then pageSize
101     };
102     return CheckAndGetDBConfig(config, DB_CONFIG_REDO_PUB_BUFF_SIZE, checkFunction, redoBufSize);
103 }
104 
CheckMaxConnNumConfig(const JsonObject & config,int32_t & maxConnNum)105 bool CheckMaxConnNumConfig(const JsonObject &config, int32_t &maxConnNum)
106 {
107     std::function<bool(int32_t)> checkFunction = [](int32_t val) {
108         return val >= MIN_CONNECTION_NUM && val <= MAX_CONNECTION_NUM;
109     };
110     return CheckAndGetDBConfig(config, DB_CONFIG_MAX_CONN_NUM, checkFunction, maxConnNum);
111 }
112 
CheckBufferPoolSizeConfig(const JsonObject & config,int32_t pageSize,uint32_t & redoBufSize)113 bool CheckBufferPoolSizeConfig(const JsonObject &config, int32_t pageSize, uint32_t &redoBufSize)
114 {
115     std::function<bool(uint32_t)> checkFunction = [pageSize](uint32_t val) {
116         return val >= MIN_BUFFER_POOL_SIZE && val <= MAX_BUFFER_POOL_SIZE &&
117             val >= static_cast<uint32_t>(pageSize * 64); // 64: pool size should be 64 times larger then pageSize
118     };
119     return CheckAndGetDBConfig(config, DB_CONFIG_BUFFER_POOL_SIZE, checkFunction, redoBufSize);
120 }
121 
CheckCrcCheckEnableConfig(const JsonObject & config,uint32_t & crcCheckEnable)122 bool CheckCrcCheckEnableConfig(const JsonObject &config, uint32_t &crcCheckEnable)
123 {
124     std::function<bool(uint32_t)> checkFunction = [](uint32_t val) {
125         return val == 0 || val == 1;
126     };
127     return CheckAndGetDBConfig(config, DB_CONFIG_CRC_CHECK_ENABLE, checkFunction, crcCheckEnable);
128 }
129 
CheckShareModeConfig(const JsonObject & config,uint32_t & shareModeCheckEnable)130 bool CheckShareModeConfig(const JsonObject &config, uint32_t &shareModeCheckEnable)
131 {
132     std::function<bool(uint32_t)> checkFunction = [](uint32_t val) {
133         return val == 0;
134     };
135     return CheckAndGetDBConfig(config, DB_CONFIG_SHARED_MODE, checkFunction, shareModeCheckEnable);
136 }
137 
IsDbconfigValid(const JsonObject & config)138 int IsDbconfigValid(const JsonObject &config)
139 {
140     JsonObject child = config.GetChild();
141     while (!child.IsNull()) {
142         std::string fieldName = child.GetItemField();
143         bool isSupport = false;
144         for (uint32_t i = 0; i < sizeof(DB_CONFIG) / sizeof(char *); i++) {
145             if (strcmp(DB_CONFIG[i], fieldName.c_str()) == 0) {
146                 isSupport = true;
147                 break;
148             }
149         }
150 
151         if (!isSupport) {
152             GLOGE("Invalid db config");
153             return -E_INVALID_CONFIG_VALUE;
154         }
155 
156         child = child.GetNext();
157     }
158     return E_OK;
159 }
160 } // namespace
161 
GetDBConfigFromJsonStr(const std::string & confStr,int & errCode)162 DBConfig DBConfig::GetDBConfigFromJsonStr(const std::string &confStr, int &errCode)
163 {
164     JsonObject dbConfig = JsonObject::Parse(confStr, errCode);
165     if (errCode != E_OK) {
166         GLOGE("Read DB config failed from str. %d", errCode);
167         return {};
168     }
169 
170     errCode = IsDbconfigValid(dbConfig);
171     if (errCode != E_OK) {
172         GLOGE("Check DB config, not support config item. %d", errCode);
173         return {};
174     }
175 
176     DBConfig conf;
177     if (!CheckPageSizeConfig(dbConfig, conf.pageSize_)) {
178         GLOGE("Check DB config 'pageSize' failed.");
179         errCode = -E_INVALID_CONFIG_VALUE;
180         return {};
181     }
182 
183     if (!CheckRedoFlushConfig(dbConfig, conf.redoFlushByTrx_)) {
184         GLOGE("Check DB config 'redoFlushByTrx' failed.");
185         errCode = -E_INVALID_CONFIG_VALUE;
186         return {};
187     }
188 
189     if (!CheckRedoBufSizeConfig(dbConfig, conf.pageSize_, conf.redoPubBufSize_)) {
190         GLOGE("Check DB config 'redoPubBufSize' failed.");
191         errCode = -E_INVALID_CONFIG_VALUE;
192         return {};
193     }
194 
195     if (!CheckMaxConnNumConfig(dbConfig, conf.maxConnNum_)) {
196         GLOGE("Check DB config 'maxConnNum' failed.");
197         errCode = -E_INVALID_CONFIG_VALUE;
198         return {};
199     }
200 
201     if (!CheckBufferPoolSizeConfig(dbConfig, conf.pageSize_, conf.bufferPoolSize_)) {
202         GLOGE("Check DB config 'bufferPoolSize' failed.");
203         errCode = -E_INVALID_CONFIG_VALUE;
204         return {};
205     }
206 
207     if (!CheckCrcCheckEnableConfig(dbConfig, conf.crcCheckEnable_)) {
208         GLOGE("Check DB config 'crcCheckEnable' failed.");
209         errCode = -E_INVALID_CONFIG_VALUE;
210         return {};
211     }
212 
213     if (!CheckShareModeConfig(dbConfig, conf.shareModeEnable_)) {
214         GLOGE("Check DB config 'shareModeEnable' failed.");
215         errCode = -E_INVALID_CONFIG_VALUE;
216         return {};
217     }
218 
219     conf.configStr_ = confStr;
220     return conf;
221 }
222 
ReadConfig(const std::string & confStr,int & errCode)223 DBConfig DBConfig::ReadConfig(const std::string &confStr, int &errCode)
224 {
225     if (confStr.empty()) {
226         return {};
227     }
228 
229     if (confStr.length() + 1 > MAX_DB_CONFIG_LEN) {
230         GLOGE("Config json string is too long.");
231         errCode = -E_OVER_LIMIT;
232         return {};
233     }
234 
235     std::string lowerCaseConfStr = confStr;
236     std::transform(lowerCaseConfStr.begin(), lowerCaseConfStr.end(), lowerCaseConfStr.begin(), [](unsigned char c) {
237         return std::tolower(c);
238     });
239 
240     return GetDBConfigFromJsonStr(lowerCaseConfStr, errCode);
241 }
242 
ToString() const243 std::string DBConfig::ToString() const
244 {
245     return configStr_;
246 }
247 
GetPageSize() const248 int32_t DBConfig::GetPageSize() const
249 {
250     return pageSize_;
251 }
252 
operator ==(const DBConfig & targetConfig) const253 bool DBConfig::operator==(const DBConfig &targetConfig) const
254 {
255     return pageSize_ == targetConfig.pageSize_ && redoFlushByTrx_ == targetConfig.redoFlushByTrx_ &&
256         redoPubBufSize_ == targetConfig.redoPubBufSize_ && maxConnNum_ == targetConfig.maxConnNum_ &&
257         bufferPoolSize_ == targetConfig.bufferPoolSize_ && crcCheckEnable_ == targetConfig.crcCheckEnable_;
258 }
259 
operator !=(const DBConfig & targetConfig) const260 bool DBConfig::operator!=(const DBConfig &targetConfig) const
261 {
262     return !(*this == targetConfig);
263 }
264 
CheckPersistenceEqual(const DBConfig & targetConfig) const265 bool DBConfig::CheckPersistenceEqual(const DBConfig &targetConfig) const
266 {
267     return pageSize_ == targetConfig.pageSize_ && crcCheckEnable_ == targetConfig.crcCheckEnable_;
268 }
269 } // namespace DocumentDB