List:Commits« Previous MessageNext Message »
From:magnus.blaudd Date:June 10 2011 10:26am
Subject:bzr commit into mysql-trunk branch (magnus.blaudd:3187) WL#5906
View as plain text  
#At file:///data0/magnus/mysql/trunk-wl5906-rbwr/ based on revid:jon.hauglid@stripped

 3187 magnus.blaudd@stripped	2011-06-10
      WL#5906 read before write removal (RBWR)
       - Make it possible for storage engines to optimize away
         read of record before UPDATE/DELETE in order to save
         roundtrips and allow for batching.

    modified:
      sql/handler.h
      sql/sql_delete.cc
      sql/sql_update.cc
=== modified file 'sql/handler.h'
--- a/sql/handler.h	2011-06-01 09:11:28 +0000
+++ b/sql/handler.h	2011-06-10 10:24:29 +0000
@@ -1796,6 +1796,28 @@ public:
   virtual int extra_opt(enum ha_extra_function operation, ulong cache_size)
   { return extra(operation); }
 
+  /*
+    Informs the handler if this handler support read removal
+    (could use table_flags, but patch is smaller this way)
+   */
+  virtual bool read_before_write_removal_supported(void) const
+  { return false; }
+
+  /*
+    Informs handler that it is possible to optimise away the real read
+    operation from the handler for the current table and instead
+    use a generated read to optimise simple UPDATE and DELETEs.
+  */
+  virtual bool read_before_write_removal_possible(void)
+  { return false; }
+
+  /*
+    Return the number of rows the handler has written while using
+    read before write removal
+   */
+  virtual ha_rows read_before_write_removal_rows_written(void) const
+  { DBUG_ASSERT(0); return (ha_rows) 0; }
+
   /**
     In an UPDATE or DELETE, if the row under the cursor was locked by another
     transaction, and the engine used an optimistic read of the last

=== modified file 'sql/sql_delete.cc'
--- a/sql/sql_delete.cc	2011-05-26 15:20:09 +0000
+++ b/sql/sql_delete.cc	2011-06-10 10:24:29 +0000
@@ -59,6 +59,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *
   bool          const_cond_result;
   ha_rows	deleted= 0;
   bool          reverse= FALSE;
+  bool          read_removal= false;
   bool          skip_record;
   ORDER *order= (ORDER *) ((order_list && order_list->elements) ?
                            order_list->first : NULL);
@@ -293,6 +294,31 @@ bool mysql_delete(THD *thd, TABLE_LIST *
   else
     will_batch= !table->file->start_bulk_delete();
 
+  /*
+    Read removal is possible if the selected quick read
+    method is using full unique index
+  */
+  if (select && select->quick &&
+      will_batch &&
+      !using_limit &&
+      table->file->read_before_write_removal_supported())
+  {
+    const uint idx = select->quick->index;
+    DBUG_PRINT("rbwr", ("checking index: %d", idx));
+    const KEY *key= table->key_info + idx;
+    if ((key->flags & HA_NOSAME) == HA_NOSAME)
+    {
+      DBUG_PRINT("rbwr", ("index is unique"));
+      bitmap_clear_all(&table->tmp_set);
+      table->mark_columns_used_by_index_no_reset(idx, &table->tmp_set);
+      if (bitmap_cmp(&table->tmp_set, table->read_set))
+      {
+        DBUG_PRINT("rbwr", ("using whole index, rbwr possible"));
+        read_removal=
+          table->file->read_before_write_removal_possible();
+      }
+    }
+  }
 
   table->mark_columns_needed_for_delete();
 
@@ -355,6 +381,13 @@ bool mysql_delete(THD *thd, TABLE_LIST *
       table->file->print_error(loc_error,MYF(0));
     error=1;
   }
+  if (read_removal)
+  {
+    /* Only handler knows how many records really was written */
+    DBUG_PRINT("rbwr", ("old deleted: %ld", (long)deleted));
+    deleted= table->file->read_before_write_removal_rows_written();
+    DBUG_PRINT("rbwr", ("really deleted: %ld", (long)deleted));
+  }
   THD_STAGE_INFO(thd, stage_end);
   end_read_record(&info);
   if (options & OPTION_QUICK)

