List:Commits« Previous MessageNext Message »
From:Mats Kindahl Date:August 23 2007 1:17pm
Subject:Re: bk commit into 5.1 tree (rafal:1.2530) BUG#21842 - part3
View as plain text  
Hi Rafal,

Comments below.

/Matz

Rafal Somla wrote:
> Hi Mats,
>
> Here are more replies to your comments. I save the issue of using 
> "gotos" for a separate, last email.
>
> Mats Kindahl wrote:
>>    * You are passing in a THD instance that is already available as a
>>      member variable in the class.
>
> I'm doing this because I saw in the code that you wrote the following 
> declaration:
>
>   virtual int do_prepare_row(THD*, Relay_log_info const*, TABLE*,
>                              uchar const *row_start,
>                              uchar const **row_end) = 0;
>
> inside Write_rows_log_event class. You added THD parameter despite the 
> fact that the class contains a thd member. I thought there was some 
> reason for that and played it safe by following your example. Now, if 
> you think that Log_event::thd is the correct value to be used here, it 
> would be better to use it instead of passing thd as method argument. 
> I'll change the code then.

Yes, I think the code I wrote is wrong in this aspect (I think it is a 
result of some of the functions not being member functions earlier). 
Just to be sure, remove the parameter from the declaration/definition, 
and then go though each error to make sure that it's passing the value 
of Log_event::thd directly or indirectly.

>
>
>>    * Add tests to check the result for both fewer and more columns on
>>      the slave's table. The "fewer columns on the slave" tests will
>>      fail now, but when you merge you have WL#3228 to handle, so you
>>      can just as well add those tests right now.
>
> I'm bit reluctant to do that as it will introduce dependency of my 
> patch on WL#3228. That is, after doing it, if one pushes my patch to a 
> tree which doesn't contain WL#3228, the tree will get broken (failing 
> tests). I think it is better if tests for "less columns on slave" are 
> introduced in the patch for WL#3228 or in a separate patch to come 
> after both WL#3228 and BUG#21842 fix. Actually I can prepare such a 
> patch to add "less slave colums" case to my rpl_ndb_2other test.

OK. That is fine as well, just don't forget to test both cases after the 
merge.

>
>>    * Avoid qualifying parameters with 'const' in the definition and
>>      without in the declaration. This is correct according to the
>>      standard, but we have compilers that require the signature to be
>>      exactly the same, even the cv-qualifiers for the parameters [sic].
>
> Ok, I'll check that declarations and definitions agree. You also wrote:
>
> >> +int Write_rows_log_event::do_exec_row(THD *thd,
> >> +                                      const
> >> Slave_reporting_capability *const log)
> >>
> >
> > See [1] above.
> >
> > Also, there is a bug in some compiler (HP-UX, what else?) that requires
> > the const qualifier on the parameter to be identical to what it is in
> > the definition, which is not required. I suggest removing the 'const'
> > that is just before 'log'. For some reason, they got the idea that the
> > cv-qualification is part of the signature, even though the standard
> > clearly states that this cv-qualifier is *not* part of the function
> > type. [ISO 14882:2003, section 8.3.5].
>
> I don't understand why you want me to remove const qualifier here. 
> Wouldn't it be enough to include it in both declaration and 
> definition. After all, I'm not going to modify this pointer and I want 
> to inform compiler about that.

Either way, as long as the qualifier for the declaration and definition 
is the same.

