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