• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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_common.h"
17 
18 #include <atomic>
19 #include <charconv>
20 #include <climits>
21 #include <cstdio>
22 #ifndef _WIN32
23 #include <dlfcn.h>
24 #endif
25 #include <mutex>
26 #include <queue>
27 
28 #include "cloud/cloud_db_constant.h"
29 #include "cloud/cloud_db_types.h"
30 #include "db_errno.h"
31 #include "param_check_utils.h"
32 #include "platform_specific.h"
33 #include "query_sync_object.h"
34 #include "hash.h"
35 #include "runtime_context.h"
36 #include "version.h"
37 
38 namespace DistributedDB {
39 namespace {
RemoveFiles(const std::list<OS::FileAttr> & fileList,OS::FileType type)40     void RemoveFiles(const std::list<OS::FileAttr> &fileList, OS::FileType type)
41     {
42         for (const auto &item : fileList) {
43             if (item.fileType != type) {
44                 continue;
45             }
46             int errCode = OS::RemoveFile(item.fileName);
47             if (errCode != E_OK) {
48                 LOGE("Remove file failed:%d", errno);
49             }
50         }
51     }
52 
RemoveDirectories(const std::list<OS::FileAttr> & fileList,OS::FileType type)53     void RemoveDirectories(const std::list<OS::FileAttr> &fileList, OS::FileType type)
54     {
55         for (auto item = fileList.rbegin(); item != fileList.rend(); ++item) {
56             if (item->fileType != type) {
57                 continue;
58             }
59             int errCode = OS::RemoveDBDirectory(item->fileName);
60             if (errCode != 0) {
61                 LOGE("Remove directory failed:%d", errno);
62             }
63         }
64     }
65     const std::string CAP_HEX_CHAR_MAP = "0123456789ABCDEF";
66 }
67 
68 static std::atomic_bool g_isGrdLoaded = false;
69 
CreateDirectory(const std::string & directory)70 int DBCommon::CreateDirectory(const std::string &directory)
71 {
72     bool isExisted = OS::CheckPathExistence(directory);
73     if (!isExisted) {
74         int errCode = OS::MakeDBDirectory(directory);
75         if (errCode != E_OK) {
76             return errCode;
77         }
78     }
79     return E_OK;
80 }
81 
VectorToString(const std::vector<uint8_t> & src,std::string & dst)82 void DBCommon::VectorToString(const std::vector<uint8_t> &src, std::string &dst)
83 {
84     dst.clear();
85     dst.assign(src.begin(), src.end());
86 }
87 
VectorToHexString(const std::vector<uint8_t> & inVec,const std::string & separator)88 std::string DBCommon::VectorToHexString(const std::vector<uint8_t> &inVec, const std::string &separator)
89 {
90     std::string outString;
91     for (auto &entry : inVec) {
92         outString.push_back(CAP_HEX_CHAR_MAP[entry >> 4]); // high 4 bits to one hex.
93         outString.push_back(CAP_HEX_CHAR_MAP[entry & 0x0F]); // low 4 bits to one hex.
94         outString += separator;
95     }
96     outString.erase(outString.size() - separator.size(), separator.size()); // remove needless separator at last
97     return outString;
98 }
99 
PrintHexVector(const std::vector<uint8_t> & data,int line,const std::string & tag)100 void DBCommon::PrintHexVector(const std::vector<uint8_t> &data, int line, const std::string &tag)
101 {
102     const size_t maxDataLength = 1024;
103     const int byteHexNum = 2;
104     size_t dataLength = data.size();
105 
106     if (data.size() > maxDataLength) {
107         dataLength = maxDataLength;
108     }
109 
110     char *buff = new (std::nothrow) char[dataLength * byteHexNum + 1]; // dual and add one for the end;
111     if (buff == nullptr) {
112         return;
113     }
114 
115     for (std::vector<uint8_t>::size_type i = 0; i < dataLength; ++i) {
116         buff[byteHexNum * i] = CAP_HEX_CHAR_MAP[data[i] >> 4]; // high 4 bits to one hex.
117         buff[byteHexNum * i + 1] = CAP_HEX_CHAR_MAP[data[i] & 0x0F]; // low 4 bits to one hex.
118     }
119     buff[dataLength * byteHexNum] = '\0';
120 
121     if (line == 0) {
122         LOGD("[%s] size:%zu -- %s", tag.c_str(), data.size(), buff);
123     } else {
124         LOGD("[%s][%d] size:%zu -- %s", tag.c_str(), line, data.size(), buff);
125     }
126 
127     delete []buff;
128     return;
129 }
130 
CreateStoreDirectory(const std::string & directory,const std::string & identifierName,const std::string & subDir,bool isCreate)131 int DBCommon::CreateStoreDirectory(const std::string &directory, const std::string &identifierName,
132     const std::string &subDir, bool isCreate)
133 {
134     std::string newDir = directory;
135     if (newDir.back() != '/') {
136         newDir += "/";
137     }
138 
139     newDir += identifierName;
140     if (!isCreate) {
141         if (!OS::CheckPathExistence(newDir)) {
142             LOGE("Required path does not exist and won't create.");
143             return -E_INVALID_ARGS;
144         }
145         return E_OK;
146     }
147 
148     if (directory.empty()) {
149         return -E_INVALID_ARGS;
150     }
151 
152     int errCode = DBCommon::CreateDirectory(newDir);
153     if (errCode != E_OK) {
154         return errCode;
155     }
156 
157     newDir += ("/" + subDir);
158     return DBCommon::CreateDirectory(newDir);
159 }
160 
CopyFile(const std::string & srcFile,const std::string & dstFile)161 int DBCommon::CopyFile(const std::string &srcFile, const std::string &dstFile)
162 {
163     const int copyBlockSize = 4096;
164     std::vector<uint8_t> tmpBlock(copyBlockSize, 0);
165     int errCode;
166     FILE *fileIn = fopen(srcFile.c_str(), "rb");
167     if (fileIn == nullptr) {
168         LOGE("[Common:CpFile] open the source file error:%d", errno);
169         return -E_INVALID_FILE;
170     }
171     FILE *fileOut = fopen(dstFile.c_str(), "wb");
172     if (fileOut == nullptr) {
173         LOGE("[Common:CpFile] open the target file error:%d", errno);
174         errCode = -E_INVALID_FILE;
175         goto END;
176     }
177     for (;;) {
178         size_t readSize = fread(static_cast<void *>(tmpBlock.data()), 1, copyBlockSize, fileIn);
179         if (readSize < copyBlockSize) {
180             // not end and have error.
181             if (feof(fileIn) != 0 && ferror(fileIn) != 0) {
182                 LOGE("Copy the file error:%d", errno);
183                 errCode = -E_SYSTEM_API_FAIL;
184                 break;
185             }
186         }
187 
188         if (readSize != 0) {
189             size_t writeSize = fwrite(static_cast<void *>(tmpBlock.data()), 1, readSize, fileOut);
190             if (ferror(fileOut) != 0 || writeSize != readSize) {
191                 LOGE("Write the data while copy:%d", errno);
192                 errCode = -E_SYSTEM_API_FAIL;
193                 break;
194             }
195         }
196 
197         if (feof(fileIn) != 0) {
198             errCode = E_OK;
199             break;
200         }
201     }
202 
203 END:
204     if (fileIn != nullptr) {
205         (void)fclose(fileIn);
206     }
207     if (fileOut != nullptr) {
208         (void)fclose(fileOut);
209     }
210     return errCode;
211 }
212 
RemoveAllFilesOfDirectory(const std::string & dir,bool isNeedRemoveDir)213 int DBCommon::RemoveAllFilesOfDirectory(const std::string &dir, bool isNeedRemoveDir)
214 {
215     std::list<OS::FileAttr> fileList;
216     bool isExisted = OS::CheckPathExistence(dir);
217     if (!isExisted) {
218         return E_OK;
219     }
220     int errCode = OS::GetFileAttrFromPath(dir, fileList, true);
221     if (errCode != E_OK) {
222         return errCode;
223     }
224 
225     RemoveFiles(fileList, OS::FileType::FILE);
226     RemoveDirectories(fileList, OS::FileType::PATH);
227     if (isNeedRemoveDir) {
228         // Pay attention to the order of deleting the directory
229         if (OS::CheckPathExistence(dir) && OS::RemoveDBDirectory(dir) != 0) {
230             LOGI("Remove the directory error:%d", errno);
231             errCode = -E_SYSTEM_API_FAIL;
232         }
233     }
234 
235     return errCode;
236 }
237 
GenerateIdentifierId(const std::string & storeId,const std::string & appId,const std::string & userId,const std::string & subUser,int32_t instanceId)238 std::string DBCommon::GenerateIdentifierId(const std::string &storeId,
239     const std::string &appId, const std::string &userId, const std::string &subUser, int32_t instanceId)
240 {
241     std::string id = userId + "-" + appId + "-" + storeId;
242     if (instanceId != 0) {
243         id += "-" + std::to_string(instanceId);
244     }
245     if (!subUser.empty()) {
246         id += "-" + subUser;
247     }
248     return id;
249 }
250 
GenerateDualTupleIdentifierId(const std::string & storeId,const std::string & appId)251 std::string DBCommon::GenerateDualTupleIdentifierId(const std::string &storeId, const std::string &appId)
252 {
253     return appId + "-" + storeId;
254 }
255 
SetDatabaseIds(KvDBProperties & properties,const DbIdParam & dbIdParam)256 void DBCommon::SetDatabaseIds(KvDBProperties &properties, const DbIdParam &dbIdParam)
257 {
258     properties.SetIdentifier(dbIdParam.userId, dbIdParam.appId, dbIdParam.storeId,
259         dbIdParam.subUser, dbIdParam.instanceId);
260     std::string oriStoreDir;
261     // IDENTIFIER_DIR no need cal with instanceId and subUser
262     std::string identifier = GenerateIdentifierId(dbIdParam.storeId, dbIdParam.appId, dbIdParam.userId);
263     if (properties.GetBoolProp(KvDBProperties::CREATE_DIR_BY_STORE_ID_ONLY, false)) {
264         oriStoreDir = dbIdParam.storeId;
265     } else {
266         oriStoreDir = identifier;
267     }
268     std::string hashIdentifier = TransferHashString(identifier);
269     std::string hashDir = TransferHashString(oriStoreDir);
270     std::string hexHashDir = TransferStringToHex(hashDir);
271     properties.SetStringProp(KvDBProperties::IDENTIFIER_DIR, hexHashDir);
272 }
273 
StringMasking(const std::string & oriStr,size_t remain)274 std::string DBCommon::StringMasking(const std::string &oriStr, size_t remain)
275 {
276 #ifndef DB_DEBUG_ENV
277     if (oriStr.size() > remain) {
278         return oriStr.substr(0, remain);
279     }
280 #endif
281     return oriStr;
282 }
283 
GetDistributedTableName(const std::string & device,const std::string & tableName)284 std::string DBCommon::GetDistributedTableName(const std::string &device, const std::string &tableName)
285 {
286     if (!RuntimeContext::GetInstance()->ExistTranslateDevIdCallback()) {
287         return GetDistributedTableNameWithHash(device, tableName);
288     }
289     return CalDistributedTableName(device, tableName);
290 }
291 
GetDistributedTableName(const std::string & device,const std::string & tableName,const StoreInfo & info)292 std::string DBCommon::GetDistributedTableName(const std::string &device, const std::string &tableName,
293     const StoreInfo &info)
294 {
295     std::string newDeviceId;
296     if (RuntimeContext::GetInstance()->TranslateDeviceId(device, info, newDeviceId) != E_OK) {
297         return GetDistributedTableNameWithHash(device, tableName);
298     }
299     return CalDistributedTableName(newDeviceId, tableName);
300 }
301 
GetDistributedTableNameWithHash(const std::string & device,const std::string & tableName)302 std::string DBCommon::GetDistributedTableNameWithHash(const std::string &device, const std::string &tableName)
303 {
304     std::string deviceHashHex = DBCommon::TransferStringToHex(DBCommon::TransferHashString(device));
305     return CalDistributedTableName(deviceHashHex, tableName);
306 }
307 
CalDistributedTableName(const std::string & device,const std::string & tableName)308 std::string DBCommon::CalDistributedTableName(const std::string &device, const std::string &tableName)
309 {
310     return DBConstant::RELATIONAL_PREFIX + tableName + "_" + device;
311 }
312 
GetDeviceFromName(const std::string & deviceTableName,std::string & deviceHash,std::string & tableName)313 void DBCommon::GetDeviceFromName(const std::string &deviceTableName, std::string &deviceHash, std::string &tableName)
314 {
315     std::size_t found = deviceTableName.rfind('_');
316     if (found != std::string::npos && found + 1 < deviceTableName.length() &&
317         found > DBConstant::RELATIONAL_PREFIX_SIZE) {
318         deviceHash = deviceTableName.substr(found + 1);
319         tableName = deviceTableName.substr(DBConstant::RELATIONAL_PREFIX_SIZE,
320             found - DBConstant::RELATIONAL_PREFIX_SIZE);
321     }
322 }
323 
IsSameCipher(CipherType srcType,CipherType inputType)324 bool DBCommon::IsSameCipher(CipherType srcType, CipherType inputType)
325 {
326     // At present, the default type is AES-256-GCM.
327     // So when src is default and input is AES-256-GCM,
328     // or when src is AES-256-GCM and input is default,
329     // we think they are the same type.
330     if (srcType == inputType ||
331         ((srcType == CipherType::DEFAULT || srcType == CipherType::AES_256_GCM) &&
332         (inputType == CipherType::DEFAULT || inputType == CipherType::AES_256_GCM))) {
333         return true;
334     }
335     return false;
336 }
337 
CheckQueryWithoutMultiTable(const Query & query)338 bool DBCommon::CheckQueryWithoutMultiTable(const Query &query)
339 {
340     if (!QuerySyncObject::GetQuerySyncObject(query).empty()) {
341         LOGE("check query object from table failed!");
342         return false;
343     }
344     return true;
345 }
346 
347 /* this function us topology sorting algorithm to detect whether a ring exists in the dependency
348  * the algorithm main procedure as below:
349  * 1. select a point which in-degree is 0 in the graph and record it;
350  * 2. delete the point and all edges starting from this point;
351  * 3. repeat step 1 and 2, until the graph is empty or there is no point with a zero degree
352  * */
IsCircularDependency(int size,const std::vector<std::vector<int>> & dependency)353 bool DBCommon::IsCircularDependency(int size, const std::vector<std::vector<int>> &dependency)
354 {
355     std::vector<int> inDegree(size, 0); // save in-degree of every point
356     std::vector<std::vector<int>> adjacencyList(size);
357     for (size_t i = 0; i < dependency.size(); i++) {
358         adjacencyList[dependency[i][0]].push_back(dependency[i][1]); // update adjacencyList
359         inDegree[dependency[i][1]]++;
360     }
361     std::queue<int> que;
362     for (size_t i = 0; i < inDegree.size(); i++) {
363         if (inDegree[i] == 0) {
364             que.push(i); // push all point which in-degree = 0
365         }
366     }
367 
368     int zeroDegreeCnt = static_cast<int>(que.size());
369     while (!que.empty()) {
370         int index = que.front();
371         que.pop();
372         for (size_t i = 0; i < adjacencyList[index].size(); ++i) {
373             int j = adjacencyList[index][i]; // adjacencyList[index] save the point which is connected to index
374             inDegree[j]--;
375             if (inDegree[j] == 0) {
376                 zeroDegreeCnt++;
377                 que.push(j);
378             }
379         }
380     }
381     return zeroDegreeCnt != size;
382 }
383 
SerializeWaterMark(Timestamp localMark,const std::string & cloudMark,Value & blobMeta)384 int DBCommon::SerializeWaterMark(Timestamp localMark, const std::string &cloudMark, Value &blobMeta)
385 {
386     uint64_t length = Parcel::GetUInt64Len() + Parcel::GetStringLen(cloudMark);
387     blobMeta.resize(length);
388     Parcel parcel(blobMeta.data(), blobMeta.size());
389     parcel.WriteUInt64(localMark);
390     parcel.WriteString(cloudMark);
391     if (parcel.IsError()) {
392         LOGE("[DBCommon] Parcel error while serializing cloud meta data.");
393         return -E_PARSE_FAIL;
394     }
395     return E_OK;
396 }
397 
GetPrefixTableName(const TableName & tableName)398 Key DBCommon::GetPrefixTableName(const TableName &tableName)
399 {
400     TableName newName = CloudDbConstant::CLOUD_META_TABLE_PREFIX + tableName;
401     Key prefixedTableName(newName.begin(), newName.end());
402     return prefixedTableName;
403 }
404 
InsertNodesByScore(const std::map<std::string,std::map<std::string,bool>> & graph,const std::vector<std::string> & generateNodes,const std::map<std::string,int> & scoreGraph,std::list<std::string> & insertTarget)405 void DBCommon::InsertNodesByScore(const std::map<std::string, std::map<std::string, bool>> &graph,
406     const std::vector<std::string> &generateNodes, const std::map<std::string, int> &scoreGraph,
407     std::list<std::string> &insertTarget)
408 {
409     auto copyGraph = graph;
410     // insert all nodes into res
411     for (const auto &generateNode : generateNodes) {
412         auto iterator = insertTarget.begin();
413         for (; iterator != insertTarget.end(); iterator++) {
414             // don't compare two no reachable node
415             if (!copyGraph[*iterator][generateNode] && !copyGraph[generateNode][*iterator]) {
416                 continue;
417             }
418             if (scoreGraph.find(*iterator) == scoreGraph.end() || scoreGraph.find(generateNode) == scoreGraph.end()) {
419                 // should not happen
420                 LOGW("[DBCommon] not find score in graph");
421                 continue;
422             }
423             if (scoreGraph.at(*iterator) <= scoreGraph.at(generateNode)) {
424                 break;
425             }
426         }
427         insertTarget.insert(iterator, generateNode);
428     }
429 }
430 
GenerateNodesByNodeWeight(const std::vector<std::string> & nodes,const std::map<std::string,std::map<std::string,bool>> & graph,const std::map<std::string,int> & nodeWeight)431 std::list<std::string> DBCommon::GenerateNodesByNodeWeight(const std::vector<std::string> &nodes,
432     const std::map<std::string, std::map<std::string, bool>> &graph,
433     const std::map<std::string, int> &nodeWeight)
434 {
435     std::list<std::string> res;
436     std::set<std::string> paramNodes;
437     std::set<std::string> visitNodes;
438     for (const auto &node : nodes) {
439         res.push_back(node);
440         paramNodes.insert(node);
441         visitNodes.insert(node);
442     }
443     // find all node which can be reached by param nodes
444     for (const auto &source : paramNodes) {
445         if (graph.find(source) == graph.end()) {
446             continue;
447         }
448         for (const auto &[target, reach] : graph.at(source)) {
449             if (reach) {
450                 visitNodes.insert(target);
451             }
452         }
453     }
454     std::vector<std::string> generateNodes;
455     for (const auto &node : visitNodes) {
456         // ignore the node which is param
457         if (paramNodes.find(node) == paramNodes.end()) {
458             generateNodes.push_back(node);
459         }
460     }
461     InsertNodesByScore(graph, generateNodes, nodeWeight, res);
462     return res;
463 }
464 
HasPrimaryKey(const std::vector<Field> & fields)465 bool DBCommon::HasPrimaryKey(const std::vector<Field> &fields)
466 {
467     for (const auto &field : fields) {
468         if (field.primary) {
469             return true;
470         }
471     }
472     return false;
473 }
474 
IsRecordError(const VBucket & record)475 bool DBCommon::IsRecordError(const VBucket &record)
476 {
477     // check record err should deal or skip, false is no error or error is considered, true is error not considered
478     if (record.find(CloudDbConstant::ERROR_FIELD) == record.end()) {
479         return false;
480     }
481     if (record.at(CloudDbConstant::ERROR_FIELD).index() != TYPE_INDEX<int64_t>) {
482         return false;
483     }
484     auto status = std::get<int64_t>(record.at(CloudDbConstant::ERROR_FIELD));
485     return status != static_cast<int64_t>(DBStatus::CLOUD_RECORD_EXIST_CONFLICT) &&
486            status != static_cast<int64_t>(DBStatus::CLOUD_RECORD_ALREADY_EXISTED) &&
487            status != static_cast<int64_t>(DBStatus::CLOUD_RECORD_NOT_FOUND) &&
488            status != static_cast<int64_t>(DBStatus::LOCAL_ASSET_NOT_FOUND);
489 }
490 
IsIntTypeRecordError(const VBucket & record)491 bool DBCommon::IsIntTypeRecordError(const VBucket &record)
492 {
493     if (record.find(CloudDbConstant::ERROR_FIELD) == record.end()) {
494         return false;
495     }
496     return record.at(CloudDbConstant::ERROR_FIELD).index() == TYPE_INDEX<int64_t>;
497 }
498 
IsRecordIgnored(const VBucket & record)499 bool DBCommon::IsRecordIgnored(const VBucket &record)
500 {
501     if (record.find(CloudDbConstant::ERROR_FIELD) == record.end()) {
502         return false;
503     }
504     if (record.at(CloudDbConstant::ERROR_FIELD).index() != TYPE_INDEX<int64_t>) {
505         return false;
506     }
507     auto status = std::get<int64_t>(record.at(CloudDbConstant::ERROR_FIELD));
508     return status == static_cast<int64_t>(DBStatus::CLOUD_RECORD_EXIST_CONFLICT) ||
509            status == static_cast<int64_t>(DBStatus::CLOUD_VERSION_CONFLICT);
510 }
511 
IsRecordFailed(const VBucket & record,DBStatus status)512 bool DBCommon::IsRecordFailed(const VBucket &record, DBStatus status)
513 {
514     if (status == OK) {
515         return false;
516     }
517     return DBCommon::IsRecordError(record) || !DBCommon::IsRecordSuccess(record);
518 }
519 
IsRecordVersionConflict(const VBucket & record)520 bool DBCommon::IsRecordVersionConflict(const VBucket &record)
521 {
522     if (record.find(CloudDbConstant::ERROR_FIELD) == record.end()) {
523         return false;
524     }
525     if (record.at(CloudDbConstant::ERROR_FIELD).index() != TYPE_INDEX<int64_t>) {
526         return false;
527     }
528     auto status = std::get<int64_t>(record.at(CloudDbConstant::ERROR_FIELD));
529     return status == static_cast<int64_t>(DBStatus::CLOUD_VERSION_CONFLICT);
530 }
531 
IsRecordAssetsMissing(const VBucket & record)532 bool DBCommon::IsRecordAssetsMissing(const VBucket &record)
533 {
534     if (record.find(CloudDbConstant::ERROR_FIELD) == record.end()) {
535         return false;
536     }
537     if (record.at(CloudDbConstant::ERROR_FIELD).index() != TYPE_INDEX<int64_t>) {
538         return false;
539     }
540     auto status = std::get<int64_t>(record.at(CloudDbConstant::ERROR_FIELD));
541     return status == static_cast<int64_t>(DBStatus::LOCAL_ASSET_NOT_FOUND);
542 }
543 
IsRecordDelete(const VBucket & record)544 bool DBCommon::IsRecordDelete(const VBucket &record)
545 {
546     if (record.find(CloudDbConstant::DELETE_FIELD) == record.end()) {
547         return false;
548     }
549     if (record.at(CloudDbConstant::DELETE_FIELD).index() != TYPE_INDEX<bool>) {
550         return false;
551     }
552     return std::get<bool>(record.at(CloudDbConstant::DELETE_FIELD));
553 }
554 
IsCloudRecordNotFound(const VBucket & record)555 bool DBCommon::IsCloudRecordNotFound(const VBucket &record)
556 {
557     if (record.find(CloudDbConstant::ERROR_FIELD) == record.end()) {
558         return false;
559     }
560     if (record.at(CloudDbConstant::ERROR_FIELD).index() != TYPE_INDEX<int64_t>) {
561         return false;
562     }
563     auto status = std::get<int64_t>(record.at(CloudDbConstant::ERROR_FIELD));
564     return status == static_cast<int64_t>(DBStatus::CLOUD_RECORD_NOT_FOUND);
565 }
566 
IsCloudRecordAlreadyExisted(const VBucket & record)567 bool DBCommon::IsCloudRecordAlreadyExisted(const VBucket &record)
568 {
569     if (record.find(CloudDbConstant::ERROR_FIELD) == record.end()) {
570         return false;
571     }
572     if (record.at(CloudDbConstant::ERROR_FIELD).index() != TYPE_INDEX<int64_t>) {
573         return false;
574     }
575     auto status = std::get<int64_t>(record.at(CloudDbConstant::ERROR_FIELD));
576     return status == static_cast<int64_t>(DBStatus::CLOUD_RECORD_ALREADY_EXISTED);
577 }
578 
IsNeedCompensatedForUpload(const VBucket & uploadExtend,const CloudWaterType & type)579 bool DBCommon::IsNeedCompensatedForUpload(const VBucket &uploadExtend, const CloudWaterType &type)
580 {
581     return (DBCommon::IsCloudRecordAlreadyExisted(uploadExtend) && type == CloudWaterType::INSERT) ||
582         (DBCommon::IsCloudRecordNotFound(uploadExtend) && type == CloudWaterType::UPDATE);
583 }
584 
IsRecordIgnoredForReliability(const VBucket & uploadExtend,const CloudWaterType & type)585 bool DBCommon::IsRecordIgnoredForReliability(const VBucket &uploadExtend, const CloudWaterType &type)
586 {
587     return (DBCommon::IsCloudRecordAlreadyExisted(uploadExtend) && type == CloudWaterType::INSERT) ||
588         (DBCommon::IsCloudRecordNotFound(uploadExtend) &&
589         (type == CloudWaterType::UPDATE || type == CloudWaterType::DELETE));
590 }
591 
IsRecordSuccess(const VBucket & record)592 bool DBCommon::IsRecordSuccess(const VBucket &record)
593 {
594     return record.find(CloudDbConstant::ERROR_FIELD) == record.end();
595 }
596 
GenerateHashLabel(const DBInfo & dbInfo)597 std::string DBCommon::GenerateHashLabel(const DBInfo &dbInfo)
598 {
599     if (dbInfo.syncDualTupleMode) {
600         return DBCommon::TransferHashString(dbInfo.appId + "-" + dbInfo.storeId);
601     }
602     return DBCommon::TransferHashString(dbInfo.userId + "-" + dbInfo.appId + "-" + dbInfo.storeId);
603 }
604 
EraseBit(uint64_t origin,uint64_t eraseBit)605 uint64_t DBCommon::EraseBit(uint64_t origin, uint64_t eraseBit)
606 {
607     return origin & (~eraseBit);
608 }
609 
LoadGrdLib(void)610 void *DBCommon::LoadGrdLib(void)
611 {
612 #ifndef _WIN32
613     auto handle = dlopen("libarkdata_db_core.z.so", RTLD_LAZY);
614     if (handle == nullptr) {
615         LOGW("[DBCommon] unable to load grd lib, errno: %d, %s", errno, dlerror());
616         return nullptr;
617     }
618     return handle;
619 #else
620     return nullptr;
621 #endif
622 }
623 
UnLoadGrdLib(void * handle)624 void DBCommon::UnLoadGrdLib(void *handle)
625 {
626 #ifndef _WIN32
627     if (handle == nullptr) {
628         return;
629     }
630     dlclose(handle);
631 #endif
632 }
633 
IsGrdLibLoaded(void)634 bool DBCommon::IsGrdLibLoaded(void)
635 {
636     return g_isGrdLoaded;
637 }
638 
CheckCloudSyncConfigValid(const CloudSyncConfig & config)639 bool DBCommon::CheckCloudSyncConfigValid(const CloudSyncConfig &config)
640 {
641     if (config.maxUploadCount < CloudDbConstant::MIN_UPLOAD_BATCH_COUNT ||
642         config.maxUploadCount > CloudDbConstant::MAX_UPLOAD_BATCH_COUNT) {
643         LOGE("[DBCommon] invalid upload count %" PRId32, config.maxUploadCount);
644         return false;
645     }
646     if (config.maxUploadSize < CloudDbConstant::MIN_UPLOAD_SIZE ||
647         config.maxUploadSize > CloudDbConstant::MAX_UPLOAD_SIZE) {
648         LOGE("[DBCommon] invalid upload size %" PRId32, config.maxUploadSize);
649         return false;
650     }
651     if (config.maxRetryConflictTimes < CloudDbConstant::MIN_RETRY_CONFLICT_COUNTS) {
652         LOGE("[DBCommon] invalid retry conflict count %" PRId32, config.maxRetryConflictTimes);
653         return false;
654     }
655     return true;
656 }
657 
ConvertToUInt64(const std::string & str,uint64_t & value)658 bool DBCommon::ConvertToUInt64(const std::string &str, uint64_t &value)
659 {
660     auto [ptr, errCode] = std::from_chars(str.data(), str.data() + str.size(), value);
661     return errCode == std::errc{} && ptr == str.data() + str.size();
662 }
663 
CmpModifyTime(const std::string & preModifyTimeStr,const std::string & curModifyTimeStr)664 bool CmpModifyTime(const std::string &preModifyTimeStr, const std::string &curModifyTimeStr)
665 {
666     uint64_t curModifyTime = 0;
667     uint64_t preModifyTime = 0;
668     if (preModifyTimeStr.empty() || !DBCommon::ConvertToUInt64(preModifyTimeStr, preModifyTime)) {
669         return true;
670     }
671     if (curModifyTimeStr.empty() || !DBCommon::ConvertToUInt64(curModifyTimeStr, curModifyTime)) {
672         return false;
673     }
674     return curModifyTime >= preModifyTime;
675 }
676 
RemoveDuplicateAssetsData(std::vector<Asset> & assets)677 void DBCommon::RemoveDuplicateAssetsData(std::vector<Asset> &assets)
678 {
679     std::unordered_map<std::string, size_t> indexMap;
680     size_t vectorSize = assets.size();
681     std::vector<size_t> arr(vectorSize, 0);
682     for (std::vector<DistributedDB::Asset>::size_type i = 0; i < assets.size(); ++i) {
683         DistributedDB::Asset asset = assets.at(i);
684         auto it = indexMap.find(asset.name);
685         if (it == indexMap.end()) {
686             indexMap[asset.name] = i;
687             continue;
688         }
689         size_t prevIndex = it->second;
690         Asset &prevAsset = assets.at(prevIndex);
691         if (prevAsset.assetId.empty() && !asset.assetId.empty()) {
692             arr[prevIndex] = 1;
693             indexMap[asset.name] = i;
694             continue;
695         }
696         if (!prevAsset.assetId.empty() && asset.assetId.empty()) {
697             arr[i] = 1;
698             indexMap[asset.name] = prevIndex;
699             continue;
700         }
701         if (CmpModifyTime(prevAsset.modifyTime, asset.modifyTime)) {
702             arr[prevIndex] = 1;
703             indexMap[asset.name] = i;
704             continue;
705         }
706         arr[i] = 1;
707         indexMap[asset.name] = prevIndex;
708     }
709     indexMap.clear();
710     size_t arrIndex = 0;
711     for (auto it = assets.begin(); it != assets.end();) {
712         if (arr[arrIndex] == 1) {
713             it = assets.erase(it);
714         } else {
715             it++;
716         }
717         arrIndex++;
718     }
719 }
720 
TransformToCaseInsensitive(const std::vector<std::string> & origin)721 std::set<std::string, CaseInsensitiveComparator> DBCommon::TransformToCaseInsensitive(
722     const std::vector<std::string> &origin)
723 {
724     std::set<std::string, CaseInsensitiveComparator> res;
725     for (const auto &item : origin) {
726         res.insert(item);
727     }
728     return res;
729 }
730 
GetStoreIdentifier(const StoreInfo & info,const std::string & subUser,bool syncDualTupleMode,bool allowStoreIdWithDot)731 std::string DBCommon::GetStoreIdentifier(const StoreInfo &info, const std::string &subUser, bool syncDualTupleMode,
732     bool allowStoreIdWithDot)
733 {
734     if (!ParamCheckUtils::CheckStoreParameter(info, syncDualTupleMode, subUser, allowStoreIdWithDot)) {
735         return "";
736     }
737     if (syncDualTupleMode) {
738         return DBCommon::TransferHashString(info.appId + "-" + info.storeId);
739     }
740     if (subUser.empty()) {
741         return DBCommon::TransferHashString(info.userId + "-" + info.appId + "-" + info.storeId);
742     }
743     return DBCommon::TransferHashString(info.userId + "-" + info.appId + "-" + info.storeId + "-" + subUser);
744 }
745 
TransfDbVersionToSoftwareVersion(uint16_t dbVersion)746 uint32_t DBCommon::TransfDbVersionToSoftwareVersion(uint16_t dbVersion)
747 {
748     return SOFTWARE_VERSION_EARLIEST + dbVersion;
749 }
750 } // namespace DistributedDB
751