同步代码

Signed-off-by: Yuanbo Feng <fengyuanbo2@huawei.com>
This commit is contained in:
openharmony_ci 2024-09-18 13:19:55 +00:00 committed by Yuanbo Feng
commit 92352bb9bc
29 changed files with 802 additions and 324 deletions

View File

@ -22,6 +22,7 @@
#include <string>
#include <utility>
#include "rdb_common.h"
#include "rdb_types.h"
#include "statement.h"
namespace OHOS::NativeRdb {
@ -63,11 +64,10 @@ public:
virtual int32_t Unsubscribe(const std::string &event,
const std::shared_ptr<DistributedRdb::RdbStoreObserver> &observer) = 0;
virtual int32_t Backup(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey,
bool isAsync = false) = 0;
virtual int32_t Restore(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey) = 0;
virtual int32_t InterruptBackup() = 0;
virtual int32_t GetBackupStatus() const = 0;
virtual std::pair<bool, bool> IsExchange(const RdbStoreConfig &config) = 0;
bool isAsync, SlaveStatus &slaveStatus) = 0;
virtual int32_t Restore(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey,
SlaveStatus &slaveStatus) = 0;
virtual ExchangeStrategy GenerateExchangeStrategy(const SlaveStatus &status) = 0;
private:
int32_t id_ = 0;

View File

@ -53,7 +53,7 @@ public:
int RestartReaders();
int ConfigLocale(const std::string &localeStr);
int ChangeDbFileForRestore(const std::string &newPath, const std::string &backupPath,
const std::vector<uint8_t> &newKey);
const std::vector<uint8_t> &newKey, SlaveStatus &slaveStatus);
std::stack<BaseTransaction> &GetTransactionStack();
std::mutex &GetTransactionStackMutex();
int AcquireTransaction();
@ -115,7 +115,7 @@ private:
int32_t GetMaxReaders(const RdbStoreConfig &config);
std::shared_ptr<Connection> Convert2AutoConn(std::shared_ptr<ConnNode> node);
void ReleaseNode(std::shared_ptr<ConnNode> node);
int RestoreByDbSqliteType(const std::string &newPath, const std::string &backupPath);
int RestoreByDbSqliteType(const std::string &newPath, const std::string &backupPath, SlaveStatus &slaveStatus);
static constexpr int LIMITATION = 1024;
static constexpr uint32_t ITER_V1 = 5000;

View File

@ -55,11 +55,10 @@ public:
int32_t Unsubscribe(const std::string& event,
const std::shared_ptr<DistributedRdb::RdbStoreObserver>& observer) override;
int32_t Backup(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey,
bool isAsync = false) override;
int32_t Restore(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey) override;
int32_t InterruptBackup() override;
int32_t GetBackupStatus() const override;
std::pair<bool, bool> IsExchange(const RdbStoreConfig &config) override;
bool isAsync, SlaveStatus &slaveStatus) override;
int32_t Restore(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey,
SlaveStatus &slaveStatus) override;
ExchangeStrategy GenerateExchangeStrategy(const SlaveStatus &status) override;
private:
static constexpr int MAX_VARIABLE_NUM = 500;

View File

@ -132,6 +132,7 @@ public:
bool IsReadOnly() const override;
bool IsMemoryRdb() const override;
bool IsHoldingConnection() override;
bool IsSlaveDiffFromMaster() const override;
int ConfigLocale(const std::string &localeStr);
int Restore(const std::string &backupPath, const std::vector<uint8_t> &newKey) override;
std::string GetName();
@ -189,6 +190,7 @@ public:
int ModifyLockStatus(const AbsRdbPredicates &predicates, bool isLock) override;
int InterruptBackup() override;
int32_t GetDbType() const override;
int32_t ExchangeSlaverToMaster();
void AfterOpen(const RdbStoreConfig &config);
std::pair<int32_t, uint32_t> LockCloudContainer() override;
int32_t UnlockCloudContainer() override;
@ -289,6 +291,7 @@ private:
std::map<std::string, std::list<sptr<RdbStoreLocalSharedObserver>>> localSharedObservers_;
ConcurrentMap<std::string, std::string> attachedInfo_;
uint32_t rebuild_;
SlaveStatus slaveStatus_;
};
} // namespace OHOS::NativeRdb
#endif

View File

@ -24,7 +24,6 @@
#include <vector>
#include "connection.h"
#include "rdb_common.h"
#include "rdb_local_db_observer.h"
#include "rdb_store_config.h"
#include "sqlite3sym.h"
@ -65,11 +64,10 @@ public:
int32_t Unsubscribe(const std::string &event,
const std::shared_ptr<DistributedRdb::RdbStoreObserver> &observer) override;
int32_t Backup(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey,
bool isAsync = false) override;
int32_t Restore(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey) override;
int32_t InterruptBackup() override;
int32_t GetBackupStatus() const override;
std::pair<bool, bool> IsExchange(const RdbStoreConfig &config) override;
bool isAsync, SlaveStatus &slaveStatus) override;
int32_t Restore(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey,
SlaveStatus &slaveStatus) override;
ExchangeStrategy GenerateExchangeStrategy(const SlaveStatus &status) override;
protected:
std::pair<int32_t, ValueObject> ExecuteForValue(const std::string &sql,
@ -112,13 +110,16 @@ private:
int LoadExtension(const RdbStoreConfig &config, sqlite3 *dbHandle);
RdbStoreConfig GetSlaveRdbStoreConfig(const RdbStoreConfig rdbConfig);
int CreateSlaveConnection(const RdbStoreConfig &config, bool isWrite, bool checkSlaveExist = true);
int MasterSlaveExchange(bool isRestore = false);
bool IsRepairable();
std::pair<bool, int> ExchangeVerify(bool isRestore);
int ExchangeSlaverToMaster(bool isRestore, SlaveStatus &status);
int IsRepairable();
int ExchangeVerify(bool isRestore);
static std::pair<int32_t, std::shared_ptr<SqliteConnection>> InnerCreate(const RdbStoreConfig &config,
bool isWrite);
void ReportDbCorruptedEvent(int errCode, const std::string &checkResultInfo);
static constexpr int DEFAULT_BUSY_TIMEOUT_MS = 2000;
static constexpr int BACKUP_PAGES_PRE_STEP = 12800; // 1024 * 4 * 12800 == 50m
static constexpr int BACKUP_PRE_WAIT_TIME = 10;
static constexpr uint32_t NO_ITER = 0;
static const int32_t regCreator_;
static const int32_t regRepairer_;

View File

@ -58,7 +58,8 @@ public:
static int GetFileSize(const std::string &fileName);
static bool IsSlaveDbName(const std::string &fileName);
static std::string GetSlavePath(const std::string& name);
static bool TryAccessSlaveLock(const std::string &dbPath, bool isDelete, bool needCreate);
static bool TryAccessSlaveLock(const std::string &dbPath, bool isDelete, bool needCreate,
bool isSlaveFailure = false);
private:
struct SqlType {

View File

@ -22,6 +22,7 @@
#include <string>
#include <utility>
#include "rdb_common.h"
#include "rdb_types.h"
#include "statement.h"
namespace OHOS::NativeRdb {
@ -63,11 +64,10 @@ public:
virtual int32_t Unsubscribe(const std::string &event,
const std::shared_ptr<DistributedRdb::RdbStoreObserver> &observer) = 0;
virtual int32_t Backup(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey,
bool isAsync = false) = 0;
virtual int32_t Restore(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey) = 0;
virtual int32_t InterruptBackup() = 0;
virtual int32_t GetBackupStatus() const = 0;
virtual std::pair<bool, bool> IsExchange(const RdbStoreConfig &config) = 0;
bool isAsync, SlaveStatus &slaveStatus) = 0;
virtual int32_t Restore(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey,
SlaveStatus &slaveStatus) = 0;
virtual ExchangeStrategy GenerateExchangeStrategy(const SlaveStatus &status) = 0;
private:
int32_t id_ = 0;

View File

@ -53,7 +53,7 @@ public:
int RestartReaders();
int ConfigLocale(const std::string &localeStr);
int ChangeDbFileForRestore(const std::string &newPath, const std::string &backupPath,
const std::vector<uint8_t> &newKey);
const std::vector<uint8_t> &newKey, SlaveStatus &slaveStatus);
std::stack<BaseTransaction> &GetTransactionStack();
std::mutex &GetTransactionStackMutex();
int AcquireTransaction();
@ -115,7 +115,7 @@ private:
int32_t GetMaxReaders(const RdbStoreConfig &config);
std::shared_ptr<Connection> Convert2AutoConn(std::shared_ptr<ConnNode> node);
void ReleaseNode(std::shared_ptr<ConnNode> node);
int RestoreByDbSqliteType(const std::string &newPath, const std::string &backupPath);
int RestoreByDbSqliteType(const std::string &newPath, const std::string &backupPath, SlaveStatus &slaveStatus);
static constexpr int LIMITATION = 1024;
static constexpr uint32_t ITER_V1 = 5000;

View File

@ -83,6 +83,7 @@ public:
bool IsReadOnly() const override;
bool IsMemoryRdb() const override;
bool IsHoldingConnection() override;
bool IsSlaveDiffFromMaster() const override;
int ConfigLocale(const std::string &localeStr);
int Restore(const std::string &backupPath, const std::vector<uint8_t> &newKey) override;
std::string GetName();
@ -101,6 +102,7 @@ public:
int GetRebuilt(RebuiltType &rebuilt) override;
int InterruptBackup() override;
int32_t GetBackupStatus() const override;
int32_t ExchangeSlaverToMaster();
std::pair<int32_t, int32_t> Attach(
const RdbStoreConfig &config, const std::string &attachName, int32_t waitTime = 2) override;
std::pair<int32_t, int32_t> Detach(const std::string &attachName, int32_t waitTime = 2) override;
@ -166,6 +168,7 @@ private:
std::shared_ptr<ConnectionPool> connectionPool_;
ConcurrentMap<std::string, std::string> attachedInfo_;
uint32_t rebuild_;
SlaveStatus slaveStatus_;
};
} // namespace OHOS::NativeRdb
#endif

View File

