diff options
Diffstat (limited to 'storage/myisam')
-rw-r--r-- | storage/myisam/ha_myisam.cc | 103 | ||||
-rw-r--r-- | storage/myisam/ha_myisam.h | 29 | ||||
-rw-r--r-- | storage/myisam/mi_extra.c | 6 | ||||
-rw-r--r-- | storage/myisam/mi_key.c | 57 | ||||
-rw-r--r-- | storage/myisam/mi_rkey.c | 92 | ||||
-rw-r--r-- | storage/myisam/mi_rnext.c | 40 | ||||
-rw-r--r-- | storage/myisam/mi_rnext_same.c | 3 | ||||
-rw-r--r-- | storage/myisam/mi_rprev.c | 38 | ||||
-rw-r--r-- | storage/myisam/myisamdef.h | 6 |
9 files changed, 294 insertions, 80 deletions
diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index d92a576a5d7..7e319fc80f6 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -1676,6 +1676,48 @@ int ha_myisam::delete_row(const uchar *buf) return mi_delete(file,buf); } + +C_MODE_START + +ICP_RESULT index_cond_func_myisam(void *arg) +{ + ha_myisam *h= (ha_myisam*)arg; + 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 (ICP_RESULT) test(h->pushed_idx_cond->val_int()); +} + +C_MODE_END + + +int ha_myisam::index_init(uint idx, bool sorted) +{ + active_index=idx; + if (pushed_idx_cond_keyno == idx) + mi_set_index_cond_func(file, index_cond_func_myisam, this); + return 0; +} + + +int ha_myisam::index_end() +{ + active_index=MAX_KEY; + //pushed_idx_cond_keyno= MAX_KEY; + mi_set_index_cond_func(file, NULL, 0); + in_range_check_pushed_down= FALSE; + ds_mrr.dsmrr_close(); + return 0; +} + +int ha_myisam::rnd_end() +{ + ds_mrr.dsmrr_close(); + return 0; +} + int ha_myisam::index_read_map(uchar *buf, const uchar *key, key_part_map keypart_map, enum ha_rkey_function find_flag) @@ -1878,8 +1920,13 @@ int ha_myisam::extra(enum ha_extra_function operation) return mi_extra(file, operation, 0); } + int ha_myisam::reset(void) { + pushed_idx_cond= NULL; + pushed_idx_cond_keyno= MAX_KEY; + mi_set_index_cond_func(file, NULL, 0); + ds_mrr.dsmrr_close(); return mi_reset(file); } @@ -2164,6 +2211,62 @@ static int myisam_init(void *p) return 0; } +/**************************************************************************** + * MyISAM MRR implementation: use DS-MRR + ***************************************************************************/ + +int ha_myisam::multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param, + uint n_ranges, uint mode, + HANDLER_BUFFER *buf) +{ + return ds_mrr.dsmrr_init(this, seq, seq_init_param, n_ranges, mode, buf); +} + +int ha_myisam::multi_range_read_next(char **range_info) +{ + return ds_mrr.dsmrr_next(range_info); +} + +ha_rows ha_myisam::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, + void *seq_init_param, + uint n_ranges, uint *bufsz, + uint *flags, COST_VECT *cost) +{ + /* + This call is here because there is no location where this->table would + already be known. + TODO: consider moving it into some per-query initialization call. + */ + ds_mrr.init(this, table); + return ds_mrr.dsmrr_info_const(keyno, seq, seq_init_param, n_ranges, bufsz, + flags, cost); +} + +ha_rows ha_myisam::multi_range_read_info(uint keyno, uint n_ranges, uint keys, + uint *bufsz, uint *flags, + COST_VECT *cost) +{ + ds_mrr.init(this, table); + return ds_mrr.dsmrr_info(keyno, n_ranges, keys, bufsz, flags, cost); +} + +/* MyISAM MRR implementation ends */ + + +/* Index condition pushdown implementation*/ + + +Item *ha_myisam::idx_cond_push(uint keyno_arg, Item* idx_cond_arg) +{ + pushed_idx_cond_keyno= keyno_arg; + pushed_idx_cond= idx_cond_arg; + in_range_check_pushed_down= TRUE; + if (active_index == pushed_idx_cond_keyno) + mi_set_index_cond_func(file, index_cond_func_myisam, this); + return NULL; +} + + struct st_mysql_storage_engine myisam_storage_engine= { MYSQL_HANDLERTON_INTERFACE_VERSION }; diff --git a/storage/myisam/ha_myisam.h b/storage/myisam/ha_myisam.h index 7a1595573d4..76db0e89536 100644 --- a/storage/myisam/ha_myisam.h +++ b/storage/myisam/ha_myisam.h @@ -34,6 +34,10 @@ extern ulong myisam_sort_buffer_size; extern TYPELIB myisam_recover_typelib; extern ulong myisam_recover_options; +C_MODE_START +ICP_RESULT index_cond_func_myisam(void *arg); +C_MODE_END + class ha_myisam: public handler { MI_INFO *file; @@ -50,11 +54,15 @@ class ha_myisam: public handler const char *index_type(uint key_number); const char **bas_ext() const; ulonglong table_flags() const { return int_table_flags; } + int index_init(uint idx, bool sorted); + int index_end(); + int rnd_end(); + ulong index_flags(uint inx, uint part, bool all_parts) const { return ((table_share->key_info[inx].algorithm == HA_KEY_ALG_FULLTEXT) ? 0 : HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE | - HA_READ_ORDER | HA_KEYREAD_ONLY); + HA_READ_ORDER | HA_KEYREAD_ONLY | HA_DO_INDEX_COND_PUSHDOWN); } uint max_supported_keys() const { return MI_MAX_KEY; } uint max_supported_key_length() const { return HA_MAX_KEY_LENGTH; } @@ -149,4 +157,23 @@ class ha_myisam: public handler { return file; } +public: + /** + * Multi Range Read interface + */ + int multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param, + uint n_ranges, uint mode, HANDLER_BUFFER *buf); + int multi_range_read_next(char **range_info); + ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, + void *seq_init_param, + uint n_ranges, uint *bufsz, + uint *flags, COST_VECT *cost); + ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys, + uint *bufsz, uint *flags, COST_VECT *cost); + + /* Index condition pushdown implementation */ + Item *idx_cond_push(uint keyno, Item* idx_cond); +private: + DsMrr_impl ds_mrr; + friend ICP_RESULT index_cond_func_myisam(void *arg); }; diff --git a/storage/myisam/mi_extra.c b/storage/myisam/mi_extra.c index 9c5dade28ab..7bb79108357 100644 --- a/storage/myisam/mi_extra.c +++ b/storage/myisam/mi_extra.c @@ -403,6 +403,12 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) DBUG_RETURN(error); } /* mi_extra */ +void mi_set_index_cond_func(MI_INFO *info, index_cond_func_t func, + void *func_arg) +{ + info->index_cond_func= func; + info->index_cond_func_arg= func_arg; +} /* Start/Stop Inserting Duplicates Into a Table, WL#1648. diff --git a/storage/myisam/mi_key.c b/storage/myisam/mi_key.c index 94f3f34ec58..aab5797a03b 100644 --- a/storage/myisam/mi_key.c +++ b/storage/myisam/mi_key.c @@ -31,7 +31,8 @@ set_if_smaller(char_length,length); \ } while(0) -static int _mi_put_key_in_record(MI_INFO *info,uint keynr,uchar *record); +static int _mi_put_key_in_record(MI_INFO *info,uint keynr, + my_bool unpack_blobs, uchar *record); /* Make a intern key from a record @@ -312,6 +313,9 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old, _mi_put_key_in_record() info MyISAM handler keynr Key number that was used + unpack_blobs TRUE <=> Unpack blob columns + FALSE <=> Skip them. This is used by index condition + pushdown check function record Store key here Last read key is in info->lastkey @@ -325,7 +329,7 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old, */ static int _mi_put_key_in_record(register MI_INFO *info, uint keynr, - uchar *record) + my_bool unpack_blobs, uchar *record) { reg2 uchar *key; uchar *pos,*key_end; @@ -418,16 +422,19 @@ static int _mi_put_key_in_record(register MI_INFO *info, uint keynr, if (length > keyseg->length || key+length > key_end) goto err; #endif - memcpy(record+keyseg->start+keyseg->bit_start, - (char*) &blob_ptr,sizeof(char*)); - memcpy(blob_ptr,key,length); - blob_ptr+=length; + if (unpack_blobs) + { + memcpy(record+keyseg->start+keyseg->bit_start, + (char*) &blob_ptr,sizeof(char*)); + memcpy(blob_ptr,key,length); + blob_ptr+=length; - /* The above changed info->lastkey2. Inform mi_rnext_same(). */ - info->update&= ~HA_STATE_RNEXT_SAME; + /* The above changed info->lastkey2. Inform mi_rnext_same(). */ + info->update&= ~HA_STATE_RNEXT_SAME; - _mi_store_blob_length(record+keyseg->start, - (uint) keyseg->bit_start,length); + _mi_store_blob_length(record+keyseg->start, + (uint) keyseg->bit_start,length); + } key+=length; } else if (keyseg->flag & HA_SWAP_KEY) @@ -471,7 +478,7 @@ int _mi_read_key_record(MI_INFO *info, my_off_t filepos, uchar *buf) { if (info->lastinx >= 0) { /* Read only key */ - if (_mi_put_key_in_record(info,(uint) info->lastinx,buf)) + if (_mi_put_key_in_record(info,(uint) info->lastinx, TRUE, buf)) { mi_print_error(info->s, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; @@ -487,6 +494,34 @@ int _mi_read_key_record(MI_INFO *info, my_off_t filepos, uchar *buf) /* + Save current key tuple to record and call index condition check function + + SYNOPSIS + mi_check_index_cond() + info MyISAM handler + keynr Index we're running a scan on + record Record buffer to use (it is assumed that index check function + will look for column values there) + + RETURN + -1 Error + 0 Index condition is not satisfied, continue scanning + 1 Index condition is satisfied + 2 Index condition is not satisfied, end the scan. +*/ + +int mi_check_index_cond(register MI_INFO *info, uint keynr, uchar *record) +{ + if (_mi_put_key_in_record(info, keynr, FALSE, record)) + { + mi_print_error(info->s, HA_ERR_CRASHED); + my_errno=HA_ERR_CRASHED; + return -1; + } + return info->index_cond_func(info->index_cond_func_arg); +} + +/* Retrieve auto_increment info SYNOPSIS diff --git a/storage/myisam/mi_rkey.c b/storage/myisam/mi_rkey.c index f20b0366683..47e2ce51a9e 100644 --- a/storage/myisam/mi_rkey.c +++ b/storage/myisam/mi_rkey.c @@ -29,6 +29,7 @@ int mi_rkey(MI_INFO *info, uchar *buf, int inx, const uchar *key, MI_KEYDEF *keyinfo; HA_KEYSEG *last_used_keyseg; uint pack_key_length, use_key_length, nextflag; + int res= 0; DBUG_ENTER("mi_rkey"); DBUG_PRINT("enter", ("base: 0x%lx buf: 0x%lx inx: %d search_flag: %d", (long) info, (long) buf, inx, search_flag)); @@ -105,55 +106,62 @@ int mi_rkey(MI_INFO *info, uchar *buf, int inx, const uchar *key, saved the current data_file_length. Concurrent inserts always go to the end of the file. So we can test if the found key references a new record. + + If we are searching for a partial key (or using >, >=, < or <=) and + the data is outside of the data file, we need to continue searching + for the first key inside the data file. + + We do also continue searching if an index condition check function + is available. */ - if (info->lastpos >= info->state->data_file_length) + while ((info->lastpos >= info->state->data_file_length && + (search_flag != HA_READ_KEY_EXACT || + last_used_keyseg != keyinfo->seg + keyinfo->keysegs)) || + (info->index_cond_func && + !(res= mi_check_index_cond(info, inx, buf)))) { - /* The key references a concurrently inserted record. */ + uint not_used[2]; + /* + Skip rows that are inserted by other threads since we got a lock + Note that this can only happen if we are not searching after an + full length exact key, because the keys are sorted + according to position + */ + if (_mi_search_next(info, keyinfo, info->lastkey, + info->lastkey_length, + myisam_readnext_vec[search_flag], + info->s->state.key_root[inx])) + break; + /* + Check that the found key does still match the search. + _mi_search_next() delivers the next key regardless of its + value. + */ if (search_flag == HA_READ_KEY_EXACT && - last_used_keyseg == keyinfo->seg + keyinfo->keysegs) + ha_key_cmp(keyinfo->seg, key_buff, info->lastkey, use_key_length, + SEARCH_FIND, not_used)) { - /* Simply ignore the key if it matches exactly. (Bug #29838) */ my_errno= HA_ERR_KEY_NOT_FOUND; info->lastpos= HA_OFFSET_ERROR; + break; } - else - { - /* - If searching for a partial key (or using >, >=, < or <=) and - the data is outside of the data file, we need to continue - searching for the first key inside the data file. - */ - do - { - uint not_used[2]; - /* - Skip rows that are inserted by other threads since we got - a lock. Note that this can only happen if we are not - searching after a full length exact key, because the keys - are sorted according to position. - */ - if (_mi_search_next(info, keyinfo, info->lastkey, - info->lastkey_length, - myisam_readnext_vec[search_flag], - info->s->state.key_root[inx])) - break; /* purecov: inspected */ - /* - Check that the found key does still match the search. - _mi_search_next() delivers the next key regardless of its - value. - */ - if (search_flag == HA_READ_KEY_EXACT && - ha_key_cmp(keyinfo->seg, key_buff, info->lastkey, - use_key_length, SEARCH_FIND, not_used)) - { - /* purecov: begin inspected */ - my_errno= HA_ERR_KEY_NOT_FOUND; - info->lastpos= HA_OFFSET_ERROR; - break; - /* purecov: end */ - } - } while (info->lastpos >= info->state->data_file_length); - } + } + if (res == 2) + { + 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)); + } + /* + Error if no row found within the data file. (Bug #29838) + Do not overwrite my_errno if already at HA_OFFSET_ERROR. + */ + if (info->lastpos != HA_OFFSET_ERROR && + info->lastpos >= info->state->data_file_length) + { + info->lastpos= HA_OFFSET_ERROR; + my_errno= HA_ERR_KEY_NOT_FOUND; } } } diff --git a/storage/myisam/mi_rnext.c b/storage/myisam/mi_rnext.c index 7ce66d41e0f..ad5ec60dc98 100644 --- a/storage/myisam/mi_rnext.c +++ b/storage/myisam/mi_rnext.c @@ -28,6 +28,7 @@ int mi_rnext(MI_INFO *info, uchar *buf, int inx) { int error,changed; uint flag; + int res= 0; DBUG_ENTER("mi_rnext"); if ((inx = _mi_check_index(info,inx)) < 0) @@ -81,23 +82,36 @@ int mi_rnext(MI_INFO *info, uchar *buf, int inx) } } - if (info->s->concurrent_insert) + if (!error) { - if (!error) + while ((info->s->concurrent_insert && + info->lastpos >= info->state->data_file_length) || + (info->index_cond_func && + !(res= mi_check_index_cond(info, inx, buf)))) { - while (info->lastpos >= info->state->data_file_length) - { - /* Skip rows inserted by other threads since we got a lock */ - if ((error=_mi_search_next(info,info->s->keyinfo+inx, - info->lastkey, - info->lastkey_length, - SEARCH_BIGGER, - info->s->state.key_root[inx]))) - break; - } + /* + Skip rows that are either inserted by other threads since + we got a lock or do not match pushed index conditions + */ + if ((error=_mi_search_next(info,info->s->keyinfo+inx, + info->lastkey, + info->lastkey_length, + SEARCH_BIGGER, + info->s->state.key_root[inx]))) + break; + } + if (!error && res == 2) + { + 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); } - rw_unlock(&info->s->key_root_lock[inx]); } + + 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; diff --git a/storage/myisam/mi_rnext_same.c b/storage/myisam/mi_rnext_same.c index 1892fe3e1e0..76775dec8ac 100644 --- a/storage/myisam/mi_rnext_same.c +++ b/storage/myisam/mi_rnext_same.c @@ -76,7 +76,8 @@ int mi_rnext_same(MI_INFO *info, uchar *buf) break; } /* Skip rows that are inserted by other threads since we got a lock */ - if (info->lastpos < info->state->data_file_length) + if (info->lastpos < info->state->data_file_length && + (!info->index_cond_func || mi_check_index_cond(info, inx, buf))) break; } } diff --git a/storage/myisam/mi_rprev.c b/storage/myisam/mi_rprev.c index d1407012590..93bd224bd56 100644 --- a/storage/myisam/mi_rprev.c +++ b/storage/myisam/mi_rprev.c @@ -51,22 +51,36 @@ int mi_rprev(MI_INFO *info, uchar *buf, int inx) error=_mi_search(info,share->keyinfo+inx,info->lastkey, USE_WHOLE_KEY, flag, share->state.key_root[inx]); - if (share->concurrent_insert) + if (!error) { - if (!error) + int res= 0; + while ((share->concurrent_insert && + info->lastpos >= info->state->data_file_length) || + (info->index_cond_func && + !(res= mi_check_index_cond(info, inx, buf)))) { - while (info->lastpos >= info->state->data_file_length) - { - /* Skip rows that are inserted by other threads since we got a lock */ - if ((error=_mi_search_next(info,share->keyinfo+inx,info->lastkey, - info->lastkey_length, - SEARCH_SMALLER, - share->state.key_root[inx]))) - break; - } + /* + Skip rows that are either inserted by other threads since + we got a lock or do not match pushed index conditions + */ + if ((error=_mi_search_next(info,share->keyinfo+inx,info->lastkey, + info->lastkey_length, + SEARCH_SMALLER, + 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); } - rw_unlock(&share->key_root_lock[inx]); } + + if (share->concurrent_insert) + rw_unlock(&share->key_root_lock[inx]); + info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED); info->update|= HA_STATE_PREV_FOUND; if (error) diff --git a/storage/myisam/myisamdef.h b/storage/myisam/myisamdef.h index c2841c49199..2dcd008da58 100644 --- a/storage/myisam/myisamdef.h +++ b/storage/myisam/myisamdef.h @@ -232,6 +232,7 @@ typedef struct st_mi_isam_share rw_lock_t mmap_lock; } MYISAM_SHARE; +typedef ICP_RESULT (*index_cond_func_t)(void *param); struct st_myisam_info { @@ -300,6 +301,8 @@ struct st_myisam_info /* If info->buff has to be reread for rnext */ my_bool buff_used; my_bool once_flags; /* For MYISAMMRG */ + index_cond_func_t index_cond_func; /* Index condition function */ + void *index_cond_func_arg; /* parameter for the func */ #ifdef __WIN__ my_bool owned_by_merge; /* This MyISAM table is part of a merge union */ #endif @@ -724,6 +727,7 @@ void mi_setup_functions(register MYISAM_SHARE *share); my_bool mi_dynmap_file(MI_INFO *info, my_off_t size); void mi_remap_file(MI_INFO *info, my_off_t size); +int mi_check_index_cond(register MI_INFO *info, uint keynr, uchar *record); /* Functions needed by mi_check */ volatile int *killed_ptr(HA_CHECK *param); void mi_check_print_error _VARARGS((HA_CHECK *param, const char *fmt, ...)); @@ -732,6 +736,8 @@ void mi_check_print_info _VARARGS((HA_CHECK *param, const char *fmt, ...)); #ifdef THREAD pthread_handler_t thr_find_all_keys(void *arg); #endif +extern void mi_set_index_cond_func(MI_INFO *info, index_cond_func_t func, + void *func_arg); int flush_blocks(HA_CHECK *param, KEY_CACHE *key_cache, File file); #ifdef __cplusplus } |