List:Internals« Previous MessageNext Message »
From:mikael Date:August 22 2005 4:03pm
Subject:bk commit into 5.1 tree (mronstrom:1.1894)
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of mikron. When mikron 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
  1.1894 05/08/22 18:03:18 mronstrom@stripped +1 -0
  Merge mikael@stripped:/home/mikael/wl2602
  into  mysql.com:/Users/mikron/wl2602

  sql/sql_table.cc
    1.265 05/08/22 18:03:09 mronstrom@stripped +0 -0
    SCCS merged

# 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:	mronstrom
# Host:	c-2f0ae253.1238-1-64736c10.cust.bredbandsbolaget.se
# Root:	/Users/mikron/wl2602/RESYNC

--- 1.264/sql/sql_table.cc	2005-08-20 22:56:46 +02:00
+++ 1.265/sql/sql_table.cc	2005-08-22 18:03:09 +02:00
@@ -43,7 +43,64 @@
 				    ha_rows *copied,ha_rows *deleted);
 static bool prepare_blob_field(THD *thd, create_field *sql_field);
 static bool check_engine(THD *thd, const char *table_name,
-                         enum db_type *new_engine);                             
+                         enum db_type *new_engine);                          
+
+class write_frm_type
+{
+  public:
+  THD *thd;
+  HA_CREATE_INFO *create_info;
+  List<create_field> *create_list;
+  List<Key> *key_list;
+  uint db_options;
+  TABLE *table;
+  KEY *key_info_buffer;
+  uint key_count;
+  uint syntax_len;
+  char *db;
+  char *table_name;
+}
+
+
+static bool mysql_write_frm(write_frm_type *wft,
+                            bool initial_write,
+                            bool create_handler_files)
+{
+  /*
+    Prepare table to prepare for writing a new frm file where the
+    partitions in add/drop state have temporarily changed their state
+  */
+  partition_info *part_info= wft->table->s->part_info;
+  char path[FN_REFLEN+1];
+  DBUG_ENTER("mysql_write_frm");
+
+  if (initial_write)
+  {
+    mysql_prepare_table(wft->thd, wft->create_info, &wft->create_list,
+                        &wft->key_list, /*tmp_table*/ 0, &wft->db_options,
+                        wft->table->file, &wft->key_info_buffer,
+                        &wft->key_count, /*select_field_count*/ 0);
+  }
+  if (!(part_syntax_buf= generate_partition_syntax(part_info,
+                                                   &syntax_len,
+                                                   TRUE)))
+  {
+    DBUG_RETURN(TRUE);
+  }
+  part_info->part_info_string= part_syntax_buf;
+  part_info->part_info_len= syntax_len;
+  build_table_path(path, sizeof(path), wft->db, wft->table_name, reg_ext);
+  if (mysql_create_frm(wft->thd, path, wft->db, wft->table_name,
+                       wft->create_info, wft->create_list, wft->key_count,
+                       wft->key_info_buffer, wft->table->file) ||
+      (create_handler_files && table->file->create_handler_files(path)))
+  {
+    DBUG_RETURN(TRUE);
+  }
+  /* Frm file have been updated to reflect the change about to happen.  */
+  DBUG_RETURN(FALSE);
+}
+
 
 /*
   SYNOPSIS
@@ -91,17 +148,20 @@
                                    uint *old_lock_level)
 {
   uint flags= RTFC_WAIT_OTHER_THREAD_FLAG | RTFC_CHECK_KILLED_FLAG;
+  int error= FALSE;
   DBUG_ENTER("abort_and_upgrade_locks");
 
   *old_lock_level= table->reginfo.lock_type;
+  VOID(pthread_mutex_lock(&LOCK_open));
   mysql_lock_abort(thd, table);
   VOID(remove_table_from_cache(thd, db, table_name, flags));
   if (thd->killed)
   {
     thd->no_warnings_for_error= 0;
-    DBUG_RETURN(TRUE);
+    error= TRUE;
   }
-  DBUG_RETURN(FALSE);
+  VOID(pthread_mutex_unlock(&LOCK_open));
+  DBUG_RETURN(error);
 }
 
 /*
@@ -3523,26 +3583,9 @@
         {
           partition_element *part_elem= alt_it++;
           tab_part_info->partitions.push_back(part_elem);
-          tab_part_info->temp_partitions.push_back(part_elem);
         } while (++part_count < no_new_partitions);
         tab_part_info->no_parts+= no_new_partitions;
       }
-      {
-        List_iterator<partition_element> tab_it(tab_part_info->partitions);
-        partition_element *part_elem= tab_it++;
-        if (is_sub_partitioned(tab_part_info))
-        {
-          List_iterator<partition_element> sub_it(part_elem->subpartitions);
-          part_elem= sub_it++;
-        }
-        if (check_partition_info(tab_part_info, part_elem->engine_type,
-                                 table->file, (ulonglong)0ULL))
-        {
-          DBUG_RETURN(TRUE);
-        }
-      }
-      create_info->db_type= DB_TYPE_PARTITION_DB;
-      thd->lex->part_info= tab_part_info;
       if (table->file->alter_table_flags() & HA_ONLINE_ADD_EMPTY_PARTITION &&
           (tab_part_info->part_type == RANGE_PARTITION ||
            tab_part_info->part_type == LIST_PARTITION))
@@ -3550,30 +3593,14 @@
         /*
           For range and list partitions add partition is simply adding a new
           empty partition to the table. If the handler support this we will
-          use the simple method of doing this. In this case we need to break
-          out the new partitions from the list again and only keep them in the
-          temporary list. Added partitions are always added at the end.
+          use the simple method of doing this.
+
+          Hash partitions can be optimised for linear hash variants. For
+          normal hash it is a full table reorganise anyways so in this
+          case there is no on-line add partition at the moment.
         */
