• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "cloud/cloud_sync_tag_assets.h"
16 
17 namespace DistributedDB {
18 namespace {
19 
TagSingleAsset(AssetOpType flag,AssetStatus status,Asset & asset,Assets & res,int & errCode)20 void TagSingleAsset(AssetOpType flag, AssetStatus status, Asset &asset, Assets &res, int &errCode)
21 {
22     if (asset.status == static_cast<uint32_t>(AssetStatus::DELETE)) {
23         asset.flag = static_cast<uint32_t>(AssetOpType::DELETE);
24     } else {
25         asset.flag = static_cast<uint32_t>(flag);
26     }
27     asset.status = static_cast<uint32_t>(status);
28 
29     Timestamp timestamp;
30     errCode = OS::GetCurrentSysTimeInMicrosecond(timestamp);
31     if (errCode != E_OK) {
32         LOGE("Can not get current timestamp.");
33         return;
34     }
35     asset.timestamp = static_cast<int64_t>(timestamp / CloudDbConstant::TEN_THOUSAND);
36     asset.status = asset.flag == static_cast<uint32_t>(AssetOpType::NO_CHANGE) ?
37         static_cast<uint32_t>(AssetStatus::NORMAL) : asset.status;
38     res.push_back(asset);
39 }
40 
TagAssetWithNormalStatus(const bool isNormalStatus,AssetOpType flag,Asset & asset,Assets & res,int & errCode)41 void TagAssetWithNormalStatus(const bool isNormalStatus, AssetOpType flag,
42     Asset &asset, Assets &res, int &errCode)
43 {
44     if (isNormalStatus) {
45         TagSingleAsset(flag, AssetStatus::NORMAL, asset, res, errCode);
46         return;
47     }
48     TagSingleAsset(flag, AssetStatus::DOWNLOADING, asset, res, errCode);
49 }
50 
TagAssetsWithNormalStatus(const bool isNormalStatus,AssetOpType flag,Assets & assets,Assets & res,int & errCode)51 void TagAssetsWithNormalStatus(const bool isNormalStatus, AssetOpType flag,
52     Assets &assets, Assets &res, int &errCode)
53 {
54     for (Asset &asset : assets) {
55         TagAssetWithNormalStatus(isNormalStatus, flag, asset, res, errCode);
56         if (errCode != E_OK) {
57             break;
58         }
59     }
60 }
61 
62 template<typename T>
IsDataContainField(const std::string & assetFieldName,const VBucket & data)63 bool IsDataContainField(const std::string &assetFieldName, const VBucket &data)
64 {
65     auto assetIter = data.find(assetFieldName);
66     if (assetIter == data.end()) {
67         return false;
68     }
69     // When type of Assets is not Nil but a vector which size is 0, we think data is not contain this field.
70     if (assetIter->second.index() == TYPE_INDEX<Assets>) {
71         if (std::get<Assets>(assetIter->second).empty()) {
72             return false;
73         }
74     }
75     if (assetIter->second.index() != TYPE_INDEX<T>) {
76         return false;
77     }
78     return true;
79 }
80 
81 // AssetOpType and AssetStatus will be tagged, assets to be changed will be returned
82 // use VBucket rather than Type because we need to check whether it is empty
TagAssets(const std::string & assetFieldName,VBucket & coveredData,VBucket & beCoveredData,bool setNormalStatus,int & errCode)83 Assets TagAssets(const std::string &assetFieldName, VBucket &coveredData, VBucket &beCoveredData,
84     bool setNormalStatus, int &errCode)
85 {
86     Assets res = {};
87     bool beCoveredHasAssets = IsDataContainField<Assets>(assetFieldName, beCoveredData);
88     bool coveredHasAssets = IsDataContainField<Assets>(assetFieldName, coveredData);
89     if (!beCoveredHasAssets) {
90         if (!coveredHasAssets) {
91             return res;
92         }
93         // all the element in assets will be set to INSERT
94         TagAssetsWithNormalStatus(setNormalStatus,
95             AssetOpType::INSERT, std::get<Assets>(coveredData[assetFieldName]), res, errCode);
96         return res;
97     }
98     if (!coveredHasAssets) {
99         // all the element in assets will be set to DELETE
100         TagAssetsWithNormalStatus(setNormalStatus,
101             AssetOpType::DELETE, std::get<Assets>(beCoveredData[assetFieldName]), res, errCode);
102         coveredData[assetFieldName] = res;
103         return res;
104     }
105     Assets &covered = std::get<Assets>(coveredData[assetFieldName]);
106     Assets &beCovered = std::get<Assets>(beCoveredData[assetFieldName]);
107     std::map<std::string, size_t> coveredAssetsIndexMap = CloudStorageUtils::GenAssetsIndexMap(covered);
108     for (Asset &beCoveredAsset : beCovered) {
109         auto it = coveredAssetsIndexMap.find(beCoveredAsset.name);
110         if (it == coveredAssetsIndexMap.end()) {
111             TagAssetWithNormalStatus(setNormalStatus, AssetOpType::DELETE, beCoveredAsset, res, errCode);
112             std::get<Assets>(coveredData[assetFieldName]).push_back(beCoveredAsset);
113             continue;
114         }
115         Asset &coveredAsset = covered[it->second];
116         if (beCoveredAsset.hash != coveredAsset.hash) {
117             TagAssetWithNormalStatus(setNormalStatus, AssetOpType::UPDATE, coveredAsset, res, errCode);
118         } else {
119             TagAssetWithNormalStatus(setNormalStatus, AssetOpType::NO_CHANGE, coveredAsset, res, errCode);
120         }
121         // Erase element which has been handled, remaining element will be set to Insert
122         coveredAssetsIndexMap.erase(it);
123         if (errCode != E_OK) {
124             LOGE("Tag assets UPDATE or NO_CHANGE fail!");
125             break;
126         }
127     }
128     for (const auto &noHandledAssetKvPair : coveredAssetsIndexMap) {
129         TagAssetWithNormalStatus(setNormalStatus, AssetOpType::INSERT,
130             covered[noHandledAssetKvPair.second], res, errCode);
131         if (errCode != E_OK) {
132             LOGE("Tag assets INSERT fail!");
133             break;
134         }
135     }
136     return res;
137 }
138 
139 // AssetOpType and AssetStatus will be tagged, assets to be changed will be returned
TagAsset(const std::string & assetFieldName,VBucket & coveredData,VBucket & beCoveredData,bool setNormalStatus,int & errCode)140 Assets TagAsset(const std::string &assetFieldName, VBucket &coveredData, VBucket &beCoveredData,
141     bool setNormalStatus, int &errCode)
142 {
143     Assets res = {};
144     bool beCoveredHasAsset = IsDataContainField<Asset>(assetFieldName, beCoveredData) ||
145         IsDataContainField<Assets>(assetFieldName, beCoveredData);
146     bool coveredHasAsset = IsDataContainField<Asset>(assetFieldName, coveredData);
147     if (!beCoveredHasAsset) {
148         if (!coveredHasAsset) {
149             LOGD("[CloudSyncer] Both data do not contain certain asset field");
150             return res;
151         }
152         TagAssetWithNormalStatus(setNormalStatus, AssetOpType::INSERT,
153             std::get<Asset>(coveredData[assetFieldName]), res, errCode);
154         return res;
155     }
156     if (!coveredHasAsset) {
157         if (beCoveredData[assetFieldName].index() == TYPE_INDEX<Asset>) {
158             TagAssetWithNormalStatus(setNormalStatus, AssetOpType::DELETE,
159                 std::get<Asset>(beCoveredData[assetFieldName]), res, errCode);
160         } else if (beCoveredData[assetFieldName].index() == TYPE_INDEX<Assets>) {
161             TagAssetsWithNormalStatus(setNormalStatus, AssetOpType::DELETE,
162                 std::get<Assets>(beCoveredData[assetFieldName]), res, errCode);
163         }
164         return res;
165     }
166     Asset &covered = std::get<Asset>(coveredData[assetFieldName]);
167     Asset beCovered;
168     if (beCoveredData[assetFieldName].index() == TYPE_INDEX<Asset>) {
169         // This indicates that asset in cloudData is stored as Asset
170         beCovered = std::get<Asset>(beCoveredData[assetFieldName]);
171     } else if (beCoveredData[assetFieldName].index() == TYPE_INDEX<Assets>) {
172         // Stored as ASSETS, first element in assets will be the target asset
173         beCovered = (std::get<Assets>(beCoveredData[assetFieldName]))[0];
174     } else {
175         LOGE("The type of data is neither Asset nor Assets");
176         return res;
177     }
178     if (covered.name != beCovered.name) {
179         TagAssetWithNormalStatus(setNormalStatus, AssetOpType::INSERT, covered, res, errCode);
180         TagAssetWithNormalStatus(setNormalStatus, AssetOpType::DELETE, beCovered, res, errCode);
181         return res;
182     }
183     if (covered.hash != beCovered.hash) {
184         TagAssetWithNormalStatus(setNormalStatus, AssetOpType::UPDATE, covered, res, errCode);
185     } else {
186         Assets tmpAssets;
187         TagAssetWithNormalStatus(true, AssetOpType::NO_CHANGE, covered, tmpAssets, errCode);
188     }
189     return res;
190 }
191 } // namespace
192 
TagAssetsInSingleCol(VBucket & coveredData,VBucket & beCoveredData,const Field & assetField,bool setNormalStatus,int & errCode)193 Assets TagAssetsInSingleCol(
194     VBucket &coveredData, VBucket &beCoveredData, const Field &assetField, bool setNormalStatus, int &errCode)
195 {
196     // Define a list to store the tagged result
197     Assets assets = {};
198     switch (assetField.type) {
199         case TYPE_INDEX<Assets>: {
200             assets = TagAssets(assetField.colName, coveredData, beCoveredData, setNormalStatus, errCode);
201             break;
202         }
203         case TYPE_INDEX<Asset>: {
204             assets = TagAsset(assetField.colName, coveredData, beCoveredData, setNormalStatus, errCode);
205             break;
206         }
207         default:
208             LOGW("[CloudSyncer] Meet an unexpected type %d", assetField.type);
209             break;
210     }
211     return assets;
212 }
213 } // namespace DistributedDB
214