Bug #107989 Contribution by Tencent: force recovery fail to start if need insert gtids
Submitted: 27 Jul 2022 1:18 Modified: 27 Jul 2022 7:43
Reporter: yewei Xu (OCA) Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: Replication Severity:S4 (Feature request)
Version:5.7,8.0 OS:Linux
Assigned to: CPU Architecture:Any
Tags: Contribution

[27 Jul 2022 1:18] yewei Xu
Description:
If mysqld killed before persist all gtids into table mysql.gtid_executed, mysql will try to insert these "gtids_in_binlog_not_in_table" into mysql.gtid_executed when next startup. If mysql start with force_recovery, these insert will fail with error "Operation not allowed when innodb_forced_recovery > 0" and start will abort.

How to repeat:
--source include/have_debug.inc                                                                                                                                                                                                   
--source include/have_innodb.inc                                                                                                                                                                                                  
--source include/have_log_bin.inc                                                                                                                                                                                                 
                                                                                                                                                                                                                                  
create table test(id int);                                                                                                                                                                                                        
                                                                                                                                                                                                                                  
insert into test values (1);                                                                                                                                                                                                      
                                                                                                                                                                                                                                  
--let $restart_parameters=restart:--innodb-force-recovery=1                                                                                                                                                                       
--source include/kill_and_restart_mysqld.inc

Suggested fix:
don't insert "gtids_in_binlog_not_in_table" into mysql.gtid_executed if force_recovery on
[27 Jul 2022 1:25] yewei Xu
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 36c93e96d74..f08308714dc 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -7715,9 +7715,14 @@ int mysqld_main(int argc, char **argv)
              gtid_executed table and executed_gtids during recovery
              from the crash.
       */
-      if (gtid_state->save(&gtids_in_binlog_not_in_table) == -1) {
-        global_sid_lock->unlock();
-        unireg_abort(MYSQLD_ABORT_EXIT);
+      if (srv_force_recovery) {
+        sql_print_warning("Skip save gtids_in_binlog_not_in_table to table "
+                          "since force_recovery is on");
+      } else {
+        if (gtid_state->save(&gtids_in_binlog_not_in_table) == -1) {
+          global_sid_lock->unlock();
+          unireg_abort(MYSQLD_ABORT_EXIT);
+        }
       }
       executed_gtids->add_gtid_set(&gtids_in_binlog_not_in_table);
     }
[27 Jul 2022 7:43] MySQL Verification Team
Hello  Yewei Xu,

Thank you for the report and contribution.

regards,
Umesh