[Commits] Rev 3917: MDEV-9095: Executing triggers on slave in row-based replication in file:///home/bell/maria/bzr/work-maria-10.0-MDEV-5095/

sanja at askmonty.org sanja at askmonty.org
Thu Dec 19 10:10:15 EET 2013


At file:///home/bell/maria/bzr/work-maria-10.0-MDEV-5095/

------------------------------------------------------------
revno: 3917
revision-id: sanja at askmonty.org-20131219081000-bfmcn0zhy0x9c6pr
parent: sanja at montyprogram.com-20131208220835-k5hl11lf9aaor0l8
committer: sanja at askmonty.org
branch nick: work-maria-10.0-MDEV-5095
timestamp: Thu 2013-12-19 10:10:00 +0200
message:
  MDEV-9095: Executing triggers on slave in row-based replication
  
  Postreview changes.
-------------- next part --------------
=== modified file 'mysql-test/r/mysqld--help.result'
--- a/mysql-test/r/mysqld--help.result	2013-12-08 22:08:35 +0000
+++ b/mysql-test/r/mysqld--help.result	2013-12-19 08:10:00 +0000
@@ -887,10 +887,11 @@ The following options may be given as th
  Modes for how triggers in row-base replication on slave
  side will be executed. Legal values are NO (default), YES
  and LOGGING. NO means that trigger for RBR will not be
- running on slave YES and LOGGING means that triggers will
- be running on slave (if there was not triggers running on
- the naster), LOGGING also mens that flag about executed
- triggers will be written to binlog.
+ running on slave. YES and LOGGING means that triggers
+ will be running on slave, if there was not triggers
+ running on the master for the statement. LOGGING also
+ means results of that the executed triggers work will be
+ written to the binlog.
  --slave-skip-errors=name 
  Tells the slave thread to continue replication when a
  query event returns an error from the provided list

