From 1859b27292fd9cff71a88e237c918dae127279d5 Mon Sep 17 00:00:00 2001 From: Liu Hongyang Date: Thu, 11 Sep 2025 14:49:52 +0800 Subject: [PATCH] binlog replay add rollback on failure Signed-off-by: Liu Hongyang --- patch/0006-Support-Binlog.patch | 19 ++++++---- unittest/sqlite_binlog_test.cpp | 66 +++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 8 deletions(-) diff --git a/patch/0006-Support-Binlog.patch b/patch/0006-Support-Binlog.patch index 2002aa6..d48a2dd 100644 --- a/patch/0006-Support-Binlog.patch +++ b/patch/0006-Support-Binlog.patch @@ -1,14 +1,14 @@ -From bde4a0d2534ab3578c9ff04a35b1bb797e58cbfa Mon Sep 17 00:00:00 2001 +From 266fef0b19accb15bcde0bedb73d254cb9965651 Mon Sep 17 00:00:00 2001 From: Liu Hongyang -Date: Fri, 5 Sep 2025 15:34:47 +0800 +Date: Thu, 11 Sep 2025 14:27:25 +0800 [PATCH 06/12] Support-Binlog --- - src/sqlite3.c | 1584 ++++++++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 1575 insertions(+), 9 deletions(-) + src/sqlite3.c | 1587 ++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 1578 insertions(+), 9 deletions(-) diff --git a/src/sqlite3.c b/src/sqlite3.c -index b433dfb..a225fbc 100644 +index 3bbaf39..ebddb54 100644 --- a/src/sqlite3.c +++ b/src/sqlite3.c @@ -2938,7 +2938,9 @@ SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); @@ -697,7 +697,7 @@ index b433dfb..a225fbc 100644 *ppDb = db; #ifdef SQLITE_ENABLE_SQLLOG if( sqlite3GlobalConfig.xSqllog ){ -@@ -256913,6 +257340,1133 @@ static void walLogCheckpointInfo(Wal *pWal, sqlite3 *db, sqlite3_int64 startTime +@@ -256913,6 +257340,1136 @@ static void walLogCheckpointInfo(Wal *pWal, sqlite3 *db, sqlite3_int64 startTime } #endif @@ -1793,6 +1793,9 @@ index b433dfb..a225fbc 100644 + } + } while (1); + destDb->xBinlogHandle.isSkipTrigger = oldIsSkipTrigger; ++ if (res != SQLITE_OK) { ++ sqlite3_exec(destDb, "rollback;", NULL, NULL, NULL); ++ } + (void)srcDb->xBinlogHandle.binlogApi.binlogUnlockReadApi(srcDb->xBinlogHandle.binlogConn); + if (res != SQLITE_OK) { + sqlite3BinlogClose(srcDb); @@ -1831,7 +1834,7 @@ index b433dfb..a225fbc 100644 // export the symbols #ifdef SQLITE_EXPORT_SYMBOLS #ifndef SQLITE_CKSUMVFS_STATIC -@@ -256942,6 +258496,9 @@ struct sqlite3_api_routines_extra { +@@ -256942,6 +258499,9 @@ struct sqlite3_api_routines_extra { int (*key_v2)(sqlite3*,const char*,const void*,int); int (*rekey)(sqlite3*,const void*,int); int (*rekey_v2)(sqlite3*,const char*,const void*,int); @@ -1841,7 +1844,7 @@ index b433dfb..a225fbc 100644 }; typedef struct sqlite3_api_routines_extra sqlite3_api_routines_extra; -@@ -256952,13 +258509,22 @@ static const sqlite3_api_routines_extra sqlite3ExtraApis = { +@@ -256952,13 +258512,22 @@ static const sqlite3_api_routines_extra sqlite3ExtraApis = { sqlite3_key, sqlite3_key_v2, sqlite3_rekey, diff --git a/unittest/sqlite_binlog_test.cpp b/unittest/sqlite_binlog_test.cpp index e79848f..fe7daa5 100644 --- a/unittest/sqlite_binlog_test.cpp +++ b/unittest/sqlite_binlog_test.cpp @@ -231,6 +231,72 @@ HWTEST_F(SqliteBinlogTest, BinlogReplayTest002, TestSize.Level1) sqlite3_close_v2(backupDb); } +/** + * @tc.name: BinlogReplayTest003 + * @tc.desc: Test replay binlog with transaction failed + * @tc.type: FUNC + */ +HWTEST_F(SqliteBinlogTest, BinlogReplayTest003, TestSize.Level1) +{ + /** + * @tc.steps: step1. open db and set binlog + * @tc.expected: step1. ok + */ + sqlite3 *db = NULL; + EXPECT_EQ(sqlite3_open_v2(TEST_DB, &db, + SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, nullptr), SQLITE_OK); + ASSERT_NE(db, nullptr); + UtEnableBinlog(db); + /** + * @tc.steps: step2. Insert records + * @tc.expected: step2. Execute successfully + */ + EXPECT_EQ(sqlite3_exec(db, "begin;", nullptr, nullptr, nullptr), SQLITE_OK); + static const char *UT_SQL_INSERT_DATA = + "INSERT INTO salary(entryId, entryName, salary, class) VALUES(1,'test',2,3);"; + EXPECT_EQ(sqlite3_exec(db, UT_SQL_INSERT_DATA, nullptr, nullptr, nullptr), SQLITE_OK); + EXPECT_EQ(sqlite3_exec(db, "commit;", nullptr, nullptr, nullptr), SQLITE_OK); + /** + * @tc.steps: step3. drop table in backup and replay + * @tc.expected: step3. replay failed + */ + sqlite3 *backupDb = NULL; + EXPECT_EQ(sqlite3_open_v2(TEST_BACKUP_DB, &backupDb, + SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, nullptr), SQLITE_OK); + ASSERT_NE(backupDb, nullptr); + EXPECT_EQ(sqlite3_exec(backupDb, "drop table salary;", nullptr, nullptr, nullptr), SQLITE_OK); + EXPECT_EQ(sqlite3_replay_binlog(db, backupDb), SQLITE_ERROR); + /** + * @tc.steps: step4. re-create table and clean binlog + * @tc.expected: step4. clean ok + */ + static const char *UT_DDL_CREATE_TABLE = "CREATE TABLE salary(" + "entryId INTEGER PRIMARY KEY," + "entryName Text," + "salary REAL," + "class INTEGER," + "extra BLOB);"; + EXPECT_EQ(sqlite3_exec(backupDb, UT_DDL_CREATE_TABLE, NULL, NULL, NULL), SQLITE_OK); + UtEnableBinlog(db); + EXPECT_EQ(sqlite3_clean_binlog(db, BinlogFileCleanModeE::BINLOG_FILE_CLEAN_ALL_MODE), SQLITE_OK); + /** + * @tc.steps: step5. insert one more data with transaction + * @tc.expected: step5. insert ok + */ + EXPECT_EQ(sqlite3_exec(db, "begin;", nullptr, nullptr, nullptr), SQLITE_OK); + static const char *UT_SQL_INSERT_DATA2 = + "INSERT INTO salary(entryId, entryName, salary, class) VALUES (2, 'test', 2, 3);"; + EXPECT_EQ(sqlite3_exec(db, UT_SQL_INSERT_DATA2, nullptr, nullptr, nullptr), SQLITE_OK); + EXPECT_EQ(sqlite3_exec(db, "commit;", nullptr, nullptr, nullptr), SQLITE_OK); + /** + * @tc.steps: step5. replay transaction into backup + * @tc.expected: step5. replay success + */ + EXPECT_EQ(sqlite3_replay_binlog(db, backupDb), SQLITE_OK); + sqlite3_close_v2(db); + sqlite3_close_v2(backupDb); +} + /** * @tc.name: BinlogInterfaceTest001 * @tc.desc: Test replay sql with invalid db pointer -- Gitee