@ -24,7 +24,6 @@
#include <vector>
#include "connection.h"
#include "rdb_common.h"
#include "rdb_local_db_observer.h"
#include "rdb_store_config.h"
#include "sqlite3sym.h"
@ -65,11 +64,11 @@ public:
int32_t Unsubscribe(const std::string &event,
const std::shared_ptr<DistributedRdb::RdbStoreObserver> &observer) override;
int32_t Backup(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey,
bool isAsync = false) override;
int32_t Restore(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey) override;
int32_t InterruptBackup() override;
int32_t GetBackupStatus() const override;
std::pair<bool, bool> IsExchange(const RdbStoreConfig &config) override;
bool isAsync, SlaveStatus &slaveStatus) override;
int32_t Restore(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey,
SlaveStatus &slaveStatus) override;
ExchangeStrategy GenerateExchangeStrategy(const SlaveStatus &status) override;
protected:
@ -114,13 +113,16 @@ private:
int LoadExtension(const RdbStoreConfig &config, sqlite3 *dbHandle);
RdbStoreConfig GetSlaveRdbStoreConfig(const RdbStoreConfig rdbConfig);
int CreateSlaveConnection(const RdbStoreConfig &config, bool isWrite, bool checkSlaveExist = false);
int MasterSlaveExchange(bool isRestore = false);
bool IsRepairable();
std::pair<bool, int> ExchangeVerify(bool isRestore);
int ExchangeSlaverToMaster(bool isRestore, SlaveStatus &status);
int IsRepairable();
int ExchangeVerify(bool isRestore);
static std::pair<int32_t, std::shared_ptr<SqliteConnection>> InnerCreate(const RdbStoreConfig &config,
bool isWrite);
void ReportDbCorruptedEvent(int errCode, const std::string &checkResultInfo);
static constexpr int DEFAULT_BUSY_TIMEOUT_MS = 2000;
static constexpr int BACKUP_PAGES_PRE_STEP = 12800; // 1024 * 4 * 12800 == 50m
static constexpr int BACKUP_PRE_WAIT_TIME = 10;
static constexpr uint32_t NO_ITER = 0;
static const int32_t regCreator_;
static const int32_t regRepairer_;

View File

