mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
DS-MRR improvements
- Code cleanup - Always propagate the error code we got from storage engine all the way up
This commit is contained in:
parent
d6ec99d0b6
commit
197c99427d
2 changed files with 150 additions and 61 deletions
|
@ -292,13 +292,14 @@ int Mrr_simple_index_reader::init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
|
|||
{
|
||||
HANDLER_BUFFER no_buffer = {NULL, NULL, NULL};
|
||||
h= h_arg;
|
||||
res= 0;
|
||||
return h->handler::multi_range_read_init(seq_funcs, seq_init_param, n_ranges,
|
||||
mode, &no_buffer);
|
||||
}
|
||||
|
||||
|
||||
int Mrr_simple_index_reader::get_next(char **range_info)
|
||||
{
|
||||
int res;
|
||||
while (!(res= h->handler::multi_range_read_next(range_info)))
|
||||
{
|
||||
KEY_MULTI_RANGE *curr_range= &h->handler::mrr_cur_range;
|
||||
|
@ -328,6 +329,7 @@ int Mrr_simple_index_reader::get_next(char **range_info)
|
|||
|
||||
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)
|
||||
|
@ -344,33 +346,32 @@ int Mrr_ordered_index_reader::get_next(char **range_info)
|
|||
bool have_record= FALSE;
|
||||
if (scanning_key_val_iter)
|
||||
{
|
||||
if (kv_it.get_next())
|
||||
if ((res= kv_it.get_next()))
|
||||
{
|
||||
kv_it.close();
|
||||
scanning_key_val_iter= FALSE;
|
||||
if ((res != HA_ERR_KEY_NOT_FOUND && res != HA_ERR_END_OF_FILE))
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
else
|
||||
have_record= TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (kv_it.init(this))
|
||||
while ((res= kv_it.init(this)))
|
||||
{
|
||||
if (key_buffer->is_empty())
|
||||
if ((res != HA_ERR_KEY_NOT_FOUND && res != HA_ERR_END_OF_FILE) ||
|
||||
key_buffer->is_empty())
|
||||
{
|
||||
index_scan_eof= TRUE;
|
||||
DBUG_RETURN(HA_ERR_END_OF_FILE);
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
}
|
||||
scanning_key_val_iter= TRUE;
|
||||
}
|
||||
|
||||
if (have_record &&
|
||||
(!mrr_funcs.skip_index_tuple ||
|
||||
!mrr_funcs.skip_index_tuple(mrr_iter, *(char**)cur_range_info))
|
||||
&&
|
||||
(!mrr_funcs.skip_record ||
|
||||
!mrr_funcs.skip_record(mrr_iter, *(char**)cur_range_info, NULL)))
|
||||
!skip_index_tuple(*(char**)cur_range_info) &&
|
||||
!skip_record(*(char**)cur_range_info, NULL))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -448,7 +449,6 @@ int Mrr_ordered_index_reader::refill_buffer()
|
|||
|
||||
bool no_more_keys= test(res);
|
||||
scanning_key_val_iter= FALSE;
|
||||
index_scan_eof= FALSE;
|
||||
|
||||
if (no_more_keys && (!know_key_tuple_params || key_buffer->is_empty()))
|
||||
DBUG_RETURN(HA_ERR_END_OF_FILE);
|
||||
|
@ -586,7 +586,7 @@ int Mrr_ordered_rndpos_reader::refill_from_key_buffer()
|
|||
|
||||
|
||||
/*
|
||||
Get the next record+range_id using ordered array of rowid+range_id pairds
|
||||
Get the next {record, range_id} using ordered array of rowid+range_id pairs
|
||||
|
||||
@note
|
||||
Since we have sorted rowids, we try not to make multiple rnd_pos() calls
|
||||
|
@ -976,7 +976,8 @@ equals:
|
|||
}
|
||||
|
||||
|
||||
int Mrr_ordered_index_reader::key_tuple_cmp_reverse(void* arg, uchar* key1, uchar* key2)
|
||||
int Mrr_ordered_index_reader::key_tuple_cmp_reverse(void* arg, uchar* key1,
|
||||
uchar* key2)
|
||||
{
|
||||
return -key_tuple_cmp(arg, key1, key2);
|
||||
}
|
||||
|
@ -1070,11 +1071,11 @@ void DsMrr_impl::reset_buffer_sizes()
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
Take unused space from the key buffer and give it to the rowid buffer
|
||||
*/
|
||||
//psergey-todo: do invoke this function.
|
||||
void DsMrr_impl::reallocate_buffer_space()
|
||||
|
||||
void DsMrr_impl::redistribute_buffer_space()
|
||||
{
|
||||
uchar *unused_start, *unused_end;
|
||||
key_buffer->remove_unused_space(&unused_start, &unused_end);
|
||||
|
@ -1082,19 +1083,35 @@ void DsMrr_impl::reallocate_buffer_space()
|
|||
}
|
||||
|
||||
|
||||
bool Key_value_records_iterator::init(Mrr_ordered_index_reader *owner_arg)
|
||||
/*
|
||||
@brief Initialize the iterator
|
||||
|
||||
@note
|
||||
Initialize the iterator to produce matches for the key of the first element
|
||||
in owner_arg->key_buffer
|
||||
|
||||
@retval 0 OK
|
||||
@retval HA_ERR_END_OF_FILE Either the owner->key_buffer is empty or
|
||||
no matches for the key we've tried (check
|
||||
key_buffer->is_empty() to tell these apart)
|
||||
@retval other code Fatal error
|
||||
*/
|
||||
|
||||
int Key_value_records_iterator::init(Mrr_ordered_index_reader *owner_arg)
|
||||
{
|
||||
int res;
|
||||
owner= owner_arg;
|
||||
|
||||
identical_key_it.init(owner->key_buffer);
|
||||
/* Get the first pair into (cur_index_tuple, cur_range_info) */
|
||||
owner->key_buffer->setup_reading(&cur_index_tuple, owner->keypar.key_size_in_keybuf,
|
||||
owner->is_mrr_assoc? (uchar**)&owner->cur_range_info: NULL,
|
||||
sizeof(void*));
|
||||
owner->key_buffer->setup_reading(&cur_index_tuple,
|
||||
owner->keypar.key_size_in_keybuf,
|
||||
owner->is_mrr_assoc?
|
||||
(uchar**)&owner->cur_range_info: NULL,
|
||||
sizeof(void*));
|
||||
|
||||
if (identical_key_it.read())
|
||||
return TRUE;
|
||||
return HA_ERR_END_OF_FILE;
|
||||
|
||||
uchar *key_in_buf= cur_index_tuple;
|
||||
|
||||
|
@ -1106,21 +1123,22 @@ bool Key_value_records_iterator::init(Mrr_ordered_index_reader *owner_arg)
|
|||
uchar *save_cur_index_tuple= cur_index_tuple;
|
||||
while (!identical_key_it.read())
|
||||
{
|
||||
if (Mrr_ordered_index_reader::key_tuple_cmp(owner, key_in_buf, cur_index_tuple))
|
||||
if (Mrr_ordered_index_reader::key_tuple_cmp(owner, key_in_buf,
|
||||
cur_index_tuple))
|
||||
break;
|
||||
last_identical_key_ptr= cur_index_tuple;
|
||||
}
|
||||
identical_key_it.init(owner->key_buffer);
|
||||
cur_index_tuple= save_cur_index_tuple;
|
||||
res= owner->h->ha_index_read_map(owner->h->get_table()->record[0],
|
||||
cur_index_tuple,
|
||||
owner->keypar.key_tuple_map,
|
||||
HA_READ_KEY_EXACT);
|
||||
cur_index_tuple,
|
||||
owner->keypar.key_tuple_map,
|
||||
HA_READ_KEY_EXACT);
|
||||
|
||||
if (res)
|
||||
{
|
||||
close();
|
||||
return res; /* Fatal error */
|
||||
return res;
|
||||
}
|
||||
get_next_row= FALSE;
|
||||
return 0;
|
||||
|
@ -1141,14 +1159,14 @@ int Key_value_records_iterator::get_next()
|
|||
cur_index_tuple,
|
||||
owner->keypar.key_tuple_length)))
|
||||
{
|
||||
/* EOF is EOF for iterator, also, any error means EOF on the iterator */
|
||||
return res;
|
||||
/* It's either HA_ERR_END_OF_FILE or some other error */
|
||||
return res;
|
||||
}
|
||||
identical_key_it.init(owner->key_buffer);
|
||||
get_next_row= FALSE;
|
||||
}
|
||||
|
||||
identical_key_it.read(); // This gets us next range_id.
|
||||
identical_key_it.read(); /* This gets us next range_id */
|
||||
if (!last_identical_key_ptr || (cur_index_tuple == last_identical_key_ptr))
|
||||
{
|
||||
get_next_row= TRUE;
|
||||
|
@ -1156,6 +1174,7 @@ int Key_value_records_iterator::get_next()
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void Key_value_records_iterator::close()
|
||||
{
|
||||
while (!owner->key_buffer->read() &&
|
||||
|
@ -1178,7 +1197,6 @@ int DsMrr_impl::dsmrr_next(char **range_info)
|
|||
break; /* EOF or error */
|
||||
}
|
||||
return res;
|
||||
//return strategy->get_next(range_info);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -77,30 +77,65 @@ public:
|
|||
/**
|
||||
A class to enumerate (record, range_id) pairs that match given key value.
|
||||
|
||||
The idea is that we have an array of
|
||||
@note
|
||||
|
||||
(key, range_id1), (key, range_id2) ... (key, range_idN)
|
||||
The idea is that we have a Lifo_buffer which holds (key, range_id) pairs
|
||||
ordered by key value. From the front of the buffer we see
|
||||
|
||||
pairs, i.e. multiple identical key values with their different range_id-s,
|
||||
and also we have ha_engine object where we can find matches for the key
|
||||
value.
|
||||
(key_val1, range_id1), (key_val1, range_id2) ... (key_val2, range_idN)
|
||||
|
||||
What this class does is produces all combinations of (key_match_record_X,
|
||||
range_idN) pairs.
|
||||
we take the first elements that have the same key value (key_val1 in the
|
||||
example above), and make lookup into the table. The table will have
|
||||
multiple matches for key_val1:
|
||||
|
||||
== Table Index ==
|
||||
...
|
||||
key_val1 -> key_val1, index_tuple1
|
||||
key_val1, index_tuple2
|
||||
...
|
||||
key_val1, index_tupleN
|
||||
...
|
||||
|
||||
Our goal is to produce all possible combinations, i.e. we need:
|
||||
|
||||
{(key_val1, index_tuple1), range_id1}
|
||||
{(key_val1, index_tuple1), range_id2}
|
||||
... ... |
|
||||
{(key_val1, index_tuple1), range_idN},
|
||||
|
||||
{(key_val1, index_tuple2), range_id1}
|
||||
{(key_val1, index_tuple2), range_id2}
|
||||
... ... |
|
||||
{(key_val1, index_tuple2), range_idN},
|
||||
|
||||
... ... ...
|
||||
|
||||
{(key_val1, index_tupleK), range_idN}
|
||||
*/
|
||||
|
||||
class Key_value_records_iterator
|
||||
{
|
||||
/* Use this to get table handler, key buffer and other parameters */
|
||||
Mrr_ordered_index_reader *owner;
|
||||
Lifo_buffer_iterator identical_key_it;
|
||||
|
||||
/* Iterator to get (key, range_id) pairs from */
|
||||
Lifo_buffer_iterator identical_key_it;
|
||||
|
||||
/*
|
||||
Last of the identical key values (when we get this pointer from
|
||||
identical_key_it, it will be time to stop).
|
||||
*/
|
||||
uchar *last_identical_key_ptr;
|
||||
|
||||
/*
|
||||
FALSE <=> we're right after the init() call, the record has been already
|
||||
read with owner->h->index_read_map() call
|
||||
*/
|
||||
bool get_next_row;
|
||||
|
||||
uchar *cur_index_tuple; /* key_buffer.read() reads to here */
|
||||
public:
|
||||
bool init(Mrr_ordered_index_reader *owner_arg);
|
||||
int init(Mrr_ordered_index_reader *owner_arg);
|
||||
int get_next();
|
||||
void close();
|
||||
};
|
||||
|
@ -113,10 +148,23 @@ public:
|
|||
class Buffer_manager
|
||||
{
|
||||
public:
|
||||
/*
|
||||
Index-based reader calls this when it gets the first key, so we get to know
|
||||
key length and
|
||||
*/
|
||||
virtual void setup_buffer_sizes(uint key_size_in_keybuf,
|
||||
key_part_map key_tuple_map)=0;
|
||||
virtual void reset_buffer_sizes()= 0;
|
||||
virtual Lifo_buffer* get_key_buffer()= 0;
|
||||
key_part_map key_tuple_map) = 0;
|
||||
|
||||
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;
|
||||
|
||||
virtual Lifo_buffer* get_key_buffer() = 0;
|
||||
|
||||
virtual ~Buffer_manager(){} /* Shut up the compiler */
|
||||
};
|
||||
|
||||
|
@ -160,21 +208,21 @@ public:
|
|||
uint mode, Buffer_manager *buf_manager_arg) = 0;
|
||||
|
||||
/* Get pointer to place where every get_next() call will put rowid */
|
||||
virtual uchar *get_rowid_ptr()= 0;
|
||||
virtual uchar *get_rowid_ptr() = 0;
|
||||
/* Get the rowid (call this after get_next() call) */
|
||||
void position();
|
||||
virtual bool skip_record(char *range_id, uchar *rowid)=0;
|
||||
virtual bool skip_record(char *range_id, uchar *rowid) = 0;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
A "bypass" reader that uses default MRR implementation (i.e.
|
||||
handler::multi_range_read_XXX() calls) to produce rows.
|
||||
A "bypass" index reader that just does and index scan. The index scan is done
|
||||
by calling default MRR implementation (i.e. handler::multi_range_read_XXX())
|
||||
functions.
|
||||
*/
|
||||
|
||||
class Mrr_simple_index_reader : public Mrr_index_reader
|
||||
{
|
||||
int res;
|
||||
public:
|
||||
int init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
|
||||
void *seq_init_param, uint n_ranges,
|
||||
|
@ -209,31 +257,42 @@ public:
|
|||
return (mrr_funcs.skip_record &&
|
||||
mrr_funcs.skip_record(mrr_iter, range_info, rowid));
|
||||
}
|
||||
|
||||
bool skip_index_tuple(char *range_info)
|
||||
{
|
||||
return (mrr_funcs.skip_index_tuple &&
|
||||
mrr_funcs.skip_index_tuple(mrr_iter, range_info));
|
||||
}
|
||||
|
||||
private:
|
||||
Key_value_records_iterator kv_it;
|
||||
|
||||
bool scanning_key_val_iter;
|
||||
|
||||
/* Key_value_records_iterator::read() will place range_info here */
|
||||
char *cur_range_info;
|
||||
|
||||
/* Buffer to store (key, range_id) pairs */
|
||||
Lifo_buffer *key_buffer;
|
||||
|
||||
|
||||
/* This manages key buffer allocation and sizing for us */
|
||||
Buffer_manager *buf_manager;
|
||||
|
||||
/* Initially FALSE, becomes TRUE when we've set key_tuple_xxx members */
|
||||
/*
|
||||
Initially FALSE, becomes TRUE when we saw the first lookup key and set
|
||||
keypar's member.
|
||||
*/
|
||||
bool know_key_tuple_params;
|
||||
|
||||
Key_parameters keypar;
|
||||
|
||||
Key_parameters keypar; /* index scan and lookup tuple parameters */
|
||||
|
||||
/* TRUE <=> need range association, buffers hold {rowid, range_id} pairs */
|
||||
bool is_mrr_assoc;
|
||||
|
||||
|
||||
/* Range sequence iteration members */
|
||||
RANGE_SEQ_IF mrr_funcs;
|
||||
range_seq_t mrr_iter;
|
||||
|
||||
bool index_scan_eof;
|
||||
|
||||
static int key_tuple_cmp(void* arg, uchar* key1, uchar* key2);
|
||||
static int key_tuple_cmp_reverse(void* arg, uchar* key1, uchar* key2);
|
||||
|
||||
|
@ -256,18 +315,27 @@ public:
|
|||
int get_next(char **range_info);
|
||||
int refill_buffer();
|
||||
private:
|
||||
handler *h;
|
||||
handler *h; /* Handler to use */
|
||||
|
||||
DsMrr_impl *dsmrr;
|
||||
/* This what we get (rowid, range_info) pairs from */
|
||||
Mrr_index_reader *index_reader;
|
||||
|
||||
/* index_reader->get_next() puts rowid here */
|
||||
uchar *index_rowid;
|
||||
|
||||
/* TRUE <=> index_reader->refill_buffer() call has returned EOF */
|
||||
bool index_reader_exhausted;
|
||||
|
||||
/* TRUE <=> need range association, buffers hold {rowid, range_id} pairs */
|
||||
bool is_mrr_assoc;
|
||||
|
||||
|
||||
/*
|
||||
When reading from ordered rowid buffer: the rowid element of the last
|
||||
buffer element that has rowid identical to this one.
|
||||
*/
|
||||
uchar *last_identical_rowid;
|
||||
|
||||
/* Buffer to store (rowid, range_id) pairs */
|
||||
Lifo_buffer *rowid_buffer;
|
||||
|
||||
/* rowid_buffer.read() will set the following: */
|
||||
|
@ -278,7 +346,11 @@ private:
|
|||
};
|
||||
|
||||
|
||||
/* A place where one can get readers without having to alloc them on the heap */
|
||||
/*
|
||||
A primitive "factory" of various Mrr_*_reader classes (the point is to
|
||||
get various kinds of readers without having to allocate them on the heap)
|
||||
*/
|
||||
|
||||
class Mrr_reader_factory
|
||||
{
|
||||
public:
|
||||
|
@ -497,10 +569,9 @@ private:
|
|||
uint *buffer_size, COST_VECT *cost);
|
||||
bool check_cpk_scan(THD *thd, uint keyno, uint mrr_flags);
|
||||
|
||||
void reallocate_buffer_space();
|
||||
|
||||
/* 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();
|
||||
Lifo_buffer* get_key_buffer() { return key_buffer; }
|
||||
|
||||
|
|
Loading…
Reference in a new issue