← Back to team overview

maria-developers team mailing list archive

Re: [Commits] Rev 2892: BUG#711565 Index Condition Pushdown can make a thread hold MyISAM locks as well as be unKILLable for long time in file:///home/psergey/dev2/5.3/

 

Hi!

>>>>> "Sergey" == Sergey Petrunya <psergey@xxxxxxxxxxxx> writes:

Sergey> At file:///home/psergey/dev2/5.3/
Sergey> ------------------------------------------------------------
Sergey> revno: 2892
Sergey> revision-id: psergey@xxxxxxxxxxxx-20110201233314-6j8yc7jrx9425f3b
Sergey> parent: sergii@xxxxxxxxx-20110114205155-i8poq0jti8o8mob1
Sergey> committer: Sergey Petrunya <psergey@xxxxxxxxxxxx>
Sergey> branch nick: 5.3
Sergey> timestamp: Wed 2011-02-02 02:33:14 +0300
Sergey> message:
Sergey>   BUG#711565 Index Condition Pushdown can make a thread hold MyISAM locks as well as be unKILLable for long time

<cut>

Sergey> === modified file 'mysql-test/t/myisam_icp.test'
Sergey> --- a/mysql-test/t/myisam_icp.test	2011-01-14 13:38:41 +0000
Sergey> +++ b/mysql-test/t/myisam_icp.test	2011-02-01 23:33:14 +0000
Sergey> @@ -4,3 +4,183 @@
 
Sergey>  --source include/icp_tests.inc
<cut>

Instead of using # for each row, please use
--disable_parsing
--enable_parsing

This makes it easier to enable the test temporarly when testing.

<cut>

Sergey> === modified file 'sql/multi_range_read.cc'
Sergey> --- a/sql/multi_range_read.cc	2010-12-21 23:26:35 +0000
Sergey> +++ b/sql/multi_range_read.cc	2011-02-01 23:33:14 +0000
Sergey> @@ -902,7 +902,7 @@
Sergey>    close_second_handler();
Sergey>     /* Safety, not really needed but: */
Sergey>    strategy= NULL;
Sergey> -  DBUG_RETURN(1);
Sergey> +  DBUG_RETURN(res);
 
Sergey>  use_default_impl:
Sergey>    DBUG_ASSERT(primary_file->inited == handler::INDEX);

Sergey> === modified file 'sql/sql_base.cc'
Sergey> --- a/sql/sql_base.cc	2010-12-06 08:25:44 +0000
Sergey> +++ b/sql/sql_base.cc	2011-02-01 23:33:14 +0000
Sergey> @@ -8283,11 +8283,9 @@
Sergey>    List_iterator_fast<Item> f(fields),v(values);
Sergey>    Item *value, *fld;
Sergey>    Item_field *field;
Sergey> -  TABLE *table= 0;
Sergey> -  List<TABLE> tbl_list;
Sergey> +  TABLE *table= 0, *vcol_table= 0;
Sergey>    bool abort_on_warning_saved= thd->abort_on_warning;
Sergey>    DBUG_ENTER("fill_record");
Sergey> -  tbl_list.empty();
 
Sergey>    /*
Sergey>      Reset the table->auto_increment_field_not_null as it is valid for
Sergey> @@ -8310,7 +8308,7 @@
Sergey>      f.rewind();
Sergey>    }
Sergey>    else if (thd->lex->unit.insert_table_with_stored_vcol)
Sergey> -    tbl_list.push_back(thd->lex->unit.insert_table_with_stored_vcol);
Sergey> +    vcol_table= thd->lex->unit.insert_table_with_stored_vcol;
Sergey>    while ((fld= f++))
Sergey>    {
Sergey>      if (!(field= fld->filed_for_view_update()))
Sergey> @@ -8340,31 +8338,17 @@
Sergey>        my_message(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR), MYF(0));
Sergey>        goto err;
Sergey>      }
Sergey> -    tbl_list.push_back(table);
Sergey> +    DBUG_ASSERT(vcol_table == 0 || vcol_table == table);
Sergey> +    vcol_table= table;
Sergey>    }
Sergey>    /* Update virtual fields*/
Sergey>    thd->abort_on_warning= FALSE;
Sergey> -  if (tbl_list.head())
Sergey> +  if (vcol_table)
Sergey>    {
Sergey> -    List_iterator_fast<TABLE> it(tbl_list);
Sergey> -    TABLE *prev_table= 0;
Sergey> -    while ((table= it++))
Sergey> +    if (vcol_table->vfield)
Sergey>      {
Sergey> -      /*
Sergey> -        Do simple optimization to prevent unnecessary re-generating 
Sergey> -        values for virtual fields
Sergey> -      */
Sergey> -      if (table != prev_table)
Sergey> -      {
Sergey> -        prev_table= table;
Sergey> -        if (table->vfield)
Sergey> -        {
Sergey> -          if (update_virtual_fields(thd, table, TRUE))
Sergey> -          {
Sergey> -            goto err;
Sergey> -          }
Sergey> -        }
Sergey> -      }
Sergey> +      if (update_virtual_fields(thd, vcol_table, TRUE))
Sergey> +        goto err;
Sergey>      }
Sergey>    }
Sergey>    thd->abort_on_warning= abort_on_warning_saved;

