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
30 // Different storeId used to distinguish different database
31 const OHOS::DistributedKv::StoreId KVSTORE_MONTH_STOREID_OLD_VERSION = {"medialibrary_month_astc"};
32 const OHOS::DistributedKv::StoreId KVSTORE_YEAR_STOREID_OLD_VERSION = {"medialibrary_year_astc"};
33
~MediaLibraryKvStore()34 MediaLibraryKvStore::~MediaLibraryKvStore()
35 {
36 Close();
37 }
38
Init(const KvStoreRoleType & roleType,const KvStoreValueType & valueType,const std::string & baseDir)39 int32_t MediaLibraryKvStore::Init(
40 const KvStoreRoleType &roleType, const KvStoreValueType &valueType, const std::string &baseDir)
41 {
42 MediaLibraryTracer tracer;
43 tracer.Start("MediaLibraryKvStore::InitKvStore");
44 Options options;
45 if (!GetKvStoreOption(options, roleType, baseDir)) {
46 MEDIA_ERR_LOG("failed to GetKvStoreOption");
47 return E_ERR;
48 }
49
50 MEDIA_INFO_LOG("InitKvStore baseDir %{public}s", options.group.groupDir.c_str());
51 Status status;
52 if (valueType == KvStoreValueType::MONTH_ASTC) {
53 status = dataManager_.GetSingleKvStore(options, KVSTORE_APPID, KVSTORE_MONTH_STOREID, kvStorePtr_);
54 } else if (valueType == KvStoreValueType::YEAR_ASTC) {
55 status = dataManager_.GetSingleKvStore(options, KVSTORE_APPID, KVSTORE_YEAR_STOREID, kvStorePtr_);
56 } else if (valueType == KvStoreValueType::MONTH_ASTC_OLD_VERSION) {
57 status = dataManager_.GetSingleKvStore(options, KVSTORE_APPID, KVSTORE_MONTH_STOREID_OLD_VERSION, kvStorePtr_);
58 } else if (valueType == KvStoreValueType::YEAR_ASTC_OLD_VERSION) {
59 status = dataManager_.GetSingleKvStore(options, KVSTORE_APPID, KVSTORE_YEAR_STOREID_OLD_VERSION, kvStorePtr_);
60 } else {
61 MEDIA_ERR_LOG("invalid value type");
62 return E_ERR;
63 }
64
65 if (status != Status::SUCCESS || kvStorePtr_ == nullptr) {
66 MEDIA_ERR_LOG("init KvStore failed, status %{public}d", status);
67 return static_cast<int32_t>(status);
68 }
69 return E_OK;
70 }
71
Insert(const std::string & key,const std::vector<uint8_t> & value)72 int32_t MediaLibraryKvStore::Insert(const std::string &key, const std::vector<uint8_t> &value)
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::Insert");
81 Key k(key);
82 Value v(value);
83 Status status = kvStorePtr_->Put(k, v);
84 if (status != Status::SUCCESS) {
85 MEDIA_ERR_LOG("insert failed, status %{public}d", status);
86 }
87 return static_cast<int32_t>(status);
88 }
89
Delete(const std::string & key)90 int32_t MediaLibraryKvStore::Delete(const std::string &key)
91 {
92 if (kvStorePtr_ == nullptr) {
93 MEDIA_ERR_LOG("kvStorePtr_ is nullptr");
94 return E_HAS_DB_ERROR;
95 }
96
97 MediaLibraryTracer tracer;
98 tracer.Start("MediaLibraryKvStore::Delete");
99 Key k(key);
100 Status status = kvStorePtr_->Delete(k);
101 if (status != Status::SUCCESS) {
102 MEDIA_ERR_LOG("delete failed, status %{public}d", status);
103 }
104 return static_cast<int32_t>(status);
105 }
106
Query(const std::string & key,std::vector<uint8_t> & value)107 int32_t MediaLibraryKvStore::Query(const std::string &key, std::vector<uint8_t> &value)
108 {
109 if (kvStorePtr_ == nullptr) {
110 MEDIA_ERR_LOG("kvStorePtr_ is nullptr");
111 return E_HAS_DB_ERROR;
112 }
113
114 MediaLibraryTracer tracer;
115 tracer.Start("MediaLibraryKvStore::Query");
116 std::vector<uint8_t> tmp;
117 Key k(key);
118 Value v(tmp);
119 Status status = kvStorePtr_->Get(k, v);
120 value = v.Data();
121 if (status != Status::SUCCESS) {
122 MEDIA_ERR_LOG("query failed, status %{public}d", status);
123 }
124 return static_cast<int32_t>(status);
125 }
126
AddEmptyValue(std::vector<std::vector<uint8_t>> & values)127 void AddEmptyValue(std::vector<std::vector<uint8_t>> &values)
128 {
129 std::vector<uint8_t> value = {};
130 values.emplace_back(std::move(value));
131 }
132
GenEmptyValues(std::vector<std::string> & batchKeys,std::vector<std::vector<uint8_t>> & values)133 void GenEmptyValues(std::vector<std::string> &batchKeys, std::vector<std::vector<uint8_t>> &values)
134 {
135 for (size_t i = 0; i < batchKeys.size(); i++) {
136 std::vector<uint8_t> value = {};
137 values.emplace_back(std::move(value));
138 }
139 }
140
FillBatchValues(std::vector<std::string> & batchKeys,std::vector<std::vector<uint8_t>> & values,std::shared_ptr<DistributedKv::SingleKvStore> kvStorePtr)141 int32_t FillBatchValues(std::vector<std::string> &batchKeys, std::vector<std::vector<uint8_t>> &values,
142 std::shared_ptr<DistributedKv::SingleKvStore> kvStorePtr)
143 {
144 DataQuery dataQuery;
145 dataQuery.Between(batchKeys.back(), batchKeys.front());
146 std::shared_ptr<KvStoreResultSet> resultSet;
147 Status status = kvStorePtr->GetResultSet(dataQuery, resultSet);
148 if (status != Status::SUCCESS || resultSet == nullptr) {
149 MEDIA_ERR_LOG("GetResultSet error occur, status: %{public}d", status);
150 return static_cast<int32_t>(status);
151 }
152
153 if (!resultSet->MoveToNext()) {
154 // This may happen if all images in this group is not generated.
155 MEDIA_ERR_LOG("ResultSet is empty.");
156 GenEmptyValues(batchKeys, values);
157 return static_cast<int32_t>(status);
158 }
159 auto begin = batchKeys.crbegin();
160 auto end = batchKeys.crend();
161 bool isEndOfResultSet = false;
162 while (begin != end) {
163 if (isEndOfResultSet) {
164 AddEmptyValue(values);
165 ++begin;
166 continue;
167 }
168 Entry entry;
169 status = resultSet->GetEntry(entry);
170 if (status != Status::SUCCESS) {
171 MEDIA_ERR_LOG("GetEntry error occur, status: %{public}d", status);
172 return static_cast<int32_t>(status);
173 }
174
175 int result = std::strcmp(entry.key.ToString().c_str(), (*begin).c_str());
176 if (result == 0) {
177 std::vector<uint8_t>&& value = entry.value;
178 values.emplace_back(std::move(value));
179 ++begin;
180 if (!resultSet->MoveToNext()) {
181 isEndOfResultSet = true;
182 }
183 } else if (result < 0) {
184 // This may happen if image is hidden or trashed by user.
185 if (!resultSet->MoveToNext()) {
186 isEndOfResultSet = true;
187 }
188 } else {
189 // This may happen if image is not generated.
190 AddEmptyValue(values);
191 ++begin;
192 }
193 }
194 status = kvStorePtr->CloseResultSet(resultSet);
195 return static_cast<int32_t>(status);
196 }
197
BatchQuery(std::vector<std::string> & batchKeys,std::vector<std::vector<uint8_t>> & values)198 int32_t MediaLibraryKvStore::BatchQuery(
199 std::vector<std::string> &batchKeys, std::vector<std::vector<uint8_t>> &values)
200 {
201 if (kvStorePtr_ == nullptr) {
202 MEDIA_ERR_LOG("kvStorePtr_ is nullptr");
203 return E_HAS_DB_ERROR;
204 }
205
206 if (batchKeys.empty()) {
207 MEDIA_ERR_LOG("batchKeys is empty");
208 return E_ERR;
209 }
210
211 std::sort(batchKeys.begin(), batchKeys.end(), [](std::string a, std::string b) {return a > b;});
212 MediaLibraryTracer tracer;
213 tracer.Start("MediaLibraryKvStore::BatchQuery");
214 return FillBatchValues(batchKeys, values, kvStorePtr_);
215 }
216
Close()217 bool MediaLibraryKvStore::Close()
218 {
219 MediaLibraryTracer tracer;
220 tracer.Start("MediaLibraryKvStore::Close");
221 if (kvStorePtr_ == nullptr) {
222 MEDIA_ERR_LOG("kvStorePtr_ is nullptr");
223 return true;
224 }
225
226 Status status = dataManager_.CloseKvStore(KVSTORE_APPID, kvStorePtr_);
227 if (status != Status::SUCCESS) {
228 MEDIA_ERR_LOG("close KvStore failed, status %{public}d", status);
229 return false;
230 }
231 kvStorePtr_ = nullptr;
232 return true;
233 }
234
GetKvStoreOption(DistributedKv::Options & options,const KvStoreRoleType & roleType,const std::string & baseDir)235 bool MediaLibraryKvStore::GetKvStoreOption(
236 DistributedKv::Options &options, const KvStoreRoleType &roleType, const std::string &baseDir)
237 {
238 if (roleType == KvStoreRoleType::OWNER) {
239 options.createIfMissing = true;
240 options.role = RoleType::OWNER;
241 } else if (roleType == KvStoreRoleType::VISITOR) {
242 options.createIfMissing = false;
243 options.role = RoleType::VISITOR;
244 } else {
245 MEDIA_ERR_LOG("GetKvStoreOption invalid role");
246 return false;
247 }
248 options.group.groupDir = baseDir;
249 options.encrypt = false;
250 options.backup = false;
251 options.autoSync = false;
252 options.securityLevel = SecurityLevel::S3;
253 options.kvStoreType = KvStoreType::LOCAL_ONLY;
254 return true;
255 }
256
RebuildKvStore(const KvStoreValueType & valueType,const std::string & baseDir)257 int32_t MediaLibraryKvStore::RebuildKvStore(const KvStoreValueType &valueType, const std::string &baseDir)
258 {
259 MEDIA_INFO_LOG("Start RebuildKvStore, type %{public}d", valueType);
260 MediaLibraryTracer tracer;
261 tracer.Start("MediaLibraryKvStore::RebuildKvStore");
262 Status status;
263 tracer.Start("DeleteKvStore");
264 if (valueType == KvStoreValueType::MONTH_ASTC) {
265 status = dataManager_.DeleteKvStore(KVSTORE_APPID, KVSTORE_MONTH_STOREID, baseDir);
266 } else if (valueType == KvStoreValueType::YEAR_ASTC) {
267 status = dataManager_.DeleteKvStore(KVSTORE_APPID, KVSTORE_YEAR_STOREID, baseDir);
268 } else {
269 MEDIA_ERR_LOG("Invalid value type: %{public}d", valueType);
270 return E_ERR;
271 }
272 tracer.Finish();
273
274 if (status != Status::SUCCESS) {
275 MEDIA_ERR_LOG("Delete kvstore failed, type %{public}d, status %{public}d", valueType, status);
276 return static_cast<int32_t>(status);
277 }
278
279 int32_t err = Init(KvStoreRoleType::OWNER, valueType, baseDir);
280 if (err != E_OK) {
281 MEDIA_ERR_LOG("Rebuild kvstore failed, type %{public}d, status %{public}d", valueType, err);
282 return err;
283 }
284
285 if (!Close()) {
286 return E_ERR;
287 }
288 MEDIA_INFO_LOG("RebuildKvStore finish, type %{public}d", valueType);
289 return E_OK;
290 }
291 } // namespace OHOS::Media
292