1 /*
2  * Copyright (c) 2021 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 #ifndef OMIT_MULTI_VER
17 #include "kv_store_delegate_impl.h"
18 
19 #include <functional>
20 #include <string>
21 
22 #include "db_errno.h"
23 #include "db_types.h"
24 #include "kv_store_changed_data_impl.h"
25 #include "kv_store_errno.h"
26 #include "kv_store_observer.h"
27 #include "kv_store_snapshot_delegate_impl.h"
28 #include "kvdb_manager.h"
29 #include "kvdb_pragma.h"
30 #include "log_print.h"
31 #include "param_check_utils.h"
32 #include "platform_specific.h"
33 
34 namespace DistributedDB {
35 namespace {
36     constexpr const char *INVALID_CONNECTION = "[KvStoreDelegate] Invalid connection for operation";
37 }
KvStoreDelegateImpl(IKvDBConnection * conn,const std::string & storeId)38 KvStoreDelegateImpl::KvStoreDelegateImpl(IKvDBConnection *conn, const std::string &storeId)
39     : conn_(conn),
40       storeId_(storeId),
41       releaseFlag_(false)
42 {}
43 
~KvStoreDelegateImpl()44 KvStoreDelegateImpl::~KvStoreDelegateImpl()
45 {
46     if (!releaseFlag_) {
47         LOGF("[KvStoreDelegate] can not release object directly");
48         return;
49     }
50 
51     LOGI("[KvStoreDelegate] deconstruct");
52     conn_ = nullptr;
53 }
54 
Put(const Key & key,const Value & value)55 DBStatus KvStoreDelegateImpl::Put(const Key &key, const Value &value)
56 {
57     if (conn_ != nullptr) {
58         IOption option;
59         int errCode = conn_->Put(option, key, value);
60         if (errCode == E_OK) {
61             return OK;
62         }
63 
64         LOGE("[KvStoreDelegate] Put data failed:%d", errCode);
65         return TransferDBErrno(errCode);
66     }
67 
68     LOGE("%s", INVALID_CONNECTION);
69     return DB_ERROR;
70 }
71 
PutBatch(const std::vector<Entry> & entries)72 DBStatus KvStoreDelegateImpl::PutBatch(const std::vector<Entry> &entries)
73 {
74     if (conn_ != nullptr) {
75         IOption option;
76         int errCode = conn_->PutBatch(option, entries);
77         if (errCode == E_OK) {
78             return OK;
79         }
80 
81         LOGE("[KvStoreDelegate] Put batch data failed:%d", errCode);
82         return TransferDBErrno(errCode);
83     }
84 
85     LOGE("%s", INVALID_CONNECTION);
86     return DB_ERROR;
87 }
88 
Delete(const Key & key)89 DBStatus KvStoreDelegateImpl::Delete(const Key &key)
90 {
91     if (conn_ != nullptr) {
92         IOption option;
93         int errCode = conn_->Delete(option, key);
94         if (errCode == E_OK || errCode == -E_NOT_FOUND) {
95             return OK;
96         }
97 
98         LOGE("[KvStoreDelegate] Delete data failed:%d", errCode);
99         return TransferDBErrno(errCode);
100     }
101 
102     LOGE("%s", INVALID_CONNECTION);
103     return DB_ERROR;
104 }
105 
DeleteBatch(const std::vector<Key> & keys)106 DBStatus KvStoreDelegateImpl::DeleteBatch(const std::vector<Key> &keys)
107 {
108     if (conn_ != nullptr) {
109         IOption option;
110         int errCode = conn_->DeleteBatch(option, keys);
111         if (errCode == E_OK || errCode == -E_NOT_FOUND) {
112             return OK;
113         }
114 
115         LOGE("[KvStoreDelegate] Delete batch data failed:%d", errCode);
116         return TransferDBErrno(errCode);
117     }
118 
119     LOGE("%s", INVALID_CONNECTION);
120     return DB_ERROR;
121 }
122 
Clear()123 DBStatus KvStoreDelegateImpl::Clear()
124 {
125     if (conn_ != nullptr) {
126         IOption option;
127         int errCode = conn_->Clear(option);
128         if (errCode == E_OK) {
129             return OK;
130         }
131 
132         LOGE("[KvStoreDelegate] Clear data failed:%d", errCode);
133         return TransferDBErrno(errCode);
134     }
135 
136     LOGE("%s", INVALID_CONNECTION);
137     return DB_ERROR;
138 }
139 
GetStoreId() const140 std::string KvStoreDelegateImpl::GetStoreId() const
141 {
142     return storeId_;
143 }
144 
GetKvStoreSnapshot(KvStoreObserver * observer,const std::function<void (DBStatus,KvStoreSnapshotDelegate *)> & callback)145 void KvStoreDelegateImpl::GetKvStoreSnapshot(KvStoreObserver *observer,
146     const std::function<void(DBStatus, KvStoreSnapshotDelegate *)> &callback)
147 {
148     if (!callback) {
149         LOGE("[KvStoreDelegate] Invalid callback for snapshot!");
150         return;
151     }
152 
153     if (conn_ != nullptr) {
154         if (observer != nullptr && RegisterObserver(observer) != E_OK) {
155             LOGE("[KvStoreDelegate][GetSnapshot] Register observer failed!");
156             callback(DB_ERROR, nullptr);
157             return;
158         }
159 
160         IKvDBSnapshot *snapshot = nullptr;
161         int errCode = conn_->GetSnapshot(snapshot);
162         if (errCode == E_OK) {
163             auto snapshotDelegate = new (std::nothrow) KvStoreSnapshotDelegateImpl(snapshot, observer);
164             if (snapshotDelegate != nullptr) {
165                 callback(OK, snapshotDelegate);
166                 return;
167             }
168             conn_->ReleaseSnapshot(snapshot);
169             snapshot = nullptr;
170         }
171 
172         // UnRegister the registered observer.
173         errCode = UnRegisterObserver(observer);
174         if (errCode != E_OK) {
175             LOGE("[KvStoreDelegate][GetSnapshot] UnRegister observer failed:%d!", errCode);
176         }
177     }
178 
179     LOGE("%s", INVALID_CONNECTION);
180     callback(DB_ERROR, nullptr);
181 }
182 
ReleaseKvStoreSnapshot(KvStoreSnapshotDelegate * & snapshotDelegate)183 DBStatus KvStoreDelegateImpl::ReleaseKvStoreSnapshot(KvStoreSnapshotDelegate *&snapshotDelegate)
184 {
185     if (conn_ != nullptr && snapshotDelegate != nullptr) {
186         KvStoreObserver *observer = nullptr;
187         (static_cast<KvStoreSnapshotDelegateImpl *>(snapshotDelegate))->GetObserver(observer);
188         if (observer != nullptr && UnRegisterObserver(observer) != E_OK) {
189             LOGE("[KvStoreDelegate][ReleaseSnapshot] UnRegistObserver failed!");
190             return DB_ERROR;
191         }
192 
193         IKvDBSnapshot *snapshot = nullptr;
194         (static_cast<KvStoreSnapshotDelegateImpl *>(snapshotDelegate))->GetSnapshot(snapshot);
195         conn_->ReleaseSnapshot(snapshot);
196         snapshot = nullptr;
197         delete snapshotDelegate;
198         snapshotDelegate = nullptr;
199         return OK;
200     }
201 
202     return DB_ERROR;
203 }
204 
RegisterObserver(KvStoreObserver * observer)205 DBStatus KvStoreDelegateImpl::RegisterObserver(KvStoreObserver *observer)
206 {
207     if (observer == nullptr) {
208         return INVALID_ARGS;
209     }
210 
211     if (conn_ == nullptr) {
212         LOGE("%s", INVALID_CONNECTION);
213         return DB_ERROR;
214     }
215 
216     std::lock_guard<std::mutex> lockGuard(observerMapLock_);
217     if (observerMap_.find(observer) != observerMap_.end()) {
218         LOGE("[KvStoreDelegate] Observer has been already registered!");
219         return DB_ERROR;
220     }
221 
222     Key key;
223     int errCode = E_OK;
224     KvDBObserverHandle *observerHandle = conn_->RegisterObserver(
225         static_cast<unsigned int>(DATABASE_COMMIT_EVENT),
226         key,
227         [observer](const KvDBCommitNotifyData &ptr) {
228             KvStoreChangedDataImpl data(&ptr);
229             observer->OnChange(data);
230         },
231         errCode);
232 
233     if (errCode != E_OK || observerHandle == nullptr) {
234         LOGE("[KvStoreDelegate] Register listener failed:%d!", errCode);
235         return DB_ERROR;
236     }
237 
238     observerMap_.insert(std::pair<const KvStoreObserver *, const KvDBObserverHandle *>(observer, observerHandle));
239     return OK;
240 }
241 
242 // Unregister a data change observer
UnRegisterObserver(const KvStoreObserver * observer)243 DBStatus KvStoreDelegateImpl::UnRegisterObserver(const KvStoreObserver *observer)
244 {
245     if (observer == nullptr) {
246         return INVALID_ARGS;
247     }
248 
249     if (conn_ == nullptr) {
250         LOGE("%s", INVALID_CONNECTION);
251         return DB_ERROR;
252     }
253 
254     std::lock_guard<std::mutex> lockGuard(observerMapLock_);
255     auto iter = observerMap_.find(observer);
256     if (iter == observerMap_.end()) {
257         LOGE("[KvStoreDelegate] observer has not been registered!");
258         return NOT_FOUND;
259     }
260 
261     const KvDBObserverHandle *observerHandle = iter->second;
262     int errCode = conn_->UnRegisterObserver(observerHandle);
263     if (errCode != E_OK) {
264         LOGE("[KvStoreDelegate] UnRegister observer failed:%d!", errCode);
265         return DB_ERROR;
266     }
267     observerMap_.erase(iter);
268     return OK;
269 }
270 
StartTransaction()271 DBStatus KvStoreDelegateImpl::StartTransaction()
272 {
273     if (conn_ == nullptr) {
274         LOGE("%s", INVALID_CONNECTION);
275         return DB_ERROR;
276     }
277 
278     int errCode = conn_->StartTransaction();
279     if (errCode != E_OK) {
280         LOGE("[KvStoreDelegate] StartTransaction failed:%d", errCode);
281         return TransferDBErrno(errCode);
282     }
283     return OK;
284 }
285 
Commit()286 DBStatus KvStoreDelegateImpl::Commit()
287 {
288     if (conn_ == nullptr) {
289         LOGE("%s", INVALID_CONNECTION);
290         return DB_ERROR;
291     }
292 
293     int errCode = conn_->Commit();
294     if (errCode != E_OK) {
295         LOGE("[KvStoreDelegate] Commit failed:%d", errCode);
296         return TransferDBErrno(errCode);
297     }
298     return OK;
299 }
300 
Rollback()301 DBStatus KvStoreDelegateImpl::Rollback()
302 {
303     if (conn_ == nullptr) {
304         LOGE("%s", INVALID_CONNECTION);
305         return DB_ERROR;
306     }
307 
308     int errCode = conn_->RollBack();
309     if (errCode != E_OK) {
310         LOGE("[KvStoreDelegate] Rollback failed:%d", errCode);
311         return TransferDBErrno(errCode);
312     }
313     return OK;
314 }
315 
SetConflictResolutionPolicy(ResolutionPolicyType type,const ConflictResolution & resolution)316 DBStatus KvStoreDelegateImpl::SetConflictResolutionPolicy(ResolutionPolicyType type,
317     const ConflictResolution &resolution)
318 {
319     if (type == AUTO_LAST_WIN) {
320         return OK;
321     }
322 
323     if (type == CUSTOMER_RESOLUTION && resolution != nullptr) {
324         return OK;
325     }
326     LOGE("[KvStoreDelegate] Invalid conflict resolution policy:%d", type);
327     return DB_ERROR;
328 }
329 
Rekey(const CipherPassword & password)330 DBStatus KvStoreDelegateImpl::Rekey(const CipherPassword &password)
331 {
332     if (conn_ != nullptr) {
333         int errCode = conn_->Rekey(password);
334         if (errCode == E_OK) {
335             return OK;
336         }
337 
338         LOGE("[KvStoreDelegate] rekey failed:%d", errCode);
339         return TransferDBErrno(errCode);
340     }
341 
342     LOGE("%s", INVALID_CONNECTION);
343     return DB_ERROR;
344 }
345 
Export(const std::string & filePath,const CipherPassword & passwd)346 DBStatus KvStoreDelegateImpl::Export(const std::string &filePath, const CipherPassword &passwd)
347 {
348     std::string fileDir;
349     std::string fileName;
350     OS::SplitFilePath(filePath, fileDir, fileName);
351 
352     std::string canonicalUrl;
353     if (!ParamCheckUtils::CheckDataDir(fileDir, canonicalUrl)) {
354         return INVALID_ARGS;
355     }
356 
357     if (!OS::CheckPathExistence(canonicalUrl)) {
358         return NO_PERMISSION;
359     }
360 
361     canonicalUrl = canonicalUrl + "/" + fileName;
362     if (OS::CheckPathExistence(canonicalUrl)) {
363         LOGE("[KvStoreDelegate] The exported file has already been existed");
364         return FILE_ALREADY_EXISTED;
365     }
366 
367     if (conn_ != nullptr) {
368         int errCode = conn_->Export(canonicalUrl, passwd);
369         if (errCode == E_OK) {
370             return OK;
371         }
372         LOGE("[KvStoreDelegate] Export failed:%d", errCode);
373         return TransferDBErrno(errCode);
374     }
375 
376     LOGE("%s", INVALID_CONNECTION);
377     return DB_ERROR;
378 }
379 
Import(const std::string & filePath,const CipherPassword & passwd)380 DBStatus KvStoreDelegateImpl::Import(const std::string &filePath, const CipherPassword &passwd)
381 {
382     std::string fileDir;
383     std::string fileName;
384     OS::SplitFilePath(filePath, fileDir, fileName);
385 
386     std::string canonicalUrl;
387     if (!ParamCheckUtils::CheckDataDir(fileDir, canonicalUrl)) {
388         return INVALID_ARGS;
389     }
390 
391     canonicalUrl = canonicalUrl + "/" + fileName;
392     if (!OS::CheckPathExistence(canonicalUrl)) {
393         LOGE("[KvStoreDelegate] The imported file not existed:%d", errno);
394         return INVALID_FILE;
395     }
396 
397     if (conn_ != nullptr) {
398         int errCode = conn_->Import(canonicalUrl, passwd);
399         if (errCode == E_OK) {
400             return OK;
401         }
402         LOGE("[KvStoreDelegate] Import failed:%d", errCode);
403         return TransferDBErrno(errCode);
404     }
405 
406     LOGE("%s", INVALID_CONNECTION);
407     return DB_ERROR;
408 }
409 
SetReleaseFlag(bool flag)410 void KvStoreDelegateImpl::SetReleaseFlag(bool flag)
411 {
412     releaseFlag_ = flag;
413 }
414 
Close()415 DBStatus KvStoreDelegateImpl::Close()
416 {
417     if (conn_ != nullptr) {
418         int errCode = KvDBManager::ReleaseDatabaseConnection(conn_);
419         if (errCode == -E_BUSY) {
420             LOGW("[KvStoreDelegate] busy for close");
421             return BUSY;
422         }
423 
424         LOGI("[KvStoreDelegate] Close");
425         conn_ = nullptr;
426     }
427     return OK;
428 }
429 
Pragma(PragmaCmd cmd,PragmaData & paramData)430 DBStatus KvStoreDelegateImpl::Pragma(PragmaCmd cmd, PragmaData &paramData)
431 {
432     if (conn_ == nullptr) {
433         LOGE("%s", INVALID_CONNECTION);
434         return DB_ERROR;
435     }
436     int errCode;
437     switch (cmd) {
438         case PERFORMANCE_ANALYSIS_GET_REPORT:
439             errCode = conn_->Pragma(PRAGMA_PERFORMANCE_ANALYSIS_GET_REPORT, paramData);
440             break;
441         case PERFORMANCE_ANALYSIS_OPEN:
442             errCode = conn_->Pragma(PRAGMA_PERFORMANCE_ANALYSIS_OPEN, paramData);
443             break;
444         case PERFORMANCE_ANALYSIS_CLOSE:
445             errCode = conn_->Pragma(PRAGMA_PERFORMANCE_ANALYSIS_CLOSE, paramData);
446             break;
447         case PERFORMANCE_ANALYSIS_SET_REPORTFILENAME:
448             errCode = conn_->Pragma(PRAGMA_PERFORMANCE_ANALYSIS_SET_REPORTFILENAME, paramData);
449             break;
450         default:
451             errCode = -E_NOT_SUPPORT;
452             break;
453     }
454 
455     if (errCode != E_OK) {
456         LOGE("[KvStoreDelegate] Pragma failed:%d", errCode);
457         return TransferDBErrno(errCode);
458     }
459     return OK;
460 }
461 } // namespace DistributedDB
462 #endif
463