What has the above to do with the IPC patch?

In any case, how will the above work when there is more than one table
involved in fill_tables ?

(By the way, agree that the old code as stupid; There is no reason to
add all involved tables to tbl_list (trivial to avoid).

Sergey> === modified file 'sql/sql_select.cc'
Sergey> --- a/sql/sql_select.cc	2011-01-14 11:03:41 +0000
Sergey> +++ b/sql/sql_select.cc	2011-02-01 23:33:14 +0000
Sergey> @@ -13618,13 +13618,17 @@
Sergey>                " cond: %p error: %d", join, join_tab, select_cond, error));
Sergey>    if (error > 0 || (join->thd->is_error()))     // Fatal error
Sergey>      DBUG_RETURN(NESTED_LOOP_ERROR);
Sergey> +  /* 
Sergey> +    Check if we're killed before checking for EOF. This is important because
Sergey> +    if we're killed while reading a record, the handler will return EOF.
Sergey> +  */

Please update the comment;  We should not send EOF from the handler if
the query is killed;  There is too many things that can go wrong if
we send EOF on killed from the handler.

Sergey> +  if (join->thd->killed)			// Aborted by user
Sergey> +  {
Sergey> +    join->thd->send_kill_message();
Sergey> +    DBUG_RETURN(NESTED_LOOP_KILLED);            /* purecov: inspected */
Sergey> +  }

<cut>

Sergey> === modified file 'storage/maria/ma_rkey.c'
Sergey> --- a/storage/maria/ma_rkey.c	2011-01-14 11:05:46 +0000
Sergey> +++ b/storage/maria/ma_rkey.c	2011-02-01 23:33:14 +0000
Sergey> @@ -34,7 +34,7 @@
Sergey>    HA_KEYSEG *last_used_keyseg;
Sergey>    uint32 nextflag;
Sergey>    MARIA_KEY key;
Sergey> -  int icp_res= 1;
Sergey> +  ICP_RESULT icp_res= ICP_MATCH;
Sergey>    DBUG_ENTER("maria_rkey");
Sergey>    DBUG_PRINT("enter", ("base: 0x%lx  buf: 0x%lx  inx: %d  search_flag: %d",
Sergey>                         (long) info, (long) buf, inx, search_flag));
Sergey> @@ -115,7 +115,7 @@
Sergey>          not satisfied with an out-of-range condition.
Sergey>        */
Sergey>        if ((*share->row_is_visible)(info) && 
Sergey> -          ((icp_res= ma_check_index_cond(info, inx, buf)) != 0))
Sergey> +          ((icp_res= ma_check_index_cond(info, inx, buf)) != ICP_NO_MATCH))
Sergey>          break;
 
Sergey>        /* The key references a concurrently inserted record. */
Sergey> @@ -145,6 +145,19 @@
Sergey>          if  (_ma_search_next(info, &lastkey, maria_readnext_vec[search_flag],
Sergey>                               info->s->state.key_root[inx]))
Sergey>            break;                          /* purecov: inspected */
Sergey> +
Sergey> +        /*
Sergey> +          If we are at the last key on the key page, allow writers to
Sergey> +          access the index.
Sergey> +        */
Sergey> +        if (info->int_keypos >= info->int_maxpos &&
Sergey> +            ma_yield_and_check_if_killed(info, inx))
Sergey> +        {
Sergey> +          buf= 0;                               /* Fast abort */
Sergey> +          icp_res= ICP_ERROR;

We should not return an IPC_ERROR here as this test has nothing to do
with IPC. It can also happens when we are scanning for a visible row.

Better to just threat this as a normal handler error. See later
comments...

Sergey> +          break;
Sergey> +        }
Sergey> +
Sergey>          /*
Sergey>            Check that the found key does still match the search.
Sergey>            _ma_search_next() delivers the next key regardless of its
Sergey> @@ -168,9 +181,9 @@
Sergey>    if (share->lock_key_trees)
Sergey>      rw_unlock(&keyinfo->root_lock);
 
Sergey> -  if (info->cur_row.lastpos == HA_OFFSET_ERROR || (icp_res != 1))
Sergey> +  if (info->cur_row.lastpos == HA_OFFSET_ERROR || (icp_res != ICP_MATCH))
Sergey>    {
Sergey> -    if (icp_res == 2)
Sergey> +    if (icp_res == ICP_OUT_OF_RANGE || icp_res == ICP_ERROR)
Sergey>      {
Sergey>        info->cur_row.lastpos= HA_OFFSET_ERROR;
Sergey>        my_errno= HA_ERR_KEY_NOT_FOUND;

We should not return HA_ERR_KEY_NOT_FOUND in the case of a real error.
(Too big risk we loose the reason that something went wrong).

Sergey> +/*
Sergey> +  Yield to possible other writers during a index scan.
Sergey> +  Check also if we got killed by the user and if yes, return
Sergey> +  HA_ERR_LOCK_WAIT_TIMEOUT
Sergey> +
Sergey> +  return  0  ok
Sergey> +  return  1  Query has been requested to be killed
Sergey> +*/
Sergey> +
Sergey> +my_bool ma_yield_and_check_if_killed(MARIA_HA *info, int inx)
Sergey> +{
Sergey> +  MARIA_SHARE *share;
Sergey> +  if (ma_killed(info))
Sergey> +  {
Sergey> +    //info->lastpos= HA_OFFSET_ERROR;
Sergey> +    my_errno= HA_ERR_KEY_NOT_FOUND;
Sergey> +    return 1;

The above is not safe. Please use:

info->cur_row.lastpos= HA_OFFSET_ERROR;
my_errno= HA_ERR_ABORTED_BY_USER;

In this case we can not return HA_ERR_KEY_NOT_FOUND as it's too big
risk that the calling code may think that there was really no key and
send a result to the client instead of aborting.

By sending a fatal error message to the user, we can be sure that the
calling code will not ignore it.

That is why we probably should introduce HA_ERR_ABORTED_BY_USER.
If we do this, then we have to fix that handler::print_error() ignores
this error if thd->killed is set. dispatch_command will generate
the necessary error message.

Sergey> +  }
Sergey> +
Sergey> +  if ((share= info->s)->lock_key_trees)
Sergey> +  {
Sergey> +    /* Give writers a chance to access index */
Sergey> +    rw_unlock(&share->keyinfo[inx].root_lock);
Sergey> +    rw_rdlock(&share->keyinfo[inx].root_lock);
Sergey> +  }
Sergey> +  return 0;
Sergey> +}
Sergey> +

Sergey> === modified file 'storage/maria/ma_rnext.c'
Sergey> --- a/storage/maria/ma_rnext.c	2009-12-15 07:16:46 +0000
Sergey> +++ b/storage/maria/ma_rnext.c	2011-02-01 23:33:14 +0000

<cut>

Sergey> +      if (info->int_keypos >= info->int_maxpos &&
Sergey> +          ma_yield_and_check_if_killed(info, inx))
Sergey> +      {
Sergey> +        error= 0;
Sergey> +        icp_res= ICP_ERROR;
Sergey> +        break;
Sergey> +      }

Same thing as above, don't use IPC_ERROR, treat this as a real error!

