1 /*
2 * Copyright (c) 2024 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 "preferences_enhance_impl.h"
17
18 #include <cinttypes>
19 #include <climits>
20 #include <cstdint>
21 #include <cstdlib>
22 #include <functional>
23 #include <sstream>
24 #include <thread>
25
26 #include "executor_pool.h"
27 #include "preferences_file_operation.h"
28 #include "log_print.h"
29 #include "preferences_observer_stub.h"
30 #include "preferences_value.h"
31 #include "preferences_value_parcel.h"
32
33 namespace OHOS {
34 namespace NativePreferences {
35
36 constexpr int32_t CACHED_THRESHOLDS = 512 * 1024; // we will cached big obj(len >= 512k)
37
PreferencesEnhanceImpl(const Options &options)38 PreferencesEnhanceImpl::PreferencesEnhanceImpl(const Options &options): PreferencesBase(options)
39 {
40 }
41
~PreferencesEnhanceImpl()42 PreferencesEnhanceImpl::~PreferencesEnhanceImpl()
43 {
44 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
45 db_ = nullptr;
46 }
47
Init()48 int PreferencesEnhanceImpl::Init()
49 {
50 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
51 db_ = std::make_shared<PreferencesDb>();
52 cachedDataVersion_ = 0;
53 int errCode = db_->Init(options_.filePath, options_.bundleName);
54 if (errCode != E_OK) {
55 db_ = nullptr;
56 }
57 return errCode;
58 }
59
Get(const std::string &key, const PreferencesValue &defValue)60 PreferencesValue PreferencesEnhanceImpl::Get(const std::string &key, const PreferencesValue &defValue)
61 {
62 if (CheckKey(key) != E_OK) {
63 return defValue;
64 }
65 // write lock here, get not support concurrence
66 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
67 if (db_ == nullptr) {
68 LOG_ERROR("PreferencesEnhanceImpl:Get failed, db has been closed.");
69 return defValue;
70 }
71
72 int64_t kernelDataVersion = 0;
73 if (db_->GetKernelDataVersion(kernelDataVersion) != E_OK) {
74 LOG_ERROR("PreferencesEnhanceImpl:Get failed, get kernel data version failed.");
75 return defValue;
76 }
77 if (kernelDataVersion == cachedDataVersion_) {
78 auto it = largeCachedData_.find(key);
79 if (it != largeCachedData_.end()) {
80 return it->second;
81 }
82 }
83
84 std::vector<uint8_t> oriKey(key.begin(), key.end());
85 std::vector<uint8_t> oriValue;
86 int errCode = db_->Get(oriKey, oriValue);
87 if (errCode != E_OK) {
88 LOG_ERROR("get key failed, errCode=%{public}d", errCode);
89 return defValue;
90 }
91 auto item = PreferencesValueParcel::UnmarshallingPreferenceValue(oriValue);
92 if (item.first != E_OK) {
93 LOG_ERROR("get key failed, errCode=%{public}d", item.first);
94 return defValue;
95 }
96 if (oriValue.size() >= CACHED_THRESHOLDS) {
97 largeCachedData_.insert_or_assign(key, item.second);
98 cachedDataVersion_ = kernelDataVersion;
99 }
100 return item.second;
101 }
102
HasKey(const std::string &key)103 bool PreferencesEnhanceImpl::HasKey(const std::string &key)
104 {
105 if (CheckKey(key) != E_OK) {
106 return false;
107 }
108 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
109 if (db_ == nullptr) {
110 LOG_ERROR("PreferencesEnhanceImpl:HasKey failed, db has been closed.");
111 return false;
112 }
113
114 int64_t kernelDataVersion = 0;
115 if (db_->GetKernelDataVersion(kernelDataVersion) != E_OK) {
116 LOG_ERROR("PreferencesEnhanceImpl:HasKey failed, get kernel data version failed.");
117 return false;
118 }
119 if (kernelDataVersion == cachedDataVersion_) {
120 auto it = largeCachedData_.find(key);
121 if (it != largeCachedData_.end()) {
122 return true;
123 }
124 }
125
126 std::vector<uint8_t> oriKey(key.begin(), key.end());
127 std::vector<uint8_t> oriValue;
128 int errCode = db_->Get(oriKey, oriValue);
129 if (errCode != E_OK) {
130 LOG_ERROR("get key failed, errCode=%{public}d", errCode);
131 return false;
132 }
133 if (oriValue.size() >= CACHED_THRESHOLDS) {
134 auto item = PreferencesValueParcel::UnmarshallingPreferenceValue(oriValue);
135 if (item.first != E_OK) {
136 LOG_WARN("haskey unmarshall failed, haskey return true, errCode=%{public}d", item.first);
137 return true;
138 }
139 largeCachedData_.insert_or_assign(key, item.second);
140 cachedDataVersion_ = kernelDataVersion;
141 }
142 return true;
143 }
144
Put(const std::string &key, const PreferencesValue &value)145 int PreferencesEnhanceImpl::Put(const std::string &key, const PreferencesValue &value)
146 {
147 int errCode = CheckKey(key);
148 if (errCode != E_OK) {
149 return errCode;
150 }
151 errCode = CheckValue(value);
152 if (errCode != E_OK) {
153 return errCode;
154 }
155 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
156 if (db_ == nullptr) {
157 LOG_ERROR("PreferencesEnhanceImpl:Put failed, db has been closed.");
158 return E_ERROR;
159 }
160
161 std::vector<uint8_t> oriValue;
162 uint32_t oriValueLen = PreferencesValueParcel::CalSize(value);
163 oriValue.resize(oriValueLen);
164 errCode = PreferencesValueParcel::MarshallingPreferenceValue(value, oriValue);
165 if (errCode != E_OK) {
166 LOG_ERROR("marshalling value failed, errCode=%{public}d", errCode);
167 return errCode;
168 }
169 std::vector<uint8_t> oriKey(key.begin(), key.end());
170 errCode = db_->Put(oriKey, oriValue);
171 if (errCode != E_OK) {
172 LOG_ERROR("put data failed, errCode=%{public}d", errCode);
173 return errCode;
174 }
175
176 // update cached and version
177 if (oriValueLen >= CACHED_THRESHOLDS) {
178 largeCachedData_.insert_or_assign(key, value);
179 cachedDataVersion_ = cachedDataVersion_ == INT64_MAX ? 0 : cachedDataVersion_ + 1;
180 } else {
181 auto pos = largeCachedData_.find(key);
182 if (pos != largeCachedData_.end()) {
183 largeCachedData_.erase(pos);
184 }
185 }
186
187 ExecutorPool::Task task = [pref = shared_from_this(), key, value] {
188 PreferencesEnhanceImpl::NotifyPreferencesObserver(pref, key, value);
189 };
190 executorPool_.Execute(std::move(task));
191 return E_OK;
192 }
193
Delete(const std::string &key)194 int PreferencesEnhanceImpl::Delete(const std::string &key)
195 {
196 int errCode = CheckKey(key);
197 if (errCode != E_OK) {
198 return errCode;
199 }
200 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
201 if (db_ == nullptr) {
202 LOG_ERROR("PreferencesEnhanceImpl:Delete failed, db has been closed.");
203 return E_ERROR;
204 }
205
206 std::vector<uint8_t> oriKey(key.begin(), key.end());
207 errCode = db_->Delete(oriKey);
208 if (errCode != E_OK) {
209 LOG_ERROR("delete data failed, errCode=%{public}d", errCode);
210 return errCode;
211 }
212
213 // update cached and version
214 auto it = largeCachedData_.find(key);
215 if (it != largeCachedData_.end()) {
216 largeCachedData_.erase(it);
217 cachedDataVersion_ = cachedDataVersion_ == INT64_MAX ? 0 : cachedDataVersion_ + 1;
218 }
219
220 PreferencesValue value;
221 ExecutorPool::Task task = [pref = shared_from_this(), key, value] {
222 PreferencesEnhanceImpl::NotifyPreferencesObserver(pref, key, value);
223 };
224 executorPool_.Execute(std::move(task));
225 return E_OK;
226 }
227
GetAllInner()228 std::pair<int, std::map<std::string, PreferencesValue>> PreferencesEnhanceImpl::GetAllInner()
229 {
230 std::map<std::string, PreferencesValue> map;
231 if (db_ == nullptr) {
232 LOG_ERROR("PreferencesEnhanceImpl:GetAll failed, db has been closed.");
233 return std::make_pair(E_ALREADY_CLOSED, map);
234 }
235
236 int64_t kernelDataVersion = 0;
237 if (db_->GetKernelDataVersion(kernelDataVersion) != E_OK) {
238 LOG_ERROR("PreferencesEnhanceImpl:GetAll failed, get kernel data version failed.");
239 return std::make_pair(E_ERROR, map);
240 }
241
242 std::map<std::string, PreferencesValue> result;
243 std::list<std::pair<std::vector<uint8_t>, std::vector<uint8_t>>> data;
244 int errCode = db_->GetAll(data);
245 if (errCode != E_OK) {
246 LOG_ERROR("get all failed, errCode=%{public}d", errCode);
247 return std::make_pair(errCode, map);
248 }
249 for (auto it = data.begin(); it != data.end(); it++) {
250 std::string key(it->first.begin(), it->first.end());
251 auto item = PreferencesValueParcel::UnmarshallingPreferenceValue(it->second);
252 result.insert({key, item.second});
253 if (item.first != E_OK) {
254 LOG_ERROR("get key failed, errCode=%{public}d", errCode);
255 return std::make_pair(item.first, map);
256 }
257 if (it->second.size() >= CACHED_THRESHOLDS) {
258 largeCachedData_.insert_or_assign(key, item.second);
259 }
260 }
261 cachedDataVersion_ = kernelDataVersion;
262 return std::make_pair(E_OK, result);
263 }
264
GetAll()265 std::map<std::string, PreferencesValue> PreferencesEnhanceImpl::GetAll()
266 {
267 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
268 std::pair<int, std::map<std::string, PreferencesValue>> res = GetAllInner();
269 return res.second;
270 }
271
NotifyPreferencesObserver(std::shared_ptr<PreferencesEnhanceImpl> pref, const std::string &key, const PreferencesValue &value)272 void PreferencesEnhanceImpl::NotifyPreferencesObserver(std::shared_ptr<PreferencesEnhanceImpl> pref,
273 const std::string &key, const PreferencesValue &value)
274 {
275 std::shared_lock<std::shared_mutex> readLock(pref->obseverMetux_);
276 LOG_DEBUG("notify observer size:%{public}zu", pref->dataObserversMap_.size());
277 for (const auto &[weakPrt, keys] : pref->dataObserversMap_) {
278 auto itKey = keys.find(key);
279 if (itKey == keys.end()) {
280 continue;
281 }
282 std::map<std::string, PreferencesValue> records = {{key, value}};
283 if (std::shared_ptr<PreferencesObserver> sharedPtr = weakPrt.lock()) {
284 LOG_DEBUG("dataChange observer call, resultSize:%{public}zu", records.size());
285 sharedPtr->OnChange(records);
286 }
287 }
288 auto dataObsMgrClient = DataObsMgrClient::GetInstance();
289 for (auto it = pref->localObservers_.begin(); it != pref->localObservers_.end(); ++it) {
290 std::weak_ptr<PreferencesObserver> weakPreferencesObserver = *it;
291 if (std::shared_ptr<PreferencesObserver> sharedPreferencesObserver = weakPreferencesObserver.lock()) {
292 sharedPreferencesObserver->OnChange(key);
293 }
294 }
295 if (dataObsMgrClient != nullptr) {
296 dataObsMgrClient->NotifyChange(pref->MakeUri(key));
297 }
298 }
299
NotifyPreferencesObserverBatchKeys(std::shared_ptr<PreferencesEnhanceImpl> pref, const std::map<std::string, PreferencesValue> &data)300 void PreferencesEnhanceImpl::NotifyPreferencesObserverBatchKeys(std::shared_ptr<PreferencesEnhanceImpl> pref,
301 const std::map<std::string, PreferencesValue> &data)
302 {
303 for (const auto &[key, value] : data) {
304 NotifyPreferencesObserver(pref, key, value);
305 }
306 }
307
Clear()308 int PreferencesEnhanceImpl::Clear()
309 {
310 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
311 LOG_INFO("Clear called, file: %{public}s", ExtractFileName(options_.filePath).c_str());
312 if (db_ == nullptr) {
313 LOG_ERROR("PreferencesEnhanceImpl:Clear failed, db has been closed.");
314 return E_ERROR;
315 }
316
317 std::pair<int, std::map<std::string, PreferencesValue>> res = GetAllInner();
318 if (res.first != E_OK) {
319 LOG_ERROR("get all failed when clear, errCode=%{public}d", res.first);
320 return res.first;
321 }
322
323 std::map<std::string, PreferencesValue> allData = res.second;
324
325 int errCode = db_->DropCollection();
326 if (errCode != E_OK) {
327 LOG_ERROR("drop collection failed when clear, errCode=%{public}d", errCode);
328 return errCode;
329 }
330
331 if (!allData.empty()) {
332 ExecutorPool::Task task = [pref = shared_from_this(), allData] {
333 PreferencesEnhanceImpl::NotifyPreferencesObserverBatchKeys(pref, allData);
334 };
335 executorPool_.Execute(std::move(task));
336 }
337
338 errCode = db_->CreateCollection();
339 if (errCode != E_OK) {
340 LOG_ERROR("create collection failed when clear, errCode=%{public}d", errCode);
341 return errCode;
342 }
343 largeCachedData_.clear();
344 cachedDataVersion_ = cachedDataVersion_ == INT64_MAX ? 0 : cachedDataVersion_ + 1;
345 return E_OK;
346 }
347
CloseDb()348 int PreferencesEnhanceImpl::CloseDb()
349 {
350 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
351 if (db_ == nullptr) {
352 LOG_WARN("PreferencesEnhanceImpl:CloseDb failed, db has been closed, no need to close again.");
353 return E_OK;
354 }
355 int errCode = db_->CloseDb();
356 if (errCode != E_OK) {
357 LOG_ERROR("PreferencesEnhanceImpl:CloseDb failed.");
358 return errCode;
359 }
360 largeCachedData_.clear();
361 db_ = nullptr;
362 return E_OK;
363 }
364
GetValue(const std::string &key, const PreferencesValue &defValue)365 std::pair<int, PreferencesValue> PreferencesEnhanceImpl::GetValue(const std::string &key,
366 const PreferencesValue &defValue)
367 {
368 int errCode = CheckKey(key);
369 if (errCode != E_OK) {
370 return std::make_pair(errCode, defValue);
371 }
372 // write lock here, get not support concurrence
373 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
374 if (db_ == nullptr) {
375 LOG_ERROR("PreferencesEnhanceImpl:Get failed, db has been closed.");
376 return std::make_pair(E_ALREADY_CLOSED, defValue);
377 }
378
379 int64_t kernelDataVersion = 0;
380 if (db_->GetKernelDataVersion(kernelDataVersion) != E_OK) {
381 LOG_ERROR("PreferencesEnhanceImpl:Get failed, get kernel data version failed.");
382 return std::make_pair(E_ERROR, defValue);
383 }
384 if (kernelDataVersion == cachedDataVersion_) {
385 auto it = largeCachedData_.find(key);
386 if (it != largeCachedData_.end()) {
387 return std::make_pair(E_OK, it->second);
388 }
389 }
390
391 std::vector<uint8_t> oriKey(key.begin(), key.end());
392 std::vector<uint8_t> oriValue;
393 errCode = db_->Get(oriKey, oriValue);
394 if (errCode != E_OK) {
395 LOG_ERROR("get key failed, errCode=%{public}d", errCode);
396 return std::make_pair(errCode, defValue);
397 }
398 auto item = PreferencesValueParcel::UnmarshallingPreferenceValue(oriValue);
399 if (item.first != E_OK) {
400 LOG_ERROR("get key failed, errCode=%{public}d", item.first);
401 return std::make_pair(item.first, defValue);
402 }
403 if (oriValue.size() >= CACHED_THRESHOLDS) {
404 largeCachedData_.insert_or_assign(key, item.second);
405 cachedDataVersion_ = kernelDataVersion;
406 }
407 return std::make_pair(E_OK, item.second);
408 }
409
GetAllData()410 std::pair<int, std::map<std::string, PreferencesValue>> PreferencesEnhanceImpl::GetAllData()
411 {
412 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
413 return GetAllInner();
414 }
415 } // End of namespace NativePreferences
416 } // End of namespace OHOS
417