MWL#121-125 DS-MRR improvements
- Address Monty's review feedback, part 5
This commit is contained in:
parent
f2abf5f6b1
commit
44be131cd3
@ -71,6 +71,9 @@ select b,filler from t3 where (b>='c-1011=w' and b<= 'c-1018=w') or
|
||||
#
|
||||
# Now try different keypart types and special values
|
||||
#
|
||||
--disable_warnings
|
||||
drop table if exists t4;
|
||||
--enable_warnings
|
||||
create table t4 (a varchar(10), b int, c char(10), filler char(200),
|
||||
key idx1 (a, b, c));
|
||||
|
||||
|
@ -168,6 +168,7 @@ c-1020=w filler
|
||||
c-1021=w filler
|
||||
c-1022=w filler
|
||||
c-1023=w filler
|
||||
drop table if exists t4;
|
||||
create table t4 (a varchar(10), b int, c char(10), filler char(200),
|
||||
key idx1 (a, b, c));
|
||||
insert into t4 (filler) select concat('NULL-', 15-a) from t2 order by a limit 15;
|
||||
|
@ -169,6 +169,7 @@ c-1020=w filler
|
||||
c-1021=w filler
|
||||
c-1022=w filler
|
||||
c-1023=w filler
|
||||
drop table if exists t4;
|
||||
create table t4 (a varchar(10), b int, c char(10), filler char(200),
|
||||
key idx1 (a, b, c));
|
||||
insert into t4 (filler) select concat('NULL-', 15-a) from t2 order by a limit 15;
|
||||
|
@ -1,4 +1,4 @@
|
||||
drop table if exists t1, t2, t3;
|
||||
drop table if exists t0, t1, t2, t3;
|
||||
set @mrr_buffer_size_save= @@mrr_buffer_size;
|
||||
set mrr_buffer_size=79;
|
||||
Warnings:
|
||||
@ -170,6 +170,7 @@ c-1020=w filler
|
||||
c-1021=w filler
|
||||
c-1022=w filler
|
||||
c-1023=w filler
|
||||
drop table if exists t4;
|
||||
create table t4 (a varchar(10), b int, c char(10), filler char(200),
|
||||
key idx1 (a, b, c));
|
||||
insert into t4 (filler) select concat('NULL-', 15-a) from t2 order by a limit 15;
|
||||
@ -432,8 +433,8 @@ a a b
|
||||
1 1 1
|
||||
2 2 2
|
||||
NULL NULL 1234
|
||||
NULL NULL 1234
|
||||
NULL NULL 5678
|
||||
NULL NULL 1234
|
||||
NULL NULL 5678
|
||||
set @@join_cache_level=@save_join_cache_level;
|
||||
drop table t0, t1;
|
||||
|
@ -3,7 +3,7 @@
|
||||
#
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1, t2, t3;
|
||||
drop table if exists t0, t1, t2, t3;
|
||||
--enable_warnings
|
||||
|
||||
set @mrr_buffer_size_save= @@mrr_buffer_size;
|
||||
|
@ -1154,6 +1154,23 @@ typedef void *range_seq_t;
|
||||
|
||||
typedef struct st_range_seq_if
|
||||
{
|
||||
/*
|
||||
Get key information
|
||||
|
||||
SYNOPSIS
|
||||
get_key_info()
|
||||
init_params The seq_init_param parameter
|
||||
length OUT length of the keys in this range sequence
|
||||
map OUT key_part_map of the keys in this range sequence
|
||||
|
||||
DESCRIPTION
|
||||
This function is set only when using HA_MRR_FIXED_KEY mode. In that mode,
|
||||
all ranges are single-point equality ranges that use the same set of key
|
||||
parts. This function allows the MRR implementation to get the length of
|
||||
a key, and which keyparts it uses.
|
||||
*/
|
||||
void (*get_key_info)(void *init_params, uint *length, key_part_map *map);
|
||||
|
||||
/*
|
||||
Initialize the traversal of range sequence
|
||||
|
||||
|
@ -288,7 +288,9 @@ scan_it_again:
|
||||
|
||||
int Mrr_simple_index_reader::init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
|
||||
void *seq_init_param, uint n_ranges,
|
||||
uint mode, Buffer_manager *buf_manager_arg)
|
||||
uint mode, Key_parameters *key_par_arg,
|
||||
Lifo_buffer *key_buffer_arg,
|
||||
Buffer_manager *buf_manager_arg)
|
||||
{
|
||||
HANDLER_BUFFER no_buffer = {NULL, NULL, NULL};
|
||||
h= h_arg;
|
||||
@ -332,42 +334,29 @@ int Mrr_ordered_index_reader::get_next(char **range_info)
|
||||
int res;
|
||||
DBUG_ENTER("Mrr_ordered_index_reader::get_next");
|
||||
|
||||
if (!know_key_tuple_params)
|
||||
{
|
||||
//psergey-todo: this will be removed
|
||||
/*
|
||||
We're at the very start, haven't filled the buffer or even know what
|
||||
will be there. Force the caller to call refill_buffer():
|
||||
*/
|
||||
DBUG_RETURN(HA_ERR_END_OF_FILE);
|
||||
}
|
||||
|
||||
for(;;)
|
||||
{
|
||||
if (scanning_key_val_iter)
|
||||
{
|
||||
if ((res= kv_it.get_next()))
|
||||
{
|
||||
scanning_key_val_iter= FALSE;
|
||||
if ((res != HA_ERR_KEY_NOT_FOUND && res != HA_ERR_END_OF_FILE))
|
||||
DBUG_RETURN(res);
|
||||
kv_it.move_to_next_key_value();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!scanning_key_val_iter)
|
||||
{
|
||||
while ((res= kv_it.init(this)))
|
||||
{
|
||||
if ((res != HA_ERR_KEY_NOT_FOUND && res != HA_ERR_END_OF_FILE))
|
||||
DBUG_RETURN(res); /* Some fatal error */
|
||||
|
||||
if (key_buffer->is_empty()) //psergey-todo: the problem is here?
|
||||
if (key_buffer->is_empty())
|
||||
{
|
||||
DBUG_RETURN(HA_ERR_END_OF_FILE);
|
||||
}
|
||||
}
|
||||
scanning_key_val_iter= TRUE;
|
||||
}
|
||||
|
||||
if ((res= kv_it.get_next()))
|
||||
{
|
||||
scanning_key_val_iter= FALSE;
|
||||
if ((res != HA_ERR_KEY_NOT_FOUND && res != HA_ERR_END_OF_FILE))
|
||||
DBUG_RETURN(res);
|
||||
kv_it.move_to_next_key_value();
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -386,14 +375,6 @@ int Mrr_ordered_index_reader::get_next(char **range_info)
|
||||
|
||||
/**
|
||||
Fill the buffer with (lookup_tuple, range_id) pairs and sort
|
||||
|
||||
@note
|
||||
We don't know lookup_tuple before we get the first key from
|
||||
mrr_funcs.get_next(). Not knowing tuple length means we can't setup the
|
||||
key buffer (in particular, which part of the buffer space it should occupy
|
||||
when we have both key and rowid buffers). This problem is solved by having
|
||||
know_key_tuple_params variabe, and buf_manager, which we ask to set/reset
|
||||
buffers for us.
|
||||
*/
|
||||
|
||||
int Mrr_ordered_index_reader::refill_buffer(bool initial)
|
||||
@ -403,45 +384,25 @@ int Mrr_ordered_index_reader::refill_buffer(bool initial)
|
||||
uchar *key_ptr;
|
||||
DBUG_ENTER("Mrr_ordered_index_reader::refill_buffer");
|
||||
|
||||
DBUG_ASSERT(!know_key_tuple_params || key_buffer->is_empty());
|
||||
DBUG_ASSERT(key_buffer->is_empty());
|
||||
|
||||
if (source_exhausted)
|
||||
DBUG_RETURN(HA_ERR_END_OF_FILE);
|
||||
|
||||
if (know_key_tuple_params)
|
||||
//if (know_key_tuple_params)
|
||||
{
|
||||
buf_manager->reset_buffer_sizes();
|
||||
buf_manager->reset_buffer_sizes(buf_manager->arg);
|
||||
key_buffer->reset();
|
||||
key_buffer->setup_writing(&key_ptr, keypar.key_size_in_keybuf,
|
||||
is_mrr_assoc? (uchar**)&range_info_ptr : NULL,
|
||||
sizeof(uchar*));
|
||||
}
|
||||
|
||||
while ((!know_key_tuple_params || key_buffer->can_write()) &&
|
||||
while (key_buffer->can_write() &&
|
||||
!(source_exhausted= (bool)mrr_funcs.next(mrr_iter, &cur_range)))
|
||||
{
|
||||
DBUG_ASSERT(cur_range.range_flag & EQ_RANGE);
|
||||
|
||||
if (!know_key_tuple_params)
|
||||
{
|
||||
/* This only happens when we've just started filling the buffer */
|
||||
key_range *sample_key= &cur_range.start_key;
|
||||
know_key_tuple_params= TRUE;
|
||||
keypar.key_tuple_length= sample_key->length;
|
||||
keypar.key_tuple_map= sample_key->keypart_map;
|
||||
keypar.key_size_in_keybuf= keypar.use_key_pointers ? sizeof(char*) : keypar.key_tuple_length;
|
||||
KEY *key_info= &h->get_table()->key_info[h->active_index];
|
||||
keypar.index_ranges_unique= test(key_info->flags & HA_NOSAME &&
|
||||
key_info->key_parts ==
|
||||
my_count_bits(sample_key->keypart_map));
|
||||
buf_manager->setup_buffer_sizes(keypar.key_size_in_keybuf, keypar.key_tuple_map);
|
||||
key_buffer= buf_manager->get_key_buffer();
|
||||
key_buffer->setup_writing(&key_ptr, keypar.key_size_in_keybuf,
|
||||
is_mrr_assoc? (uchar**)&range_info_ptr : NULL,
|
||||
sizeof(uchar*));
|
||||
DBUG_ASSERT(key_buffer->can_write());
|
||||
}
|
||||
|
||||
/* Put key, or {key, range_id} pair into the buffer */
|
||||
key_ptr= (keypar.use_key_pointers)? (uchar*)&cur_range.start_key.key :
|
||||
(uchar*)cur_range.start_key.key;
|
||||
@ -452,7 +413,7 @@ int Mrr_ordered_index_reader::refill_buffer(bool initial)
|
||||
/* Force get_next() to start with kv_it.init() call: */
|
||||
scanning_key_val_iter= FALSE;
|
||||
|
||||
if (source_exhausted && (!know_key_tuple_params || key_buffer->is_empty()))
|
||||
if (source_exhausted && key_buffer->is_empty())
|
||||
DBUG_RETURN(HA_ERR_END_OF_FILE);
|
||||
|
||||
key_buffer->sort((key_buffer->type() == Lifo_buffer::FORWARD)?
|
||||
@ -465,16 +426,24 @@ int Mrr_ordered_index_reader::refill_buffer(bool initial)
|
||||
|
||||
int Mrr_ordered_index_reader::init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
|
||||
void *seq_init_param, uint n_ranges,
|
||||
uint mode, Buffer_manager *buf_manager_arg)
|
||||
uint mode, Key_parameters *key_par_arg,
|
||||
Lifo_buffer *key_buffer_arg,
|
||||
Buffer_manager *buf_manager_arg)
|
||||
{
|
||||
h= h_arg;
|
||||
key_buffer= key_buffer_arg;
|
||||
buf_manager= buf_manager_arg;
|
||||
keypar= *key_par_arg;
|
||||
|
||||
KEY *key_info= &h->get_table()->key_info[h->active_index];
|
||||
keypar.index_ranges_unique= test(key_info->flags & HA_NOSAME &&
|
||||
key_info->key_parts ==
|
||||
my_count_bits(keypar.key_tuple_map));
|
||||
|
||||
mrr_iter= seq_funcs->init(seq_init_param, n_ranges, mode);
|
||||
keypar.use_key_pointers= test(mode & HA_MRR_MATERIALIZED_KEYS);
|
||||
is_mrr_assoc= !test(mode & HA_MRR_NO_ASSOCIATION);
|
||||
mrr_funcs= *seq_funcs;
|
||||
know_key_tuple_params= FALSE;
|
||||
source_exhausted= FALSE;
|
||||
buf_manager= buf_manager_arg;
|
||||
/*
|
||||
Short: don't do identical key handling when we have a pushed index
|
||||
condition.
|
||||
@ -546,9 +515,6 @@ int Mrr_ordered_rndpos_reader::init(handler *h_arg,
|
||||
When this function returns, either rowid buffer is not empty, or the source
|
||||
of lookup keys (i.e. ranges) is exhaused.
|
||||
|
||||
dsmrr_eof is set to indicate whether we've exhausted the list of ranges we're
|
||||
scanning. This function never returns HA_ERR_END_OF_FILE.
|
||||
|
||||
@retval 0 OK, the next portion of rowids is in the buffer,
|
||||
properly ordered
|
||||
@retval other Error
|
||||
@ -751,6 +717,11 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
|
||||
{
|
||||
THD *thd= current_thd;
|
||||
int res;
|
||||
Key_parameters keypar;
|
||||
uint key_buff_elem_size;
|
||||
handler *h_idx;
|
||||
Mrr_ordered_rndpos_reader *disk_strategy= NULL;
|
||||
bool do_sort_keys= FALSE;
|
||||
DBUG_ENTER("DsMrr_impl::dsmrr_init");
|
||||
|
||||
/*
|
||||
@ -761,16 +732,14 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
|
||||
is_mrr_assoc= !test(mode & HA_MRR_NO_ASSOCIATION);
|
||||
|
||||
strategy_exhausted= FALSE;
|
||||
|
||||
/* By default, have do-nothing buffer manager */
|
||||
buf_manager.arg= this;
|
||||
buf_manager.reset_buffer_sizes= do_nothing;
|
||||
buf_manager.redistribute_buffer_space= do_nothing;
|
||||
|
||||
if (mode & (HA_MRR_USE_DEFAULT_IMPL | HA_MRR_SORTED))
|
||||
{
|
||||
DBUG_ASSERT(h->inited == handler::INDEX);
|
||||
/* Call correct init function and assign to top level object */
|
||||
Mrr_simple_index_reader *s= &reader_factory.simple_index_reader;
|
||||
res= s->init(h, seq_funcs, seq_init_param, n_ranges, mode, this);
|
||||
strategy= s;
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
goto use_default_impl;
|
||||
|
||||
/*
|
||||
Determine whether we'll need to do key sorting and/or rnd_pos() scan
|
||||
@ -779,6 +748,7 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
|
||||
if ((mode & HA_MRR_SINGLE_POINT) &&
|
||||
optimizer_flag(thd, OPTIMIZER_SWITCH_MRR_SORT_KEYS))
|
||||
{
|
||||
do_sort_keys= TRUE;
|
||||
index_strategy= &reader_factory.ordered_index_reader;
|
||||
}
|
||||
else
|
||||
@ -794,10 +764,9 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
|
||||
(h->inited == handler::RND && h2 &&
|
||||
h2->inited == handler::INDEX));
|
||||
|
||||
handler *h_idx= (h->inited == handler::INDEX)? h: h2;
|
||||
h_idx= (h->inited == handler::INDEX)? h: h2;
|
||||
keyno= h_idx->active_index;
|
||||
|
||||
Mrr_ordered_rndpos_reader *disk_strategy= NULL;
|
||||
if (!(keyno == table->s->primary_key && h_idx->primary_key_is_clustered()))
|
||||
{
|
||||
strategy= disk_strategy= &reader_factory.ordered_rndpos_reader;
|
||||
@ -808,29 +777,64 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
|
||||
|
||||
full_buf= buf->buffer;
|
||||
full_buf_end= buf->buffer_end;
|
||||
|
||||
|
||||
if (do_sort_keys)
|
||||
{
|
||||
/* Pre-calculate some parameters of key sorting */
|
||||
keypar.use_key_pointers= test(mode & HA_MRR_MATERIALIZED_KEYS);
|
||||
seq_funcs->get_key_info(seq_init_param, &keypar.key_tuple_length,
|
||||
&keypar.key_tuple_map);
|
||||
keypar.key_size_in_keybuf= keypar.use_key_pointers?
|
||||
sizeof(char*) : keypar.key_tuple_length;
|
||||
key_buff_elem_size= keypar.key_size_in_keybuf + (int)is_mrr_assoc * sizeof(void*);
|
||||
}
|
||||
|
||||
if (strategy == index_strategy)
|
||||
{
|
||||
/* Index strategy serves it all. We don't need two handlers, etc */
|
||||
/* Give the buffer to index strategy */
|
||||
/*
|
||||
Index strategy alone handles the record retrieval. Give all buffer space
|
||||
to it. Key buffer should have forward orientation so we can return the
|
||||
end of it.
|
||||
*/
|
||||
key_buffer= &forward_key_buf;
|
||||
key_buffer->set_buffer_space(full_buf, full_buf_end);
|
||||
|
||||
/* Safety: specify that rowid buffer has zero size: */
|
||||
rowid_buffer.set_buffer_space(full_buf_end, full_buf_end);
|
||||
|
||||
if (do_sort_keys && !key_buffer->have_space_for(key_buff_elem_size))
|
||||
goto use_default_impl;
|
||||
|
||||
if ((res= index_strategy->init(h, seq_funcs, seq_init_param, n_ranges,
|
||||
mode, this)))
|
||||
mode, &keypar, key_buffer, &buf_manager)))
|
||||
goto error;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
If we got here the request is served by both index and rndpos strategies
|
||||
working together.
|
||||
/* We'll have both index and rndpos strategies working together */
|
||||
if (do_sort_keys)
|
||||
{
|
||||
/* Both strategies will need buffer space, share the buffer */
|
||||
if (setup_buffer_sharing(keypar.key_size_in_keybuf, keypar.key_tuple_map))
|
||||
goto use_default_impl;
|
||||
|
||||
*/
|
||||
rowid_buffer.set_buffer_space(buf->buffer, buf->buffer_end);
|
||||
buf_manager.reset_buffer_sizes= reset_buffer_sizes;
|
||||
buf_manager.redistribute_buffer_space= redistribute_buffer_space;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* index strategy doesn't need buffer, give all space to rowids*/
|
||||
rowid_buffer.set_buffer_space(full_buf, full_buf_end);
|
||||
if (!rowid_buffer.have_space_for(h->ref_length +
|
||||
(int)is_mrr_assoc * sizeof(char*)))
|
||||
goto use_default_impl;
|
||||
}
|
||||
|
||||
if ((res= setup_two_handlers()))
|
||||
goto error;
|
||||
|
||||
if ((res= index_strategy->init(h2, seq_funcs, seq_init_param, n_ranges,
|
||||
mode, this)) ||
|
||||
mode, &keypar, key_buffer, &buf_manager)) ||
|
||||
(res= disk_strategy->init(h, index_strategy, mode, &rowid_buffer)))
|
||||
{
|
||||
goto error;
|
||||
@ -859,6 +863,14 @@ error:
|
||||
/* Safety, not really needed but: */
|
||||
strategy= NULL;
|
||||
DBUG_RETURN(1);
|
||||
|
||||
use_default_impl:
|
||||
DBUG_ASSERT(h->inited == handler::INDEX);
|
||||
/* Call correct init function and assign to top level object */
|
||||
Mrr_simple_index_reader *s= &reader_factory.simple_index_reader;
|
||||
res= s->init(h, seq_funcs, seq_init_param, n_ranges, mode, NULL, NULL, NULL);
|
||||
strategy= s;
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
|
||||
@ -1010,34 +1022,23 @@ int Mrr_ordered_index_reader::compare_keys_reverse(void* arg, uchar* key1,
|
||||
|
||||
|
||||
/**
|
||||
Setup key/rowid buffer sizes based on sample_key and its length.
|
||||
|
||||
@param
|
||||
sample_key A lookup key to use as a sample. It is assumed that
|
||||
all other keys will have the same length/etc.
|
||||
@note
|
||||
This function must be called when all buffers are empty
|
||||
Set the buffer space to be shared between rowid and key buffer
|
||||
|
||||
@return FALSE ok
|
||||
@return TRUE There is so little buffer space that we won't be able to use
|
||||
the strategy.
|
||||
This happens when we don't have enough space for one rowid
|
||||
element and one key element so this is mainly targeted at
|
||||
testing.
|
||||
*/
|
||||
|
||||
void DsMrr_impl::setup_buffer_sizes(uint key_size_in_keybuf,
|
||||
key_part_map key_tuple_map)
|
||||
bool DsMrr_impl::setup_buffer_sharing(uint key_size_in_keybuf,
|
||||
key_part_map key_tuple_map)
|
||||
{
|
||||
uint key_buff_elem_size= key_size_in_keybuf +
|
||||
(int)is_mrr_assoc * sizeof(void*);
|
||||
|
||||
KEY *key_info= &h->get_table()->key_info[keyno];
|
||||
if (strategy == index_strategy)
|
||||
{
|
||||
/* Give all space to the key buffer, key buffer must be forward */
|
||||
key_buffer= &forward_key_buf;
|
||||
key_buffer->set_buffer_space(full_buf, full_buf_end);
|
||||
DBUG_ASSERT(key_buffer->have_space_for(key_buff_elem_size));
|
||||
|
||||
/* Just in case, tell rowid buffer that it has zero size: */
|
||||
rowid_buffer.set_buffer_space(full_buf_end, full_buf_end);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Ok if we got here we need to allocate one part of the buffer
|
||||
for keys and another part for rowids.
|
||||
@ -1048,7 +1049,6 @@ void DsMrr_impl::setup_buffer_sizes(uint key_size_in_keybuf,
|
||||
/*
|
||||
Use rec_per_key statistics as a basis to find out how many rowids
|
||||
we'll get for each key value.
|
||||
TODO: are we guaranteed to get r_p_c==1 for unique keys?
|
||||
TODO: what should be the default value to use when there is no
|
||||
statistics?
|
||||
*/
|
||||
@ -1065,45 +1065,48 @@ void DsMrr_impl::setup_buffer_sizes(uint key_size_in_keybuf,
|
||||
size_t bytes_for_rowids=
|
||||
round(fraction_for_rowids * (full_buf_end - full_buf));
|
||||
|
||||
uint bytes_for_keys= (full_buf_end - full_buf) - bytes_for_rowids;
|
||||
long bytes_for_keys= (full_buf_end - full_buf) - bytes_for_rowids;
|
||||
|
||||
if (bytes_for_keys < key_buff_elem_size + 1)
|
||||
{
|
||||
ulong add= key_buff_elem_size + 1 - bytes_for_keys;
|
||||
long add= key_buff_elem_size + 1 - bytes_for_keys;
|
||||
bytes_for_keys= key_buff_elem_size + 1;
|
||||
bytes_for_rowids -= add;
|
||||
DBUG_ASSERT(bytes_for_rowids >= rowid_buf_elem_size + 1);
|
||||
}
|
||||
|
||||
if (bytes_for_rowids < rowid_buf_elem_size + 1)
|
||||
{
|
||||
ulong add= rowid_buf_elem_size + 1 - bytes_for_rowids;
|
||||
long add= rowid_buf_elem_size + 1 - bytes_for_rowids;
|
||||
bytes_for_rowids= rowid_buf_elem_size + 1;
|
||||
bytes_for_keys -= add;
|
||||
DBUG_ASSERT(bytes_for_keys >= key_buff_elem_size + 1);
|
||||
}
|
||||
|
||||
rowid_buffer_end= full_buf + bytes_for_rowids;
|
||||
rowid_buffer.set_buffer_space(full_buf, rowid_buffer_end);
|
||||
key_buffer= &backward_key_buf;
|
||||
key_buffer->set_buffer_space(rowid_buffer_end, full_buf_end);
|
||||
DBUG_ASSERT(key_buffer->have_space_for(key_buff_elem_size));
|
||||
DBUG_ASSERT(rowid_buffer.have_space_for(rowid_buf_elem_size));
|
||||
|
||||
if (!key_buffer->have_space_for(key_buff_elem_size) ||
|
||||
!rowid_buffer.have_space_for(rowid_buf_elem_size))
|
||||
return TRUE; /* Failed to provide minimum space for one of the buffers */
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
void DsMrr_impl::reset_buffer_sizes()
|
||||
void DsMrr_impl::do_nothing(void *dsmrr_arg)
|
||||
{
|
||||
if (strategy != index_strategy)
|
||||
{
|
||||
/*
|
||||
Ok we have both ordered index reader and there is a disk rearder.
|
||||
Redistribute the buffer space.
|
||||
*/
|
||||
rowid_buffer.set_buffer_space(full_buf, rowid_buffer_end);
|
||||
key_buffer= &backward_key_buf;
|
||||
key_buffer->set_buffer_space(rowid_buffer_end, full_buf_end);
|
||||
}
|
||||
/* Do nothing */
|
||||
}
|
||||
|
||||
|
||||
void DsMrr_impl::reset_buffer_sizes(void *dsmrr_arg)
|
||||
{
|
||||
DsMrr_impl *dsmrr= (DsMrr_impl*)dsmrr_arg;
|
||||
dsmrr->rowid_buffer.set_buffer_space(dsmrr->full_buf,
|
||||
dsmrr->rowid_buffer_end);
|
||||
dsmrr->key_buffer->set_buffer_space(dsmrr->rowid_buffer_end,
|
||||
dsmrr->full_buf_end);
|
||||
}
|
||||
|
||||
|
||||
@ -1111,11 +1114,12 @@ void DsMrr_impl::reset_buffer_sizes()
|
||||
Take unused space from the key buffer and give it to the rowid buffer
|
||||
*/
|
||||
|
||||
void DsMrr_impl::redistribute_buffer_space()
|
||||
void DsMrr_impl::redistribute_buffer_space(void *dsmrr_arg)
|
||||
{
|
||||
DsMrr_impl *dsmrr= (DsMrr_impl*)dsmrr_arg;
|
||||
uchar *unused_start, *unused_end;
|
||||
key_buffer->remove_unused_space(&unused_start, &unused_end);
|
||||
rowid_buffer.grow(unused_start, unused_end);
|
||||
dsmrr->key_buffer->remove_unused_space(&unused_start, &unused_end);
|
||||
dsmrr->rowid_buffer.grow(unused_start, unused_end);
|
||||
}
|
||||
|
||||
|
||||
|
@ -56,9 +56,6 @@ class Mrr_ordered_index_reader;
|
||||
class Key_parameters
|
||||
{
|
||||
public:
|
||||
/* TRUE <=> We can get at most one index tuple for a lookup key */
|
||||
bool index_ranges_unique;
|
||||
|
||||
uint key_tuple_length; /* Length of index lookup tuple, in bytes */
|
||||
key_part_map key_tuple_map; /* keyparts used in index lookup tuples */
|
||||
|
||||
@ -71,6 +68,9 @@ public:
|
||||
|
||||
/* TRUE <=> don't copy key values, use pointers to them instead. */
|
||||
bool use_key_pointers;
|
||||
|
||||
/* TRUE <=> We can get at most one index tuple for a lookup key */
|
||||
bool index_ranges_unique;
|
||||
};
|
||||
|
||||
|
||||
@ -145,28 +145,27 @@ public:
|
||||
Buffer manager interface. Mrr_reader objects use it to inqure DsMrr_impl
|
||||
to manage buffer space for them.
|
||||
*/
|
||||
class Buffer_manager
|
||||
typedef struct st_buffer_manager
|
||||
{
|
||||
public:
|
||||
/*
|
||||
Index-based reader calls this when it gets the first key, so we get to know
|
||||
key length and
|
||||
/* Opaque value to be passed as the first argument to all member functions */
|
||||
void *arg;
|
||||
|
||||
/*
|
||||
This is called when we've freed more space from the rowid buffer. The
|
||||
callee will get the unused space from the rowid buffer and give it to the
|
||||
key buffer.
|
||||
*/
|
||||
virtual void setup_buffer_sizes(uint key_size_in_keybuf,
|
||||
key_part_map key_tuple_map) = 0;
|
||||
void (*redistribute_buffer_space)(void *arg);
|
||||
|
||||
virtual void redistribute_buffer_space() = 0;
|
||||
/*
|
||||
This is called when both key and rowid buffers are empty, and so it's time
|
||||
to reset them to their original size (They've lost their original size,
|
||||
because we were dynamically growing rowid buffer and shrinking key buffer).
|
||||
*/
|
||||
virtual void reset_buffer_sizes() = 0;
|
||||
void (*reset_buffer_sizes)(void *arg);
|
||||
|
||||
virtual Lifo_buffer* get_key_buffer() = 0;
|
||||
|
||||
virtual ~Buffer_manager(){} /* Shut up the compiler */
|
||||
};
|
||||
} Buffer_manager;
|
||||
|
||||
|
||||
/*
|
||||
@ -205,7 +204,9 @@ protected:
|
||||
public:
|
||||
virtual int init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
|
||||
void *seq_init_param, uint n_ranges,
|
||||
uint mode, Buffer_manager *buf_manager_arg) = 0;
|
||||
uint mode, Key_parameters *key_par,
|
||||
Lifo_buffer *key_buffer,
|
||||
Buffer_manager *buf_manager_arg) = 0;
|
||||
|
||||
/* Get pointer to place where every get_next() call will put rowid */
|
||||
virtual uchar *get_rowid_ptr() = 0;
|
||||
@ -224,9 +225,11 @@ public:
|
||||
class Mrr_simple_index_reader : public Mrr_index_reader
|
||||
{
|
||||
public:
|
||||
int init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
|
||||
int init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
|
||||
void *seq_init_param, uint n_ranges,
|
||||
uint mode, Buffer_manager *buf_manager_arg);
|
||||
uint mode, Key_parameters *key_par,
|
||||
Lifo_buffer *key_buffer,
|
||||
Buffer_manager *buf_manager_arg);
|
||||
int get_next(char **range_info);
|
||||
int refill_buffer(bool initial) { return initial? 0: HA_ERR_END_OF_FILE; }
|
||||
uchar *get_rowid_ptr() { return h->ref; }
|
||||
@ -247,7 +250,9 @@ class Mrr_ordered_index_reader : public Mrr_index_reader
|
||||
public:
|
||||
int init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
|
||||
void *seq_init_param, uint n_ranges,
|
||||
uint mode, Buffer_manager *buf_manager_arg);
|
||||
uint mode, Key_parameters *key_par,
|
||||
Lifo_buffer *key_buffer,
|
||||
Buffer_manager *buf_manager_arg);
|
||||
int get_next(char **range_info);
|
||||
int refill_buffer(bool initial);
|
||||
uchar *get_rowid_ptr() { return h->ref; }
|
||||
@ -278,12 +283,6 @@ private:
|
||||
/* This manages key buffer allocation and sizing for us */
|
||||
Buffer_manager *buf_manager;
|
||||
|
||||
/*
|
||||
Initially FALSE, becomes TRUE when we saw the first lookup key and set
|
||||
keypar's member.
|
||||
*/
|
||||
bool know_key_tuple_params;
|
||||
|
||||
Key_parameters keypar; /* index scan and lookup tuple parameters */
|
||||
|
||||
/* TRUE <=> need range association, buffers hold {rowid, range_id} pairs */
|
||||
@ -498,7 +497,7 @@ public:
|
||||
|
||||
*/
|
||||
|
||||
class DsMrr_impl : public Buffer_manager
|
||||
class DsMrr_impl
|
||||
{
|
||||
public:
|
||||
typedef void (handler::*range_check_toggle_func_t)(bool on);
|
||||
@ -582,10 +581,14 @@ private:
|
||||
uint *buffer_size, COST_VECT *cost);
|
||||
bool check_cpk_scan(THD *thd, uint keyno, uint mrr_flags);
|
||||
|
||||
/* Buffer_manager implementation */
|
||||
void setup_buffer_sizes(uint key_size_in_keybuf, key_part_map key_tuple_map);
|
||||
void redistribute_buffer_space();
|
||||
void reset_buffer_sizes();
|
||||
bool setup_buffer_sharing(uint key_size_in_keybuf, key_part_map key_tuple_map);
|
||||
|
||||
/* Buffer_manager and its member functions */
|
||||
Buffer_manager buf_manager;
|
||||
static void redistribute_buffer_space(void *dsmrr_arg);
|
||||
static void reset_buffer_sizes(void *dsmrr_arg);
|
||||
static void do_nothing(void *dsmrr_arg);
|
||||
|
||||
Lifo_buffer* get_key_buffer() { return key_buffer; }
|
||||
|
||||
friend class Key_value_records_iterator;
|
||||
|
@ -7449,7 +7449,7 @@ ha_rows check_quick_select(PARAM *param, uint idx, bool index_only,
|
||||
uint *mrr_flags, uint *bufsize, COST_VECT *cost)
|
||||
{
|
||||
SEL_ARG_RANGE_SEQ seq;
|
||||
RANGE_SEQ_IF seq_if = {sel_arg_range_seq_init, sel_arg_range_seq_next, 0, 0};
|
||||
RANGE_SEQ_IF seq_if = {NULL, sel_arg_range_seq_init, sel_arg_range_seq_next, 0, 0};
|
||||
handler *file= param->table->file;
|
||||
ha_rows rows;
|
||||
uint keynr= param->real_keynr[idx];
|
||||
@ -8377,7 +8377,7 @@ int QUICK_RANGE_SELECT::reset()
|
||||
if (!mrr_buf_desc)
|
||||
empty_buf.buffer= empty_buf.buffer_end= empty_buf.end_of_used_area= NULL;
|
||||
|
||||
RANGE_SEQ_IF seq_funcs= {quick_range_seq_init, quick_range_seq_next, 0, 0};
|
||||
RANGE_SEQ_IF seq_funcs= {NULL, quick_range_seq_init, quick_range_seq_next, 0, 0};
|
||||
error= file->multi_range_read_init(&seq_funcs, (void*)this, ranges.elements,
|
||||
mrr_flags, mrr_buf_desc? mrr_buf_desc:
|
||||
&empty_buf);
|
||||
|
@ -3597,6 +3597,16 @@ int JOIN_TAB_SCAN_MRR::next()
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void bka_range_seq_key_info(void *init_params, uint *length,
|
||||
key_part_map *map)
|
||||
{
|
||||
TABLE_REF *ref= &(((JOIN_CACHE*)init_params)->join_tab->ref);
|
||||
*length= ref->key_length;
|
||||
*map= (key_part_map(1) << ref->key_parts) - 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Initialize retrieval of range sequence for BKA join algorithm
|
||||
|
||||
@ -3876,7 +3886,8 @@ int JOIN_CACHE_BKA::init()
|
||||
int res;
|
||||
bool check_only_first_match= join_tab->check_only_first_match();
|
||||
|
||||
RANGE_SEQ_IF rs_funcs= { bka_range_seq_init,
|
||||
RANGE_SEQ_IF rs_funcs= { bka_range_seq_key_info,
|
||||
bka_range_seq_init,
|
||||
bka_range_seq_next,
|
||||
check_only_first_match ?
|
||||
bka_range_seq_skip_record : 0,
|
||||
@ -4265,7 +4276,8 @@ int JOIN_CACHE_BKAH::init()
|
||||
|
||||
no_association= test(mrr_mode & HA_MRR_NO_ASSOCIATION);
|
||||
|
||||
RANGE_SEQ_IF rs_funcs= { bkah_range_seq_init,
|
||||
RANGE_SEQ_IF rs_funcs= { bka_range_seq_key_info,
|
||||
bkah_range_seq_init,
|
||||
bkah_range_seq_next,
|
||||
check_only_first_match && !no_association ?
|
||||
bkah_range_seq_skip_record : 0,
|
||||
|
Loading…
x
Reference in New Issue
Block a user