mirror of
https://gitee.com/openharmony/distributeddatamgr_relational_store
synced 2024-11-23 07:00:41 +00:00
commit
fc7f52f520
@ -81,6 +81,11 @@ private:
|
||||
const char *debug_ = nullptr;
|
||||
};
|
||||
|
||||
enum SlaveOpenPolicy : int32_t {
|
||||
FORCE_OPEN = 0,
|
||||
OPEN_IF_DB_VALID // DB exists and there are no -slaveFailure and -syncInterrupt files
|
||||
};
|
||||
|
||||
int InnerOpen(const RdbStoreConfig &config);
|
||||
int Configure(const RdbStoreConfig &config, std::string &dbPath);
|
||||
int SetPageSize(const RdbStoreConfig &config);
|
||||
@ -113,10 +118,13 @@ private:
|
||||
int32_t OpenDatabase(const std::string &dbPath, int openFileFlags);
|
||||
int LoadExtension(const RdbStoreConfig &config, sqlite3 *dbHandle);
|
||||
RdbStoreConfig GetSlaveRdbStoreConfig(const RdbStoreConfig &rdbConfig);
|
||||
int CreateSlaveConnection(const RdbStoreConfig &config, bool checkSlaveExist = true);
|
||||
int ExchangeSlaverToMaster(bool isRestore, SlaveStatus &status);
|
||||
int IsRepairable();
|
||||
std::pair<int32_t, std::shared_ptr<SqliteConnection>> CreateSlaveConnection(const RdbStoreConfig &config,
|
||||
SlaveOpenPolicy slaveOpenPolicy);
|
||||
int ExchangeSlaverToMaster(bool isRestore, bool verifyDb, SlaveStatus &status);
|
||||
int ExchangeVerify(bool isRestore);
|
||||
int SqliteNativeBackup(bool isRestore, SlaveStatus &curStatus);
|
||||
int VeritySlaveIntegrity();
|
||||
bool IsDbVersionBelowSlave();
|
||||
static std::pair<int32_t, std::shared_ptr<SqliteConnection>> InnerCreate(const RdbStoreConfig &config,
|
||||
bool isWrite);
|
||||
static constexpr SqliteConnection::Suffix FILE_SUFFIXES[] = {
|
||||
@ -134,7 +142,9 @@ private:
|
||||
static constexpr int BACKUP_PAGES_PRE_STEP = 12800; // 1024 * 4 * 12800 == 50m
|
||||
static constexpr int BACKUP_PRE_WAIT_TIME = 10;
|
||||
static constexpr ssize_t SLAVE_WAL_SIZE_LIMIT = 2147483647; // 2147483647 = 2g - 1
|
||||
static constexpr ssize_t SLAVE_INTEGRITY_CHECK_LIMIT = 524288000; // 524288000 == 1024 * 1024 * 500
|
||||
static constexpr uint32_t NO_ITER = 0;
|
||||
static constexpr uint32_t DB_INDEX = 0;
|
||||
static constexpr uint32_t WAL_INDEX = 2;
|
||||
static const int32_t regCreator_;
|
||||
static const int32_t regRepairer_;
|
||||
|
@ -43,6 +43,8 @@ public:
|
||||
static constexpr int ENABLE_LOAD_EXTENSION = 1;
|
||||
static constexpr int MAX_LOAD_EXTENSION_COUNT = 16;
|
||||
static constexpr const char* REP = "#_";
|
||||
static constexpr const char* SLAVE_FAILURE = "-slaveFailure";
|
||||
static constexpr const char* SLAVE_INTERRUPT = "-syncInterrupt";
|
||||
|
||||
static int GetSqlStatementType(const std::string &sql);
|
||||
static bool IsSupportSqlForExecute(int sqlType);
|
||||
@ -58,8 +60,11 @@ public:
|
||||
static ssize_t 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,
|
||||
bool isSlaveFailure = false);
|
||||
static int SetSlaveInvalid(const std::string &dbPath);
|
||||
static int SetSlaveInterrupted(const std::string &dbPath);
|
||||
static bool IsSlaveInvalid(const std::string &dbPath);
|
||||
static bool IsSlaveInterrupted(const std::string &dbPath);
|
||||
static void SetSlaveValid(const std::string &dbPath);
|
||||
static const char *HmacAlgoDescription(int32_t hmacAlgo);
|
||||
static const char *KdfAlgoDescription(int32_t kdfAlgo);
|
||||
static const char *EncryptAlgoDescription(int32_t encryptAlgo);
|
||||
|
@ -81,9 +81,12 @@ std::pair<RebuiltType, std::shared_ptr<ConnectionPool>> ConnPool::HandleDataCorr
|
||||
errCode = Connection::Repair(storeConfig);
|
||||
if (errCode == E_OK) {
|
||||
rebuiltType = RebuiltType::REPAIRED;
|
||||
} else {
|
||||
} else if (storeConfig.GetAllowRebuild()) {
|
||||
Connection::Delete(storeConfig);
|
||||
rebuiltType = RebuiltType::REBUILT;
|
||||
} else {
|
||||
errCode = E_SQLITE_CORRUPT;
|
||||
return result;
|
||||
}
|
||||
pool = Create(storeConfig, errCode);
|
||||
if (errCode != E_OK) {
|
||||
|
@ -348,11 +348,6 @@ void RdbStoreConfig::RestoreEncryptKey(const std::vector<uint8_t> &encryptKey) c
|
||||
cryptoParam_.encryptKey_ = encryptKey;
|
||||
}
|
||||
|
||||
void RdbStoreConfig::SetNewEncryptKey(const std::vector<uint8_t> newEncryptKey)
|
||||
{
|
||||
newEncryptKey_ = newEncryptKey;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> RdbStoreConfig::GetEncryptKey() const
|
||||
{
|
||||
return cryptoParam_.encryptKey_;
|
||||
|
@ -889,8 +889,9 @@ RdbStoreImpl::RdbStoreImpl(const RdbStoreConfig &config, int &errCode)
|
||||
path_ = (config.GetRoleType() != OWNER) ? config.GetVisitorDir() : config.GetPath();
|
||||
bool created = access(path_.c_str(), F_OK) != 0;
|
||||
connectionPool_ = ConnectionPool::Create(config_, errCode);
|
||||
if (connectionPool_ == nullptr && errCode == E_SQLITE_CORRUPT && config.GetAllowRebuild() && !isReadOnly_) {
|
||||
LOG_ERROR("database corrupt, rebuild database %{public}s", SqliteUtils::Anonymous(name_).c_str());
|
||||
if (connectionPool_ == nullptr && errCode == E_SQLITE_CORRUPT && !isReadOnly_) {
|
||||
LOG_ERROR("database corrupt, %{public}s, %{public}s", SqliteUtils::Anonymous(name_).c_str(),
|
||||
Reportor::FormatBrief(Connection::Collect(config_), "master").c_str());
|
||||
#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
|
||||
RdbParam param;
|
||||
param.bundleName_ = config_.GetBundleName();
|
||||
@ -2312,14 +2313,13 @@ bool RdbStoreImpl::TryGetMasterSlaveBackupPath(const std::string &srcPath, std::
|
||||
|
||||
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;
|
||||
return SqliteUtils::IsSlaveInvalid(config_.GetPath()) || (access(slaveDbPath.c_str(), F_OK) != 0);
|
||||
}
|
||||
|
||||
int32_t RdbStoreImpl::ExchangeSlaverToMaster()
|
||||
{
|
||||
if (isReadOnly_) {
|
||||
if (isReadOnly_ || rebuild_ != RebuiltType::NONE) {
|
||||
return E_OK;
|
||||
}
|
||||
auto conn = connectionPool_->AcquireConnection(false);
|
||||
|
@ -63,7 +63,9 @@ constexpr int SqliteConnection::DEFAULT_BUSY_TIMEOUT_MS;
|
||||
constexpr int SqliteConnection::BACKUP_PAGES_PRE_STEP; // 1024 * 4 * 12800 == 50m
|
||||
constexpr int SqliteConnection::BACKUP_PRE_WAIT_TIME;
|
||||
constexpr ssize_t SqliteConnection::SLAVE_WAL_SIZE_LIMIT;
|
||||
constexpr ssize_t SqliteConnection::SLAVE_INTEGRITY_CHECK_LIMIT;
|
||||
constexpr uint32_t SqliteConnection::NO_ITER;
|
||||
constexpr uint32_t SqliteConnection::DB_INDEX;
|
||||
constexpr uint32_t SqliteConnection::WAL_INDEX;
|
||||
__attribute__((used))
|
||||
const int32_t SqliteConnection::regCreator_ = Connection::RegisterCreator(DB_SQLITE, SqliteConnection::Create);
|
||||
@ -141,15 +143,15 @@ SqliteConnection::SqliteConnection(const RdbStoreConfig &config, bool isWriteCon
|
||||
backupId_ = TaskExecutor::INVALID_TASK_ID;
|
||||
}
|
||||
|
||||
int SqliteConnection::CreateSlaveConnection(const RdbStoreConfig &config, bool checkSlaveExist)
|
||||
std::pair<int32_t, std::shared_ptr<SqliteConnection>> SqliteConnection::CreateSlaveConnection(
|
||||
const RdbStoreConfig &config, SlaveOpenPolicy slaveOpenPolicy)
|
||||
{
|
||||
if (config.GetHaMode() != HAMode::MAIN_REPLICA && config.GetHaMode() != HAMode::MANUAL_TRIGGER) {
|
||||
return E_OK;
|
||||
}
|
||||
std::pair<int32_t, std::shared_ptr<SqliteConnection>> result = { E_ERROR, nullptr };
|
||||
auto &[errCode, conn] = result;
|
||||
std::map<std::string, DebugInfo> bugInfo = Connection::Collect(config);
|
||||
bool isSlaveExist = access(config.GetPath().c_str(), F_OK) == 0;
|
||||
bool isSlaveLockExist = SqliteUtils::TryAccessSlaveLock(config_.GetPath(), false, false);
|
||||
bool hasFailure = SqliteUtils::TryAccessSlaveLock(config_.GetPath(), false, false, true);
|
||||
bool isSlaveLockExist = SqliteUtils::IsSlaveInterrupted(config_.GetPath());
|
||||
bool hasFailure = SqliteUtils::IsSlaveInvalid(config_.GetPath());
|
||||
bool walOverLimit = bugInfo.find(FILE_SUFFIXES[WAL_INDEX].debug_) != bugInfo.end() &&
|
||||
bugInfo[FILE_SUFFIXES[WAL_INDEX].debug_].size_ > SLAVE_WAL_SIZE_LIMIT;
|
||||
LOG_INFO("slave cfg:[%{public}d,%{public}d,%{public}d,%{public}d,%{public}d,%{public}d,%{public}d]%{public}s "
|
||||
@ -159,34 +161,38 @@ int SqliteConnection::CreateSlaveConnection(const RdbStoreConfig &config, bool c
|
||||
Reportor::FormatBrief(bugInfo, SqliteUtils::Anonymous(config.GetName())).c_str(),
|
||||
Reportor::FormatBrief(Connection::Collect(config_), "master").c_str(), isSlaveExist, isSlaveLockExist,
|
||||
hasFailure, walOverLimit);
|
||||
if (config.GetHaMode() == HAMode::MANUAL_TRIGGER &&
|
||||
(checkSlaveExist && (!isSlaveExist || isSlaveLockExist || hasFailure || walOverLimit))) {
|
||||
if (config.GetHaMode() == HAMode::MANUAL_TRIGGER && (slaveOpenPolicy == SlaveOpenPolicy::OPEN_IF_DB_VALID &&
|
||||
(!isSlaveExist || isSlaveLockExist || hasFailure || walOverLimit))) {
|
||||
if (walOverLimit) {
|
||||
SqliteUtils::TryAccessSlaveLock(config_.GetPath(), false, true, true);
|
||||
SqliteUtils::SetSlaveInvalid(config_.GetPath());
|
||||
}
|
||||
return E_OK;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<SqliteConnection> connection = std::make_shared<SqliteConnection>(config, true);
|
||||
int errCode = connection->InnerOpen(config);
|
||||
errCode = connection->InnerOpen(config);
|
||||
if (errCode != E_OK) {
|
||||
SqliteUtils::TryAccessSlaveLock(config_.GetPath(), false, true, true);
|
||||
SqliteUtils::SetSlaveInvalid(config_.GetPath());
|
||||
if (errCode == E_SQLITE_CORRUPT) {
|
||||
LOG_WARN("slave corrupt, rebuild:%{public}s", SqliteUtils::Anonymous(config.GetPath()).c_str());
|
||||
(void)Delete(config.GetPath());
|
||||
// trigger mode does not require rebuild the slave
|
||||
if (config.GetHaMode() == HAMode::MANUAL_TRIGGER) {
|
||||
return result;
|
||||
}
|
||||
errCode = connection->InnerOpen(config);
|
||||
if (errCode != E_OK) {
|
||||
LOG_ERROR("reopen slave failed:%{public}d", errCode);
|
||||
return errCode;
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
LOG_WARN("open slave failed:%{public}d, %{public}s", errCode,
|
||||
SqliteUtils::Anonymous(config.GetPath()).c_str());
|
||||
return errCode;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
slaveConnection_ = connection;
|
||||
return errCode;
|
||||
conn = connection;
|
||||
return result;
|
||||
}
|
||||
|
||||
RdbStoreConfig SqliteConnection::GetSlaveRdbStoreConfig(const RdbStoreConfig &rdbConfig)
|
||||
@ -451,7 +457,7 @@ std::pair<int, std::shared_ptr<Statement>> SqliteConnection::CreateStatement(
|
||||
errCode = slaveStmt->Prepare(slaveConnection_->dbHandle_, sql);
|
||||
if (errCode != E_OK) {
|
||||
LOG_WARN("prepare slave stmt failed:%{public}d, sql:%{public}s", errCode, sql.c_str());
|
||||
SqliteUtils::TryAccessSlaveLock(config_.GetPath(), false, true, true);
|
||||
SqliteUtils::SetSlaveInvalid(config_.GetPath());
|
||||
return { E_OK, statement };
|
||||
}
|
||||
statement->slave_ = slaveStmt;
|
||||
@ -1229,14 +1235,15 @@ int32_t SqliteConnection::Backup(const std::string &databasePath, const std::vec
|
||||
if (!isAsync) {
|
||||
if (slaveConnection_ == nullptr) {
|
||||
RdbStoreConfig rdbSlaveStoreConfig = GetSlaveRdbStoreConfig(config_);
|
||||
int errCode = CreateSlaveConnection(rdbSlaveStoreConfig, false);
|
||||
auto [errCode, conn] = CreateSlaveConnection(rdbSlaveStoreConfig, SlaveOpenPolicy::FORCE_OPEN);
|
||||
if (errCode != E_OK) {
|
||||
LOG_ERROR("manual slave conn failed:%{public}d", errCode);
|
||||
return errCode;
|
||||
}
|
||||
slaveConnection_ = conn;
|
||||
}
|
||||
return ExchangeSlaverToMaster(false, slaveStatus);
|
||||
return ExchangeSlaverToMaster(false, true, slaveStatus);
|
||||
}
|
||||
|
||||
if (backupId_ == TaskExecutor::INVALID_TASK_ID) {
|
||||
auto pool = TaskExecutor::GetInstance().GetExecutor();
|
||||
if (pool == nullptr) {
|
||||
@ -1248,7 +1255,7 @@ int32_t SqliteConnection::Backup(const std::string &databasePath, const std::vec
|
||||
if (err != E_OK) {
|
||||
return;
|
||||
}
|
||||
err = conn->ExchangeSlaverToMaster(false, slaveStatus);
|
||||
err = conn->ExchangeSlaverToMaster(false, true, slaveStatus);
|
||||
if (err != E_OK) {
|
||||
LOG_WARN("master backup to slave failed:%{public}d", err);
|
||||
}
|
||||
@ -1261,8 +1268,7 @@ int32_t SqliteConnection::Backup(const std::string &databasePath, const std::vec
|
||||
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 ExchangeSlaverToMaster(true, slaveStatus);
|
||||
return ExchangeSlaverToMaster(true, true, slaveStatus);
|
||||
};
|
||||
|
||||
int SqliteConnection::LoadExtension(const RdbStoreConfig &config, sqlite3 *dbHandle)
|
||||
@ -1338,15 +1344,19 @@ int SqliteConnection::SetServiceKey(const RdbStoreConfig &config, int32_t errCod
|
||||
return errCode;
|
||||
}
|
||||
|
||||
int SqliteConnection::ExchangeSlaverToMaster(bool isRestore, SlaveStatus &curStatus)
|
||||
int SqliteConnection::ExchangeSlaverToMaster(bool isRestore, bool verifyDb, SlaveStatus &curStatus)
|
||||
{
|
||||
curStatus = SlaveStatus::BACKING_UP;
|
||||
auto err = ExchangeVerify(isRestore);
|
||||
int err = verifyDb ? ExchangeVerify(isRestore) : E_OK;
|
||||
if (err != E_OK) {
|
||||
curStatus = SlaveStatus::UNDEFINED;
|
||||
return err;
|
||||
}
|
||||
return SqliteNativeBackup(isRestore, curStatus);
|
||||
}
|
||||
|
||||
int SqliteConnection::SqliteNativeBackup(bool isRestore, SlaveStatus &curStatus)
|
||||
{
|
||||
sqlite3 *dbFrom = isRestore ? dbHandle_ : slaveConnection_->dbHandle_;
|
||||
sqlite3 *dbTo = isRestore ? slaveConnection_->dbHandle_ : dbHandle_;
|
||||
sqlite3_backup *pBackup = sqlite3_backup_init(dbFrom, "main", dbTo, "main");
|
||||
@ -1358,7 +1368,6 @@ int SqliteConnection::ExchangeSlaverToMaster(bool isRestore, SlaveStatus &curSta
|
||||
int rc = SQLITE_OK;
|
||||
do {
|
||||
if (!isRestore && curStatus == SlaveStatus::BACKUP_INTERRUPT) {
|
||||
LOG_INFO("backup slave was interrupt!");
|
||||
rc = E_CANCEL;
|
||||
break;
|
||||
}
|
||||
@ -1392,8 +1401,7 @@ int SqliteConnection::ExchangeSlaverToMaster(bool isRestore, SlaveStatus &curSta
|
||||
return E_OK;
|
||||
}
|
||||
curStatus = SlaveStatus::BACKUP_FINISHED;
|
||||
SqliteUtils::TryAccessSlaveLock(config_.GetPath(), true, false);
|
||||
SqliteUtils::TryAccessSlaveLock(config_.GetPath(), true, false, true);
|
||||
SqliteUtils::SetSlaveValid(config_.GetPath());
|
||||
LOG_INFO("backup slave success, isRestore:%{public}d", isRestore);
|
||||
return E_OK;
|
||||
}
|
||||
@ -1424,8 +1432,7 @@ ExchangeStrategy SqliteConnection::GenerateExchangeStrategy(const SlaveStatus &s
|
||||
return ExchangeStrategy::BACKUP;
|
||||
}
|
||||
int64_t sCount = static_cast<int64_t>(sObj);
|
||||
std::string failureFlagFile = config_.GetPath() + "-slaveFailure";
|
||||
if (mCount == sCount && access(failureFlagFile.c_str(), F_OK) != 0) {
|
||||
if ((mCount == sCount) && !SqliteUtils::IsSlaveInvalid(config_.GetPath())) {
|
||||
LOG_INFO("equal, main:%{public}" PRId64 ",slave:%{public}" PRId64, mCount, sCount);
|
||||
return ExchangeStrategy::NOT_HANDLE;
|
||||
}
|
||||
@ -1439,23 +1446,23 @@ ExchangeStrategy SqliteConnection::GenerateExchangeStrategy(const SlaveStatus &s
|
||||
|
||||
int32_t SqliteConnection::Repair(const RdbStoreConfig &config)
|
||||
{
|
||||
if (config.GetHaMode() != MAIN_REPLICA && config.GetHaMode() != MANUAL_TRIGGER) {
|
||||
return E_NOT_SUPPORT;
|
||||
}
|
||||
std::shared_ptr<SqliteConnection> connection = std::make_shared<SqliteConnection>(config, true);
|
||||
if (connection == nullptr) {
|
||||
return E_NOT_SUPPORT;
|
||||
return E_ERROR;
|
||||
}
|
||||
RdbStoreConfig rdbSlaveStoreConfig = connection->GetSlaveRdbStoreConfig(config);
|
||||
int ret = connection->CreateSlaveConnection(rdbSlaveStoreConfig);
|
||||
if (access(rdbSlaveStoreConfig.GetPath().c_str(), F_OK) != 0) {
|
||||
return E_NOT_SUPPORT;
|
||||
}
|
||||
auto [ret, conn] = connection->CreateSlaveConnection(rdbSlaveStoreConfig, SlaveOpenPolicy::FORCE_OPEN);
|
||||
if (ret != E_OK) {
|
||||
return ret;
|
||||
}
|
||||
ret = connection->IsRepairable();
|
||||
connection->slaveConnection_ = conn;
|
||||
ret = connection->VeritySlaveIntegrity();
|
||||
if (ret != E_OK) {
|
||||
return ret;
|
||||
}
|
||||
LOG_WARN("begin repair main:%{public}s", SqliteUtils::Anonymous(config.GetPath()).c_str());
|
||||
(void)SqliteConnection::Delete(config.GetPath());
|
||||
ret = connection->InnerOpen(config);
|
||||
if (ret != E_OK) {
|
||||
@ -1463,78 +1470,46 @@ int32_t SqliteConnection::Repair(const RdbStoreConfig &config)
|
||||
return ret;
|
||||
}
|
||||
SlaveStatus curStatus;
|
||||
ret = connection->ExchangeSlaverToMaster(true, curStatus);
|
||||
ret = connection->ExchangeSlaverToMaster(true, false, curStatus);
|
||||
if (ret != E_OK) {
|
||||
LOG_ERROR("repair failed, [%{public}s]->[%{public}s], err:%{public}d", rdbSlaveStoreConfig.GetName().c_str(),
|
||||
SqliteUtils::Anonymous(config.GetName()).c_str(), ret);
|
||||
} else {
|
||||
LOG_INFO("repair main success:%{public}s", SqliteUtils::Anonymous(config.GetPath()).c_str());
|
||||
}
|
||||
connection->slaveConnection_ = nullptr;
|
||||
connection = nullptr;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SqliteConnection::IsRepairable()
|
||||
{
|
||||
if (slaveConnection_ == nullptr || slaveConnection_->dbHandle_ == nullptr) {
|
||||
return E_STORE_CLOSED;
|
||||
}
|
||||
if (SqliteUtils::TryAccessSlaveLock(config_.GetPath(), false, false, false)) {
|
||||
LOG_ERROR("unavailable slave, %{public}s", config_.GetName().c_str());
|
||||
return E_SQLITE_CORRUPT;
|
||||
}
|
||||
std::string querySql = "SELECT COUNT(*) FROM sqlite_master WHERE type='table';";
|
||||
auto [qRet, qObj] = slaveConnection_->ExecuteForValue(querySql);
|
||||
if (qRet == E_SQLITE_CORRUPT || (static_cast<int64_t>(qObj) == 0L)) {
|
||||
LOG_INFO("cancel repair, ret:%{public}d", qRet);
|
||||
return E_SQLITE_CORRUPT;
|
||||
}
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
int SqliteConnection::ExchangeVerify(bool isRestore)
|
||||
{
|
||||
if (dbHandle_ == nullptr || slaveConnection_ == nullptr || slaveConnection_->dbHandle_ == nullptr) {
|
||||
LOG_WARN("slave conn invalid");
|
||||
return E_STORE_CLOSED;
|
||||
if (isRestore) {
|
||||
int err = VeritySlaveIntegrity();
|
||||
if (err != E_OK) {
|
||||
return err;
|
||||
}
|
||||
if (IsDbVersionBelowSlave()) {
|
||||
return E_OK;
|
||||
}
|
||||
if (SqliteUtils::IsSlaveInvalid(config_.GetPath())) {
|
||||
LOG_ERROR("incomplete slave, %{public}s", config_.GetName().c_str());
|
||||
return E_SQLITE_CORRUPT;
|
||||
}
|
||||
return E_OK;
|
||||
}
|
||||
if (slaveConnection_ == nullptr) {
|
||||
return E_ALREADY_CLOSED;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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, ret:%{public}s, cRet:%{public}d",
|
||||
static_cast<std::string>(cObj).c_str(), cRet);
|
||||
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_NOT_SUPPORTED;
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
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, %{public}s, ret:%{public}s, qRet:%{public}d",
|
||||
SqliteUtils::Anonymous(config_.GetName()).c_str(), static_cast<std::string>(cObj).c_str(), cRet);
|
||||
return E_SQLITE_CORRUPT;
|
||||
}
|
||||
SqliteUtils::SetSlaveInterrupted(config_.GetPath());
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
@ -1555,10 +1530,84 @@ std::pair<int32_t, std::shared_ptr<SqliteConnection>> SqliteConnection::InnerCre
|
||||
return result;
|
||||
}
|
||||
conn = connection;
|
||||
if (isWrite) {
|
||||
(void)connection->CreateSlaveConnection(slaveCfg, isWrite);
|
||||
if (isWrite && config.GetHaMode() != HAMode::SINGLE) {
|
||||
auto [err, slaveConn] = connection->CreateSlaveConnection(slaveCfg, SlaveOpenPolicy::OPEN_IF_DB_VALID);
|
||||
if (err == E_OK) {
|
||||
conn->slaveConnection_ = slaveConn;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int SqliteConnection::VeritySlaveIntegrity()
|
||||
{
|
||||
if (slaveConnection_ == nullptr) {
|
||||
return E_ALREADY_CLOSED;
|
||||
}
|
||||
|
||||
RdbStoreConfig slaveCfg = GetSlaveRdbStoreConfig(config_);
|
||||
std::map<std::string, DebugInfo> bugInfo = Connection::Collect(slaveCfg);
|
||||
LOG_INFO("%{public}s", Reportor::FormatBrief(bugInfo, SqliteUtils::Anonymous(slaveCfg.GetName())).c_str());
|
||||
|
||||
if (SqliteUtils::IsSlaveInterrupted(config_.GetPath())) {
|
||||
return E_SQLITE_CORRUPT;
|
||||
}
|
||||
|
||||
std::string sql = "SELECT COUNT(*) FROM sqlite_master WHERE type='table';";
|
||||
auto [err, obj] = slaveConnection_->ExecuteForValue(sql);
|
||||
auto val = std::get_if<int64_t>(&obj.value);
|
||||
if (err == E_SQLITE_CORRUPT || (val != nullptr && static_cast<int64_t>(*val) == 0L)) {
|
||||
LOG_ERROR("slave %{public}d", err);
|
||||
return E_SQLITE_CORRUPT;
|
||||
}
|
||||
|
||||
int64_t mCount = 0L;
|
||||
if (dbHandle_ != nullptr) {
|
||||
std::tie(err, obj) = ExecuteForValue(sql);
|
||||
val = std::get_if<int64_t>(&obj.value);
|
||||
if (val != nullptr) {
|
||||
mCount = static_cast<int64_t>(*val);
|
||||
}
|
||||
}
|
||||
bool isSlaveDbOverLimit = bugInfo.find(FILE_SUFFIXES[DB_INDEX].debug_) != bugInfo.end() &&
|
||||
bugInfo[FILE_SUFFIXES[DB_INDEX].debug_].size_ > SLAVE_INTEGRITY_CHECK_LIMIT;
|
||||
if (isSlaveDbOverLimit && mCount == 0L) {
|
||||
return SqliteUtils::IsSlaveInvalid(config_.GetPath()) ? E_SQLITE_CORRUPT : E_OK;
|
||||
}
|
||||
|
||||
std::tie(err, obj) = slaveConnection_->ExecuteForValue(INTEGRITIES[2]); // 2 is integrity_check
|
||||
if (err == E_OK && (static_cast<std::string>(obj) != "ok")) {
|
||||
LOG_ERROR("slave corrupt, ret:%{public}s, cRet:%{public}d, %{public}d",
|
||||
static_cast<std::string>(obj).c_str(), err, errno);
|
||||
SqliteUtils::SetSlaveInvalid(config_.GetPath());
|
||||
return E_SQLITE_CORRUPT;
|
||||
}
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
bool SqliteConnection::IsDbVersionBelowSlave()
|
||||
{
|
||||
if (slaveConnection_ == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto[cRet, cObj] = ExecuteForValue("SELECT COUNT(*) FROM sqlite_master WHERE type='table';");
|
||||
auto cVal = std::get_if<int64_t>(&cObj.value);
|
||||
if (cRet == E_SQLITE_CORRUPT || (cVal != nullptr && (static_cast<int64_t>(*cVal) == 0L))) {
|
||||
LOG_INFO("main empty, %{public}d, %{public}s", cRet, config_.GetName().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
std::tie(cRet, cObj) = ExecuteForValue(GlobalExpr::PRAGMA_VERSION);
|
||||
if (cVal == nullptr || (cVal != nullptr && static_cast<int64_t>(*cVal) == 0L)) {
|
||||
std::tie(cRet, cObj) = slaveConnection_->ExecuteForValue(GlobalExpr::PRAGMA_VERSION);
|
||||
cVal = std::get_if<int64_t>(&cObj.value);
|
||||
if (cVal != nullptr && static_cast<int64_t>(*cVal) > 0L) {
|
||||
LOG_INFO("version, %{public}" PRId64, static_cast<int64_t>(*cVal));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace NativeRdb
|
||||
} // namespace OHOS
|
@ -205,7 +205,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);
|
||||
SqliteUtils::SetSlaveInvalid(config_->GetPath());
|
||||
}
|
||||
}
|
||||
return E_OK;
|
||||
@ -246,7 +246,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);
|
||||
SqliteUtils::SetSlaveInvalid(config_->GetPath());
|
||||
}
|
||||
}
|
||||
return E_OK;
|
||||
@ -384,8 +384,9 @@ int32_t SqliteStatement::Execute(const std::vector<std::reference_wrapper<ValueO
|
||||
if (slave_) {
|
||||
int errCode = slave_->Execute(args);
|
||||
if (errCode != E_OK) {
|
||||
LOG_ERROR("slave execute error:%{public}d", errCode);
|
||||
SqliteUtils::TryAccessSlaveLock(config_->GetPath(), false, true, true);
|
||||
LOG_ERROR("slave execute error:%{public}d, sql is %{public}s, errno %{public}d",
|
||||
errCode, sql_.c_str(), errno);
|
||||
SqliteUtils::SetSlaveInvalid(config_->GetPath());
|
||||
}
|
||||
}
|
||||
return E_OK;
|
||||
|
@ -260,36 +260,6 @@ 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 isSlaveFailure)
|
||||
{
|
||||
std::string lockFile = isSlaveFailure ? dbPath + "-slaveFailure" : dbPath + "-syncInterrupt";
|
||||
if (isDelete) {
|
||||
if (std::remove(lockFile.c_str()) != 0) {
|
||||
return false;
|
||||
} else {
|
||||
LOG_INFO("remove %{public}s", Anonymous(lockFile).c_str());
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (access(lockFile.c_str(), F_OK) == 0) {
|
||||
return true;
|
||||
}
|
||||
if (needCreate) {
|
||||
std::ofstream src(lockFile.c_str(), std::ios::binary);
|
||||
if (src.is_open()) {
|
||||
LOG_INFO("open %{public}s", Anonymous(lockFile).c_str());
|
||||
src.close();
|
||||
return true;
|
||||
} else {
|
||||
LOG_WARN("open errno %{public}d %{public}s", errno, Anonymous(lockFile).c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string SqliteUtils::GetSlavePath(const std::string& name)
|
||||
{
|
||||
std::string suffix(".db");
|
||||
@ -343,5 +313,40 @@ const char *SqliteUtils::EncryptAlgoDescription(int32_t encryptAlgo)
|
||||
}
|
||||
}
|
||||
|
||||
int SqliteUtils::SetSlaveInvalid(const std::string &dbPath)
|
||||
{
|
||||
std::ofstream src((dbPath + SLAVE_FAILURE).c_str(), std::ios::binary);
|
||||
if (src.is_open()) {
|
||||
src.close();
|
||||
return E_OK;
|
||||
}
|
||||
return E_ERROR;
|
||||
}
|
||||
|
||||
int SqliteUtils::SetSlaveInterrupted(const std::string &dbPath)
|
||||
{
|
||||
std::ofstream src((dbPath + SLAVE_INTERRUPT).c_str(), std::ios::binary);
|
||||
if (src.is_open()) {
|
||||
src.close();
|
||||
return E_OK;
|
||||
}
|
||||
return E_ERROR;
|
||||
}
|
||||
|
||||
bool SqliteUtils::IsSlaveInvalid(const std::string &dbPath)
|
||||
{
|
||||
return access((dbPath + SLAVE_FAILURE).c_str(), F_OK) == 0;
|
||||
}
|
||||
|
||||
bool SqliteUtils::IsSlaveInterrupted(const std::string &dbPath)
|
||||
{
|
||||
return access((dbPath + SLAVE_INTERRUPT).c_str(), F_OK) == 0;
|
||||
}
|
||||
|
||||
void SqliteUtils::SetSlaveValid(const std::string &dbPath)
|
||||
{
|
||||
std::remove((dbPath + SLAVE_INTERRUPT).c_str());
|
||||
std::remove((dbPath + SLAVE_FAILURE).c_str());
|
||||
}
|
||||
} // namespace NativeRdb
|
||||
} // namespace OHOS
|
||||
|
@ -676,8 +676,6 @@ public:
|
||||
|
||||
void SetHaMode(int32_t haMode);
|
||||
|
||||
void SetNewEncryptKey(const std::vector<uint8_t> newEncryptKey);
|
||||
|
||||
void SetScalarFunctions(const std::map<std::string, ScalarFunctionInfo> functions);
|
||||
|
||||
void SetCryptoParam(CryptoParam cryptoParam);
|
||||
|
@ -256,7 +256,6 @@ public:
|
||||
PromiseInfo GetPromiseInfo() const;
|
||||
void SetPromiseInfo(PromiseInfo promiseInfo);
|
||||
void SetHaMode(int32_t haMode);
|
||||
void SetNewEncryptKey(const std::vector<uint8_t> newEncryptKey);
|
||||
void SetScalarFunctions(const std::map<std::string, ScalarFunctionInfo> functions);
|
||||
void SetCryptoParam(CryptoParam cryptoParam);
|
||||
CryptoParam GetCryptoParam() const;
|
||||
|
@ -66,8 +66,8 @@ public:
|
||||
};
|
||||
};
|
||||
|
||||
const std::string RdbDoubleWriteTest::DATABASE_NAME = RDB_TEST_PATH + "insert_test.db";
|
||||
const std::string RdbDoubleWriteTest::SLAVE_DATABASE_NAME = RDB_TEST_PATH + "insert_test_slave.db";
|
||||
const std::string RdbDoubleWriteTest::DATABASE_NAME = RDB_TEST_PATH + "dual_write_test.db";
|
||||
const std::string RdbDoubleWriteTest::SLAVE_DATABASE_NAME = RDB_TEST_PATH + "dual_write_test_slave.db";
|
||||
std::shared_ptr<RdbStore> RdbDoubleWriteTest::store = nullptr;
|
||||
std::shared_ptr<RdbStore> RdbDoubleWriteTest::slaveStore = nullptr;
|
||||
std::shared_ptr<RdbStore> RdbDoubleWriteTest::store3 = nullptr;
|
||||
@ -1078,4 +1078,43 @@ HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_032, TestSize.Level1)
|
||||
RdbStoreConfig config(RdbDoubleWriteTest::DATABASE_NAME);
|
||||
RdbHelper::DeleteRdbStore(config);
|
||||
EXPECT_NE(access(RdbDoubleWriteTest::SLAVE_DATABASE_NAME.c_str(), F_OK), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: RdbStore_DoubleWrite_033
|
||||
* @tc.desc: open db, write, close, corrupt, open SINGLE db, check
|
||||
* @tc.type: FUNC
|
||||
*/
|
||||
HWTEST_F(RdbDoubleWriteTest, RdbStore_DoubleWrite_033, TestSize.Level1)
|
||||
{
|
||||
InitDb();
|
||||
int64_t id = 10;
|
||||
int count = 100;
|
||||
Insert(id, count);
|
||||
|
||||
store = nullptr;
|
||||
slaveStore = nullptr;
|
||||
|
||||
std::fstream file(DATABASE_NAME, std::ios::in | std::ios::out | std::ios::binary);
|
||||
ASSERT_TRUE(file.is_open() == true);
|
||||
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();
|
||||
|
||||
int errCode = E_OK;
|
||||
RdbStoreConfig config(RdbDoubleWriteTest::DATABASE_NAME);
|
||||
config.SetHaMode(HAMode::SINGLE);
|
||||
DoubleWriteTestOpenCallback helper;
|
||||
store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
|
||||
EXPECT_EQ(errCode, E_OK);
|
||||
ASSERT_NE(store, nullptr);
|
||||
|
||||
RebuiltType rebuiltType;
|
||||
store->GetRebuilt(rebuiltType);
|
||||
EXPECT_EQ(rebuiltType, RebuiltType::REPAIRED);
|
||||
|
||||
RdbDoubleWriteTest::CheckNumber(store, count);
|
||||
}
|
Loading…
Reference in New Issue
Block a user