@ -326,7 +326,7 @@ int ConnPool::ConfigLocale(const std::string &localeStr)
* Rename the backed up database.
*/
int ConnPool::ChangeDbFileForRestore(const std::string &newPath, const std::string &backupPath,
const std::vector<uint8_t> &newKey)
const std::vector<uint8_t> &newKey, SlaveStatus &slaveStatus)
{
if (!writers_.IsFull() || config_.GetPath() == backupPath || newPath == backupPath) {
LOG_ERROR("Connection pool is busy now!");
@ -340,8 +340,7 @@ int ConnPool::ChangeDbFileForRestore(const std::string &newPath, const std::stri
LOG_ERROR("Get null connection.");
return retVal;
}
retVal = connection->Restore(backupPath, {});
retVal = connection->Restore(backupPath, {}, slaveStatus);
if (retVal != E_OK) {
LOG_ERROR("RdDbRestore error.");
return retVal;
@ -350,10 +349,10 @@ int ConnPool::ChangeDbFileForRestore(const std::string &newPath, const std::stri
auto [errCode, node] = Init();
return errCode;
}
return RestoreByDbSqliteType(newPath, backupPath);
return RestoreByDbSqliteType(newPath, backupPath, slaveStatus);
}
int ConnPool::RestoreByDbSqliteType(const std::string &newPath, const std::string &backupPath)
int ConnPool::RestoreByDbSqliteType(const std::string &newPath, const std::string &backupPath, SlaveStatus &slaveStatus)
{
int ret = E_OK;
if (SqliteUtils::IsSlaveDbName(backupPath) && config_.GetHaMode() != HAMode::SINGLE) {
@ -361,26 +360,7 @@ int ConnPool::RestoreByDbSqliteType(const std::string &newPath, const std::strin
if (connection == nullptr) {
return E_DATABASE_BUSY;
}
ret = connection->Restore(backupPath, {});
if (ret == E_SQLITE_CORRUPT && config_.GetAllowRebuild()) {
LOG_WARN("corrupt, rebuild:%{public}s", SqliteUtils::Anonymous(backupPath).c_str());
CloseAllConnections();
Connection::Delete(config_);
auto [errCode, node] = Init();
if (errCode != E_OK) {
LOG_ERROR("init failed:%{public}d", errCode);
return errCode;
}
auto newConn = AcquireConnection(false);
if (newConn == nullptr) {
return E_DATABASE_BUSY;
}
ret = newConn->Restore(backupPath, {});
if (ret != E_OK) {
LOG_ERROR("restore failed:%{public}d, %{public}s", ret, SqliteUtils::Anonymous(backupPath).c_str());
}
}
return ret;
return connection->Restore(backupPath, {}, slaveStatus);
}
CloseAllConnections();
Connection::Delete(config_);

View File

@ -207,7 +207,7 @@ int32_t RdConnection::Unsubscribe(const std::string& event,
}
int32_t RdConnection::Backup(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey,
bool isAsync)
bool isAsync, SlaveStatus &slaveStatus)
{
uint32_t size = destEncryptKey.size();
if (size != 0) {
@ -216,7 +216,8 @@ int32_t RdConnection::Backup(const std::string &databasePath, const std::vector<
return RdUtils::RdDbBackup(dbHandle_, databasePath.c_str(), nullptr, 0);
}
int32_t RdConnection::Restore(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey)
int32_t RdConnection::Restore(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey,
SlaveStatus &slaveStatus)
{
uint32_t size = destEncryptKey.size();
if (size != 0) {
@ -225,19 +226,9 @@ int32_t RdConnection::Restore(const std::string &databasePath, const std::vector
return RdUtils::RdDbRestore(dbHandle_, databasePath.c_str(), nullptr, 0);
}
int32_t RdConnection::InterruptBackup()
ExchangeStrategy RdConnection::GenerateExchangeStrategy(const SlaveStatus &status)
{
return E_NOT_SUPPORT;
}
int32_t RdConnection::GetBackupStatus() const
{
return SlaveStatus::UNDEFINED;
}
std::pair<bool, bool> RdConnection::IsExchange(const RdbStoreConfig &config)
{
return { false, false };
return ExchangeStrategy::NOT_HANDLE;
}
} // namespace NativeRdb
} // namespace OHOS

View File

@ -481,11 +481,21 @@ bool RdbSecurityManager::LoadSecretKeyFromDisk(const std::string &keyPath, RdbSe
}
}
auto size = content.size();
auto offset = 0;
auto iter = content.begin();
if (offset + 1 >= size) {
return false;
}
keyData.distributed = *iter;
iter++;
offset++;
std::vector<uint8_t> createTime;
if (offset + sizeof(time_t) / sizeof(uint8_t) >= size) {
return false;
}
offset += sizeof(time_t) / sizeof(uint8_t);
for (int i = 0; i < static_cast<int>(sizeof(time_t) / sizeof(uint8_t)); i++) {
createTime.push_back(*iter);
iter++;
@ -495,6 +505,10 @@ bool RdbSecurityManager::LoadSecretKeyFromDisk(const std::string &keyPath, RdbSe
keyData.timeValue = *reinterpret_cast<time_t *>(&createTime[0]);
}
if (offset + AEAD_LEN >= size) {
return false;
}
offset = size;
keyData.secretKey.insert(keyData.secretKey.end(), iter, content.end());
return true;

View File

@ -117,6 +117,11 @@ void RdbStoreConfig::SetJournalMode(JournalMode journalMode)
this->journalMode_ = GetJournalModeValue(journalMode);
}
void RdbStoreConfig::SetJournalMode(const std::string &journalMode)
{
this->journalMode_ = journalMode;
}
void RdbStoreConfig::SetDatabaseFileType(DatabaseFileType type)
{
this->databaseFileType = GetDatabaseFileTypeValue(type);

View File

@ -313,14 +313,15 @@ int RdbStoreImpl::CleanDirtyData(const std::string &table, uint64_t cursor)
RdbStoreImpl::RdbStoreImpl(const RdbStoreConfig &config)
: config_(config), isOpen_(false), isReadOnly_(config.IsReadOnly()), isMemoryRdb_(config.IsMemoryRdb()),
isEncrypt_(config.IsEncrypt()), path_(config.GetPath()), name_(config.GetName()),
fileType_(config.GetDatabaseFileType()), connectionPool_(nullptr), rebuild_(RebuiltType::NONE)
fileType_(config.GetDatabaseFileType()), connectionPool_(nullptr), rebuild_(RebuiltType::NONE),
slaveStatus_(SlaveStatus::UNDEFINED)
{
}
RdbStoreImpl::RdbStoreImpl(const RdbStoreConfig &config, int &errCode)
: config_(config), isReadOnly_(config.IsReadOnly()), isMemoryRdb_(config.IsMemoryRdb()),
isEncrypt_(config.IsEncrypt()), name_(config.GetName()), fileType_(config.GetDatabaseFileType()),
rebuild_(RebuiltType::NONE)
rebuild_(RebuiltType::NONE), slaveStatus_(SlaveStatus::UNDEFINED)
{
path_ = (config.GetRoleType() == VISITOR) ? config.GetVisitorDir() : config.GetPath();
connectionPool_ = ConnectionPool::Create(config_, errCode);
@ -360,6 +361,8 @@ void RdbStoreImpl::RemoveDbFiles(std::string &path)
SqliteUtils::DeleteFile(path + "-shm");
SqliteUtils::DeleteFile(path + "-wal");
SqliteUtils::DeleteFile(path + "-journal");
SqliteUtils::DeleteFile(path + "-slaveFailure");
SqliteUtils::DeleteFile(path + "-syncInterrupt");
}
const RdbStoreConfig &RdbStoreImpl::GetConfig()
@ -1151,11 +1154,11 @@ int RdbStoreImpl::InnerBackup(const std::string &databasePath, const std::vector
if (isEncrypt_) {
return E_NOT_SUPPORT;
}
return conn->Backup(databasePath, {});
return conn->Backup(databasePath, {}, false, slaveStatus_);
}
if (config_.GetHaMode() != HAMode::SINGLE && SqliteUtils::IsSlaveDbName(databasePath)) {
auto conn = connectionPool_->AcquireConnection(false);
return conn == nullptr ? E_BASE : conn->Backup(databasePath, {});
return conn == nullptr ? E_BASE : conn->Backup(databasePath, {}, false, slaveStatus_);
}
auto [errCode, statement] = GetStatement(GlobalExpr::CIPHER_DEFAULT_ATTACH_HMAC_ALGO, true);
if (statement == nullptr) {
@ -1771,7 +1774,7 @@ int RdbStoreImpl::Restore(const std::string &backupPath, const std::vector<uint8
service->Disable(syncerParam_);
}
#endif
int errCode = connectionPool_->ChangeDbFileForRestore(path_, destPath, newKey);
int errCode = connectionPool_->ChangeDbFileForRestore(path_, destPath, newKey, slaveStatus_);
#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
SecurityPolicy::SetSecurityLabel(config_);
if (service != nullptr) {
@ -1852,10 +1855,11 @@ int RdbStoreImpl::SetDistributedTables(const std::vector<std::string> &tables, i
}
if (type == DistributedRdb::DISTRIBUTED_CLOUD) {
auto conn = connectionPool_->AcquireConnection(false);
if (conn == nullptr) {
LOG_WARN("acquire conn failed when set distributed.");
} else if (conn->IsExchange(config_).first) {
(void)conn->Backup({}, {});
if (conn != nullptr) {
auto strategy = conn->GenerateExchangeStrategy(slaveStatus_);
if (strategy == ExchangeStrategy::BACKUP) {
(void)conn->Backup({}, {}, false, slaveStatus_);
}
}
}
if (type != DistributedRdb::DISTRIBUTED_CLOUD || !distributedConfig.autoSync) {
@ -2443,16 +2447,11 @@ int RdbStoreImpl::InterruptBackup()
if (config_.GetHaMode() != HAMode::MANUAL_TRIGGER) {
return E_NOT_SUPPORT;
}
auto conn = connectionPool_->AcquireConnection(false);
if (conn == nullptr) {
return E_DATABASE_BUSY;
if (slaveStatus_ == SlaveStatus::BACKING_UP) {
slaveStatus_ = SlaveStatus::BACKUP_INTERRUPT;
return E_OK;
}
int32_t ret = conn->InterruptBackup();
if (ret != E_OK) {
LOG_ERROR("InterruptBackup failed");
return ret;
}
return E_OK;
return E_INVALID_INTERRUPT;
}
int32_t RdbStoreImpl::GetBackupStatus() const
@ -2460,11 +2459,7 @@ int32_t RdbStoreImpl::GetBackupStatus() const
if (config_.GetHaMode() != HAMode::MANUAL_TRIGGER && config_.GetHaMode() != HAMode::MAIN_REPLICA) {
return SlaveStatus::UNDEFINED;
}
auto conn = connectionPool_->AcquireConnection(false);
if (conn == nullptr) {
return SlaveStatus::UNDEFINED;
}
return conn->GetBackupStatus();
return slaveStatus_;
}
bool RdbStoreImpl::TryGetMasterSlaveBackupPath(const std::string &srcPath, std::string &destPath, bool isRestore)
@ -2483,4 +2478,36 @@ bool RdbStoreImpl::TryGetMasterSlaveBackupPath(const std::string &srcPath, std::
}
return true;
}
bool RdbStoreImpl::IsSlaveDiffFromMaster() const
{
std::string failureFlagFile = config_.GetPath() + "-slaveFailure";
std::string slaveDbPath = SqliteUtils::GetSlavePath(config_.GetPath());
return access(failureFlagFile.c_str(), F_OK) == 0 || access(slaveDbPath.c_str(), F_OK) != 0;
}
int32_t RdbStoreImpl::ExchangeSlaverToMaster()
{
if (config_.GetRoleType() == VISITOR || config_.IsReadOnly()) {
return E_OK;
}
auto conn = connectionPool_->AcquireConnection(false);
if (conn == nullptr) {
return E_DATABASE_BUSY;
}
auto strategy = conn->GenerateExchangeStrategy(slaveStatus_);
if (strategy != ExchangeStrategy::NOT_HANDLE) {
LOG_WARN("exchange st:%{public}d, %{public}s,", strategy, config_.GetName().c_str());
}
int ret = E_OK;
if (strategy == ExchangeStrategy::RESTORE) {
conn = nullptr;
// disable is required before restore
ret = Restore({}, {});
} else if (strategy == ExchangeStrategy::BACKUP) {
// async backup
ret = conn->Backup({}, {}, true, slaveStatus_);
}
return ret;
}
} // namespace OHOS::NativeRdb

View File

@ -91,6 +91,7 @@ std::shared_ptr<RdbStore> RdbStoreManager::GetRdbStore(const RdbStoreConfig &con
storeCache_[path] = rdbStore;
return rdbStore;
}
(void)rdbStore->ExchangeSlaverToMaster();
errCode = ProcessOpenCallback(*rdbStore, config, version, openCallback);
if (errCode != E_OK) {
LOG_ERROR("fail, storeName:%{public}s path:%{public}s ProcessOpenCallback errCode:%{public}d",

View File

@ -67,35 +67,7 @@ std::pair<int32_t, std::shared_ptr<Connection>> SqliteConnection::Create(const R
{
std::pair<int32_t, std::shared_ptr<Connection>> result = { E_ERROR, nullptr };
auto &[errCode, conn] = result;
std::shared_ptr<SqliteConnection> connection = std::make_shared<SqliteConnection>(config, isWrite);
if (connection == nullptr) {
LOG_ERROR("connection is nullptr.");
return result;
}
RdbStoreConfig rdbSlaveStoreConfig = connection->GetSlaveRdbStoreConfig(config);
errCode = connection->InnerOpen(config);
if (errCode != E_OK) {
return result;
}
conn = connection;
if (isWrite) {
int ret = connection->CreateSlaveConnection(rdbSlaveStoreConfig, isWrite);
if (ret != E_OK) {
return { E_OK, conn };
}
auto [isExchange, isRestore] = connection->IsExchange(rdbSlaveStoreConfig);
if (isExchange) {
LOG_INFO("exchange isRes:%{public}d, %{public}s,", isRestore,
SqliteUtils::Anonymous(rdbSlaveStoreConfig.GetPath()).c_str());
if (isRestore) {
(void)connection->Restore({}, {});
} else {
(void)connection->Backup({}, {}, true);
}
}
}
std::tie(errCode, conn) = InnerCreate(config, isWrite);
return result;
}
@ -106,6 +78,8 @@ int32_t SqliteConnection::Delete(const RdbStoreConfig &config)
SqliteUtils::DeleteFile(path + "-shm");
SqliteUtils::DeleteFile(path + "-wal");
SqliteUtils::DeleteFile(path + "-journal");
SqliteUtils::DeleteFile(path + "-slaveFailure");
SqliteUtils::DeleteFile(path + "-syncInterrupt");
return E_OK;
}
@ -122,10 +96,7 @@ int SqliteConnection::CreateSlaveConnection(const RdbStoreConfig &config, bool i
}
bool isSlaveExist = access(config.GetPath().c_str(), F_OK) == 0;
bool isSlaveLockExist = SqliteUtils::TryAccessSlaveLock(config_.GetPath(), false, false);
if (!isSlaveExist) {
slaveStatus_.store(SlaveStatus::DB_NOT_EXITS);
}
if (config.GetHaMode() == HAMode::MANUAL_TRIGGER && ((checkSlaveExist && !isSlaveExist) || isSlaveLockExist)) {
if (config.GetHaMode() == HAMode::MANUAL_TRIGGER && (checkSlaveExist && (!isSlaveExist || isSlaveLockExist))) {
LOG_INFO("not dual write on manual, slave:%{public}d, lock:%{public}d",
isSlaveExist, isSlaveLockExist);
return E_OK;
@ -135,6 +106,7 @@ int SqliteConnection::CreateSlaveConnection(const RdbStoreConfig &config, bool i
slaveConnection_ = connection;
int errCode = slaveConnection_->InnerOpen(config);
if (errCode != E_OK) {
SqliteUtils::TryAccessSlaveLock(config_.GetPath(), false, true, true);
if (errCode == E_SQLITE_CORRUPT) {
LOG_WARN("slave corrupt, rebuild:%{public}s",
SqliteUtils::Anonymous(config.GetPath()).c_str());
@ -177,6 +149,7 @@ RdbStoreConfig SqliteConnection::GetSlaveRdbStoreConfig(const RdbStoreConfig rdb
rdbStoreConfig.SetEncryptKey(rdbConfig.GetEncryptKey());
rdbStoreConfig.SetNewEncryptKey(rdbConfig.GetNewEncryptKey());
rdbStoreConfig.SetScalarFunctions(rdbConfig.GetScalarFunctions());
rdbStoreConfig.SetJournalMode(rdbConfig.GetJournalMode());
rdbStoreConfig.SetModuleName(rdbConfig.GetModuleName());
rdbStoreConfig.SetArea(rdbConfig.GetArea());
@ -230,7 +203,7 @@ int SqliteConnection::InnerOpen(const RdbStoreConfig &config)
static_cast<std::string>(checkResult).c_str(), sql);
ReportDbCorruptedEvent(errCode, static_cast<std::string>(checkResult));
} else {
LOG_INFO("%{public}s integrity check err:%{public}d, result is %{public}s, sql:%{public}s",
LOG_DEBUG("%{public}s integrity check err:%{public}d, result is %{public}s, sql:%{public}s",
config.GetName().c_str(), errCode, static_cast<std::string>(checkResult).c_str(), sql);
}
}
@ -439,7 +412,8 @@ std::pair<int, std::shared_ptr<Statement>> SqliteConnection::CreateStatement(
slaveStmt->config_ = &slaveConnection_->config_;
errCode = slaveStmt->Prepare(slaveConnection_->dbHandle_, sql);
if (errCode != E_OK) {
LOG_WARN("prepare slave stmt failed:%{public}d", errCode);
LOG_WARN("prepare slave stmt failed:%{public}d, sql:%{public}s", errCode, sql.c_str());
SqliteUtils::TryAccessSlaveLock(config_.GetPath(), false, true, true);
return { E_OK, statement };
}
statement->slave_ = slaveStmt;
@ -1158,12 +1132,16 @@ int32_t SqliteConnection::UnsubscribeLocalDetailAll(const std::string &event)
}
int32_t SqliteConnection::Backup(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey,
bool isAsync)
bool isAsync, SlaveStatus &slaveStatus)
{
if (slaveStatus == SlaveStatus::BACKING_UP) {
LOG_INFO("backing up, return:%{public}s", config_.GetName().c_str());
return E_OK;
}
LOG_INFO("begin backup to slave:%{public}s, isAsync:%{public}d", SqliteUtils::Anonymous(databasePath).c_str(),
isAsync);
if (!isAsync) {
if (config_.GetHaMode() == HAMode::MANUAL_TRIGGER && slaveConnection_ == nullptr) {
if (slaveConnection_ == nullptr) {
RdbStoreConfig rdbSlaveStoreConfig = GetSlaveRdbStoreConfig(config_);
int errCode = CreateSlaveConnection(rdbSlaveStoreConfig, true, false);
if (errCode != E_OK) {
@ -1171,7 +1149,7 @@ int32_t SqliteConnection::Backup(const std::string &databasePath, const std::vec
return errCode;
}
}
return MasterSlaveExchange();
return ExchangeSlaverToMaster(false, slaveStatus);
}
if (backupId_ == TaskExecutor::INVALID_TASK_ID) {
@ -1180,10 +1158,14 @@ int32_t SqliteConnection::Backup(const std::string &databasePath, const std::vec
LOG_WARN("task pool err when restore");
return E_OK;
}
backupId_ = pool->Execute([this]() {
int ret = MasterSlaveExchange();
if (ret != E_OK) {
LOG_WARN("master backup to slave failed:%{public}d", ret);
backupId_ = pool->Execute([this, &slaveStatus]() {
auto [err, conn] = InnerCreate(config_, true);
if (err != E_OK) {
return;
}
err = conn->ExchangeSlaverToMaster(false, slaveStatus);
if (err != E_OK) {
LOG_WARN("master backup to slave failed:%{public}d", err);
}
backupId_ = TaskExecutor::INVALID_TASK_ID;
});
@ -1191,10 +1173,11 @@ int32_t SqliteConnection::Backup(const std::string &databasePath, const std::vec
return E_OK;
}
int32_t SqliteConnection::Restore(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey)
int32_t SqliteConnection::Restore(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey,
SlaveStatus &slaveStatus)
{
LOG_INFO("begin to restore from slave:%{public}s", SqliteUtils::Anonymous(databasePath).c_str());
return MasterSlaveExchange(true);
return ExchangeSlaverToMaster(true, slaveStatus);
};
int SqliteConnection::LoadExtension(const RdbStoreConfig &config, sqlite3 *dbHandle)
@ -1270,10 +1253,12 @@ int SqliteConnection::SetServiceKey(const RdbStoreConfig &config, int32_t errCod
return errCode;
}
int SqliteConnection::MasterSlaveExchange(bool isRestore)
int SqliteConnection::ExchangeSlaverToMaster(bool isRestore, SlaveStatus &curStatus)
{
auto [isReturn, err] = ExchangeVerify(isRestore);
if (isReturn) {
curStatus = SlaveStatus::BACKING_UP;
auto err = ExchangeVerify(isRestore);
if (err != E_OK) {
curStatus = SlaveStatus::UNDEFINED;
return err;
}
@ -1282,106 +1267,87 @@ int SqliteConnection::MasterSlaveExchange(bool isRestore)
sqlite3_backup *pBackup = sqlite3_backup_init(dbFrom, "main", dbTo, "main");
if (pBackup == nullptr) {
LOG_WARN("slave backup init failed");
slaveStatus_.store(SlaveStatus::UNDEFINED);
curStatus = SlaveStatus::UNDEFINED;
return E_OK;
}
int rc = SQLITE_OK;
do {
if (!isRestore && slaveStatus_.load() == SlaveStatus::BACKUP_INTERRUPT) {
if (!isRestore && curStatus == SlaveStatus::BACKUP_INTERRUPT) {
LOG_INFO("backup slave was interrupt!");
(void)sqlite3_backup_finish(pBackup);
(void)SqliteConnection::Delete(slaveConnection_->config_);
return E_OK;
rc = E_BACKUP_INTERRUPT;
break;
}
rc = sqlite3_backup_step(pBackup, BACKUP_PAGES_PRE_STEP);
LOG_INFO("backup slave process cur/total:%{public}d/%{public}d, isRestore:%{public}d",
LOG_INFO("backup slave process cur/total:%{public}d/%{public}d, rs:%{public}d, isRestore:%{public}d",
sqlite3_backup_pagecount(pBackup) - sqlite3_backup_remaining(pBackup), sqlite3_backup_pagecount(pBackup),
isRestore);
} while (rc == SQLITE_OK || rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
rc, isRestore);
if (!isRestore) {
sqlite3_sleep(BACKUP_PRE_WAIT_TIME);
}
} while (sqlite3_backup_pagecount(pBackup) != 0 && (rc == SQLITE_OK || rc == SQLITE_BUSY || rc == SQLITE_LOCKED));
(void)sqlite3_backup_finish(pBackup);
if (rc != SQLITE_DONE) {
slaveStatus_.store(SlaveStatus::BACKUP_INTERRUPT);
LOG_WARN("backup slave err:%{public}d, isRestore:%{public}d", rc, isRestore);
return SQLiteError::ErrNo(rc);
} else {
isRestore ? TryCheckPoint() : slaveConnection_->TryCheckPoint();
slaveStatus_.store(SlaveStatus::BACKUP_FINISHED);
if (!SqliteUtils::TryAccessSlaveLock(config_.GetPath(), true, false)) {
LOG_WARN("try remove slave lock failed! isRestore:%{public}d", isRestore);
LOG_ERROR("backup slave err:%{public}d, isRestore:%{public}d", rc, isRestore);
if (!isRestore) {
RdbStoreConfig slaveConfig(slaveConnection_->config_.GetPath());
if (rc != SQLITE_BUSY && rc != SQLITE_LOCKED) {
slaveConnection_ = nullptr;
(void)SqliteConnection::Delete(slaveConfig);
}
curStatus = SlaveStatus::BACKUP_INTERRUPT;
}
LOG_INFO("backup slave success, isRestore:%{public}d", isRestore);
return rc == E_BACKUP_INTERRUPT ? E_BACKUP_INTERRUPT : SQLiteError::ErrNo(rc);
}
isRestore ? TryCheckPoint() : slaveConnection_->TryCheckPoint();
curStatus = SlaveStatus::BACKUP_FINISHED;
SqliteUtils::TryAccessSlaveLock(config_.GetPath(), true, false);
SqliteUtils::TryAccessSlaveLock(config_.GetPath(), true, false, true);
LOG_INFO("backup slave success, isRestore:%{public}d", isRestore);
return E_OK;
}
std::pair<bool, bool> SqliteConnection::IsExchange(const RdbStoreConfig &config)
ExchangeStrategy SqliteConnection::GenerateExchangeStrategy(const SlaveStatus &status)
{
std::pair<bool, bool> res = { false, false };
auto &[isExchanged, isRestore] = res;
if (dbHandle_ == nullptr || slaveConnection_ == nullptr || slaveConnection_->dbHandle_ == nullptr) {
return res;
}
if (config.GetHaMode() != HAMode::MAIN_REPLICA) {
return res;
}
SlaveStatus curSlaveStatus = slaveStatus_.load();
if (curSlaveStatus == SlaveStatus::BACKING_UP) {
return res;
}
if (curSlaveStatus == SlaveStatus::DB_NOT_EXITS || curSlaveStatus == SlaveStatus::BACKUP_INTERRUPT) {
isExchanged = true;
return res;
if (dbHandle_ == nullptr || slaveConnection_ == nullptr || slaveConnection_->dbHandle_ == nullptr ||
config_.GetHaMode() == HAMode::SINGLE || status == SlaveStatus::BACKING_UP) {
return ExchangeStrategy::NOT_HANDLE;
}
static const std::string querySql = "SELECT COUNT(*) FROM sqlite_master WHERE type='table';";
auto [mRet, mObj] = ExecuteForValue(querySql);
if (mRet != E_OK) {
return res;
LOG_WARN("main abnormal, err:%{public}d", mRet);
return ExchangeStrategy::RESTORE;
}
int64_t mCount = static_cast<int64_t>(mObj);
// trigger mode only does restore, not backup
if (config_.GetHaMode() == HAMode::MANUAL_TRIGGER) {
return mCount == 0 ? ExchangeStrategy::RESTORE : ExchangeStrategy::NOT_HANDLE;
}
auto [sRet, sObj] = slaveConnection_->ExecuteForValue(querySql);
if (sRet != E_OK) {
LOG_WARN("slave db abnormal, need backup, err:%{public}d", sRet);
isExchanged = true;
return res;
return ExchangeStrategy::BACKUP;
}
if (status == SlaveStatus::DB_NOT_EXITS || status == SlaveStatus::BACKUP_INTERRUPT) {
return ExchangeStrategy::BACKUP;
}
int64_t mCount = static_cast<int64_t>(mObj);
int64_t sCount = static_cast<int64_t>(sObj);
if (mCount == sCount) {
return res;
std::string failureFlagFile = config_.GetPath() + "-slaveFailure";
if (mCount == sCount && access(failureFlagFile.c_str(), F_OK) != 0) {
LOG_INFO("equal, main:%{public}" PRId64 ",slave:%{public}" PRId64, mCount, sCount);
return ExchangeStrategy::NOT_HANDLE;
}
isExchanged = true;
if (mCount == 0) {
isRestore = true;
LOG_INFO("main empty, main:%{public}" PRId64 ",slave:%{public}" PRId64, mCount, sCount);
} else {
auto [cRet, cObj] = ExecuteForValue(INTEGRITIES[1]); // 1 is quick_check
if (cRet != E_OK || (static_cast<std::string>(cObj) != "ok")) {
LOG_ERROR("main corrupt, need restore, ret:%{public}s, cRet:%{public}d",
static_cast<std::string>(cObj).c_str(), cRet);
isRestore = true;
} else {
LOG_INFO("not equal, main:%{public}" PRId64 ",slave:%{public}" PRId64, mCount, sCount);
}
return ExchangeStrategy::RESTORE;
}
return res;
}
int32_t SqliteConnection::InterruptBackup()
{
if (slaveStatus_.load() == SlaveStatus::BACKING_UP) {
slaveStatus_.store(SlaveStatus::BACKUP_INTERRUPT);
return E_OK;
}
return E_NOT_SUPPORT;
}
int32_t SqliteConnection::GetBackupStatus() const
{
return slaveStatus_.load();
LOG_INFO("backup, main:%{public}" PRId64 ",slave:%{public}" PRId64, mCount, sCount);
return ExchangeStrategy::BACKUP;
}
int32_t SqliteConnection::Repair(const RdbStoreConfig &config)
{
if (config.GetHaMode() != MAIN_REPLICA) {
if (config.GetHaMode() != MAIN_REPLICA && config.GetHaMode() != MANUAL_TRIGGER) {
return E_NOT_SUPPORT;
}
std::shared_ptr<SqliteConnection> connection = std::make_shared<SqliteConnection>(config, true);
@ -1393,8 +1359,9 @@ int32_t SqliteConnection::Repair(const RdbStoreConfig &config)
if (ret != E_OK) {
return ret;
}
if (!connection->IsRepairable()) {
return E_NOT_SUPPORT;
ret = connection->IsRepairable();
if (ret != E_OK) {
return ret;
}
LOG_WARN("begin repair main:%{public}s", SqliteUtils::Anonymous(config.GetPath()).c_str());
(void)SqliteConnection::Delete(config);
@ -1403,57 +1370,103 @@ int32_t SqliteConnection::Repair(const RdbStoreConfig &config)
LOG_ERROR("reopen db failed, err:%{public}d", ret);
return ret;
}
ret = connection->MasterSlaveExchange(true);
SlaveStatus curStatus;
ret = connection->ExchangeSlaverToMaster(true, curStatus);
if (ret != E_OK) {
LOG_ERROR("repair failed, [%{public}s]->[%{public}s], err:%{public}d", rdbSlaveStoreConfig.GetName().c_str(),
config.GetName().c_str(), ret);
return ret;
} else {
LOG_INFO("repair main success:%{public}s", SqliteUtils::Anonymous(config.GetPath()).c_str());
}
LOG_INFO("repair main success:%{public}s", SqliteUtils::Anonymous(config.GetPath()).c_str());
connection->slaveConnection_ = nullptr;
connection = nullptr;
return E_OK;
return ret;
}
bool SqliteConnection::IsRepairable()
int SqliteConnection::IsRepairable()
{
if (slaveConnection_ == nullptr || slaveConnection_->dbHandle_ == nullptr) {
return false;
return E_STORE_CLOSED;
}
static const std::string querySql = "SELECT COUNT(*) FROM sqlite_master WHERE type='table';";
if (SqliteUtils::TryAccessSlaveLock(config_.GetPath(), false, false, false)) {
LOG_ERROR("unavailable slave, %{public}s", config_.GetName().c_str());
return E_DB_RESTORE_NOT_ALLOWED;
}
std::string querySql = "SELECT COUNT(*) FROM sqlite_master WHERE type='table';";
auto [qRet, qObj] = slaveConnection_->ExecuteForValue(querySql);
if (qRet != E_OK || (static_cast<int64_t>(qObj) == 0L)) {
LOG_INFO("cancel repair, ret:%{public}d", qRet);
return false;
return E_DB_RESTORE_NOT_ALLOWED;
}
auto [cRet, cObj] = slaveConnection_->ExecuteForValue(INTEGRITIES[1]); // 1 is quick check
if (cRet != E_OK || (static_cast<std::string>(cObj) != "ok")) {
LOG_ERROR("cancel repair, ret:%{public}s, cRet:%{public}d", static_cast<std::string>(cObj).c_str(), cRet);
return false;
}
return true;
return E_OK;
}
std::pair<bool, int> SqliteConnection::ExchangeVerify(bool isRestore)
int SqliteConnection::ExchangeVerify(bool isRestore)
{
if (dbHandle_ == nullptr || slaveConnection_ == nullptr || slaveConnection_->dbHandle_ == nullptr) {
LOG_WARN("slave conn invalid");
return { true, E_OK };
return E_STORE_CLOSED;
}
if (!SqliteUtils::TryAccessSlaveLock(config_.GetPath(), false, true)) {
LOG_WARN("try create slave lock failed! isRestore:%{public}d", isRestore);
if (access(config_.GetPath().c_str(), F_OK) != 0) {
LOG_WARN("main no exist, isR:%{public}d, %{public}s", isRestore, config_.GetName().c_str());
return E_DB_NOT_EXIST;
}
slaveStatus_.store(SlaveStatus::BACKING_UP);
if (isRestore) {
int err = IsRepairable();
if (err != E_OK) {
return err;
}
auto [cRet, cObj] = slaveConnection_->ExecuteForValue(INTEGRITIES[2]); // 2 is integrity_check
if (cRet != E_OK || (static_cast<std::string>(cObj) != "ok")) {
LOG_ERROR("slave may corrupt, cancel backup, ret:%{public}s, cRet:%{public}d",
LOG_ERROR("slave may corrupt, cancel, ret:%{public}s, cRet:%{public}d",
static_cast<std::string>(cObj).c_str(), cRet);
slaveStatus_.store(SlaveStatus::DB_NOT_EXITS);
return { true, E_SQLITE_CORRUPT };
return E_SQLITE_CORRUPT;
}
std::string querySql = "SELECT COUNT(*) FROM sqlite_master WHERE type='table';";
std::tie(cRet, cObj) = ExecuteForValue(querySql);
if (cRet == E_OK && (static_cast<int64_t>(cObj) == 0L)) {
LOG_INFO("main empty, need restore, %{public}s", config_.GetName().c_str());
return E_OK;
}
if (SqliteUtils::TryAccessSlaveLock(config_.GetPath(), false, false, true)) {
LOG_ERROR("incomplete slave, %{public}s", config_.GetName().c_str());
return E_DB_RESTORE_NOT_ALLOWED;
}
} else {
auto [cRet, cObj] = ExecuteForValue(INTEGRITIES[1]); // 1 is quick_check
if (cRet != E_OK || (static_cast<std::string>(cObj) != "ok")) {
LOG_ERROR("main corrupt, cancel, ret:%{public}s, qRet:%{public}d",
static_cast<std::string>(cObj).c_str(), cRet);
return E_SQLITE_CORRUPT;
}
if (!SqliteUtils::TryAccessSlaveLock(config_.GetPath(), false, true)) {
LOG_WARN("try create slave lock failed! isRestore:%{public}d", isRestore);
}
}
return { false, E_OK };
return E_OK;
}
std::pair<int32_t, std::shared_ptr<SqliteConnection>> SqliteConnection::InnerCreate(const RdbStoreConfig &config,
bool isWrite)
{
std::pair<int32_t, std::shared_ptr<SqliteConnection>> result = { E_ERROR, nullptr };
auto &[errCode, conn] = result;
std::shared_ptr<SqliteConnection> connection = std::make_shared<SqliteConnection>(config, isWrite);
if (connection == nullptr) {
LOG_ERROR("connection is nullptr.");
return result;
}
RdbStoreConfig rdbSlaveStoreConfig = connection->GetSlaveRdbStoreConfig(config);
errCode = connection->InnerOpen(config);
if (errCode != E_OK) {
return result;
}
conn = connection;
if (isWrite) {
(void)connection->CreateSlaveConnection(rdbSlaveStoreConfig, isWrite);
}
return result;
}
} // namespace NativeRdb
} // namespace OHOS

View File

@ -56,6 +56,7 @@ SqliteStatement::~SqliteStatement()
SqlStatistic sqlStatistic("", SqlStatistic::Step::STEP_TOTAL_RES, seqId_);
Finalize();
conn_ = nullptr;
config_ = nullptr;
}
int SqliteStatement::Prepare(sqlite3 *dbHandle, const std::string &newSql)
@ -186,6 +187,7 @@ int SqliteStatement::Prepare(const std::string &sql)
int errCode = slave_->Prepare(sql);
if (errCode != E_OK) {
LOG_WARN("slave prepare Error:%{public}d", errCode);
SqliteUtils::TryAccessSlaveLock(config_->GetPath(), false, true, true);
}
}
return E_OK;
@ -226,6 +228,7 @@ int SqliteStatement::Bind(const std::vector<ValueObject> &args)
int errCode = slave_->Bind(args);
if (errCode != E_OK) {
LOG_ERROR("slave bind error:%{public}d", errCode);
SqliteUtils::TryAccessSlaveLock(config_->GetPath(), false, true, true);
}
}
return E_OK;
@ -328,6 +331,7 @@ int SqliteStatement::Execute(const std::vector<ValueObject> &args)
int errCode = slave_->Execute(args);
if (errCode != E_OK) {
LOG_ERROR("slave execute error:%{public}d", errCode);
SqliteUtils::TryAccessSlaveLock(config_->GetPath(), false, true, true);
}
}
return E_OK;
@ -670,7 +674,6 @@ int SqliteStatement::InnerFinalize()
columnCount_ = -1;
numParameters_ = 0;
types_ = std::vector<int32_t>();
config_ = nullptr;
if (errCode != SQLITE_OK) {
LOG_ERROR("finalize ret is %{public}d, errno is %{public}d", errCode, errno);
return SQLiteError::ErrNo(errCode);

View File

@ -184,15 +184,15 @@ bool SqliteUtils::IsSlaveDbName(const std::string &fileName)
return (pos != std::string::npos) && (pos == fileName.size() - slaveSuffix.size());
}
bool SqliteUtils::TryAccessSlaveLock(const std::string &dbPath, bool isDelete, bool needCreate)
bool SqliteUtils::TryAccessSlaveLock(const std::string &dbPath, bool isDelete, bool needCreate,
bool isSlaveFailure)
{
std::string lockFile = dbPath + "-locker";
std::string lockFile = isSlaveFailure ? dbPath + "-slaveFailure" : dbPath + "-syncInterrupt";
if (isDelete) {
if (std::remove(lockFile.c_str()) != 0) {
LOG_WARN("remove slave lock failed errno %{public}d %{public}s", errno, Anonymous(lockFile).c_str());
return false;
} else {
LOG_INFO("remove slave lock %{public}s", Anonymous(lockFile).c_str());
LOG_INFO("remove %{public}s", Anonymous(lockFile).c_str());
return true;
}
} else {
@ -202,11 +202,11 @@ bool SqliteUtils::TryAccessSlaveLock(const std::string &dbPath, bool isDelete, b
if (needCreate) {
std::ofstream src(lockFile.c_str(), std::ios::binary);
if (src.is_open()) {
LOG_INFO("create slave lock %{public}s", Anonymous(lockFile).c_str());
LOG_INFO("open %{public}s", Anonymous(lockFile).c_str());
src.close();
return true;
} else {
LOG_WARN("open slave lock failed errno %{public}d %{public}s", errno, Anonymous(lockFile).c_str());
LOG_WARN("open errno %{public}d %{public}s", errno, Anonymous(lockFile).c_str());
return false;
}
}

View File

@ -47,6 +47,12 @@ enum SlaveStatus : uint32_t {
BACKUP_INTERRUPT,
BACKUP_FINISHED,
};
enum ExchangeStrategy : uint32_t {
NOT_HANDLE,
BACKUP,
RESTORE,
};
} // namespace NativeRdb
} // namespace OHOS

View File

@ -399,6 +399,21 @@ static constexpr int E_SERVICE_NOT_FOUND = (E_BASE + 71);
* @brief Database schema has changed.
*/
static constexpr int E_SQLITE_SCHEMA = (E_BASE + 72);
/**
* @brief Database backup was interrupted.
*/
static constexpr int E_BACKUP_INTERRUPT = (E_BASE + 0x49);
/**
* @brief Backup interrupt operation is invalid
*/
static constexpr int E_INVALID_INTERRUPT = (E_BASE + 0x4a);
/**
* @brief Restore is not allowed
*/
static constexpr int E_DB_RESTORE_NOT_ALLOWED = (E_BASE + 0x4b);
} // namespace NativeRdb
} // namespace OHOS

View File

@ -563,6 +563,14 @@ public:
*/
virtual int Notify(const std::string &event) = 0;
/**
* @brief Check the slave database is different from current database.
*/
virtual bool IsSlaveDiffFromMaster() const
{
return false;
}
virtual int32_t GetDbType() const
{
return DB_SQLITE;

View File

@ -625,6 +625,8 @@ public:
void SetScalarFunctions(const std::map<std::string, ScalarFunctionInfo> functions);
void SetJournalMode(const std::string &journalMode);
void EnableRekey(bool enable);
private:

View File

@ -40,6 +40,12 @@ enum SlaveStatus : uint32_t {
BACKUP_INTERRUPT,
BACKUP_FINISHED,
};
enum ExchangeStrategy : uint32_t {
NOT_HANDLE,
BACKUP,
RESTORE,
};
}
}

View File

@ -113,7 +113,10 @@ public:
{
return E_OK;
}
virtual bool IsSlaveDiffFromMaster() const
{
return false;
}
virtual int32_t GetBackupStatus() const
{
return SlaveStatus::UNDEFINED;

View File

@ -229,6 +229,7 @@ public:
void SetHaMode(int32_t haMode);
void SetNewEncryptKey(const std::vector<uint8_t> newEncryptKey);
void SetScalarFunctions(const std::map<std::string, ScalarFunctionInfo> functions);
void SetJournalMode(const std::string &journalMode);
void EnableRekey(bool enable);

View File

@ -18,10 +18,14 @@
#include <fstream>
#include <string>
#include "sys/types.h"
#include <sys/stat.h>
#include <unistd.h>
#include "logger.h"
#include "common.h"
#include "sqlite_utils.h"
#include "file_ex.h"
#include "rdb_common.h"
#include "rdb_errno.h"
#include "rdb_helper.h"
@ -43,8 +47,10 @@ public:
void CheckBlob(std::shared_ptr<ResultSet> &resultSet);
void CheckNumber(std::shared_ptr<RdbStore> &store, int num, int errCode = E_OK,
const std::string &tableName = "test");
void Insert(int64_t start, int count, bool isSlave = false);
void WaitForBackupFinish(int32_t expectStatus);
void Insert(int64_t start, int count, bool isSlave = false, int dataSize = 0);
void WaitForBackupFinish(int32_t expectStatus, int maxTimes = 400);
void TryInterruptBackup();
void InitDb();
static const std::string DATABASE_NAME;
static const std::string SLAVE_DATABASE_NAME;
@ -102,6 +108,17 @@ void RdbDoubleWriteTest::TearDownTestCase(void)
}
void RdbDoubleWriteTest::SetUp(void)
{
}
void RdbDoubleWriteTest::TearDown(void)
{
store = nullptr;
slaveStore = nullptr;
RdbHelper::DeleteRdbStore(RdbDoubleWriteTest::DATABASE_NAME);
}
void RdbDoubleWriteTest::InitDb()
{
int errCode = E_OK;
RdbStoreConfig config(RdbDoubleWriteTest::DATABASE_NAME);
@ -118,13 +135,6 @@ void RdbDoubleWriteTest::SetUp(void)
slaveStore->ExecuteSql("DELETE FROM test");
}
void RdbDoubleWriteTest::TearDown(void)
{
RdbHelper::DeleteRdbStore(RdbDoubleWriteTest::DATABASE_NAME);
RdbHelper::DeleteRdbStore(RdbDoubleWriteTest::SLAVE_DATABASE_NAME);
std::this_thread::sleep_for(std::chrono::milliseconds(200)); // 200ms delay
}
/**
* @tc.name: RdbStore_DoubleWrite_001
* @tc.desc: test RdbStore doubleWrite
@ -132,8 +142,7 @@ void RdbDoubleWriteTest::TearDown(void)
*/
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_001, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbDoubleWriteTest::store;
std::shared_ptr<RdbStore> &slaveStore = RdbDoubleWriteTest::slaveStore;
InitDb();
int64_t id;
ValuesBucket values;
@ -169,7 +178,7 @@ HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_001, TestSize.Level1)
RdbDoubleWriteTest::CheckResultSet(slaveStore);
}
void RdbDoubleWriteTest::Insert(int64_t start, int count, bool isSlave)
void RdbDoubleWriteTest::Insert(int64_t start, int count, bool isSlave, int dataSize)
{
ValuesBucket values;
int64_t id = start;
@ -177,7 +186,11 @@ void RdbDoubleWriteTest::Insert(int64_t start, int count, bool isSlave)
for (int i = 0; i < count; i++) {
values.Clear();
values.PutInt("id", id);
values.PutString("name", std::string("zhangsan"));
if (dataSize > 0) {
values.PutString("name", std::string(dataSize, 'a'));
} else {
values.PutString("name", std::string("zhangsan"));
}
values.PutInt("age", CHECKAGE);
values.PutDouble("salary", CHECKCOLUMN);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
@ -191,17 +204,29 @@ void RdbDoubleWriteTest::Insert(int64_t start, int count, bool isSlave)
}
}
void RdbDoubleWriteTest::WaitForBackupFinish(int32_t expectStatus)
void RdbDoubleWriteTest::WaitForBackupFinish(int32_t expectStatus, int maxTimes)
{
int32_t curStatus = store->GetBackupStatus();
int tryTimes = 0;
while (curStatus != expectStatus && (++tryTimes <= 5)) { // 5 is try time
usleep(50000); // 50000 is wait time
while (curStatus != expectStatus && (++tryTimes <= maxTimes)) {
usleep(50000); // 50000 delay
curStatus = store->GetBackupStatus();
}
LOG_INFO("----------cur backup Status:%{public}d---------", curStatus);
ASSERT_EQ(curStatus, expectStatus);
}
void RdbDoubleWriteTest::TryInterruptBackup()
{
int err = store->InterruptBackup();
int tryTimes = 0;
while (err != E_OK && (++tryTimes <= 1000)) { // 1000 is try time
usleep(10000); // 10000 delay
err = store->InterruptBackup();
}
EXPECT_EQ(err, E_OK);
LOG_INFO("----------interrupt backup---------");
}
void RdbDoubleWriteTest::CheckResultSet(std::shared_ptr<RdbStore> &store)
{
@ -316,32 +341,7 @@ void RdbDoubleWriteTest::CheckNumber(std::shared_ptr<RdbStore> &store, int num,
EXPECT_EQ(ret, errCode);
EXPECT_EQ(num, countNum);
}
/**
* @tc.name: RdbStore_DoubleWrite_002
* @tc.desc: test RdbStore waL limit
* @tc.type: FUNC
*/
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_002, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbDoubleWriteTest::store;
std::shared_ptr<RdbStore> &slaveStore = RdbDoubleWriteTest::slaveStore;
int64_t id = 10;
ValuesBucket values;
for (int i = 0; i < 25158; i++) {
id++;
values.Clear();
values.PutInt("id", id);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", CHECKAGE);
values.PutDouble("salary", CHECKCOLUMN);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
int ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
}
RdbDoubleWriteTest::CheckNumber(slaveStore, 25158);
}
/**
* @tc.name: RdbStore_DoubleWrite_003
* @tc.desc: test RdbStore execute
@ -349,8 +349,7 @@ HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_002, TestSize.Level1)
*/
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_003, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbDoubleWriteTest::store;
std::shared_ptr<RdbStore> &slaveStore = RdbDoubleWriteTest::slaveStore;
InitDb();
int64_t id;
ValuesBucket values;
@ -374,8 +373,7 @@ HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_003, TestSize.Level1)
*/
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_004, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbDoubleWriteTest::store;
std::shared_ptr<RdbStore> &slaveStore = RdbDoubleWriteTest::slaveStore;
InitDb();
int64_t id;
@ -404,8 +402,7 @@ HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_004, TestSize.Level1)
*/
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_005, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbDoubleWriteTest::store;
std::shared_ptr<RdbStore> &slaveStore = RdbDoubleWriteTest::slaveStore;
InitDb();
ValuesBucket values;
int64_t id;
@ -454,9 +451,6 @@ HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_005, TestSize.Level1)
*/
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_007, TestSize.Level1)
{
RdbHelper::DeleteRdbStore(RdbDoubleWriteTest::DATABASE_NAME);
RdbHelper::DeleteRdbStore(RdbDoubleWriteTest::SLAVE_DATABASE_NAME);
int errCode = E_OK;
RdbStoreConfig config(RdbDoubleWriteTest::DATABASE_NAME);
config.SetHaMode(HAMode::SINGLE);
@ -490,7 +484,7 @@ HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_007, TestSize.Level1)
*/
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_008, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbDoubleWriteTest::store;
InitDb();
int64_t id = 10;
int count = 100;
Insert(id, count);
@ -531,6 +525,7 @@ HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_008, TestSize.Level1)
*/
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_009, TestSize.Level1)
{
InitDb();
int64_t id = 10;
Insert(id, 100);
id = 200;
@ -548,7 +543,7 @@ HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_009, TestSize.Level1)
*/
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_010, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbDoubleWriteTest::store;
InitDb();
int64_t id = 10;
int count = 100;
Insert(id, count);
@ -581,7 +576,7 @@ HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_010, TestSize.Level1)
RdbDoubleWriteTest::slaveStore = RdbHelper::GetRdbStore(slaveConfig, 1, slaveHelper, errCode);
EXPECT_NE(RdbDoubleWriteTest::slaveStore, nullptr);
LOG_INFO("RdbStore_DoubleWrite_010 reopen slave db finish");
WaitForBackupFinish(BACKUP_FINISHED);
RdbDoubleWriteTest::CheckNumber(slaveStore, count);
}
@ -592,7 +587,7 @@ HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_010, TestSize.Level1)
*/
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_011, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbDoubleWriteTest::store;
InitDb();
int64_t id = 10;
int count = 100;
Insert(id, count);
@ -630,8 +625,7 @@ HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_011, TestSize.Level1)
*/
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_012, TestSize.Level1)
{
std::shared_ptr<RdbStore> &store = RdbDoubleWriteTest::store;
std::shared_ptr<RdbStore> &slaveStore = RdbDoubleWriteTest::slaveStore;
InitDb();
int err = store->BeginTransaction();
EXPECT_EQ(err, E_OK);
@ -659,9 +653,6 @@ HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_012, TestSize.Level1)
*/
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_013, TestSize.Level1)
{
RdbHelper::DeleteRdbStore(RdbDoubleWriteTest::DATABASE_NAME);
RdbHelper::DeleteRdbStore(RdbDoubleWriteTest::SLAVE_DATABASE_NAME);
int errCode = E_OK;
RdbStoreConfig config(RdbDoubleWriteTest::DATABASE_NAME);
config.SetHaMode(HAMode::MANUAL_TRIGGER);
@ -703,9 +694,6 @@ HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_013, TestSize.Level1)
*/
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_014, TestSize.Level1)
{
RdbHelper::DeleteRdbStore(RdbDoubleWriteTest::DATABASE_NAME);
RdbHelper::DeleteRdbStore(RdbDoubleWriteTest::SLAVE_DATABASE_NAME);
int errCode = E_OK;
RdbStoreConfig config(RdbDoubleWriteTest::DATABASE_NAME);
config.SetHaMode(HAMode::MANUAL_TRIGGER);
@ -745,6 +733,7 @@ HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_014, TestSize.Level1)
*/
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_015, TestSize.Level1)
{
InitDb();
int64_t id = 10;
int count = 100;
ValuesBucket values;
@ -800,12 +789,14 @@ HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_015, TestSize.Level1)
*/
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_016, TestSize.Level1)
{
InitDb();
int64_t id = 10;
int count = 100;
Insert(id, count);
LOG_INFO("RdbStore_DoubleWrite_016 insert finish");
store = nullptr;
LOG_INFO("RdbStore_DoubleWrite_016 close finish");
SqliteUtils::DeleteFile(DATABASE_NAME);
SqliteUtils::DeleteFile(DATABASE_NAME + "-shm");
@ -821,21 +812,92 @@ HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_016, TestSize.Level1)
ASSERT_NE(store, nullptr);
LOG_INFO("RdbStore_DoubleWrite_016 reopen db finish");
WaitForBackupFinish(BACKUP_FINISHED);
RdbDoubleWriteTest::CheckNumber(store, count);
RdbDoubleWriteTest::CheckNumber(slaveStore, count);
}
/**
* @tc.name: RdbStore_DoubleWrite_017
* @tc.desc: open MAIN_REPLICA db, write, close, reopen, corrupt db, restore, check count
* @tc.name: RdbStore_DoubleWrite_018
* @tc.desc: open MAIN_REPLICA db, update slave, insert, M succ && S failed,
* check failureFlag, backup, check failureFlag
* @tc.type: FUNC
*/
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_017, TestSize.Level1)
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_018, TestSize.Level1)
{
int64_t id = 10;
int count = 100;
Insert(id, count);
LOG_INFO("RdbStore_DoubleWrite_017 insert finish");
InitDb();
int64_t id;
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 25);
values.PutDouble("salary", CHECKCOLUMN);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
int ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
auto [ret2, outValue2] = slaveStore->Execute("UPDATE test SET id = 3 WHERE id = 1");
EXPECT_EQ(E_OK, ret2);
int64_t id2;
ValuesBucket values2;
values2.PutInt("id", 3);
values2.PutString("name", std::string("zhangsan"));
values2.PutInt("age", 25);
values2.PutDouble("salary", CHECKCOLUMN);
values2.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
int ret3 = store->Insert(id2, "test", values2);
EXPECT_EQ(E_OK, ret3);
std::string failureFlagPath = RdbDoubleWriteTest::DATABASE_NAME + + "-slaveFailure";
bool isFlagFileExists = OHOS::FileExists(failureFlagPath);
ASSERT_TRUE(isFlagFileExists);
ASSERT_TRUE(store->IsSlaveDiffFromMaster());
int errCode;
errCode = store->Backup(std::string(""), {});
EXPECT_EQ(errCode, E_OK);
isFlagFileExists = OHOS::FileExists(failureFlagPath);
ASSERT_FALSE(isFlagFileExists);
}
/**
* @tc.name: RdbStore_DoubleWrite_019
* @tc.desc: open MAIN_REPLICA db, update slave, insert, M succ && S failed,
* check failureFlag, reopen, check failureFlag
* @tc.type: FUNC
*/
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_019, TestSize.Level1)
{
InitDb();
int64_t id;
ValuesBucket values;
values.PutInt("id", 1);
values.PutString("name", std::string("zhangsan"));
values.PutInt("age", 25);
values.PutDouble("salary", CHECKCOLUMN);
values.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
int ret = store->Insert(id, "test", values);
EXPECT_EQ(ret, E_OK);
auto [ret2, outValue2] = slaveStore->Execute("UPDATE test SET id = 3 WHERE id = 1");
EXPECT_EQ(E_OK, ret2);
int64_t id2;
ValuesBucket values2;
values2.PutInt("id", 3);
values2.PutString("name", std::string("zhangsan"));
values2.PutInt("age", 25);
values2.PutDouble("salary", CHECKCOLUMN);
values2.PutBlob("blobType", std::vector<uint8_t>{ 1, 2, 3 });
int ret3 = store->Insert(id2, "test", values2);
EXPECT_EQ(E_OK, ret3);
std::string failureFlagPath = RdbDoubleWriteTest::DATABASE_NAME + + "-slaveFailure";
bool isFlagFileExists = OHOS::FileExists(failureFlagPath);
ASSERT_TRUE(isFlagFileExists);
ASSERT_TRUE(store->IsSlaveDiffFromMaster());
store = nullptr;
RdbStoreConfig config(RdbDoubleWriteTest::DATABASE_NAME);
@ -844,23 +906,333 @@ HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_017, TestSize.Level1)
DoubleWriteTestOpenCallback helper;
int errCode;
store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
WaitForBackupFinish(BACKUP_FINISHED);
store = nullptr;
isFlagFileExists = OHOS::FileExists(failureFlagPath);
ASSERT_FALSE(isFlagFileExists);
}
/**
* @tc.name: RdbStore_DoubleWrite_022
* @tc.desc: open SINGLE db, write, close, reopen MAIN_REPLICA db, wait for backup, insert, check count
* @tc.type: FUNC
*/
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_022, TestSize.Level1)
{
int errCode = E_OK;
RdbStoreConfig config(RdbDoubleWriteTest::DATABASE_NAME);
config.SetHaMode(HAMode::SINGLE);
DoubleWriteTestOpenCallback helper;
store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(store, nullptr);
int64_t id = 10;
int strSize = 1024 * 100;
int count = 2000;
Insert(id, count, false, strSize);
LOG_INFO("RdbStore_DoubleWrite_022 insert finish");
store = nullptr;
config.SetHaMode(HAMode::MAIN_REPLICA);
store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
ASSERT_NE(store, nullptr);
LOG_INFO("RdbStore_DoubleWrite_022 reopen db finish");
WaitForBackupFinish(BACKUP_FINISHED);
id = 6666;
Insert(id, count);
LOG_INFO("RdbStore_DoubleWrite_022 insert db finish");
RdbStoreConfig slaveConfig(RdbDoubleWriteTest::SLAVE_DATABASE_NAME);
DoubleWriteTestOpenCallback slaveHelper;
RdbDoubleWriteTest::slaveStore = RdbHelper::GetRdbStore(slaveConfig, 1, slaveHelper, errCode);
EXPECT_NE(RdbDoubleWriteTest::slaveStore, nullptr);
LOG_INFO("RdbStore_DoubleWrite_022 reopen slave db finish");
RdbDoubleWriteTest::CheckNumber(store, count + count);
RdbDoubleWriteTest::CheckNumber(slaveStore, count + count);
}
/**
* @tc.name: RdbStore_DoubleWrite_023
* @tc.desc: open MANUAL_TRIGGER db, write, backup async, interrupt, backup async, wait finish, check count
* @tc.type: FUNC
*/
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_023, TestSize.Level1)
{
int errCode = E_OK;
RdbStoreConfig config(RdbDoubleWriteTest::DATABASE_NAME);
config.SetHaMode(HAMode::MANUAL_TRIGGER);
DoubleWriteTestOpenCallback helper;
store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(store, nullptr);
ASSERT_TRUE(store->IsSlaveDiffFromMaster());
LOG_INFO("RdbStore_DoubleWrite_023 reopen finish");
int64_t id = 10;
int strSize = 1024 * 100;
int count = 2000;
Insert(id, count, false, strSize);
LOG_INFO("RdbStore_DoubleWrite_023 insert finish");
std::thread thread([this]() {
LOG_INFO("RdbStore_DoubleWrite_023 t1 backup begin");
EXPECT_EQ(store->Backup(std::string(""), {}), E_BACKUP_INTERRUPT);
LOG_INFO("RdbStore_DoubleWrite_023 t1 backup end");
});
LOG_INFO("RdbStore_DoubleWrite_023 begin interrupt");
TryInterruptBackup();
LOG_INFO("RdbStore_DoubleWrite_023 interrupt end");
EXPECT_EQ(store->GetBackupStatus(), SlaveStatus::BACKUP_INTERRUPT);
thread.join();
std::thread thread1([this]() {
LOG_INFO("RdbStore_DoubleWrite_023 t2 backup begin");
EXPECT_EQ(store->Backup(std::string(""), {}), E_OK);
LOG_INFO("RdbStore_DoubleWrite_023 t2 backup end");
});
WaitForBackupFinish(BACKUP_FINISHED);
LOG_INFO("RdbStore_DoubleWrite_023 wait finish");
thread1.join();
RdbStoreConfig slaveConfig(RdbDoubleWriteTest::SLAVE_DATABASE_NAME);
DoubleWriteTestOpenCallback slaveHelper;
RdbDoubleWriteTest::slaveStore = RdbHelper::GetRdbStore(slaveConfig, 1, slaveHelper, errCode);
EXPECT_NE(RdbDoubleWriteTest::slaveStore, nullptr);
LOG_INFO("RdbStore_DoubleWrite_023 reopen slave db finish");
RdbDoubleWriteTest::CheckNumber(store, count);
RdbDoubleWriteTest::CheckNumber(slaveStore, count);
}
/**
* @tc.name: RdbStore_DoubleWrite_024
* @tc.desc: open SINGLE db, write, close, reopen MAIN_REPLICA db, wait for backup, insert, check count
* @tc.type: FUNC
*/
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_024, TestSize.Level1)
{
int errCode = E_OK;
RdbStoreConfig config(RdbDoubleWriteTest::DATABASE_NAME);
config.SetHaMode(HAMode::SINGLE);
DoubleWriteTestOpenCallback helper;
store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(store, nullptr);
int64_t id = 10;
int strSize = 1024 * 200;
int count = 1000;
Insert(id, count, false, strSize);
LOG_INFO("RdbStore_DoubleWrite_024 insert finish");
store = nullptr;
LOG_INFO("RdbStore_DoubleWrite_024 close finish");
config.SetHaMode(HAMode::MAIN_REPLICA);
store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
ASSERT_NE(store, nullptr);
LOG_INFO("RdbStore_DoubleWrite_024 reopen db finish");
usleep(200000); // 200000 us delay
store = nullptr;
LOG_INFO("RdbStore_DoubleWrite_024 close again");
RdbStoreConfig slaveConfig(RdbDoubleWriteTest::SLAVE_DATABASE_NAME);
DoubleWriteTestOpenCallback slaveHelper;
RdbDoubleWriteTest::slaveStore = RdbHelper::GetRdbStore(slaveConfig, 1, slaveHelper, errCode);
EXPECT_NE(RdbDoubleWriteTest::slaveStore, nullptr);
LOG_INFO("RdbStore_DoubleWrite_024 reopen slave");
RdbDoubleWriteTest::CheckNumber(slaveStore, count);
}
/**
* @tc.name: RdbStore_DoubleWrite_025
* @tc.desc: open SINGLE db, write, close, reopen MAIN_REPLICA db, insert, wait for backup, check count
* @tc.type: FUNC
*/
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_025, TestSize.Level1)
{
int errCode = E_OK;
RdbStoreConfig config(RdbDoubleWriteTest::DATABASE_NAME);
config.SetHaMode(HAMode::SINGLE);
DoubleWriteTestOpenCallback helper;
store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_NE(store, nullptr);
int64_t id = 10;
int strSize = 1024 * 200;
int count = 1000;
Insert(id, count, false, strSize);
LOG_INFO("RdbStore_DoubleWrite_025 insert finish");
store = nullptr;
LOG_INFO("RdbStore_DoubleWrite_025 close finish");
config.SetHaMode(HAMode::MAIN_REPLICA);
store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
ASSERT_NE(store, nullptr);
LOG_INFO("RdbStore_DoubleWrite_025 reopen db finish");
id = 6666;
LOG_INFO("RdbStore_DoubleWrite_025 begin insert");
Insert(id, count, false, strSize);
LOG_INFO("RdbStore_DoubleWrite_025 insert end");
WaitForBackupFinish(BACKUP_FINISHED, 1000); // 1000 is max retry time
LOG_INFO("RdbStore_DoubleWrite_025 wait finish");
RdbStoreConfig slaveConfig(RdbDoubleWriteTest::SLAVE_DATABASE_NAME);
DoubleWriteTestOpenCallback slaveHelper;
RdbDoubleWriteTest::slaveStore = RdbHelper::GetRdbStore(slaveConfig, 1, slaveHelper, errCode);
EXPECT_NE(RdbDoubleWriteTest::slaveStore, nullptr);
LOG_INFO("RdbStore_DoubleWrite_025 reopen slave");
RdbDoubleWriteTest::CheckNumber(store, count + count);
std::shared_ptr<ResultSet> resultSet = slaveStore->QuerySql("SELECT * FROM test");
ASSERT_NE(resultSet, nullptr);
int countNum;
EXPECT_EQ(resultSet->GetRowCount(countNum), errCode);
EXPECT_GT(countNum, count);
EXPECT_LE(countNum, count + count);
}
/**
* @tc.name: RdbStore_DoubleWrite_026
* @tc.desc: open MANUAL_TRIGGER db, write, restore, insert, check count
* @tc.type: FUNC
*/
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_026, TestSize.Level1)
{
int errCode = E_OK;
RdbStoreConfig config(RdbDoubleWriteTest::DATABASE_NAME);
config.SetHaMode(HAMode::MANUAL_TRIGGER);
DoubleWriteTestOpenCallback helper;
store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_EQ(errCode, E_OK);
ASSERT_NE(store, nullptr);
LOG_INFO("RdbStore_DoubleWrite_017 reopen db finish");
int64_t id = 10;
int count = 100;
Insert(id, count);
EXPECT_EQ(store->Restore(std::string(""), {}), E_INVALID_FILE_PATH);
id = 2000;
Insert(id, count);
RdbDoubleWriteTest::CheckNumber(store, count + count);
}
/**
* @tc.name: RdbStore_DoubleWrite_027
* @tc.desc: open MANUAL_TRIGGER db, write, close, corrupt db, reopen, insert, check count
* @tc.type: FUNC
*/
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_027, TestSize.Level1)
{
int errCode = E_OK;
RdbStoreConfig config(RdbDoubleWriteTest::DATABASE_NAME);
config.SetHaMode(HAMode::MANUAL_TRIGGER);
config.SetAllowRebuild(true);
DoubleWriteTestOpenCallback helper;
RdbStoreConfig slaveConfig(RdbDoubleWriteTest::SLAVE_DATABASE_NAME);
DoubleWriteTestOpenCallback slaveHelper;
RdbDoubleWriteTest::slaveStore = RdbHelper::GetRdbStore(slaveConfig, 1, slaveHelper, errCode);
EXPECT_NE(RdbDoubleWriteTest::slaveStore, nullptr);
store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_EQ(errCode, E_OK);
ASSERT_NE(store, nullptr);
int64_t id = 10;
int count = 100;
Insert(id, count);
RdbDoubleWriteTest::CheckNumber(slaveStore, count);
store = nullptr;
std::fstream file(DATABASE_NAME, std::ios::in | std::ios::out | std::ios::binary);
ASSERT_TRUE(file.is_open() == true);
file.seekp(0, std::ios::beg);
file.seekp(30, std::ios::beg);
ASSERT_TRUE(file.good() == true);
char bytes[2] = {0x6, 0x6};
file.write(bytes, 2);
ASSERT_TRUE(file.good() == true);
file.close();
LOG_INFO("RdbStore_DoubleWrite_017 corrupt db finish");
EXPECT_EQ(store->Restore(std::string(""), {}), E_OK);
LOG_INFO("RdbStore_DoubleWrite_017 restore db finish");
store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
EXPECT_EQ(errCode, E_OK);
ASSERT_NE(store, nullptr);
id = 1000;
Insert(id, count);
RdbDoubleWriteTest::CheckNumber(store, count + count);
}
/**
* @tc.name: RdbStore_DoubleWrite_029
* @tc.desc: open db, write, corrupt slave db, backup, backup, check count
* @tc.type: FUNC
*/
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_029, TestSize.Level1)
{
InitDb();
int64_t id = 10;
int count = 100;
Insert(id, count);
std::fstream slaveFile(SLAVE_DATABASE_NAME, std::ios::in | std::ios::out | std::ios::trunc);
ASSERT_TRUE(slaveFile.is_open() == true);
slaveFile << "0000";
slaveFile.flush();
slaveFile.close();
std::fstream slaveWalFile(SLAVE_DATABASE_NAME + "-wal", std::ios::in | std::ios::out | std::ios::trunc);
ASSERT_TRUE(slaveWalFile.is_open() == true);
slaveWalFile << "0000";
slaveWalFile.flush();
slaveWalFile.close();
EXPECT_NE(store->Backup(std::string(""), {}), E_OK);
LOG_INFO("RdbStore_DoubleWrite_029 backup again");
EXPECT_EQ(store->Backup(std::string(""), {}), E_OK);
RdbDoubleWriteTest::CheckNumber(store, count);
RdbDoubleWriteTest::CheckNumber(slaveStore, -1, E_SQLITE_IOERR);
int errCode = E_OK;
slaveStore = nullptr;
RdbStoreConfig slaveConfig(RdbDoubleWriteTest::SLAVE_DATABASE_NAME);
DoubleWriteTestOpenCallback slaveHelper;
RdbDoubleWriteTest::slaveStore = RdbHelper::GetRdbStore(slaveConfig, 1, slaveHelper, errCode);
EXPECT_NE(RdbDoubleWriteTest::slaveStore, nullptr);
RdbDoubleWriteTest::CheckNumber(slaveStore, count);
}
/**
* @tc.name: RdbStore_DoubleWrite_030
* @tc.desc: open db, write, update slave, insert, check failure, restore, check count
* @tc.type: FUNC
*/
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_030, TestSize.Level1)
{
InitDb();
int64_t id = 10;
int count = 100;
Insert(id, count);
auto [ret2, outValue2] = slaveStore->Execute("UPDATE test SET id = 666 WHERE id = 22");
EXPECT_EQ(E_OK, ret2);
id = 666;
Insert(id, 1);
std::string failureFlagPath = RdbDoubleWriteTest::DATABASE_NAME + + "-slaveFailure";
bool isFlagFileExists = OHOS::FileExists(failureFlagPath);
ASSERT_TRUE(isFlagFileExists);
EXPECT_NE(store->Restore(std::string(""), {}), E_OK);
RdbDoubleWriteTest::CheckNumber(store, count + 1);
RdbDoubleWriteTest::CheckNumber(slaveStore, count);
}

