Commit c6d1dee7 authored by unknown's avatar unknown
Browse files

WL 2826: Error handling of ALTER TABLE for partitioning

Make lots of fixes to handle the most complex case of reorganising
of partitions where two-phased processes are needed in some cases.


sql/ha_partition.cc:
  Rewrote the rename partitions and drop partitions to align with how
  the table log handles things.
sql/handler.h:
  Added new entry to partition_element to keep track of log entry for
  a partition during ALTER TABLE that reorganises existing partitions.
sql/mysql_priv.h:
  Converted 'd', 'e' and so forth to constants with somewhat more
  descriptive names
  Added method to inactivate log entries
sql/sql_partition.cc:
  Fix change of partitions
sql/sql_table.cc:
  More constants with somewhat descriptive names
  Moved around some methods between internal part and external part
  Added new method to handle inactivation of log entries
parent 8ae7ef46
Loading
Loading
Loading
Loading
+68 −64
Original line number Diff line number Diff line
@@ -577,7 +577,6 @@ int ha_partition::create(const char *name, TABLE *table_arg,
int ha_partition::drop_partitions(const char *path)
{
  List_iterator<partition_element> part_it(m_part_info->partitions);
  List_iterator<partition_element> temp_it(m_part_info->temp_partitions);
  char part_name_buff[FN_REFLEN];
  uint no_parts= m_part_info->partitions.elements;
  uint part_count= 0;
@@ -585,37 +584,18 @@ int ha_partition::drop_partitions(const char *path)
  uint i= 0;
  uint name_variant;
  int  error= 0;
  bool reorged_parts= (m_reorged_parts > 0);
  bool temp_partitions= (m_part_info->temp_partitions.elements > 0);
  DBUG_ENTER("ha_partition::drop_partitions");

  if (temp_partitions)
    no_parts= m_part_info->temp_partitions.elements;
  do
  {
    partition_element *part_elem;
    if (temp_partitions)
    {
      /*
        We need to remove the reorganised partitions that were put in the
        temp_partitions-list.
      */
      part_elem= temp_it++;
      DBUG_ASSERT(part_elem->part_state == PART_TO_BE_DROPPED);
    }
    else
      part_elem= part_it++;
    if (part_elem->part_state == PART_TO_BE_DROPPED ||
        part_elem->part_state == PART_IS_CHANGED)
    partition_element *part_elem= part_it++;
    if (part_elem->part_state == PART_TO_BE_DROPPED)
    {
      handler *file;
      /*
        This part is to be dropped, meaning the part or all its subparts.
      */
      name_variant= NORMAL_PART_NAME;
      if (part_elem->part_state == PART_IS_CHANGED ||
          (part_elem->part_state == PART_TO_BE_DROPPED && temp_partitions))
        name_variant= RENAMED_PART_NAME;
      if (m_is_sub_partitioned)
      {
        List_iterator<partition_element> sub_it(part_elem->subpartitions);
@@ -627,9 +607,6 @@ int ha_partition::drop_partitions(const char *path)
          create_subpartition_name(part_name_buff, path,
                                   part_elem->partition_name,
                                   sub_elem->partition_name, name_variant);
          if (reorged_parts)
            file= m_reorged_file[part_count++];
          else
          file= m_file[part];
          DBUG_PRINT("info", ("Drop subpartition %s", part_name_buff));
          error+= file->delete_table((const char *) part_name_buff);
@@ -640,9 +617,6 @@ int ha_partition::drop_partitions(const char *path)
        create_partition_name(part_name_buff, path,
                              part_elem->partition_name, name_variant,
                              TRUE);
        if (reorged_parts)
          file= m_reorged_file[part_count++];
        else
        file= m_file[i];
        DBUG_PRINT("info", ("Drop partition %s", part_name_buff));
        error+= file->delete_table((const char *) part_name_buff);
@@ -695,6 +669,14 @@ int ha_partition::rename_partitions(const char *path)

  if (temp_partitions)
  {
    /*
      These are the reorganised partitions that have already been copied.
      We delete the partitions and log the delete by inactivating the
      delete log entry in the table log. We only need to synchronise
      these writes before moving to the next loop since there is no
      interaction among reorganised partitions, they cannot have the
      same name.
    */
    do
    {
      part_elem= temp_it++;
@@ -705,39 +687,57 @@ int ha_partition::rename_partitions(const char *path)
        {
          sub_elem= sub_it++;
          file= m_reorged_file[part_count++];
          create_subpartition_name(part_name_buff, path,
                                   part_elem->partition_name,
                                   sub_elem->partition_name,
                                   RENAMED_PART_NAME);
          create_subpartition_name(norm_name_buff, path,
                                   part_elem->partition_name,
                                   sub_elem->partition_name,
                                   NORMAL_PART_NAME);
          DBUG_PRINT("info", ("Rename subpartition from %s to %s",
                     norm_name_buff, part_name_buff));
          error+= file->rename_table((const char *) norm_name_buff,
                                     (const char *) part_name_buff);
          DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff));
          if (file->delete_table((const char *) norm_name_buff) ||
              inactivate_table_log_entry(sub_elem->log_entry->entry_pos))
            error= 1;
          else
            sub_elem->log_entry= NULL; /* Indicate success */
        } while (++j < no_subparts);
      }
      else
      {
        file= m_reorged_file[part_count++];
        create_partition_name(part_name_buff, path,
                              part_elem->partition_name, RENAMED_PART_NAME,
                              TRUE);
        create_partition_name(norm_name_buff, path,
                              part_elem->partition_name, NORMAL_PART_NAME,
                              TRUE);
        DBUG_PRINT("info", ("Rename partition from %s to %s",
                   norm_name_buff, part_name_buff));
        error+= file->rename_table((const char *) norm_name_buff,
                                   (const char *) part_name_buff);
        DBUG_PRINT("info", ("Delete partition %s", norm_name_buff));
        if (file->delete_table((const char *) norm_name_buff) ||
            inactivate_table_log_entry(sub_elem->log_entry->entry_pos))
          error= 1;
        else
          sub_elem->log_entry= NULL; /* Indicate success */
      }
    } while (++i < temp_partitions);
    VOID(sync_table_log());
  }
  i= 0;
  do
  {
    /*
       When state is PART_IS_CHANGED it means that we have created a new
       TEMP partition that is to be renamed to normal partition name and
       we are to delete the old partition with currently the normal name.
       
       We perform this operation by
       1) Delete old partition with normal partition name
       2) Signal this in table log entry
       3) Synch table log to ensure we have consistency in crashes
       4) Rename temporary partition name to normal partition name
       5) Signal this to table log entry
       It is not necessary to synch the last state since a new rename
       should not corrupt things if there was no temporary partition.

       The only other parts we need to cater for are new parts that
       replace reorganised parts. The reorganised parts were deleted
       by the code above that goes through the temp_partitions list.
       Thus the synch above makes it safe to simply perform step 4 and 5
       for those entries.
    */
    part_elem= part_it++;
    if (part_elem->part_state == PART_IS_CHANGED ||
        (part_elem->part_state == PART_IS_ADDED && temp_partitions))
@@ -759,14 +759,11 @@ int ha_partition::rename_partitions(const char *path)
          if (part_elem->part_state == PART_IS_CHANGED)
          {
            file= m_reorged_file[part_count++];
            create_subpartition_name(part_name_buff, path,
                                     part_elem->partition_name,
                                     sub_elem->partition_name,
                                     RENAMED_PART_NAME);
            DBUG_PRINT("info", ("Rename subpartition from %s to %s",
                       norm_name_buff, part_name_buff));
            error+= file->rename_table((const char *) norm_name_buff,
                                       (const char *) part_name_buff);
            DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff));
            if (file->delete_table((const char *) norm_name_buff) ||
              inactivate_table_log_entry(sub_elem->log_entry->entry_pos))
              error= 1;
            VOID(synch_table_log());
          }
          file= m_new_file[part];
          create_subpartition_name(part_name_buff, path,
@@ -775,8 +772,12 @@ int ha_partition::rename_partitions(const char *path)
                                   TEMP_PART_NAME);
          DBUG_PRINT("info", ("Rename subpartition from %s to %s",
                     part_name_buff, norm_name_buff));
          error+= file->rename_table((const char *) part_name_buff,
                                     (const char *) norm_name_buff);
          if (file->rename_table((const char *) norm_name_buff,
                                 (const char *) part_name_buff) ||
              inactivate_table_log_entry(sub_elem->log_entry->entry_pos))
            error= 1;
          else
            sub_elem->log_entry= NULL;
        } while (++j < no_subparts);
      }
      else
