diff --git a/components/mysqlbackup/backup_comp_constants.h b/components/mysqlbackup/backup_comp_constants.h index b7d22395d85..cd01195c4b6 100644 --- a/components/mysqlbackup/backup_comp_constants.h +++ b/components/mysqlbackup/backup_comp_constants.h @@ -40,6 +40,7 @@ constexpr const char *udf_get_changed_pages{ "mysqlbackup_page_track_get_changed_pages"}; constexpr const char *udf_get_changed_page_count{ "mysqlbackup_page_track_get_changed_page_count"}; +constexpr const char *udf_purge_pages{"mysqlbackup_page_track_purge_pages"}; // Changed pages file path constexpr const char *backup_scratch_dir{"#meb"}; // Changed pages file extension diff --git a/components/mysqlbackup/backup_page_tracker.cc b/components/mysqlbackup/backup_page_tracker.cc index 3e5d60e5473..c4f09cc92d0 100644 --- a/components/mysqlbackup/backup_page_tracker.cc +++ b/components/mysqlbackup/backup_page_tracker.cc @@ -95,6 +95,12 @@ void Backup_page_tracker::initialize_udf_list() { reinterpret_cast(page_track_get_changed_pages), reinterpret_cast(page_track_get_changed_pages_init), reinterpret_cast(page_track_get_changed_pages_deinit))); + + m_udf_list.push_back(new udf_data_t( + Backup_comp_constants::udf_purge_pages, INT_RESULT, + reinterpret_cast(page_track_purge_pages), + reinterpret_cast(page_track_purge_pages_init), + reinterpret_cast(page_track_purge_pages_deinit))); } /** @@ -475,3 +481,50 @@ int page_track_callback(MYSQL_THD opaque_thd [[maybe_unused]], else return (0); } + +/** + Callback function for initialization of UDF + "mysqlbackup_page_track_purge_pages". + + @return Status of purge + @retval false on success + @retval true on failure +*/ +bool Backup_page_tracker::page_track_purge_pages_init(UDF_INIT *, UDF_ARGS *, + char *) { + return (false); +} + +/** + Callback method for dinitialization of UDF + "mysqlbackup_page_track_purge_pages". +*/ +void Backup_page_tracker::page_track_purge_pages_deinit( + UDF_INIT *initid MY_ATTRIBUTE((unused))) {} + +/** + UDF for "mysqlbackup_page_track_purge_pages" + See include/mysql/udf_registration_types.h + + @returns an int status + */ +long long Backup_page_tracker::page_track_purge_pages(UDF_INIT *, + UDF_ARGS *args, + unsigned char *, + unsigned char *) { + MYSQL_THD thd; + if (mysql_service_mysql_current_thread_reader->get(&thd)) { + return (-1); + } + + if (args->arg_count != 1 || args->arg_type[0] != INT_RESULT) { + return (-1); + } + + int retval = 0; + uint64_t lsn = *((long long *)args->args[0]); + retval = + mysql_service_mysql_page_track->purge(thd, PAGE_TRACK_SE_INNODB, &lsn); + if (retval) return (-1 * retval); + return retval; +} diff --git a/components/mysqlbackup/backup_page_tracker.h b/components/mysqlbackup/backup_page_tracker.h index 4fe693caa57..61aca7a1072 100644 --- a/components/mysqlbackup/backup_page_tracker.h +++ b/components/mysqlbackup/backup_page_tracker.h @@ -111,6 +111,13 @@ class Backup_page_tracker { unsigned char *is_null, unsigned char *error); + static bool page_track_purge_pages_init(UDF_INIT *initid, UDF_ARGS *, char *); + static void page_track_purge_pages_deinit( + UDF_INIT *initid MY_ATTRIBUTE((unused))); + static long long page_track_purge_pages(UDF_INIT *initid, UDF_ARGS *, + unsigned char *is_null, + unsigned char *error); + // method to act on a changed backup-id static bool backup_id_update(); diff --git a/mysql-test/suite/innodb/t/page_tracking_purge.test b/mysql-test/suite/innodb/t/page_tracking_purge.test new file mode 100644 index 00000000000..8dc3e59f172 --- /dev/null +++ b/mysql-test/suite/innodb/t/page_tracking_purge.test @@ -0,0 +1,109 @@ +#test page tracking purge +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/count_sessions.inc + +LET $MYSQLD_DATADIR = `select @@datadir`; +SET GLOBAL innodb_monitor_enable = module_log; + +DELIMITER |; +CREATE PROCEDURE prepare_data(IN val INT) +BEGIN + DECLARE i INT DEFAULT 1; + + WHILE i < val DO + INSERT INTO t1 (b,c) VALUES (REPEAT(a,600), REPEAT(b,600)); + INSERT INTO t2 (b,c) VALUES (REPEAT(a,600), REPEAT(b,600)); + INSERT INTO t3 (b,c) VALUES (REPEAT(a,600), REPEAT(b,600)); + SET i = i + 1; + END WHILE; +END| +DELIMITER ;| + +--eval INSTALL COMPONENT "file://component_mysqlbackup" + +--echo #Case 1 check basic scenario with purge function +SELECT mysqlbackup_page_track_purge_pages(1); +SELECT mysqlbackup_page_track_purge_pages("string"); +SELECT mysqlbackup_page_track_purge_pages(); +SELECT mysqlbackup_page_track_purge_pages(1,2); + +--echo #Case 2 check if page archive cleans archive file stop lsn +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b LONGBLOB, c +LONGBLOB); +CREATE TABLE t2 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b LONGBLOB, c +LONGBLOB); +CREATE TABLE t3 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b LONGBLOB, c +LONGBLOB); +SELECT mysqlbackup_page_track_set(1); +CALL prepare_data(100); +SET GLOBAL innodb_log_checkpoint_now = 1; +SELECT mysqlbackup_page_track_set(0); +--source ../include/log_read_current_lsn.inc +if ($debug_test) { + --echo LSN: $current_lsn +} +--eval SELECT mysqlbackup_page_track_purge_pages($current_lsn) +--list_files $MYSQLD_DATADIR/#ib_archive + +--echo #Case 3 page archive should not interfare when clone in progress + +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); + +--let $CLONE_DATADIR = $MYSQL_TMP_DIR/data_new + +--replace_result $CLONE_PLUGIN CLONE_PLUGIN +--eval INSTALL PLUGIN clone SONAME '$CLONE_PLUGIN' +--connection con1 +SET DEBUG_SYNC = 'clone_file_copy SIGNAL page_signal WAIT_FOR go_page'; +--source ../../clone/include/clone_command_send.inc + +--connection con2 +SET DEBUG_SYNC = 'now WAIT_FOR page_signal'; +CALL prepare_data(100); +--source ../include/log_read_current_lsn.inc +if ($debug_test) { + --echo LSN: $current_lsn +} +--eval SELECT mysqlbackup_page_track_purge_pages($current_lsn) +SET DEBUG_SYNC = 'now SIGNAL go_page'; + +--connection con1 +--reap + +select count(*) from t1; +select count(*) from t2; +select count(*) from t3; + +# Restart server on cloned data directory +--replace_result $CLONE_DATADIR CLONE_DATADIR +--let restart_parameters="restart: --datadir=$CLONE_DATADIR" +--source include/restart_mysqld.inc + +select count(*) from t1; +select count(*) from t2; +select count(*) from t3; + +#Cleanup +--let restart_parameters="restart:" +--source include/restart_mysqld.inc + +--connection con1 +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; + +SET DEBUG_SYNC = 'RESET'; + +--force-rmdir $CLONE_DATADIR + +DROP PROCEDURE prepare_data; + +UNINSTALL PLUGIN clone; +UNINSTALL COMPONENT "file://component_mysqlbackup"; + +--disconnect con1 +--disconnect con2 +--disconnect con3 +