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