• 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 <climits>
19 #include <cstdio>
20 #include <queue>
21 
22 #include "cloud/cloud_db_constant.h"
23 #include "cloud/cloud_db_types.h"
24 #include "db_errno.h"
25 #include "platform_specific.h"
26 #include "query_sync_object.h"
27 #include "hash.h"
28 #include "runtime_context.h"
29 #include "value_hash_calc.h"
30 
31 namespace DistributedDB {
32 namespace {
RemoveFiles(const std::list<OS::FileAttr> & fileList,OS::FileType type)33     void RemoveFiles(const std::list<OS::FileAttr> &fileList, OS::FileType type)
34     {
35         for (const auto &item : fileList) {
36             if (item.fileType != type) {
37                 continue;
38             }
39             int errCode = OS::RemoveFile(item.fileName);
40             if (errCode != E_OK) {
41                 LOGE("Remove file failed:%d", errno);
42             }
43         }
44     }
45 
RemoveDirectories(const std::list<OS::FileAttr> & fileList,OS::FileType type)46     void RemoveDirectories(const std::list<OS::FileAttr> &fileList, OS::FileType type)
47     {
48         for (auto item = fileList.rbegin(); item != fileList.rend(); ++item) {
49             if (item->fileType != type) {
50                 continue;
51             }
52             int errCode = OS::RemoveDBDirectory(item->fileName);
53             if (errCode != 0) {
54                 LOGE("Remove directory failed:%d", errno);
55             }
56         }
57     }
58     const std::string HEX_CHAR_MAP = "0123456789abcdef";
59     const std::string CAP_HEX_CHAR_MAP = "0123456789ABCDEF";
60 }
61 
CreateDirectory(const std::string & directory)62 int DBCommon::CreateDirectory(const std::string &directory)
63 {
64     bool isExisted = OS::CheckPathExistence(directory);
65     if (!isExisted) {
66         int errCode = OS::MakeDBDirectory(directory);
67         if (errCode != E_OK) {
68             return errCode;
69         }
70     }
71     return E_OK;
72 }
73 
StringToVector(const std::string & src,std::vector<uint8_t> & dst)74 void DBCommon::StringToVector(const std::string &src, std::vector<uint8_t> &dst)
75 {
76     dst.resize(src.size());
77     dst.assign(src.begin(), src.end());
78 }
79 
VectorToString(const std::vector<uint8_t> & src,std::string & dst)80 void DBCommon::VectorToString(const std::vector<uint8_t> &src, std::string &dst)
81 {
82     dst.clear();
83     dst.assign(src.begin(), src.end());
84 }
85 
VectorToHexString(const std::vector<uint8_t> & inVec,const std::string & separator)86 std::string DBCommon::VectorToHexString(const std::vector<uint8_t> &inVec, const std::string &separator)
87 {
88     std::string outString;
89     for (auto &entry : inVec) {
90         outString.push_back(CAP_HEX_CHAR_MAP[entry >> 4]); // high 4 bits to one hex.
91         outString.push_back(CAP_HEX_CHAR_MAP[entry & 0x0F]); // low 4 bits to one hex.
92         outString += separator;
93     }
94     outString.erase(outString.size() - separator.size(), separator.size()); // remove needless separator at last
95     return outString;
96 }
97 
PrintHexVector(const std::vector<uint8_t> & data,int line,const std::string & tag)98 void DBCommon::PrintHexVector(const std::vector<uint8_t> &data, int line, const std::string &tag)
99 {
100     const size_t maxDataLength = 1024;
101     const int byteHexNum = 2;
102     size_t dataLength = data.size();
103 
104     if (data.size() > maxDataLength) {
105         dataLength = maxDataLength;
106     }
107 
108     char *buff = new (std::nothrow) char[dataLength * byteHexNum + 1]; // dual and add one for the end;
109     if (buff == nullptr) {
110         return;
111     }
112 
113     for (std::vector<uint8_t>::size_type i = 0; i < dataLength; ++i) {
114         buff[byteHexNum * i] = CAP_HEX_CHAR_MAP[data[i] >> 4]; // high 4 bits to one hex.
115         buff[byteHexNum * i + 1] = CAP_HEX_CHAR_MAP[data[i] & 0x0F]; // low 4 bits to one hex.
116     }
117     buff[dataLength * byteHexNum] = '\0';
118 
119     if (line == 0) {
120         LOGD("[%s] size:%zu -- %s", tag.c_str(), data.size(), buff);
121     } else {
122         LOGD("[%s][%d] size:%zu -- %s", tag.c_str(), line, data.size(), buff);
123     }
124 
125     delete []buff;
126     return;
127 }
128 
TransferHashString(const std::string & devName)129 std::string DBCommon::TransferHashString(const std::string &devName)
130 {
131     if (devName.empty()) {
132         return "";
133     }
134     std::vector<uint8_t> devVect(devName.begin(), devName.end());
135     std::vector<uint8_t> hashVect;
136     int errCode = CalcValueHash(devVect, hashVect);
137     if (errCode != E_OK) {
138         return "";
139     }
140 
141     return std::string(hashVect.begin(), hashVect.end());
142 }
143 
TransferStringToHex(const std::string & origStr)144 std::string DBCommon::TransferStringToHex(const std::string &origStr)
145 {
146     if (origStr.empty()) {
147         return "";
148     }
149 
150     std::string tmp;
151     for (auto item : origStr) {
152         unsigned char currentByte = static_cast<unsigned char>(item);
153         tmp.push_back(HEX_CHAR_MAP[currentByte >> 4]); // high 4 bits to one hex.
154         tmp.push_back(HEX_CHAR_MAP[currentByte & 0x0F]); // low 4 bits to one hex.
155     }
156     return tmp;
157 }
158 
CalcValueHash(const std::vector<uint8_t> & value,std::vector<uint8_t> & hashValue)159 int DBCommon::CalcValueHash(const std::vector<uint8_t> &value, std::vector<uint8_t> &hashValue)
160 {
161     ValueHashCalc hashCalc;
162     int errCode = hashCalc.Initialize();
163     if (errCode != E_OK) {
164         return -E_INTERNAL_ERROR;
165     }
166 
167     errCode = hashCalc.Update(value);
168     if (errCode != E_OK) {
169         return -E_INTERNAL_ERROR;
170     }
171 
172     errCode = hashCalc.GetResult(hashValue);
173     if (errCode != E_OK) {
174         return -E_INTERNAL_ERROR;
175     }
176 
177     return E_OK;
178 }
179 
CreateStoreDirectory(const std::string & directory,const std::string & identifierName,const std::string & subDir,bool isCreate)180 int DBCommon::CreateStoreDirectory(const std::string &directory, const std::string &identifierName,
181     const std::string &subDir, bool isCreate)
182 {
183     std::string newDir = directory;
184     if (newDir.back() != '/') {
185         newDir += "/";
186     }
187 
188     newDir += identifierName;
189     if (!isCreate) {
190         if (!OS::CheckPathExistence(newDir)) {
191             LOGE("Required path does not exist and won't create.");
192             return -E_INVALID_ARGS;
193         }
194         return E_OK;
195     }
196 
197     if (directory.empty()) {
198         return -E_INVALID_ARGS;
199     }
200 
201     int errCode = DBCommon::CreateDirectory(newDir);
202     if (errCode != E_OK) {
203         return errCode;
204     }
205 
206     newDir += ("/" + subDir);
207     return DBCommon::CreateDirectory(newDir);
208 }
209 
CopyFile(const std::string & srcFile,const std::string & dstFile)210 int DBCommon::CopyFile(const std::string &srcFile, const std::string &dstFile)
211 {
212     const int copyBlockSize = 4096;
213     std::vector<uint8_t> tmpBlock(copyBlockSize, 0);
214     int errCode;
215     FILE *fileIn = fopen(srcFile.c_str(), "rb");
216     if (fileIn == nullptr) {
217         LOGE("[Common:CpFile] open the source file error:%d", errno);
218         return -E_INVALID_FILE;
219     }
220     FILE *fileOut = fopen(dstFile.c_str(), "wb");
221     if (fileOut == nullptr) {
222         LOGE("[Common:CpFile] open the target file error:%d", errno);
223         errCode = -E_INVALID_FILE;
224         goto END;
225     }
226     for (;;) {
227         size_t readSize = fread(static_cast<void *>(tmpBlock.data()), 1, copyBlockSize, fileIn);
228         if (readSize < copyBlockSize) {
229             // not end and have error.
230             if (feof(fileIn) != 0 && ferror(fileIn) != 0) {
231                 LOGE("Copy the file error:%d", errno);
232                 errCode = -E_SYSTEM_API_FAIL;
233                 break;
234             }
235         }
236 
237         if (readSize != 0) {
238             size_t writeSize = fwrite(static_cast<void *>(tmpBlock.data()), 1, readSize, fileOut);
239             if (ferror(fileOut) != 0 || writeSize != readSize) {
240                 LOGE("Write the data while copy:%d", errno);
241                 errCode = -E_SYSTEM_API_FAIL;
242                 break;
243             }
244         }
245 
246         if (feof(fileIn) != 0) {
247             errCode = E_OK;
248             break;
249         }
250     }
251 
252 END:
253     if (fileIn != nullptr) {
254         (void)fclose(fileIn);
255     }
256     if (fileOut != nullptr) {
257         (void)fclose(fileOut);
258     }
259     return errCode;
260 }
261 
RemoveAllFilesOfDirectory(const std::string & dir,bool isNeedRemoveDir)262 int DBCommon::RemoveAllFilesOfDirectory(const std::string &dir, bool isNeedRemoveDir)
263 {
264     std::list<OS::FileAttr> fileList;
265     bool isExisted = OS::CheckPathExistence(dir);
266     if (!isExisted) {
267         return E_OK;
268     }
269     int errCode = OS::GetFileAttrFromPath(dir, fileList, true);
270     if (errCode != E_OK) {
271         return errCode;
272     }
273 
274     RemoveFiles(fileList, OS::FileType::FILE);
275     RemoveDirectories(fileList, OS::FileType::PATH);
276     if (isNeedRemoveDir) {
277         // Pay attention to the order of deleting the directory
278         if (OS::CheckPathExistence(dir) && OS::RemoveDBDirectory(dir) != 0) {
279             LOGI("Remove the directory error:%d", errno);
280             errCode = -E_SYSTEM_API_FAIL;
281         }
282     }
283 
284     return errCode;
285 }
286 
GenerateIdentifierId(const std::string & storeId,const std::string & appId,const std::string & userId,int32_t instanceId)287 std::string DBCommon::GenerateIdentifierId(const std::string &storeId,
288     const std::string &appId, const std::string &userId, int32_t instanceId)
289 {
290     std::string id = userId + "-" + appId + "-" + storeId;
291     if (instanceId != 0) {
292         id += "-" + std::to_string(instanceId);
293     }
294     return id;
295 }
296 
GenerateDualTupleIdentifierId(const std::string & storeId,const std::string & appId)297 std::string DBCommon::GenerateDualTupleIdentifierId(const std::string &storeId, const std::string &appId)
298 {
299     return appId + "-" + storeId;
300 }
301 
SetDatabaseIds(KvDBProperties & properties,const std::string & appId,const std::string & userId,const std::string & storeId,int32_t instanceId)302 void DBCommon::SetDatabaseIds(KvDBProperties &properties, const std::string &appId, const std::string &userId,
303     const std::string &storeId, int32_t instanceId)
304 {
305     properties.SetIdentifier(userId, appId, storeId, instanceId);
306     std::string oriStoreDir;
307     // IDENTIFIER_DIR no need cal with instanceId
308     std::string identifier = GenerateIdentifierId(storeId, appId, userId);
309     if (properties.GetBoolProp(KvDBProperties::CREATE_DIR_BY_STORE_ID_ONLY, false)) {
310         oriStoreDir = storeId;
311     } else {
312         oriStoreDir = identifier;
313     }
314     std::string hashIdentifier = TransferHashString(identifier);
315     std::string hashDir = TransferHashString(oriStoreDir);
316     std::string hexHashDir = TransferStringToHex(hashDir);
317     properties.SetStringProp(KvDBProperties::IDENTIFIER_DIR, hexHashDir);
318 }
319 
StringMasking(const std::string & oriStr,size_t remain)320 std::string DBCommon::StringMasking(const std::string &oriStr, size_t remain)
321 {
322 #ifndef DB_DEBUG_ENV
323     if (oriStr.size() > remain) {
324         return oriStr.substr(0, remain);
325     }
326 #endif
327     return oriStr;
328 }
329 
GetDistributedTableName(const std::string & device,const std::string & tableName)330 std::string DBCommon::GetDistributedTableName(const std::string &device, const std::string &tableName)
331 {
332     if (!RuntimeContext::GetInstance()->ExistTranslateDevIdCallback()) {
333         return GetDistributedTableNameWithHash(device, tableName);
334     }
335     return CalDistributedTableName(device, tableName);
336 }
337 
GetDistributedTableName(const std::string & device,const std::string & tableName,const StoreInfo & info)338 std::string DBCommon::GetDistributedTableName(const std::string &device, const std::string &tableName,
339     const StoreInfo &info)
340 {
341     std::string newDeviceId;
342     if (RuntimeContext::GetInstance()->TranslateDeviceId(device, info, newDeviceId) != E_OK) {
343         return GetDistributedTableNameWithHash(device, tableName);
344     }
345     return CalDistributedTableName(newDeviceId, tableName);
346 }
347 
GetDistributedTableNameWithHash(const std::string & device,const std::string & tableName)348 std::string DBCommon::GetDistributedTableNameWithHash(const std::string &device, const std::string &tableName)
349 {
350     std::string deviceHashHex = DBCommon::TransferStringToHex(DBCommon::TransferHashString(device));
351     return CalDistributedTableName(deviceHashHex, tableName);
352 }
353 
CalDistributedTableName(const std::string & device,const std::string & tableName)354 std::string DBCommon::CalDistributedTableName(const std::string &device, const std::string &tableName)
355 {
356     return DBConstant::RELATIONAL_PREFIX + tableName + "_" + device;
357 }
358 
GetDeviceFromName(const std::string & deviceTableName,std::string & deviceHash,std::string & tableName)359 void DBCommon::GetDeviceFromName(const std::string &deviceTableName, std::string &deviceHash, std::string &tableName)
360 {
361     std::size_t found = deviceTableName.rfind('_');
362     if (found != std::string::npos && found + 1 < deviceTableName.length() &&
363         found > DBConstant::RELATIONAL_PREFIX.length()) {
364         deviceHash = deviceTableName.substr(found + 1);
365         tableName = deviceTableName.substr(DBConstant::RELATIONAL_PREFIX.length(),
366             found - DBConstant::RELATIONAL_PREFIX.length());
367     }
368 }
369 
TrimSpace(const std::string & input)370 std::string DBCommon::TrimSpace(const std::string &input)
371 {
372     std::string res;
373     res.reserve(input.length());
374     bool isPreSpace = true;
375     for (char c : input) {
376         if (std::isspace(c)) {
377             isPreSpace = true;
378         } else {
379             if (!res.empty() && isPreSpace) {
380                 res += ' ';
381             }
382             res += c;
383             isPreSpace = false;
384         }
385     }
386     res.shrink_to_fit();
387     return res;
388 }
389 
RTrim(std::string & oriString)390 void DBCommon::RTrim(std::string &oriString)
391 {
392     if (oriString.empty()) {
393         return;
394     }
395     oriString.erase(oriString.find_last_not_of(" ") + 1);
396 }
397 
398 namespace {
CharIn(char c,const std::string & pattern)399 bool CharIn(char c, const std::string &pattern)
400 {
401     return std::any_of(pattern.begin(), pattern.end(), [c] (char p) {
402         return c == p;
403     });
404 }
405 }
406 
HasConstraint(const std::string & sql,const std::string & keyWord,const std::string & prePattern,const std::string & nextPattern)407 bool DBCommon::HasConstraint(const std::string &sql, const std::string &keyWord, const std::string &prePattern,
408     const std::string &nextPattern)
409 {
410     size_t pos = 0;
411     while ((pos = sql.find(keyWord, pos)) != std::string::npos) {
412         if (pos >= 1 && CharIn(sql[pos - 1], prePattern) && ((pos + keyWord.length() == sql.length()) ||
413             ((pos + keyWord.length() < sql.length()) && CharIn(sql[pos + keyWord.length()], nextPattern)))) {
414             return true;
415         }
416         pos++;
417     }
418     return false;
419 }
420 
IsSameCipher(CipherType srcType,CipherType inputType)421 bool DBCommon::IsSameCipher(CipherType srcType, CipherType inputType)
422 {
423     // At present, the default type is AES-256-GCM.
424     // So when src is default and input is AES-256-GCM,
425     // or when src is AES-256-GCM and input is default,
426     // we think they are the same type.
427     if (srcType == inputType ||
428         ((srcType == CipherType::DEFAULT || srcType == CipherType::AES_256_GCM) &&
429         (inputType == CipherType::DEFAULT || inputType == CipherType::AES_256_GCM))) {
430         return true;
431     }
432     return false;
433 }
434 
ToLowerCase(const std::string & str)435 std::string DBCommon::ToLowerCase(const std::string &str)
436 {
437     std::string res(str.length(), ' ');
438     std::transform(str.begin(), str.end(), res.begin(), ::tolower);
439     return res;
440 }
441 
ToUpperCase(const std::string & str)442 std::string DBCommon::ToUpperCase(const std::string &str)
443 {
444     std::string res(str.length(), ' ');
445     std::transform(str.begin(), str.end(), res.begin(), ::toupper);
446     return res;
447 }
448 
CaseInsensitiveCompare(const std::string & first,const std::string & second)449 bool DBCommon::CaseInsensitiveCompare(const std::string &first, const std::string &second)
450 {
451     return (strcasecmp(first.c_str(), second.c_str()) == 0);
452 }
453 
CheckIsAlnumOrUnderscore(const std::string & text)454 bool DBCommon::CheckIsAlnumOrUnderscore(const std::string &text)
455 {
456     auto iter = std::find_if_not(text.begin(), text.end(), [](char c) {
457         return (std::isalnum(c) || c == '_');
458     });
459     return iter == text.end();
460 }
461 
CheckQueryWithoutMultiTable(const Query & query)462 bool DBCommon::CheckQueryWithoutMultiTable(const Query &query)
463 {
464     QuerySyncObject syncObject(query);
465     if (!syncObject.GetRelationTableNames().empty()) {
466         LOGE("check query table names from tables failed!");
467         return false;
468     }
469     if (!QuerySyncObject::GetQuerySyncObject(query).empty()) {
470         LOGE("check query object from table failed!");
471         return false;
472     }
473     return true;
474 }
475 
476 /* this function us topology sorting algorithm to detect whether a ring exists in the dependency
477  * the algorithm main procedure as below:
478  * 1. select a point which in-degree is 0 in the graph and record it;
479  * 2. delete the point and all edges starting from this point;
480  * 3. repeat step 1 and 2, until the graph is empty or there is no point with a zero degree
481  * */
IsCircularDependency(int size,const std::vector<std::vector<int>> & dependency)482 bool DBCommon::IsCircularDependency(int size, const std::vector<std::vector<int>> &dependency)
483 {
484     std::vector<int> inDegree(size, 0); // save in-degree of every point
485     std::vector<std::vector<int>> adjacencyList(size);
486     for (size_t i = 0; i < dependency.size(); i++) {
487         adjacencyList[dependency[i][0]].push_back(dependency[i][1]); // update adjacencyList
488         inDegree[dependency[i][1]]++;
489     }
490     std::queue<int> que;
491     for (size_t i = 0; i < inDegree.size(); i++) {
492         if (inDegree[i] == 0) {
493             que.push(i); // push all point which in-degree = 0
494         }
495     }
496 
497     int zeroDegreeCnt = static_cast<int>(que.size());
498     while (!que.empty()) {
499         int index = que.front();
500         que.pop();
501         for (size_t i = 0; i < adjacencyList[index].size(); ++i) {
502             int j = adjacencyList[index][i]; // adjacencyList[index] save the point which is connected to index
503             inDegree[j]--;
504             if (inDegree[j] == 0) {
505                 zeroDegreeCnt++;
506                 que.push(j);
507             }
508         }
509     }
510     return zeroDegreeCnt != size;
511 }
512 
SerializeWaterMark(Timestamp localMark,const std::string & cloudMark,Value & blobMeta)513 int DBCommon::SerializeWaterMark(Timestamp localMark, const std::string &cloudMark, Value &blobMeta)
514 {
515     uint64_t length = Parcel::GetUInt64Len() + Parcel::GetStringLen(cloudMark);
516     blobMeta.resize(length);
517     Parcel parcel(blobMeta.data(), blobMeta.size());
518     parcel.WriteUInt64(localMark);
519     parcel.WriteString(cloudMark);
520     if (parcel.IsError()) {
521         LOGE("[DBCommon] Parcel error while serializing cloud meta data.");
522         return -E_PARSE_FAIL;
523     }
524     return E_OK;
525 }
526 
GetPrefixTableName(const TableName & tableName)527 Key DBCommon::GetPrefixTableName(const TableName &tableName)
528 {
529     TableName newName = CloudDbConstant::CLOUD_META_TABLE_PREFIX + tableName;
530     Key prefixedTableName(newName.begin(), newName.end());
531     return prefixedTableName;
532 }
533 
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)534 void DBCommon::InsertNodesByScore(const std::map<std::string, std::map<std::string, bool>> &graph,
535     const std::vector<std::string> &generateNodes, const std::map<std::string, int> &scoreGraph,
536     std::list<std::string> &insertTarget)
537 {
538     auto copyGraph = graph;
539     // insert all nodes into res
540     for (const auto &generateNode : generateNodes) {
541         auto iterator = insertTarget.begin();
542         for (; iterator != insertTarget.end(); iterator++) {
543             // don't compare two no reachable node
544             if (!copyGraph[*iterator][generateNode] && !copyGraph[generateNode][*iterator]) {
545                 continue;
546             }
547             if (scoreGraph.find(*iterator) == scoreGraph.end() || scoreGraph.find(generateNode) == scoreGraph.end()) {
548                 // should not happen
549                 LOGW("[DBCommon] not find score in graph");
550                 continue;
551             }
552             if (scoreGraph.at(*iterator) <= scoreGraph.at(generateNode)) {
553                 break;
554             }
555         }
556         insertTarget.insert(iterator, generateNode);
557     }
558 }
559 
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)560 std::list<std::string> DBCommon::GenerateNodesByNodeWeight(const std::vector<std::string> &nodes,
561     const std::map<std::string, std::map<std::string, bool>> &graph,
562     const std::map<std::string, int> &nodeWeight)
563 {
564     std::list<std::string> res;
565     std::set<std::string> paramNodes;
566     std::set<std::string> visitNodes;
567     for (const auto &node : nodes) {
568         res.push_back(node);
569         paramNodes.insert(node);
570         visitNodes.insert(node);
571     }
572     // find all node which can be reached by param nodes
573     for (const auto &source : paramNodes) {
574         if (graph.find(source) == graph.end()) {
575             continue;
576         }
577         for (const auto &[target, reach] : graph.at(source)) {
578             if (reach) {
579                 visitNodes.insert(target);
580             }
581         }
582     }
583     std::vector<std::string> generateNodes;
584     for (const auto &node : visitNodes) {
585         // ignore the node which is param
586         if (paramNodes.find(node) == paramNodes.end()) {
587             generateNodes.push_back(node);
588         }
589     }
590     InsertNodesByScore(graph, generateNodes, nodeWeight, res);
591     return res;
592 }
593 
HasPrimaryKey(const std::vector<Field> & fields)594 bool DBCommon::HasPrimaryKey(const std::vector<Field> &fields)
595 {
596     for (const auto &field : fields) {
597         if (field.primary) {
598             return true;
599         }
600     }
601     return false;
602 }
603 
IsRecordError(const VBucket & record)604 bool DBCommon::IsRecordError(const VBucket &record)
605 {
606     if (record.find(CloudDbConstant::ERROR_FIELD) == record.end()) {
607         return false;
608     }
609     return record.at(CloudDbConstant::ERROR_FIELD).index() == TYPE_INDEX<std::string>;
610 }
611 
IsRecordIgnored(const VBucket & record)612 bool DBCommon::IsRecordIgnored(const VBucket &record)
613 {
614     if (record.find(CloudDbConstant::ERROR_FIELD) == record.end()) {
615         return false;
616     }
617     if (record.at(CloudDbConstant::ERROR_FIELD).index() != TYPE_INDEX<int64_t>) {
618         return false;
619     }
620     auto status = std::get<int64_t>(record.at(CloudDbConstant::ERROR_FIELD));
621     return status == static_cast<int64_t>(DBStatus::CLOUD_RECORD_EXIST_CONFLICT);
622 }
623 
GenerateHashLabel(const DBInfo & dbInfo)624 std::string DBCommon::GenerateHashLabel(const DBInfo &dbInfo)
625 {
626     if (dbInfo.syncDualTupleMode) {
627         return DBCommon::TransferHashString(dbInfo.appId + "-" + dbInfo.storeId);
628     }
629     return DBCommon::TransferHashString(dbInfo.userId + "-" + dbInfo.appId + "-" + dbInfo.storeId);
630 }
631 } // namespace DistributedDB
632