List:Commits« Previous MessageNext Message »
From:Jorgen Loland Date:November 8 2011 11:38am
Subject:bzr push into mysql-trunk branch (jorgen.loland:3479 to 3480) WL#5860
View as plain text  
 3480 Jorgen Loland	2011-11-08
      WL#5860: Make COST_VECT a properly encapsulated C++ class
            
      This changeset:
       * Changes name of COST_VECT to Cost_estimate
       * Encapsulates variables
       * Merges io_count and io_avg_cost into one variable: io_cost
       * Modifies code that used COST_VECT to use Cost_estimate instead
       * Adds unit tests for the Cost_estimate class
            
      This changeset does NOT change any cost calculations. It is 
      purely a refactoring to an encapsulated C++ class following
      our coding guidelines.
     @ sql/handler.cc
        Refactoring: Move from COST_VECT to Cost_estimate
     @ sql/handler.h
        Refactoring: Make COST_VECT a properly encapsulated C++ class
        with name Cost_estimate
     @ sql/opt_range.cc
        Refactoring: Move from COST_VECT to Cost_estimate
     @ sql/sql_select.cc
        Refactoring: Move from COST_VECT to Cost_estimate
     @ sql/sql_select.h
        Refactoring: Move from COST_VECT to Cost_estimate
     @ sql/table.h
        Refactoring: Move from COST_VECT to Cost_estimate
     @ storage/innobase/handler/ha_innodb.cc
        Refactoring: Move from COST_VECT to Cost_estimate
     @ storage/innobase/handler/ha_innodb.h
        Refactoring: Move from COST_VECT to Cost_estimate
     @ storage/myisam/ha_myisam.cc
        Refactoring: Move from COST_VECT to Cost_estimate
     @ storage/myisam/ha_myisam.h
        Refactoring: Move from COST_VECT to Cost_estimate
     @ unittest/gunit/CMakeLists.txt
        Added gunit test file: cost_estimate
     @ unittest/gunit/cost_estimate-t.cc
        Unit tests for class Cost_estimate

    added:
      unittest/gunit/cost_estimate-t.cc
    modified:
      sql/handler.cc
      sql/handler.h
      sql/opt_range.cc
      sql/sql_select.cc
      sql/sql_select.h
      sql/table.h
      storage/innobase/handler/ha_innodb.cc
      storage/innobase/handler/ha_innodb.h
      storage/myisam/ha_myisam.cc
      storage/myisam/ha_myisam.h
      unittest/gunit/CMakeLists.txt
 3479 Oystein Grovlen	2011-11-08
      WL#5559 -  Factor tmp table out of optimizer.
        Part 3: Unify the code for creation of temporary tables
                for GROUP BY/ORDER BY
      
      Changed JOIN::create_intermediate_table() so that it 
      can be used to create both temporary tables, and let it
      return a pointer to the created table, and use it to also
      create JOIN::exec_tmp_table2.
      	
     @ sql/sql_select.cc
        1. Extended JOIN::create_intermediate_table() with parameters
           for characteristics that vary between the two temporary
           tables.
        
        2. Changed JOIN::create_intermediate_table() to return the
           pointer to the created temporary table, instead of 
           assigning it to exec_tmp_table1.
        
        3. Moved code in JOIN::create_intermediate_table() that are
           only relevant to exec_tmp_table1 to JOIN::exec().
        
        4. Moved code in JOIN::create_intermediate_table() related
           to optimization for distinct to a new private function  
           JOIN::optimize_distinct(). (To be called from
           JOIN::exec() after creating the exec_tmp_table1
           for time being, but longer term this should be moved to
           optimization phase.)
        
        5. Call create_intermediate_table() to create 
           exec_tmp_table2.
     @ sql/sql_select.h
        Created new private function JOIN::optimize_distinct() to optimize
        distinct when used on a subset of tables in query.
        
        Changed signature of JOIN::create_intermediate table to be able to
        handle creation of both temporary tables used for sorting.

    modified:
      sql/sql_select.cc
      sql/sql_select.h
