From 189555f39a8a5edeb2ca4f780cee13c44144fa5c Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Mon, 20 Sep 2010 13:02:17 +0400 Subject: DS-MRR improvements: more code cleanup - better comments - rename variables to better reflect their meaning --- sql/multi_range_read.cc | 75 +++++++++--------- sql/multi_range_read.h | 197 +++++++++++++++++++++++++++++------------------- 2 files changed, 157 insertions(+), 115 deletions(-) diff --git a/sql/multi_range_read.cc b/sql/multi_range_read.cc index e86bd8470b7..083f18f86c8 100644 --- a/sql/multi_range_read.cc +++ b/sql/multi_range_read.cc @@ -400,17 +400,6 @@ void SimpleBuffer::reset_for_writing() write_pos= read_pos= end; } -void SimpleBuffer::reset_for_reading() -{ -/* -Do we need this at all? - if (direction == 1) - pos= start; - else - pos= end; -//end? -*/ -} uchar *SimpleBuffer::end_of_space() { @@ -478,15 +467,20 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs, use_key_pointers= test(mode & HA_MRR_MATERIALIZED_KEYS); } - do_rowid_fetch= FALSE; - doing_cpk_scan= check_cpk_scan(thd, h->inited == handler::INDEX? + do_rndpos_scan= FALSE; + bool doing_cpk_scan= check_cpk_scan(thd, h->inited == handler::INDEX? h->active_index: h2->active_index, mode); if (!doing_cpk_scan /* && !index_only_read */) { /* Will use rowid buffer to store/sort rowids, etc */ - do_rowid_fetch= TRUE; + do_rndpos_scan= TRUE; } - DBUG_ASSERT(do_sort_keys || do_rowid_fetch); + + /* + We should either sort keys, or do ordered rnd_pos scan, or both. If we + decide to do neither, we should have used default MRR implementation. + */ + DBUG_ASSERT(do_sort_keys || do_rndpos_scan); if (is_mrr_assoc) @@ -509,11 +503,11 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs, keyno= (h->inited == handler::INDEX)? h->active_index : h2->active_index; dsmrr_fill_key_buffer(); - if (dsmrr_eof && !do_rowid_fetch) + if (dsmrr_eof && !do_rndpos_scan) buf->end_of_used_area= key_buffer.end_of_space(); } - if (!do_rowid_fetch) + if (!do_rndpos_scan) { /* We have the keys and won't need to fetch rowids, as key lookup will be @@ -523,11 +517,6 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs, } rowid_buff_elem_size= h->ref_length + (is_mrr_assoc? sizeof(char*) : 0); - /* - 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 @@ -821,7 +810,7 @@ void DsMrr_impl::setup_buffer_sizes(key_range *sample_key) index_ranges_unique= test(key_info->flags & HA_NOSAME && key_info->key_parts == my_count_bits(sample_key->keypart_map)); - if (!do_rowid_fetch) + if (!do_rndpos_scan) { /* Give all space to key buffer. */ key_buffer.set_buffer_space(full_buf, full_buf_end, SimpleBuffer::FORWARD); @@ -908,7 +897,7 @@ void DsMrr_impl::dsmrr_fill_key_buffer() uchar *key_ptr; if (know_key_tuple_params) { - if (do_rowid_fetch && rowid_buffer.is_empty()) + if (do_rndpos_scan && rowid_buffer.is_empty()) { /* We're using two buffers and both of them are empty now. Restore the @@ -963,6 +952,18 @@ void DsMrr_impl::dsmrr_fill_key_buffer() } +/* + Take unused space from key buffer and give it to rowid buffer. +*/ + +void DsMrr_impl::reallocate_buffer_space() +{ + uchar *unused_start, *unused_end; + key_buffer.remove_unused_space(&unused_start, &unused_end); + rowid_buffer.grow(unused_start, unused_end); +} + + /* DS-MRR/CPK: multi_range_read_next() function @@ -993,7 +994,7 @@ int DsMrr_impl::dsmrr_next_from_index(char **range_info_arg) { int res; uchar *key_in_buf; - handler *file= do_rowid_fetch? h2: h; + handler *file= do_rndpos_scan? h2: h; bool res2; while (in_identical_keys_range) @@ -1068,7 +1069,7 @@ check_record: When rowid fetching is used, it controls all buffer refills. When we're on our own, try refilling our buffer. */ - if (!do_rowid_fetch) + if (!do_rndpos_scan) dsmrr_fill_key_buffer(); if (key_buffer.is_empty()) @@ -1078,17 +1079,13 @@ check_record: } } - if (do_rowid_fetch) - { - /* - At this point we're not using anything what we've read from key - buffer. Cut off unused key buffer space and give it to the rowid - buffer. - */ - uchar *unused_start, *unused_end; - key_buffer.remove_unused_space(&unused_start, &unused_end); - rowid_buffer.grow(unused_start, unused_end); - } + /* + At this point we're not using anything what we've read from key + buffer. Cut off unused key buffer space and give it to the rowid + buffer. + */ + if (do_rndpos_scan) + reallocate_buffer_space(); /* Get the next range to scan */ key_buffer.read(); // reads to (cur_index_tuple, cur_range_info) @@ -1147,7 +1144,7 @@ int DsMrr_impl::dsmrr_next(char **range_info) if (use_default_impl) return h->handler::multi_range_read_next(range_info); - if (!do_rowid_fetch) + if (!do_rndpos_scan) return dsmrr_next_from_index(range_info); while (last_identical_rowid) @@ -1421,7 +1418,7 @@ bool DsMrr_impl::choose_mrr_impl(uint keyno, ha_rows rows, uint *flags, bool res; THD *thd= current_thd; - doing_cpk_scan= check_cpk_scan(thd, keyno, *flags); + bool doing_cpk_scan= check_cpk_scan(thd, keyno, *flags); bool using_cpk= test(keyno == table->s->primary_key && h->primary_key_is_clustered()); if (thd->variables.optimizer_use_mrr == 2 || *flags & HA_MRR_INDEX_ONLY || diff --git a/sql/multi_range_read.h b/sql/multi_range_read.h index 21cc0a49d74..06809c22c5e 100644 --- a/sql/multi_range_read.h +++ b/sql/multi_range_read.h @@ -73,7 +73,9 @@ start | | end | | usused space user data - + + For reverse buffer, start/end have the same meaning, but reading and + writing is done from end to start. */ class SimpleBuffer @@ -134,7 +136,6 @@ public: /* Read-mode functions */ bool is_empty() { return used_size() == 0; } - void reset_for_reading(); void setup_reading(uchar **data1, size_t len1, uchar **data2, size_t len2); bool read(); @@ -209,23 +210,31 @@ public: */ class PeekIterator { + SimpleBuffer *buf; /* The buffer we're iterating over*/ /* - if sb->direction==1 : pointer to what to return next - if sb->direction==-1: pointer to the end of what is to be returned next + if buf->direction==FORWARD : pointer to what to return next + if buf->direction==BACKWARD : pointer to the end of what is to be + returned next */ uchar *pos; - SimpleBuffer *sb; - public: - void init(SimpleBuffer *sb_arg) + /* + Initialize the iterator. After intiialization, the first read_next() call + will read what buf_arg->read() would read. + */ + void init(SimpleBuffer *buf_arg) { - sb= sb_arg; - pos= sb->read_pos; + buf= buf_arg; + pos= buf->read_pos; } /* - If the buffer stores tuples, this call will return pointer to the first - component. + Read the next value. The calling convention is the same as buf->read() + has. + + RETURN + FALSE - Ok + TRUE - EOF, reached the end of the buffer */ bool read_next() { @@ -234,11 +243,11 @@ public: have written the second component first). */ uchar *res; - if ((res= get_next(sb->read_size1))) + if ((res= get_next(buf->read_size1))) { - *(sb->read_ptr1)= res; - if (sb->read_ptr2) - *sb->read_ptr2= get_next(sb->read_size2); + *(buf->read_ptr1)= res; + if (buf->read_ptr2) + *buf->read_ptr2= get_next(buf->read_size2); return FALSE; } return TRUE; /* EOF */ @@ -247,9 +256,9 @@ public: /* Return pointer to next chunk of nbytes bytes and avance over it */ uchar *get_next(size_t nbytes) { - if (sb->direction == 1) + if (buf->direction == 1) { - if (pos + nbytes > sb->write_pos) + if (pos + nbytes > buf->write_pos) return NULL; uchar *res= pos; pos += nbytes; @@ -257,7 +266,7 @@ public: } else { - if (pos - nbytes < sb->write_pos) + if (pos - nbytes < buf->write_pos) return NULL; pos -= nbytes; return pos; @@ -288,6 +297,8 @@ private: S2. Sort Keys S3. Sort Rowids + psergey-TODO. + S1 is used for cases which DS-MRR is unable to handle for some reason. S2 is the actual DS-MRR. The basic algorithm is as follows: @@ -339,75 +350,78 @@ public: uint *flags, COST_VECT *cost); private: /* - The "owner" handler object (the one that calls dsmrr_XXX functions. - It is used to retrieve full table rows by calling rnd_pos(). + The "owner" handler object (the one that is expected to "own" this object + and call its functions). */ handler *h; TABLE *table; /* Always equal to h->table */ /* - Secondary handler object, if needed (we need it when we need to both scan - the index and return rows). + Secondary handler object. (created when needed, we need it when we need + to run both index scan and rnd_pos() at the same time) */ handler *h2; - /* Full buffer that we're using (the buffer is obtained from SQL layer) */ + /** Properties of current MRR scan **/ + + uint keyno; /* index we're running the scan on */ + bool use_default_impl; /* TRUE <=> shortcut all calls to default MRR impl */ + /* TRUE <=> need range association, buffers hold {rowid, range_id} pairs */ + bool is_mrr_assoc; + /* TRUE <=> sort the keys before making index lookups */ + bool do_sort_keys; + /* TRUE <=> sort rowids and use rnd_pos() to get and return full records */ + bool do_rndpos_scan; + + /* + (if do_sort_keys==TRUE) don't copy key values, use pointers to them + instead. + */ + bool use_key_pointers; + + + /* The whole buffer space that we're using */ uchar *full_buf; uchar *full_buf_end; - /* Valid when using both rowid and key buffer: the original bound between them */ + /* + When using both rowid and key buffers: the bound between key and rowid + parts of the buffer. This is the "original" value, actual memory ranges + used by key and rowid parts may be different because of dynamic space + reallocation between them. + */ uchar *rowid_buffer_end; + - /* Buffer to store rowids, or (rowid, range_id) pairs */ - SimpleBuffer rowid_buffer; - - /* 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; + /** Index scaning and key buffer-related members **/ - /* Identical keys */ - bool in_identical_keys_range; - uchar *last_identical_key_ptr; - SimpleBuffer::PeekIterator identical_key_it; + /* TRUE <=> We can get at most one index tuple for a lookup key */ + bool index_ranges_unique; - SimpleBuffer key_buffer; + /* TRUE<=> we're in a middle of enumerating records for a key range */ + bool in_index_range; - uint keyno; + /* Buffer to store (key, range_id) pairs */ + SimpleBuffer key_buffer; + + /* key_buffer.read() reads */ + uchar *cur_index_tuple; - /* Execution control */ - bool do_sort_keys; - bool use_key_pointers; - bool do_rowid_fetch; + /* if in_index_range==TRUE: range_id of the range we're enumerating */ + char *cur_range_info; - bool dsmrr_eof; /* TRUE <=> We have reached EOF when reading index tuples */ - /* - TRUE <=> key buffer is exhausted (we need this because we may have a situation - where we've read everything from the key buffer but haven't finished with - scanning the last range) + TRUE <=> we've got index tuples/rowids for all keys (need this flag because + we may have a situation where we've read everything from the key buffer but + haven't finished with getting index tuples for the last key) */ bool key_eof; - /* TRUE <=> need range association, buffer holds {rowid, range_id} pairs */ - bool is_mrr_assoc; - - bool use_default_impl; /* TRUE <=> shortcut all calls to default MRR impl */ - - bool doing_cpk_scan; /* TRUE <=> DS-MRR/CPK variant is used */ - - /* Initially FALSE, becomes TRUE when we've set key_tuple_xxx members */ bool know_key_tuple_params; - /* Length of lookup tuple being used, in bytes */ - uint key_tuple_length; - key_part_map key_tuple_map; + uint key_tuple_length; /* Length of index lookup tuple, in bytes */ + key_part_map key_tuple_map; /* keyparts used in index lookup tuples */ + /* This is = key_tuple_length if we copy keys to buffer @@ -418,23 +432,52 @@ private: /* = key_size_in_keybuf [ + sizeof(range_assoc_info) ] */ uint key_buff_elem_size; - /* = h->ref_length [ + sizeof(range_assoc_info) ] */ - uint rowid_buff_elem_size; - - /* - TRUE <=> We're scanning on a full primary key (and not on prefix), and so - can get max. one match for each key + /* + TRUE <=> we're doing key-ordered index scan and right now several + subsequent key values are the same as the one we've already retrieved and + returned index tuple for. */ - bool index_ranges_unique; - /* TRUE<=> we're in a middle of enumerating records from a range */ - bool in_index_range; - uchar *cur_index_tuple; - - /* if in_index_range==TRUE: range_id of the range we're enumerating */ - char *cur_range_info; + bool in_identical_keys_range; + /* range_id of the first of the identical keys */ char *first_identical_range_info; + /* Pointer to the last of the identical key values */ + uchar *last_identical_key_ptr; + + /* + key_buffer iterator for walking the identical key range (we need to + enumerate the set of (identical_key, range_id) pairs multiple times, + and do that by walking from current buffer read position until we get + last_identical_key_ptr. + */ + SimpleBuffer::PeekIterator identical_key_it; + + + /** rnd_pos() scan and rowid buffer-related members **/ + + /* + Buffer to store (rowid, range_id) pairs, or just rowids if + is_mrr_assoc==FALSE + */ + SimpleBuffer rowid_buffer; + + /* rowid_buffer.read() will set the following: */ + 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; + + bool dsmrr_eof; /* TRUE <=> We have reached EOF when reading index tuples */ + + /* = h->ref_length [ + sizeof(range_assoc_info) ] */ + uint rowid_buff_elem_size; + bool choose_mrr_impl(uint keyno, ha_rows rows, uint *flags, uint *bufsz, COST_VECT *cost); bool get_disk_sweep_mrr_cost(uint keynr, ha_rows rows, uint flags, @@ -446,8 +489,10 @@ private: int dsmrr_next_from_index(char **range_info); void setup_buffer_sizes(key_range *sample_key); + void reallocate_buffer_space(); static range_seq_t key_buf_seq_init(void *init_param, uint n_ranges, uint flags); static uint key_buf_seq_next(range_seq_t rseq, KEY_MULTI_RANGE *range); }; + -- cgit v1.2.1