>
>>> @@ -6028,7 +6031,9 @@ int Rows_log_event::do_apply_event(RELAY
>>>  
>>>    DBUG_ASSERT(rli->tables_to_lock == NULL && 
>>> rli->tables_to_lock_count == 0);
>>>  
>>> -  TABLE* table= 
>>>
> const_cast<RELAY_LOG_INFO*>(rli)->m_table_map.get_table(m_table_id);
>>> +  TABLE* +    table= +    m_table= 
>>>
> const_cast<RELAY_LOG_INFO*>(rli)->m_table_map.get_table(m_table_id);
>>>   
>>
>> Why not handle each assignment on a separate line? That will be much 
>> easier to read.
>>
>> m_table= const_cast....
>> TABLE *table= m_table;
>>
>
> Hmm, is really
>
> int a= 0;
> int b= a;
>
> that much easier to read than
>
> int a= b= 0; ?

No, but the line I commented on is easier to read in the first form.

>
>
>>> @@ -7044,58 +6968,89 @@ is_duplicate_key_error(int errcode)
>>>    return false;
>>>  }
>>>  
>>> +/**
>>> +  Write the current row into @c m_table.
>>>   
>>
>> What does it mean to write the current row into m_table? m_table = 
>> m_curr_row? If you could elaborate a little (just a little, this is 
>> the brief description, so it shouldn't be too long). Something like: 
>> "Unpack the contents of the current row and store it into 
>> m_table->record[0]".
>>
>
> m_table of type TABLE* represents the table on which we operate. The 
> function writes a row into this table (using its handler methods). It 
> is not just storing it in m_table->record[0]. Do you still think that 
> my description is not adequate? Then please elaborate a bit more.

This is not important, but m_table is variable holding a pointer, so I 
just find it unclear on what it means to write into a variable holding a 
pointer.

>
>>> +  error= unpack_current_row(); // TODO: how to handle errors?
>>> +
>>> +  DBUG_DUMP("record[0]", m_table->record[0],
> m_table->s->reclength);
>>> +  DBUG_PRINT_BITSET("debug", "write_set = %s", m_table->write_set);
>>> +  DBUG_PRINT_BITSET("debug", "read_set = %s", m_table->read_set);
>>>   
>>
>> Maybe remove these debug print-outs since you've got it working.
>>
>
> I'm not sure - this code is quite tricky and Andrei is working on 
> conflict detection where this type of info can be useful. If you don't 
> object I'd leave it here (and other similar places), especially that 
> the original code contained such debug info.

OK.

>
>>> @@ -7166,37 +7141,71 @@ replace_record(THD *thd, TABLE *table,
>>>         fail, so we're better off just deleting the row and inserting
>>>         the correct row.
>>>       */
>>> -    if (last_uniq_key(table, keynum) &&
>>> -        !table->file->referenced_by_foreign_key())
>>> +    if (last_uniq_key(m_table, keynum) &&
>>> +        !m_table->file->referenced_by_foreign_key())
>>>      {
>>> -      error=table->file->ha_update_row(table->record[1],
>>> -                                       table->record[0]);
>>> -      if (error && error != HA_ERR_RECORD_IS_THE_SAME)
>>> -        table->file->print_error(error, MYF(0));
>>> -      else
>>> +      DBUG_PRINT("info",("Updating row using ha_update_row()"));
>>> +      error= m_table->file->ha_update_row(m_table->record[1],
>>> +                                          m_table->record[0]);
>>> +      if (error == HA_ERR_RECORD_IS_THE_SAME)
>>> +      {
>>> +        DBUG_PRINT("info",("ignoring HA_ERR_RECORD_IS_THE_SAME ret. 
>>> value from"
>>> +                           " ha_update_row()"));
>>>          error= 0;
>>>   
>>
>> Might be an idea to use a switch here: I suspect that there will be a 
>> few more error codes to ignore. Not important, though.
>>
>
> Ok, sounds reasonable - I'll change it.
>
>>> @@ -7289,50 +7298,79 @@ record_compare_exit:
>>>    return result;
>>>  }
>>>  
>>> +/**
>>> +  Locate the current row in @c m_table.
>>>  
>>> -/*
>>> -  Find the row given by 'key', if the table has keys, or else use a 
>>> table scan
>>> -  to find (and fetch) the row.
>>> +  The current row is stored in event's row buffer, pointed by @c 
>>> m_curr_row +  member. Member @c m_width tells how many columns are 
>>> there in the row (this   
>> s/are there/there are/
>>
>>> +  number can be smaller than the number of columns in the table). 
>>> It is assumed   
>>
>> With the introduction of WL#3228: s/smaller/smaller or larger/
>>
>> I think you will run into this when merging, so better write some 
>> tests for it now and see how they are affected by the merge. No need 
>> to write any code to handle it right now, though. Better to see how 
>> the resulting merged code looks, and fix it there.
>>
>
> Ok, I'll add this as a separate patch.
>
>>> +  that event's table is already open and pointed by @c m_table.
>>> +
>>> +  If a corresponding record is found in the table it is stored in 
>>> +  @c m_table->record[0]. Note that when record is located based on 
>>> a primary +  key, it is possible that the record found differs from 
>>> the row being located.
>>> +
>>> +  If no key is specified or table does not have keys, a table scan 
>>> is used to +  find the row. In that case the row should be complete 
>>> and contain values for
>>> +  all columns. However, it can still be shorter than the table, 
>>> i.e. the table +  can contain extra columns not present in the row. +
>>> +  @returns Error code on failure, 0 on success. If success @c 
>>> m_table->record[0] +  contains the record found. Also, the internal 
>>> "cursor" of the table is +  positioned at the record found.
>>>   
>>
>> It seems that @retval is used for "enumerated" return values, and 
>> @return for more descriptive cases. I think this would be a @retval 
>> case.
>>
>>  @retval 0 Success
>>  @retval errno Error number
>>
>>  @post On success, @c m_table->record[0]....
>>
>
> OK, nice suggestion.
>
>>> +  /* Select best method for locating the row based on handler 
>>> capabilities */
>>> +
>>> +  enum { TABLE_SCAN, INDEX, POSITION } method= TABLE_SCAN;
>>> +
>>> +  if ((m_table->file->ha_table_flags() & 
>>> HA_PRIMARY_KEY_REQUIRED_FOR_POSITION) &&
>>> +      m_table->s->primary_key < MAX_KEY)
>>> +   method= POSITION;
>>> +  else if (m_table->s->keys > 0)
>>> +   method= INDEX;
>>>   
>>
>> I still don't understand why you insist on this structure.
>>
>
> What is nice about it, in my opinion, is that all the logic deciding 
> about the search method is put in one place, making it easy to 
> understand how decision is made and also easy to modify the logic. 
> Before, the code had structure:
>
> if(<conditions for first method>)
> {
>   <use first method>
> }
> else if(<conditions for second method>)
> {
>   <use second method>
> }
> else
> {
>   <use third method>
> }
>
> Given that the blocks of code are several screens long, it was 
> difficult to see when each method is selected.

Define separate functions for each method. I don't think turning it into 
a switch makes it easier to read (and yes, the original code was just as 
bad in this respect).

>
>>> +  DBUG_ASSERT(m_table != NULL);
>>> +  DBUG_ASSERT(m_table->s->fields >= m_width);
>>>   
>>
>> Good, but this will fire when you merge. No need to do anything right 
>> now (the assertion is correct), just hinting that you should remove 
>> it after you've made the merge.
>>
>
> Good to know - thanks.
>
>>> @@ -23,6 +23,10 @@
>>>  
>>>  #include <my_bitmap.h>
>>>  #include "rpl_constants.h"
>>> +#ifndef MYSQL_CLIENT
>>> +#include "rpl_record.h"
>>> +#include "rpl_reporting.h"
>>> +#endif
>>>  
>>>  #define LOG_READ_EOF    -1
>>>  #define LOG_READ_BOGUS  -2
>>> @@ -2135,7 +2139,13 @@ public:
>>>      NO_FOREIGN_KEY_CHECKS_F = (1U << 1),
>>>  
>>>      /* Value of the OPTION_RELAXED_UNIQUE_CHECKS flag in 
>>> thd->options */
>>> -    RELAXED_UNIQUE_CHECKS_F = (1U << 2)
>>> +    RELAXED_UNIQUE_CHECKS_F = (1U << 2),
>>> +
>>> +    /*   
>> /**
>>
>> This is an excellent comment for Doxygen.
>>
>>> +      Indicates that rows in this event are complete, that is contain
>>> +      values for all columns of the table.
>>> +     */
>>> +    COMPLETE_ROWS_F = (1U << 3)
>>>    };
>>>
>
> Ok, will do.
>
>
>>> @@ -1,9 +1,961 @@
>>>  
>>>  #include "mysql_priv.h"
>>> +#ifndef MYSQL_CLIENT
>>> +#include "rpl_rli.h"
>>> +#include "rpl_utility.h"
>>> +#endif
>>>  #include "log_event_old.h"
>>>  #include "rpl_record_old.h"
>>>  
>>> +#define DBUG_PRINT_BITSET(N,FRM,BS)                \
>>> +  do {                                             \
>>> +    char buf[256];                                 \
>>> +    for (uint i = 0 ; i < (BS)->n_bits ; ++i)      \
>>> +      buf[i] = bitmap_is_set((BS), i) ? '1' : '0'; \
>>> +    buf[(BS)->n_bits] = '\0';                      \
>>> +    DBUG_PRINT((N), ((FRM), buf));                 \
>>> +  } while (0)
>>>   
>>
>> Inline function?
>>
>
> This is just existing code pasted here.