=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc	2013-12-08 22:08:35 +0000
+++ b/sql/log_event.cc	2013-12-19 08:10:00 +0000
@@ -9286,6 +9286,13 @@ int Rows_log_event::do_add_row_data(ucha
 
 #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
 
+/**
+  Restores empty table list as it was before trigger processing.
+
+  @note We have a lot of ASSERTS that check the lists when we close tables.
+  There was the same problem with MERGE MYISAM tables and so here we try to
+  go the same way.
+*/
 static void restore_empty_query_table_list(LEX *lex)
 {
   if (lex->first_not_own_table())
@@ -9298,6 +9305,7 @@ static void restore_empty_query_table_li
 int Rows_log_event::do_apply_event(rpl_group_info *rgi)
 {
   Relay_log_info const *rli= rgi->rli;
+  TABLE* table;
   DBUG_ENTER("Rows_log_event::do_apply_event(Relay_log_info*)");
   int error= 0;
   /*
@@ -9382,6 +9390,12 @@ int Rows_log_event::do_apply_event(rpl_g
       LEX *lex= thd->lex;
       uint8 new_trg_event_map= get_trg_event_map();
 
+      /*
+        Trigger's procedures work with global table list. So we have to add
+        rgi->tables_to_lock content there to get trigger's in the list.
+
+        Then restore_empty_query_table_list() restore the list as it was
+      */
       DBUG_ASSERT(lex->query_tables == NULL);
       if ((lex->query_tables= rgi->tables_to_lock))
         rgi->tables_to_lock->prev_global= &lex->query_tables;
@@ -9411,10 +9425,8 @@ int Rows_log_event::do_apply_event(rpl_g
         thd->is_slave_error= 1;
       }
       /* remove trigger's tables */
-      if (slave_run_triggers_for_rbr)
-        restore_empty_query_table_list(thd->lex);
-      rgi->slave_close_thread_tables(thd);
-      DBUG_RETURN(actual_error);
+      error= actual_error;
+      goto err;
     }
 
     /*
@@ -9459,10 +9471,8 @@ int Rows_log_event::do_apply_event(rpl_g
           */
           thd->is_slave_error= 1;
           /* remove trigger's tables */
-          if (slave_run_triggers_for_rbr)
-            restore_empty_query_table_list(thd->lex);
-          rgi->slave_close_thread_tables(thd);
-          DBUG_RETURN(ERR_BAD_TABLE_DEF);
+          error= ERR_BAD_TABLE_DEF;
+          goto err;
         }
         DBUG_PRINT("debug", ("Table: %s.%s is compatible with master"
                              " - conv_table: %p",
@@ -9490,6 +9500,12 @@ int Rows_log_event::do_apply_event(rpl_g
     for (uint i=0 ;  ptr && (i < rgi->tables_to_lock_count); ptr= ptr->next_global, i++)
     {
       rgi->m_table_map.set_table(ptr->table_id, ptr->table);
+      /*
+        Following is passing flag about triggers on the server. The problem was
+        to pass it between table map event and row event. I do it via extended
+        TABLE_LIST (RPL_TABLE_LIST) but row event uses only TABLE so I need to
+        find somehow the corresponding TABLE_LIST.
+      */
       if (m_table_id == ptr->table_id)
         master_had_triggers= ((RPL_TABLE_LIST*)ptr)->master_had_triggers;
     }
@@ -9499,9 +9515,7 @@ int Rows_log_event::do_apply_event(rpl_g
 #endif
   }
 
-  TABLE* 
-    table= 
-    m_table= rgi->m_table_map.get_table(m_table_id);
+  table= m_table= rgi->m_table_map.get_table(m_table_id);
 
   DBUG_PRINT("debug", ("m_table: 0x%lx, m_table_id: %lu%s",
                        (ulong) m_table, m_table_id,
@@ -9673,9 +9687,7 @@ int Rows_log_event::do_apply_event(rpl_g
     thd->reset_current_stmt_binlog_format_row();
     thd->is_slave_error= 1;
     /* remove trigger's tables */
-    if (slave_run_triggers_for_rbr)
-      restore_empty_query_table_list(thd->lex);
-    DBUG_RETURN(error);
+    goto err;
   }
 
   /* remove trigger's tables */
@@ -9688,6 +9700,12 @@ int Rows_log_event::do_apply_event(rpl_g
                             get_type_str(),
                             RPL_LOG_NAME, (ulong) log_pos);
   DBUG_RETURN(error);
+
+err:
+  if (slave_run_triggers_for_rbr)
+    restore_empty_query_table_list(thd->lex);
+  rgi->slave_close_thread_tables(thd);
+  DBUG_RETURN(error);
 }
 
 Log_event::enum_skip_reason
@@ -10861,28 +10879,7 @@ Write_rows_log_event::do_before_row_oper
     */
   }
   if (slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers )
-  {
-    if (m_table->triggers->has_triggers(TRG_EVENT_DELETE,
-                                        TRG_ACTION_AFTER))
-    {
-      /*
-        The table has AFTER DELETE triggers that might access to 
-        subject table and therefore might need delete to be done 
-        immediately. So we turn-off the batching.
-      */ 
-      (void) m_table->file->extra(HA_EXTRA_DELETE_CANNOT_BATCH);
-    }
-    if (m_table->triggers->has_triggers(TRG_EVENT_UPDATE,
-                                        TRG_ACTION_AFTER))
-    {
-      /*
-        The table has AFTER UPDATE triggers that might access to subject 
-        table and therefore might need update to be done immediately. 
-        So we turn-off the batching.
-      */ 
-      (void) m_table->file->extra(HA_EXTRA_UPDATE_CANNOT_BATCH);
-    }
-  }
+    m_table->prepare_triggers_for_insert_stmt_or_event();
 
   /* Honor next number column if present */
   m_table->next_number_field= m_table->found_next_number_field;
@@ -11912,17 +11909,8 @@ Delete_rows_log_event::do_before_row_ope
     */
     return 0;
   }
-  if (slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers &&
-      m_table->triggers->has_triggers(TRG_EVENT_DELETE,
-                                    TRG_ACTION_AFTER))
-  {
-    /*
-      The table has AFTER DELETE triggers that might access to subject table
-      and therefore might need delete to be done immediately. So we turn-off
-      the batching.
-    */
-    (void) m_table->file->extra(HA_EXTRA_DELETE_CANNOT_BATCH);
-  }
+  if (slave_run_triggers_for_rbr && !master_had_triggers)
+    m_table->prepare_triggers_for_update_stmt_or_event();
 
   return find_key();
 }
@@ -12065,17 +12053,8 @@ Update_rows_log_event::do_before_row_ope
   if ((err= find_key()))
     return err;
 
-  if (slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers &&
-      m_table->triggers->has_triggers(TRG_EVENT_UPDATE,
-                                      TRG_ACTION_AFTER))
-  {
-    /*
-      The table has AFTER UPDATE triggers that might access to subject
-      table and therefore might need update to be done immediately.
-      So we turn-off the batching.
-    */ 
-    (void) m_table->file->extra(HA_EXTRA_UPDATE_CANNOT_BATCH);
-  }
+  if (slave_run_triggers_for_rbr && !master_had_triggers)
+    m_table->prepare_triggers_for_update_stmt_or_event();
 
   return 0;
 }

=== modified file 'sql/sql_delete.cc'
--- a/sql/sql_delete.cc	2013-10-16 09:38:42 +0000
+++ b/sql/sql_delete.cc	2013-12-19 08:10:00 +0000
@@ -525,12 +525,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *
       table->triggers->has_triggers(TRG_EVENT_DELETE,
                                     TRG_ACTION_AFTER))
   {
-    /*
-      The table has AFTER DELETE triggers that might access to subject table
-      and therefore might need delete to be done immediately. So we turn-off
-      the batching.
-    */
-    (void) table->file->extra(HA_EXTRA_DELETE_CANNOT_BATCH);
+    table->prepare_triggers_for_delete_stmt_or_event();
     will_batch= FALSE;
   }
   else