View File

@ -21,6 +21,7 @@
#include "common.h"
#include "rdb_errno.h"
#include "file_ex.h"
using namespace testing::ext;
using namespace OHOS::NativeRdb;
@ -99,4 +100,24 @@ HWTEST_F(RdbSecurityManagerTest, LockUnlock, TestSize.Level1)
ASSERT_TRUE(afterUnlock);
thread.join();
}
/**
* @tc.name: LoadSecretKeyFromDiskTest
* @tc.desc: test load secret key from disk test
* @tc.type: FUNC
*/
HWTEST_F(RdbSecurityManagerTest, LoadSecretKeyFromDiskTest, TestSize.Level1)
{
std::string name = "secret_key_load_test";
auto keyPath = RDB_TEST_PATH + "key/" + name + ".pub_key";
RdbSecurityManager::KeyFiles keyFile(keyPath);
const std::string file = keyFile.GetKeyFile(RdbSecurityManager::KeyFileType::PUB_KEY_FILE);
std::vector<char> content = { 'a' };
bool ret = OHOS::SaveBufferToFile(file, content);
ASSERT_TRUE(ret);
RdbPassword pwd =
RdbSecurityManager::GetInstance().GetRdbPassword(keyPath, RdbSecurityManager::KeyFileType::PUB_KEY_FILE);
ASSERT_EQ(pwd.GetSize(), 0);
}
}

View File

@ -501,15 +501,16 @@ HWTEST_F(RdbStoreImplTest, Rdb_ConnectionPoolTest_0023, TestSize.Level2)
// newPath == currentPath, writeConnectionUsed == true
auto connection = connectionPool->AcquireConnection(false);
errCode = connectionPool->ChangeDbFileForRestore(newPath, backupPath, newKey);
SlaveStatus curStatus;
errCode = connectionPool->ChangeDbFileForRestore(newPath, backupPath, newKey, curStatus);
EXPECT_EQ(E_ERROR, errCode);
connection = nullptr;
// newPath == currentPath
errCode = connectionPool->ChangeDbFileForRestore(newPath, backupPath, newKey);
errCode = connectionPool->ChangeDbFileForRestore(newPath, backupPath, newKey, curStatus);
EXPECT_NE(E_OK, errCode);
// newPath != currentPath
const std::string newPath2 = RDB_TEST_PATH + "tmp.db";
errCode = connectionPool->ChangeDbFileForRestore(newPath2, backupPath, newKey);
errCode = connectionPool->ChangeDbFileForRestore(newPath2, backupPath, newKey, curStatus);
EXPECT_EQ(E_ERROR, errCode);
}