List:Commits« Previous MessageNext Message »
From:He Zhenxing Date:July 30 2008 3:43pm
Subject:Re: bzr commit into mysql-5.1 branch (hezx:2632) Bug#37051
View as plain text  
Sven Sandberg wrote:
> Hi Zhenxing,
> 
> The patch is very good, I'm impressed. I found a couple of mistakes in 
> the patch and some speling errors, see comments inline.
> 

Thanks! And thank you for your careful and constructive review.

> /Sven
> 
> 
> He Zhenxing wrote:
> > #At file:///media/sda3/work/mysql/bzrwork/b37051/5.1-rpl-new/
> > 
> >  2632 He Zhenxing	2008-07-30
> >       BUG#37051 Replication rules not evaluated correctly
> >       
> >       The problem of this bug is that we need to get the list of tables
> >       to be updated for a multi-update statement, which requires to
> >       open all the tables referenced by the statement and resolve all
> >       the fields involved in update in order to figure out the list of
> >       tables for update. However if there are replicate filter rules,
> >       some tables might not exist on slave and result in a failure
> >       before we could examine the filter rules.
> >       
> >       I think the whole problem can not be solved on slave alone,
> >       the master must record and send the information of tables
> >       involved for update to slave, so that the slave do not need to
> >       open all the tables referencec by the multi-update statement to
> 
> referencec -> referenced
> 

OK

> >       figure out which tables are involved for udpate.
> 
> udpate -> update
> 

OK

> >       
> >       So a status variable is added to Query_log event to store the
> >       value of table map for update on master. And on slave, it will
> >       try to get the value of this variable and use it to examine
> >       filter rules without opening any tables on slav, if this values
> 
> slav -> slave
> 

OK

[snip]

> > === modified file 'sql/log_event.cc'
> > --- a/sql/log_event.cc	2008-05-30 09:12:07 +0000
> > +++ b/sql/log_event.cc	2008-07-30 09:50:27 +0000
> > @@ -1632,6 +1632,12 @@ bool Query_log_event::write(IO_CACHE* fi
> >      int2store(start, charset_database_number);
> >      start+= 2;
> >    }
> > +  if (table_map_for_update)
> > +  {
> > +    *start++= Q_TABLE_MAP_FOR_UPDATE;
> > +    int8store(start, table_map_for_update);
> > +    start+= 8;
> > +  }
> 
> The patch does not increase the size of the buffer where the table map 
> is stored, so there is a risk of buffer overflow here. See the 
> definition of the buffer in the beginning of this function.
> 

yes, miss that, good finding, thanks!

> Actually, there seems to be a few problems here even before your patch:
> 
>   - Query_log_event::write() should use MAX_LOG_EVENT_HEADER, instead of 
> computing the length of the buffer. That would avoid duplicate code.
> 
>   - More importantly, MAX_LOG_EVENT_HEADER is wrongly computed, as it 
> does not account for the type code. The formula used in 
> Query_log_event::write() is probably more correct.
> 


Agreed, I think by MAX_LOG_EVENT_HEADER, you mean
MAX_SIZE_LOG_EVENT_STATUS. I will correct the computation of
MAX_ZIE_LOG_EVENT_STATUS and use it to reserve the buffer.

>   - MAX_LOG_EVENT_HEADER and MAX_SIZE_LOG_EVENT_STATUS should probably 
> be renamed to something like MAX_QUERY_LOG_EVENT_HEADER_LENGTH, and 
> MAX_QUERY_LOG_EVENT_STATUS_VARIABLES_LENGTH, because they are specific 
> to Query_log_events.
> 

Agreed, but I'll keep it that way now.

> >    /*
> >      Here there could be code like
> >      if (command-line-option-which-says-"log_this_variable" && inited)
> > @@ -1709,7 +1715,8 @@ Query_log_event::Query_log_event(THD* th
> >     auto_increment_increment(thd_arg->variables.auto_increment_increment),
> >     auto_increment_offset(thd_arg->variables.auto_increment_offset),
> >     lc_time_names_number(thd_arg->variables.lc_time_names->number),
> > -   charset_database_number(0)
> > +   charset_database_number(0),
> > +   table_map_for_update((ulonglong)thd_arg->variables.table_map_for_update)
> >  {
> >    time_t end_time;
> >  
> > @@ -1874,7 +1881,8 @@ Query_log_event::Query_log_event(const c
> >     db(NullS), catalog_len(0), status_vars_len(0),
> >     flags2_inited(0), sql_mode_inited(0), charset_inited(0),
> >     auto_increment_increment(1), auto_increment_offset(1),
> > -   time_zone_len(0), lc_time_names_number(0), charset_database_number(0)
> > +   time_zone_len(0), lc_time_names_number(0), charset_database_number(0),
> > +   table_map_for_update(0)
> >  {
> >    ulong data_len;
> >    uint32 tmp;
> > @@ -2016,6 +2024,10 @@ Query_log_event::Query_log_event(const c
> >        charset_database_number= uint2korr(pos);
> >        pos+= 2;
> >        break;
> > +    case Q_TABLE_MAP_FOR_UPDATE:
> > +      CHECK_SPACE(pos, end, 8);
> > +      table_map_for_update= uint8korr(pos);
> > +      pos+= 8;
> 
> Missing 'break' here
> 

right, thanks!

> >      default:
> >        /* That's why you must write status vars in growing order of code */
> >        DBUG_PRINT("info",("Query_log_event has unknown status vars (first has\
> > @@ -2238,6 +2250,13 @@ void Query_log_event::print_query_header
> >                    print_event_info->delimiter);
> >      print_event_info->charset_database_number= charset_database_number;
> >    }
> > +  if (table_map_for_update)
> > +  {
> > +    char int_buf[22];
> > +    longlong10_to_str(uint8korr(&table_map_for_update), int_buf, 10);
> > +    my_b_printf(file, "SET @@session.table_map_for_update=%s%s\n",
> > +                int_buf, print_event_info->delimiter);
> > +  }
> 
> This must be a mistake? There is no @@session.table_map_for_update 
> variable. This method is invoked only from mysqlbinlog, which is not 
> subject to --replicate-* options. So I think the above 7 lines can just 
> be removed.
> 

