salve integrity check size limit

Signed-off-by: lobty <butaoyu@huawei.com>
This commit is contained in:
lobty 2024-10-31 15:20:24 +08:00
parent 7ddaaa15e2
commit d89c1b75d0
2 changed files with 91 additions and 50 deletions

View File

@ -123,7 +123,8 @@ private:
int ExchangeSlaverToMaster(bool isRestore, bool verifyDb, SlaveStatus &status);
int ExchangeVerify(bool isRestore);
int SqliteNativeBackup(bool isRestore, SlaveStatus &curStatus);
int IsRestoreFeasible(bool ignoreDataDiff);
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[] = {
@ -141,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_;

View File

@ -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);
@ -1452,12 +1454,12 @@ int32_t SqliteConnection::Repair(const RdbStoreConfig &config)
if (access(rdbSlaveStoreConfig.GetPath().c_str(), F_OK) != 0) {
return E_NOT_SUPPORT;
}
auto [ret, conn] = connection->CreateSlaveConnection(rdbSlaveStoreConfig, SlaveOpenPolicy::OPEN_IF_DB_VALID);
auto [ret, conn] = connection->CreateSlaveConnection(rdbSlaveStoreConfig, SlaveOpenPolicy::FORCE_OPEN);
if (ret != E_OK) {
return ret;
}
connection->slaveConnection_ = conn;
ret = connection->IsRestoreFeasible(true);
ret = connection->VeritySlaveIntegrity();
if (ret != E_OK) {
return ret;
}
@ -1478,56 +1480,21 @@ int32_t SqliteConnection::Repair(const RdbStoreConfig &config)
return ret;
}
int32_t SqliteConnection::IsRestoreFeasible(bool ignoreDataDiff)
{
if (slaveConnection_ == nullptr) {
return E_ALREADY_CLOSED;
}
if (SqliteUtils::IsSlaveInterrupted(config_.GetPath())) {
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;
}
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;
}
if (ignoreDataDiff) {
return E_OK;
}
std::tie(cRet, cObj) = ExecuteForValue(querySql);
auto cVal = std::get_if<int64_t>(&cObj.value);
if (cVal != nullptr && (static_cast<int64_t>(*cVal) == 0L)) {
LOG_INFO("main empty, need restore, %{public}s", config_.GetName().c_str());
return E_OK;
}
std::tie(cRet, cObj) = ExecuteForValue(GlobalExpr::PRAGMA_VERSION);
cVal = std::get_if<int64_t>(&cObj.value);
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) {
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;
}
int SqliteConnection::ExchangeVerify(bool isRestore)
{
if (isRestore) {
return IsRestoreFeasible(false);
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;
@ -1571,5 +1538,76 @@ std::pair<int32_t, std::shared_ptr<SqliteConnection>> SqliteConnection::InnerCre
}
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