@@ -787,13 +788,11 @@ int ha_partition::rename_partitions(const char *path)
        if (part_elem->part_state == PART_IS_CHANGED)
        {
          file= m_reorged_file[part_count++];
          create_partition_name(part_name_buff, path,
                                part_elem->partition_name, RENAMED_PART_NAME,
                                TRUE);
          DBUG_PRINT("info", ("Rename partition from %s to %s",
                     norm_name_buff, part_name_buff));
          error+= file->rename_table((const char *) norm_name_buff,
                                     (const char *) part_name_buff);
          DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff));
          if (file->delete_table((const char *) norm_name_buff) ||
            inactivate_table_log_entry(part_elem->log_entry->entry_pos))
            error= 1;
          VOID(synch_table_log());
        }
        file= m_new_file[i];
        create_partition_name(part_name_buff, path,
@@ -801,11 +800,16 @@ int ha_partition::rename_partitions(const char *path)
                              TRUE);
        DBUG_PRINT("info", ("Rename partition from %s to %s",
                   part_name_buff, norm_name_buff));
        error+= file->rename_table((const char *) part_name_buff,
                                  (const char *) norm_name_buff);
        if (file->rename_table((const char *) norm_name_buff,
                               (const char *) part_name_buff) ||
            inactivate_table_log_entry(part_elem->log_entry->entry_pos))
          error= 1;
        else
          part_elem->log_entry= NULL;
      }
    }
  } while (++i < no_parts);
  VOID(synch_table_log());
  DBUG_RETURN(error);
}