=== modified file 'sql/sql_update.cc'
--- a/sql/sql_update.cc	2011-06-09 08:58:41 +0000
+++ b/sql/sql_update.cc	2011-06-10 10:24:29 +0000
@@ -158,6 +158,37 @@ static bool check_fields(THD *thd, List<
 }
 
 
+/*
+  Check if all expressions in list are constant expressions
+
+  SYNOPSIS
+    check_constant_expressions()
+    values                       List of expressions
+
+  RETURN
+    TRUE                         Only constant expressions
+    FALSE                        At least one non-constant expression
+*/
+
+static bool check_constant_expressions(List<Item> &values)
+{
+  Item *value;
+  List_iterator_fast<Item> v(values);
+  DBUG_ENTER("check_constant_expressions");
+
+  while ((value= v++))
+  {
+    if (!value->const_item())
+    {
+      DBUG_PRINT("exit", ("expression is not constant"));
+      DBUG_RETURN(FALSE);
+    }
+  }
+  DBUG_PRINT("exit", ("expression is constant"));
+  DBUG_RETURN(TRUE);
+}
+
+
 /**
   Re-read record if more columns are needed for error message.
 
@@ -423,6 +454,36 @@ int mysql_update(THD *thd,
     DBUG_RETURN(0);
   }
 
+  /*
+    Read removal is possible if the selected quick read
+    method is using full unique index
+
+    NOTE! table->read_set currently holds the columns which are
+    used for the WHERE clause(this info is most likely already
+    available in select->quick, but where?)
+  */
+  bool read_removal= false;
+  if (select && select->quick &&
+      !ignore &&
+      !using_limit &&
+      table->file->read_before_write_removal_supported())
+  {
+    const uint idx= select->quick->index;
+    DBUG_PRINT("rbwr", ("checking index: %d", idx));
+    const KEY *key= table->key_info + idx;
+    if ((key->flags & HA_NOSAME) == HA_NOSAME)
+    {
+      DBUG_PRINT("rbwr", ("index is unique"));
+      bitmap_clear_all(&table->tmp_set);
+      table->mark_columns_used_by_index_no_reset(idx, &table->tmp_set);
+      if (bitmap_cmp(&table->tmp_set, table->read_set))
+      {
+        DBUG_PRINT("rbwr", ("using full index, rbwr possible"));
+        read_removal= true;
+      }
+    }
+  }
+
   /* If running in safe sql mode, don't allow updates without keys */
   if (table->quick_keys.is_clear_all())
   {
@@ -595,6 +656,10 @@ int mysql_update(THD *thd,
     }
     if (table->key_read)
       table->restore_column_maps_after_mark_index();
+
+    /* Rows are already read -> not possible to remove */
+    DBUG_PRINT("rbwr", ("rows are already read, turning off rbwr"));
+    read_removal= false;
   }
 
   if (ignore)
@@ -634,6 +699,14 @@ int mysql_update(THD *thd,
   else
     will_batch= !table->file->start_bulk_update();
 
+  if (read_removal &&
+      will_batch &&
+      check_constant_expressions(values))
+  {
+    assert(select && select->quick);
+    read_removal= table->file->read_before_write_removal_possible();
+  }
+
   /*
     Assure that we can use position()
     if we need to create an error message.
@@ -840,6 +913,20 @@ int mysql_update(THD *thd,
     table->file->end_bulk_update();
   table->file->try_semi_consistent_read(0);
 
+  if (read_removal)
+  {
+    /* Only handler knows how many records really was written */
+    DBUG_PRINT("rbwr", ("adjusting updated: %ld, found: %ld",
+                        (long)updated, (long)found));
+
+    updated= table->file->read_before_write_removal_rows_written();
+    if (!records_are_comparable(table))
+      found= updated;
+
+    DBUG_PRINT("rbwr", ("really updated: %ld, found: %ld",
+                        (long)updated, (long)found));
+  }
+
   if (!transactional_table && updated > 0)
     thd->transaction.stmt.mark_modified_non_trans_table();
 


Attachment: [text/bzr-bundle] bzr/magnus.blaudd@oracle.com-20110610102429-nav9ppjwmf59u6xw.bundle
Thread
bzr commit into mysql-trunk branch (magnus.blaudd:3187) WL#5906magnus.blaudd10 Jun