=== modified file 'sql/handler.cc'
--- a/sql/handler.cc	2011-10-21 14:59:52 +0000
+++ b/sql/handler.cc	2011-11-08 11:37:54 +0000
@@ -4563,7 +4563,8 @@ bool key_uses_partial_cols(TABLE *table,
 ha_rows 
 handler::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
                                      void *seq_init_param, uint n_ranges_arg,
-                                     uint *bufsz, uint *flags, COST_VECT *cost)
+                                     uint *bufsz, uint *flags, 
+                                     Cost_estimate *cost)
 {
   KEY_MULTI_RANGE range;
   range_seq_t seq_it;
@@ -4613,13 +4614,14 @@ handler::multi_range_read_info_const(uin
   {
     /* The following calculation is the same as in multi_range_read_info(): */
     *flags |= HA_MRR_USE_DEFAULT_IMPL;
-    cost->zero();
-    cost->avg_io_cost= 1; /* assume random seeks */
+    DBUG_ASSERT(cost->is_zero());
     if ((*flags & HA_MRR_INDEX_ONLY) && total_rows > 2)
-      cost->io_count= index_only_read_time(keyno, total_rows);
+      cost->add_io(index_only_read_time(keyno, total_rows) *
+                   Cost_estimate::IO_BLOCK_READ_COST());
     else
-      cost->io_count= read_time(keyno, n_ranges, total_rows);
-    cost->cpu_cost= total_rows * ROW_EVALUATE_COST + 0.01;
+      cost->add_io(read_time(keyno, n_ranges, total_rows) *
+                   Cost_estimate::IO_BLOCK_READ_COST());
+    cost->add_cpu(total_rows * ROW_EVALUATE_COST + 0.01);
   }
   return total_rows;
 }
@@ -4660,20 +4662,22 @@ handler::multi_range_read_info_const(uin
 */
 
 ha_rows handler::multi_range_read_info(uint keyno, uint n_ranges, uint n_rows,
-                                       uint *bufsz, uint *flags, COST_VECT *cost)
+                                       uint *bufsz, uint *flags, 
+                                       Cost_estimate *cost)
 {
   *bufsz= 0; /* Default implementation doesn't need a buffer */
 
   *flags |= HA_MRR_USE_DEFAULT_IMPL;
 
-  cost->zero();
-  cost->avg_io_cost= 1; /* assume random seeks */
+  DBUG_ASSERT(cost->is_zero());
 
   /* Produce the same cost as non-MRR code does */
   if (*flags & HA_MRR_INDEX_ONLY)
-    cost->io_count= index_only_read_time(keyno, n_rows);
+    cost->add_io(index_only_read_time(keyno, n_rows) * 
+                 Cost_estimate::IO_BLOCK_READ_COST());
   else
-    cost->io_count= read_time(keyno, n_ranges, n_rows);
+    cost->add_io(read_time(keyno, n_ranges, n_rows) *
+                 Cost_estimate::IO_BLOCK_READ_COST());
   return 0;
 }
 
@@ -5145,7 +5149,7 @@ end:
   DS-MRR implementation: multi_range_read_info() function
 */
 ha_rows DsMrr_impl::dsmrr_info(uint keyno, uint n_ranges, uint rows,
-                               uint *bufsz, uint *flags, COST_VECT *cost)
+                               uint *bufsz, uint *flags, Cost_estimate *cost)
 {  
   ha_rows res;
   uint def_flags= *flags;
@@ -5179,7 +5183,7 @@ ha_rows DsMrr_impl::dsmrr_info(uint keyn
 
 ha_rows DsMrr_impl::dsmrr_info_const(uint keyno, RANGE_SEQ_IF *seq,
                                  void *seq_init_param, uint n_ranges, 
-                                 uint *bufsz, uint *flags, COST_VECT *cost)
+                                 uint *bufsz, uint *flags, Cost_estimate *cost)
 {
   ha_rows rows;
   uint def_flags= *flags;
@@ -5240,9 +5244,8 @@ ha_rows DsMrr_impl::dsmrr_info_const(uin
 */
 
 bool DsMrr_impl::choose_mrr_impl(uint keyno, ha_rows rows, uint *flags,
-                                 uint *bufsz, COST_VECT *cost)
+                                 uint *bufsz, Cost_estimate *cost)
 {
-  COST_VECT dsmrr_cost;
   bool res;
   THD *thd= current_thd;
   if (!thd->optimizer_switch_flag(OPTIMIZER_SWITCH_MRR) ||
@@ -5257,6 +5260,7 @@ bool DsMrr_impl::choose_mrr_impl(uint ke
   
   uint add_len= table->key_info[keyno].key_length + h->ref_length; 
   *bufsz -= add_len;
+  Cost_estimate dsmrr_cost;
   if (get_disk_sweep_mrr_cost(keyno, rows, *flags, bufsz, &dsmrr_cost))
     return TRUE;
   *bufsz += add_len;
@@ -5274,7 +5278,7 @@ bool DsMrr_impl::choose_mrr_impl(uint ke
       dsmrr_cost.total_cost() > cost->total_cost())
     dsmrr_cost= *cost;
 
-  if (force_dsmrr || dsmrr_cost.total_cost() <= cost->total_cost())
+  if (force_dsmrr || (dsmrr_cost.total_cost() <= cost->total_cost()))
   {
     *flags &= ~HA_MRR_USE_DEFAULT_IMPL;  /* Use the DS-MRR implementation */
     *flags &= ~HA_MRR_SORTED;          /* We will return unordered output */
@@ -5290,7 +5294,8 @@ bool DsMrr_impl::choose_mrr_impl(uint ke
 }
 
 
-static void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, COST_VECT *cost);
+static void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, 
+                                    Cost_estimate *cost);
 
 
 /**
@@ -5308,7 +5313,8 @@ static void get_sort_and_sweep_cost(TABL
 */
 
 bool DsMrr_impl::get_disk_sweep_mrr_cost(uint keynr, ha_rows rows, uint flags,
-                                         uint *buffer_size, COST_VECT *cost)
+                                         uint *buffer_size, 
+                                         Cost_estimate *cost)
 {
   ulong max_buff_entries, elem_size;
   ha_rows rows_in_last_step;
@@ -5329,7 +5335,8 @@ bool DsMrr_impl::get_disk_sweep_mrr_cost
     non-full buffer
   */
   rows_in_last_step= rows % max_buff_entries;
-
+  
+  DBUG_ASSERT(cost->is_zero());
   /* Adjust buffer size if we expect to use only part of the buffer */
   if (n_full_steps)
   {
@@ -5338,24 +5345,35 @@ bool DsMrr_impl::get_disk_sweep_mrr_cost
   }
   else
   {
-    cost->zero();
     *buffer_size= max(*buffer_size, 
                       (size_t)(1.2*rows_in_last_step) * elem_size + 
                       h->ref_length + table->key_info[keynr].key_length);
   }
 
-  COST_VECT last_step_cost;
+  Cost_estimate last_step_cost;
   get_sort_and_sweep_cost(table, rows_in_last_step, &last_step_cost);
-  cost->add(&last_step_cost);
+  (*cost)+= last_step_cost;
 
+  /*
+    With the old COST_VECT, memory cost was part of total_cost() but
+    that's not the case with Cost_estimate. Introducing Cost_estimate
+    shall not change any costs, hence the memory cost is added as if
+    it was CPU cost below. To be reconsidered when DsMRR costs are
+    refactored.
+  */
   if (n_full_steps != 0)
-    cost->mem_cost= *buffer_size;
+  {
+    cost->add_mem(*buffer_size);
+    cost->add_cpu(*buffer_size);
+  }
   else
-    cost->mem_cost= rows_in_last_step * elem_size;
-  
+  {
+    cost->add_mem(rows_in_last_step * elem_size);
+    cost->add_cpu(rows_in_last_step * elem_size);
+  }  
   /* Total cost of all index accesses */
   index_read_cost= h->index_only_read_time(keynr, rows);
-  cost->add_io(index_read_cost, 1 /* Random seeks */);
+  cost->add_io(index_read_cost * Cost_estimate::IO_BLOCK_READ_COST());
   return FALSE;
 }
 
@@ -5376,8 +5394,9 @@ bool DsMrr_impl::get_disk_sweep_mrr_cost
 */
 
 static 
-void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, COST_VECT *cost)
+void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, Cost_estimate *cost)
 {
+  DBUG_ASSERT(cost->is_zero());
   if (nrows)
   {
     get_sweep_read_cost(table, nrows, FALSE, cost);
@@ -5385,10 +5404,8 @@ void get_sort_and_sweep_cost(TABLE *tabl
     double cmp_op= rows2double(nrows) * ROWID_COMPARE_COST;
     if (cmp_op < 3)
       cmp_op= 3;
-    cost->cpu_cost += cmp_op * log2(cmp_op);
+    cost->add_cpu(cmp_op * log2(cmp_op));
   }
-  else
-    cost->zero();
 }
 
 
@@ -5436,15 +5453,16 @@ void get_sort_and_sweep_cost(TABLE *tabl
 */
 
 void get_sweep_read_cost(TABLE *table, ha_rows nrows, bool interrupted, 
-                         COST_VECT *cost)
+                         Cost_estimate *cost)
 {
   DBUG_ENTER("get_sweep_read_cost");
 
-  cost->zero();
+  DBUG_ASSERT(cost->is_zero());
   if (table->file->primary_key_is_clustered())
   {
-    cost->io_count= table->file->read_time(table->s->primary_key, (uint)nrows, 
-                                           nrows);
+    cost->add_io(table->file->read_time(table->s->primary_key,
+                                        (uint)nrows, nrows) *
+                 Cost_estimate::IO_BLOCK_READ_COST());
   }
   else
   {
@@ -5459,14 +5477,13 @@ void get_sweep_read_cost(TABLE *table, h
 
     DBUG_PRINT("info",("sweep: nblocks=%g, busy_blocks=%g", n_blocks,
                        busy_blocks));
-    cost->io_count= busy_blocks;
-
-    if (!interrupted)
-    {
+    if (interrupted)
+      cost->add_io(busy_blocks * Cost_estimate::IO_BLOCK_READ_COST());
+    else
       /* Assume reading is done in one 'sweep' */
-      cost->avg_io_cost= (DISK_SEEK_BASE_COST +
-                          DISK_SEEK_PROP_COST*n_blocks/busy_blocks);
-    }
+      cost->add_io(busy_blocks * 
+                   (DISK_SEEK_BASE_COST +
+                    DISK_SEEK_PROP_COST * n_blocks / busy_blocks));
   }
   DBUG_PRINT("info",("returning cost=%g", cost->total_cost()));
   DBUG_VOID_RETURN;

=== modified file 'sql/handler.h'
--- a/sql/handler.h	2011-10-21 14:59:52 +0000
+++ b/sql/handler.h	2011-11-08 11:37:54 +0000
@@ -1053,73 +1053,96 @@ typedef struct st_range_seq_if
 uint16 &mrr_persistent_flag_storage(range_seq_t seq, uint idx);
 char* &mrr_get_ptr_by_idx(range_seq_t seq, uint idx);
 
-class COST_VECT
+/**
+  Used to store optimizer cost estimates.
+
+  The class consists of PODs only: default operator=, copy constructor
+  and destructor are used.
+ */
+class Cost_estimate
 { 
-public:
-  double io_count;     /* number of I/O                 */
-  double avg_io_cost;  /* cost of an average I/O oper.  */
-  double cpu_cost;     /* cost of operations in CPU     */
-  double mem_cost;     /* cost of used memory           */ 
-  double import_cost;  /* cost of remote operations     */
+private:
+  double io_cost;                               ///< cost of I/O operations
+  double cpu_cost;                              ///< cost of CPU operations
+  double import_cost;                           ///< cost of remote operations
+  double mem_cost;                              ///< memory used (bytes)
   
-  enum { IO_COEFF=1 };
-  enum { CPU_COEFF=1 };
-  enum { MEM_COEFF=1 };
-  enum { IMPORT_COEFF=1 };
+public:
 
-  COST_VECT() { zero(); }                              // keep gcc happy
+  /// The cost of one I/O operation
+  static double IO_BLOCK_READ_COST() { return  1.0; } 
 
-  double total_cost() 
-  {
-    return IO_COEFF*io_count*avg_io_cost + CPU_COEFF * cpu_cost +
-           MEM_COEFF*mem_cost + IMPORT_COEFF*import_cost;
+  Cost_estimate() :
+    io_cost(0),
+    cpu_cost(0),
+    import_cost(0),
+    mem_cost(0)
+  {}
+
+  /// Returns sum of time-consuming costs, i.e., not counting memory cost
+  double total_cost()      const { return io_cost + cpu_cost + import_cost; }
+  double get_io_cost()     const { return io_cost; }
+  double get_cpu_cost()    const { return cpu_cost; }
+  double get_import_cost() const { return import_cost; }
+  double get_mem_cost()    const { return mem_cost; }
+
+  /**
+    Whether or not all costs in the object are zero
+    
+    @return true if all costs are zero, false otherwise
+  */
+  bool is_zero() const
+  { 
+    return !(io_cost || cpu_cost || import_cost || mem_cost);
   }
 
-  void zero()
+  /// Reset all costs to zero
+  void reset()
   {
-    avg_io_cost= 1.0;
-    io_count= cpu_cost= mem_cost= import_cost= 0.0;
+    io_cost= cpu_cost= import_cost= mem_cost= 0;
   }
 
+  /// Multiply io, cpu and import costs by parameter
   void multiply(double m)
   {
-    io_count *= m;
+    io_cost *= m;
     cpu_cost *= m;
     import_cost *= m;
     /* Don't multiply mem_cost */
   }
 
-  void add(const COST_VECT* cost)
+  Cost_estimate& operator+= (const Cost_estimate &other)
   {
-    double io_count_sum= io_count + cost->io_count;
-    add_io(cost->io_count, cost->avg_io_cost);
-    io_count= io_count_sum;
-    cpu_cost += cost->cpu_cost;
-  }
-  void add_io(double add_io_cnt, double add_avg_cost)
-  {
-    double io_count_sum= io_count + add_io_cnt;
-    if (io_count_sum != 0.0)
-      avg_io_cost= (io_count * avg_io_cost + 
-                    add_io_cnt * add_avg_cost) / io_count_sum;
-    DBUG_ASSERT(!isnan(avg_io_cost));
-    io_count= io_count_sum;
+    io_cost+= other.io_cost;
+    cpu_cost+= other.cpu_cost;
+    import_cost+= other.import_cost;
+    mem_cost+= other.mem_cost;
+
+    return *this;
   }
 
-  /*
-    To be used when we go from old single value-based cost calculations to
-    the new COST_VECT-based.
-  */
-  void convert_from_cost(double cost)
+  Cost_estimate operator+ (const Cost_estimate &other)
   {
-    zero();
-    avg_io_cost= 1.0;
-    io_count= cost;
+    Cost_estimate result= *this;
+    result+= other;
+    return result;
   }
+
+  /// Add to IO cost
+  void add_io(double add_io_cost) { io_cost+= add_io_cost; }
+
+  /// Add to CPU cost
+  void add_cpu(double add_cpu_cost) { cpu_cost+= add_cpu_cost; }
+
+  /// Add to import cost
+  void add_import(double add_import_cost) { import_cost+= add_import_cost; }
+
+  /// Add to memory cost
+  void add_mem(double add_mem_cost) { mem_cost+= add_mem_cost; }
 };
 
 void get_sweep_read_cost(TABLE *table, ha_rows nrows, bool interrupted, 
-                         COST_VECT *cost);
+                         Cost_estimate *cost);
 
 /*
   The below two are not used (and not handled) in this milestone of this WL
@@ -1595,9 +1618,11 @@ public:
   virtual ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
                                               void *seq_init_param, 
                                               uint n_ranges, uint *bufsz,
-                                              uint *flags, COST_VECT *cost);
+                                              uint *flags, 
+                                              Cost_estimate *cost);
   virtual ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys,
-                                        uint *bufsz, uint *flags, COST_VECT *cost);
+                                        uint *bufsz, uint *flags, 
+                                        Cost_estimate *cost);
   virtual int multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
                                     uint n_ranges, uint mode,
                                     HANDLER_BUFFER *buf);
@@ -2440,16 +2465,16 @@ public:
   int dsmrr_next(char **range_info);
 
   ha_rows dsmrr_info(uint keyno, uint n_ranges, uint keys, uint *bufsz,
-                     uint *flags, COST_VECT *cost);
+                     uint *flags, Cost_estimate *cost);
 
   ha_rows dsmrr_info_const(uint keyno, RANGE_SEQ_IF *seq, 
                             void *seq_init_param, uint n_ranges, uint *bufsz,
-                            uint *flags, COST_VECT *cost);
+                            uint *flags, Cost_estimate *cost);
 private:
   bool choose_mrr_impl(uint keyno, ha_rows rows, uint *flags, uint *bufsz, 
-                       COST_VECT *cost);
+                       Cost_estimate *cost);
   bool get_disk_sweep_mrr_cost(uint keynr, ha_rows rows, uint flags, 
-                               uint *buffer_size, COST_VECT *cost);
+                               uint *buffer_size, Cost_estimate *cost);
 };
 	/* Some extern variables used with handlers */
 

=== modified file 'sql/opt_range.cc'
--- a/sql/opt_range.cc	2011-11-07 14:00:01 +0000
+++ b/sql/opt_range.cc	2011-11-08 11:37:54 +0000
@@ -840,7 +840,7 @@ static bool is_key_scan_ror(PARAM *param
 static ha_rows check_quick_select(PARAM *param, uint idx, bool index_only,
                                   SEL_ARG *tree, bool update_tbl_stats, 
                                   uint *mrr_flags, uint *bufsize,
-                                  COST_VECT *cost);
+                                  Cost_estimate *cost);
 QUICK_RANGE_SELECT *get_quick_select(PARAM *param,uint index,
                                      SEL_ARG *key_tree, uint mrr_flags, 
                                      uint mrr_buf_size, MEM_ROOT *alloc);
@@ -4281,7 +4281,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick
 
   /* Calculate cost(rowid_to_row_scan) */
   {
-    COST_VECT sweep_cost;
+    Cost_estimate sweep_cost;
     JOIN *join= param->thd->lex->select_lex.join;
     bool is_interrupted= test(join && join->tables != 1);
     get_sweep_read_cost(param->table, non_cpk_scan_records, is_interrupted,
@@ -4429,7 +4429,7 @@ skip_to_ror_scan:
   */
   double roru_total_cost;
   {
-    COST_VECT sweep_cost;
+    Cost_estimate sweep_cost;
     JOIN *join= param->thd->lex->select_lex.join;
     bool is_interrupted= test(join && join->tables != 1);
     get_sweep_read_cost(param->table, roru_total_records, is_interrupted,
@@ -4893,7 +4893,7 @@ static bool ror_intersect_add(ROR_INTERS
   DBUG_PRINT("info", ("info->total_cost: %g", info->total_cost));
   if (!info->is_covering)
   {
-    COST_VECT sweep_cost;
+    Cost_estimate sweep_cost;
     JOIN *join= info->param->thd->lex->select_lex.join;
     bool is_interrupted= test(join && join->tables == 1);
     get_sweep_read_cost(info->param->table, double2rows(info->out_rows),
@@ -5420,7 +5420,7 @@ static TRP_RANGE *get_key_scans_params(P
     if (*key)
     {
       ha_rows found_records;
-      COST_VECT cost;
+      Cost_estimate cost;
       double found_read_time;
       uint mrr_flags, buf_size;
       uint keynr= param->real_keynr[idx];
@@ -8659,7 +8659,7 @@ walk_up_n_right:
 static
 ha_rows check_quick_select(PARAM *param, uint idx, bool index_only,
                            SEL_ARG *tree, bool update_tbl_stats, 
-                           uint *mrr_flags, uint *bufsize, COST_VECT *cost)
+                           uint *mrr_flags, uint *bufsize, Cost_estimate *cost)
 {
   SEL_ARG_RANGE_SEQ seq;
   RANGE_SEQ_IF seq_if = {sel_arg_range_seq_init, sel_arg_range_seq_next, 0, 0};
@@ -9155,7 +9155,7 @@ QUICK_RANGE_SELECT *get_quick_select_for
   QUICK_RANGE *range;
   uint part;
   bool create_err= FALSE;
-  COST_VECT cost;
+  Cost_estimate cost;
 
   old_root= thd->mem_root;
   /* The following call may change thd->mem_root */
@@ -10904,7 +10904,7 @@ get_best_group_min_max(PARAM *param, SEL
       cur_index_tree= get_index_range_tree(cur_index, tree, param,
                                            &cur_param_idx);
       /* Check if this range tree can be used for prefix retrieval. */
-      COST_VECT dummy_cost;
+      Cost_estimate dummy_cost;
       uint mrr_flags= HA_MRR_USE_DEFAULT_IMPL;
       uint mrr_bufsize=0;
       cur_quick_prefix_records= check_quick_select(param, cur_param_idx, 

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2011-11-08 10:20:56 +0000
+++ b/sql/sql_select.cc	2011-11-08 11:37:54 +0000
@@ -5875,10 +5875,16 @@ static bool optimize_semijoin_nests_for_
                sizeof(st_position) * n_tables);
 
         sj_nest->nested_join->sjm.expected_rowcount= distinct_rowcount;
+        sj_nest->nested_join->sjm.materialization_cost.reset();
         sj_nest->nested_join->sjm.materialization_cost
-          .convert_from_cost(sjm_cost);
-        sj_nest->nested_join->sjm.scan_cost.convert_from_cost(scan_cost);       
-        sj_nest->nested_join->sjm.lookup_cost.convert_from_cost(row_cost);
+          .add_io(sjm_cost);
+
+        sj_nest->nested_join->sjm.scan_cost.reset();
+        if (sj_nest->nested_join->sjm.expected_rowcount > 0.0)
+          sj_nest->nested_join->sjm.scan_cost.add_io(scan_cost);
+
+        sj_nest->nested_join->sjm.lookup_cost.reset();
+        sj_nest->nested_join->sjm.lookup_cost.add_io(row_cost);
       }
     }
   }
@@ -11980,7 +11986,7 @@ static bool setup_join_buffering(JOIN_TA
                                  bool *icp_other_tables_ok)
 {
   uint flags;
-  COST_VECT cost;
+  Cost_estimate cost;
   ha_rows rows;
   uint bufsz= 4096;
   JOIN_CACHE *prev_cache;
@@ -15847,7 +15853,8 @@ void Optimize_table_order::advance_sj_st
 
   DBUG_ENTER("Optimize_table_order::advance_sj_state");
 
-  pos->prefix_cost.convert_from_cost(*current_cost);
+  pos->prefix_cost.reset();
+  pos->prefix_cost.add_io(*current_cost);
   pos->prefix_record_count= *current_rowcount;
 
   Opt_trace_array trace_choices(trace, "semijoin_strategy_choice");
@@ -16232,7 +16239,8 @@ void Optimize_table_order::advance_sj_st
   */
   if (sj_strategy != SJ_OPT_NONE)
   {
-    pos->prefix_cost.convert_from_cost(*current_cost);
+    pos->prefix_cost.reset();
+    pos->prefix_cost.add_io(*current_cost);
     pos->prefix_record_count= *current_rowcount;
   }
 

=== modified file 'sql/sql_select.h'
--- a/sql/sql_select.h	2011-11-08 10:20:56 +0000
+++ b/sql/sql_select.h	2011-11-08 11:37:54 +0000
@@ -1588,7 +1588,7 @@ typedef struct st_position : public Sql_
   
   
   /* These form a stack of partial join order costs and output sizes */
-  COST_VECT prefix_cost;
+  Cost_estimate prefix_cost;
   double    prefix_record_count;
 
   /*

=== modified file 'sql/table.h'
--- a/sql/table.h	2011-10-18 14:25:42 +0000
+++ b/sql/table.h	2011-11-08 11:37:54 +0000
@@ -2080,11 +2080,11 @@ struct Semijoin_mat_optimize
   /* Expected #rows in the materialized table */
   double expected_rowcount;
   /* Materialization cost - execute sub-join and write rows to temp.table */
-  COST_VECT materialization_cost;
+  Cost_estimate materialization_cost;
   /* Cost to make one lookup in the temptable */
-  COST_VECT lookup_cost;
+  Cost_estimate lookup_cost;
   /* Cost of scanning the materialized table */
-  COST_VECT scan_cost;
+  Cost_estimate scan_cost;
 };
 
 typedef struct st_nested_join

=== modified file 'storage/innobase/handler/ha_innodb.cc'
--- a/storage/innobase/handler/ha_innodb.cc	2011-10-27 08:20:56 +0000
+++ b/storage/innobase/handler/ha_innodb.cc	2011-11-08 11:37:54 +0000
@@ -13389,7 +13389,7 @@ ha_innobase::multi_range_read_info_const
 	uint		n_ranges,
 	uint*		bufsz,
 	uint*		flags,
-	COST_VECT*	cost)
+	Cost_estimate*	cost)
 {
 	/* See comments in ha_myisam::multi_range_read_info_const */
 	ds_mrr.init(this, table);
@@ -13404,7 +13404,7 @@ ha_innobase::multi_range_read_info(
 	uint		keys,
 	uint*		bufsz,
 	uint*		flags,
-	COST_VECT*	cost)
+	Cost_estimate*	cost)
 {
 	ds_mrr.init(this, table);
 	return(ds_mrr.dsmrr_info(keyno, n_ranges, keys, bufsz, flags, cost));

=== modified file 'storage/innobase/handler/ha_innodb.h'
--- a/storage/innobase/handler/ha_innodb.h	2011-10-21 14:59:52 +0000
+++ b/storage/innobase/handler/ha_innodb.h	2011-11-08 11:37:54 +0000
@@ -265,7 +265,7 @@ public:
 	ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF* seq,
 					   void* seq_init_param,
 					   uint n_ranges, uint* bufsz,
-					   uint* flags, COST_VECT* cost);
+					   uint* flags, Cost_estimate* cost);
 	/** Initialize multi range read and get information.
 	* @see DsMrr_impl::dsmrr_info
 	* @param keyno
@@ -278,7 +278,7 @@ public:
 	*/
 	ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys,
 				      uint* bufsz, uint* flags,
-				      COST_VECT* cost);
+				      Cost_estimate* cost);
 
 	/** Attempt to push down an index condition.
 	* @param[in] keyno	MySQL key number

=== modified file 'storage/myisam/ha_myisam.cc'
--- a/storage/myisam/ha_myisam.cc	2011-10-21 05:42:01 +0000
+++ b/storage/myisam/ha_myisam.cc	2011-11-08 11:37:54 +0000
@@ -2147,7 +2147,7 @@ int ha_myisam::multi_range_read_next(cha
 ha_rows ha_myisam::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
                                                void *seq_init_param, 
                                                uint n_ranges, uint *bufsz,
-                                               uint *flags, COST_VECT *cost)
+                                               uint *flags, Cost_estimate *cost)
 {
   /*
     This call is here because there is no location where this->table would
@@ -2161,7 +2161,7 @@ ha_rows ha_myisam::multi_range_read_info
 
 ha_rows ha_myisam::multi_range_read_info(uint keyno, uint n_ranges, uint keys,
                                          uint *bufsz, uint *flags,
-                                         COST_VECT *cost)
+                                         Cost_estimate *cost)
 {
   ds_mrr.init(this, table);
   return ds_mrr.dsmrr_info(keyno, n_ranges, keys, bufsz, flags, cost);

=== modified file 'storage/myisam/ha_myisam.h'
--- a/storage/myisam/ha_myisam.h	2011-07-04 00:25:46 +0000
+++ b/storage/myisam/ha_myisam.h	2011-11-08 11:37:54 +0000
@@ -161,9 +161,9 @@ public:
   ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
                                       void *seq_init_param, 
                                       uint n_ranges, uint *bufsz,
-                                      uint *flags, COST_VECT *cost);
+                                      uint *flags, Cost_estimate *cost);
   ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys,
-                                uint *bufsz, uint *flags, COST_VECT *cost);
+                                uint *bufsz, uint *flags, Cost_estimate *cost);
   
   /* Index condition pushdown implementation */
   Item *idx_cond_push(uint keyno, Item* idx_cond);

=== modified file 'unittest/gunit/CMakeLists.txt'
--- a/unittest/gunit/CMakeLists.txt	2011-10-13 12:33:08 +0000
+++ b/unittest/gunit/CMakeLists.txt	2011-11-08 11:37:54 +0000
@@ -240,6 +240,7 @@ SET(TESTS
   sql_list
   sql_plist
   thread_utils
+  cost_estimate
   )
 
 # Add tests (link them with gunit library and the server libraries) 

=== added file 'unittest/gunit/cost_estimate-t.cc'
--- a/unittest/gunit/cost_estimate-t.cc	1970-01-01 00:00:00 +0000
+++ b/unittest/gunit/cost_estimate-t.cc	2011-11-08 11:37:54 +0000
@@ -0,0 +1,140 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+// First include (the generated) my_config.h, to get correct platform defines,
+// then gtest.h (before any other MySQL headers), to avoid min() macros etc ...
+#include "my_config.h"
+#include <gtest/gtest.h>
+
+#include "handler.h"
+
+namespace {
+
+TEST(CostEstimateTest, Basics)
+{
+  Cost_estimate ce1;
+
+  EXPECT_EQ(0, ce1.total_cost());
+  EXPECT_TRUE(ce1.is_zero());
+
+  const double initial_io_cost= 4.5;
+
+  ce1.add_io(initial_io_cost);
+  EXPECT_FALSE(ce1.is_zero());
+  EXPECT_DOUBLE_EQ(initial_io_cost, ce1.total_cost());
+
+  const double initial_cpu_cost= 3.3;
+  ce1.add_cpu(initial_cpu_cost);
+
+  EXPECT_DOUBLE_EQ(initial_cpu_cost, ce1.get_cpu_cost());
+  EXPECT_DOUBLE_EQ(initial_io_cost, ce1.get_io_cost());
+  EXPECT_DOUBLE_EQ(initial_io_cost + initial_cpu_cost, ce1.total_cost());
+  
+  EXPECT_EQ(0, ce1.get_mem_cost());
+  EXPECT_EQ(0, ce1.get_import_cost());
+
+  const double initial_mem_cost= 7;
+  const double initial_import_cost= 11;
+  ce1.add_mem(initial_mem_cost);
+  ce1.add_import(initial_import_cost);
+
+  const double total_initial_cost= 
+    initial_io_cost + initial_cpu_cost + initial_import_cost;
+  EXPECT_DOUBLE_EQ(total_initial_cost, ce1.total_cost());
+  
+  const double added_io_cost= 1.5;
+  ce1.add_io(added_io_cost);
+  EXPECT_DOUBLE_EQ(initial_io_cost + added_io_cost, ce1.get_io_cost());
+  EXPECT_DOUBLE_EQ(total_initial_cost + added_io_cost, ce1.total_cost());
+
+  EXPECT_FALSE(ce1.is_zero());
+
+  ce1.reset();
+  EXPECT_TRUE(ce1.is_zero());
+  
+}
+
+TEST(CostEstimateTest, Operators)
+{
+  Cost_estimate ce_io;
+
+  EXPECT_EQ(0, ce_io.total_cost());
+  EXPECT_TRUE(ce_io.is_zero());
+
+  const double initial_io_cost= 4.5;
+  ce_io.add_io(initial_io_cost);
+  EXPECT_DOUBLE_EQ(initial_io_cost, ce_io.total_cost());
+
+  Cost_estimate ce_cpu;
+  const double initial_cpu_cost= 3.3;
+  ce_cpu.add_cpu(initial_cpu_cost);
+  EXPECT_DOUBLE_EQ(initial_cpu_cost, ce_cpu.total_cost());
+  EXPECT_EQ(0, ce_cpu.get_io_cost());
+  
+  // Copy CTOR
+  Cost_estimate ce_copy(ce_io);
+  const double added_io_cost= 1.5;
+  ce_io.add_io(added_io_cost); // should not add to ce_copy
+  EXPECT_DOUBLE_EQ(initial_io_cost + added_io_cost, ce_io.total_cost());
+  EXPECT_DOUBLE_EQ(initial_io_cost, ce_copy.total_cost());
+
+  // operator+=
+  ce_copy+= ce_cpu;
+  EXPECT_DOUBLE_EQ(initial_io_cost + initial_cpu_cost, ce_copy.total_cost());
+  
+  // operator+
+  Cost_estimate ce_copy2= ce_io + ce_cpu;
+  const double copy2_totcost= 
+    initial_io_cost + added_io_cost + initial_cpu_cost;
+  EXPECT_DOUBLE_EQ(copy2_totcost, ce_copy2.total_cost());
+
+  Cost_estimate ce_mem_import1;
+  const double import1_mem_cost= 3;
+  const double import1_import_cost= 5;
+  ce_mem_import1.add_mem(import1_mem_cost);
+  ce_mem_import1.add_import(import1_import_cost);
+
+  Cost_estimate ce_mem_import2;
+  const double import2_mem_cost= 11;
+  const double import2_import_cost= 13;
+  ce_mem_import2.add_mem(import2_mem_cost);
+  ce_mem_import2.add_import(import2_import_cost);
+
+  // operator+
+  Cost_estimate ce_mi_copy= ce_mem_import1 + ce_mem_import2;
+  EXPECT_DOUBLE_EQ(import1_import_cost + import2_import_cost, 
+                   ce_mi_copy.total_cost());
+  EXPECT_DOUBLE_EQ(import1_mem_cost + import2_mem_cost, 
+                   ce_mi_copy.get_mem_cost());
+  EXPECT_DOUBLE_EQ(import1_import_cost + import2_import_cost, 
+                   ce_mi_copy.get_import_cost());
+
+  // operator+=
+  ce_mi_copy+= ce_mem_import1;
+  EXPECT_DOUBLE_EQ(2*import1_import_cost + import2_import_cost, 
+                   ce_mi_copy.total_cost());
+  EXPECT_DOUBLE_EQ(2*import1_mem_cost + import2_mem_cost, 
+                   ce_mi_copy.get_mem_cost());
+  EXPECT_DOUBLE_EQ(2*import1_import_cost + import2_import_cost, 
+                   ce_mi_copy.get_import_cost());
+
+  // copy assignment
+  Cost_estimate ce_copy3;
+  ce_copy3= ce_copy2;
+  EXPECT_DOUBLE_EQ(copy2_totcost, ce_copy3.total_cost());
+}
+
+
+} //namespace

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk branch (jorgen.loland:3479 to 3480) WL#5860Jorgen Loland11 Nov