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