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