@@ -938,17 +933,7 @@ multi_delete::initialize_tables(JOIN *jo
 	transactional_tables= 1;
       else
 	normal_tables= 1;
-      if (tbl->triggers &&
-          tbl->triggers->has_triggers(TRG_EVENT_DELETE,
-                                      TRG_ACTION_AFTER))
-      {
-	/*
-          The table has AFTER DELETE triggers that might access to subject 
-          table and therefore might need delete to be done immediately. 
-          So we turn-off the batching.
-        */
-	(void) tbl->file->extra(HA_EXTRA_DELETE_CANNOT_BATCH);
-      }
+      tbl->prepare_triggers_for_delete_stmt_or_event();
       tbl->prepare_for_position();
       tbl->mark_columns_needed_for_delete();
     }

=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc	2013-11-01 11:00:11 +0000
+++ b/sql/sql_insert.cc	2013-12-19 08:10:00 +0000
@@ -373,48 +373,6 @@ static int check_update_fields(THD *thd,
   return 0;
 }
 
-/*
-  Prepare triggers  for INSERT-like statement.
-
-  SYNOPSIS
-    prepare_triggers_for_insert_stmt()
-      table   Table to which insert will happen
-
-  NOTE
-    Prepare triggers for INSERT-like statement by marking fields
-    used by triggers and inform handlers that batching of UPDATE/DELETE 
-    cannot be done if there are BEFORE UPDATE/DELETE triggers.
-*/
-
-void prepare_triggers_for_insert_stmt(TABLE *table)
-{
-  if (table->triggers)
-  {
-    if (table->triggers->has_triggers(TRG_EVENT_DELETE,
-                                      TRG_ACTION_AFTER))
-    {
-      /*
-        The table has AFTER DELETE triggers that might access to 
-        subject table and therefore might need delete to be done 
-        immediately. So we turn-off the batching.
-      */ 
-      (void) table->file->extra(HA_EXTRA_DELETE_CANNOT_BATCH);
-    }
-    if (table->triggers->has_triggers(TRG_EVENT_UPDATE,
-                                      TRG_ACTION_AFTER))
-    {
-      /*
-        The table has AFTER UPDATE triggers that might access to subject 
-        table and therefore might need update to be done immediately. 
-        So we turn-off the batching.
-      */ 
-      (void) table->file->extra(HA_EXTRA_UPDATE_CANNOT_BATCH);
-    }
-  }
-  table->mark_columns_needed_for_insert();
-}
-
-
 /**
   Upgrade table-level lock of INSERT statement to TL_WRITE if
   a more concurrent lock is infeasible for some reason. This is
@@ -902,7 +860,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
 
   thd->abort_on_warning= !ignore && thd->is_strict_mode();
 
-  prepare_triggers_for_insert_stmt(table);
+  table->prepare_triggers_for_insert_stmt_or_event();
+  table->mark_columns_needed_for_insert();
 
 
   if (table_list->prepare_where(thd, 0, TRUE) ||
@@ -3529,7 +3488,10 @@ select_insert::prepare(List<Item> &value
         table_list->prepare_check_option(thd));
 
   if (!res)
-     prepare_triggers_for_insert_stmt(table);
+  {
+     table->prepare_triggers_for_insert_stmt_or_event();
+     table->mark_columns_needed_for_insert();
+  }
 
   DBUG_RETURN(res);
 }

=== modified file 'sql/sql_insert.h'
--- a/sql/sql_insert.h	2011-06-30 15:46:53 +0000
+++ b/sql/sql_insert.h	2013-12-19 08:10:00 +0000
@@ -38,7 +38,6 @@ void upgrade_lock_type_for_insert(THD *t
                                   bool is_multi_insert);
 int check_that_all_fields_are_given_values(THD *thd, TABLE *entry,
                                            TABLE_LIST *table_list);
-void prepare_triggers_for_insert_stmt(TABLE *table);
 int write_record(THD *thd, TABLE *table, COPY_INFO *info);
 void kill_delayed_threads(void);
 

=== modified file 'sql/sql_load.cc'
--- a/sql/sql_load.cc	2013-11-01 11:00:11 +0000
+++ b/sql/sql_load.cc	2013-12-19 08:10:00 +0000
@@ -28,7 +28,6 @@
 #include <my_dir.h>
 #include "sql_view.h"                           // check_key_in_view
 #include "sql_insert.h" // check_that_all_fields_are_given_values,
-                        // prepare_triggers_for_insert_stmt,
                         // write_record
 #include "sql_acl.h"    // INSERT_ACL, UPDATE_ACL
 #include "log_event.h"  // Delete_file_log_event,
@@ -297,7 +296,8 @@ int mysql_load(THD *thd,sql_exchange *ex
       DBUG_RETURN(TRUE);
   }
 
-  prepare_triggers_for_insert_stmt(table);
+  table->prepare_triggers_for_insert_stmt_or_event();
+  table->mark_columns_needed_for_insert();
 
   uint tot_length=0;
   bool use_blobs= 0, use_vars= 0;

=== modified file 'sql/sql_update.cc'
--- a/sql/sql_update.cc	2013-10-16 09:38:42 +0000
+++ b/sql/sql_update.cc	2013-12-19 08:10:00 +0000
@@ -707,12 +707,7 @@ int mysql_update(THD *thd,
       table->triggers->has_triggers(TRG_EVENT_UPDATE,
                                     TRG_ACTION_AFTER))
   {
-    /*
-      The table has AFTER UPDATE triggers that might access to subject 
-      table and therefore might need update to be done immediately. 
-      So we turn-off the batching.
-    */ 
-    (void) table->file->extra(HA_EXTRA_UPDATE_CANNOT_BATCH);
+    table->prepare_triggers_for_update_stmt_or_event();
     will_batch= FALSE;
   }
   else
