From: Jorgen Loland Date: June 27 2011 7:04am Subject: bzr commit into mysql-trunk branch (jorgen.loland:3237) WL#5860 List-Archive: http://lists.mysql.com/commits/139882 Message-Id: <20110627070424.3189797E@atum21.norway.sun.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============5929939996752188492==" --===============5929939996752188492== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///export/home/jl208045/mysql/wl4774/mysql-trunk-costvect-refact/ based on revid:tor.didriksen@stripped 3237 Jorgen Loland 2011-06-27 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 === modified file 'sql/handler.cc' --- a/sql/handler.cc 2011-06-09 08:58:41 +0000 +++ b/sql/handler.cc 2011-06-27 07:04:14 +0000 @@ -4506,7 +4506,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; @@ -4556,13 +4557,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; } @@ -4603,20 +4605,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; } @@ -5088,7 +5092,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; @@ -5122,7 +5126,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; @@ -5183,9 +5187,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) || @@ -5200,6 +5203,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; @@ -5217,7 +5221,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 */ @@ -5233,7 +5237,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); /** @@ -5251,7 +5256,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_full_step, rows_in_last_step; @@ -5275,6 +5281,7 @@ bool DsMrr_impl::get_disk_sweep_mrr_cost rows_in_full_step= max_buff_entries; 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) { @@ -5283,24 +5290,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; } @@ -5321,8 +5339,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); @@ -5330,10 +5349,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(); } @@ -5381,15 +5398,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 { @@ -5404,14 +5422,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-06-01 09:11:28 +0000 +++ b/sql/handler.h 2011-06-27 07:04:14 +0000 @@ -1051,73 +1051,92 @@ 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 const double IO_BLOCK_READ_COST= 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) + {} - void zero() - { - avg_io_cost= 1.0; - io_count= cpu_cost= mem_cost= import_cost= 0.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); } + /// 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 @@ -1577,9 +1596,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); @@ -2414,16 +2435,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-05-30 07:00:39 +0000 +++ b/sql/opt_range.cc 2011-06-27 07:04:14 +0000 @@ -771,7 +771,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); @@ -3882,7 +3882,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, @@ -4007,7 +4007,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, @@ -4492,7 +4492,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), @@ -4940,7 +4940,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]; @@ -8109,7 +8109,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}; @@ -8605,7 +8605,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 */ @@ -10292,7 +10292,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-06-24 09:29:07 +0000 +++ b/sql/sql_select.cc 2011-06-27 07:04:14 +0000 @@ -5296,7 +5296,7 @@ static bool optimize_semijoin_nests(JOIN &subjoin_read_time, &subjoin_out_rows); sj_nest->nested_join->sjm.materialization_cost - .convert_from_cost(subjoin_read_time); + .add_io(subjoin_read_time); sj_nest->nested_join->sjm.expected_rowcount= subjoin_out_rows; List &inner_expr_list= sj_nest->nested_join->sj_inner_exprs; @@ -5357,19 +5357,21 @@ static bool optimize_semijoin_nests(JOIN Let materialization cost include the cost to write the data into the temporary table: */ + DBUG_ASSERT(sj_nest->nested_join->sjm.materialization_cost.is_zero()); sj_nest->nested_join->sjm.materialization_cost - .add_io(subjoin_out_rows, lookup_cost); + .add_io(subjoin_out_rows * lookup_cost); /* Set the cost to do a full scan of the temptable (will need this to consider doing sjm-scan): */ - sj_nest->nested_join->sjm.scan_cost.zero(); + DBUG_ASSERT(sj_nest->nested_join->sjm.scan_cost.is_zero()); if (sj_nest->nested_join->sjm.expected_rowcount > 0.0) sj_nest->nested_join->sjm.scan_cost - .add_io(sj_nest->nested_join->sjm.expected_rowcount, lookup_cost); + .add_io(sj_nest->nested_join->sjm.expected_rowcount * lookup_cost); - sj_nest->nested_join->sjm.lookup_cost.convert_from_cost(lookup_cost); + DBUG_ASSERT(sj_nest->nested_join->sjm.lookup_cost.is_zero()); + sj_nest->nested_join->sjm.lookup_cost.add_io(lookup_cost); } } } @@ -10766,7 +10768,7 @@ uint check_join_cache_usage(JOIN_TAB *ta bool *icp_other_tables_ok) { uint flags; - COST_VECT cost; + Cost_estimate cost; ha_rows rows; uint bufsz= 4096; JOIN_CACHE *prev_cache=0; @@ -14109,7 +14111,7 @@ void Optimize_table_order::advance_sj_st DBUG_ENTER("Optimize_table_order::advance_sj_state"); - pos->prefix_cost.convert_from_cost(*current_read_time); + pos->prefix_cost.add_io(*current_read_time); pos->prefix_record_count= *current_record_count; pos->sj_strategy= SJ_OPT_NONE; @@ -14347,14 +14349,11 @@ void Optimize_table_order::advance_sj_st } else if (sjm_strategy == SJ_OPT_MATERIALIZE_LOOKUP) { - COST_VECT prefix_cost; + Cost_estimate prefix_cost; int first_tab= (int)idx - my_count_bits(emb_sj_nest->sj_inner_tables); double prefix_rec_count; if (first_tab < (int)join->const_tables) - { - prefix_cost.zero(); prefix_rec_count= 1.0; - } else { prefix_cost= join->positions[first_tab].prefix_cost; === modified file 'sql/sql_select.h' --- a/sql/sql_select.h 2011-06-24 09:29:07 +0000 +++ b/sql/sql_select.h 2011-06-27 07:04:14 +0000 @@ -1511,7 +1511,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-06-16 06:30:16 +0000 +++ b/sql/table.h 2011-06-27 07:04:14 +0000 @@ -2024,11 +2024,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-06-23 06:48:48 +0000 +++ b/storage/innobase/handler/ha_innodb.cc 2011-06-27 07:04:14 +0000 @@ -12881,7 +12881,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); @@ -12896,7 +12896,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-06-01 09:11:28 +0000 +++ b/storage/innobase/handler/ha_innodb.h 2011-06-27 07:04:14 +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-05-26 15:20:09 +0000 +++ b/storage/myisam/ha_myisam.cc 2011-06-27 07:04:14 +0000 @@ -2128,7 +2128,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 @@ -2142,7 +2142,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-04-23 20:44:45 +0000 +++ b/storage/myisam/ha_myisam.h 2011-06-27 07:04:14 +0000 @@ -160,9 +160,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-06-24 09:29:07 +0000 +++ b/unittest/gunit/CMakeLists.txt 2011-06-27 07:04:14 +0000 @@ -216,6 +216,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-06-27 07:04:14 +0000 @@ -0,0 +1,136 @@ +/* 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 + +#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()); +} + +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 --===============5929939996752188492== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/jorgen.loland@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: jorgen.loland@stripped\ # j6cjrtzp7zy4yxla # target_branch: file:///export/home/jl208045/mysql/wl4774/mysql-\ # trunk-costvect-refact/ # testament_sha1: 5853b91b29c45d7be37db6b6bb4d9e7b0e62b518 # timestamp: 2011-06-27 09:04:24 +0200 # base_revision_id: tor.didriksen@stripped\ # sy16mrj8w9vz6266 # # Begin bundle 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 in7gQvoslZH/4u5IpwoSFFX9RwA= --===============5929939996752188492==--