Commit dbc63bed authored by Sergey Petrunya's avatar Sergey Petrunya

MWL#121-125: DS-MRR improvements

- Address review feedback, step 1 
parent fae27347
...@@ -1807,6 +1807,10 @@ public: ...@@ -1807,6 +1807,10 @@ public:
inline int ha_index_first(uchar * buf); inline int ha_index_first(uchar * buf);
inline int ha_index_last(uchar * buf); inline int ha_index_last(uchar * buf);
inline int ha_index_next_same(uchar *buf, const uchar *key, uint keylen); inline int ha_index_next_same(uchar *buf, const uchar *key, uint keylen);
/*
TODO: should we make for those functions non-virtual ha_func_name wrappers,
too?
*/
virtual ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, virtual ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
void *seq_init_param, void *seq_init_param,
uint n_ranges, uint *bufsz, uint n_ranges, uint *bufsz,
......
...@@ -286,6 +286,28 @@ scan_it_again: ...@@ -286,6 +286,28 @@ scan_it_again:
/**************************************************************************** /****************************************************************************
* DS-MRR implementation * DS-MRR implementation
***************************************************************************/ ***************************************************************************/
void SimpleBuffer::setup_writing(uchar **data1, size_t len1,
uchar **data2, size_t len2)
{
write_ptr1= data1;
write_size1= len1;
write_ptr2= data2;
write_size2= len2;
}
void SimpleBuffer::write()
{
if (is_reverse() && write_ptr2)
write(*write_ptr2, write_size2);
write(*write_ptr1, write_size1);
if (!is_reverse() && write_ptr2)
write(*write_ptr2, write_size2);
}
void SimpleBuffer::write(const uchar *data, size_t bytes) void SimpleBuffer::write(const uchar *data, size_t bytes)
{ {
...@@ -313,6 +335,27 @@ size_t SimpleBuffer::used_size() ...@@ -313,6 +335,27 @@ size_t SimpleBuffer::used_size()
return (direction == 1)? write_pos - read_pos : read_pos - write_pos; return (direction == 1)? write_pos - read_pos : read_pos - write_pos;
} }
void SimpleBuffer::setup_reading(uchar **data1, size_t len1,
uchar **data2, size_t len2)
{
read_ptr1= data1;
read_size1= len1;
read_ptr2= data2;
read_size2= len2;
}
bool SimpleBuffer::read()
{
if (!have_data(read_size1 + read_ptr2? read_size2 : 0))
return TRUE;
*read_ptr1 =read(read_size1);
if (read_ptr2)
*read_ptr2= read(read_size2);
return FALSE;
}
uchar *SimpleBuffer::read(size_t bytes) uchar *SimpleBuffer::read(size_t bytes)
{ {
DBUG_ASSERT(have_data(bytes)); DBUG_ASSERT(have_data(bytes));
...@@ -636,12 +679,16 @@ static int rowid_cmp(void *h, uchar *a, uchar *b) ...@@ -636,12 +679,16 @@ static int rowid_cmp(void *h, uchar *a, uchar *b)
int DsMrr_impl::dsmrr_fill_rowid_buffer() int DsMrr_impl::dsmrr_fill_rowid_buffer()
{ {
char *range_info; char *range_info;
uchar **range_info_ptr= (uchar**)&range_info;
int res; int res;
DBUG_ENTER("DsMrr_impl::dsmrr_fill_rowid_buffer"); DBUG_ENTER("DsMrr_impl::dsmrr_fill_rowid_buffer");
DBUG_ASSERT(rowid_buffer.is_empty()); DBUG_ASSERT(rowid_buffer.is_empty());
rowid_buffer.reset_for_writing(); rowid_buffer.reset_for_writing();
identical_rowid_ptr= NULL; rowid_buffer.setup_writing(&h2->ref, h2->ref_length,
is_mrr_assoc? (uchar**)&range_info_ptr: NULL, sizeof(void*));
last_identical_rowid= NULL;
if (do_sort_keys && key_buffer.is_reverse()) if (do_sort_keys && key_buffer.is_reverse())
key_buffer.flip(); key_buffer.flip();
...@@ -664,10 +711,8 @@ int DsMrr_impl::dsmrr_fill_rowid_buffer() ...@@ -664,10 +711,8 @@ int DsMrr_impl::dsmrr_fill_rowid_buffer()
/* Put rowid, or {rowid, range_id} pair into the buffer */ /* Put rowid, or {rowid, range_id} pair into the buffer */
h2->position(table->record[0]); h2->position(table->record[0]);
rowid_buffer.write(h2->ref, h2->ref_length);
if (is_mrr_assoc) rowid_buffer.write();
rowid_buffer.write((uchar*)&range_info, sizeof(void*));
} }
if (res && res != HA_ERR_END_OF_FILE) if (res && res != HA_ERR_END_OF_FILE)
...@@ -677,15 +722,19 @@ int DsMrr_impl::dsmrr_fill_rowid_buffer() ...@@ -677,15 +722,19 @@ int DsMrr_impl::dsmrr_fill_rowid_buffer()
dsmrr_eof= test(res == HA_ERR_END_OF_FILE); dsmrr_eof= test(res == HA_ERR_END_OF_FILE);
/* Sort the buffer contents by rowid */ /* Sort the buffer contents by rowid */
uint elem_size= h->ref_length + (int)is_mrr_assoc * sizeof(void*); rowid_buffer.sort((qsort2_cmp)rowid_cmp, (void*)h);
uint n_rowids= rowid_buffer.used_size() / elem_size;
my_qsort2(rowid_buffer.used_area(), n_rowids, elem_size,
(qsort2_cmp)rowid_cmp, (void*)h);
rowid_buffer.setup_reading(&rowid, h->ref_length,
is_mrr_assoc? (uchar**)&rowids_range_id: NULL, sizeof(void*));
DBUG_RETURN(0); DBUG_RETURN(0);
} }
void SimpleBuffer::sort(qsort2_cmp cmp_func, void *cmp_func_arg)
{
uint elem_size=write_size1 + (write_ptr2 ? write_size2 : 0);
uint n_elements= used_size() / elem_size;
my_qsort2(used_area(), n_elements, elem_size, cmp_func, cmp_func_arg);
}
/* /*
my_qsort2-compatible function to compare key tuples my_qsort2-compatible function to compare key tuples
...@@ -838,6 +887,7 @@ void DsMrr_impl::dsmrr_fill_key_buffer() ...@@ -838,6 +887,7 @@ void DsMrr_impl::dsmrr_fill_key_buffer()
{ {
int res; int res;
KEY_MULTI_RANGE cur_range; KEY_MULTI_RANGE cur_range;
uchar **range_info_ptr= (uchar**)&cur_range.ptr;
DBUG_ENTER("DsMrr_impl::dsmrr_fill_key_buffer"); DBUG_ENTER("DsMrr_impl::dsmrr_fill_key_buffer");
DBUG_ASSERT(!key_tuple_length || key_buffer.is_empty()); DBUG_ASSERT(!key_tuple_length || key_buffer.is_empty());
...@@ -856,6 +906,7 @@ void DsMrr_impl::dsmrr_fill_key_buffer() ...@@ -856,6 +906,7 @@ void DsMrr_impl::dsmrr_fill_key_buffer()
key_buffer.reset_for_writing(); key_buffer.reset_for_writing();
} }
uchar *key_ptr;
while ((key_tuple_length == 0 || while ((key_tuple_length == 0 ||
key_buffer.have_space_for(key_buff_elem_size)) && key_buffer.have_space_for(key_buff_elem_size)) &&
!(res= h->mrr_funcs.next(h->mrr_iter, &cur_range))) !(res= h->mrr_funcs.next(h->mrr_iter, &cur_range)))
...@@ -865,33 +916,29 @@ void DsMrr_impl::dsmrr_fill_key_buffer() ...@@ -865,33 +916,29 @@ void DsMrr_impl::dsmrr_fill_key_buffer()
{ {
/* This only happens when we've just started filling the buffer */ /* This only happens when we've just started filling the buffer */
setup_buffer_sizes(&cur_range.start_key); setup_buffer_sizes(&cur_range.start_key);
key_buffer.setup_writing(&key_ptr, key_size_in_keybuf,
is_mrr_assoc? (uchar**)&range_info_ptr : NULL,
sizeof(uchar*));
} }
if (key_buffer.is_reverse() && is_mrr_assoc)
key_buffer.write((uchar*)&cur_range.ptr, sizeof(void*));
/* Put key, or {key, range_id} pair into the buffer */ /* Put key, or {key, range_id} pair into the buffer */
if (use_key_pointers) if (use_key_pointers)
key_buffer.write((uchar*)&cur_range.start_key.key, sizeof(char*)); key_ptr=(uchar*) &cur_range.start_key.key;
else else
key_buffer.write(cur_range.start_key.key, key_tuple_length); key_ptr=(uchar*) cur_range.start_key.key;
if (!key_buffer.is_reverse() && is_mrr_assoc) key_buffer.write();
key_buffer.write((uchar*)&cur_range.ptr, sizeof(void*));
} }
dsmrr_eof= test(res); dsmrr_eof= test(res);
/* Sort the buffer contents by rowid */ key_buffer.sort((qsort2_cmp)DsMrr_impl::key_tuple_cmp, (void*)this);
uint key_elem_size= key_size_in_keybuf + (int)is_mrr_assoc * sizeof(void*);
uint n_keys= key_buffer.used_size() / key_elem_size;
my_qsort2(key_buffer.used_area(), n_keys, key_elem_size,
(qsort2_cmp)DsMrr_impl::key_tuple_cmp, (void*)this);
key_buffer.setup_reading(&cur_index_tuple, key_size_in_keybuf,
is_mrr_assoc? (uchar**)&cur_range_info: NULL, sizeof(void*));
last_identical_key_ptr= NULL; last_identical_key_ptr= NULL;
in_identical_keys_range= FALSE; in_identical_keys_range= FALSE;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -927,15 +974,15 @@ int DsMrr_impl::dsmrr_next_from_index(char **range_info_arg) ...@@ -927,15 +974,15 @@ int DsMrr_impl::dsmrr_next_from_index(char **range_info_arg)
int res; int res;
uchar *key_in_buf; uchar *key_in_buf;
handler *file= do_rowid_fetch? h2: h; handler *file= do_rowid_fetch? h2: h;
bool res2;
while (in_identical_keys_range) while (in_identical_keys_range)
{ {
/* Read record/key pointer from the buffer */ /* This will read to (cur_index_tuple, cur_range_info): */
key_in_buf= identical_key_it.get_next(key_size_in_keybuf); res2= identical_key_it.read_next();
if (is_mrr_assoc) DBUG_ASSERT(!res2);
cur_range_info= (char*)identical_key_it.get_next(sizeof(void*));
if (key_in_buf == last_identical_key_ptr) if (cur_index_tuple == last_identical_key_ptr)
{ {
/* We're looking at the last of the identical keys */ /* We're looking at the last of the identical keys */
in_identical_keys_range= FALSE; in_identical_keys_range= FALSE;
...@@ -985,13 +1032,8 @@ check_record: ...@@ -985,13 +1032,8 @@ check_record:
/* Jump over the keys that were handled by identical key processing */ /* Jump over the keys that were handled by identical key processing */
if (last_identical_key_ptr) if (last_identical_key_ptr)
{ {
while (key_buffer.read(key_size_in_keybuf) != last_identical_key_ptr) /* key_buffer.read() reads to (cur_index_tuple, cur_range_info) */
{ while (!key_buffer.read() && (cur_index_tuple != last_identical_key_ptr)) {}
if (is_mrr_assoc)
key_buffer.read(sizeof(void*));
}
if (is_mrr_assoc)
key_buffer.read(sizeof(void*));
last_identical_key_ptr= NULL; last_identical_key_ptr= NULL;
} }
...@@ -1030,14 +1072,12 @@ check_record: ...@@ -1030,14 +1072,12 @@ check_record:
} }
/* Get the next range to scan */ /* Get the next range to scan */
cur_index_tuple= key_in_buf= key_buffer.read(key_size_in_keybuf); key_buffer.read(); // reads to (cur_index_tuple, cur_range_info)
key_in_buf= cur_index_tuple;
if (use_key_pointers) if (use_key_pointers)
cur_index_tuple= *((uchar**)cur_index_tuple); cur_index_tuple= *((uchar**)cur_index_tuple);
if (is_mrr_assoc)
cur_range_info= (char*)key_buffer.read(sizeof(void*));
/* Do index lookup */ /* Do index lookup */
if ((res= file->ha_index_read_map(table->record[0], cur_index_tuple, if ((res= file->ha_index_read_map(table->record[0], cur_index_tuple,
key_tuple_map, HA_READ_KEY_EXACT))) key_tuple_map, HA_READ_KEY_EXACT)))
...@@ -1049,19 +1089,17 @@ check_record: ...@@ -1049,19 +1089,17 @@ check_record:
/* Check if subsequent keys in the key buffer are the same as this one */ /* Check if subsequent keys in the key buffer are the same as this one */
{ {
uchar *ptr; char *save_cur_range_info= cur_range_info;
identical_key_it.init(&key_buffer); identical_key_it.init(&key_buffer);
last_identical_key_ptr= NULL; last_identical_key_ptr= NULL;
while ((ptr= identical_key_it.get_next(key_size_in_keybuf))) while (!identical_key_it.read_next())
{ {
if (is_mrr_assoc) if (key_tuple_cmp(this, key_in_buf, cur_index_tuple))
identical_key_it.get_next(sizeof(void*));
if (key_tuple_cmp(this, key_in_buf, ptr))
break; break;
last_identical_key_ptr= ptr; last_identical_key_ptr= cur_index_tuple;
} }
cur_range_info= save_cur_range_info;
if (last_identical_key_ptr) if (last_identical_key_ptr)
{ {
in_identical_keys_range= TRUE; in_identical_keys_range= TRUE;
...@@ -1086,9 +1124,6 @@ end: ...@@ -1086,9 +1124,6 @@ end:
int DsMrr_impl::dsmrr_next(char **range_info) int DsMrr_impl::dsmrr_next(char **range_info)
{ {
int res; int res;
uchar *cur_range_info= 0;
uchar *rowid;
uchar *range_id;
if (use_default_impl) if (use_default_impl)
return h->handler::multi_range_read_next(range_info); return h->handler::multi_range_read_next(range_info);
...@@ -1096,23 +1131,22 @@ int DsMrr_impl::dsmrr_next(char **range_info) ...@@ -1096,23 +1131,22 @@ int DsMrr_impl::dsmrr_next(char **range_info)
if (!do_rowid_fetch) if (!do_rowid_fetch)
return dsmrr_next_from_index(range_info); return dsmrr_next_from_index(range_info);
while (identical_rowid_ptr) while (last_identical_rowid)
{ {
/* /*
Current record (the one we've returned in previous call) was obtained Current record (the one we've returned in previous call) was obtained
from a rowid that matched multiple range_ids. Return this record again, from a rowid that matched multiple range_ids. Return this record again,
with next matching range_id. with next matching range_id.
*/ */
rowid= rowid_buffer.read(h->ref_length); bool bres= rowid_buffer.read();
DBUG_ASSERT(!bres);
if (is_mrr_assoc) if (is_mrr_assoc)
{ memcpy(range_info, rowids_range_id, sizeof(uchar*));
uchar *range_ptr= rowid_buffer.read(sizeof(uchar*));
memcpy(range_info, range_ptr, sizeof(uchar*));
}
if (rowid == identical_rowid_ptr) if (rowid == last_identical_rowid)
{ {
identical_rowid_ptr= NULL; /* reached the last of identical rowids */ last_identical_rowid= NULL; /* reached the last of identical rowids */
} }
if (!h2->mrr_funcs.skip_record || if (!h2->mrr_funcs.skip_record ||
...@@ -1157,20 +1191,18 @@ int DsMrr_impl::dsmrr_next(char **range_info) ...@@ -1157,20 +1191,18 @@ int DsMrr_impl::dsmrr_next(char **range_info)
} }
} }
last_identical_rowid= NULL;
/* Return eof if there are no rowids in the buffer after re-fill attempt */ /* Return eof if there are no rowids in the buffer after re-fill attempt */
if (rowid_buffer.is_empty()) if (rowid_buffer.read())
return HA_ERR_END_OF_FILE; return HA_ERR_END_OF_FILE;
rowid= rowid_buffer.read(h->ref_length);
identical_rowid_ptr= NULL;
if (is_mrr_assoc) if (is_mrr_assoc)
{ {
range_id= rowid_buffer.read(sizeof(uchar*)); memcpy(range_info, rowids_range_id, sizeof(uchar*));
memcpy(&cur_range_info, range_id, sizeof(uchar*)); memcpy(&cur_range_info, rowids_range_id, sizeof(uchar*));
memcpy(range_info, range_id, sizeof(uchar*));
} }
if (h2->mrr_funcs.skip_record && if (h2->mrr_funcs.skip_record &&
h2->mrr_funcs.skip_record(h2->mrr_iter, (char *) cur_range_info, rowid)) h2->mrr_funcs.skip_record(h2->mrr_iter, (char *) cur_range_info, rowid))
continue; continue;
...@@ -1187,21 +1219,18 @@ int DsMrr_impl::dsmrr_next(char **range_info) ...@@ -1187,21 +1219,18 @@ int DsMrr_impl::dsmrr_next(char **range_info)
*/ */
if (!res) if (!res)
{ {
uchar *cur_rowid= rowid;
/* /*
Note: this implies that SQL layer doesn't touch table->record[0] Note: this implies that SQL layer doesn't touch table->record[0]
between calls. between calls.
*/ */
uchar *ptr;
SimpleBuffer::PeekIterator identical_rowid_it; SimpleBuffer::PeekIterator identical_rowid_it;
identical_rowid_it.init(&rowid_buffer); identical_rowid_it.init(&rowid_buffer);
while ((ptr= identical_rowid_it.get_next(h->ref_length))) while (!identical_rowid_it.read_next()) // reads to (rowid, ...)
{ {
if (is_mrr_assoc) if (h2->cmp_ref(rowid, cur_rowid))
identical_rowid_it.get_next(sizeof(void*));
if (h2->cmp_ref(rowid, ptr))
break; break;
identical_rowid_ptr= ptr; last_identical_rowid= rowid;
} }
} }
return 0; return 0;
......
...@@ -61,20 +61,51 @@ class SimpleBuffer ...@@ -61,20 +61,51 @@ class SimpleBuffer
-1 <=> everthing is done from end to start instead. -1 <=> everthing is done from end to start instead.
*/ */
int direction; int direction;
/* Pointers to read data from */
uchar **write_ptr1;
size_t write_size1;
/* Same as above, but may be NULL */
uchar **write_ptr2;
size_t write_size2;
/* Pointers to write data to */
uchar **read_ptr1;
size_t read_size1;
/* Same as above, but may be NULL */
uchar **read_ptr2;
size_t read_size2;
public: public:
/* Set up writing*/
void setup_writing(uchar **data1, size_t len1,
uchar **data2, size_t len2);
void sort(qsort2_cmp cmp_func, void *cmp_func_arg);
/* Write-mode functions */ /* Write-mode functions */
void reset_for_writing(); void reset_for_writing();
void write(const uchar *data, size_t bytes); void write();
bool have_space_for(size_t bytes); bool have_space_for(size_t bytes);
private:
void write(const uchar *data, size_t bytes);
uchar *used_area() { return (direction == 1)? read_pos : write_pos; } uchar *used_area() { return (direction == 1)? read_pos : write_pos; }
size_t used_size(); size_t used_size();
public:
bool is_empty() { return used_size() == 0; } bool is_empty() { return used_size() == 0; }
/* Read-mode functions */ /* Read-mode functions */
void reset_for_reading(); void reset_for_reading();
// todo: join with setup-writing?
void setup_reading(uchar **data1, size_t len1,
uchar **data2, size_t len2);
bool read();
private:
uchar *read(size_t bytes); uchar *read(size_t bytes);
public:
bool have_data(size_t bytes); bool have_data(size_t bytes);
uchar *end_of_space(); uchar *end_of_space();
...@@ -135,7 +166,6 @@ public: ...@@ -135,7 +166,6 @@ public:
DBUG_ASSERT(0); /* Attempt to grow buffer in wrong direction */ DBUG_ASSERT(0); /* Attempt to grow buffer in wrong direction */
} }
//friend class PeekIterator;
class PeekIterator class PeekIterator
{ {
// if direction==1 : pointer to what to return next // if direction==1 : pointer to what to return next
...@@ -148,6 +178,26 @@ public: ...@@ -148,6 +178,26 @@ public:
sb= sb_arg; sb= sb_arg;
pos= sb->read_pos; pos= sb->read_pos;
} }
/*
If the buffer stores tuples, this call will return pointer to the first
component.
*/
bool read_next()
{
// Always read the first component first? (because we do inverted-writes
// if needed, so no measures need to be taken here).
uchar *res;
if ((res= get_next(sb->read_size1)))
{
*(sb->read_ptr1)= res;
if (sb->read_ptr2)
*sb->read_ptr2= get_next(sb->read_size2);
return FALSE;
}
return TRUE; /* EOF */
}
private:
/* Return pointer to next chunk of nbytes bytes and avance over it */ /* Return pointer to next chunk of nbytes bytes and avance over it */
uchar *get_next(size_t nbytes) uchar *get_next(size_t nbytes)
{ {
...@@ -170,6 +220,7 @@ public: ...@@ -170,6 +220,7 @@ public:
}; };
}; };
/* /*
DS-MRR implementation for one table. Create/use one object of this class for DS-MRR implementation for one table. Create/use one object of this class for
each ha_{myisam/innobase/etc} object. That object will be further referred to each ha_{myisam/innobase/etc} object. That object will be further referred to
...@@ -206,8 +257,6 @@ public: ...@@ -206,8 +257,6 @@ public:
scanning. scanning.
*/ */
class DsMrr_impl class DsMrr_impl
{ {
public: public:
...@@ -252,7 +301,16 @@ private: ...@@ -252,7 +301,16 @@ private:
/* Buffer to store rowids, or (rowid, range_id) pairs */ /* Buffer to store rowids, or (rowid, range_id) pairs */
SimpleBuffer rowid_buffer; SimpleBuffer rowid_buffer;
uchar *identical_rowid_ptr; /* Reads from rowid buffer go to here: */
uchar *rowid;
uchar *rowids_range_id;
/*
not-NULL: we're traversing a group of (rowid, range_id) pairs with
identical rowid values, and this is the pointer to the last one.
NULL: we're not in the group of indentical rowids.
*/
uchar *last_identical_rowid;
/* Identical keys */ /* Identical keys */
bool in_identical_keys_range; bool in_identical_keys_range;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment