summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/my_base.h3
-rw-r--r--include/my_handler.h3
-rw-r--r--mysql-test/r/myisam_icp.result1
-rw-r--r--mysql-test/t/myisam_icp.test188
-rw-r--r--mysys/my_handler_errors.h4
-rw-r--r--sql/handler.cc6
-rw-r--r--sql/multi_range_read.cc8
-rw-r--r--storage/maria/ha_maria.cc15
-rw-r--r--storage/maria/ma_extra.c6
-rw-r--r--storage/maria/ma_key.c28
-rw-r--r--storage/maria/ma_rkey.c60
-rw-r--r--storage/maria/ma_rnext.c25
-rw-r--r--storage/maria/ma_rnext_same.c23
-rw-r--r--storage/maria/ma_rprev.c26
-rw-r--r--storage/maria/ma_search.c6
-rw-r--r--storage/maria/ma_static.c3
-rw-r--r--storage/maria/maria_def.h9
-rw-r--r--storage/myisam/ha_myisam.cc11
-rw-r--r--storage/myisam/mi_extra.c5
-rw-r--r--storage/myisam/mi_key.c19
-rw-r--r--storage/myisam/mi_rkey.c98
-rw-r--r--storage/myisam/mi_rnext.c26
-rw-r--r--storage/myisam/mi_rnext_same.c22
-rw-r--r--storage/myisam/mi_rprev.c31
-rw-r--r--storage/myisam/mi_search.c5
-rw-r--r--storage/myisam/mi_static.c1
-rw-r--r--storage/myisam/myisamdef.h6
-rw-r--r--storage/xtradb/handler/ha_innodb.cc22
-rw-r--r--storage/xtradb/handler/ha_innodb.h3
-rw-r--r--storage/xtradb/include/db0err.h3
-rw-r--r--storage/xtradb/include/row0mysql.h11
-rw-r--r--storage/xtradb/row/row0sel.c12
32 files changed, 590 insertions, 99 deletions
diff --git a/include/my_base.h b/include/my_base.h
index 8f50120a970..a5f18146859 100644
--- a/include/my_base.h
+++ b/include/my_base.h
@@ -445,7 +445,8 @@ enum ha_base_keytype {
#define HA_ERR_WRONG_CRC 176 /* Wrong CRC on page */
#define HA_ERR_ROW_NOT_VISIBLE 177
#define HA_ERR_TOO_MANY_CONCURRENT_TRXS 178 /*Too many active concurrent transactions */
-#define HA_ERR_LAST 178 /* Copy of last error nr */
+#define HA_ERR_ABORTED_BY_USER 179
+#define HA_ERR_LAST 179 /* Copy of last error nr */
/* Number of different errors */
#define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1)
diff --git a/include/my_handler.h b/include/my_handler.h
index 275dd92fa18..5fc0565538d 100644
--- a/include/my_handler.h
+++ b/include/my_handler.h
@@ -135,6 +135,9 @@ extern void my_handler_error_unregister(void);
if we're scanning "t.key BETWEEN 10 AND 20" and got a
"t.key=21" tuple (the engine should stop scanning and return
HA_ERR_END_OF_FILE right away).
+
+ -1= ICP_ERROR - Reserved for internal errors in engines. Should not be
+ returned by index_cond_func_xxx
*/
typedef enum icp_result {
diff --git a/mysql-test/r/myisam_icp.result b/mysql-test/r/myisam_icp.result
index d72ae90d230..45d45bd3452 100644
--- a/mysql-test/r/myisam_icp.result
+++ b/mysql-test/r/myisam_icp.result
@@ -198,3 +198,4 @@ COUNT(*)
12
DROP PROCEDURE insert_data;
DROP TABLE t1, t2, t3;
+drop table if exists t0, t1, t1i, t1m;
diff --git a/mysql-test/t/myisam_icp.test b/mysql-test/t/myisam_icp.test
index 4c3db4d9d12..30a8b208230 100644
--- a/mysql-test/t/myisam_icp.test
+++ b/mysql-test/t/myisam_icp.test
@@ -4,3 +4,191 @@
--source include/icp_tests.inc
+--disable_warnings
+drop table if exists t0, t1, t1i, t1m;
+--enable_warnings
+
+#
+# BUG#711565 Index Condition Pushdown can make a thread hold MyISAM locks as well as be unKILLable for long time
+# This is not a ready mysqltest testcase but rather a set of queries that
+# allow to check the bug[fix] manually. Making this testcase automatic is
+# difficult because
+# - big tables are involved
+# - it's difficult to have automatic checks of whether the query could be
+# KILLed that would reliably work on fast/slow buildslaves, etc.
+
+--disable_parsing
+
+ create table t0 (a int);
+ insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+
+ create table t1 (
+ kp1 int, kp2 int,
+ filler char(100),
+ col int,
+ key(kp1, kp2)
+ );
+
+ set myisam_sort_buffer_size=32*1000*1000;
+ insert into t1
+ select
+ 1000 + A.a + 10*B.a + 100*C.a + 1000*D.a + 10000 * F.a,
+ 1,
+ 'filler-data filler-data filler-data filler-data filler-data',
+ 1
+ from
+ t0 A, t0 B, t0 C, t0 D, t0 E, t0 F, t0 G
+ ;
+
+ insert into t1 values (990, 100, 'a record to test index_next checks',100);
+
+ update t1 set kp2=10 where kp1 between 20000+100 and 28000;
+
+ update t1 set kp1=20000 where kp1 between 20000 and 28000;
+
+ insert into t1 values (20000, 100, 'last-20K-record',1);
+
+ create table t1i like t1;
+ alter table t1i engine=innodb;
+ insert into t1i select * from t1;
+
+ create table t1m like t1;
+ alter table t1m engine=maria;
+ insert into t1m select * from t1;
+
+#
+# XtraDB has one check for all kinds of ranges.
+#
+ explain
+ select * from t1i
+ where
+ kp1 < 8000 and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ kp2 +1 > 10;
+
+
+#
+# MyISAM, check range access + mi_rnext():
+# (will return HA_ERR_END_OF_FILE)
+ explain
+ select * from t1
+ where
+ kp1 < 10000 and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ kp2 +1 > 10;
+
+
+#
+# MyISAM, check range access + mi_rkey():
+# (will return HA_ERR_END_OF_FILE)
+ explain
+ select * from t1
+ where
+ kp1 >= 999 and kp1 < 10000 and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ kp2 +1 > 10;
+
+
+
+#
+# MyISAM, check mi_rnext_same:
+#
+
+ explain
+ select * from t1
+ where
+ kp1 = 20000 and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ kp2 +1 < 10;
+
+
+#
+# MyISAM, check mi_rprev:
+#
+
+ explain
+ select * from t1
+ where
+ kp1 = 20000 and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ kp2 +1 > 20
+ order by kp1, kp2 desc;
+
+
+
+#
+# Maria, check range access + maria_rkey():
+#
+ explain
+ select * from t1m
+ where
+ kp1 >= 999 and kp1 < 10000 and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ kp2 +1 > 10;
+
+
+
+#
+# Maria, check range access + maria_rnext():
+#
+ explain
+ select * from t1m
+ where
+ kp1 < 10000 and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ kp2 +1 > 10;
+
+
+#
+# Maria, check maria_rnext_same:
+#
+
+ explain
+ select * from t1m
+ where
+ kp1 = 20000 and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ kp2 +1 > 100;
+
+#
+# Maria, check maria_rprev:
+#
+
+ explain
+ select * from t1m
+ where
+ kp1 = 20000 and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ concat(repeat('foo-bar-', 100000), kp2) like '%bar-1%' and
+ kp2 +1 > 20
+ order by kp1, kp2 desc;
+
+drop table t0, t1, t1i, t1m;
+
+--enable_parsing
diff --git a/mysys/my_handler_errors.h b/mysys/my_handler_errors.h
index 4f0fd52e767..31445cd8671 100644
--- a/mysys/my_handler_errors.h
+++ b/mysys/my_handler_errors.h
@@ -64,6 +64,6 @@ static const char *handler_error_messages[]=
"File too short; Expected more data in file",
"Read page with wrong checksum",
"Too many active concurrent transactions",
- "Row is not visible by the current transaction"
+ "Row is not visible by the current transaction",
+ "Operation was interrupted by end user (probably kill command?)"
};
-
diff --git a/sql/handler.cc b/sql/handler.cc
index 45de1aafc10..b49f29059b0 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -2688,6 +2688,12 @@ void handler::print_error(int error, myf errflag)
SET_FATAL_ERROR;
textno=ER_KEY_NOT_FOUND;
break;
+ case HA_ERR_ABORTED_BY_USER:
+ {
+ DBUG_ASSERT(table->in_use->killed);
+ table->in_use->send_kill_message();
+ DBUG_VOID_RETURN;
+ }
case HA_ERR_WRONG_MRG_TABLE_DEF:
textno=ER_WRONG_MRG_TABLE;
break;
diff --git a/sql/multi_range_read.cc b/sql/multi_range_read.cc
index d9dcd354b3e..3aeb75fd896 100644
--- a/sql/multi_range_read.cc
+++ b/sql/multi_range_read.cc
@@ -316,6 +316,8 @@ int Mrr_simple_index_reader::get_next(char **range_info)
!file->mrr_funcs.skip_index_tuple(file->mrr_iter, curr_range->ptr))
break;
}
+ if (res && res != HA_ERR_END_OF_FILE && res != HA_ERR_KEY_NOT_FOUND)
+ file->print_error(res, MYF(0)); // Fatal error
return res;
}
@@ -333,7 +335,7 @@ int Mrr_simple_index_reader::get_next(char **range_info)
@retval 0 OK, next record was successfully read
@retval HA_ERR_END_OF_FILE End of records
- @retval Other Some other error
+ @retval Other Some other error; Error is printed
*/
int Mrr_ordered_index_reader::get_next(char **range_info)
@@ -349,7 +351,7 @@ int Mrr_ordered_index_reader::get_next(char **range_info)
{
if ((res != HA_ERR_KEY_NOT_FOUND && res != HA_ERR_END_OF_FILE))
DBUG_RETURN(res); /* Some fatal error */
-
+
if (key_buffer->is_empty())
{
DBUG_RETURN(HA_ERR_END_OF_FILE);
@@ -902,7 +904,7 @@ error:
close_second_handler();
/* Safety, not really needed but: */
strategy= NULL;
- DBUG_RETURN(1);
+ DBUG_RETURN(res);
use_default_impl:
DBUG_ASSERT(primary_file->inited == handler::INDEX);
diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc
index 9acabf29774..406def92808 100644
--- a/storage/maria/ha_maria.cc
+++ b/storage/maria/ha_maria.cc
@@ -758,7 +758,7 @@ void _ma_check_print_warning(HA_CHECK *param, const char *fmt, ...)
static int maria_create_trn_for_mysql(MARIA_HA *info)
{
- THD *thd= (THD*) info->external_ptr;
+ THD *thd= ((TABLE*) info->external_ref)->in_use;
TRN *trn= THD_TRN;
DBUG_ENTER("maria_create_trn_for_mysql");
@@ -797,6 +797,11 @@ static int maria_create_trn_for_mysql(MARIA_HA *info)
DBUG_RETURN(0);
}
+my_bool ma_killed_in_mariadb(MARIA_HA *info)
+{
+ return (((TABLE*) (info->external_ref))->in_use->killed != 0);
+}
+
} /* extern "C" */
/**
@@ -1013,6 +1018,8 @@ int ha_maria::open(const char *name, int mode, uint test_if_locked)
return (my_errno ? my_errno : -1);
file->s->chst_invalidator= query_cache_invalidate_by_MyISAM_filename_ref;
+ /* Set external_ref, mainly for temporary tables */
+ file->external_ref= (void*) table; // For ma_killed()
if (test_if_locked & (HA_OPEN_IGNORE_IF_LOCKED | HA_OPEN_TMP_TABLE))
VOID(maria_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0));
@@ -2525,6 +2532,7 @@ void ha_maria::drop_table(const char *name)
int ha_maria::external_lock(THD *thd, int lock_type)
{
DBUG_ENTER("ha_maria::external_lock");
+ file->external_ref= (void*) table; // For ma_killed()
/*
We don't test now_transactional because it may vary between lock/unlock
and thus confuse our reference counting.
@@ -2543,8 +2551,6 @@ int ha_maria::external_lock(THD *thd, int lock_type)
/* Transactional table */
if (lock_type != F_UNLCK)
{
- file->external_ptr= thd; // For maria_register_trn()
-
if (!file->s->lock_key_trees) // If we don't use versioning
{
/*
@@ -3392,6 +3398,9 @@ static int ha_maria_init(void *p)
#endif
if (res)
maria_hton= 0;
+
+ ma_killed= ma_killed_in_mariadb;
+
return res ? HA_ERR_INITIALIZATION : 0;
}
diff --git a/storage/maria/ma_extra.c b/storage/maria/ma_extra.c
index 7a30b613ea5..a2d40b1c828 100644
--- a/storage/maria/ma_extra.c
+++ b/storage/maria/ma_extra.c
@@ -635,3 +635,9 @@ int _ma_flush_table_files(MARIA_HA *info, uint flush_data_or_index,
return 1;
}
+
+my_bool ma_killed_standalone(MARIA_HA *info __attribute__((unused)))
+{
+ return 0;
+}
+
diff --git a/storage/maria/ma_key.c b/storage/maria/ma_key.c
index ac23bf5fef6..df15d029ce6 100644
--- a/storage/maria/ma_key.c
+++ b/storage/maria/ma_key.c
@@ -669,25 +669,39 @@ int _ma_read_key_record(MARIA_HA *info, uchar *buf, MARIA_RECORD_POS filepos)
will look for column values there)
RETURN
- ICP_ERROR Error
+ ICP_ERROR Error ; my_errno set to HA_ERR_CRASHED
ICP_NO_MATCH Index condition is not satisfied, continue scanning
ICP_MATCH Index condition is satisfied
- ICP_OUT_OF_RANGE Index condition is not satisfied, end the scan.
+ ICP_OUT_OF_RANGE Index condition is not satisfied, end the scan.
+ my_errno set to HA_ERR_END_OF_FILE
+
+ info->cur_row.lastpos is set to HA_OFFSET_ERROR in case of ICP_ERROR or
+ ICP_OUT_OF_RANGE to indicate that we don't have any active row.
*/
-int ma_check_index_cond(register MARIA_HA *info, uint keynr, uchar *record)
+ICP_RESULT ma_check_index_cond(register MARIA_HA *info, uint keynr,
+ uchar *record)
{
+ ICP_RESULT res= ICP_MATCH;
if (info->index_cond_func)
{
if (_ma_put_key_in_record(info, keynr, FALSE, record))
{
+ /* Impossible case; Can only happen if bug in code */
maria_print_error(info->s, HA_ERR_CRASHED);
- my_errno=HA_ERR_CRASHED;
- return -1;
+ info->cur_row.lastpos= HA_OFFSET_ERROR; /* No active record */
+ my_errno= HA_ERR_CRASHED;
+ res= ICP_ERROR;
+ }
+ else if ((res= info->index_cond_func(info->index_cond_func_arg)) ==
+ ICP_OUT_OF_RANGE)
+ {
+ /* We got beyond the end of scanned range */
+ info->cur_row.lastpos= HA_OFFSET_ERROR; /* No active record */
+ my_errno= HA_ERR_END_OF_FILE;
}
- return info->index_cond_func(info->index_cond_func_arg);
}
- return 1;
+ return res;
}
diff --git a/storage/maria/ma_rkey.c b/storage/maria/ma_rkey.c
index 5da541005f8..415f20cc631 100644
--- a/storage/maria/ma_rkey.c
+++ b/storage/maria/ma_rkey.c
@@ -34,7 +34,7 @@ int maria_rkey(MARIA_HA *info, uchar *buf, int inx, const uchar *key_data,
HA_KEYSEG *last_used_keyseg;
uint32 nextflag;
MARIA_KEY key;
- int icp_res= 1;
+ ICP_RESULT icp_res= ICP_MATCH;
DBUG_ENTER("maria_rkey");
DBUG_PRINT("enter", ("base: 0x%lx buf: 0x%lx inx: %d search_flag: %d",
(long) info, (long) buf, inx, search_flag));
@@ -115,7 +115,7 @@ int maria_rkey(MARIA_HA *info, uchar *buf, int inx, const uchar *key_data,
not satisfied with an out-of-range condition.
*/
if ((*share->row_is_visible)(info) &&
- ((icp_res= ma_check_index_cond(info, inx, buf)) != 0))
+ ((icp_res= ma_check_index_cond(info, inx, buf)) != ICP_NO_MATCH))
break;
/* The key references a concurrently inserted record. */
@@ -145,6 +145,18 @@ int maria_rkey(MARIA_HA *info, uchar *buf, int inx, const uchar *key_data,
if (_ma_search_next(info, &lastkey, maria_readnext_vec[search_flag],
info->s->state.key_root[inx]))
break; /* purecov: inspected */
+
+ /*
+ If we are at the last key on the key page, allow writers to
+ access the index.
+ */
+ if (info->int_keypos >= info->int_maxpos &&
+ ma_yield_and_check_if_killed(info, inx))
+ {
+ DBUG_ASSERT(info->cur_row.lastpos == HA_OFFSET_ERROR);
+ break;
+ }
+
/*
Check that the found key does still match the search.
_ma_search_next() delivers the next key regardless of its
@@ -164,15 +176,19 @@ int maria_rkey(MARIA_HA *info, uchar *buf, int inx, const uchar *key_data,
} while (!(*share->row_is_visible)(info) ||
((icp_res= ma_check_index_cond(info, inx, buf)) == 0));
}
+ else
+ {
+ DBUG_ASSERT(info->cur_row.lastpos);
+ }
}
if (share->lock_key_trees)
rw_unlock(&keyinfo->root_lock);
- if (info->cur_row.lastpos == HA_OFFSET_ERROR || (icp_res != 1))
+ if (info->cur_row.lastpos == HA_OFFSET_ERROR)
{
- if (icp_res == 2)
+ if (icp_res == ICP_OUT_OF_RANGE)
{
- info->cur_row.lastpos= HA_OFFSET_ERROR;
+ /* We don't want HA_ERR_END_OF_FILE in this particular case */
my_errno= HA_ERR_KEY_NOT_FOUND;
}
fast_ma_writeinfo(info);
@@ -214,3 +230,37 @@ err:
info->update|=HA_STATE_NEXT_FOUND; /* Previous gives last row */
DBUG_RETURN(my_errno);
} /* _ma_rkey */
+
+
+/*
+ Yield to possible other writers during a index scan.
+ Check also if we got killed by the user and if yes, return
+ HA_ERR_LOCK_WAIT_TIMEOUT
+
+ return 0 ok
+ return 1 Query has been requested to be killed
+*/
+
+my_bool ma_yield_and_check_if_killed(MARIA_HA *info, int inx)
+{
+ MARIA_SHARE *share;
+ if (ma_killed(info))
+ {
+ /* purecov: begin tested */
+ /* Mark that we don't have an active row */
+ info->cur_row.lastpos= HA_OFFSET_ERROR;
+ /* Set error that we where aborted by kill from application */
+ my_errno= HA_ERR_ABORTED_BY_USER;
+ return 1;
+ /* purecov: end */
+ }
+
+ if ((share= info->s)->lock_key_trees)
+ {
+ /* Give writers a chance to access index */
+ rw_unlock(&share->keyinfo[inx].root_lock);
+ rw_rdlock(&share->keyinfo[inx].root_lock);
+ }
+ return 0;
+}
+
diff --git a/storage/maria/ma_rnext.c b/storage/maria/ma_rnext.c
index bdba5ff3a17..2fd8bf4e603 100644
--- a/storage/maria/ma_rnext.c
+++ b/storage/maria/ma_rnext.c
@@ -30,7 +30,7 @@ int maria_rnext(MARIA_HA *info, uchar *buf, int inx)
uint flag;
MARIA_SHARE *share= info->s;
MARIA_KEYDEF *keyinfo;
- int icp_res= 1;
+ ICP_RESULT icp_res= ICP_MATCH;
DBUG_ENTER("maria_rnext");
if ((inx = _ma_check_index(info,inx)) < 0)
@@ -92,8 +92,20 @@ int maria_rnext(MARIA_HA *info, uchar *buf, int inx)
if (!error)
{
while (!(*share->row_is_visible)(info) ||
- ((icp_res= ma_check_index_cond(info, inx, buf)) == 0))
+ ((icp_res= ma_check_index_cond(info, inx, buf)) == ICP_NO_MATCH))
{
+ /*
+ If we are at the last key on the key page, allow writers to
+ access the index.
+ */
+ if (info->int_keypos >= info->int_maxpos &&
+ ma_yield_and_check_if_killed(info, inx))
+ {
+ /* my_errno is set by ma_yield_and_check_if_killed() */
+ error= 1;
+ break;
+ }
+
/* Skip rows inserted by other threads since we got a lock */
if ((error= _ma_search_next(info, &info->last_key,
SEARCH_BIGGER,
@@ -108,16 +120,15 @@ int maria_rnext(MARIA_HA *info, uchar *buf, int inx)
info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
info->update|= HA_STATE_NEXT_FOUND;
- if (icp_res == 2)
- my_errno=HA_ERR_END_OF_FILE; /* got beyond the end of scanned range */
-
- if (error || icp_res != 1)
+ if (error || icp_res != ICP_MATCH)
{
+ fast_ma_writeinfo(info);
if (my_errno == HA_ERR_KEY_NOT_FOUND)
- my_errno=HA_ERR_END_OF_FILE;
+ my_errno= HA_ERR_END_OF_FILE;
}
else if (!buf)
{
+ fast_ma_writeinfo(info);
DBUG_RETURN(info->cur_row.lastpos == HA_OFFSET_ERROR ? my_errno : 0);
}
else if (!(*info->read_record)(info, buf, info->cur_row.lastpos))
diff --git a/storage/maria/ma_rnext_same.c b/storage/maria/ma_rnext_same.c
index f67a76a366f..c35d8ae0222 100644
--- a/storage/maria/ma_rnext_same.c
+++ b/storage/maria/ma_rnext_same.c
@@ -30,7 +30,7 @@ int maria_rnext_same(MARIA_HA *info, uchar *buf)
int error;
uint inx,not_used[2];
MARIA_KEYDEF *keyinfo;
- int icp_res= 1;
+ ICP_RESULT icp_res= ICP_MATCH;
DBUG_ENTER("maria_rnext_same");
if ((int) (inx= info->lastinx) < 0 ||
@@ -80,9 +80,19 @@ int maria_rnext_same(MARIA_HA *info, uchar *buf)
info->cur_row.lastpos= HA_OFFSET_ERROR;
break;
}
+ /*
+ If we are at the last key on the key page, allow writers to
+ access the index.
+ */
+ if (info->int_keypos >= info->int_maxpos &&
+ ma_yield_and_check_if_killed(info, inx))
+ {
+ error= 1;
+ break;
+ }
/* Skip rows that are inserted by other threads since we got a lock */
if ((info->s->row_is_visible)(info) &&
- ((icp_res= ma_check_index_cond(info, inx, buf)) != 0))
+ ((icp_res= ma_check_index_cond(info, inx, buf)) != ICP_NO_MATCH))
break;
}
}
@@ -92,16 +102,15 @@ int maria_rnext_same(MARIA_HA *info, uchar *buf)
info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
info->update|= HA_STATE_NEXT_FOUND | HA_STATE_RNEXT_SAME;
- if (icp_res == 2)
- my_errno=HA_ERR_END_OF_FILE; /* got beyond the end of scanned range */
-
- if (error || icp_res != 1)
+ if (error || icp_res != ICP_MATCH)
{
+ fast_ma_writeinfo(info);
if (my_errno == HA_ERR_KEY_NOT_FOUND)
- my_errno=HA_ERR_END_OF_FILE;
+ my_errno= HA_ERR_END_OF_FILE;
}
else if (!buf)
{
+ fast_ma_writeinfo(info);
DBUG_RETURN(info->cur_row.lastpos == HA_OFFSET_ERROR ? my_errno : 0);
}
else if (!(*info->read_record)(info, buf, info->cur_row.lastpos))
diff --git a/storage/maria/ma_rprev.c b/storage/maria/ma_rprev.c
index b9f46d7c405..c4bcb9de967 100644
--- a/storage/maria/ma_rprev.c
+++ b/storage/maria/ma_rprev.c
@@ -28,6 +28,7 @@ int maria_rprev(MARIA_HA *info, uchar *buf, int inx)
register uint flag;
MARIA_SHARE *share= info->s;
MARIA_KEYDEF *keyinfo;
+ ICP_RESULT icp_res= ICP_MATCH;
DBUG_ENTER("maria_rprev");
if ((inx = _ma_check_index(info,inx)) < 0)
@@ -55,8 +56,24 @@ int maria_rprev(MARIA_HA *info, uchar *buf, int inx)
if (!error)
{
- while (!(*share->row_is_visible)(info))
+ my_off_t cur_keypage= info->last_keypage;
+ while (!(*share->row_is_visible)(info) ||
+ ((icp_res= ma_check_index_cond(info, inx, buf)) == ICP_NO_MATCH))
{
+ /*
+ If we are at the last (i.e. first?) key on the key page,
+ allow writers to access the index.
+ */
+ if (info->last_keypage != cur_keypage)
+ {
+ cur_keypage= info->last_keypage;
+ if (ma_yield_and_check_if_killed(info, inx))
+ {
+ error= 1;
+ break;
+ }
+ }
+
/* Skip rows that are inserted by other threads since we got a lock */
if ((error= _ma_search_next(info, &info->last_key,
SEARCH_SMALLER,
@@ -68,13 +85,16 @@ int maria_rprev(MARIA_HA *info, uchar *buf, int inx)
rw_unlock(&keyinfo->root_lock);
info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
info->update|= HA_STATE_PREV_FOUND;
- if (error)
+
+ if (error || icp_res != ICP_MATCH)
{
+ fast_ma_writeinfo(info);
if (my_errno == HA_ERR_KEY_NOT_FOUND)
- my_errno=HA_ERR_END_OF_FILE;
+ my_errno= HA_ERR_END_OF_FILE;
}
else if (!buf)
{
+ fast_ma_writeinfo(info);
DBUG_RETURN(info->cur_row.lastpos == HA_OFFSET_ERROR ? my_errno : 0);
}
else if (!(*info->read_record)(info, buf, info->cur_row.lastpos))
diff --git a/storage/maria/ma_search.c b/storage/maria/ma_search.c
index 8d3b5721336..4ac6dfeb15f 100644
--- a/storage/maria/ma_search.c
+++ b/storage/maria/ma_search.c
@@ -141,7 +141,11 @@ static int _ma_search_no_save(register MARIA_HA *info, MARIA_KEY *key,
flag= (*keyinfo->bin_search)(key, &page, nextflag, &keypos, lastkey,
&last_key_not_used);
if (flag == MARIA_FOUND_WRONG_KEY)
- DBUG_RETURN(-1);
+ {
+ maria_print_error(info->s, HA_ERR_CRASHED);
+ my_errno= HA_ERR_CRASHED;
+ goto err;
+ }
page_flag= page.flag;
used_length= page.size;
nod_flag= page.node;
diff --git a/storage/maria/ma_static.c b/storage/maria/ma_static.c
index 917385f9568..37814b42dc2 100644
--- a/storage/maria/ma_static.c
+++ b/storage/maria/ma_static.c
@@ -107,3 +107,6 @@ static int always_valid(const char *filename __attribute__((unused)))
}
int (*maria_test_invalid_symlink)(const char *filename)= always_valid;
+
+my_bool (*ma_killed)(MARIA_HA *)= ma_killed_standalone;
+
diff --git a/storage/maria/maria_def.h b/storage/maria/maria_def.h
index 65898666686..beb286c7d4b 100644
--- a/storage/maria/maria_def.h
+++ b/storage/maria/maria_def.h
@@ -492,7 +492,6 @@ struct st_maria_handler
{
MARIA_SHARE *s; /* Shared between open:s */
struct st_ma_transaction *trn; /* Pointer to active transaction */
- void *external_ptr; /* Pointer to THD in mysql */
MARIA_STATUS_INFO *state, state_save;
MARIA_STATUS_INFO *state_start; /* State at start of transaction */
MARIA_ROW cur_row; /* The active row that we just read */
@@ -509,6 +508,7 @@ struct st_maria_handler
DYNAMIC_ARRAY *ft1_to_ft2; /* used only in ft1->ft2 conversion */
MEM_ROOT ft_memroot; /* used by the parser */
MYSQL_FTPARSER_PARAM *ftparser_param; /* share info between init/deinit */
+ void *external_ref; /* For MariaDB TABLE */
uchar *buff; /* page buffer */
uchar *keyread_buff; /* Buffer for last key read */
uchar *lastkey_buff; /* Last used search key */
@@ -813,6 +813,7 @@ extern my_bool maria_inited, maria_in_ha_maria, maria_recovery_changed_data;
extern my_bool maria_recovery_verbose;
extern HASH maria_stored_state;
extern int (*maria_create_trn_hook)(MARIA_HA *);
+extern my_bool (*ma_killed)(MARIA_HA *);
/* This is used by _ma_calc_xxx_key_length och _ma_store_key */
typedef struct st_maria_s_param
@@ -1281,4 +1282,8 @@ extern my_bool maria_flush_log_for_page_none(uchar *page,
extern PAGECACHE *maria_log_pagecache;
extern void ma_set_index_cond_func(MARIA_HA *info, index_cond_func_t func,
void *func_arg);
-int ma_check_index_cond(register MARIA_HA *info, uint keynr, uchar *record);
+ICP_RESULT ma_check_index_cond(register MARIA_HA *info, uint keynr, uchar *record);
+
+extern my_bool ma_yield_and_check_if_killed(MARIA_HA *info, int inx);
+extern my_bool ma_killed_standalone(MARIA_HA *);
+
diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc
index 781ce39a99a..b32cce9e43c 100644
--- a/storage/myisam/ha_myisam.cc
+++ b/storage/myisam/ha_myisam.cc
@@ -538,6 +538,13 @@ void mi_check_print_warning(HA_CHECK *param, const char *fmt,...)
va_end(args);
}
+/* Return 1 if user have requested query to be killed */
+
+my_bool mi_killed_in_mariadb(MI_INFO *info)
+{
+ return (((TABLE*) (info->external_ref))->in_use->killed != 0);
+}
+
}
@@ -699,6 +706,8 @@ int ha_myisam::open(const char *name, int mode, uint test_if_locked)
return (my_errno ? my_errno : -1);
file->s->chst_invalidator= query_cache_invalidate_by_MyISAM_filename_ref;
+ /* Set external_ref, mainly for temporary tables */
+ file->external_ref= (void*) table; // For mi_killed()
if (!table->s->tmp_table) /* No need to perform a check for tmp table */
{
@@ -1971,6 +1980,7 @@ int ha_myisam::delete_table(const char *name)
int ha_myisam::external_lock(THD *thd, int lock_type)
{
+ file->external_ref= (void*) table; // For mi_killed()
return mi_lock_database(file, !table->s->tmp_table ?
lock_type : ((lock_type == F_UNLCK) ?
F_UNLCK : F_EXTRA_LCK));
@@ -2219,6 +2229,7 @@ static int myisam_init(void *p)
myisam_hton->create= myisam_create_handler;
myisam_hton->panic= myisam_panic;
myisam_hton->flags= HTON_CAN_RECREATE | HTON_SUPPORT_LOG_TABLES;
+ mi_killed= mi_killed_in_mariadb;
return 0;
}
diff --git a/storage/myisam/mi_extra.c b/storage/myisam/mi_extra.c
index 648e5fb0024..2f8af89c27d 100644
--- a/storage/myisam/mi_extra.c
+++ b/storage/myisam/mi_extra.c
@@ -473,3 +473,8 @@ int mi_reset(MI_INFO *info)
HA_STATE_PREV_FOUND);
DBUG_RETURN(error);
}
+
+my_bool mi_killed_standalone(MI_INFO *info __attribute__((unused)))
+{
+ return 0;
+}
diff --git a/storage/myisam/mi_key.c b/storage/myisam/mi_key.c
index 52273f013ec..a3d38269e61 100644
--- a/storage/myisam/mi_key.c
+++ b/storage/myisam/mi_key.c
@@ -510,15 +510,26 @@ int _mi_read_key_record(MI_INFO *info, my_off_t filepos, uchar *buf)
ICP_OUT_OF_RANGE Index condition is not satisfied, end the scan.
*/
-int mi_check_index_cond(register MI_INFO *info, uint keynr, uchar *record)
+ICP_RESULT mi_check_index_cond(register MI_INFO *info, uint keynr,
+ uchar *record)
{
+ ICP_RESULT res;
if (_mi_put_key_in_record(info, keynr, FALSE, record))
{
+ /* Impossible case; Can only happen if bug in code */
mi_print_error(info->s, HA_ERR_CRASHED);
- my_errno=HA_ERR_CRASHED;
- return ICP_ERROR;
+ info->lastpos= HA_OFFSET_ERROR; /* No active record */
+ my_errno= HA_ERR_CRASHED;
+ res= ICP_ERROR;
}
- return info->index_cond_func(info->index_cond_func_arg);
+ else if ((res= info->index_cond_func(info->index_cond_func_arg)) ==
+ ICP_OUT_OF_RANGE)
+ {
+ /* We got beyond the end of scanned range */
+ info->lastpos= HA_OFFSET_ERROR; /* No active record */
+ my_errno= HA_ERR_END_OF_FILE;
+ }
+ return res;
}
/*
diff --git a/storage/myisam/mi_rkey.c b/storage/myisam/mi_rkey.c
index da757d270bc..dbe4d59ee90 100644
--- a/storage/myisam/mi_rkey.c
+++ b/storage/myisam/mi_rkey.c
@@ -88,6 +88,7 @@ int mi_rkey(MI_INFO *info, uchar *buf, int inx, const uchar *key,
my_errno=HA_ERR_CRASHED;
if (share->concurrent_insert)
rw_unlock(&share->key_root_lock[inx]);
+ fast_mi_writeinfo(info);
goto err;
}
break;
@@ -131,7 +132,10 @@ int mi_rkey(MI_INFO *info, uchar *buf, int inx, const uchar *key,
info->lastkey_length,
myisam_readnext_vec[search_flag],
info->s->state.key_root[inx]))
+ {
+ info->lastpos= HA_OFFSET_ERROR;
break;
+ }
/*
Check that the found key does still match the search.
_mi_search_next() delivers the next key regardless of its
@@ -145,13 +149,22 @@ int mi_rkey(MI_INFO *info, uchar *buf, int inx, const uchar *key,
info->lastpos= HA_OFFSET_ERROR;
break;
}
+ /*
+ If we are at the last key on the key page, allow writers to
+ access the index.
+ */
+ if (info->int_keypos >= info->int_maxpos &&
+ mi_yield_and_check_if_killed(info, inx))
+ {
+ /* Aborted by user */
+ buf= 0; /* Fast abort */
+ }
}
if (res == ICP_OUT_OF_RANGE)
{
- info->lastpos= HA_OFFSET_ERROR;
- if (share->concurrent_insert)
- rw_unlock(&share->key_root_lock[inx]);
- DBUG_RETURN((my_errno= HA_ERR_KEY_NOT_FOUND));
+ /* Change error from HA_ERR_END_OF_FILE */
+ DBUG_ASSERT(info->lastpos == HA_OFFSET_ERROR);
+ my_errno= HA_ERR_KEY_NOT_FOUND;
}
/*
Error if no row found within the data file. (Bug #29838)
@@ -164,29 +177,43 @@ int mi_rkey(MI_INFO *info, uchar *buf, int inx, const uchar *key,
my_errno= HA_ERR_KEY_NOT_FOUND;
}
}
+ else
+ {
+ DBUG_ASSERT(info->lastpos= HA_OFFSET_ERROR);
+ }
}
if (share->concurrent_insert)
rw_unlock(&share->key_root_lock[inx]);
- /* Calculate length of the found key; Used by mi_rnext_same */
- if ((keyinfo->flag & HA_VAR_LENGTH_KEY) && last_used_keyseg &&
- info->lastpos != HA_OFFSET_ERROR)
- info->last_rkey_length= _mi_keylength_part(keyinfo, info->lastkey,
- last_used_keyseg);
- else
- info->last_rkey_length= pack_key_length;
-
- /* Check if we don't want to have record back, only error message */
- if (!buf)
- DBUG_RETURN(info->lastpos == HA_OFFSET_ERROR ? my_errno : 0);
+ info->last_rkey_length= pack_key_length;
- if (!(*info->read_record)(info,info->lastpos,buf))
+ if (info->lastpos == HA_OFFSET_ERROR) /* No such record */
{
- info->update|= HA_STATE_AKTIV; /* Record is read */
- DBUG_RETURN(0);
+ fast_mi_writeinfo(info);
+ if (!buf)
+ DBUG_RETURN(my_errno);
}
+ else
+ {
+ /* Calculate length of the found key; Used by mi_rnext_same */
+ if ((keyinfo->flag & HA_VAR_LENGTH_KEY) && last_used_keyseg)
+ info->last_rkey_length= _mi_keylength_part(keyinfo, info->lastkey,
+ last_used_keyseg);
- info->lastpos = HA_OFFSET_ERROR; /* Didn't find key */
+ /* Check if we don't want to have record back, only error message */
+ if (!buf)
+ {
+ fast_mi_writeinfo(info);
+ DBUG_RETURN(0);
+ }
+ if (!(*info->read_record)(info,info->lastpos,buf))
+ {
+ info->update|= HA_STATE_AKTIV; /* Record is read */
+ DBUG_RETURN(0);
+ }
+ DBUG_PRINT("error", ("Didn't find row. Error %d", my_errno));
+ info->lastpos= HA_OFFSET_ERROR; /* Didn't find row */
+ }
/* Store last used key as a base for read next */
memcpy(info->lastkey,key_buff,pack_key_length);
@@ -199,3 +226,36 @@ int mi_rkey(MI_INFO *info, uchar *buf, int inx, const uchar *key,
err:
DBUG_RETURN(my_errno);
} /* _mi_rkey */
+
+
+/*
+ Yield to possible other writers during a index scan.
+ Check also if we got killed by the user and if yes, return
+ HA_ERR_LOCK_WAIT_TIMEOUT
+
+ return 0 ok
+ return 1 Query has been requested to be killed
+*/
+
+my_bool mi_yield_and_check_if_killed(MI_INFO *info, int inx)
+{
+ MYISAM_SHARE *share;
+ if (mi_killed(info))
+ {
+ /* purecov: begin tested */
+ info->lastpos= HA_OFFSET_ERROR;
+ /* Set error that we where aborted by kill from application */
+ my_errno= HA_ERR_ABORTED_BY_USER;
+ return 1;
+ /* purecov: end */
+
+ }
+
+ if ((share= info->s)->concurrent_insert)
+ {
+ /* Give writers a chance to access index */
+ rw_unlock(&share->key_root_lock[inx]);
+ rw_rdlock(&share->key_root_lock[inx]);
+ }
+ return 0;
+}
diff --git a/storage/myisam/mi_rnext.c b/storage/myisam/mi_rnext.c
index b1c261dd6b1..79db5fb992d 100644
--- a/storage/myisam/mi_rnext.c
+++ b/storage/myisam/mi_rnext.c
@@ -28,7 +28,7 @@ int mi_rnext(MI_INFO *info, uchar *buf, int inx)
{
int error,changed;
uint flag;
- ICP_RESULT res= 0;
+ ICP_RESULT icp_res= ICP_MATCH;
uint update_mask= HA_STATE_NEXT_FOUND;
DBUG_ENTER("mi_rnext");
@@ -102,8 +102,19 @@ int mi_rnext(MI_INFO *info, uchar *buf, int inx)
while ((info->s->concurrent_insert &&
info->lastpos >= info->state->data_file_length) ||
(info->index_cond_func &&
- (res= mi_check_index_cond(info, inx, buf)) == ICP_NO_MATCH))
+ (icp_res= mi_check_index_cond(info, inx, buf)) == ICP_NO_MATCH))
{
+ /*
+ If we are at the last key on the key page, allow writers to
+ access the index.
+ */
+ if (info->int_keypos >= info->int_maxpos &&
+ mi_yield_and_check_if_killed(info, inx))
+ {
+ error= 1;
+ break;
+ }
+
/*
Skip rows that are either inserted by other threads since
we got a lock or do not match pushed index conditions
@@ -115,13 +126,6 @@ int mi_rnext(MI_INFO *info, uchar *buf, int inx)
info->s->state.key_root[inx])))
break;
}
- if (!error && res == ICP_OUT_OF_RANGE)
- {
- if (info->s->concurrent_insert)
- rw_unlock(&info->s->key_root_lock[inx]);
- info->lastpos= HA_OFFSET_ERROR;
- DBUG_RETURN(my_errno= HA_ERR_END_OF_FILE);
- }
}
if (info->s->concurrent_insert)
@@ -131,13 +135,15 @@ int mi_rnext(MI_INFO *info, uchar *buf, int inx)
info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
info->update|= update_mask;
- if (error)
+ if (error || icp_res != ICP_MATCH)
{
+ fast_mi_writeinfo(info);
if (my_errno == HA_ERR_KEY_NOT_FOUND)
my_errno=HA_ERR_END_OF_FILE;
}
else if (!buf)
{
+ fast_mi_writeinfo(info);
DBUG_RETURN(info->lastpos==HA_OFFSET_ERROR ? my_errno : 0);
}
else if (!(*info->read_record)(info,info->lastpos,buf))
diff --git a/storage/myisam/mi_rnext_same.c b/storage/myisam/mi_rnext_same.c
index df3b678d663..3aa7e93dfd5 100644
--- a/storage/myisam/mi_rnext_same.c
+++ b/storage/myisam/mi_rnext_same.c
@@ -29,6 +29,7 @@ int mi_rnext_same(MI_INFO *info, uchar *buf)
int error;
uint inx,not_used[2];
MI_KEYDEF *keyinfo;
+ ICP_RESULT icp_res= ICP_MATCH;
DBUG_ENTER("mi_rnext_same");
if ((int) (inx=info->lastinx) < 0 || info->lastpos == HA_OFFSET_ERROR)
@@ -63,6 +64,17 @@ int mi_rnext_same(MI_INFO *info, uchar *buf)
}
for (;;)
{
+ /*
+ If we are at the last key on the key page, allow writers to
+ access the index.
+ */
+ if (info->int_keypos >= info->int_maxpos &&
+ mi_yield_and_check_if_killed(info, inx))
+ {
+ error=1;
+ break;
+ }
+
if ((error=_mi_search_next(info,keyinfo,info->lastkey,
info->lastkey_length,SEARCH_BIGGER,
info->s->state.key_root[inx])))
@@ -78,26 +90,30 @@ int mi_rnext_same(MI_INFO *info, uchar *buf)
/*
Skip
- rows that are inserted by other threads since we got a lock
- - rows that don't match index condition */
+ - rows that don't match index condition
+ */
if (info->lastpos < info->state->data_file_length &&
(!info->index_cond_func ||
- mi_check_index_cond(info, inx, buf) != ICP_NO_MATCH))
+ (icp_res= mi_check_index_cond(info, inx, buf)) != ICP_NO_MATCH))
break;
}
}
if (info->s->concurrent_insert)
rw_unlock(&info->s->key_root_lock[inx]);
+
/* Don't clear if database-changed */
info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
info->update|= HA_STATE_NEXT_FOUND | HA_STATE_RNEXT_SAME;
- if (error)
+ if (error || icp_res != ICP_MATCH)
{
+ fast_mi_writeinfo(info);
if (my_errno == HA_ERR_KEY_NOT_FOUND)
my_errno=HA_ERR_END_OF_FILE;
}
else if (!buf)
{
+ fast_mi_writeinfo(info);
DBUG_RETURN(info->lastpos==HA_OFFSET_ERROR ? my_errno : 0);
}
else if (!(*info->read_record)(info,info->lastpos,buf))
diff --git a/storage/myisam/mi_rprev.c b/storage/myisam/mi_rprev.c
index 93bd224bd56..040b08b428c 100644
--- a/storage/myisam/mi_rprev.c
+++ b/storage/myisam/mi_rprev.c
@@ -27,6 +27,7 @@ int mi_rprev(MI_INFO *info, uchar *buf, int inx)
int error,changed;
register uint flag;
MYISAM_SHARE *share=info->s;
+ ICP_RESULT icp_res= ICP_MATCH;
DBUG_ENTER("mi_rprev");
if ((inx = _mi_check_index(info,inx)) < 0)
@@ -53,12 +54,26 @@ int mi_rprev(MI_INFO *info, uchar *buf, int inx)
if (!error)
{
- int res= 0;
+ my_off_t cur_keypage= info->last_keypage;
while ((share->concurrent_insert &&
info->lastpos >= info->state->data_file_length) ||
(info->index_cond_func &&
- !(res= mi_check_index_cond(info, inx, buf))))
+ (icp_res= mi_check_index_cond(info, inx, buf)) == ICP_NO_MATCH))
{
+ /*
+ If we are at the last (i.e. first?) key on the key page,
+ allow writers to access the index.
+ */
+ if (info->last_keypage != cur_keypage)
+ {
+ cur_keypage= info->last_keypage;
+ if (mi_yield_and_check_if_killed(info, inx))
+ {
+ error= 1;
+ break;
+ }
+ }
+
/*
Skip rows that are either inserted by other threads since
we got a lock or do not match pushed index conditions
@@ -69,13 +84,6 @@ int mi_rprev(MI_INFO *info, uchar *buf, int inx)
share->state.key_root[inx])))
break;
}
- if (!error && res == 2)
- {
- if (share->concurrent_insert)
- rw_unlock(&share->key_root_lock[inx]);
- info->lastpos= HA_OFFSET_ERROR;
- DBUG_RETURN(my_errno= HA_ERR_END_OF_FILE);
- }
}
if (share->concurrent_insert)
@@ -83,13 +91,16 @@ int mi_rprev(MI_INFO *info, uchar *buf, int inx)
info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
info->update|= HA_STATE_PREV_FOUND;
- if (error)
+
+ if (error || icp_res != ICP_MATCH)
{
+ fast_mi_writeinfo(info);
if (my_errno == HA_ERR_KEY_NOT_FOUND)
my_errno=HA_ERR_END_OF_FILE;
}
else if (!buf)
{
+ fast_mi_writeinfo(info);
DBUG_RETURN(info->lastpos==HA_OFFSET_ERROR ? my_errno : 0);
}
else if (!(*info->read_record)(info,info->lastpos,buf))
diff --git a/storage/myisam/mi_search.c b/storage/myisam/mi_search.c
index 1f8399f25ca..13ee552e7ec 100644
--- a/storage/myisam/mi_search.c
+++ b/storage/myisam/mi_search.c
@@ -89,7 +89,10 @@ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
flag=(*keyinfo->bin_search)(info,keyinfo,buff,key,key_len,nextflag,
&keypos,lastkey, &last_key);
if (flag == MI_FOUND_WRONG_KEY)
- DBUG_RETURN(-1);
+ {
+ my_errno= HA_ERR_CRASHED;
+ goto err;
+ }
nod_flag=mi_test_if_nod(buff);
maxpos=buff+mi_getint(buff)-1;
diff --git a/storage/myisam/mi_static.c b/storage/myisam/mi_static.c
index 27485e101ff..2d297ddc907 100644
--- a/storage/myisam/mi_static.c
+++ b/storage/myisam/mi_static.c
@@ -41,6 +41,7 @@ my_off_t myisam_max_temp_length= MAX_FILE_SIZE;
ulong myisam_bulk_insert_tree_size=8192*1024;
ulong myisam_data_pointer_size=4;
ulonglong myisam_mmap_size= SIZE_T_MAX, myisam_mmap_used= 0;
+my_bool (*mi_killed)(MI_INFO *)= mi_killed_standalone;
static int always_valid(const char *filename __attribute__((unused)))
{
diff --git a/storage/myisam/myisamdef.h b/storage/myisam/myisamdef.h
index 20974e0b717..cde46e9dd96 100644
--- a/storage/myisam/myisamdef.h
+++ b/storage/myisam/myisamdef.h
@@ -248,6 +248,7 @@ struct st_myisam_info
DYNAMIC_ARRAY *ft1_to_ft2; /* used only in ft1->ft2 conversion */
MEM_ROOT ft_memroot; /* used by the parser */
MYSQL_FTPARSER_PARAM *ftparser_param; /* share info between init/deinit */
+ void *external_ref; /* For MariaDB TABLE */
char *filename; /* parameter to open filename */
uchar *buff, /* Temp area for key */
*lastkey, *lastkey2; /* Last used search key */
@@ -433,6 +434,7 @@ extern uint NEAR myisam_read_vec[], NEAR myisam_readnext_vec[];
extern uint myisam_quick_table_bits;
extern File myisam_log_file;
extern ulong myisam_pid;
+extern my_bool (*mi_killed)(MI_INFO *);
/* This is used by _mi_calc_xxx_key_length och _mi_store_key */
@@ -593,6 +595,8 @@ extern ulonglong mi_safe_mul(ulonglong a, ulonglong b);
extern int _mi_ft_update(MI_INFO *info, uint keynr, uchar *keybuf,
const uchar *oldrec, const uchar *newrec,
my_off_t pos);
+extern my_bool mi_yield_and_check_if_killed(MI_INFO *info, int inx);
+extern my_bool mi_killed_standalone(MI_INFO *);
struct st_sort_info;
@@ -729,7 +733,7 @@ my_bool mi_dynmap_file(MI_INFO *info, my_off_t size);
int mi_munmap_file(MI_INFO *info);
void mi_remap_file(MI_INFO *info, my_off_t size);
-int mi_check_index_cond(register MI_INFO *info, uint keynr, uchar *record);
+ICP_RESULT mi_check_index_cond(register MI_INFO *info, uint keynr, uchar *record);
/* Functions needed by mi_check */
int killed_ptr(HA_CHECK *param);
void mi_check_print_error _VARARGS((HA_CHECK *param, const char *fmt, ...));
diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc
index 6eeaa4187ac..39621852c4c 100644
--- a/storage/xtradb/handler/ha_innodb.cc
+++ b/storage/xtradb/handler/ha_innodb.cc
@@ -126,7 +126,7 @@ static pthread_mutex_t commit_cond_m;
static bool innodb_inited = 0;
C_MODE_START
-static int index_cond_func_innodb(void *arg);
+static xtradb_icp_result_t index_cond_func_innodb(void *arg);
C_MODE_END
@@ -853,6 +853,9 @@ convert_error_code_to_mysql(
case DB_RECORD_NOT_FOUND:
return(HA_ERR_NO_ACTIVE_RECORD);
+ case DB_SEARCH_ABORTED_BY_USER:
+ return(HA_ERR_ABORTED_BY_USER);
+
case DB_DEADLOCK:
/* Since we rolled back the whole transaction, we must
tell it also to MySQL so that MySQL knows to empty the
@@ -12082,6 +12085,14 @@ ha_rows ha_innobase::multi_range_read_info(uint keyno, uint n_ranges, uint keys,
}
+/*
+ A helper function used only in index_cond_func_innodb
+*/
+
+bool ha_innobase::is_thd_killed()
+{
+ return test(user_thd->killed);
+}
/**
* Index Condition Pushdown interface implementation
@@ -12094,15 +12105,18 @@ C_MODE_START
See note on ICP_RESULT for return values description.
*/
-static int index_cond_func_innodb(void *arg)
+static xtradb_icp_result_t index_cond_func_innodb(void *arg)
{
ha_innobase *h= (ha_innobase*)arg;
+ if (h->is_thd_killed())
+ return XTRADB_ICP_ERROR;
+
if (h->end_range)
{
if (h->compare_key2(h->end_range) > 0)
- return ICP_OUT_OF_RANGE; /* caller should return HA_ERR_END_OF_FILE already */
+ return XTRADB_ICP_OUT_OF_RANGE; /* caller should return HA_ERR_END_OF_FILE already */
}
- return h->pushed_idx_cond->val_int()? ICP_MATCH : ICP_NO_MATCH;
+ return h->pushed_idx_cond->val_int()? XTRADB_ICP_MATCH : XTRADB_ICP_NO_MATCH;
}
C_MODE_END
diff --git a/storage/xtradb/handler/ha_innodb.h b/storage/xtradb/handler/ha_innodb.h
index 8945ce95ee5..c3d90491f31 100644
--- a/storage/xtradb/handler/ha_innodb.h
+++ b/storage/xtradb/handler/ha_innodb.h
@@ -240,6 +240,9 @@ public:
DsMrr_impl ds_mrr;
Item *idx_cond_push(uint keyno, Item* idx_cond);
+
+ /* An helper function for index_cond_func_innodb: */
+ bool is_thd_killed();
};
/* Some accessor functions which the InnoDB plugin needs, but which
diff --git a/storage/xtradb/include/db0err.h b/storage/xtradb/include/db0err.h
index c7fa6d2a444..220878629fb 100644
--- a/storage/xtradb/include/db0err.h
+++ b/storage/xtradb/include/db0err.h
@@ -105,7 +105,8 @@ enum db_err {
DB_STRONG_FAIL,
DB_ZIP_OVERFLOW,
DB_RECORD_NOT_FOUND = 1500,
- DB_END_OF_INDEX
+ DB_END_OF_INDEX,
+ DB_SEARCH_ABORTED_BY_USER= 1533
};
#endif
diff --git a/storage/xtradb/include/row0mysql.h b/storage/xtradb/include/row0mysql.h
index fbb9ee92a90..88de6421cf9 100644
--- a/storage/xtradb/include/row0mysql.h
+++ b/storage/xtradb/include/row0mysql.h
@@ -577,7 +577,16 @@ struct mysql_row_templ_struct {
#define ROW_PREBUILT_ALLOCATED 78540783
#define ROW_PREBUILT_FREED 26423527
-typedef int (*index_cond_func_t)(void *param);
+
+typedef enum xtradb_icp_result {
+ XTRADB_ICP_ERROR=-1,
+ XTRADB_ICP_NO_MATCH=0,
+ XTRADB_ICP_MATCH=1,
+ XTRADB_ICP_OUT_OF_RANGE=2,
+ XTRADB_ICP_ABORTED_BY_USER=3,
+} xtradb_icp_result_t;
+
+typedef xtradb_icp_result_t (*index_cond_func_t)(void *param);
/** A struct for (sometimes lazily) prebuilt structures in an Innobase table
handle used within MySQL; these are used to save CPU time. */
diff --git a/storage/xtradb/row/row0sel.c b/storage/xtradb/row/row0sel.c
index 4c6a91f3c69..79cf88904eb 100644
--- a/storage/xtradb/row/row0sel.c
+++ b/storage/xtradb/row/row0sel.c
@@ -3348,7 +3348,8 @@ and fetch prev. NOTE that if we do a search with a full key value
from a unique index (ROW_SEL_EXACT), then we will not store the cursor
position and fetch next or fetch prev must not be tried to the cursor!
@return DB_SUCCESS, DB_RECORD_NOT_FOUND, DB_END_OF_INDEX, DB_DEADLOCK,
-DB_LOCK_TABLE_FULL, DB_CORRUPTION, or DB_TOO_BIG_RECORD */
+DB_LOCK_TABLE_FULL, DB_CORRUPTION, DB_SEARCH_ABORTED_BY_USER or
+DB_TOO_BIG_RECORD */
UNIV_INTERN
ulint
row_search_for_mysql(
@@ -4396,12 +4397,15 @@ idx_cond_check:
*/
ut_ad(ib_res);
res= prebuilt->idx_cond_func(prebuilt->idx_cond_func_arg);
- if (res == 0)
+ if (res == XTRADB_ICP_NO_MATCH)
goto next_rec;
- if (res == 2) {
- err = DB_RECORD_NOT_FOUND;
+ else if (res != XTRADB_ICP_MATCH) {
+ err= (res == XTRADB_ICP_ABORTED_BY_USER ?
+ DB_SEARCH_ABORTED_BY_USER :
+ DB_RECORD_NOT_FOUND);
goto idx_cond_failed;
}
+ /* res == XTRADB_ICP_MATCH */
}
/* Get the clustered index record if needed, if we did not do the