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 7b4bc52f9f67297fc0221991cc88214fccd43523..672ec0b2b70e3c5c8784870ae06cc67dc3f96ce1 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 @@ -380,6 +380,8 @@ private: int DeleteOneCloudNoneExistRecord(const std::string &tableName, SQLiteRelationalUtils::CloudNotExistRecord &record, SQLiteSingleVerRelationalStorageExecutor *handle, std::vector &removeAssetsVec); + + int GetGidRecordCount(const std::string &tableName, uint64_t &count) const override; #endif // data 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 2c832d0a78ac0b2780a9cef6813432e36798825b..f571b5c756976934429bef5e1a985900ee3e1d35 100644 --- a/frameworks/libs/distributeddb/storage/include/icloud_sync_storage_interface.h +++ b/frameworks/libs/distributeddb/storage/include/icloud_sync_storage_interface.h @@ -350,6 +350,11 @@ public: { return E_OK; } + + virtual int GetGidRecordCount([[gnu::unused]] const std::string &tableName, [[gnu::unused]] uint64_t &count) const + { + return E_OK; + } }; } diff --git a/frameworks/libs/distributeddb/storage/include/storage_proxy.h b/frameworks/libs/distributeddb/storage/include/storage_proxy.h index 981f3734afd38010bbc121f5f6b24226f7aaf5f5..c3fac43127377b8c8e42e1f093edcc231f7d0cf7 100644 --- a/frameworks/libs/distributeddb/storage/include/storage_proxy.h +++ b/frameworks/libs/distributeddb/storage/include/storage_proxy.h @@ -215,6 +215,8 @@ public: int CleanCloudInfo(const std::string &tableName); int DeleteCloudNoneExistRecord(const std::string &tableName, std::pair isNeedDeleted = {false, true}); + + int GetGidRecordCount(const std::string &tableName, uint64_t &count) const; protected: void Init(); private: 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 da9201b5af166640ba47f7e2c6f6423f7c73e2a5..b01c763f24c043847b6a8ebd5db28ff4ce387576 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 @@ -938,6 +938,21 @@ int RelationalSyncAbleStorage::DeleteOneCloudNoneExistRecord(const std::string & } return errCode; } + +int RelationalSyncAbleStorage::GetGidRecordCount(const std::string &tableName, uint64_t &count) const +{ + int errCode = E_OK; + auto *readHandle = static_cast( + storageEngine_->FindExecutor(false, OperatePerm::NORMAL_PERM, errCode)); + if (readHandle == nullptr) { + return errCode; + } + ResFinalizer finalizer([this, readHandle] { + auto handle = readHandle; + ReleaseHandle(handle); + }); + return readHandle->GetGidRecordCount(tableName, count); +} #endif } #endif diff --git a/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_utils.cpp b/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_utils.cpp index 1ea6e172bd5e17a174ba75d0c4115eb5e3160432..e024f185644965836b0526a236dd86adadb208cb 100644 --- a/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_utils.cpp +++ b/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_utils.cpp @@ -1520,6 +1520,19 @@ std::map SQLiteRelationalUtils::GetCloudFieldDataType() cloudFieldTypeMap[TYPE_INDEX] = "ASSETS"; return cloudFieldTypeMap; } + +int SQLiteRelationalUtils::GetGidRecordCount(sqlite3 *db, const std::string &tableName, uint64_t &count) +{ + std::string sql = "SELECT COUNT(1) FROM " + DBCommon::GetLogTableName(tableName) + " WHERE cloud_gid != ''"; + int ret = 0; + int errCode = SQLiteUtils::GetCountBySql(db, sql, ret); + count = static_cast(ret); + if (errCode == E_OK) { + LOGI("[GetGidRecordCount] Local[%s] exist %d record", DBCommon::StringMiddleMaskingWithLen(tableName).c_str(), + ret); + } + return errCode; +} #endif int SQLiteRelationalUtils::DeleteDistributedExceptDeviceTable(sqlite3 *db, const std::string &removedTable, diff --git a/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_utils.h b/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_utils.h index ace087fc8cea1ae5f5fa725c3cc6b594f5d04d70..c9014d2958dc5fdbad58d0a6199933568c1e4478 100644 --- a/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_utils.h +++ b/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_utils.h @@ -177,6 +177,8 @@ public: static int CheckUserCreateSharedTable(sqlite3 *db, const TableSchema &oriTable, const std::string &sharedTable); static std::map GetCloudFieldDataType(); + + static int GetGidRecordCount(sqlite3 *db, const std::string &tableName, uint64_t &count); #endif static int DeleteDistributedExceptDeviceTable(sqlite3 *db, const std::string &removedTable, const std::vector &keepDevices); 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 f1765f26aa1db347fee4236854340cef6128e36d..ccec96d8cd16553da181ea7ac4b93d1e509d44b3 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 @@ -2059,6 +2059,11 @@ int SQLiteSingleVerRelationalStorageExecutor::RemoveCloudNoneExistRecordAssets(c assetLoader_->BatchRemoveLocalAssets(tableName, removeAssets); return E_OK; } + +int SQLiteSingleVerRelationalStorageExecutor::GetGidRecordCount(const std::string &tableName, uint64_t &count) const +{ + return SQLiteRelationalUtils::GetGidRecordCount(dbHandle_, tableName, count); +} #endif int SQLiteSingleVerRelationalStorageExecutor::DeleteDistributedExceptDeviceTable( 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 28854059103cf45248c25f71faf87a45f670b0e4..a44ec294cdee3e89518d32e8e9e5f4ad90605e1d 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 @@ -300,6 +300,7 @@ public: int DropTempTable(const std::string &tableName) const; + int GetGidRecordCount(const std::string &tableName, uint64_t &count) const; #endif int DeleteDistributedExceptDeviceTable(const std::string &removedTable, const std::vector &keepDevices) const; diff --git a/frameworks/libs/distributeddb/storage/src/storage_proxy.cpp b/frameworks/libs/distributeddb/storage/src/storage_proxy.cpp index 19230d9517e728b7f02a9b7a03898057eee85326..4ebcd7d3ad4ba4d002e3e88f9199819240f2562b 100644 --- a/frameworks/libs/distributeddb/storage/src/storage_proxy.cpp +++ b/frameworks/libs/distributeddb/storage/src/storage_proxy.cpp @@ -997,4 +997,14 @@ int StorageProxy::DeleteCloudNoneExistRecord(const std::string &tableName, std:: } return store_->DeleteCloudNoneExistRecord(tableName, isNeedDeleted); } + +int StorageProxy::GetGidRecordCount(const std::string &tableName, uint64_t &count) const +{ + std::shared_lock readLock(storeMutex_); + if (store_ == nullptr) { + LOGE("[CountGidRecords] store is null"); + return -E_INVALID_DB; + } + return store_->GetGidRecordCount(tableName, count); +} } \ No newline at end of file diff --git a/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer.h b/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer.h index e9a0c18d6eaa24472edb43f8bc1f9d85b323dbf4..8bedcd484e3e82e815b16fda4bfd43d8518026df 100644 --- a/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer.h +++ b/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer.h @@ -572,6 +572,8 @@ protected: int DoUpdateExpiredCursor(TaskId taskId, const std::string &table, std::string &newCursor); + int DoQueryAllGid(TaskId taskId, SyncParam &¶m); + int DoUpdatePotentialCursorIfNeed(const std::string &table); int DownloadOneBatchGID(TaskId taskId, SyncParam ¶m); diff --git a/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer_extend_extend.cpp b/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer_extend_extend.cpp index a0add21239ace520ef7afb3964e71edb730da989..cab8092058f0df56e0424a4dba03384ce3526388 100644 --- a/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer_extend_extend.cpp +++ b/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer_extend_extend.cpp @@ -286,8 +286,27 @@ int CloudSyncer::DoUpdateExpiredCursor(TaskId taskId, const std::string &table, if (errCode != E_OK) { return errCode; } + errCode = DoQueryAllGid(taskId, std::move(param)); + if (errCode != E_OK) { + return errCode; + } + return UpdateCloudMarkAndCleanExpiredCursor(param, newCursor); +} + +int CloudSyncer::DoQueryAllGid(TaskId taskId, SyncParam &¶m) +{ + uint64_t count = 0; + int errCode = storageProxy_->GetGidRecordCount(param.tableName, count); + if (errCode != E_OK) { + return errCode; + } int retryCount = 0; do { + if (count == 0) { + LOGI("[CloudSyncer] Skip query[%s] all gid by not exists gid record", + DBCommon::StringMiddleMasking(param.tableName).c_str()); + break; + } param.downloadData.data.clear(); int ret = DownloadOneBatchGID(taskId, param); if (ret == -E_EXPIRED_CURSOR && retryCount < MAX_EXPIRED_CURSOR_COUNT) { @@ -309,12 +328,16 @@ int CloudSyncer::DoUpdateExpiredCursor(TaskId taskId, const std::string &table, return ret; } } while (!param.isLastBatch); - std::pair isNeedDeleted = {IsModeForcePush(taskId), IsModeForcePull(taskId)}; - errCode = storageProxy_->DeleteCloudNoneExistRecord(param.tableName, isNeedDeleted); - if (errCode != E_OK) { - return errCode; + if (count == 0) { + errCode = DropTempTable(param.tableName); + } else { + std::pair isNeedDeleted = {IsModeForcePush(taskId), IsModeForcePull(taskId)}; + errCode = storageProxy_->DeleteCloudNoneExistRecord(param.tableName, isNeedDeleted); + if (errCode != E_OK) { + return errCode; + } } - return UpdateCloudMarkAndCleanExpiredCursor(param, newCursor); + return errCode; } int CloudSyncer::DoUpdatePotentialCursorIfNeed(const std::string &table) diff --git a/frameworks/libs/distributeddb/test/unittest/common/store_test/rdb/distributeddb_rdb_complex_cloud_test.cpp b/frameworks/libs/distributeddb/test/unittest/common/store_test/rdb/distributeddb_rdb_complex_cloud_test.cpp index 96ab9d38812f06f455c7a259ee8c669195ea5e38..a211d9c5433adde514ce926f2ffd2a465918f21c 100644 --- a/frameworks/libs/distributeddb/test/unittest/common/store_test/rdb/distributeddb_rdb_complex_cloud_test.cpp +++ b/frameworks/libs/distributeddb/test/unittest/common/store_test/rdb/distributeddb_rdb_complex_cloud_test.cpp @@ -227,6 +227,7 @@ HWTEST_F(DistributedDBRDBComplexCloudTest, ExpireCursor004, TestSize.Level2) */ Query query = Query::Select().FromTable({CLOUD_SYNC_TABLE_A}); EXPECT_NO_FATAL_FAILURE(CloudBlockSync(info1_, query, SyncMode::SYNC_MODE_CLOUD_MERGE, OK, OK)); + EXPECT_NO_FATAL_FAILURE(CloudBlockSync(info2_, query, SyncMode::SYNC_MODE_CLOUD_MERGE, OK, OK)); auto cloudDB = GetVirtualCloudDb(); ASSERT_NE(cloudDB, nullptr); cloudDB->ForkAfterQueryResult([](VBucket &, std::vector &) { @@ -409,5 +410,42 @@ HWTEST_F(DistributedDBRDBComplexCloudTest, ExpireCursor010, TestSize.Level2) { EXPECT_NO_FATAL_FAILURE(ExpireCursorWithEmptyGid(false, SyncMode::SYNC_MODE_CLOUD_FORCE_PULL)); } + +/** + * @tc.name: ExpireCursor010 + * @tc.desc: Test sync with expire cursor and local not exits gid. + * @tc.type: FUNC + * @tc.author: zqq + */ +HWTEST_F(DistributedDBRDBComplexCloudTest, ExpireCursor011, TestSize.Level2) +{ + /** + * @tc.steps:step1. store1 insert one data + * @tc.expected: step1. insert success. + */ + auto ret = ExecuteSQL("INSERT INTO CLOUD_SYNC_TABLE_A VALUES(1, 1, 'text1', 'text2', 'uuid1')", info1_); + ASSERT_EQ(ret, E_OK); + /** + * @tc.steps:step2. store1 push + * @tc.expected: step2. sync success. + */ + Query query = Query::Select().FromTable({CLOUD_SYNC_TABLE_A}); + EXPECT_NO_FATAL_FAILURE(CloudBlockSync(info1_, query, SyncMode::SYNC_MODE_CLOUD_MERGE, OK, OK)); + /** + * @tc.steps:step3. store2 pull + * @tc.expected: step3. sync failed with expired cursor too much times. + */ + auto cloudDB = GetVirtualCloudDb(); + ASSERT_NE(cloudDB, nullptr); + cloudDB->ForkAfterQueryResult([](VBucket &, std::vector &) { + return DBStatus::EXPIRED_CURSOR; + }); + cloudDB->ForkQueryAllGid([](const std::string &, VBucket &, std::vector &) { + return DBStatus::DB_ERROR; + }); + EXPECT_NO_FATAL_FAILURE(CloudBlockSync(info2_, query, SyncMode::SYNC_MODE_CLOUD_MERGE, OK, EXPIRED_CURSOR)); + cloudDB->ForkAfterQueryResult(nullptr); + cloudDB->ForkQueryAllGid(nullptr); +} } #endif