List:Commits« Previous MessageNext Message »
From:Andrei Elkin Date:February 14 2007 5:45pm
Subject:bk commit into 5.1 tree (aelkin:1.2409) BUG#22583
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of elkin. When elkin does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2007-02-14 19:45:48+02:00, aelkin@stripped +3 -0
  wl3557 conflict detection
  
  auxilary cset consisting of merging  bug#22583 fixes (Feb 12th) with my local tree.
  To be removed after the bug's patch will be merged with 5.1-rpl.

  sql/log_event.cc@stripped, 2007-02-14 19:45:40+02:00, aelkin@stripped +73 -58
    new format for rbr events

  sql/log_event.h@stripped, 2007-02-14 19:45:40+02:00, aelkin@stripped +16 -3
    new event types

  sql/sql_class.cc@stripped, 2007-02-14 19:45:41+02:00, aelkin@stripped +98 -15
    new pack

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	aelkin
# Host:	dsl-kpogw6-fe8ddc00-181.dhcp.inet.fi
# Root:	/home/elkin/MySQL/TEAM/FIXES/5.1/wl3557_conflict_detection

--- 1.262/sql/log_event.cc	2007-02-14 19:45:58 +02:00
+++ 1.263/sql/log_event.cc	2007-02-14 19:45:58 +02:00
@@ -5519,18 +5519,18 @@ int Rows_log_event::do_add_row_data(byte
   
   SYNOPSIS
     unpack_row()
-    rli     Relay log info
-    table   Table to unpack into
-    colcnt  Number of columns to read from record
-    row     Packed row data
-    cols    Pointer to columns data to fill in
-    row_end Pointer to variable that will hold the value of the
-            one-after-end position for the row
+    rli      Relay log info
+    table    Table to unpack into
+    colcnt   Number of columns to read from record
+    row_data Packed row data
+    cols     Pointer to columns data to fill in
+    row_end  Pointer to variable that will hold the value of the
+             one-after-end position for the row
     master_reclength
-            Pointer to variable that will be set to the length of the
-            record on the master side
-    rw_set  Pointer to bitmap that holds either the read_set or the
-            write_set of the table
+             Pointer to variable that will be set to the length of the
+             record on the master side
+    rw_set   Pointer to bitmap that holds either the read_set or the
+             write_set of the table
 
   DESCRIPTION
 
@@ -5558,68 +5558,79 @@ int Rows_log_event::do_add_row_data(byte
 static int
 unpack_row(RELAY_LOG_INFO *rli,
            TABLE *table, uint const colcnt,
-           char const *row, MY_BITMAP const *cols,
-           char const **row_end, ulong *master_reclength,
+           char const *const row_data, MY_BITMAP const *cols,
+           char const **const row_end, ulong *const master_reclength,
            MY_BITMAP* const rw_set, Log_event_type const event_type)
 {
   byte *const record= table->record[0];
   DBUG_ENTER("unpack_row");
-  DBUG_ASSERT(record && row);
-  DBUG_PRINT("enter", ("row: 0x%lx  table->record[0]: 0x%lx", (long) row, (long) record));
-  my_size_t master_null_bytes= table->s->null_bytes;
-
-  if (colcnt != table->s->fields)
-  {
-    Field **fptr= &table->field[colcnt-1];
-    do
-      master_null_bytes= (*fptr)->last_null_byte();
-    while (master_null_bytes == Field::LAST_NULL_BYTE_UNDEF &&
-           fptr-- > table->field);
-
-    /*
-      If master_null_bytes is LAST_NULL_BYTE_UNDEF (0) at this time,
-      there were no nullable fields nor BIT fields at all in the
-      columns that are common to the master and the slave. In that
-      case, there is only one null byte holding the X bit.
+  DBUG_ASSERT(record && row_data);
+  my_ptrdiff_t const offset= record - (byte*) table->record[0];
+  my_size_t const master_null_byte_count= (bitmap_bits_set(cols) + 7) / 8;
+  int error= 0;
 
-      OBSERVE! There might still be nullable columns following the
-      common columns, so table->s->null_bytes might be greater than 1.
-     */
-    if (master_null_bytes == Field::LAST_NULL_BYTE_UNDEF)
-      master_null_bytes= 1;
-  }
+  char const *null_ptr= row_data;
+  char const *pack_ptr= row_data + master_null_byte_count;
 
-  DBUG_ASSERT(master_null_bytes <= table->s->null_bytes);
-  memcpy(record, row, master_null_bytes);            // [1]
-  int error= 0;
+  bitmap_clear_all(rw_set);
 
-  bitmap_set_all(rw_set);
+  memcpy(record, table->s->default_values, table->s->null_bytes);
 
   Field **const begin_ptr = table->field;
   Field **field_ptr;
-  char const *ptr= row + master_null_bytes;
   Field **const end_ptr= begin_ptr + colcnt;
+
+  DBUG_ASSERT(null_ptr < row_data + master_null_byte_count);
+
+  // Mask to mask out the correct bit among the null bits
+  unsigned int null_mask= 1U;
+  // The "current" null bits
+  unsigned int null_bits= *null_ptr++;
   for (field_ptr= begin_ptr ; field_ptr < end_ptr ; ++field_ptr)
   {
     Field *const f= *field_ptr;
 
     if (bitmap_is_set(cols, field_ptr -  begin_ptr))
     {
-      DBUG_ASSERT((const char *)table->record[0] <= f->ptr);
-      DBUG_ASSERT(f->ptr < ((const char *)table->record[0] + table->s->reclength +
-                            (f->pack_length_in_rec() == 0)));
-
-      DBUG_PRINT("info", ("unpacking column '%s' to 0x%lx", f->field_name,
-                          (long) f->ptr));
-      ptr= f->unpack(f->ptr, ptr);
+      if ((null_mask & 0xFF) == 0)
+      {
+        DBUG_ASSERT(null_ptr < row_data + master_null_byte_count);
+        null_mask= 1U;
+        null_bits= *null_ptr++;
+      }
+
+      DBUG_ASSERT(null_mask & 0xFF); // One of the 8 LSB should be set
+
+
       /* Field...::unpack() cannot return 0 */
-      DBUG_ASSERT(ptr != NULL);
+      DBUG_ASSERT(pack_ptr != NULL);
+
+      if ((null_bits & null_mask) && f->maybe_null())
+        f->set_null(offset);
+      else
+      {
+        f->set_notnull(offset);
+
+        /*
+          We only unpack the field if it was non-null
+        */
+        f->move_field_offset(offset);
+        pack_ptr= f->unpack(f->ptr, pack_ptr);
+        f->move_field_offset(-offset);
+      }
+
+      bitmap_set_bit(rw_set, field_ptr - begin_ptr);
+      null_mask <<= 1;
     }
-    else
-      bitmap_clear_bit(rw_set, field_ptr - begin_ptr);
   }
 
-  *row_end = ptr;
+  /*
+    We should now have read all the null bytes, otherwise something is
+    really wrong.
+   */
+  DBUG_ASSERT(null_ptr == row_data + master_null_byte_count);
+
+  *row_end = pack_ptr;
   if (master_reclength)
   {
     if (*field_ptr)
@@ -6846,6 +6857,8 @@ static int find_and_fetch_row(TABLE *tab
 
   DBUG_ASSERT(table->in_use != NULL);
 
+  DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
+
   if ((table->file->ha_table_flags() & HA_PRIMARY_KEY_REQUIRED_FOR_POSITION) &&
       table->s->primary_key < MAX_KEY)
   {
@@ -6980,16 +6993,18 @@ static int find_and_fetch_row(TABLE *tab
     /* Continue until we find the right record or have made a full loop */
     do
     {
+      error= table->file->rnd_next(table->record[1]);
+
       /*
-        We need to set the null bytes to ensure that the filler bit
-        are all set when returning.  There are storage engines that
-        just set the necessary bits on the bytes and don't set the
-        filler bits correctly.
+        Patching the returned record since some storage engines do
+        not set the filler bits correctly.
       */
       my_ptrdiff_t const pos=
         table->s->null_bytes > 0 ? table->s->null_bytes - 1 : 0;
-      table->record[1][pos]= 0xFF;
-      error= table->file->rnd_next(table->record[1]);
+      table->record[1][pos]|= 256U - (1U << table->s->last_null_bit_pos);
+
+      DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
+      DBUG_DUMP("record[1]", table->record[1], table->s->reclength);
 
       switch (error)
       {

--- 1.145/sql/log_event.h	2007-02-14 19:45:58 +02:00
+++ 1.146/sql/log_event.h	2007-02-14 19:45:58 +02:00
@@ -467,10 +467,23 @@ enum Log_event_type
   XID_EVENT= 16,
   BEGIN_LOAD_QUERY_EVENT= 17,
   EXECUTE_LOAD_QUERY_EVENT= 18,
+
   TABLE_MAP_EVENT = 19,
-  WRITE_ROWS_EVENT = 20,
-  UPDATE_ROWS_EVENT = 21,
-  DELETE_ROWS_EVENT = 22,
+
+  /*
+    These event numbers were used for 5.1.0 to 5.1.15 and are
+    therefore obsolete.
+   */
+  PRE_GA_WRITE_ROWS_EVENT = 20,
+  PRE_GA_UPDATE_ROWS_EVENT = 21,
+  PRE_GA_DELETE_ROWS_EVENT = 22,
+
+  /*
+    These event numbers are used from 5.1.16 and forward
+   */
+  WRITE_ROWS_EVENT = 23,
+  UPDATE_ROWS_EVENT = 24,
+  DELETE_ROWS_EVENT = 25,
 
   /*
     Add new events here - right above this comment!

--- 1.306/sql/sql_class.cc	2007-02-14 19:45:58 +02:00
+++ 1.307/sql/sql_class.cc	2007-02-14 19:45:58 +02:00
@@ -2493,30 +2493,113 @@ my_size_t THD::max_row_length_blob(TABLE
 }
 
 
-my_size_t THD::pack_row(TABLE *table, MY_BITMAP const* cols, byte *row_data, 
-                        const byte *record) const
+/*
+  Pack a record of data for a table into a format suitable for
+  transfer via the binary log.
+
+  SYNOPSIS
+    THD::pack_row()
+    table     Table describing the format of the record
+    cols      Bitmap with a set bit for each column that should be
+              stored in the row
+    row_data  Pointer to memory where row will be written
+    record    Pointer to record that should be packed. It is assumed
+              that the pointer refers to either record[0] or
+              record[1], but no such check is made since the code does
+              not rely on that.
+
+  DESCRIPTION
+
+    The format for a row in transfer with N fields is the following:
+
+    ceil(N/8) null bytes:
+        One null bit for every column *regardless of whether it can be
+        null or not*. This simplifies the decoding. Observe that the
+        number of null bits is equal to the number of set bits in the
+        'cols' bitmap. The number of null bytes is the smallest number
+        of bytes necessary to store the null bits.
+
+        Padding bits are 1.
+
+    N packets:
+        Each field is stored in packed format.
+
+
+  RETURN VALUE
+
+    The number of bytes written at 'row_data'.
+ */
+my_size_t
+THD::pack_row(TABLE *table, MY_BITMAP const* cols,
+              byte *const row_data, const byte *record) const
 {
   Field **p_field= table->field, *field;
-  int n_null_bytes= table->s->null_bytes;
-  byte *ptr;
-  uint i;
+  int const null_byte_count= (bitmap_bits_set(cols) + 7) / 8;
+  byte *pack_ptr = row_data + null_byte_count;
+  byte *null_ptr = row_data;
   my_ptrdiff_t const rec_offset= record - table->record[0];
   my_ptrdiff_t const def_offset= table->s->default_values - table->record[0];
-  memcpy(row_data, record, n_null_bytes);
-  ptr= row_data+n_null_bytes;
 
-  for (i= 0 ; (field= *p_field) ; i++, p_field++)
+  /*
+    We write the null bits and the packed records using one pass
+    through all the fields. The null bytes are written little-endian,
+    i.e., the first fields are in the first byte.
+   */
+  unsigned int null_bits= (1U << 8) - 1;
+  // Mask to mask out the correct but among the null bits
+  unsigned int null_mask= 1U;
+  for ( ; (field= *p_field) ; p_field++)
   {
-    if (bitmap_is_set(cols,i))
+    DBUG_PRINT("debug", ("null_mask=%d; null_ptr=%p; row_data=%p; null_byte_count=%d",
+                         null_mask, null_ptr, row_data, null_byte_count));
+    if (bitmap_is_set(cols, p_field - table->field))
     {
-      my_ptrdiff_t const offset=
-        field->is_null(rec_offset) ? def_offset : rec_offset;
-      field->move_field_offset(offset);
-      ptr= (byte*)field->pack((char *) ptr, field->ptr);
-      field->move_field_offset(-offset);
+      my_ptrdiff_t offset;
+      if (field->is_null(rec_offset))
+      {
+        offset= def_offset;
+        null_bits |= null_mask;
+      }
+      else
+      {
+        offset= rec_offset;
+        null_bits &= ~null_mask;
+
+        /*
+          We only store the data of the field if it is non-null
+         */
+        field->move_field_offset(offset);
+        pack_ptr= (byte*)field->pack((char *) pack_ptr, field->ptr);
+        field->move_field_offset(-offset);
+      }
+
+      null_mask <<= 1;
+      if ((null_mask & 0xFF) == 0)
+      {
+        DBUG_ASSERT(null_ptr < row_data + null_byte_count);
+        null_mask = 1U;
+        *null_ptr++ = null_bits;
+        null_bits= (1U << 8) - 1;
+      }
     }
   }
-  return (static_cast<my_size_t>(ptr - row_data));
+
+  /*
+    Write the last (partial) byte, if there is one
+  */
+  if ((null_mask & 0xFF) > 1)
+  {
+    DBUG_ASSERT(null_ptr < row_data + null_byte_count);
+    *null_ptr++ = null_bits;
+  }
+
+  /*
+    The null pointer should now point to the first byte of the
+    packed data. If it doesn't, something is very wrong.
+  */
+  DBUG_ASSERT(null_ptr == row_data + null_byte_count);
+
+  return static_cast<my_size_t>(pack_ptr - row_data);
 }
 
 
Thread
bk commit into 5.1 tree (aelkin:1.2409) BUG#22583Andrei Elkin14 Feb