1 /*
2 Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software Foundation,
22 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
23
24 // First include (the generated) my_config.h, to get correct platform defines.
25 #include "my_config.h"
26 #include "handler.h" // handlerton
27 #include "m_ctype.h" // my_charset_utf8_general_ci
28 #include "my_dbug.h"
29 #include "opt_costconstants.h"
30 #include "sql_plugin.h" // plugin_ref
31 #include "table.h" // TABLE
32
33 /**
34 The default value for storage device type. If device type information
35 is added to the data dictionary or the storage engines start to
36 provide this information, this default can be replaced.
37 */
38 const unsigned int DEFAULT_STORAGE_CLASS= 0;
39
40 /*
41 Values for cost constants defined as static const variables in the
42 Server_cost_constants class.
43 These are the default cost constant values that will be use if
44 the server administrator has not added new values in the server_cost
45 table.
46 */
47
48 // Default cost for evaluation of the query condition for a row.
49 const double Server_cost_constants::ROW_EVALUATE_COST= 0.2;
50
51 // Default cost for comparing row ids.
52 const double Server_cost_constants::KEY_COMPARE_COST= 0.1;
53
54 /*
55 Creating a Memory temporary table is by benchmark found to be as
56 costly as writing 10 rows into the table.
57 */
58 const double Server_cost_constants::MEMORY_TEMPTABLE_CREATE_COST= 2.0;
59
60 /*
61 Writing a row to or reading a row from a Memory temporary table is
62 equivalent to evaluating a row in the join engine.
63 */
64 const double Server_cost_constants::MEMORY_TEMPTABLE_ROW_COST= 0.2;
65
66 /*
67 Creating a MyISAM table is 20 times slower than creating a Memory table.
68 */
69 const double Server_cost_constants::DISK_TEMPTABLE_CREATE_COST= 40.0;
70
71 /*
72 Generating MyISAM rows sequentially is 2 times slower than
73 generating Memory rows, when number of rows is greater than
74 1000. However, we do not have benchmarks for very large tables, so
75 setting this factor conservatively to be 5 times slower (ie the cost
76 is 1.0).
77 */
78 const double Server_cost_constants::DISK_TEMPTABLE_ROW_COST= 1.0;
79
80
set(const LEX_CSTRING & name,double value)81 cost_constant_error Server_cost_constants::set(const LEX_CSTRING &name,
82 double value)
83 {
84 DBUG_ASSERT(name.str != NULL);
85 DBUG_ASSERT(name.length > 0);
86
87 if (name.str == NULL || name.length == 0)
88 return UNKNOWN_COST_NAME; /* purecov: inspected */
89
90 /*
91 The cost constant value must be a positive and non-zero.
92 */
93 if (value <= 0.0)
94 return INVALID_COST_VALUE;
95
96 // ROW_EVALUATE_COST
97 if (my_strcasecmp(&my_charset_utf8_general_ci,
98 "ROW_EVALUATE_COST", name.str) == 0)
99 {
100 m_row_evaluate_cost= value;
101 return COST_CONSTANT_OK;
102 }
103 // KEY_COMPARE_COST
104 if (my_strcasecmp(&my_charset_utf8_general_ci,
105 "KEY_COMPARE_COST", name.str) == 0)
106 {
107 m_key_compare_cost= value;
108 return COST_CONSTANT_OK;
109 }
110 // MEMORY_TEMPTABLE_CREATE_COST
111 if (my_strcasecmp(&my_charset_utf8_general_ci,
112 "MEMORY_TEMPTABLE_CREATE_COST", name.str) == 0)
113 {
114 m_memory_temptable_create_cost= value;
115 return COST_CONSTANT_OK;
116 }
117 // MEMORY_TEMPTABLE_ROW_COST
118 if (my_strcasecmp(&my_charset_utf8_general_ci,
119 "MEMORY_TEMPTABLE_ROW_COST", name.str) == 0)
120 {
121 m_memory_temptable_row_cost= value;
122 return COST_CONSTANT_OK;
123 }
124 // DISK_TEMPTABLE_CREATE_COST
125 if (my_strcasecmp(&my_charset_utf8_general_ci,
126 "DISK_TEMPTABLE_CREATE_COST", name.str) == 0)
127 {
128 m_disk_temptable_create_cost= value;
129 return COST_CONSTANT_OK;
130 }
131 // DISK_TEMPTABLE_ROW_COST
132 if (my_strcasecmp(&my_charset_utf8_general_ci,
133 "DISK_TEMPTABLE_ROW_COST", name.str) == 0)
134 {
135 m_disk_temptable_row_cost= value;
136 return COST_CONSTANT_OK;
137 }
138
139 return UNKNOWN_COST_NAME; // Cost constant does not exist
140 }
141
142
143 /*
144 Values for cost constants defined as static const variables in the
145 SE_cost_constants class.
146 These are the default cost constant values that will be used if
147 the server administrator has not added new values in the engine_cost
148 table.
149 */
150
151 // The cost of reading a block from a main memory buffer pool
152 const double SE_cost_constants::MEMORY_BLOCK_READ_COST= 1.0;
153
154 // The cost of reading a block from an IO device (disk)
155 const double SE_cost_constants::IO_BLOCK_READ_COST= 1.0;
156
157
set(const LEX_CSTRING & name,const double value,bool default_value)158 cost_constant_error SE_cost_constants::set(const LEX_CSTRING &name,
159 const double value,
160 bool default_value)
161 {
162 DBUG_ASSERT(name.str != NULL);
163 DBUG_ASSERT(name.length > 0);
164
165 if (name.str == NULL || name.length == 0)
166 return UNKNOWN_COST_NAME; /* purecov: inspected */
167
168 /*
169 The cost constant value must be a positive and non-zero number.
170 */
171 if (value <= 0.0)
172 return INVALID_COST_VALUE;
173
174 // MEMORY_BLOCK_READ_COST
175 if (my_strcasecmp(&my_charset_utf8_general_ci, "MEMORY_BLOCK_READ_COST",
176 name.str) == 0)
177 {
178 update_cost_value(&m_memory_block_read_cost,
179 &m_memory_block_read_cost_default, value, default_value);
180 return COST_CONSTANT_OK;
181 }
182 // IO_BLOCK_READ_COST
183 if (my_strcasecmp(&my_charset_utf8_general_ci, "IO_BLOCK_READ_COST",
184 name.str) == 0)
185 {
186 update_cost_value(&m_io_block_read_cost, &m_io_block_read_cost_default,
187 value, default_value);
188 return COST_CONSTANT_OK;
189 }
190
191 return UNKNOWN_COST_NAME; // Cost constant does not exist
192 }
193
194
update(const LEX_CSTRING & name,const double value)195 cost_constant_error SE_cost_constants::update(const LEX_CSTRING &name,
196 const double value)
197 {
198 return set(name, value, false);
199 }
200
201
update_default(const LEX_CSTRING & name,const double value)202 cost_constant_error SE_cost_constants::update_default(const LEX_CSTRING &name,
203 const double value)
204 {
205 return set(name, value, true);
206 }
207
208
update_cost_value(double * cost_constant,bool * cost_constant_is_default,double new_value,bool new_value_is_default)209 void SE_cost_constants::update_cost_value(double *cost_constant,
210 bool *cost_constant_is_default,
211 double new_value,
212 bool new_value_is_default)
213 {
214 // If this is not a new default value then do the update unconditionally
215 if (!new_value_is_default)
216 {
217 *cost_constant= new_value;
218 *cost_constant_is_default= false; // No longer default value
219 }
220 else
221 {
222 /*
223 This new value is a default value. Only update the cost constant if it
224 currently has the default value.
225 */
226 if (*cost_constant_is_default)
227 *cost_constant= new_value;
228 }
229 }
230
231
Cost_model_se_info()232 Cost_model_se_info::Cost_model_se_info()
233 {
234 for (uint i= 0; i < MAX_STORAGE_CLASSES; ++i)
235 m_se_cost_constants[i]= NULL;
236 }
237
238
~Cost_model_se_info()239 Cost_model_se_info::~Cost_model_se_info()
240 {
241 for (uint i= 0; i < MAX_STORAGE_CLASSES; ++i)
242 {
243 delete m_se_cost_constants[i];
244 m_se_cost_constants[i]= NULL;
245 }
246 }
247
248
Cost_model_constants()249 Cost_model_constants::Cost_model_constants()
250 : m_ref_counter(0)
251 {
252 /**
253 Create default cost constants for each storage engine.
254 */
255 for (uint engine= 0; engine < MAX_HA; ++engine)
256 {
257 const handlerton *ht= NULL;
258
259 // Check if the storage engine has been installed
260 if (hton2plugin[engine])
261 {
262 // Find the handlerton for the storage engine
263 ht= static_cast<handlerton*>(hton2plugin[engine]->data);
264 }
265
266 for (uint storage= 0; storage < MAX_STORAGE_CLASSES; ++storage)
267 {
268 SE_cost_constants *se_cost= NULL;
269
270 /*
271 If the storage engine has provided a function for creating
272 storage engine specific cost constants, then ask the
273 storage engine to create the cost constants.
274 */
275 if (ht && ht->get_cost_constants)
276 se_cost= ht->get_cost_constants(storage); /* purecov: tested */
277
278 /*
279 If the storage engine did not provide cost constants, then the
280 default cost constants will be used.
281 */
282 if (se_cost == NULL)
283 se_cost= new SE_cost_constants();
284
285 m_engines[engine].set_cost_constants(se_cost, storage);
286 }
287 }
288 }
289
290
~Cost_model_constants()291 Cost_model_constants::~Cost_model_constants()
292 {
293 DBUG_ASSERT(m_ref_counter == 0);
294 }
295
296
297 const SE_cost_constants
get_se_cost_constants(const TABLE * table) const298 *Cost_model_constants::get_se_cost_constants(const TABLE *table) const
299 {
300 DBUG_ASSERT(table->file != NULL);
301 DBUG_ASSERT(table->file->ht != NULL);
302
303 const SE_cost_constants *se_cc=
304 m_engines[table->file->ht->slot].get_cost_constants(DEFAULT_STORAGE_CLASS);
305 DBUG_ASSERT(se_cc != NULL);
306
307 return se_cc;
308 }
309
310
311 cost_constant_error
update_server_cost_constant(const LEX_CSTRING & name,double value)312 Cost_model_constants::update_server_cost_constant(const LEX_CSTRING &name,
313 double value)
314 {
315 return m_server_constants.set(name, value);
316 }
317
318
319 cost_constant_error
update_engine_cost_constant(THD * thd,const LEX_CSTRING & se_name,uint storage_category,const LEX_CSTRING & name,double value)320 Cost_model_constants::update_engine_cost_constant(THD *thd,
321 const LEX_CSTRING &se_name,
322 uint storage_category,
323 const LEX_CSTRING &name,
324 double value)
325 {
326 cost_constant_error retval= COST_CONSTANT_OK;
327
328 // Validate the storage category.
329 if (storage_category >= MAX_STORAGE_CLASSES)
330 return INVALID_DEVICE_TYPE;
331
332 // Check if this is a default value
333 if (my_strcasecmp(&my_charset_utf8_general_ci, "default", se_name.str) == 0)
334 {
335 retval= update_engine_default_cost(name, storage_category, value);
336 }
337 else
338 {
339 // Look up the handler's slot id by using the storage engine name
340 const uint ht_slot_id= find_handler_slot_from_name(thd, se_name);
341 if (ht_slot_id == HA_SLOT_UNDEF)
342 return UNKNOWN_ENGINE_NAME;
343
344 SE_cost_constants *se_cc=
345 m_engines[ht_slot_id].get_cost_constants(storage_category);
346 DBUG_ASSERT(se_cc != NULL);
347
348 retval= se_cc->update(name, value);
349 }
350
351 return retval;
352 }
353
354
find_handler_slot_from_name(THD * thd,const LEX_CSTRING & name) const355 uint Cost_model_constants::find_handler_slot_from_name(THD *thd,
356 const LEX_CSTRING &name)
357 const
358 {
359 // Convert storage engine name from const to non-const lex string
360 const LEX_STRING name_non_const=
361 { const_cast<char*>(name.str), name.length };
362
363 // Look up the storage engine
364 const plugin_ref plugin= ha_resolve_by_name(thd, &name_non_const, false);
365 if (!plugin)
366 return HA_SLOT_UNDEF;
367
368 // Find the handlerton for this storage engine
369 handlerton *ht= plugin_data<handlerton*>(plugin);
370 DBUG_ASSERT(ht != NULL);
371 if (!ht)
372 {
373 DBUG_ASSERT(false); /* purecov: inspected */
374 return HA_SLOT_UNDEF;
375 }
376
377 return ht->slot;
378 }
379
380
381 cost_constant_error
update_engine_default_cost(const LEX_CSTRING & name,uint storage_category,double value)382 Cost_model_constants::update_engine_default_cost(const LEX_CSTRING &name,
383 uint storage_category,
384 double value)
385 {
386 DBUG_ASSERT(storage_category < MAX_STORAGE_CLASSES);
387
388 /*
389 Return value: if at least one of the storage engines recognizes the
390 cost constants name, then success is returned.
391 */
392 cost_constant_error retval= UNKNOWN_COST_NAME;
393
394 /*
395 Update all constants for engines that have their own cost constants
396 */
397 for (size_t i= 0; i < MAX_HA; ++i)
398 {
399 SE_cost_constants *se_cc= m_engines[i].get_cost_constants(storage_category);
400 if (se_cc)
401 {
402 const cost_constant_error err= se_cc->update_default(name, value);
403 if (err != UNKNOWN_COST_NAME)
404 retval= err;
405 }
406 }
407
408 return retval;
409 }
410