@@ -1610,17 +1605,7 @@ int multi_update::prepare(List<Item> &no
       table->no_keyread=1;
       table->covering_keys.clear_all();
       table->pos_in_table_list= tl;
-      if (table->triggers &&
-          table->triggers->has_triggers(TRG_EVENT_UPDATE,
-                                        TRG_ACTION_AFTER))
-      {
-	/*
-           The table has AFTER UPDATE triggers that might access to subject 
-           table and therefore might need update to be done immediately. 
-           So we turn-off the batching.
-	*/ 
-	(void) table->file->extra(HA_EXTRA_UPDATE_CANNOT_BATCH);
-      }
+      table->prepare_triggers_for_update_stmt_or_event();
     }
   }
 

=== modified file 'sql/sys_vars.cc'
--- a/sql/sys_vars.cc	2013-12-08 22:08:35 +0000
+++ b/sql/sys_vars.cc	2013-12-19 08:10:00 +0000
@@ -2605,13 +2605,13 @@ static const char *slave_run_triggers_fo
   {"NO", "YES", "LOGGING", 0};
 static Sys_var_enum Slave_run_triggers_for_rbr(
        "slave_run_triggers_for_rbr",
-       "Modes for how triggers in row-base replication on slave side will "
-       "be executed. Legal values "
-       "are NO (default), YES and LOGGING. "
-       "NO means that trigger for RBR will not be running on slave "
-       "YES and LOGGING means that triggers will be running on slave "
-       "(if there was not triggers running on the naster), LOGGING also "
-       "mens that flag about executed triggers will be written to binlog.",
+       "Modes for how triggers in row-base replication on slave side will be "
+       "executed. Legal values are NO (default), YES and LOGGING. NO means "
+       "that trigger for RBR will not be running on slave. YES and LOGGING "
+       "means that triggers will be running on slave, if there was not "
+       "triggers running on the master for the statement. LOGGING also means "
+       "results of that the executed triggers work will be written to "
+       "the binlog.",
        GLOBAL_VAR(slave_run_triggers_for_rbr), CMD_LINE(REQUIRED_ARG),
        slave_run_triggers_for_rbr_names,
        DEFAULT(SLAVE_RUN_TRIGGERS_FOR_RBR_NO));

