1 /*
2 * Copyright (c) 2025 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 #define MLOG_TAG "AccurateRefresh::AccurateRefreshDataManager"
17
18 #include "media_file_utils.h"
19 #include "accurate_refresh_data_manager.h"
20 #include "medialibrary_unistore_manager.h"
21 #include "accurate_debug_log.h"
22 #include "photo_asset_change_info.h"
23 #include "album_change_info.h"
24 #include "medialibrary_tracer.h"
25
26 using namespace std;
27 using namespace OHOS::NativeRdb;
28
29 namespace OHOS {
30 namespace Media::AccurateRefresh {
31
32 template <typename ChangeInfo, typename ChangeData>
Init(const AbsRdbPredicates & predicates)33 int32_t AccurateRefreshDataManager<ChangeInfo, ChangeData>::Init(const AbsRdbPredicates &predicates)
34 {
35 CHECK_AND_RETURN_RET_WARN_LOG(!CheckIsExceed(), ACCURATE_REFRESH_DATA_EXCEED, "data size exceed");
36 PendingInfo pendingInfo(AlbumAccurateRefreshManager::GetInstance().GetCurrentRefreshTag());
37 MediaLibraryTracer tracer;
38 tracer.Start("AccurateRefreshDataManager::Init predicates");
39 auto initDatas = GetInfosByPredicates(predicates);
40 if (initDatas.empty()) {
41 MEDIA_WARN_LOG("init data empty");
42 return ACCURATE_REFRESH_INIT_EMPTY;
43 }
44 return InsertInitChangeInfos(initDatas, pendingInfo);
45 }
46
47 template <typename ChangeInfo, typename ChangeData>
Init(const string sql,const vector<ValueObject> bindArgs)48 int32_t AccurateRefreshDataManager<ChangeInfo, ChangeData>::Init(const string sql, const vector<ValueObject> bindArgs)
49 {
50 CHECK_AND_RETURN_RET_WARN_LOG(!CheckIsExceed(), ACCURATE_REFRESH_DATA_EXCEED, "data size exceed");
51 CHECK_AND_RETURN_RET_LOG(!sql.empty(), ACCURATE_REFRESH_INPUT_PARA_ERR, "input sql empty");
52 PendingInfo pendingInfo(AlbumAccurateRefreshManager::GetInstance().GetCurrentRefreshTag());
53 MediaLibraryTracer tracer;
54 tracer.Start("AccurateRefreshDataManager::Init sql");
55 shared_ptr<ResultSet> resultSet;
56 if (CanTransOperate()) {
57 resultSet = trans_->QueryByStep(sql, bindArgs);
58 } else {
59 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
60 CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, ACCURATE_REFRESH_RDB_NULL, "rdbStore null");
61 resultSet = rdbStore->QueryByStep(sql, bindArgs);
62 }
63 CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, ACCURATE_REFRESH_RDB_NULL, "resultSet null");
64
65 auto initDatas = GetInfosByResult(resultSet);
66 resultSet->Close();
67 if (initDatas.empty()) {
68 MEDIA_WARN_LOG("initDatas empty");
69 return ACCURATE_REFRESH_INIT_EMPTY;
70 }
71
72 return InsertInitChangeInfos(initDatas, pendingInfo);
73 }
74
75 template <typename ChangeInfo, typename ChangeData>
Init(const vector<int32_t> & keys)76 int32_t AccurateRefreshDataManager<ChangeInfo, ChangeData>::Init(const vector<int32_t> &keys)
77 {
78 CHECK_AND_RETURN_RET_WARN_LOG(!CheckIsExceed(keys.size()), ACCURATE_REFRESH_DATA_EXCEED, "data size exceed");
79 CHECK_AND_RETURN_RET_LOG(!keys.empty(), ACCURATE_REFRESH_INPUT_PARA_ERR, "input keys empty");
80 PendingInfo pendingInfo(AlbumAccurateRefreshManager::GetInstance().GetCurrentRefreshTag());
81 MediaLibraryTracer tracer;
82 tracer.Start("AccurateRefreshDataManager::Init keys");
83 auto initDatas = GetInfoByKeys(keys);
84 if (initDatas.empty()) {
85 MEDIA_WARN_LOG("initDatas empty");
86 return ACCURATE_REFRESH_INPUT_PARA_ERR;
87 }
88
89 return InsertInitChangeInfos(initDatas, pendingInfo);
90 }
91
92 template <typename ChangeInfo, typename ChangeData>
UpdateModifiedDatasInner(const vector<int32_t> & keys,RdbOperation operation,PendingInfo & pendingInfo)93 int32_t AccurateRefreshDataManager<ChangeInfo, ChangeData>::UpdateModifiedDatasInner(const vector<int32_t> &keys,
94 RdbOperation operation, PendingInfo &pendingInfo)
95 {
96 if (keys.empty() || operation == RDB_OPERATION_UNDEFINED) {
97 MEDIA_WARN_LOG("input keys empty or operation error");
98 return ACCURATE_REFRESH_INPUT_PARA_ERR;
99 }
100 CHECK_AND_RETURN_RET_WARN_LOG(!CheckIsExceed(keys.size()), ACCURATE_REFRESH_DATA_EXCEED, "data size exceed");
101 auto ret = ACCURATE_REFRESH_RET_OK;
102 switch (operation) {
103 case RDB_OPERATION_REMOVE:
104 ret = UpdateModifiedDatasForRemove(keys, pendingInfo);
105 break;
106
107 case RDB_OPERATION_ADD:
108 ret = UpdateModifiedDatasForAdd(keys, pendingInfo);
109 break;
110
111 case RDB_OPERATION_UPDATE:
112 ret = UpdateModifiedDatasForUpdate(keys, pendingInfo);
113 break;
114
115 default:
116 return ACCURATE_REFRESH_INPUT_PARA_ERR;
117 }
118 CHECK_AND_RETURN_RET_WARN_LOG(!CheckIsExceed(true), ACCURATE_REFRESH_DATA_EXCEED, "data size exceed");
119 return ret;
120 }
121
122 template <typename ChangeInfo, typename ChangeData>
InsertInitChangeInfos(const vector<ChangeInfo> & changeInfos,PendingInfo pendingInfo)123 int32_t AccurateRefreshDataManager<ChangeInfo, ChangeData>::InsertInitChangeInfos(
124 const vector<ChangeInfo> &changeInfos, PendingInfo pendingInfo)
125 {
126 CHECK_AND_RETURN_RET_WARN_LOG(!CheckIsExceed(changeInfos.size()), ACCURATE_REFRESH_DATA_EXCEED, "data size exceed");
127 for (auto const &changeInfo : changeInfos) {
128 auto key = GetChangeInfoKey(changeInfo);
129 if (changeDatas_.find(key) != changeDatas_.end()) {
130 // 数据重复:打印异常,不替换已有数据继续执行
131 MEDIA_INFO_LOG("operate duplicate init key: %{public}d", key);
132 continue;
133 }
134 ChangeData changeData;
135 changeData.infoBeforeChange_ = changeInfo;
136 PostInsertBeforeData(changeData, pendingInfo);
137 changeDatas_.insert_or_assign(key, changeData); // 插入新值或者替换已有
138 }
139 CHECK_AND_RETURN_RET_WARN_LOG(!CheckIsExceed(true), ACCURATE_REFRESH_DATA_EXCEED, "data size exceed");
140 return ACCURATE_REFRESH_RET_OK;
141 }
142
143 template <typename ChangeInfo, typename ChangeData>
CheckAndUpdateOperation(RdbOperation & newOperation,RdbOperation oldOperation)144 int32_t AccurateRefreshDataManager<ChangeInfo, ChangeData>::CheckAndUpdateOperation(RdbOperation &newOperation,
145 RdbOperation oldOperation)
146 {
147 if (newOperation == RDB_OPERATION_UNDEFINED) {
148 MEDIA_WARN_LOG("new operation undefined");
149 return ACCURATE_REFRESH_INPUT_PARA_ERR;
150 }
151
152 if (oldOperation == RDB_OPERATION_UNDEFINED) {
153 return ACCURATE_REFRESH_RET_OK;
154 }
155
156 // 增改场景支持,还是增
157 if (oldOperation == RDB_OPERATION_ADD && newOperation == RDB_OPERATION_UPDATE) {
158 newOperation = RDB_OPERATION_ADD;
159 return ACCURATE_REFRESH_RET_OK;
160 }
161
162 // 改改场景支持
163 if (oldOperation == RDB_OPERATION_UPDATE && newOperation == RDB_OPERATION_UPDATE) {
164 return ACCURATE_REFRESH_RET_OK;
165 }
166
167 MEDIA_WARN_LOG("duplicate operation, oldOperation:%{public}d, newOperation:%{public}d",
168 static_cast<int32_t>(oldOperation), static_cast<int32_t>(newOperation));
169 return ACCURATE_REFRESH_RET_OK;
170 }
171
172 template <typename ChangeInfo, typename ChangeData>
UpdateModifiedDatasForRemove(const vector<int32_t> & keys,PendingInfo & pendingInfo)173 int32_t AccurateRefreshDataManager<ChangeInfo, ChangeData>::UpdateModifiedDatasForRemove(const vector<int32_t> &keys,
174 PendingInfo &pendingInfo)
175 {
176 ACCURATE_DEBUG("keys size: %{public}zu", keys.size());
177 auto timestamp = MediaFileUtils::UTCTimeMilliSeconds();
178 pendingInfo.end_ = AlbumAccurateRefreshManager::GetInstance().GetCurrentRefreshTag();
179 for (auto key : keys) {
180 auto iter = changeDatas_.find(key);
181 if (iter == changeDatas_.end()) {
182 MEDIA_WARN_LOG("not init info for remove.");
183 return ACCURATE_REFRESH_MODIFIED_NO_INIT;
184 }
185 ChangeData &changeData = iter->second;
186 RdbOperation operation = RDB_OPERATION_REMOVE;
187 auto ret = CheckAndUpdateOperation(operation, changeData.operation_);
188 if (ret != ACCURATE_REFRESH_RET_OK) {
189 return ret;
190 }
191 changeData.operation_ = operation;
192 changeData.isDelete_ = true;
193 changeData.version_ = timestamp;
194 changeData.infoAfterChange_ = ChangeInfo();
195 PostInsertAfterData(changeData, pendingInfo);
196 ACCURATE_INFO("[remove] info: %{public}s", changeData.infoBeforeChange_.ToString(true).c_str());
197 }
198 return ACCURATE_REFRESH_RET_OK;
199 }
200
201 template <typename ChangeInfo, typename ChangeData>
UpdateModifiedDatasForUpdate(const vector<int32_t> & keys,PendingInfo & pendingInfo)202 int32_t AccurateRefreshDataManager<ChangeInfo, ChangeData>::UpdateModifiedDatasForUpdate(const vector<int32_t> &keys,
203 PendingInfo &pendingInfo)
204 {
205 MediaLibraryTracer tracer;
206 tracer.Start("AccurateRefreshDataManager::UpdateModifiedDatasForUpdate");
207 auto &modifiedKeys = keys;
208 auto modifiedDatas = GetInfoByKeys(modifiedKeys);
209 if (modifiedDatas.empty()) {
210 MEDIA_WARN_LOG("modifiedDatas empty");
211 return ACCURATE_REFRESH_MODIFY_EMPTY;
212 }
213 auto timestamp = MediaFileUtils::UTCTimeMilliSeconds();
214 pendingInfo.end_ = AlbumAccurateRefreshManager::GetInstance().GetCurrentRefreshTag();
215 for (auto modifiedInfo : modifiedDatas) {
216 // 找到key
217 auto key = GetChangeInfoKey(modifiedInfo);
218 // 根据key值,找changeData
219 auto iter = changeDatas_.find(key);
220 if (iter == changeDatas_.end()) {
221 MEDIA_WARN_LOG("data no init.");
222 isForRecheck_ = true;
223 return ACCURATE_REFRESH_MODIFIED_NO_INIT;
224 }
225 ChangeData &changeData = iter->second;
226
227 // 更新operation
228 RdbOperation operation = RDB_OPERATION_UPDATE;
229 auto ret = CheckAndUpdateOperation(operation, changeData.operation_);
230 if (ret != ACCURATE_REFRESH_RET_OK) {
231 MEDIA_WARN_LOG("check operation wrong.");
232 return ret;
233 }
234 changeData.operation_ = operation;
235 changeData.version_ = timestamp;
236
237 // 更新infoAfterChange_
238 if (IsValidChangeInfo(changeData.infoAfterChange_)) {
239 MEDIA_INFO_LOG("operate duplicate modified key: %{public}d", key);
240 }
241 changeData.infoAfterChange_ = modifiedInfo;
242 PostInsertAfterData(changeData, pendingInfo);
243 ACCURATE_INFO("operation_: %{public}d isDelete: %{public}d", changeData.operation_, changeData.isDelete_);
244 ACCURATE_INFO("[update] info before: %{public}s", changeData.infoBeforeChange_.ToString(true).c_str());
245 ACCURATE_INFO("change: %{public}s",
246 changeData.infoBeforeChange_.GetDataDiff(changeData.infoAfterChange_).c_str());
247 }
248
249 return ACCURATE_REFRESH_RET_OK;
250 }
251
252 template <typename ChangeInfo, typename ChangeData>
UpdateModifiedDatasForAdd(const vector<int32_t> & keys,PendingInfo & pendingInfo)253 int32_t AccurateRefreshDataManager<ChangeInfo, ChangeData>::UpdateModifiedDatasForAdd(const vector<int32_t> &keys,
254 PendingInfo &pendingInfo)
255 {
256 MediaLibraryTracer tracer;
257 tracer.Start("AccurateRefreshDataManager::UpdateModifiedDatasForAdd");
258 ACCURATE_DEBUG("keys size: %{public}zu", keys.size());
259 auto modifiedDatas = GetInfoByKeys(keys);
260 if (modifiedDatas.empty()) {
261 MEDIA_WARN_LOG("modifiedDatas empty");
262 return ACCURATE_REFRESH_MODIFY_EMPTY;
263 }
264 auto timestamp = MediaFileUtils::UTCTimeMilliSeconds();
265 pendingInfo.end_ = AlbumAccurateRefreshManager::GetInstance().GetCurrentRefreshTag();
266 for (auto &modifiedInfo : modifiedDatas) {
267 // 找到key
268 auto key = GetChangeInfoKey(modifiedInfo);
269 // 根据key值,找changeData
270 auto iter = changeDatas_.find(key);
271 if (iter != changeDatas_.end()) {
272 MEDIA_WARN_LOG("add already info, key: %{public}d", key);
273 return ACCURATE_REFRESH_MODIFIED_ADD_NO_MATCH;
274 }
275
276 // 更新数据
277 ChangeData changeData;
278 changeData.infoAfterChange_ = modifiedInfo;
279 changeData.operation_ = RDB_OPERATION_ADD;
280 changeData.version_ = timestamp;
281 PostInsertAfterData(changeData, pendingInfo, true);
282 changeDatas_.emplace(key, changeData);
283 ACCURATE_INFO("[add] info: %{public}s", changeData.infoAfterChange_.ToString(true).c_str());
284 }
285
286 return ACCURATE_REFRESH_RET_OK;
287 }
288
289 template <typename ChangeInfo, typename ChangeData>
IsValidChangeInfo(const ChangeInfo & changeInfo)290 bool AccurateRefreshDataManager<ChangeInfo, ChangeData>::IsValidChangeInfo(const ChangeInfo &changeInfo)
291 {
292 return GetChangeInfoKey(changeInfo) != INVALID_INT32_VALUE;
293 }
294
295 template <typename ChangeInfo, typename ChangeData>
GetChangeDatas(bool isCheckUpdate)296 vector<ChangeData> AccurateRefreshDataManager<ChangeInfo, ChangeData>::GetChangeDatas(bool isCheckUpdate)
297 {
298 vector<ChangeData> changeDatas;
299 for (auto &data: changeDatas_) {
300 if (isCheckUpdate) {
301 CheckUpdateDataForMultiThread(data.second);
302 }
303 changeDatas.push_back(data.second);
304 }
305 return changeDatas;
306 }
307
308 template <typename ChangeInfo, typename ChangeData>
SetTransaction(std::shared_ptr<TransactionOperations> trans)309 void AccurateRefreshDataManager<ChangeInfo, ChangeData>::SetTransaction(std::shared_ptr<TransactionOperations> trans)
310 {
311 trans_ = trans;
312 }
313
314 template <typename ChangeInfo, typename ChangeData>
GetCurrentDataLength()315 size_t AccurateRefreshDataManager<ChangeInfo, ChangeData>::GetCurrentDataLength()
316 {
317 return changeDatas_.size();
318 }
319
320 template <typename ChangeInfo, typename ChangeData>
CheckIsExceed(bool isLengthChanged)321 bool AccurateRefreshDataManager<ChangeInfo, ChangeData>::CheckIsExceed(bool isLengthChanged)
322 {
323 if (!isLengthChanged) {
324 return isExceed_;
325 }
326
327 if (isExceed_) {
328 return true;
329 }
330
331 isExceed_ = GetCurrentDataLength() >= MAX_DATA_LENGTH;
332 if (isExceed_) {
333 changeDatas_.clear();
334 }
335 return isExceed_;
336 }
337
338 template <typename ChangeInfo, typename ChangeData>
CheckIsExceed(size_t length)339 bool AccurateRefreshDataManager<ChangeInfo, ChangeData>::CheckIsExceed(size_t length)
340 {
341 if (length >= MAX_DATA_LENGTH) {
342 isExceed_ = true;
343 changeDatas_.clear();
344 }
345 return isExceed_;
346 }
347
348 template <typename ChangeInfo, typename ChangeData>
CheckIsForRecheck()349 bool AccurateRefreshDataManager<ChangeInfo, ChangeData>::CheckIsForRecheck()
350 {
351 return isForRecheck_ || CheckIsExceed();
352 }
353
354 template <typename ChangeInfo, typename ChangeData>
CanTransOperate()355 bool AccurateRefreshDataManager<ChangeInfo, ChangeData>::CanTransOperate()
356 {
357 return trans_ != nullptr && trans_->GetIsOperate();
358 }
359
360 template class AccurateRefreshDataManager<PhotoAssetChangeInfo, PhotoAssetChangeData>;
361 template class AccurateRefreshDataManager<AlbumChangeInfo, AlbumChangeData>;
362
363 } // namespace Media
364 } // namespace OHOS