No, this is intended, this should also work when user dump binlog by
using mysqlbinlog and feed to mysql client program. So I think I need to
define this system variable.

> >  }
> >  
> >  
> > @@ -2425,6 +2444,8 @@ int Query_log_event::do_apply_event(Rela
> >        else
> >          thd->variables.collation_database= thd->db_charset;
> >        
> > +      thd->variables.table_map_for_update= (table_map)table_map_for_update;
> > +      
> >        /* Execute the query (note that we bypass dispatch_command()) */
> >        const char* found_semicolon= NULL;
> >        mysql_parse(thd, thd->query, thd->query_length,
> &found_semicolon);
> > 
> > === modified file 'sql/log_event.h'
> > --- a/sql/log_event.h	2008-03-28 13:52:33 +0000
> > +++ b/sql/log_event.h	2008-07-30 09:50:27 +0000
> > @@ -242,6 +242,7 @@ struct sql_ex_info
> >                                     1 + 1 + 255 /* catalog */ + \
> >                                     4 /* autoinc */ + \
> >                                     6 /* charset */ + \
> > +                                   8 /* table_map_for_update */ + \
> >                                     MAX_TIME_ZONE_NAME_LENGTH)
> 
> As mentioned above, this computation is wrong (before your patch) 
> because it does not account for the one-byte type codes.
> 

yes, will fix this

> >  #define MAX_LOG_EVENT_HEADER   ( /* in order of Query_log_event::write */ \
> >    LOG_EVENT_HEADER_LEN + /* write_header */ \
> > @@ -306,6 +307,8 @@ struct sql_ex_info
> >  #define Q_LC_TIME_NAMES_CODE    7
> >  
> >  #define Q_CHARSET_DATABASE_CODE 8
> > +
> > +#define Q_TABLE_MAP_FOR_UPDATE 9
> >  /* Intvar event post-header */
> >  
> >  #define I_TYPE_OFFSET        0
> > @@ -1455,6 +1458,22 @@ protected:
> >      This field is written if it is not 0.
> >      </td>
> >    </tr>
> > +  <tr>
> > +    <td>table_map_for_update</td>
> > +    <td>Q_TABLE_MAP_FOR_UPDATE == 9</td>
> > +    <td>8 byte integer</td>
> > +
> > +    <td>The value of the table map that is to be updated by the
> > +    multi-update query statement. Every bit of this variable
> > +    represents a table, and is set to 1 if the corresponding table is
> > +    to be updated by this statement.
> > +
> > +    The value of this variable is set when executing a multi-update
> 
> I think the terminology is multi-table update.

Agree

> 
> > +    statement and used by slave to apply filter rules without opening
> > +    all the tables on slave. This is requires because some tables may
> 
> requires -> required
> 

OK

> > +    not exist on slave because of the filter rules.
> > +    </td>
> > +  </tr>
> >    </table>
> >  
> >    @subsection Query_log_event_notes_on_previous_versions Notes on Previous
> Versions
> > @@ -1548,6 +1567,11 @@ public:
> >    const char *time_zone_str;
> >    uint lc_time_names_number; /* 0 means en_US */
> >    uint charset_database_number;
> > +  /*
> > +    map for tables that will be updated for a multi-update query
> 
> multi-table update
> 

OK

> > +    statement, for other query statements, this will be zero.
> > +  */
> > +  ulonglong table_map_for_update;

[snip]

Thread
bzr commit into mysql-5.1 branch (hezx:2632) Bug#37051He Zhenxing30 Jul
  • Re: bzr commit into mysql-5.1 branch (hezx:2632) Bug#37051Sven Sandberg30 Jul
    • Re: bzr commit into mysql-5.1 branch (hezx:2632) Bug#37051He Zhenxing30 Jul
      • Re: bzr commit into mysql-5.1 branch (hezx:2632) Bug#37051He Zhenxing30 Jul
    • Re: bzr commit into mysql-5.1 branch (hezx:2632) Bug#37051Ingo Strüwing30 Jul
      • Re: bzr commit into mysql-5.1 branch (hezx:2632) Bug#37051Sven Sandberg30 Jul
        • Re: bzr commit into mysql-5.1 branch (hezx:2632) Bug#37051Ingo Strüwing30 Jul