1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-01 03:47:19 +03:00

DS-MRR support improvements (MWL#123, MWL#124, MWL#125)

- Lots of TODO comments
- add mrr_sort_keys flag to @@optimizer_switch
- [from Igor] SQL layer part passes HA_MRR_MATERIALIZED_KEYS flag
- Don't call rnd_pos() many times in a row if sorted rowid buffer
  has the same rowid value for multiple consequive (rowid, range_id) pairs.
This commit is contained in:
Sergey Petrunya
2010-07-17 18:03:50 +04:00
parent e1006e9e1f
commit e0999cdf7c
7 changed files with 181 additions and 48 deletions

View File

@ -327,24 +327,62 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
mode, buf);
DBUG_RETURN(retval);
}
mrr_buf= buf->buffer;
use_default_impl= FALSE;
is_mrr_assoc= !test(mode & HA_MRR_NO_ASSOCIATION);
// psergey2: split the buffer:
/*
psergey2-note: we can't split the buffer here because we don't know how key
length. we'll only be able to do it when we've got the first range.
if ((mrr_flags & HA_MRR_SINGLE_POINT) &&
optimizer_flag(thd, OPTIMIZER_SWITCH_MRR_SORT_KEYS))
{
do_sort_keys= TRUE; // will use key buffer to sort keys;
bool use_key_pointers= test(mrr_flags & HA_MRR_MATERIALIZED_KEYS);
}
do_rowid_fetch= FALSE;
if (!doing_cpk_scan && !index_only_read)
{
do_rowid_fetch= TRUE; //will use rowid buffer to store/sort rowids, etc
}
if (do_sort_keys && do_rowid_fetch)
{
split buffer space proportionally
}
else
{
// give all space to one buffer
if (do_sort_keys)
{
//sort_buffer_start= ...;
}
else
{
DBUG_ASSERT(do_rowid_fetch);
//rowid_buffer_start= ...;
}
}
*/
mrr_buf= buf->buffer;
mrr_buf_end= buf->buffer_end;
if (is_mrr_assoc)
status_var_increment(table->in_use->status_var.ha_multi_range_read_init_count);
mrr_buf_end= buf->buffer_end;
if ((doing_cpk_scan= check_cpk_scan(h->active_index, mode)))
{
/* It's a DS-MRR/CPK scan */
cpk_tuple_length= 0; /* dummy value telling it needs to be inited */
cpk_have_range= FALSE;
use_default_impl= FALSE;
h->mrr_iter= seq_funcs->init(seq_init_param, n_ranges, mode);
h->mrr_funcs= *seq_funcs;
dsmrr_fill_buffer_cpk();
dsmrr_fill_key_buffer();
if (dsmrr_eof)
buf->end_of_used_area= mrr_buf_last;
DBUG_RETURN(0); /* nothing could go wrong while filling the buffer */
@ -355,6 +393,11 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
mrr_buf_last= mrr_buf + ((mrr_buf_end - mrr_buf)/ elem_size)* elem_size;
mrr_buf_end= mrr_buf_last;
/*
psergey2: this is only needed when
- doing a rowid-to-row scan
- the buffer wasn't exhausted on the first pass.
*/
/*
There can be two cases:
- This is the first call since index_init(), h2==NULL
@ -365,7 +408,7 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
*/
if (!h2)
{
/* Create a separate handler object to do rndpos() calls. */
/* Create a separate handler object to do rnd_pos() calls. */
THD *thd= current_thd;
/*
::clone() takes up a lot of stack, especially on 64 bit platforms.
@ -376,7 +419,7 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
DBUG_ASSERT(h->active_index != MAX_KEY);
uint mrr_keyno= h->active_index;
/* Create a separate handler object to do rndpos() calls. */
/* Create a separate handler object to do rnd_pos() calls. */
if (!(new_h2= h->clone(thd->mem_root)) ||
new_h2->ha_external_lock(thd, F_RDLCK))
{
@ -397,6 +440,7 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
goto error;
}
use_default_impl= FALSE;
h2= new_h2; /* Ok, now can put it into h2 */
table->prepare_for_position();
h2->extra(HA_EXTRA_KEYREAD);
@ -404,7 +448,6 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
if (h2->ha_index_init(mrr_keyno, FALSE))
goto error;
use_default_impl= FALSE;
if (pushed_cond)
h2->idx_cond_push(mrr_keyno, pushed_cond);
}
@ -422,14 +465,13 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
h2= NULL;
int res= (h->inited == handler::INDEX && h->ha_index_end());
h2= save_h2;
use_default_impl= FALSE;
if (res)
goto error;
}
if (h2->handler::multi_range_read_init(seq_funcs, seq_init_param, n_ranges,
mode, buf) ||
dsmrr_fill_buffer())
dsmrr_fill_rowid_buffer())
{
goto error;
}
@ -449,7 +491,6 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
(h->ha_rnd_init(FALSE))))
goto error;
use_default_impl= FALSE;
h->mrr_funcs= *seq_funcs;
DBUG_RETURN(0);
@ -497,6 +538,9 @@ static int rowid_cmp(void *h, uchar *a, uchar *b)
dsmrr_eof is set to indicate whether we've exhausted the list of ranges we're
scanning.
psergey2: this func will 'fill the rowid buffer'. If filling the rowid buffer
requires that key buffer is filled/sorted first, will do that, too.
@param h Table handler
@ -505,13 +549,27 @@ static int rowid_cmp(void *h, uchar *a, uchar *b)
@retval other Error
*/
int DsMrr_impl::dsmrr_fill_buffer()
int DsMrr_impl::dsmrr_fill_rowid_buffer()
{
char *range_info;
int res;
DBUG_ENTER("DsMrr_impl::dsmrr_fill_buffer");
DBUG_ENTER("DsMrr_impl::dsmrr_fill_rowid_buffer");
mrr_buf_cur= mrr_buf;
mrr_buf_next_identical= mrr_buf_cur;
/*
psergey2-todo:
- call here fill/sort key buffer, if needed.
psergey2-todo: then, get keys either from
- multi_range_read_next()
- sorted key buffer
psergey2-todo: if we're traversing an ordered key sequence,
check if next keys are the same as previous.
(note that it's easy as ordered sequence allows forward/backward
navigation so we don't need to buffer things)
*/
while ((mrr_buf_cur < mrr_buf_end) &&
!(res= h2->handler::multi_range_read_next(&range_info)))
{
@ -520,6 +578,7 @@ int DsMrr_impl::dsmrr_fill_buffer()
h2->mrr_funcs.skip_index_tuple(h2->mrr_iter, curr_range->ptr))
continue;
/* Put rowid, or {rowid, range_id} pair into the buffer */
h2->position(table->record[0]);
memcpy(mrr_buf_cur, h2->ref, h2->ref_length);
@ -579,20 +638,26 @@ int DsMrr_impl::key_tuple_cmp(void* arg, uchar* key1, uchar* key2)
DS-MRR/CPK: Fill the buffer with (lookup_tuple, range_id) pairs and sort
SYNOPSIS
DsMrr_impl::dsmrr_fill_buffer_cpk()
DsMrr_impl::dsmrr_fill_key_buffer()
DESCRIPTION
DS-MRR/CPK: Fill the buffer with (lookup_tuple, range_id) pairs and sort
dsmrr_eof is set to indicate whether we've exhausted the list of ranges
we're scanning.
psergey2-q: can this be used for filling/sorting key buffer in general case?
a: yes.
qq: can we push sequence iteration init down into here?
*/
void DsMrr_impl::dsmrr_fill_buffer_cpk()
void DsMrr_impl::dsmrr_fill_key_buffer()
{
//psergey2: here, no identicals detection is necessary since we always scan
// the unordered sequence.
int res;
KEY_MULTI_RANGE cur_range;
DBUG_ENTER("DsMrr_impl::dsmrr_fill_buffer_cpk");
DBUG_ENTER("DsMrr_impl::dsmrr_fill_key_buffer");
mrr_buf_cur= mrr_buf;
while ((mrr_buf_cur < mrr_buf_end) &&
@ -611,6 +676,8 @@ void DsMrr_impl::dsmrr_fill_buffer_cpk()
mrr_buf_end= mrr_buf_last;
}
//psergey2: if keys are materialized, store pointers, not copy keys
/* Put key, or {key, range_id} pair into the buffer */
memcpy(mrr_buf_cur, cur_range.start_key.key, cpk_tuple_length);
mrr_buf_cur += cpk_tuple_length;
@ -648,12 +715,14 @@ void DsMrr_impl::dsmrr_fill_buffer_cpk()
This is similar to DsMrr_impl::dsmrr_next(), the differences are that
- we get records with index_read(), not with rnd_pos()
- we may get multiple records for one key (=element of the buffer)
- unlike dsmrr_fill_buffer(), dsmrr_fill_buffer_cpk() never fails.
- unlike dsmrr_fill_rowid_buffer(), dsmrr_fill_key_buffer() never fails.
RETURN
0 OK, next record was successfully read
HA_ERR_END_OF_FILE End of records
Other Some other error
psergey2-todo: this should detect identical keys.
*/
int DsMrr_impl::dsmrr_next_cpk(char **range_info)
@ -697,7 +766,7 @@ int DsMrr_impl::dsmrr_next_cpk(char **range_info)
res= HA_ERR_END_OF_FILE;
goto end;
}
dsmrr_fill_buffer_cpk();
dsmrr_fill_key_buffer();
}
if (mrr_buf_cur == mrr_buf_last)
{
@ -758,6 +827,9 @@ end:
/**
DS-MRR implementation: multi_range_read_next() function
psergey2-todo: put identical rowid detection code here
it should always work because rowid sequences are always sorted
*/
int DsMrr_impl::dsmrr_next(char **range_info)
@ -772,6 +844,23 @@ int DsMrr_impl::dsmrr_next(char **range_info)
if (doing_cpk_scan)
return dsmrr_next_cpk(range_info);
if (mrr_buf_next_identical != mrr_buf_cur)
{
/*
There are multiple rowids. Return the record again, now with different
range_id
*/
do
{
if (is_mrr_assoc)
memcpy(range_info, mrr_buf_next_identical + h->ref_length, sizeof(uchar*));
} while (!h2->mrr_funcs.skip_record ||
!h2->mrr_funcs.skip_record(h2->mrr_iter, (char *) range_info, rowid));
mrr_buf_next_identical += h->ref_length + sizeof(void*) * test(is_mrr_assoc);
return 0;
}
do
{
if (mrr_buf_cur == mrr_buf_last)
@ -781,7 +870,7 @@ int DsMrr_impl::dsmrr_next(char **range_info)
res= HA_ERR_END_OF_FILE;
goto end;
}
res= dsmrr_fill_buffer();
res= dsmrr_fill_rowid_buffer();
if (res)
goto end;
}
@ -796,13 +885,34 @@ int DsMrr_impl::dsmrr_next(char **range_info)
if (is_mrr_assoc)
memcpy(&cur_range_info, mrr_buf_cur + h->ref_length, sizeof(uchar**));
size_t element_size= h->ref_length + sizeof(void*) * test(is_mrr_assoc);
mrr_buf_cur += element_size;
mrr_buf_next_identical= mrr_buf_cur;
mrr_buf_cur += h->ref_length + sizeof(void*) * test(is_mrr_assoc);
if (h2->mrr_funcs.skip_record &&
h2->mrr_funcs.skip_record(h2->mrr_iter, (char *) cur_range_info, rowid))
continue;
res= h->ha_rnd_pos(table->record[0], rowid);
if (res == HA_ERR_RECORD_DELETED)
continue;
if (0)//(!res)
{
/*
Note: this implies that SQL layer doesn't touch table->record[0]
between calls.
*/
uchar *current_el= mrr_buf_cur - element_size;
while (mrr_buf_cur != mrr_buf_last &&
!h2->cmp_ref(current_el, mrr_buf_cur))
{
mrr_buf_cur += element_size;
}
}
break;
} while (true);
if (is_mrr_assoc)
@ -986,7 +1096,7 @@ bool DsMrr_impl::choose_mrr_impl(uint keyno, ha_rows rows, uint *flags,
*flags |= HA_MRR_USE_DEFAULT_IMPL;
return TRUE;
}
uint add_len= table->key_info[keyno].key_length + h->ref_length;
*bufsz -= add_len;
if (get_disk_sweep_mrr_cost(keyno, rows, *flags, bufsz, &dsmrr_cost))
@ -1010,6 +1120,10 @@ bool DsMrr_impl::choose_mrr_impl(uint keyno, ha_rows rows, uint *flags,
*flags &= ~HA_MRR_SORTED; /* We will return unordered output */
*cost= dsmrr_cost;
res= FALSE;
if ((*flags & HA_MRR_SINGLE_POINT) &&
optimizer_flag(thd, OPTIMIZER_SWITCH_MRR_SORT_KEYS))
*flags |= HA_MRR_MATERIALIZED_KEYS;
}
else
{