Merge branch '10.1' into 10.2

This commit is contained in:
Vicențiu Ciorbaru 2018-03-21 10:36:49 +02:00
commit 82aeb6b596
47 changed files with 1566 additions and 295 deletions

View file

@ -275,7 +275,20 @@ buf_dump(
buf_dump_status(STATUS_INFO, "Dumping buffer pool(s) to %s",
full_filename);
f = fopen(tmp_filename, "w");
#if defined(__GLIBC__) || defined(__WIN__) || O_CLOEXEC == 0
f = fopen(tmp_filename, "w" STR_O_CLOEXEC);
#else
{
int fd;
fd = open(tmp_filename, O_CREAT | O_TRUNC | O_CLOEXEC | O_WRONLY, 0640);
if (fd >= 0) {
f = fdopen(fd, "w");
}
else {
f = NULL;
}
}
#endif
if (f == NULL) {
buf_dump_status(STATUS_ERR,
"Cannot open '%s' for writing: %s",

View file

@ -2255,7 +2255,7 @@ AIO::is_linux_native_aio_supported()
strcpy(name + dirnamelen, "ib_logfile0");
fd = open(name, O_RDONLY);
fd = open(name, O_RDONLY | O_CLOEXEC);
if (fd == -1) {

View file

@ -2915,7 +2915,9 @@ row_sel_field_store_in_mysql_format_func(
|| !(templ->mysql_col_len % templ->mbmaxlen));
ut_ad(len * templ->mbmaxlen >= templ->mysql_col_len
|| (field_no == templ->icp_rec_field_no
&& field->prefix_len > 0));
&& field->prefix_len > 0)
|| templ->rec_field_is_prefix);
ut_ad(templ->is_virtual
|| !(field->prefix_len % templ->mbmaxlen));
@ -4061,6 +4063,118 @@ row_sel_fill_vrow(
}
}
/** Return the record field length in characters.
@param[in] col table column of the field
@param[in] field_no field number
@param[in] rec physical record
@param[in] offsets field offsets in the physical record
@return field length in characters. */
static
size_t
rec_field_len_in_chars(
const dict_col_t* col,
const ulint field_no,
const rec_t* rec,
const ulint* offsets)
{
const ulint cset = dtype_get_charset_coll(col->prtype);
const CHARSET_INFO* cs = all_charsets[cset];
ulint rec_field_len;
const char* rec_field = reinterpret_cast<const char *>(
rec_get_nth_field(
rec, offsets, field_no, &rec_field_len));
if (UNIV_UNLIKELY(!cs)) {
ib::warn() << "Missing collation " << cset;
return SIZE_T_MAX;
}
return(cs->cset->numchars(cs, rec_field, rec_field + rec_field_len));
}
/** Avoid the clustered index lookup if all the following conditions
are true:
1) all columns are in secondary index
2) all values for columns that are prefix-only indexes are shorter
than the prefix size. This optimization can avoid many IOs for certain schemas.
@return true, to avoid clustered index lookup. */
static
bool row_search_with_covering_prefix(
row_prebuilt_t* prebuilt,
const rec_t* rec,
const ulint* offsets)
{
const dict_index_t* index = prebuilt->index;
ut_ad(!dict_index_is_clust(index));
if (!srv_prefix_index_cluster_optimization) {
return false;
}
/** Optimization only applicable if there the number of secondary index
fields are greater than or equal to number of clustered index fields. */
if (prebuilt->n_template > index->n_fields) {
return false;
}
for (ulint i = 0; i < prebuilt->n_template; i++) {
mysql_row_templ_t* templ = prebuilt->mysql_template + i;
ulint j = templ->rec_prefix_field_no;
/** Condition (1) : is the field in the index. */
if (j == ULINT_UNDEFINED) {
return false;
}
/** Condition (2): If this is a prefix index then
row's value size shorter than prefix length. */
if (!templ->rec_field_is_prefix) {
continue;
}
ulint rec_size = rec_offs_nth_size(offsets, j);
const dict_field_t* field = dict_index_get_nth_field(index, j);
ulint max_chars = field->prefix_len / templ->mbmaxlen;
ut_a(field->prefix_len > 0);
if (rec_size < max_chars) {
/* Record in bytes shorter than the index
prefix length in char. */
continue;
}
if (rec_size * templ->mbminlen >= field->prefix_len) {
/* Shortest representation string by the
byte length of the record is longer than the
maximum possible index prefix. */
return false;
}
size_t num_chars = rec_field_len_in_chars(
field->col, j, rec, offsets);
if (num_chars >= max_chars) {
/* No of chars to store the record exceeds
the index prefix character length. */
return false;
}
}
/* If prefix index optimization condition satisfied then
for all columns above, use rec_prefix_field_no instead of
rec_field_no, and skip the clustered lookup below. */
for (ulint i = 0; i < prebuilt->n_template; i++) {
mysql_row_templ_t* templ = prebuilt->mysql_template + i;
templ->rec_field_no = templ->rec_prefix_field_no;
ut_a(templ->rec_field_no != ULINT_UNDEFINED);
}
srv_stats.n_sec_rec_cluster_reads_avoided.inc();
return true;
}
/** Searches for rows in the database using cursor.
Function is mainly used for tables that are shared across connections and
so it employs technique that can help re-construct the rows that
@ -4120,7 +4234,6 @@ row_search_mvcc(
ulint* offsets = offsets_;
ibool table_lock_waited = FALSE;
byte* next_buf = 0;
ibool use_clustered_index = FALSE;
bool spatial_search = false;
rec_offs_init(offsets_);
@ -5179,69 +5292,10 @@ locks_ok_del_marked:
break;
}
/* Get the clustered index record if needed, if we did not do the
search using the clustered index... */
use_clustered_index =
(index != clust_index && prebuilt->need_to_access_clustered);
if (use_clustered_index && srv_prefix_index_cluster_optimization
&& prebuilt->n_template <= index->n_fields) {
/* ...but, perhaps avoid the clustered index lookup if
all of the following are true:
1) all columns are in the secondary index
2) all values for columns that are prefix-only
indexes are shorter than the prefix size
This optimization can avoid many IOs for certain schemas.
*/
ibool row_contains_all_values = TRUE;
uint i;
for (i = 0; i < prebuilt->n_template; i++) {
/* Condition (1) from above: is the field in the
index (prefix or not)? */
mysql_row_templ_t* templ =
prebuilt->mysql_template + i;
ulint secondary_index_field_no =
templ->rec_prefix_field_no;
if (secondary_index_field_no == ULINT_UNDEFINED) {
row_contains_all_values = FALSE;
break;
}
/* Condition (2) from above: if this is a
prefix, is this row's value size shorter
than the prefix? */
if (templ->rec_field_is_prefix) {
ulint record_size = rec_offs_nth_size(
offsets,
secondary_index_field_no);
const dict_field_t *field =
dict_index_get_nth_field(
index,
secondary_index_field_no);
ut_a(field->prefix_len > 0);
if (record_size >= field->prefix_len) {
row_contains_all_values = FALSE;
break;
}
}
if (index != clust_index && prebuilt->need_to_access_clustered) {
if (row_search_with_covering_prefix(prebuilt, rec, offsets)) {
goto use_covering_index;
}
/* If (1) and (2) were true for all columns above, use
rec_prefix_field_no instead of rec_field_no, and skip
the clustered lookup below. */
if (row_contains_all_values) {
for (i = 0; i < prebuilt->n_template; i++) {
mysql_row_templ_t* templ =
prebuilt->mysql_template + i;
templ->rec_field_no =
templ->rec_prefix_field_no;
ut_a(templ->rec_field_no != ULINT_UNDEFINED);
}
use_clustered_index = FALSE;
srv_stats.n_sec_rec_cluster_reads_avoided.inc();
}
}
if (use_clustered_index) {
requires_clust_rec:
ut_ad(index != clust_index);
/* We use a 'goto' to the preceding label if a consistent
@ -5339,6 +5393,7 @@ requires_clust_rec:
}
}
} else {
use_covering_index:
result_rec = rec;
}

View file

@ -29,6 +29,10 @@
#endif
#ifdef HAVE_ORACLE_OCI
#if (defined(WIN32) || defined(_WIN32) || defined(WINDOWS) || defined(_WINDOWS))
#include <Shlwapi.h>
#define strcasestr StrStr
#endif
#include <oci.h>
#include "spd_err.h"
#include "spd_param.h"
@ -3817,7 +3821,7 @@ int spider_db_oracle_util::open_item_func(
{
Item_func_conv_charset *item_func_conv_charset =
(Item_func_conv_charset *)item_func;
CHARSET_INFO *conv_charset = item_func_conv_charset->conv_charset;
CHARSET_INFO *conv_charset = item_func_conv_charset->collation.collation;
uint cset_length = strlen(conv_charset->csname);
if (str->reserve(SPIDER_SQL_USING_LEN + cset_length))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);

View file

@ -371,6 +371,14 @@ SPIDER_CONN *spider_udf_direct_sql_create_conn(
if (direct_sql->access_mode == 0)
{
#endif
if (direct_sql->dbton_id == SPIDER_DBTON_SIZE)
{
/* Invalid target wrapper */
*error_num = ER_SPIDER_INVALID_CONNECT_INFO_NUM;
my_printf_error(*error_num, ER_SPIDER_INVALID_CONNECT_INFO_STR,
MYF(0), direct_sql->tgt_wrapper);
goto error_alloc_conn;
}
if (!(conn = (SPIDER_CONN *)
spider_bulk_malloc(spider_current_trx, 32, MYF(MY_WME | MY_ZEROFILL),
&conn, sizeof(*conn),
@ -398,6 +406,14 @@ SPIDER_CONN *spider_udf_direct_sql_create_conn(
conn->default_database.init_calc_mem(138);
#if defined(HS_HAS_SQLCOM) && defined(HAVE_HANDLERSOCKET)
} else {
if (direct_sql->dbton_id == SPIDER_DBTON_SIZE)
{
/* Invalid target wrapper */
*error_num = ER_SPIDER_NOSQL_WRAPPER_IS_INVALID_NUM;
my_printf_error(*error_num, ER_SPIDER_NOSQL_WRAPPER_IS_INVALID_STR,
MYF(0), direct_sql->tgt_wrapper);
goto error_alloc_conn;
}
if (!(conn = (SPIDER_CONN *)
spider_bulk_malloc(spider_current_trx, 33, MYF(MY_WME | MY_ZEROFILL),
&conn, sizeof(*conn),

View file

@ -10,7 +10,7 @@ col3 smallint(5) NOT NULL DEFAULT '1',
filler varchar(255) DEFAULT NULL,
KEY pk_ersatz(col1,col2,col3),
KEY key1 (col1,col2) USING BTREE
) ENGINE=TokuDB DEFAULT CHARSET=latin1 PACK_KEYS=1 COMPRESSION=TOKUDB_LZMA;
) ENGINE=TokuDB DEFAULT CHARSET=latin1 PACK_KEYS=1;
insert into t3 select 1300000000+a, 12345, 7890, 'data' from t2;
insert into t3 select 1400000000+a, 12345, 7890, 'data' from t2;
insert into t3 select 1410799999+a, 12345, 7890, 'data' from t2;
@ -34,7 +34,7 @@ from t3
where col1 <= 1410799999
order by col1 desc,col2 desc,col3 desc limit 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t3 range pk_ersatz,key1 pk_ersatz 4 NULL 2001 Using where; Using index
1 SIMPLE t3 range pk_ersatz,key1 pk_ersatz 4 NULL # Using where; Using index
# The same query but the constant is bigger.
# The query should use range(PRIMARY), not full index scan:
explain
@ -43,5 +43,5 @@ from t3
where col1 <= 1412199999
order by col1 desc, col2 desc, col3 desc limit 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t3 range pk_ersatz,key1 pk_ersatz 4 NULL 15001 Using where; Using index
1 SIMPLE t3 range pk_ersatz,key1 pk_ersatz 4 NULL # Using where; Using index
drop table t1,t2,t3;

View file

@ -15,7 +15,7 @@ CREATE TABLE t3 (
filler varchar(255) DEFAULT NULL,
KEY pk_ersatz(col1,col2,col3),
KEY key1 (col1,col2) USING BTREE
) ENGINE=TokuDB DEFAULT CHARSET=latin1 PACK_KEYS=1 COMPRESSION=TOKUDB_LZMA;
) ENGINE=TokuDB DEFAULT CHARSET=latin1 PACK_KEYS=1;
insert into t3 select 1300000000+a, 12345, 7890, 'data' from t2;
insert into t3 select 1400000000+a, 12345, 7890, 'data' from t2;
@ -35,6 +35,7 @@ insert into t3 select 1412099999+a, 12345, 7890, 'data' from t2;
insert into t3 select 1412199999+a, 12345, 7890, 'data' from t2;
--echo # The following must use range(PRIMARY):
--replace_column 9 #
explain
select col1,col2,col3
from t3
@ -43,6 +44,7 @@ order by col1 desc,col2 desc,col3 desc limit 1;
--echo # The same query but the constant is bigger.
--echo # The query should use range(PRIMARY), not full index scan:
--replace_column 9 #
explain
select col1,col2,col3
from t3

View file

@ -216,7 +216,20 @@ buf_dump(
buf_dump_status(STATUS_NOTICE, "Dumping buffer pool(s) to %s",
full_filename);
f = fopen(tmp_filename, "w");
#if defined(__GLIBC__) || defined(__WIN__) || O_CLOEXEC == 0
f = fopen(tmp_filename, "w" STR_O_CLOEXEC);
#else
{
int fd;
fd = open(tmp_filename, O_CREAT | O_TRUNC | O_CLOEXEC | O_WRONLY, 0640);
if (fd >= 0) {
f = fdopen(fd, "w");
}
else {
f = NULL;
}
}
#endif
if (f == NULL) {
buf_dump_status(STATUS_ERR,
"Cannot open '%s' for writing: %s",

View file

@ -3685,6 +3685,117 @@ row_search_idx_cond_check(
return(result);
}
/** Return the record field length in characters.
@param[in] col table column of the field
@param[in] field_no field number
@param[in] rec physical record
@param[in] offsets field offsets in the physical record
@return field length in characters. */
static
size_t
rec_field_len_in_chars(
const dict_col_t* col,
const ulint field_no,
const rec_t* rec,
const ulint* offsets)
{
const ulint cset = dtype_get_charset_coll(col->prtype);
const CHARSET_INFO* cs = all_charsets[cset];
ulint rec_field_len;
const char* rec_field = reinterpret_cast<const char *>(
rec_get_nth_field(
rec, offsets, field_no, &rec_field_len));
if (UNIV_UNLIKELY(!cs)) {
ib_logf(IB_LOG_LEVEL_WARN, "Missing collation " ULINTPF, cset);
return SIZE_T_MAX;
}
return(cs->cset->numchars(cs, rec_field, rec_field + rec_field_len));
}
/** Avoid the clustered index lookup if all the following conditions
are true:
1) all columns are in secondary index
2) all values for columns that are prefix-only indexes are shorter
than the prefix size. This optimization can avoid many IOs for certain schemas.
@return true, to avoid clustered index lookup. */
static
bool row_search_with_covering_prefix(
row_prebuilt_t* prebuilt,
const rec_t* rec,
const ulint* offsets)
{
const dict_index_t* index = prebuilt->index;
ut_ad(!dict_index_is_clust(index));
if (!srv_prefix_index_cluster_optimization) {
return false;
}
/** Optimization only applicable if the number of secondary index
fields are greater than or equal to number of clustered index fields. */
if (prebuilt->n_template > index->n_fields) {
return false;
}
for (ulint i = 0; i < prebuilt->n_template; i++) {
mysql_row_templ_t* templ = prebuilt->mysql_template + i;
ulint j = templ->rec_prefix_field_no;
/** Condition (1) : is the field in the index. */
if (j == ULINT_UNDEFINED) {
return false;
}
/** Condition (2): If this is a prefix index then
row's value size shorter than prefix length. */
if (!templ->rec_field_is_prefix) {
continue;
}
ulint rec_size = rec_offs_nth_size(offsets, j);
const dict_field_t* field = dict_index_get_nth_field(index, j);
ulint max_chars = field->prefix_len / templ->mbmaxlen;
ut_a(field->prefix_len > 0);
if (rec_size < max_chars) {
/* Record in bytes shorter than the index
prefix length in char. */
continue;
}
if (rec_size * templ->mbminlen >= field->prefix_len) {
/* Shortest representation string by the
byte length of the record is longer than the
maximum possible index prefix. */
return false;
}
size_t num_chars = rec_field_len_in_chars(
field->col, j, rec, offsets);
if (num_chars >= max_chars) {
/* No of chars to store the record exceeds
the index prefix character length. */
return false;
}
}
for (ulint i = 0; i < prebuilt->n_template; i++) {
mysql_row_templ_t* templ = prebuilt->mysql_template + i;
templ->rec_field_no = templ->rec_prefix_field_no;
ut_a(templ->rec_field_no != ULINT_UNDEFINED);
}
srv_stats.n_sec_rec_cluster_reads_avoided.inc();
return true;
}
/********************************************************************//**
Searches for rows in the database. This is used in the interface to
MySQL. This function opens a cursor, and also implements fetch next
@ -3748,7 +3859,6 @@ row_search_for_mysql(
ulint* offsets = offsets_;
ibool table_lock_waited = FALSE;
byte* next_buf = 0;
bool use_clustered_index = false;
rec_offs_init(offsets_);
@ -4810,71 +4920,10 @@ locks_ok:
break;
}
/* Get the clustered index record if needed, if we did not do the
search using the clustered index... */
use_clustered_index =
(index != clust_index && prebuilt->need_to_access_clustered);
if (use_clustered_index && srv_prefix_index_cluster_optimization
&& prebuilt->n_template <= index->n_fields) {
/* ...but, perhaps avoid the clustered index lookup if
all of the following are true:
1) all columns are in the secondary index
2) all values for columns that are prefix-only
indexes are shorter than the prefix size
This optimization can avoid many IOs for certain schemas.
*/
bool row_contains_all_values = true;
unsigned int i;
for (i = 0; i < prebuilt->n_template; i++) {
/* Condition (1) from above: is the field in the
index (prefix or not)? */
const mysql_row_templ_t* templ =
prebuilt->mysql_template + i;
ulint secondary_index_field_no =
templ->rec_prefix_field_no;
if (secondary_index_field_no == ULINT_UNDEFINED) {
row_contains_all_values = false;
break;
}
/* Condition (2) from above: if this is a
prefix, is this row's value size shorter
than the prefix? */
if (templ->rec_field_is_prefix) {
ulint record_size = rec_offs_nth_size(
offsets,
secondary_index_field_no);
const dict_field_t *field =
dict_index_get_nth_field(
index,
secondary_index_field_no);
ut_a(field->prefix_len > 0);
if (record_size >= field->prefix_len
/ templ->mbmaxlen) {
row_contains_all_values = false;
break;
}
}
if (index != clust_index && prebuilt->need_to_access_clustered) {
if (row_search_with_covering_prefix(prebuilt, rec, offsets)) {
goto use_covering_index;
}
/* If (1) and (2) were true for all columns above, use
rec_prefix_field_no instead of rec_field_no, and skip
the clustered lookup below. */
if (row_contains_all_values) {
for (i = 0; i < prebuilt->n_template; i++) {
mysql_row_templ_t* templ =
prebuilt->mysql_template + i;
templ->rec_field_no =
templ->rec_prefix_field_no;
ut_a(templ->rec_field_no != ULINT_UNDEFINED);
}
use_clustered_index = false;
srv_stats.n_sec_rec_cluster_reads_avoided.inc();
}
}
if (use_clustered_index) {
requires_clust_rec:
ut_ad(index != clust_index);
/* We use a 'goto' to the preceding label if a consistent
@ -4960,6 +5009,7 @@ requires_clust_rec:
}
}
} else {
use_covering_index:
result_rec = rec;
}