=== modified file 'sql/table.cc'
--- a/sql/table.cc	2013-11-11 18:46:14 +0000
+++ b/sql/table.cc	2013-12-19 08:10:00 +0000
@@ -6660,6 +6660,77 @@ int TABLE::update_default_fields()
 
 
 /*
+  Prepare triggers  for INSERT-like statement.
+
+  SYNOPSIS
+    prepare_triggers_for_insert_stmt_or_event()
+
+  NOTE
+    Prepare triggers for INSERT-like statement by marking fields
+    used by triggers and inform handlers that batching of UPDATE/DELETE 
+    cannot be done if there are BEFORE UPDATE/DELETE triggers.
+*/
+
+void TABLE::prepare_triggers_for_insert_stmt_or_event()
+{
+  if (triggers)
+  {
+    if (triggers->has_triggers(TRG_EVENT_DELETE,
+                               TRG_ACTION_AFTER))
+    {
+      /*
+        The table has AFTER DELETE triggers that might access to
+        subject table and therefore might need delete to be done
+        immediately. So we turn-off the batching.
+      */
+      (void) file->extra(HA_EXTRA_DELETE_CANNOT_BATCH);
+    }
+    if (triggers->has_triggers(TRG_EVENT_UPDATE,
+                               TRG_ACTION_AFTER))
+    {
+      /*
+        The table has AFTER UPDATE triggers that might access to subject
+        table and therefore might need update to be done immediately.
+        So we turn-off the batching.
+      */
+      (void) file->extra(HA_EXTRA_UPDATE_CANNOT_BATCH);
+    }
+  }
+}
+
+
+void TABLE::prepare_triggers_for_delete_stmt_or_event()
+{
+  if (triggers &&
+      triggers->has_triggers(TRG_EVENT_DELETE,
+                             TRG_ACTION_AFTER))
+  {
+    /*
+      The table has AFTER DELETE triggers that might access to subject table
+      and therefore might need delete to be done immediately. So we turn-off
+      the batching.
+    */
+    (void) file->extra(HA_EXTRA_DELETE_CANNOT_BATCH);
+  }
+}
+
+
+void TABLE::prepare_triggers_for_update_stmt_or_event()
+{
+  if (triggers &&
+      triggers->has_triggers(TRG_EVENT_UPDATE,
+                             TRG_ACTION_AFTER))
+  {
+    /*
+      The table has AFTER UPDATE triggers that might access to subject
+      table and therefore might need update to be done immediately.
+      So we turn-off the batching.
+    */ 
+    (void) file->extra(HA_EXTRA_UPDATE_CANNOT_BATCH);
+  }
+}
+
+/*
   @brief Reset const_table flag
 
   @detail

=== modified file 'sql/table.h'
--- a/sql/table.h	2013-11-08 22:20:07 +0000
+++ b/sql/table.h	2013-12-19 08:10:00 +0000
@@ -1358,6 +1358,10 @@ public:
   ulong actual_key_flags(KEY *keyinfo);
   int update_default_fields();
   inline ha_rows stat_records() { return used_stat_records; }
+
+  void prepare_triggers_for_insert_stmt_or_event();
+  void prepare_triggers_for_delete_stmt_or_event();
+  void prepare_triggers_for_update_stmt_or_event();
 };
 
 



More information about the commits mailing list