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 "multi_ver_kvdata_storage.h"
18 
19 #include "db_constant.h"
20 #include "db_errno.h"
21 #include "log_print.h"
22 #include "ikvdb_factory.h"
23 #include "sqlite_local_kvdb.h"
24 #include "parcel.h"
25 
26 namespace DistributedDB {
27 namespace {
28     const uint8_t HASH_COUNT_MAGIC = '$';
29     const uint32_t EXPECT_ENTRIES_NUM = 2;
30     struct DatabaseIdentifierCfg {
31         std::string databaseDir;
32         std::string identifier;
33         std::string fileName;
34     };
35 }
36 
OpenKvDB(const DatabaseIdentifierCfg & config,CipherType type,const CipherPassword & passwd,int & errCode)37 static IKvDB *OpenKvDB(const DatabaseIdentifierCfg &config, CipherType type, const CipherPassword &passwd, int &errCode)
38 {
39     IKvDBFactory *factory = IKvDBFactory::GetCurrent();
40     if (factory == nullptr) {
41         LOGE("Failed to open IKvDB! Get factory failed.");
42         return nullptr;
43     }
44 
45     IKvDB *kvDB = factory->CreateKvDb(LOCAL_KVDB_SQLITE, errCode);
46     if (kvDB == nullptr) {
47         LOGE("Create local kvdb failed:%d", errCode);
48         return nullptr;
49     }
50 
51     KvDBProperties dbProperties;
52     dbProperties.SetBoolProp(KvDBProperties::CREATE_IF_NECESSARY, true);
53     dbProperties.SetStringProp(KvDBProperties::DATA_DIR, config.databaseDir);
54     dbProperties.SetStringProp(KvDBProperties::FILE_NAME, config.fileName);
55     dbProperties.SetStringProp(KvDBProperties::IDENTIFIER_DIR, config.identifier);
56     dbProperties.SetIntProp(KvDBProperties::DATABASE_TYPE, KvDBProperties::MULTI_VER_TYPE_SQLITE);
57     dbProperties.SetPassword(type, passwd);
58 
59     errCode = kvDB->Open(dbProperties);
60     if (errCode != E_OK) {
61         LOGE("Failed to open IKvDB! err:%d", errCode);
62         RefObject::KillAndDecObjRef(kvDB);
63         kvDB = nullptr;
64         return nullptr;
65     }
66     // Need to refactor in the future
67     int version = ((config.fileName == DBConstant::MULTI_VER_VALUE_STORE) ?
68         MULTI_VER_VALUESLICE_STORAGE_VERSION_CURRENT : MULTI_VER_METADATA_STORAGE_VERSION_CURRENT);
69     errCode = static_cast<SQLiteLocalKvDB *>(kvDB)->SetVersion(dbProperties, version);
70     if (errCode != E_OK) {
71         LOGE("[KvStorage][OpenDB] SetVersion fail, errCode=%d.", errCode);
72         RefObject::KillAndDecObjRef(kvDB);
73         kvDB = nullptr;
74         return nullptr;
75     }
76 
77     return kvDB;
78 }
79 
PutData(IKvDBConnection * kvDBConnection,const Key & key,const Value & value)80 static int PutData(IKvDBConnection *kvDBConnection, const Key &key, const Value &value)
81 {
82     if (kvDBConnection == nullptr) {
83         return -E_INVALID_DB;
84     }
85 
86     if (key.empty() || key.size() > DBConstant::MAX_KEY_SIZE || value.size() > DBConstant::MAX_VALUE_SIZE) {
87         return -E_INVALID_ARGS;
88     }
89 
90     IOption option;
91     int errCode = kvDBConnection->Put(option, key, value);
92     if (errCode != E_OK) {
93         LOGE("put data failed:%d", errCode);
94     }
95 
96     return errCode;
97 }
98 
DeleteData(IKvDBConnection * kvDBConnection,const Key & key)99 static int DeleteData(IKvDBConnection *kvDBConnection, const Key &key)
100 {
101     if (kvDBConnection == nullptr) {
102         return -E_INVALID_DB;
103     }
104 
105     if (key.empty() || key.size() > DBConstant::MAX_KEY_SIZE) {
106         return -E_INVALID_ARGS;
107     }
108 
109     IOption option;
110     int errCode = kvDBConnection->Delete(option, key);
111     if (errCode != E_OK) {
112         LOGE("Delete data failed:%d", errCode);
113     }
114 
115     return errCode;
116 }
117 
GetData(const IKvDBConnection * kvDBConnection,const Key & key,Value & value)118 static int GetData(const IKvDBConnection *kvDBConnection, const Key &key, Value &value)
119 {
120     if (kvDBConnection == nullptr) {
121         return -E_INVALID_DB;
122     }
123 
124     if (key.empty() || key.size() > DBConstant::MAX_KEY_SIZE) {
125         return -E_INVALID_ARGS;
126     }
127 
128     IOption option;
129     int errCode = kvDBConnection->Get(option, key, value);
130     if (errCode != E_OK && errCode != -E_NOT_FOUND) {
131         LOGE("Get data failed:%d", errCode);
132     }
133 
134     return errCode;
135 }
136 
GetEntries(const IKvDBConnection * kvDBConnection,const Key & keyPrefix,std::vector<Entry> & entries)137 static int GetEntries(const IKvDBConnection *kvDBConnection, const Key &keyPrefix, std::vector<Entry> &entries)
138 {
139     if (kvDBConnection == nullptr) {
140         return -E_INVALID_DB;
141     }
142 
143     if (keyPrefix.empty() || keyPrefix.size() > DBConstant::MAX_KEY_SIZE) {
144         return -E_INVALID_ARGS;
145     }
146 
147     IOption option;
148     int errCode = kvDBConnection->GetEntries(option, keyPrefix, entries);
149     if (errCode != E_OK && errCode != -E_NOT_FOUND) {
150         LOGE("Get entries failed:%d", errCode);
151     }
152 
153     return errCode;
154 }
155 
GetSliceCount(std::vector<Entry> && entries,uint32_t & count)156 static int GetSliceCount(std::vector<Entry> &&entries, uint32_t &count)
157 {
158     std::vector<uint8_t> buffer = (entries[0].key.size() > entries[1].key.size()) ?
159         std::move(entries[0].value) : std::move(entries[1].value);
160     Parcel parcel(buffer.data(), buffer.size());
161     uint32_t size = parcel.ReadUInt32(count);
162     if (size != sizeof(count) || parcel.IsError()) {
163         LOGE("Get slice count size:%u", size);
164         return -E_PARSE_FAIL;
165     }
166     return E_OK;
167 }
168 
PutSliceCount(IKvDBConnection * kvDBConnection,const Key & sliceKey,uint32_t count)169 static int PutSliceCount(IKvDBConnection *kvDBConnection, const Key &sliceKey, uint32_t count)
170 {
171     Key countKey(sliceKey);
172     countKey.push_back(HASH_COUNT_MAGIC);
173     std::vector<uint8_t> buffer(sizeof(uint32_t), 0);
174     Parcel parcel(buffer.data(), buffer.size());
175     int errCode = parcel.WriteUInt32(count);
176     if (errCode != E_OK) {
177         return errCode;
178     }
179     IOption option;
180     errCode = kvDBConnection->Put(option, countKey, buffer);
181     if (errCode != E_OK) {
182         LOGE("Put slice count failed:%d", errCode);
183     }
184     return errCode;
185 }
186 
PutSlice(IKvDBConnection * kvDBConnection,const Key & key,const Value & value,bool isAddCount)187 static int PutSlice(IKvDBConnection *kvDBConnection, const Key &key, const Value &value, bool isAddCount)
188 {
189     std::vector<Entry> entries;
190     int errCode = GetEntries(kvDBConnection, key, entries);
191     uint32_t dataCount = 1;
192     switch (errCode) {
193         case E_OK:
194             if (entries.size() != EXPECT_ENTRIES_NUM) {
195                 return -E_INCORRECT_DATA;
196             }
197             errCode = GetSliceCount(std::move(entries), dataCount);
198             if (errCode != E_OK) {
199                 return errCode;
200             }
201             dataCount++;
202             errCode = PutSliceCount(kvDBConnection, key, dataCount);
203             return errCode;
204         case -E_NOT_FOUND:
205             errCode = PutData(kvDBConnection, key, value);
206             if (errCode != E_OK) {
207                 return errCode;
208             }
209             dataCount = isAddCount ? 1 : 0;
210             errCode = PutSliceCount(kvDBConnection, key, dataCount);
211             return errCode;
212         default:
213             return errCode;
214     }
215 }
216 
DeleteSlice(IKvDBConnection * kvDBConnection,const Key & key)217 static int DeleteSlice(IKvDBConnection *kvDBConnection, const Key &key)
218 {
219     std::vector<Entry> entries;
220     int errCode = GetEntries(kvDBConnection, key, entries);
221     if (errCode != E_OK) {
222         return errCode;
223     }
224     if (entries.size() != EXPECT_ENTRIES_NUM) {
225         return -E_INCORRECT_DATA;
226     }
227     uint32_t dataCount = 0;
228     Key countKey(key);
229     errCode = GetSliceCount(std::move(entries), dataCount);
230     if (errCode != E_OK) {
231         return errCode;
232     }
233     if (dataCount > 1) {
234         dataCount--;
235         errCode = PutSliceCount(kvDBConnection, key, dataCount);
236         return errCode;
237     } else {
238         errCode = DeleteData(kvDBConnection, key);
239         if (errCode != E_OK) {
240             return errCode;
241         }
242         countKey.push_back(HASH_COUNT_MAGIC);
243         errCode = DeleteData(kvDBConnection, countKey);
244         return errCode;
245     }
246 }
247 
MultiVerKvDataStorage()248 MultiVerKvDataStorage::MultiVerKvDataStorage()
249     : kvStorage_(nullptr),
250       metaStorage_(nullptr),
251       kvStorageConnection_(nullptr),
252       metaStorageConnection_(nullptr)
253 {}
254 
~MultiVerKvDataStorage()255 MultiVerKvDataStorage::~MultiVerKvDataStorage()
256 {
257     Close();
258 }
259 
CheckVersion(const Property & property,bool & isDbAllExist) const260 int MultiVerKvDataStorage::CheckVersion(const Property &property, bool &isDbAllExist) const
261 {
262     int metaDataVer = 0;
263     int valueSliceVer = 0;
264     bool isMetaDbExist = false;
265     bool isSliceDbExist = false;
266     int errCode = GetVersion(property, metaDataVer, isMetaDbExist, valueSliceVer, isSliceDbExist);
267     if (errCode != E_OK) {
268         LOGE("[KvStorage][CheckVer] GetVersion failed, errCode=%d.", errCode);
269         return errCode;
270     }
271     if (isMetaDbExist != isSliceDbExist) {
272         // In case failure happens during open progress, some dbFile will not exist, we should recover from this
273         LOGW("[KvStorage][CheckVer] Detect File Lost, isMetaDbExist=%d, isSliceDbExist=%d.",
274             isMetaDbExist, isSliceDbExist);
275     }
276     isDbAllExist = isMetaDbExist && isSliceDbExist;
277     if (!isMetaDbExist && !isSliceDbExist) {
278         // If both dbFile not exist, just return.
279         return E_OK;
280     }
281     LOGD("[KvStorage][CheckVer] MetaDbVer=%d, CurMetaVer=%d, SliceDbVer=%d, CurSliceVer=%d.", metaDataVer,
282         MULTI_VER_METADATA_STORAGE_VERSION_CURRENT, valueSliceVer, MULTI_VER_VALUESLICE_STORAGE_VERSION_CURRENT);
283     // For the dbFile not exist, version value will be 0, do not affect version check below
284     if (metaDataVer > MULTI_VER_METADATA_STORAGE_VERSION_CURRENT ||
285         valueSliceVer > MULTI_VER_VALUESLICE_STORAGE_VERSION_CURRENT) {
286         LOGE("[KvStorage][CheckVer] Version Not Support!");
287         return -E_VERSION_NOT_SUPPORT;
288     }
289     return E_OK;
290 }
291 
GetVersion(const Property & property,int & metaVer,bool & isMetaDbExist,int & sliceVer,bool & isSliceDbExist) const292 int MultiVerKvDataStorage::GetVersion(const Property &property, int &metaVer, bool &isMetaDbExist,
293     int &sliceVer, bool &isSliceDbExist) const
294 {
295     SQLiteLocalKvDB *localKvdb = new (std::nothrow) SQLiteLocalKvDB();
296     if (localKvdb == nullptr) {
297         return -E_INVALID_DB;
298     }
299 
300     KvDBProperties dbProperties;
301     dbProperties.SetBoolProp(KvDBProperties::CREATE_IF_NECESSARY, property.isNeedCreate);
302     dbProperties.SetStringProp(KvDBProperties::DATA_DIR, property.dataDir);
303     dbProperties.SetStringProp(KvDBProperties::FILE_NAME, DBConstant::MULTI_VER_VALUE_STORE);
304     dbProperties.SetStringProp(KvDBProperties::IDENTIFIER_DIR, property.identifierName);
305     dbProperties.SetIntProp(KvDBProperties::DATABASE_TYPE, KvDBProperties::MULTI_VER_TYPE_SQLITE);
306     dbProperties.SetPassword(property.cipherType, property.passwd);
307     int errCode = localKvdb->GetVersion(dbProperties, sliceVer, isSliceDbExist);
308     if (errCode != E_OK) {
309         LOGE("[KvStorage][GetVer] Get valueSlice storage version fail, errCode=%d.", errCode);
310         RefObject::DecObjRef(localKvdb);
311         localKvdb = nullptr;
312         return errCode;
313     }
314 
315     dbProperties.SetStringProp(KvDBProperties::FILE_NAME, DBConstant::MULTI_VER_META_STORE);
316     errCode = localKvdb->GetVersion(dbProperties, metaVer, isMetaDbExist);
317     if (errCode != E_OK) {
318         LOGE("[KvStorage][GetVer] Get metaData storage version fail, errCode=%d.", errCode);
319         RefObject::DecObjRef(localKvdb);
320         localKvdb = nullptr;
321         return errCode;
322     }
323 
324     RefObject::DecObjRef(localKvdb);
325     localKvdb = nullptr;
326     return E_OK;
327 }
328 
Open(const Property & property)329 int MultiVerKvDataStorage::Open(const Property &property)
330 {
331     int errCode = E_OK;
332     if (kvStorage_ == nullptr) {
333         DatabaseIdentifierCfg config = {property.dataDir, property.identifierName, DBConstant::MULTI_VER_VALUE_STORE};
334         kvStorage_ = OpenKvDB(config, property.cipherType, property.passwd, errCode);
335         if (kvStorage_ == nullptr) {
336             LOGE("open kv storage failed");
337             goto END;
338         }
339     }
340 
341     if (metaStorage_ == nullptr) {
342         DatabaseIdentifierCfg config = {property.dataDir, property.identifierName, DBConstant::MULTI_VER_META_STORE};
343         metaStorage_ = OpenKvDB(config, property.cipherType, property.passwd, errCode);
344         if (metaStorage_ == nullptr) {
345             LOGE("open meta storage failed");
346             goto END;
347         }
348     }
349 
350     kvStorageConnection_ = kvStorage_->GetDBConnection(errCode);
351     if (errCode != E_OK) {
352         goto END;
353     }
354 
355     metaStorageConnection_ = metaStorage_->GetDBConnection(errCode);
356     if (errCode != E_OK) {
357         goto END;
358     }
359 
360 END:
361     if (errCode != E_OK) {
362         Close();
363     }
364     return errCode;
365 }
366 
Close()367 void MultiVerKvDataStorage::Close()
368 {
369     if (kvStorageConnection_ != nullptr) {
370         kvStorageConnection_->Close();
371         kvStorageConnection_ = nullptr;
372     }
373 
374     if (metaStorageConnection_ != nullptr) {
375         metaStorageConnection_->Close();
376         metaStorageConnection_ = nullptr;
377     }
378 
379     if (kvStorage_ != nullptr) {
380         RefObject::KillAndDecObjRef(kvStorage_);
381         kvStorage_ = nullptr;
382     }
383 
384     if (metaStorage_ != nullptr) {
385         RefObject::KillAndDecObjRef(metaStorage_);
386         metaStorage_ = nullptr;
387     }
388 }
389 
PutMetaData(const Key & key,const Value & value)390 int MultiVerKvDataStorage::PutMetaData(const Key &key, const Value &value)
391 {
392     return PutData(metaStorageConnection_, key, value);
393 }
394 
GetMetaData(const Key & key,Value & value) const395 int MultiVerKvDataStorage::GetMetaData(const Key &key, Value &value) const
396 {
397     return GetData(metaStorageConnection_, key, value);
398 }
399 
RunRekeyLogic(CipherType type,const CipherPassword & passwd)400 int MultiVerKvDataStorage::RunRekeyLogic(CipherType type, const CipherPassword &passwd)
401 {
402     int errCode = static_cast<SQLiteLocalKvDB *>(kvStorage_)->RunRekeyLogic(type, passwd);
403     if (errCode != E_OK) {
404         LOGE("value storage rekey failed:%d", errCode);
405         return errCode;
406     }
407     errCode = static_cast<SQLiteLocalKvDB *>(metaStorage_)->RunRekeyLogic(type, passwd);
408     if (errCode != E_OK) {
409         LOGE("meta storage rekey failed:%d", errCode);
410         return errCode;
411     }
412     return E_OK;
413 }
414 
RunExportLogic(CipherType type,const CipherPassword & passwd,const std::string & dbDir) const415 int MultiVerKvDataStorage::RunExportLogic(CipherType type, const CipherPassword &passwd, const std::string &dbDir) const
416 {
417     // execute export
418     std::string valueDbName = dbDir + "/value_storage.db";
419     int errCode = static_cast<SQLiteLocalKvDB *>(kvStorage_)->RunExportLogic(type, passwd, valueDbName);
420     if (errCode != E_OK) {
421         LOGE("value storage export failed:%d", errCode);
422         return errCode;
423     }
424 
425     std::string metaDbName = dbDir + "/meta_storage.db";
426     errCode = static_cast<SQLiteLocalKvDB *>(metaStorage_)->RunExportLogic(type, passwd, metaDbName);
427     if (errCode != E_OK) {
428         LOGE("meta storage export failed:%d", errCode);
429         return errCode;
430     }
431     return E_OK;
432 }
433 
BackupCurrentDatabase(const Property & property,const std::string & dir)434 int MultiVerKvDataStorage::BackupCurrentDatabase(const Property &property, const std::string &dir)
435 {
436     KvDBProperties dbProperties;
437     dbProperties.SetBoolProp(KvDBProperties::CREATE_IF_NECESSARY, true);
438     dbProperties.SetStringProp(KvDBProperties::DATA_DIR, property.dataDir);
439     dbProperties.SetStringProp(KvDBProperties::FILE_NAME, DBConstant::MULTI_VER_META_STORE);
440     dbProperties.SetStringProp(KvDBProperties::IDENTIFIER_DIR, property.identifierName);
441     dbProperties.SetIntProp(KvDBProperties::DATABASE_TYPE, KvDBProperties::MULTI_VER_TYPE_SQLITE);
442     dbProperties.SetPassword(property.cipherType, property.passwd);
443     int errCode = SQLiteLocalKvDB::BackupCurrentDatabase(dbProperties, dir);
444     if (errCode != E_OK) {
445         return errCode;
446     }
447 
448     dbProperties.SetStringProp(KvDBProperties::FILE_NAME, DBConstant::MULTI_VER_VALUE_STORE);
449     return SQLiteLocalKvDB::BackupCurrentDatabase(dbProperties, dir);
450 }
451 
ImportDatabase(const Property & property,const std::string & dir,const CipherPassword & passwd)452 int MultiVerKvDataStorage::ImportDatabase(const Property &property, const std::string &dir,
453     const CipherPassword &passwd)
454 {
455     KvDBProperties dbProperties;
456     dbProperties.SetBoolProp(KvDBProperties::CREATE_IF_NECESSARY, true);
457     dbProperties.SetStringProp(KvDBProperties::DATA_DIR, property.dataDir);
458     dbProperties.SetStringProp(KvDBProperties::FILE_NAME, DBConstant::MULTI_VER_META_STORE);
459     dbProperties.SetStringProp(KvDBProperties::IDENTIFIER_DIR, property.identifierName);
460     dbProperties.SetIntProp(KvDBProperties::DATABASE_TYPE, KvDBProperties::MULTI_VER_TYPE_SQLITE);
461     dbProperties.SetPassword(property.cipherType, property.passwd);
462     int errCode = SQLiteLocalKvDB::ImportDatabase(dbProperties, dir, passwd);
463     if (errCode != E_OK) {
464         return errCode;
465     }
466 
467     dbProperties.SetStringProp(KvDBProperties::FILE_NAME, DBConstant::MULTI_VER_VALUE_STORE);
468     return SQLiteLocalKvDB::ImportDatabase(dbProperties, dir, passwd);
469 }
470 
GetSliceTransaction(bool isWrite,int & errCode)471 SliceTransaction *MultiVerKvDataStorage::GetSliceTransaction(bool isWrite, int &errCode)
472 {
473     auto connect = kvStorage_->GetDBConnection(errCode);
474     if (connect == nullptr) {
475         return nullptr;
476     }
477     auto transaction = new (std::nothrow) SliceTransaction(isWrite, connect);
478     if (transaction == nullptr) {
479         errCode = -E_OUT_OF_MEMORY;
480         connect->Close();
481         return nullptr;
482     }
483     errCode = E_OK;
484     return transaction;
485 }
486 
ReleaseSliceTransaction(SliceTransaction * & transaction)487 void MultiVerKvDataStorage::ReleaseSliceTransaction(SliceTransaction *&transaction)
488 {
489     if (transaction == nullptr) {
490         return;
491     }
492     transaction->Close();
493     delete transaction;
494     transaction = nullptr;
495     return;
496 }
497 
SliceTransaction(bool isWrite,IKvDBConnection * connect)498 SliceTransaction::SliceTransaction(bool isWrite, IKvDBConnection *connect)
499     : isWrite_(isWrite),
500       connect_(connect)
501 {}
502 
~SliceTransaction()503 SliceTransaction::~SliceTransaction()
504 {}
505 
Close()506 int SliceTransaction::Close()
507 {
508     if (connect_ == nullptr) {
509         return E_OK;
510     }
511     return connect_->Close();
512 }
513 
PutData(const Key & key,const Value & value,bool isAddCount)514 int SliceTransaction::PutData(const Key &key, const Value &value, bool isAddCount)
515 {
516     if (!isWrite_) {
517         return -E_INVALID_CONNECTION;
518     }
519     return PutSlice(connect_, key, value, isAddCount);
520 }
521 
GetData(const Key & key,Value & value) const522 int SliceTransaction::GetData(const Key &key, Value &value) const
523 {
524     return ::DistributedDB::GetData(connect_, key, value);
525 }
526 
DeleteData(const Key & key)527 int SliceTransaction::DeleteData(const Key &key)
528 {
529     if (!isWrite_) {
530         return -E_INVALID_CONNECTION;
531     }
532     return DeleteSlice(connect_, key);
533 }
534 
StartTransaction()535 int SliceTransaction::StartTransaction()
536 {
537     if (connect_ == nullptr) {
538         return -E_INVALID_CONNECTION;
539     }
540     return connect_->StartTransaction();
541 }
542 
CommitTransaction()543 int SliceTransaction::CommitTransaction()
544 {
545     if (connect_ == nullptr) {
546         return -E_INVALID_CONNECTION;
547     }
548     return connect_->Commit();
549 }
550 
RollbackTransaction()551 int SliceTransaction::RollbackTransaction()
552 {
553     if (connect_ == nullptr) {
554         return -E_INVALID_CONNECTION;
555     }
556     return connect_->RollBack();
557 }
558 } // namespace DistributedDB
559 #endif