• 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_kvstore.h"
17 
18 #include <algorithm>
19 
20 #include "medialibrary_errno.h"
21 #include "medialibrary_tracer.h"
22 #include "media_log.h"
23 
24 using namespace OHOS::DistributedKv;
25 namespace OHOS::Media {
26 const OHOS::DistributedKv::AppId KVSTORE_APPID = {"com.ohos.medialibrary.medialibrarydata"};
27 const OHOS::DistributedKv::StoreId KVSTORE_MONTH_STOREID = {"medialibrary_month_astc_data"};
28 const OHOS::DistributedKv::StoreId KVSTORE_YEAR_STOREID = {"medialibrary_year_astc_data"};
29 const size_t KVSTORE_MAX_NUMBER_BATCH_INSERT = 100;
30 
31 // Different storeId used to distinguish different database
32 const OHOS::DistributedKv::StoreId KVSTORE_MONTH_STOREID_OLD_VERSION = {"medialibrary_month_astc"};
33 const OHOS::DistributedKv::StoreId KVSTORE_YEAR_STOREID_OLD_VERSION = {"medialibrary_year_astc"};
34 
~MediaLibraryKvStore()35 MediaLibraryKvStore::~MediaLibraryKvStore()
36 {
37     Close();
38 }
39 
Init(const KvStoreRoleType & roleType,const KvStoreValueType & valueType,const std::string & baseDir)40 int32_t MediaLibraryKvStore::Init(
41     const KvStoreRoleType &roleType, const KvStoreValueType &valueType, const std::string &baseDir)
42 {
43     MediaLibraryTracer tracer;
44     tracer.Start("MediaLibraryKvStore::InitKvStore");
45     Options options;
46     if (!GetKvStoreOption(options, roleType, baseDir)) {
47         MEDIA_ERR_LOG("failed to GetKvStoreOption");
48         return E_ERR;
49     }
50     MEDIA_INFO_LOG("InitKvStore baseDir %{public}s", options.group.groupDir.c_str());
51     return E_ERR;
52 }
53 
Insert(const std::string & key,const std::vector<uint8_t> & value)54 int32_t MediaLibraryKvStore::Insert(const std::string &key, const std::vector<uint8_t> &value)
55 {
56     if (kvStorePtr_ == nullptr) {
57         MEDIA_ERR_LOG("kvStorePtr_ is nullptr");
58         return E_HAS_DB_ERROR;
59     }
60 
61     MediaLibraryTracer tracer;
62     tracer.Start("MediaLibraryKvStore::Insert");
63     Key k(key);
64     Value v(value);
65     Status status = kvStorePtr_->Put(k, v);
66     if (status != Status::SUCCESS) {
67         MEDIA_ERR_LOG("insert failed, status %{public}d", status);
68     }
69     return static_cast<int32_t>(status);
70 }
71 
Delete(const std::string & key)72 int32_t MediaLibraryKvStore::Delete(const std::string &key)
73 {
74     if (kvStorePtr_ == nullptr) {
75         MEDIA_ERR_LOG("kvStorePtr_ is nullptr");
76         return E_HAS_DB_ERROR;
77     }
78 
79     MediaLibraryTracer tracer;
80     tracer.Start("MediaLibraryKvStore::Delete");
81     Key k(key);
82     Status status = kvStorePtr_->Delete(k);
83     if (status != Status::SUCCESS) {
84         MEDIA_ERR_LOG("delete failed, status %{public}d", status);
85     }
86     return static_cast<int32_t>(status);
87 }
88 
DeleteBatch(const std::vector<std::string> & batchKeys)89 int32_t MediaLibraryKvStore::DeleteBatch(const std::vector<std::string> &batchKeys)
90 {
91     if (kvStorePtr_ == nullptr) {
92         MEDIA_ERR_LOG("kvStorePtr_ is nullptr");
93         return E_HAS_DB_ERROR;
94     }
95 
96     MediaLibraryTracer tracer;
97     tracer.Start("MediaLibraryKvStore::DeleteBatch");
98     std::vector<Key> batchDeleteKeys;
99     for (const std::string &key : batchKeys) {
100         Key k(key);
101         batchDeleteKeys.push_back(k);
102     }
103     Status status = kvStorePtr_->DeleteBatch(batchDeleteKeys);
104     if (status != Status::SUCCESS) {
105         MEDIA_ERR_LOG("delete failed, status %{public}d", status);
106     }
107     return static_cast<int32_t>(status);
108 }
109 
GetCount(const std::string & key,int32_t & count)110 int32_t MediaLibraryKvStore::GetCount(const std::string& key, int32_t& count)
111 {
112     if (kvStorePtr_ == nullptr) {
113         MEDIA_ERR_LOG("kvStorePtr_ is nullptr");
114         return E_HAS_DB_ERROR;
115     }
116 
117     MediaLibraryTracer tracer;
118     tracer.Start("MediaLibraryKvStore::GetCount");
119     DataQuery dataQuery;
120     dataQuery.Between(key, key);
121     std::shared_ptr<KvStoreResultSet> output;
122     Status status = kvStorePtr_->GetResultSet(dataQuery, output);
123     if (status != Status::SUCCESS) {
124         MEDIA_ERR_LOG("delete failed, status %{public}d", status);
125         count = 0;
126     } else {
127         count = output->GetCount();
128     }
129     status = kvStorePtr_->CloseResultSet(output);
130     return static_cast<int32_t>(status);
131 }
132 
Query(const std::string & key,std::vector<uint8_t> & value)133 int32_t MediaLibraryKvStore::Query(const std::string &key, std::vector<uint8_t> &value)
134 {
135     if (kvStorePtr_ == nullptr) {
136         MEDIA_ERR_LOG("kvStorePtr_ is nullptr");
137         return E_HAS_DB_ERROR;
138     }
139 
140     MediaLibraryTracer tracer;
141     tracer.Start("MediaLibraryKvStore::Query");
142     std::vector<uint8_t> tmp;
143     Key k(key);
144     Value v(tmp);
145     Status status = kvStorePtr_->Get(k, v);
146     value = v.Data();
147     if (status != Status::SUCCESS) {
148         MEDIA_ERR_LOG("query failed, status %{public}d", status);
149     }
150     return static_cast<int32_t>(status);
151 }
152 
AddEmptyValue(std::vector<std::vector<uint8_t>> & values)153 void AddEmptyValue(std::vector<std::vector<uint8_t>> &values)
154 {
155     std::vector<uint8_t> value = {};
156     values.emplace_back(std::move(value));
157 }
158 
GenEmptyValues(std::vector<std::string> & batchKeys,std::vector<std::vector<uint8_t>> & values)159 void GenEmptyValues(std::vector<std::string> &batchKeys, std::vector<std::vector<uint8_t>> &values)
160 {
161     for (size_t i = 0; i < batchKeys.size(); i++) {
162         std::vector<uint8_t> value = {};
163         values.emplace_back(std::move(value));
164     }
165 }
166 
FillBatchValues(std::vector<std::string> & batchKeys,std::vector<std::vector<uint8_t>> & values,std::shared_ptr<DistributedKv::SingleKvStore> kvStorePtr)167 int32_t FillBatchValues(std::vector<std::string> &batchKeys, std::vector<std::vector<uint8_t>> &values,
168     std::shared_ptr<DistributedKv::SingleKvStore> kvStorePtr)
169 {
170     DataQuery dataQuery;
171     dataQuery.Between(batchKeys.back(), batchKeys.front());
172     std::shared_ptr<KvStoreResultSet> resultSet;
173     Status status = kvStorePtr->GetResultSet(dataQuery, resultSet);
174     if (status != Status::SUCCESS || resultSet == nullptr) {
175         MEDIA_ERR_LOG("GetResultSet error occur, status: %{public}d", status);
176         return static_cast<int32_t>(status);
177     }
178 
179     if (!resultSet->MoveToNext()) {
180         // This may happen if all images in this group is not generated.
181         MEDIA_ERR_LOG("ResultSet is empty.");
182         GenEmptyValues(batchKeys, values);
183         return static_cast<int32_t>(status);
184     }
185     auto begin = batchKeys.crbegin();
186     auto end = batchKeys.crend();
187     bool isEndOfResultSet = false;
188     while (begin != end) {
189         if (isEndOfResultSet) {
190             AddEmptyValue(values);
191             ++begin;
192             continue;
193         }
194         Entry entry;
195         status = resultSet->GetEntry(entry);
196         if (status != Status::SUCCESS) {
197             MEDIA_ERR_LOG("GetEntry error occur, status: %{public}d", status);
198             return static_cast<int32_t>(status);
199         }
200 
201         int result = std::strcmp(entry.key.ToString().c_str(), (*begin).c_str());
202         if (result == 0) {
203             std::vector<uint8_t>&& value = entry.value;
204             values.emplace_back(std::move(value));
205             ++begin;
206             if (!resultSet->MoveToNext()) {
207                 isEndOfResultSet = true;
208             }
209         } else if (result < 0) {
210             // This may happen if image is hidden or trashed by user.
211             if (!resultSet->MoveToNext()) {
212                 isEndOfResultSet = true;
213             }
214         } else {
215             // This may happen if image is not generated.
216             AddEmptyValue(values);
217             ++begin;
218         }
219     }
220     status = kvStorePtr->CloseResultSet(resultSet);
221     return static_cast<int32_t>(status);
222 }
223 
BatchQuery(std::vector<std::string> & batchKeys,std::vector<std::vector<uint8_t>> & values)224 int32_t MediaLibraryKvStore::BatchQuery(
225     std::vector<std::string> &batchKeys, std::vector<std::vector<uint8_t>> &values)
226 {
227     if (kvStorePtr_ == nullptr) {
228         MEDIA_ERR_LOG("kvStorePtr_ is nullptr");
229         return E_HAS_DB_ERROR;
230     }
231 
232     if (batchKeys.empty()) {
233         MEDIA_ERR_LOG("batchKeys is empty");
234         return E_ERR;
235     }
236 
237     std::sort(batchKeys.begin(), batchKeys.end(), [](std::string a, std::string b) {return a > b;});
238     MediaLibraryTracer tracer;
239     tracer.Start("MediaLibraryKvStore::BatchQuery");
240     return FillBatchValues(batchKeys, values, kvStorePtr_);
241 }
242 
Close()243 bool MediaLibraryKvStore::Close()
244 {
245     MEDIA_INFO_LOG("MediaLibraryKvStore close");
246     MediaLibraryTracer tracer;
247     tracer.Start("MediaLibraryKvStore::Close");
248     if (kvStorePtr_ == nullptr) {
249         MEDIA_ERR_LOG("kvStorePtr_ is nullptr");
250         return true;
251     }
252 
253     Status status = dataManager_.CloseKvStore(KVSTORE_APPID, kvStorePtr_);
254     if (status != Status::SUCCESS) {
255         MEDIA_ERR_LOG("close KvStore failed, status %{public}d", status);
256         return false;
257     }
258     kvStorePtr_ = nullptr;
259     return true;
260 }
261 
GetKvStoreOption(DistributedKv::Options & options,const KvStoreRoleType & roleType,const std::string & baseDir)262 bool MediaLibraryKvStore::GetKvStoreOption(
263     DistributedKv::Options &options, const KvStoreRoleType &roleType, const std::string &baseDir)
264 {
265     if (roleType == KvStoreRoleType::OWNER) {
266         options.createIfMissing = true;
267         options.role = RoleType::OWNER;
268     } else if (roleType == KvStoreRoleType::VISITOR) {
269         options.createIfMissing = false;
270         options.role = RoleType::VISITOR;
271     } else {
272         MEDIA_ERR_LOG("GetKvStoreOption invalid role");
273         return false;
274     }
275     options.group.groupDir = baseDir;
276     options.encrypt = false;
277     options.backup = false;
278     options.autoSync = false;
279     options.securityLevel = SecurityLevel::S3;
280     options.kvStoreType = KvStoreType::LOCAL_ONLY;
281     return true;
282 }
283 
RebuildKvStore(const KvStoreValueType & valueType,const std::string & baseDir)284 int32_t MediaLibraryKvStore::RebuildKvStore(const KvStoreValueType &valueType, const std::string &baseDir)
285 {
286     MEDIA_INFO_LOG("Start RebuildKvStore, type %{public}d", valueType);
287     MediaLibraryTracer tracer;
288     tracer.Start("MediaLibraryKvStore::RebuildKvStore");
289     Status status;
290     tracer.Start("DeleteKvStore");
291     if (valueType == KvStoreValueType::MONTH_ASTC) {
292         status = dataManager_.DeleteKvStore(KVSTORE_APPID, KVSTORE_MONTH_STOREID, baseDir);
293     } else if (valueType == KvStoreValueType::YEAR_ASTC) {
294         status = dataManager_.DeleteKvStore(KVSTORE_APPID, KVSTORE_YEAR_STOREID, baseDir);
295     } else {
296         MEDIA_ERR_LOG("Invalid value type: %{public}d", valueType);
297         return E_ERR;
298     }
299     tracer.Finish();
300 
301     if (status != Status::SUCCESS) {
302         MEDIA_ERR_LOG("Delete kvstore failed, type %{public}d, status %{public}d", valueType, status);
303         return static_cast<int32_t>(status);
304     }
305 
306     int32_t err = Init(KvStoreRoleType::OWNER, valueType, baseDir);
307     if (err != E_OK) {
308         MEDIA_ERR_LOG("Rebuild kvstore failed, type %{public}d, status %{public}d", valueType, err);
309         return err;
310     }
311 
312     if (!Close()) {
313         return E_ERR;
314     }
315     MEDIA_INFO_LOG("RebuildKvStore finish, type %{public}d", valueType);
316     return E_OK;
317 }
318 
BatchInsert(const std::vector<DistributedKv::Entry> & entries)319 int32_t MediaLibraryKvStore::BatchInsert(const std::vector<DistributedKv::Entry> &entries)
320 {
321     if (kvStorePtr_ == nullptr) {
322         MEDIA_ERR_LOG("KvStorePtr is nullptr");
323         return E_HAS_DB_ERROR;
324     }
325     if (entries.empty()) {
326         MEDIA_ERR_LOG("Entries is empty");
327         return E_ERR;
328     }
329 
330     MediaLibraryTracer tracer;
331     tracer.Start("MediaLibraryKvStore::BatchInsert");
332     Status status = kvStorePtr_->PutBatch(entries);
333     if (status != Status::SUCCESS) {
334         MEDIA_ERR_LOG("Batch insert failed, status %{public}d", status);
335         return static_cast<int32_t>(status);
336     }
337     return E_OK;
338 }
339 
InitSingleKvstore(const KvStoreRoleType & roleType,const std::string & storeId,const std::string & baseDir)340 int32_t MediaLibraryKvStore::InitSingleKvstore(const KvStoreRoleType &roleType,
341     const std::string &storeId, const std::string &baseDir)
342 {
343     MediaLibraryTracer tracer;
344     tracer.Start("MediaLibraryKvStore::InitKvStore");
345     Options options;
346     if (roleType == KvStoreRoleType::OWNER) {
347         options.createIfMissing = true;
348         options.role = RoleType::OWNER;
349     } else if (roleType == KvStoreRoleType::VISITOR) {
350         options.createIfMissing = false;
351         options.role = RoleType::VISITOR;
352     } else {
353         MEDIA_ERR_LOG("GetKvStoreOption invalid role");
354         return E_ERR;
355     }
356     options.group.groupDir = baseDir;
357     options.encrypt = false;
358     options.backup = false;
359     options.autoSync = false;
360     options.securityLevel = SecurityLevel::S3;
361     options.kvStoreType = KvStoreType::LOCAL_ONLY;
362 
363     MEDIA_INFO_LOG("InitKvStore baseDir %{public}s", options.group.groupDir.c_str());
364     Status status = dataManager_.GetSingleKvStore(options, KVSTORE_APPID, {storeId}, kvStorePtr_);
365     if (status != Status::SUCCESS) {
366         MEDIA_ERR_LOG("Init kvstore failed, status:%{public}d", status);
367         return static_cast<int32_t>(status);
368     }
369     return E_OK;
370 }
371 
PutAllValueToNewKvStore(std::shared_ptr<MediaLibraryKvStore> & newKvstore)372 int32_t MediaLibraryKvStore::PutAllValueToNewKvStore(std::shared_ptr<MediaLibraryKvStore> &newKvstore)
373 {
374     if (kvStorePtr_ == nullptr) {
375         MEDIA_ERR_LOG("KvStorePtr is nullptr");
376         return E_HAS_DB_ERROR;
377     }
378 
379     MediaLibraryTracer tracer;
380     tracer.Start("MediaLibraryKvStore::PutAllValueToNewKvStore");
381     MEDIA_INFO_LOG("Start PutAllValueToNewKvStore");
382     DataQuery dataQuery;
383     dataQuery.Between("", "Z");
384     std::shared_ptr<KvStoreResultSet> resultSet;
385     Status status = kvStorePtr_->GetResultSet(dataQuery, resultSet);
386     if (status != Status::SUCCESS || resultSet == nullptr) {
387         MEDIA_ERR_LOG("GetResultSet error occur, status: %{public}d", status);
388         return static_cast<int32_t>(status);
389     }
390 
391     std::vector<Entry> entryList;
392     while (resultSet->MoveToNext()) {
393         Entry entry;
394         status = resultSet->GetEntry(entry);
395         if (status != Status::SUCCESS) {
396             MEDIA_ERR_LOG("GetEntry error occur, status: %{public}d", status);
397             return static_cast<int32_t>(status);
398         }
399 
400         entryList.emplace_back(std::move(entry));
401         if (entryList.size() >= KVSTORE_MAX_NUMBER_BATCH_INSERT) {
402             newKvstore->BatchInsert(entryList);
403             entryList.clear();
404         }
405     }
406     if (!entryList.empty()) {
407         newKvstore->BatchInsert(entryList);
408     }
409     status = kvStorePtr_->CloseResultSet(resultSet);
410     MEDIA_INFO_LOG("End PutAllValueToNewKvStore");
411     return static_cast<int32_t>(status);
412 }
413 } // namespace OHOS::Media
414