Sergey> +
Sergey>        /* Skip rows inserted by other threads since we got a lock */
Sergey>        if  ((error= _ma_search_next(info, &info->last_key,
Sergey>                                     SEARCH_BIGGER,
Sergey> @@ -108,10 +120,10 @@
Sergey>    info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
Sergey>    info->update|= HA_STATE_NEXT_FOUND;
   
Sergey> -  if (icp_res == 2)
Sergey> +  if (icp_res == ICP_OUT_OF_RANGE)
Sergey>      my_errno=HA_ERR_END_OF_FILE; /* got beyond the end of scanned range */
 
Sergey> -  if (error || icp_res != 1)
Sergey> +  if (error || icp_res != ICP_MATCH)
Sergey>    {
Sergey>      if (my_errno == HA_ERR_KEY_NOT_FOUND)
Sergey>        my_errno=HA_ERR_END_OF_FILE;

Don't return HA_ERR_END_OF_FILE or HA_ERR_KEY_NOT_FOUND for IPC_ERROR

Sergey> === modified file 'storage/maria/ma_rnext_same.c'
Sergey> --- a/storage/maria/ma_rnext_same.c	2010-10-30 01:59:39 +0000
Sergey> +++ b/storage/maria/ma_rnext_same.c	2011-02-01 23:33:14 +0000
Sergey> @@ -30,7 +30,7 @@
Sergey>    int error;
Sergey>    uint inx,not_used[2];
Sergey>    MARIA_KEYDEF *keyinfo;
Sergey> -  int icp_res= 1;
Sergey> +  ICP_RESULT icp_res= ICP_MATCH;
Sergey>    DBUG_ENTER("maria_rnext_same");
 
Sergey>    if ((int) (inx= info->lastinx) < 0 ||
Sergey> @@ -80,9 +80,20 @@
Sergey>            info->cur_row.lastpos= HA_OFFSET_ERROR;
Sergey>            break;
Sergey>          }
Sergey> +        /*
Sergey> +          If we are at the last key on the key page, allow writers to
Sergey> +          access the index.
Sergey> +        */
Sergey> +        if (info->int_keypos >= info->int_maxpos &&
Sergey> +            ma_yield_and_check_if_killed(info, inx))
Sergey> +        {
Sergey> +          error= 0;
Sergey> +          icp_res= ICP_ERROR;
Sergey> +          break;
Sergey> +        }

Same thing as above, don't use IPC_ERROR, treat this as a real error!

<cut>

Sergey> -  if (error || icp_res != 1)
Sergey> +  if (error || icp_res != ICP_MATCH)
Sergey>    {
Sergey>      if (my_errno == HA_ERR_KEY_NOT_FOUND)
Sergey>        my_errno=HA_ERR_END_OF_FILE;

Don't return HA_ERR_END_OF_FILE or HA_ERR_KEY_NOT_FOUND for IPC_ERROR

Sergey> === modified file 'storage/maria/ma_rprev.c'

<cut>

Sergey> +        if (ma_yield_and_check_if_killed(info, inx))
Sergey> +        {
Sergey> +          error= 0;
Sergey> +          icp_res= ICP_ERROR;
Sergey> +          break;
Sergey> +        }

Return a real error!

Sergey> +      }

Sergey> +
Sergey>        /* Skip rows that are inserted by other threads since we got a lock */
Sergey>        if  ((error= _ma_search_next(info, &info->last_key,
Sergey>                                     SEARCH_SMALLER,


Sergey> @@ -66,6 +84,10 @@
Sergey>    }
Sergey>    if (share->lock_key_trees)
Sergey>      rw_unlock(&keyinfo->root_lock);
Sergey> +  if (icp_res == ICP_ERROR || icp_res == ICP_OUT_OF_RANGE)
Sergey> +  {
Sergey> +    DBUG_RETURN(my_errno= HA_ERR_END_OF_FILE);

Don't return HA_ERR_END_OF_FILE in case of IPC_ERROR


Sergey> === modified file 'storage/maria/maria_def.h'
Sergey> --- a/storage/maria/maria_def.h	2011-01-14 11:03:41 +0000
Sergey> +++ b/storage/maria/maria_def.h	2011-02-01 23:33:14 +0000
Sergey> @@ -505,6 +505,7 @@
Sergey>    DYNAMIC_ARRAY pinned_pages;
Sergey>    /* accumulate indexfile changes between write's */
Sergey>    TREE *bulk_insert;
Sergey> +  void *__external_ref;			/* For MariaDB TABLE */ /* psergey-todo: need this?*/

No, we don't need this as we have external_ptr already in Aria that we
can use.

Sergey> --- a/storage/myisam/mi_rkey.c	2009-12-22 12:33:21 +0000

Sergey> @@ -168,26 +176,37 @@
Sergey>    if (share->concurrent_insert)
Sergey>      rw_unlock(&share->key_root_lock[inx]);
 
Sergey> -  /* Calculate length of the found key;  Used by mi_rnext_same */
Sergey> -  if ((keyinfo->flag & HA_VAR_LENGTH_KEY) && last_used_keyseg &&
Sergey> -      info->lastpos != HA_OFFSET_ERROR)
Sergey> -    info->last_rkey_length= _mi_keylength_part(keyinfo, info->lastkey,
Sergey> -					       last_used_keyseg);
Sergey> +  info->last_rkey_length= pack_key_length;
Sergey> +
Sergey> +  if (info->lastpos == HA_OFFSET_ERROR)			/* No such record */
Sergey> +  {
Sergey> +    /*
Sergey> +      psergey: what doe the next line do:vv initially there were no writeinfo
Sergey> +      calls!
Sergey> +    */
Sergey> +    fast_mi_writeinfo(info);

The original code had a bug. At start of mi_rkey.c we do
fast_mi_readinfo(), which must be followed by a fast_mi_writeinfo()
before return, which didn't happen if buf was 0.  In the normal case
'read_record()' will do the fast_mi_writeinfo() call for the other cases.

Sergey> +    if (!buf)
Sergey> +      DBUG_RETURN(my_errno);
Sergey> +  }
Sergey>    else
Sergey> +    /* Calculate length of the found key;  Used by mi_rnext_same */
Sergey> +    if ((keyinfo->flag & HA_VAR_LENGTH_KEY) && last_used_keyseg)
Sergey> +      info->last_rkey_length= _mi_keylength_part(keyinfo, info->lastkey,
Sergey> +                                                 last_used_keyseg);
Sergey> +
Sergey> +    /* Check if we don't want to have record back, only error message */
Sergey> +    if (!buf)
Sergey> +      DBUG_RETURN(0);

We have to add fast_mi_writeinfo(info) before the DBUG_RETURN above.

Sergey> +    if (!(*info->read_record)(info,info->lastpos,buf))
Sergey> +    {
Sergey> +      info->update|= HA_STATE_AKTIV;		/* Record is read */
Sergey> +      DBUG_RETURN(0);
Sergey> +    }

<cut>

Sergey> +my_bool mi_yield_and_check_if_killed(MI_INFO *info, int inx)
Sergey> +{
Sergey> +  MYISAM_SHARE *share;
Sergey> +  if (mi_killed(info))
Sergey> +  {
Sergey> +    info->lastpos= HA_OFFSET_ERROR;
Sergey> +    my_errno= HA_ERR_KEY_NOT_FOUND;

HA_ERR_KEY_NOT_FOUND -> HA_ERR_ABORTED_BY_USER

Sergey> +    return 1;
Sergey> +  }
Sergey> +
Sergey> +  if ((share= info->s)->concurrent_insert)
Sergey> +  {
Sergey> +    /* Give writers a chance to access index */
Sergey> +    rw_unlock(&share->key_root_lock[inx]);
Sergey> +    rw_rdlock(&share->key_root_lock[inx]);
Sergey> +  }
Sergey> +  return 0;
Sergey> +}

Sergey> === modified file 'storage/myisam/mi_rnext.c'
Sergey> --- a/storage/myisam/mi_rnext.c	2010-06-26 10:05:41 +0000
Sergey> +++ b/storage/myisam/mi_rnext.c	2011-02-01 23:33:14 +0000
Sergey> @@ -104,6 +104,18 @@
Sergey>             (info->index_cond_func &&
Sergey>             (res= mi_check_index_cond(info, inx, buf)) == ICP_NO_MATCH))
Sergey>      {
Sergey> +      /*
Sergey> +        If we are at the last key on the key page, allow writers to
Sergey> +        access the index.
Sergey> +      */
Sergey> +      if (info->int_keypos >= info->int_maxpos &&
Sergey> +          mi_yield_and_check_if_killed(info, inx))
Sergey> +      {
Sergey> +        error= 0;
Sergey> +        res= ICP_ERROR;

Return a real error!

Sergey> +        break;
Sergey> +      }
Sergey> +
Sergey>        /* 
Sergey>           Skip rows that are either inserted by other threads since
Sergey>           we got a lock or do not match pushed index conditions
Sergey> @@ -115,7 +127,8 @@
Sergey>                                    info->s->state.key_root[inx])))
Sergey>          break;
Sergey>      }
Sergey> -    if (!error && res == ICP_OUT_OF_RANGE)
Sergey> +    
Sergey> +    if (!error && (res == ICP_OUT_OF_RANGE || res == ICP_ERROR))
Sergey>      {
Sergey>        if (info->s->concurrent_insert)
Sergey>          rw_unlock(&info->s->key_root_lock[inx]);

Return error code in case of ICP_ERROR

Sergey> === modified file 'storage/myisam/mi_rnext_same.c'
Sergey> --- a/storage/myisam/mi_rnext_same.c	2009-12-22 12:33:21 +0000
Sergey> +++ b/storage/myisam/mi_rnext_same.c	2011-02-01 23:33:14 +0000
Sergey> @@ -63,6 +63,18 @@
Sergey>        }
Sergey>        for (;;)
Sergey>        {
Sergey> +        /*
Sergey> +          If we are at the last key on the key page, allow writers to
Sergey> +          access the index.
Sergey> +        */
Sergey> +        if (info->int_keypos >= info->int_maxpos &&
Sergey> +            mi_yield_and_check_if_killed(info, inx))
Sergey> +        {
Sergey> +          error=1;
Sergey> +          buf= 0;                               /* Fast abort */
Sergey> +          break;

Return real error

Sergey> +        }
Sergey> +
Sergey>          if ((error=_mi_search_next(info,keyinfo,info->lastkey,
Sergey>  			       info->lastkey_length,SEARCH_BIGGER,
Sergey>  			       info->s->state.key_root[inx])))
Sergey> @@ -87,6 +99,10 @@
Sergey>    }
Sergey>    if (info->s->concurrent_insert)
Sergey>      rw_unlock(&info->s->key_root_lock[inx]);
Sergey> +
Sergey> +  if (!buf)
Sergey> +    DBUG_RETURN(my_errno);
Sergey> +

Remove above;  We have to update info->update even if buf is 0

Sergey>  	/* Don't clear if database-changed */
Sergey>    info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
Sergey>    info->update|= HA_STATE_NEXT_FOUND | HA_STATE_RNEXT_SAME;

Sergey> === modified file 'storage/myisam/mi_rprev.c'
Sergey> --- a/storage/myisam/mi_rprev.c	2009-12-15 07:16:46 +0000
Sergey> +++ b/storage/myisam/mi_rprev.c	2011-02-01 23:33:14 +0000
Sergey> @@ -53,12 +53,28 @@
 
Sergey>    if (!error)
Sergey>    {
Sergey> -    int res= 0;
Sergey> +    ICP_RESULT res= 0;
Sergey> +    my_off_t cur_keypage= info->last_keypage;
Sergey>      while ((share->concurrent_insert && 
Sergey>              info->lastpos >= info->state->data_file_length) ||
Sergey>             (info->index_cond_func &&
Sergey>              !(res= mi_check_index_cond(info, inx, buf))))
Sergey>      {
Sergey> +      /*
Sergey> +        If we are at the last (i.e. first?) key on the key page, 
Sergey> +        allow writers to access the index.
Sergey> +      */
Sergey> +      if (info->last_keypage != cur_keypage)
Sergey> +      {
Sergey> +        cur_keypage= info->last_keypage;
Sergey> +        if (mi_yield_and_check_if_killed(info, inx))
Sergey> +        {
Sergey> +          error= 0;
Sergey> +          res= ICP_ERROR;
Sergey> +          break;

Return error

Sergey> +        }
Sergey> +      }
Sergey> +
Sergey>        /* 
Sergey>           Skip rows that are either inserted by other threads since
Sergey>           we got a lock or do not match pushed index conditions
Sergey> @@ -69,7 +85,7 @@
Sergey>                                    share->state.key_root[inx])))
Sergey>          break;
Sergey>      }
Sergey> -    if (!error && res == 2) 
Sergey> +    if (!error && (res == ICP_OUT_OF_RANGE || res == ICP_ERROR))
Sergey>      {
Sergey>        if (share->concurrent_insert)
Sergey>          rw_unlock(&share->key_root_lock[inx]);

Return error code in case of ICP_ERROR

<cut>

Sergey> --- a/storage/xtradb/handler/ha_innodb.cc	2011-01-12 12:00:10 +0000
Sergey> +++ b/storage/xtradb/handler/ha_innodb.cc	2011-02-01 23:33:14 +0000
<cut>
Sergey> @@ -12094,15 +12102,18 @@
Sergey>    See note on ICP_RESULT for return values description.
Sergey>  */
 
Sergey> -static int index_cond_func_innodb(void *arg)
Sergey> +static xtradb_icp_result_t index_cond_func_innodb(void *arg)
Sergey>  {
Sergey>    ha_innobase *h= (ha_innobase*)arg;
Sergey> +  if (h->is_thd_killed())
Sergey> +    return XTRADB_ICP_ERROR;
Sergey> +

rename to XTRADB_ABORTED_BY_USER;

Sergey>    if (h->end_range)
Sergey>    {
Sergey>      if (h->compare_key2(h->end_range) > 0)
Sergey> -      return ICP_OUT_OF_RANGE; /* caller should return HA_ERR_END_OF_FILE already */
Sergey> +      return XTRADB_ICP_OUT_OF_RANGE; /* caller should return HA_ERR_END_OF_FILE already */
Sergey>    }
Sergey> -  return h->pushed_idx_cond->val_int()? ICP_MATCH : ICP_NO_MATCH;
Sergey> +  return h->pushed_idx_cond->val_int()? XTRADB_ICP_MATCH : XTRADB_ICP_NO_MATCH;
Sergey>  }
 
Sergey>  C_MODE_END

<cut>

Sergey> --- a/storage/xtradb/include/row0mysql.h	2010-12-06 08:25:44 +0000
Sergey> +++ b/storage/xtradb/include/row0mysql.h	2011-02-01 23:33:14 +0000
Sergey> @@ -577,7 +577,15 @@
Sergey>  #define ROW_PREBUILT_ALLOCATED	78540783
Sergey>  #define ROW_PREBUILT_FREED	26423527
 
Sergey> -typedef int (*index_cond_func_t)(void *param);
Sergey> +
Sergey> +typedef enum xtradb_icp_result {
Sergey> +  XTRADB_ICP_ERROR=-1,

rename to XTRADB_ABORTED_BY_USER

Sergey> +  XTRADB_ICP_NO_MATCH=0,
Sergey> +  XTRADB_ICP_MATCH=1,
Sergey> +  XTRADB_ICP_OUT_OF_RANGE=2
Sergey> +} xtradb_icp_result_t;
Sergey> +
Sergey> +typedef xtradb_icp_result_t (*index_cond_func_t)(void *param);
Sergey>  /** A struct for (sometimes lazily) prebuilt structures in an Innobase table
 
Sergey>  handle used within MySQL; these are used to save CPU time. */

Sergey> === modified file 'storage/xtradb/row/row0sel.c'
Sergey> --- a/storage/xtradb/row/row0sel.c	2010-12-06 17:44:17 +0000
Sergey> +++ b/storage/xtradb/row/row0sel.c	2011-02-01 23:33:14 +0000
Sergey> @@ -4396,12 +4396,13 @@
Sergey>                  */
Sergey>                  ut_ad(ib_res);
Sergey>  		res= prebuilt->idx_cond_func(prebuilt->idx_cond_func_arg);
Sergey> -		if (res == 0)
Sergey> +		if (res == XTRADB_ICP_NO_MATCH)
Sergey>  			goto next_rec;
Sergey> -		if (res == 2) {
Sergey> +		if (res == XTRADB_ICP_OUT_OF_RANGE || res == XTRADB_ICP_ERROR) {
Sergey>  			err = DB_RECORD_NOT_FOUND;
Sergey>  			goto idx_cond_failed;

Don't return DB_RECORD_NOT_FOUND in case of XTRADB_ICP_ERROR. Return
an actual error like DB_ABORTED_BY_USER which can be translated to
HA_ERR_ABORTED_BY_USER.

Regards,
Monty