OK.

>
>>> +int Write_rows_log_event_old::do_after_row_operations(TABLE *table, 
>>> int error)
>>> +{
>>> +  int local_error= 0;
>>> +  table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
>>> +  table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
>>> +  /*
>>> +    reseting the extra with +    
>>> table->file->extra(HA_EXTRA_NO_IGNORE_NO_KEY); +    fires bug#27077
>>> +    todo: explain or fix
>>> +  */
>>> +  if ((local_error= table->file->ha_end_bulk_insert()))
>>> +  {
>>> +    table->file->print_error(local_error, MYF(0));
>>> +  }
>>> +  return error? error : local_error;
>>> +}
>>>   
>>
>> I assume this is just a cut-and-paste of the old code. If not, please 
>> tell me and I'll look closer at it.
>>
>
> Yes, you are right. All old row event application code was 
> cut-and-pasted from log_event.cc to log_event_old.cc

OK. Then I won't look closer at it.

/Matz

>
> Rafal


-- 
Mats Kindahl
Lead Software Developer
Replication Team
MySQL AB, www.mysql.com


Thread
bk commit into 5.1 tree (rafal:1.2530) BUG#21842rsomla6 Jul
  • Re: bk commit into 5.1 tree (rafal:1.2530) BUG#21842Andrei Elkin10 Jul
  • Re: bk commit into 5.1 tree (rafal:1.2530) BUG#21842Mats Kindahl22 Aug
    • Re: bk commit into 5.1 tree (rafal:1.2530) BUG#21842Mats Kindahl23 Aug
    • Re: bk commit into 5.1 tree (rafal:1.2530) BUG#21842 - part 1Rafal Somla23 Aug
      • Re: bk commit into 5.1 tree (rafal:1.2530) BUG#21842 - part 1Mats Kindahl23 Aug
        • Re: bk commit into 5.1 tree (rafal:1.2530) BUG#21842 - part 1Mats Kindahl23 Aug
        • Re: bk commit into 5.1 tree (rafal:1.2530) BUG#21842 - part 1Rafal Somla23 Aug
          • Re: bk commit into 5.1 tree (rafal:1.2530) BUG#21842 - part 1Mats Kindahl23 Aug
    • Re: bk commit into 5.1 tree (rafal:1.2530) BUG#21842 - part2Rafal Somla23 Aug
      • Re: bk commit into 5.1 tree (rafal:1.2530) BUG#21842 - part2Mats Kindahl23 Aug
    • Re: bk commit into 5.1 tree (rafal:1.2530) BUG#21842 - part3Rafal Somla23 Aug
      • Re: bk commit into 5.1 tree (rafal:1.2530) BUG#21842 - part3Mats Kindahl23 Aug