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