+3 −1
Original line number Diff line number Diff line
@@ -667,6 +667,7 @@ class partition_element :public Sql_alloc {
  ulonglong part_min_rows;
  char *partition_name;
  char *tablespace_name;
  TABLE_LOG_MEMORY_ENTRY *log_entry;
  longlong range_value;
  char* part_comment;
  char* data_file_name;
@@ -677,7 +678,8 @@ class partition_element :public Sql_alloc {
  
  partition_element()
  : part_max_rows(0), part_min_rows(0), partition_name(NULL),
    tablespace_name(NULL), range_value(0), part_comment(NULL),
    tablespace_name(NULL), log_entry(0),
    range_value(0), part_comment(NULL),
    data_file_name(NULL), index_file_name(NULL),
    engine_type(NULL),part_state(PART_NORMAL),
    nodegroup_id(UNDEF_NODEGROUP)
+13 −0
Original line number Diff line number Diff line
@@ -1177,6 +1177,8 @@ typedef struct st_table_log_entry
  uint next_entry;
  char action_type;
  char entry_type;
  char phase;
  char not_used;
} TABLE_LOG_ENTRY;

typedef struct st_table_log_memory_entry
@@ -1187,11 +1189,22 @@ typedef struct st_table_log_memory_entry
  struct st_table_log_memory_entry *next_active_log_entry;
} TABLE_LOG_MEMORY_ENTRY;

#define TLOG_EXECUTE_CODE 'e'
#define TLOG_LOG_ENTRY_CODE 'l'
#define TLOG_IGNORE_LOG_ENTRY_CODE 'i'

#define TLOG_DELETE_ACTION_CODE 'd'
#define TLOG_RENAME_ACTION_CODE 'r'
#define TLOG_REPLACE_ACTION_CODE 's'

#define TLOG_HANDLER_TYPE_LEN 32

bool write_table_log_entry(TABLE_LOG_ENTRY *table_log_entry,
                           TABLE_LOG_MEMORY_ENTRY **active_entry);
bool write_execute_table_log_entry(uint first_entry,
                                   bool complete,
                                   TABLE_LOG_MEMORY_ENTRY **active_entry);
bool inactivate_table_log_entry(uint entry_no);
void release_table_log_memory_entry(TABLE_LOG_MEMORY_ENTRY *log_entry);
void release_table_log();
void execute_table_log_recovery();
+97 −6
Original line number Diff line number Diff line
@@ -5135,9 +5135,9 @@ write_log_rename_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt,
  DBUG_ENTER("write_log_rename_frm");

  if (rename_flag)
    table_log_entry.action_type= 'r';
    table_log_entry.action_type= TLOG_RENAME_ACTION_CODE;
  else
    table_log_entry.action_type= 'd';
    table_log_entry.action_type= TLOG_DELETE_ACTION_CODE;
  table_log_entry.next_entry= next_entry;
  table_log_entry.handler_type= "frm";
  table_log_entry.name= to_path;
@@ -5160,6 +5160,18 @@ write_log_rename_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt,
  RETURN VALUES
    TRUE                     Error
    FALSE                    Success
  DESCRIPTION
    This code is used to perform safe ADD PARTITION for HASH partitions
    and COALESCE for HASH partitions and REORGANIZE for any type of
    partitions.
    We prepare entries for all partitions except the reorganised partitions
    in REORGANIZE partition, those are handled by
    write_log_dropped_partitions. For those partitions that are replaced
    special care is needed to ensure that this is performed correctly and
    this requires a two-phased approach with this log as a helper for this.

    This code is closely intertwined with the code in rename_partitions in
    the partition handler.
*/

