• 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 
16 #include "medialibrary_rdb_transaction.h"
17 #include "medialibrary_restore.h"
18 #include "media_file_utils.h"
19 #include "media_log.h"
20 #include "photo_album_column.h"
21 #include "photo_map_column.h"
22 #include "medialibrary_rdbstore.h"
23 #include "cloud_sync_helper.h"
24 
25 namespace OHOS::Media {
26 using namespace std;
27 using namespace OHOS::NativeRdb;
28 constexpr int32_t E_HAS_DB_ERROR = -222;
29 constexpr int32_t E_OK = 0;
30 
TransactionOperations()31 TransactionOperations::TransactionOperations() {}
32 
~TransactionOperations()33 TransactionOperations::~TransactionOperations()
34 {
35     if (transaction_ == nullptr) {
36         return;
37     }
38     Rollback();
39 }
40 
SetBackupRdbStore(std::shared_ptr<OHOS::NativeRdb::RdbStore> rdbStore)41 void TransactionOperations::SetBackupRdbStore(std::shared_ptr<OHOS::NativeRdb::RdbStore> rdbStore)
42 {
43     backupRdbStore_ = rdbStore;
44 }
45 
Start(std::string funcName,bool isBackup)46 int32_t TransactionOperations::Start(std::string funcName, bool isBackup)
47 {
48     funcName_ = funcName;
49     MEDIA_INFO_LOG("Start transaction_, funName is :%{public}s", funcName_.c_str());
50     if (isBackup) {
51         rdbStore_ = backupRdbStore_;
52     } else {
53         rdbStore_ = MediaLibraryRdbStore::GetRaw();
54     }
55     if (rdbStore_ == nullptr) {
56         MEDIA_ERR_LOG("rdbStore_ is null");
57         return E_HAS_DB_ERROR;
58     }
59 
60     int currentTime = 0;
61     int errCode = -1;
62     while (currentTime <= MAX_TRY_TIMES) {
63         auto [ret, transaction] = rdbStore_->CreateTransaction(OHOS::NativeRdb::Transaction::DEFERRED);
64         errCode = ret;
65         if (ret == NativeRdb::E_OK) {
66             transaction_ = transaction;
67             break;
68         } else if (ret == NativeRdb::E_SQLITE_LOCKED || ret == NativeRdb::E_DATABASE_BUSY) {
69             this_thread::sleep_for(chrono::milliseconds(TRANSACTION_WAIT_INTERVAL));
70             currentTime++;
71             MEDIA_ERR_LOG("CreateTransaction busy, ret:%{public}d, time:%{public}d", ret, currentTime);
72         } else {
73             MEDIA_ERR_LOG("CreateTransaction faile, ret = %{public}d", ret);
74             break;
75         }
76     }
77     if (errCode != NativeRdb::E_OK) {
78         errCode = E_HAS_DB_ERROR;
79     }
80     return errCode;
81 }
82 
Finish()83 int32_t TransactionOperations::Finish()
84 {
85     if (transaction_ == nullptr) {
86         MEDIA_ERR_LOG("transaction is null");
87         return E_HAS_DB_ERROR;
88     }
89     MEDIA_INFO_LOG("Commit transaction, funcName is :%{public}s", funcName_.c_str());
90     auto ret = transaction_->Commit();
91     transaction_ = nullptr;
92     if (ret != NativeRdb::E_OK) {
93         MEDIA_ERR_LOG("transaction commit fail!, ret:%{public}d", ret);
94         return ret;
95     }
96 #ifdef CLOUD_SYNC_MANAGER
97     if (isSkipCloudSync_) {
98         MEDIA_INFO_LOG("recover cloud sync for commit");
99         CloudSyncHelper::GetInstance()->StartSync();
100         isSkipCloudSync_ = false;
101     }
102 #endif
103     return ret;
104 }
105 
TryTrans(std::function<int (void)> & func,std::string funcName,bool isBackup)106 int32_t TransactionOperations::TryTrans(std::function<int(void)> &func, std::string funcName, bool isBackup)
107 {
108     int32_t err = NativeRdb::E_OK;
109     err = Start(funcName, isBackup);
110     if (err != NativeRdb::E_OK) {
111         MEDIA_ERR_LOG("Failed to begin transaction, err: %{public}d", err);
112         return err;
113     }
114     err = func();
115     if (err != E_OK) {
116         MEDIA_ERR_LOG("TryTrans: trans function fail!, ret:%{public}d", err);
117     }
118     err = Finish();
119     if (err != E_OK) {
120         MEDIA_ERR_LOG("TryTrans: trans finish fail!, ret:%{public}d", err);
121     }
122     return err;
123 }
124 
RetryTrans(std::function<int (void)> & func,std::string funcName,bool isBackup)125 int32_t TransactionOperations::RetryTrans(std::function<int(void)> &func, std::string funcName, bool isBackup)
126 {
127     int32_t err = TryTrans(func, funcName, isBackup);
128     if (err == E_OK) {
129         return err;
130     }
131     if (err == NativeRdb::E_SQLITE_BUSY && !isSkipCloudSync_) {
132         MEDIA_ERR_LOG("TryTrans busy, err:%{public}d", err);
133 #ifdef CLOUD_SYNC_MANAGER
134         MEDIA_INFO_LOG("Stop cloud sync");
135         FileManagement::CloudSync::CloudSyncManager::GetInstance()
136             .StopSync("com.ohos.medialibrary.medialibrarydata");
137         isSkipCloudSync_ = true;
138 #endif
139     }
140     err = TryTrans(func, funcName, isBackup);
141     MEDIA_INFO_LOG("RetryTrans twice result is :%{public}d", err);
142     return err;
143 }
144 
Rollback()145 int32_t TransactionOperations::Rollback()
146 {
147     if (transaction_ == nullptr) {
148         MEDIA_ERR_LOG("transaction_ is null");
149         return NativeRdb::E_OK;
150     }
151     auto ret = transaction_->Rollback();
152     transaction_ = nullptr;
153     if (ret != NativeRdb::E_OK) {
154         MEDIA_ERR_LOG("Rollback fail:%{public}d", ret);
155         return ret;
156     }
157 #ifdef CLOUD_SYNC_MANAGER
158     if (isSkipCloudSync_) {
159         MEDIA_INFO_LOG("recover cloud sync for rollback");
160         CloudSyncHelper::GetInstance()->StartSync();
161         isSkipCloudSync_ = false;
162     }
163 #endif
164     return ret;
165 }
166 
ExecuteSql(const std::string & sql,const std::vector<NativeRdb::ValueObject> & args)167 int32_t TransactionOperations::ExecuteSql(const std::string &sql, const std::vector<NativeRdb::ValueObject> &args)
168 {
169     if (transaction_ == nullptr) {
170         MEDIA_ERR_LOG("transaction is null");
171         return E_HAS_DB_ERROR;
172     }
173     auto [ret, value] = transaction_->Execute(sql, args);
174     if (ret != NativeRdb::E_OK) {
175         MEDIA_ERR_LOG("rdbStore_->ExecuteSql failed, ret = %{public}d", ret);
176         MediaLibraryRestore::GetInstance().CheckRestore(ret);
177         return E_HAS_DB_ERROR;
178     }
179     return ret;
180 }
181 
Execute(const std::string & sql,const std::vector<NativeRdb::ValueObject> & args)182 int32_t TransactionOperations::Execute(const std::string &sql, const std::vector<NativeRdb::ValueObject> &args)
183 {
184     if (transaction_ == nullptr) {
185         MEDIA_ERR_LOG("transaction is null");
186         return E_HAS_DB_ERROR;
187     }
188     auto [ret, value] = transaction_->Execute(sql, args);
189     if (ret != NativeRdb::E_OK) {
190         MEDIA_ERR_LOG("rdbStore_->Execute failed, ret = %{public}d", ret);
191         MediaLibraryRestore::GetInstance().CheckRestore(ret);
192         return E_HAS_DB_ERROR;
193     }
194     return ret;
195 }
196 
ExecuteForLastInsertedRowId(const std::string & sql,const std::vector<NativeRdb::ValueObject> & bindArgs)197 int32_t TransactionOperations::ExecuteForLastInsertedRowId(const std::string &sql,
198     const std::vector<NativeRdb::ValueObject> &bindArgs)
199 {
200     if (transaction_ == nullptr) {
201         MEDIA_ERR_LOG("transaction is null");
202         return E_HAS_DB_ERROR;
203     }
204     int64_t lastInsertRowId = 0;
205     auto [err, valueObject] = transaction_->Execute(sql, bindArgs);
206     (void)valueObject.GetLong(lastInsertRowId);
207     if (err != E_OK) {
208         MEDIA_ERR_LOG("Failed to execute insert, err: %{public}d", err);
209         MediaLibraryRestore::GetInstance().CheckRestore(err);
210         return E_HAS_DB_ERROR;
211     }
212     return lastInsertRowId;
213 }
214 
Insert(MediaLibraryCommand & cmd,int64_t & rowId)215 int32_t TransactionOperations::Insert(MediaLibraryCommand &cmd, int64_t &rowId)
216 {
217     if (transaction_ == nullptr) {
218         MEDIA_ERR_LOG("transaction is null");
219         return E_HAS_DB_ERROR;
220     }
221     auto [ret, rows] = transaction_->Insert(cmd.GetTableName(), cmd.GetValueBucket());
222     rowId = rows;
223     if (ret != NativeRdb::E_OK) {
224         MEDIA_ERR_LOG("rdbStore_->Insert failed, ret = %{public}d", ret);
225         MediaLibraryRestore::GetInstance().CheckRestore(ret);
226         return E_HAS_DB_ERROR;
227     }
228 
229     MEDIA_DEBUG_LOG("rdbStore_->Insert end, rowId = %d, ret = %{public}d", (int)rowId, ret);
230     return ret;
231 }
232 
Update(NativeRdb::ValuesBucket & values,const NativeRdb::AbsRdbPredicates & predicates)233 int32_t TransactionOperations::Update(NativeRdb::ValuesBucket &values, const NativeRdb::AbsRdbPredicates &predicates)
234 {
235     if (transaction_ == nullptr) {
236         MEDIA_ERR_LOG("transaction is null");
237         return E_HAS_DB_ERROR;
238     }
239         if (predicates.GetTableName() == PhotoColumn::PHOTOS_TABLE) {
240         values.PutLong(PhotoColumn::PHOTO_META_DATE_MODIFIED, MediaFileUtils::UTCTimeMilliSeconds());
241         values.PutLong(PhotoColumn::PHOTO_LAST_VISIT_TIME, MediaFileUtils::UTCTimeMilliSeconds());
242     }
243     auto [err, changedRows] = transaction_->Update(values, predicates);
244     if (err != E_OK) {
245         MEDIA_ERR_LOG("Failed to execute update, err: %{public}d", err);
246         MediaLibraryRestore::GetInstance().CheckRestore(err);
247         return E_HAS_DB_ERROR;
248     }
249     return changedRows;
250 }
251 
Update(int32_t & changedRows,NativeRdb::ValuesBucket & values,const NativeRdb::AbsRdbPredicates & predicates)252 int32_t TransactionOperations::Update(int32_t &changedRows, NativeRdb::ValuesBucket &values,
253     const NativeRdb::AbsRdbPredicates &predicates)
254 {
255     if (transaction_ == nullptr) {
256         MEDIA_ERR_LOG("transaction is null");
257         return E_HAS_DB_ERROR;
258     }
259         auto [err, rows] = transaction_->Update(values, predicates);
260     changedRows = rows;
261     if (err != E_OK) {
262         MEDIA_ERR_LOG("Failed to execute update, err: %{public}d", err);
263         MediaLibraryRestore::GetInstance().CheckRestore(err);
264         return err;
265     }
266     return err;
267 }
268 
Update(MediaLibraryCommand & cmd,int32_t & changedRows)269 int32_t TransactionOperations::Update(MediaLibraryCommand &cmd, int32_t &changedRows)
270 {
271     if (transaction_ == nullptr) {
272         MEDIA_ERR_LOG("transaction_ is null");
273         return E_HAS_DB_ERROR;
274     }
275     if (cmd.GetTableName() == PhotoColumn::PHOTOS_TABLE) {
276         cmd.GetValueBucket().PutLong(PhotoColumn::PHOTO_META_DATE_MODIFIED,
277             MediaFileUtils::UTCTimeMilliSeconds());
278         cmd.GetValueBucket().PutLong(PhotoColumn::PHOTO_LAST_VISIT_TIME,
279             MediaFileUtils::UTCTimeMilliSeconds());
280     }
281 
282     int32_t ret = E_HAS_DB_ERROR;
283     auto res = transaction_->Update(cmd.GetTableName(), cmd.GetValueBucket(),
284         cmd.GetAbsRdbPredicates()->GetWhereClause(), cmd.GetAbsRdbPredicates()->GetBindArgs());
285     ret = res.first;
286     changedRows = res.second;
287 
288     if (ret != NativeRdb::E_OK) {
289         MEDIA_ERR_LOG("rdbStore_->Update failed, ret = %{public}d", ret);
290         MediaLibraryRestore::GetInstance().CheckRestore(ret);
291         return E_HAS_DB_ERROR;
292     }
293     return ret;
294 }
295 
BatchInsert(int64_t & outRowId,const std::string & table,const std::vector<NativeRdb::ValuesBucket> & values)296 int32_t TransactionOperations::BatchInsert(int64_t &outRowId, const std::string &table,
297     const std::vector<NativeRdb::ValuesBucket> &values)
298 {
299     if (transaction_ == nullptr) {
300         MEDIA_ERR_LOG("transaction_ is null");
301         return E_HAS_DB_ERROR;
302     }
303     auto [ret, rows] = transaction_->BatchInsert(table, values);
304     outRowId = rows;
305     if (ret != NativeRdb::E_OK) {
306         MEDIA_ERR_LOG("transaction_->BatchInsert failed, ret = %{public}d", ret);
307         MediaLibraryRestore::GetInstance().CheckRestore(ret);
308         return E_HAS_DB_ERROR;
309     }
310     MEDIA_DEBUG_LOG("transaction_->BatchInsert end, rowId = %d, ret = %{public}d", (int)outRowId, ret);
311     return ret;
312 }
313 
BatchInsert(MediaLibraryCommand & cmd,int64_t & outInsertNum,const std::vector<ValuesBucket> & values)314 int32_t TransactionOperations::BatchInsert(MediaLibraryCommand &cmd, int64_t& outInsertNum,
315     const std::vector<ValuesBucket>& values)
316 {
317     if (transaction_ == nullptr) {
318         MEDIA_ERR_LOG("transaction_ is null");
319         return E_HAS_DB_ERROR;
320     }
321     auto [ret, rows] = transaction_->BatchInsert(cmd.GetTableName(), values);
322     outInsertNum = rows;
323     if (ret != NativeRdb::E_OK) {
324         MEDIA_ERR_LOG("transaction_->BatchInsert failed, ret = %{public}d", ret);
325         MediaLibraryRestore::GetInstance().CheckRestore(ret);
326         return E_HAS_DB_ERROR;
327     }
328     MEDIA_DEBUG_LOG("rdbStore_->BatchInsert end, rowId = %d, ret = %{public}d", (int)outInsertNum, ret);
329     return ret;
330 }
331 
Insert(int64_t & rowId,const std::string tableName,const NativeRdb::ValuesBucket & values)332 int32_t TransactionOperations::Insert(int64_t &rowId, const std::string tableName,
333     const NativeRdb::ValuesBucket &values)
334 {
335     if (transaction_ == nullptr) {
336         MEDIA_ERR_LOG("transaction_ is null");
337         return E_HAS_DB_ERROR;
338     }
339 
340     auto [ret, rows] = transaction_->Insert(tableName, values);
341     rowId = rows;
342     if (ret != NativeRdb::E_OK) {
343         MEDIA_ERR_LOG("transaction_->Insert failed, ret = %{public}d", ret);
344         MediaLibraryRestore::GetInstance().CheckRestore(ret);
345         return E_HAS_DB_ERROR;
346     }
347 
348     MEDIA_DEBUG_LOG("transaction_->Insert end, rowId = %d, ret = %{public}d", (int)rowId, ret);
349     return ret;
350 }
351 
DoDeleteFromPredicates(const AbsRdbPredicates & predicates,int32_t & deletedRows,std::shared_ptr<OHOS::NativeRdb::Transaction> transaction)352 static int32_t DoDeleteFromPredicates(const AbsRdbPredicates &predicates,
353     int32_t &deletedRows, std::shared_ptr<OHOS::NativeRdb::Transaction> transaction)
354 {
355     int32_t ret = NativeRdb::E_ERROR;
356     string tableName = predicates.GetTableName();
357     ValuesBucket valuesBucket;
358     if (tableName == MEDIALIBRARY_TABLE || tableName == PhotoColumn::PHOTOS_TABLE) {
359         valuesBucket.PutInt(MEDIA_DATA_DB_DIRTY, static_cast<int32_t>(DirtyType::TYPE_DELETED));
360         valuesBucket.PutInt(MEDIA_DATA_DB_SYNC_STATUS, static_cast<int32_t>(SyncStatusType::TYPE_UPLOAD));
361         valuesBucket.PutLong(PhotoColumn::PHOTO_META_DATE_MODIFIED, MediaFileUtils::UTCTimeMilliSeconds());
362         auto res = transaction->Update(valuesBucket, predicates);
363         ret = res.first;
364         deletedRows = res.second;
365         MEDIA_INFO_LOG("delete photos permanently, ret: %{public}d", ret);
366     } else if (tableName == PhotoAlbumColumns::TABLE) {
367         valuesBucket.PutInt(PhotoAlbumColumns::ALBUM_DIRTY, static_cast<int32_t>(DirtyType::TYPE_DELETED));
368         auto res = transaction->Update(valuesBucket, predicates);
369         ret = res.first;
370         deletedRows = res.second;
371     } else if (tableName == PhotoMap::TABLE) {
372         valuesBucket.PutInt(PhotoMap::DIRTY, static_cast<int32_t>(DirtyType::TYPE_DELETED));
373         auto res = transaction->Update(valuesBucket, predicates);
374         ret = res.first;
375         deletedRows = res.second;
376     } else {
377         auto res = transaction->Delete(predicates);
378         ret = res.first;
379         deletedRows = res.second;
380     }
381     return ret;
382 }
383 
Delete(MediaLibraryCommand & cmd,int32_t & deletedRows)384 int32_t TransactionOperations::Delete(MediaLibraryCommand &cmd, int32_t &deletedRows)
385 {
386     if (transaction_ == nullptr) {
387         MEDIA_ERR_LOG("transaction_ is null");
388         return E_HAS_DB_ERROR;
389     }
390     /* local delete */
391     int32_t ret = DoDeleteFromPredicates(*(cmd.GetAbsRdbPredicates()), deletedRows, transaction_);
392     if (ret != NativeRdb::E_OK) {
393         MEDIA_ERR_LOG("rdbStore_->Delete failed, ret = %{public}d", ret);
394         MediaLibraryRestore::GetInstance().CheckRestore(ret);
395         return E_HAS_DB_ERROR;
396     }
397     return ret;
398 }
399 } // namespace OHOS::Media
400