diff --git a/frameworks/libs/distributeddb/interfaces/src/relational/relational_sync_able_storage.h b/frameworks/libs/distributeddb/interfaces/src/relational/relational_sync_able_storage.h index b6139fd272fcaf805db3680402318c1f52a89120..34c6e04fc9beabc434ded9ae1b2fd8850e316d80 100644 --- a/frameworks/libs/distributeddb/interfaces/src/relational/relational_sync_able_storage.h +++ b/frameworks/libs/distributeddb/interfaces/src/relational/relational_sync_able_storage.h @@ -275,6 +275,8 @@ public: void SetProperty(const Property &property); Property GetProperty() const override; + + int ConvertLogToLocal(const std::string &tableName, const std::vector &gids) override; protected: int FillReferenceData(CloudSyncData &syncData); diff --git a/frameworks/libs/distributeddb/storage/include/cloud/cloud_storage_utils.h b/frameworks/libs/distributeddb/storage/include/cloud/cloud_storage_utils.h index addeeb3cb2279a3967f69a71bc910d93a1fb3442..0dd79c9e78ccdccece1bf39de430348f586f6d1d 100644 --- a/frameworks/libs/distributeddb/storage/include/cloud/cloud_storage_utils.h +++ b/frameworks/libs/distributeddb/storage/include/cloud/cloud_storage_utils.h @@ -212,6 +212,8 @@ public: static void SaveChangedDataByType(const DataValue &dataValue, Type &value); + static int ConvertLogToLocal(sqlite3 *dbHandle, + const std::string &tableName, const std::vector &gids); private: static int IdentifyCloudTypeInner(CloudSyncData &cloudSyncData, VBucket &data, VBucket &log, VBucket &flags); diff --git a/frameworks/libs/distributeddb/storage/include/icloud_sync_storage_interface.h b/frameworks/libs/distributeddb/storage/include/icloud_sync_storage_interface.h index 531b0dcaa16005a721901d3892b01e52c413ae5b..aab3d6687a23ea15e6a8af3b88a9e33b568d24ee 100644 --- a/frameworks/libs/distributeddb/storage/include/icloud_sync_storage_interface.h +++ b/frameworks/libs/distributeddb/storage/include/icloud_sync_storage_interface.h @@ -321,6 +321,11 @@ public: { return false; } + + virtual int ConvertLogToLocal(const std::string &tableName, const std::vector &gids) + { + return E_OK; + } }; } diff --git a/frameworks/libs/distributeddb/storage/include/storage_proxy.h b/frameworks/libs/distributeddb/storage/include/storage_proxy.h index 172872f902511cb8a043c076eef33a82735cc235..01f6f6d2b841817b1049f8f14a3647a4456561c3 100644 --- a/frameworks/libs/distributeddb/storage/include/storage_proxy.h +++ b/frameworks/libs/distributeddb/storage/include/storage_proxy.h @@ -192,6 +192,8 @@ public: bool GetTransactionExeFlag(); Timestamp EraseNanoTime(Timestamp localTime); + + void FilterDownloadRecordNotFound(const std::string &tableName, DownloadData &downloadData); protected: void Init(); private: diff --git a/frameworks/libs/distributeddb/storage/src/cloud/cloud_storage_utils.cpp b/frameworks/libs/distributeddb/storage/src/cloud/cloud_storage_utils.cpp index d3dacdd31da583b48101f11c805b279a3bdf6a16..e6fe5fb89bda4d07d03e9ad9bc2ec93ec6e9daff 100644 --- a/frameworks/libs/distributeddb/storage/src/cloud/cloud_storage_utils.cpp +++ b/frameworks/libs/distributeddb/storage/src/cloud/cloud_storage_utils.cpp @@ -20,6 +20,7 @@ #include "cloud/cloud_db_constant.h" #include "cloud/cloud_db_types.h" #include "db_common.h" +#include "res_finalizer.h" #include "runtime_context.h" namespace DistributedDB { @@ -1513,4 +1514,44 @@ void CloudStorageUtils::SaveChangedDataByType(const DataValue &dataValue, Type & return; } } + +int CloudStorageUtils::ConvertLogToLocal(sqlite3 *dbHandle, const std::string &tableName, + const std::vector &gids) +{ + std::string sql = "UPDATE " + DBCommon::GetLogTableName(tableName) + + " SET cloud_gid = '', flag = flag | 0x02 WHERE cloud_gid IN ("; + for (size_t i = 0; i < gids.size(); i++) { + sql += "?,"; + } + sql.pop_back(); + sql += ");"; + sqlite3_stmt *stmt = nullptr; + int errCode = SQLiteUtils::GetStatement(dbHandle, sql, stmt); + if (errCode != E_OK) { + LOGE("[CloudStorageUtils][ConvertLogToLocal]Get stmt failed: %d, tableName: %s, length: %zu", + errCode, DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size()); + return errCode; + } + ResFinalizer finalizer([&stmt] { + int ret = E_OK; + SQLiteUtils::ResetStatement(stmt, true, ret); + }); + int index = 0; + for (const auto &gid : gids) { + index++; + errCode = SQLiteUtils::BindTextToStatement(stmt, index, gid); + if (errCode != E_OK) { + return errCode; + } + } + errCode = SQLiteUtils::StepWithRetry(stmt); + if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { + LOGE("[CloudStorageUtils][ConvertLogToLocal]step failed: %d, tableName: %s, length: %zu", + errCode, DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size()); + return errCode; + } + auto count = sqlite3_changes64(dbHandle); + LOGI("[CloudStorageUtils][ConvertLogToLocal] cnt:%zu, %" PRIu64, gids.size(), count); + return E_OK; +} } diff --git a/frameworks/libs/distributeddb/storage/src/relational/relational_sync_able_storage_extend.cpp b/frameworks/libs/distributeddb/storage/src/relational/relational_sync_able_storage_extend.cpp index 18e54506b3d4e41d8607006533d436c809afbe11..dbe0f5c1d6276194bb33003b8ce75a969a5f340d 100644 --- a/frameworks/libs/distributeddb/storage/src/relational/relational_sync_able_storage_extend.cpp +++ b/frameworks/libs/distributeddb/storage/src/relational/relational_sync_able_storage_extend.cpp @@ -646,5 +646,19 @@ Property RelationalSyncAbleStorage::GetProperty() const std::lock_guard autoLock(propertyMutex_); return property_; } + +int RelationalSyncAbleStorage::ConvertLogToLocal(const std::string &tableName, const std::vector &gids) +{ + int errCode = E_OK; + auto *handle = GetHandle(true, errCode); + if (handle == nullptr) { + LOGE("[RelationalSyncAbleStorage] Get handle failed when clear cloud gid: %d", errCode); + return errCode; + } + + errCode = handle->ConvertLogToLocal(tableName, gids); + ReleaseHandle(handle); + return errCode; +} } #endif diff --git a/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_storage_executor.cpp b/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_storage_executor.cpp index fd2d12315ea2edc3b3242df018fb5e49f50c28a8..1a49c5d4e5b7028b376fa3286e5427d8c5d413ae 100644 --- a/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_storage_executor.cpp +++ b/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_storage_executor.cpp @@ -1979,5 +1979,11 @@ void SQLiteSingleVerRelationalStorageExecutor::SetTableMode(DistributedTableMode { mode_ = mode; } + +int SQLiteSingleVerRelationalStorageExecutor::ConvertLogToLocal(const std::string &tableName, + const std::vector &gids) +{ + return CloudStorageUtils::ConvertLogToLocal(dbHandle_, tableName, gids); +} } // namespace DistributedDB #endif diff --git a/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_storage_executor.h b/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_storage_executor.h index 05f471e04feb41bdb1a1507de9fa8d7a0afafa59..c506a3b18622e33cd395abb12c1e22ffb9ded6fe 100644 --- a/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_storage_executor.h +++ b/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_storage_executor.h @@ -276,6 +276,8 @@ public: int IsTableOnceDropped(const std::string &tableName, bool &onceDropped); void RecoverNullExtendLog(const TrackerSchema &trackerSchema, const TrackerTable &table); + + int ConvertLogToLocal(const std::string &tableName, const std::vector &gids); private: int UpdateHashKeyWithOutPk(DistributedTableMode mode, const TableInfo &tableInfo, TableSyncType syncType, const std::string &localIdentity); diff --git a/frameworks/libs/distributeddb/storage/src/storage_proxy.cpp b/frameworks/libs/distributeddb/storage/src/storage_proxy.cpp index 26d61ec02c760fdc87604f19959fa817cd6c7eb3..b5287c8161c28fe9b3ce9717ace1347ba62fe14e 100644 --- a/frameworks/libs/distributeddb/storage/src/storage_proxy.cpp +++ b/frameworks/libs/distributeddb/storage/src/storage_proxy.cpp @@ -846,4 +846,33 @@ bool StorageProxy::GetTransactionExeFlag() std::shared_lock readLock(storeMutex_); return transactionExeFlag_.load(); } + +void StorageProxy::FilterDownloadRecordNotFound(const std::string &tableName, DownloadData &downloadData) +{ + std::vector gids; + for (auto data = downloadData.data.begin(); data != downloadData.data.end();) { + if (!DBCommon::IsCloudRecordNotFound(*data)) { + ++data; + continue; + } + std::string gid; + (void)CloudStorageUtils::GetValueFromVBucket(CloudDbConstant::GID_FIELD, *data, gid); + if (!gid.empty()) { + gids.push_back(gid); + data = downloadData.data.erase(data); + } else { + ++data; + } + } + if (gids.empty()) { + return; + } + std::shared_lock readLock(storeMutex_); + if (store_ == nullptr) { + LOGW("[FilterDownloadRecordNotFound] store is null"); + return; + } + LOGW("Download data from cloud contains record not found."); + (void)store_->ConvertLogToLocal(tableName, gids); +} } \ No newline at end of file diff --git a/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer.cpp b/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer.cpp index decd5e8462df551af67f9b6cdd25968c5cb6854a..318355948ae0cd5c17d030556fe4bdbee826a8e9 100644 --- a/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer.cpp +++ b/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer.cpp @@ -1426,6 +1426,7 @@ int CloudSyncer::QueryCloudData(TaskId taskId, const std::string &tableName, std return ret; } ret = cloudDB_.Query(tableName, extend, downloadData.data); + storageProxy_->FilterDownloadRecordNotFound(tableName, downloadData); if ((ret == E_OK || ret == -E_QUERY_END) && downloadData.data.empty()) { if (extend[CloudDbConstant::CURSOR_FIELD].index() != TYPE_INDEX) { LOGE("[CloudSyncer] cursor type is not valid=%d", extend[CloudDbConstant::CURSOR_FIELD].index()); diff --git a/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_lock_test.cpp b/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_lock_test.cpp index 5296001276844b6281bc2386c2cfee8ef03c5f48..af9b119bfee70d0ca6cbe8157ec3ead67825b9a3 100644 --- a/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_lock_test.cpp +++ b/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_lock_test.cpp @@ -128,6 +128,7 @@ protected: void CheckAssetStatusNormal(); void UpdateCloudAssets(Asset &asset, Assets &assets, const std::string &version); void CheckUploadAbnormal(OpType opType, int64_t expCnt, bool isCompensated = false); + void CheckRecordNotFound(bool isLocalWin); sqlite3 *db = nullptr; VirtualCommunicatorAggregator *communicatorAggregator_ = nullptr; }; @@ -457,6 +458,65 @@ void DistributedDBCloudSyncerLockTest::CheckUploadAbnormal(OpType opType, int64_ reinterpret_cast(expCnt), nullptr), SQLITE_OK); } +void DistributedDBCloudSyncerLockTest::CheckRecordNotFound(bool isLocalWin) +{ + /** + * @tc.steps:step1. insert cloud and sync + * @tc.expected: step1. return ok. + */ + int cloudCount = 10; + InsertCloudDBData(0, cloudCount, 0, ASSETS_TABLE_NAME); + CloudSyncOption option = PrepareOption(Query::Select().FromTable({ ASSETS_TABLE_NAME }), LockAction::INSERT); + CallSync(option); + + /** + * @tc.steps:step2. update local data status to unlocking + * @tc.expected: step2. return ok. + */ + std::string sql = "UPDATE " + DBCommon::GetLogTableName(ASSETS_TABLE_NAME) + " SET status = 2"; + EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK); + if (isLocalWin) { + sql = "UPDATE " + ASSETS_TABLE_NAME + " SET name = id"; + EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK); + } else { + UpdateCloudDBData(0, cloudCount, 0, 0, ASSETS_TABLE_NAME); + CallSync(option); + } + sql = "UPDATE " + DBCommon::GetLogTableName(ASSETS_TABLE_NAME) + " SET status = 1"; + EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK); + + /** + * @tc.steps:step3. Compensated Sync and fork query contains not found + * @tc.expected: step3. return ok. + */ + int callCnt = 0; + g_virtualCloudDb->ForkAfterQueryResult([&](VBucket &extend, std::vector &data) { + callCnt++; + size_t expCnt = 10u; + if (callCnt == 1) { + EXPECT_EQ(data.size(), expCnt); + if (data.size() < expCnt) { + return DBStatus::CLOUD_ERROR; + } + int errIndex = 4; + data[errIndex].insert_or_assign(CloudDbConstant::ERROR_FIELD, + static_cast(DBStatus::CLOUD_RECORD_NOT_FOUND)); + } + return DBStatus::QUERY_END; + }); + option.compensatedSyncOnly = true; + CallSync(option); + + /** + * @tc.steps:step4. Check sync success + * @tc.expected: step4. return ok. + */ + sql = "select count(*) from " + DBCommon::GetLogTableName(ASSETS_TABLE_NAME) + " where status = 0;"; + EXPECT_EQ(sqlite3_exec(db, sql.c_str(), CloudDBSyncUtilsTest::QueryCountCallback, + reinterpret_cast(cloudCount), nullptr), SQLITE_OK); + g_virtualCloudDb->ForkAfterQueryResult(nullptr); +} + /** * @tc.name: RDBUnlockCloudSync001 * @tc.desc: Test sync with no lock @@ -1547,5 +1607,147 @@ HWTEST_F(DistributedDBCloudSyncerLockTest, TaskIdTest001, TestSize.Level1) CallSync(option); g_virtualCloudDb->ForkQuery(nullptr); } + +/** + * @tc.name: RecordNotFoundTest001 + * @tc.desc: Test query return not found when the cloud data is relatively new + * @tc.type: FUNC + * @tc.require: + * @tc.author: bty + */ +HWTEST_F(DistributedDBCloudSyncerLockTest, RecordNotFoundTest001, TestSize.Level1) +{ + EXPECT_NO_FATAL_FAILURE(CheckRecordNotFound(false)); +} + +/** + * @tc.name: RecordNotFoundTest002 + * @tc.desc: Test query return not found when the local data is relatively new + * @tc.type: FUNC + * @tc.require: + * @tc.author: bty + */ +HWTEST_F(DistributedDBCloudSyncerLockTest, RecordNotFoundTest002, TestSize.Level1) +{ + EXPECT_NO_FATAL_FAILURE(CheckRecordNotFound(true)); +} + +/** + * @tc.name: RecordNotFoundTest003 + * @tc.desc: Test query return not found for all data + * @tc.type: FUNC + * @tc.require: + * @tc.author: bty + */ +HWTEST_F(DistributedDBCloudSyncerLockTest, RecordNotFoundTest003, TestSize.Level1) +{ + /** + * @tc.steps:step1. insert cloud and sync + * @tc.expected: step1. return ok. + */ + int cloudCount = 10; + InsertCloudDBData(0, cloudCount, 0, ASSETS_TABLE_NAME); + CloudSyncOption option = PrepareOption(Query::Select().FromTable({ ASSETS_TABLE_NAME }), LockAction::INSERT); + CallSync(option); + + /** + * @tc.steps:step2. update local data status to unlocking + * @tc.expected: step2. return ok. + */ + std::string sql = "UPDATE " + DBCommon::GetLogTableName(ASSETS_TABLE_NAME) + " SET status = 2"; + EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK); + UpdateCloudDBData(0, cloudCount, 0, 0, ASSETS_TABLE_NAME); + CallSync(option); + sql = "UPDATE " + DBCommon::GetLogTableName(ASSETS_TABLE_NAME) + " SET status = 1"; + EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK); + + /** + * @tc.steps:step3. Compensated Sync and fork query contains not found + * @tc.expected: step3. return ok. + */ + int callCnt = 0; + g_virtualCloudDb->ForkAfterQueryResult([&](VBucket &extend, std::vector &data) { + callCnt++; + if (callCnt == 1) { + for (size_t errIndex = 0; errIndex < data.size(); errIndex++) { + data[errIndex].insert_or_assign(CloudDbConstant::ERROR_FIELD, + static_cast(DBStatus::CLOUD_RECORD_NOT_FOUND)); + } + } + return DBStatus::QUERY_END; + }); + int uploadCnt = 0; + g_virtualCloudDb->ForkUpload([&uploadCnt](const std::string &tableName, VBucket &extend) { + uploadCnt++; + }); + option.compensatedSyncOnly = true; + CallSync(option); + g_virtualCloudDb->ForkAfterQueryResult(nullptr); + g_virtualCloudDb->ForkUpload(nullptr); + EXPECT_EQ(uploadCnt, cloudCount); +} + +/** + * @tc.name: RecordNotFoundTest004 + * @tc.desc: Test query return error when record contanis not found + * @tc.type: FUNC + * @tc.require: + * @tc.author: bty + */ +HWTEST_F(DistributedDBCloudSyncerLockTest, RecordNotFoundTest004, TestSize.Level1) +{ + /** + * @tc.steps:step1. insert cloud and sync + * @tc.expected: step1. return ok. + */ + int cloudCount = 10; + InsertCloudDBData(0, cloudCount, 0, ASSETS_TABLE_NAME); + CloudSyncOption option = PrepareOption(Query::Select().FromTable({ ASSETS_TABLE_NAME }), LockAction::INSERT); + CallSync(option); + + /** + * @tc.steps:step2. update local data status to unlocking + * @tc.expected: step2. return ok. + */ + std::string sql = "UPDATE " + DBCommon::GetLogTableName(ASSETS_TABLE_NAME) + " SET status = 2"; + EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK); + UpdateCloudDBData(0, cloudCount, 0, 0, ASSETS_TABLE_NAME); + CallSync(option); + sql = "UPDATE " + DBCommon::GetLogTableName(ASSETS_TABLE_NAME) + " SET status = 1"; + EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK); + + /** + * @tc.steps:step3. Compensated Sync and fork query contains not found + * @tc.expected: step3. return ok. + */ + int callCnt = 0; + g_virtualCloudDb->ForkAfterQueryResult([&](VBucket &extend, std::vector &data) { + callCnt++; + size_t expCnt = 10u; + if (callCnt == 1) { + EXPECT_EQ(data.size(), expCnt); + if (data.size() < expCnt) { + return DBStatus::CLOUD_ERROR; + } + int errIndex = 4; + data[errIndex].insert_or_assign(CloudDbConstant::ERROR_FIELD, + static_cast(DBStatus::CLOUD_RECORD_NOT_FOUND)); + return DBStatus::CLOUD_ERROR; + } + return DBStatus::CLOUD_ERROR; + }); + option.compensatedSyncOnly = true; + CallSync(option); + + /** + * @tc.steps:step4. Check sync stop. + * @tc.expected: step4. return ok. + */ + int expRow = 1; + sql = "select count(*) from " + DBCommon::GetLogTableName(ASSETS_TABLE_NAME) + " where cloud_gid = '';"; + EXPECT_EQ(sqlite3_exec(db, sql.c_str(), CloudDBSyncUtilsTest::QueryCountCallback, + reinterpret_cast(expRow), nullptr), SQLITE_OK); + g_virtualCloudDb->ForkAfterQueryResult(nullptr); +} } // namespace #endif // RELATIONAL_STORE \ No newline at end of file diff --git a/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/mock_icloud_sync_storage_interface.h b/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/mock_icloud_sync_storage_interface.h index 3361f51813c97350dd87e511bfc2ea191ca94e57..214815522a96f6c5d88360be5a603293199f4af8 100644 --- a/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/mock_icloud_sync_storage_interface.h +++ b/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/mock_icloud_sync_storage_interface.h @@ -58,6 +58,7 @@ public: MOCK_METHOD0(GetDownloadAssetTable, std::pair>(void)); MOCK_METHOD2(GetDownloadAssetRecords, std::pair>(const std::string &, int64_t)); MOCK_METHOD0(IsExistTableContainAssets, bool(void)); + MOCK_METHOD2(ConvertLogToLocal, int(const std::string &, const std::vector &)); }; } diff --git a/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_db.cpp b/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_db.cpp index 8ffb2ac7bee623f44041825e713c91fa20654e8e..3764bb4d7201200e2932e1d711305c34f62a25bb 100644 --- a/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_db.cpp +++ b/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_db.cpp @@ -301,6 +301,9 @@ DBStatus VirtualCloudDb::Query(const std::string &tableName, VBucket &extend, st extend[g_cursorField] = increPrefix_; return OK; } + if (forkAfterQueryResult_) { + return forkAfterQueryResult_(extend, data); + } return (data.empty() || data.size() < static_cast(queryLimit_)) ? QUERY_END : OK; } @@ -683,4 +686,9 @@ void VirtualCloudDb::ForkInsertConflict(const std::function &)> &func) +{ + forkAfterQueryResult_ = func; +} } \ No newline at end of file diff --git a/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_db.h b/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_db.h index 6c90e2b13d407a7ca77bc9608efad2ab757450f0..a41cd121d12ae7405bcbc76b4bf34a801db08a69 100644 --- a/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_db.h +++ b/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_db.h @@ -100,6 +100,8 @@ public: void SetHeartbeatBlockTime(int32_t blockTime); void SetInsertHook(const std::function &insertCheckFunc); + + void ForkAfterQueryResult(const std::function &)> &func); private: DBStatus InnerBatchInsert(const std::string &tableName, std::vector &&record, std::vector &extend); @@ -156,6 +158,7 @@ private: std::function &)> forkUploadConflictFunc_; std::function insertCheckFunc_; + std::function &)> forkAfterQueryResult_; }; } #endif // VIRTUAL_CLOUD_DB_H