static
@@ -5167,7 +5179,84 @@ bool
write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
                             uint *next_entry, const char *path)
{
  TABLE_LOG_ENTRY table_log_entry;
  partition_info *part_info= lpt->part_info;
  TABLE_LOG_MEMORY_ENTRY *log_entry;
  char tmp_path[FN_LEN];
  char normal_path[FN_LEN];
  List_iterator<partition_element> part_it(part_info->partitions);
  uint temp_partitions= part_info->temp_partitions.elements;
  uint no_elements= part_info->partitions.elements;
  uint i= 0;
  DBUG_ENTER("write_log_changed_partitions");

  do
  {
    partition_element *part_elem= part_it++;
    if (part_elem->part_state == PART_IS_CHANGED ||
        (part_elem->part_state == PART_IS_ADDED && temp_partitions))
    {
      if (is_sub_partitioned(part_info))
      {
        List_iterator<partition_element> sub_it(part_elem->subpartitions);
        uint no_subparts= part_info->no_subparts;
        uint j= 0;
        do
        {
          partition_element *sub_elem= sub_it++;
          table_log_entry.next_entry= *next_entry;
          table_log_entry.handler_type=
               ha_resolve_storage_engine_name(sub_elem->engine_type);
          create_subpartition_name(tmp_path, path,
                                   part_elem->partition_name,
                                   sub_elem->partition_name,
                                   TEMP_PART_NAME);
          create_subpartition_name(normal_path, path,
                                   part_elem->partition_name,
                                   sub_elem->partition_name,
                                   NORMAL_PART_NAME);
          table_log_entry.name= norm_path;
          table_log_entry.from_name= tmp_path;
          if (part_elem->part_state == PART_IS_CHANGED)
            table_log_entry->action_type= TLOG_REPLACE_ACTION_CODE;
          else
            table_log_entry->action_type= TLOG_RENAME_ACTION_CODE;
          if (write_table_log_entry(&table_log_entry, &log_entry))
          {
            DBUG_RETURN(TRUE);
          }
          *next_entry= log_entry->entry_pos;
          sub_elem->log_entry= log_entry;
          insert_part_info_log_entry_list(part_info, log_entry);
        } while (++j < no_subparts);
      }
      else
      {
        table_log_entry.next_entry= *next_entry;
        table_log_entry.handler_type=
               ha_resolve_storage_engine_name(part_elem->engine_type);
        create_partition_name(tmp_path, path,
                              part_elem->partition_name,
                              TEMP_PART_NAME, TRUE);
        create_partition_name(normal_path, path,
                              part_elem->partition_name,
                              NORMAL_PART_NAME, TRUE);
        table_log_entry.name= normal_path;
        table_log_entry.from_name= tmp_path;
        if (part_elem->part_state == PART_IS_CHANGED)
          table_log_entry->action_type= TLOG_REPLACE_ACTION_CODE;
        else
          table_log_entry->action_type= TLOG_RENAME_ACTION_CODE;
        if (write_table_log_entry(&table_log_entry, &log_entry))
        {
          DBUG_RETURN(TRUE);
        }
        *next_entry= log_entry->entry_pos;
        part_elem->table_log_entry= log_entry;
        insert_part_info_log_entry_list(part_info, log_entry);
      }
    }
  } while (++i < no_elements)
  DBUG_RETURN(FALSE);
}

@@ -5200,7 +5289,7 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
  uint i= 0;
  DBUG_ENTER("write_log_dropped_partitions");

  table_log_entry.action_type= 'd';
  table_log_entry.action_type= TLOG_DELETE_ACTION_CODE;
  if (temp_list)
    no_elements= no_temp_partitions;
  while (no_elements--)
@@ -5242,6 +5331,8 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
            DBUG_RETURN(TRUE);
          }
          *next_entry= log_entry->entry_pos;
          if (temp_list)
            sub_elem->table_log_entry= log_entry;
          insert_part_info_log_entry_list(part_info, log_entry);
        } while (++j < no_subparts);
      }
@@ -5259,6 +5350,8 @@ write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
          DBUG_RETURN(TRUE);
        }
        *next_entry= log_entry->entry_pos;
        if (temp_list)
          part_elem->table_log_entry= log_entry;
        insert_part_info_log_entry_list(part_info, log_entry);
      }
    }
@@ -5961,10 +6054,8 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
        ERROR_INJECT_CRASH("crash_change_partition_8") ||
        (close_open_tables_and_downgrade(lpt), FALSE) ||
        ERROR_INJECT_CRASH("crash_change_partition_9") ||
        mysql_drop_partitions(lpt) ||
        ERROR_INJECT_CRASH("crash_change_partition_10") ||
        write_log_completed(lpt) ||
        ERROR_INJECT_CRASH("crash_change_partition_11") ||
        ERROR_INJECT_CRASH("crash_change_partition_10") ||
        (mysql_wait_completed_table(lpt, table), FALSE))
    {
      abort();
+146 −68

File changed.

Preview size limit exceeded, changes collapsed.