-        {
-          List_iterator<partition_element> tab_it(tab_part_info->partitions);
-          uint part_count= 0;
-          do
-          {
-            tab_it++;
-          } while (++part_count < no_orig_partitions);
-          do
-          {
-            tab_it++;
-            tab_it.remove();
-          } while (++part_count < new_total_partitions);
-        }
-        tab_part_info->no_parts-= no_new_partitions;
         online_add_empty_partition= TRUE;
       }
-      else
-      {
-        tab_part_info->temp_partitions.empty();
-      }
     }
     else if (alter_info->flags == ALTER_DROP_PARTITION)
     {
@@ -3610,7 +3637,7 @@
             list of temporary partitions with a new state.
           */
           no_parts_found++;
-          part_elem->part_state= PART_IS_DROPPED;
+          part_elem->part_state= PART_TO_BE_DROPPED;
         }
       } while (++part_count < tab_part_info->no_parts);
       if (no_parts_found != no_parts_dropped)
@@ -4227,70 +4254,79 @@
     create_info->frm_only= 1;
 
 #ifdef HAVE_PARTITION_DB
-  if (partition_changed)
+  if (partition_changed &&
+      (online_drop_partition || online_add_partition))
   {
+    /* Set-up struct used to write frm files */
+    partition_info *part_info= table->s->part_info;
+    write_frm_type wft;
+    wft.thd= thd;
+    wft.create_info= create_info;
+    wft.create_list= create_list;
+    wft.key_list= key_list;
+    wft.db_options= 0;
+    wft.table= table;
+    wft.key_info_buffer= key_info_buffer;
+    wft.key_count= key_count;
+    wft.syntax_len= 0;
+    wft.db= db;
+    wft.table_name= table_name;
+    thd->lex->part_info= part_info;
     if (online_drop_partition)
     {
-      /*
+        /*
         Now after all checks and setting state on dropped partitions we can
         start the actual dropping of the partitions.
-        1) Lock table in TL_WRITE_ONLY to ensure all other accesses on table
-           are completed and no new ones are started until we have changed
-           the frm file.
+        1) Lock the partitions to be dropped in TL_WRITE_ONLY to ensure all
+           other accesses on the partitions are completed and no new ones
+           are started until we have changed the frm file. Other partitions
+           we can downgrade the locks to TL_WRITE_ALLOW_WRITE since they
+           are not changed in any manner.
         2) Write the new frm file where state of dropped partitions is
            changed to PART_IS_DROPPED
-        3) Perform the actual drop of the partition using the handler of the
+        3) Perform the actual drop of the partitions using the handler of the
            table.
         4) Write a new frm file of the table where the partitions are dropped
            from the table.
-
+        5) Wait for all users of the table to be completed such that we are
+           certain that all new users of the table use the new frm file.
+        6) Write binlog and return from statement (including releasing all
+           remaining locks).
       */
       uint old_lock_type;
-      partition_info *part_info= table->s->part_info;
-      char path[FN_REFLEN+1];
-      uint db_options= 0, key_count, syntax_len;
-      KEY *key_info_buffer;
-      char *part_syntax_buf;
 
-      VOID(pthread_mutex_lock(&LOCK_open));
-      if (abort_and_upgrade_lock(thd, table, db, table_name, &old_lock_type))
-      {
-        DBUG_RETURN(TRUE);
-      }
-      VOID(pthread_mutex_unlock(&LOCK_open));
-      mysql_prepare_table(thd, create_info, &create_list,
-                          &key_list, /*tmp_table*/ 0, &db_options,
-                          table->file, &key_info_buffer, &key_count,
-                          /*select_field_count*/ 0);
-      if (!(part_syntax_buf= generate_partition_syntax(part_info,
-                                                       &syntax_len,
-                                                       TRUE)))
-      {
-        DBUG_RETURN(TRUE);
-      }
-      part_info->part_info_string= part_syntax_buf;
-      part_info->part_info_len= syntax_len;
-      build_table_path(path, sizeof(path), db, table_name, reg_ext);
-      if (mysql_create_frm(thd, path, db, table_name, create_info,
-                           create_list, key_count, key_info_buffer,
-                           table->file))
+      if (abort_and_upgrade_lock(thd, table, db,
+                                 table_name, &old_lock_type))
       {
         DBUG_RETURN(TRUE);
       }
-      thd->lex->part_info= part_info;
-      build_table_path(path, sizeof(path), db, table_name, "");
-      if (table->file->drop_partitions(path))
+      /*
+        Prepare table to prepare for writing a new frm file where the
+        partitions in add/drop state have temporarily changed their state
+      */
+      if (mysql_write_frm(&wft, TRUE, FALSE))
       {
         DBUG_RETURN(TRUE);
       }
+
+      /*
+        Frm file have been updated to reflect the change about to happen.
+        Now perform the change
+      */
       {
+        char path[FN_REFLEN+1];
         List_iterator<partition_element> part_it(part_info->partitions);
         uint i= 0, remove_count= 0;
+
+        build_table_path(path, sizeof(path), db, table_name, "");
+        if (table->file->drop_partitions(path))
+        {
+          DBUG_RETURN(TRUE);
+        }
         do
         {
           partition_element *part_elem= part_it++;
-          if (is_partition_in_list(part_elem->partition_name,
-                                   alter_info->partition_names))
+          if (part_elem->part_state == PART_IS_DROPPED)
           {
             part_it.remove();
             remove_count++;
@@ -4298,30 +4334,98 @@
         } while (++i < part_info->no_parts);
         part_info->no_parts-= remove_count;
       }
-      if (!(part_syntax_buf= generate_partition_syntax(part_info,
-                                                       &syntax_len,
-                                                       TRUE)))
-      {
-        DBUG_RETURN(TRUE);
-      }
-      part_info->part_info_string= part_syntax_buf;
-      part_info->part_info_len= syntax_len;
-      build_table_path(path, sizeof(path), db, table_name, reg_ext);
-      if (mysql_create_frm(thd, path, db, table_name, create_info,
-                           create_list, key_count, key_info_buffer,
-                           table->file)  ||
-          table->file->create_handler_files(path))
+      /*
+        Now we write the final version of the frm file to reflect the
+        new partitioning after the change.
+      */
+      if (mysql_write_frm(&wft, FALSE, TRUE))
       {
         DBUG_RETURN(TRUE);
       }
-      thd->proc_info="end";
-      write_bin_log(thd, FALSE);
-      send_ok(thd);
-      DBUG_RETURN(FALSE);
+      VOID(pthread_mutex_lock(&LOCK_open));
+      /*
+        We need to ensure that any thread that has managed to open the table
+        but not yet encountered our lock on the table is also thrown out to
+        ensure that no threads see our frm changes premature to the final
+        version. The intermediate versions are only meant for use after a
+        crash and later REPAIR TABLE.
+      */
+      remove_table_from_cache(thd, db, table_name,
+                              RTFC_WAIT_OTHER_THREAD_FLAG);
+      VOID(pthread_mutex_unlock(&LOCK_open));
+    }
+    else if (online_add_partition)
+    {
+      /*
+        ADD RANGE/LIST PARTITIONS
+        1) Downgrade all locks to TL_WRITE_ALLOW_WRITE
+        2) Write the new frm file where state of added partitions is
+           changed to PART_TO_BE_ADDED
+        3) Add the new partitions
+        4) Lock all partitions in TL_WRITE_ONLY to ensure that no users
+           are still using the old partitioning scheme. Wait until all
+           ongoing users have completed before progressing.
+        5) Write a new frm file of the table where the partitions are added
+           to the table.
+        6) Write binlog and return from statement (including releasing all
+           remaining locks).
+      */
+    }
+    else if (TRUE)
+    {
+      /*
+        ADD HASH PARTITION/
+        REORGANISE PARTITION (non-NDB)
+        1) Write the new frm file where state of added partitions is
+           changed to PART_TO_BE_ADDED
+        2) Add the new partitions
+        3) Copy from the reorganised partitions to the new partitions
+        4) Lock all partitions in TL_WRITE_ONLY to ensure that no users
+           are still using the old partitioning scheme. Wait until all
+           ongoing users have completed before progressing.
+        5) Drop the reorganised partitions
+        6) Write a new frm file of the table where the partitions are
+           reorganised.
+        7) Write binlog and return from statement (including releasing all
+           remaining locks).
+      */
     }
+    else
+    {
+      /*
+        ADD HASH PARTITION/
+        REORGANISE PARTITION (NDB)
+        1) Downgrade all locks to TL_WRITE_ALLOW_WRITE
+        2) Write the new frm file where state of added partitions is
+           changed to PART_TO_BE_ADDED
+        3) Add the new partitions
+        4) Copy from the reorganised partitions to the new partitions
+        5) Write a new frm file of the table where the partitions are
+           reorganised.
+        6) Wait for all users of the table to be completed such that we are
+           certain that all new users of the table use the new frm file.
+        7) Drop the reorganised partitions
+        8) Wait for all users of the table to be completed such that we are
+           certain that all new users of the table use the new frm file.
+        9) Write binlog and return from statement (including releasing all
+           remaining locks).
+      */
+    }
+    /*
+      A final step is to write the query to the binlog and send ok to the
+      user
+    */
+    thd->proc_info="end";
+    write_bin_log(thd, FALSE);
+    send_ok(thd);
+    DBUG_RETURN(FALSE);
   }
 #endif
 
+        if (table->file->add_partitions(table, create_info, path))
+        {
+          DBUG_RETURN(TRUE);
+        }
   /*
     Handling of symlinked tables:
     If no rename:
Thread
bk commit into 5.1 tree (mronstrom:1.1894)mikael24 Aug