Better comments, move Lifo_buffer to separate file.
This commit is contained in:
parent
3066c37718
commit
4f56acb676
@ -63,6 +63,7 @@ SET (SQL_SOURCE
|
|||||||
sql_cache.cc sql_class.cc sql_client.cc sql_crypt.cc sql_crypt.h
|
sql_cache.cc sql_class.cc sql_client.cc sql_crypt.cc sql_crypt.h
|
||||||
sql_cursor.cc sql_db.cc sql_delete.cc sql_derived.cc sql_do.cc
|
sql_cursor.cc sql_db.cc sql_delete.cc sql_derived.cc sql_do.cc
|
||||||
sql_error.cc sql_handler.cc sql_help.cc sql_insert.cc
|
sql_error.cc sql_handler.cc sql_help.cc sql_insert.cc
|
||||||
|
sql_lifo_buffer.h
|
||||||
sql_join_cache.cc sql_lex.cc sql_list.cc sql_load.cc sql_manager.cc
|
sql_join_cache.cc sql_lex.cc sql_list.cc sql_load.cc sql_manager.cc
|
||||||
sql_map.cc sql_parse.cc sql_partition.cc sql_plugin.cc
|
sql_map.cc sql_parse.cc sql_partition.cc sql_plugin.cc
|
||||||
sql_prepare.cc sql_rename.cc
|
sql_prepare.cc sql_rename.cc
|
||||||
|
@ -66,6 +66,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
|
|||||||
log.h log_slow.h sql_show.h rpl_rli.h rpl_mi.h \
|
log.h log_slow.h sql_show.h rpl_rli.h rpl_mi.h \
|
||||||
sql_select.h structs.h table.h sql_udf.h hash_filo.h \
|
sql_select.h structs.h table.h sql_udf.h hash_filo.h \
|
||||||
lex.h lex_symbol.h sql_acl.h sql_crypt.h \
|
lex.h lex_symbol.h sql_acl.h sql_crypt.h \
|
||||||
|
sql_lifo_buffer.h \
|
||||||
sql_repl.h slave.h rpl_filter.h rpl_injector.h \
|
sql_repl.h slave.h rpl_filter.h rpl_injector.h \
|
||||||
log_event.h rpl_record.h \
|
log_event.h rpl_record.h \
|
||||||
log_event_old.h rpl_record_old.h \
|
log_event_old.h rpl_record_old.h \
|
||||||
|
@ -1326,6 +1326,10 @@ void get_sweep_read_cost(TABLE *table, ha_rows nrows, bool interrupted,
|
|||||||
The MRR user has materialized range keys somewhere in the user's buffer.
|
The MRR user has materialized range keys somewhere in the user's buffer.
|
||||||
This can be used for optimization of the procedure that sorts these keys
|
This can be used for optimization of the procedure that sorts these keys
|
||||||
since in this case key values don't have to be copied into the MRR buffer.
|
since in this case key values don't have to be copied into the MRR buffer.
|
||||||
|
|
||||||
|
In other words, it is guaranteed that after RANGE_SEQ_IF::next() call the
|
||||||
|
pointer in range->start_key.key will point to a key value that will remain
|
||||||
|
there until the end of the MRR scan.
|
||||||
*/
|
*/
|
||||||
#define HA_MRR_MATERIALIZED_KEYS 256
|
#define HA_MRR_MATERIALIZED_KEYS 256
|
||||||
|
|
||||||
|
@ -332,7 +332,7 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
|
|||||||
is_mrr_assoc= !test(mode & HA_MRR_NO_ASSOCIATION);
|
is_mrr_assoc= !test(mode & HA_MRR_NO_ASSOCIATION);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Figure out what steps we'll need to do
|
Determine whether we'll need to do key sorting and/or rnd_pos() scan
|
||||||
*/
|
*/
|
||||||
do_sort_keys= FALSE;
|
do_sort_keys= FALSE;
|
||||||
if ((mode & HA_MRR_SINGLE_POINT) &&
|
if ((mode & HA_MRR_SINGLE_POINT) &&
|
||||||
@ -362,8 +362,9 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
|
|||||||
status_var_increment(table->in_use->status_var.ha_multi_range_read_init_count);
|
status_var_increment(table->in_use->status_var.ha_multi_range_read_init_count);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
At start, alloc all of the buffer for rowids. Key sorting code will grab a
|
At start, alloc all of the buffer for rowids. When/if key sorting code
|
||||||
piece if necessary.
|
figures how much buffer space it needs, it will call setup_buffer_sizes()
|
||||||
|
to re-distribute the buffer space.
|
||||||
*/
|
*/
|
||||||
full_buf= buf->buffer;
|
full_buf= buf->buffer;
|
||||||
full_buf_end= buf->buffer_end;
|
full_buf_end= buf->buffer_end;
|
||||||
@ -530,22 +531,19 @@ static int rowid_cmp_reverse(void *h, uchar *a, uchar *b)
|
|||||||
/**
|
/**
|
||||||
DS-MRR: Fill and sort the rowid buffer
|
DS-MRR: Fill and sort the rowid buffer
|
||||||
|
|
||||||
{This is an internal function of DiskSweep MRR implementation}
|
|
||||||
|
|
||||||
Scan the MRR ranges and collect ROWIDs (or {ROWID, range_id} pairs) into
|
Scan the MRR ranges and collect ROWIDs (or {ROWID, range_id} pairs) into
|
||||||
buffer. When the buffer is full or scan is completed, sort the buffer by
|
buffer. When the buffer is full or scan is completed, sort the buffer by
|
||||||
rowid and return.
|
rowid and return.
|
||||||
|
|
||||||
|
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
|
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.
|
scanning. This function never returns HA_ERR_END_OF_FILE.
|
||||||
|
|
||||||
post-condition:
|
|
||||||
rowid buffer is not empty, or key source is exhausted.
|
|
||||||
|
|
||||||
@retval 0 OK, the next portion of rowids is in the buffer,
|
@retval 0 OK, the next portion of rowids is in the buffer,
|
||||||
properly ordered
|
properly ordered
|
||||||
@retval other Error
|
@retval other Error
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int DsMrr_impl::dsmrr_fill_rowid_buffer()
|
int DsMrr_impl::dsmrr_fill_rowid_buffer()
|
||||||
@ -556,15 +554,13 @@ int DsMrr_impl::dsmrr_fill_rowid_buffer()
|
|||||||
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();
|
||||||
rowid_buffer.setup_writing(&h2->ref, h2->ref_length,
|
rowid_buffer.setup_writing(&h2->ref, h2->ref_length,
|
||||||
is_mrr_assoc? (uchar**)&range_info_ptr: NULL, sizeof(void*));
|
is_mrr_assoc? (uchar**)&range_info_ptr: NULL,
|
||||||
|
sizeof(void*));
|
||||||
|
|
||||||
last_identical_rowid= NULL;
|
last_identical_rowid= NULL;
|
||||||
|
|
||||||
//if (do_sort_keys && key_buffer.is_reverse())
|
|
||||||
// key_buffer.flip();
|
|
||||||
|
|
||||||
while (rowid_buffer.can_write())
|
while (rowid_buffer.can_write())
|
||||||
{
|
{
|
||||||
if (do_sort_keys)
|
if (do_sort_keys)
|
||||||
@ -652,18 +648,21 @@ equals:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int DsMrr_impl::key_tuple_cmp_reverse(void* arg, uchar* key1, uchar* key2)
|
int DsMrr_impl::key_tuple_cmp_reverse(void* arg, uchar* key1, uchar* key2)
|
||||||
{
|
{
|
||||||
return -key_tuple_cmp(arg, key1, key2);
|
return -key_tuple_cmp(arg, key1, key2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Setup key/rowid buffer sizes based on sample_key
|
|
||||||
|
|
||||||
DESCRIPTION
|
/**
|
||||||
Setup key/rowid buffer sizes based on sample_key and its length.
|
Setup key/rowid buffer sizes based on sample_key and its length.
|
||||||
|
|
||||||
This function must be called when all buffer space is empty.
|
@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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void DsMrr_impl::setup_buffer_sizes(key_range *sample_key)
|
void DsMrr_impl::setup_buffer_sizes(key_range *sample_key)
|
||||||
@ -737,22 +736,19 @@ void DsMrr_impl::setup_buffer_sizes(key_range *sample_key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/**
|
||||||
DS-MRR/CPK: Fill the buffer with (lookup_tuple, range_id) pairs and sort
|
DS-MRR/CPK: Fill the buffer with (lookup_tuple, range_id) pairs and sort
|
||||||
|
|
||||||
SYNOPSIS
|
Enumerate the input range (=key) sequence, fill the key buffer with
|
||||||
DsMrr_impl::dsmrr_fill_key_buffer()
|
(lookup_key, range_id) pairs and sort it.
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
DS-MRR/CPK: Enumerate the input range (=key) sequence, fill the key buffer
|
|
||||||
(lookup_key, range_id) pairs and sort.
|
|
||||||
|
|
||||||
|
When this function returns, either
|
||||||
|
- key buffer is non-empty, or
|
||||||
|
- key buffer is empty and source range sequence is exhausted
|
||||||
|
|
||||||
|
@note
|
||||||
dsmrr_eof is set to indicate whether we've exhausted the list of ranges
|
dsmrr_eof is set to indicate whether we've exhausted the list of ranges
|
||||||
we're scanning.
|
we're scanning.
|
||||||
|
|
||||||
post-condition:
|
|
||||||
- key buffer is non-empty
|
|
||||||
- key buffer is empty and source range sequence is exhausted
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void DsMrr_impl::dsmrr_fill_key_buffer()
|
void DsMrr_impl::dsmrr_fill_key_buffer()
|
||||||
@ -778,7 +774,7 @@ void DsMrr_impl::dsmrr_fill_key_buffer()
|
|||||||
identical_key_it= &backward_key_it;
|
identical_key_it= &backward_key_it;
|
||||||
key_buffer->set_buffer_space(rowid_buffer_end, full_buf_end);
|
key_buffer->set_buffer_space(rowid_buffer_end, full_buf_end);
|
||||||
}
|
}
|
||||||
key_buffer->reset_for_writing();
|
key_buffer->reset();
|
||||||
key_buffer->setup_writing(&key_ptr, key_size_in_keybuf,
|
key_buffer->setup_writing(&key_ptr, key_size_in_keybuf,
|
||||||
is_mrr_assoc? (uchar**)&range_info_ptr : NULL,
|
is_mrr_assoc? (uchar**)&range_info_ptr : NULL,
|
||||||
sizeof(uchar*));
|
sizeof(uchar*));
|
||||||
@ -825,8 +821,8 @@ void DsMrr_impl::dsmrr_fill_key_buffer()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/**
|
||||||
Take unused space from key buffer and give it to rowid buffer.
|
Take unused space from the key buffer and give it to the rowid buffer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void DsMrr_impl::reallocate_buffer_space()
|
void DsMrr_impl::reallocate_buffer_space()
|
||||||
@ -837,30 +833,25 @@ void DsMrr_impl::reallocate_buffer_space()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/**
|
||||||
DS-MRR/CPK: multi_range_read_next() function
|
DS-MRR/CPK: multi_range_read_next() function
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
DsMrr_impl::dsmrr_next_from_index()
|
|
||||||
range_info OUT identifier of range that the returned record belongs to
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
|
|
||||||
This function walks over key buffer and does index reads, i.e. it produces
|
@param range_info OUT identifier of range that the returned record belongs to
|
||||||
{current_record, range_id} pairs.
|
|
||||||
|
|
||||||
The function has the same call contract like multi_range_read_next()'s.
|
|
||||||
|
|
||||||
We actually iterate nested sequences:
|
|
||||||
|
|
||||||
- a disjoint sequence of index ranges
|
@note
|
||||||
- each range has multiple records
|
This function walks over key buffer and does index reads, i.e. it produces
|
||||||
- each record goes into multiple identical ranges.
|
{current_record, range_id} pairs.
|
||||||
|
|
||||||
RETURN
|
The function has the same call contract like multi_range_read_next()'s.
|
||||||
0 OK, next record was successfully read
|
|
||||||
HA_ERR_END_OF_FILE End of records
|
We actually iterate over nested sequences:
|
||||||
Other Some other error
|
- a disjoint sequence of index ranges
|
||||||
|
- each range has multiple records
|
||||||
|
- each record goes into multiple identical ranges.
|
||||||
|
|
||||||
|
@retval 0 OK, next record was successfully read
|
||||||
|
@retval HA_ERR_END_OF_FILE End of records
|
||||||
|
@retval Other Some other error
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int DsMrr_impl::dsmrr_next_from_index(char **range_info_arg)
|
int DsMrr_impl::dsmrr_next_from_index(char **range_info_arg)
|
||||||
@ -1007,7 +998,9 @@ end:
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
DS-MRR implementation: multi_range_read_next() function
|
DS-MRR implementation: multi_range_read_next() function.
|
||||||
|
|
||||||
|
Calling convention is like multi_range_read_next() has.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int DsMrr_impl::dsmrr_next(char **range_info)
|
int DsMrr_impl::dsmrr_next(char **range_info)
|
||||||
@ -1237,17 +1230,12 @@ bool key_uses_partial_cols(TABLE *table, uint keyno)
|
|||||||
/*
|
/*
|
||||||
Check if key/flags allow DS-MRR/CPK strategy to be used
|
Check if key/flags allow DS-MRR/CPK strategy to be used
|
||||||
|
|
||||||
SYNOPSIS
|
@param thd
|
||||||
DsMrr_impl::check_cpk_scan()
|
@param keyno Index that will be used
|
||||||
keyno Index that will be used
|
@param mrr_flags
|
||||||
mrr_flags
|
|
||||||
|
|
||||||
DESCRIPTION
|
@retval TRUE DS-MRR/CPK should be used
|
||||||
Check if key/flags allow DS-MRR/CPK strategy to be used.
|
@retval FALSE Otherwise
|
||||||
|
|
||||||
RETURN
|
|
||||||
TRUE DS-MRR/CPK should be used
|
|
||||||
FALSE Otherwise
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool DsMrr_impl::check_cpk_scan(THD *thd, uint keyno, uint mrr_flags)
|
bool DsMrr_impl::check_cpk_scan(THD *thd, uint keyno, uint mrr_flags)
|
||||||
@ -1413,17 +1401,14 @@ bool DsMrr_impl::get_disk_sweep_mrr_cost(uint keynr, ha_rows rows, uint flags,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
Get cost of one sort-and-sweep step
|
Get cost of one sort-and-sweep step
|
||||||
|
|
||||||
|
It consists of two parts:
|
||||||
|
- sort an array of #nrows ROWIDs using qsort
|
||||||
|
- read #nrows records from table in a sweep.
|
||||||
|
|
||||||
SYNOPSIS
|
@param table Table being accessed
|
||||||
get_sort_and_sweep_cost()
|
@param nrows Number of rows to be sorted and retrieved
|
||||||
table Table being accessed
|
@param cost OUT The cost of scan
|
||||||
nrows Number of rows to be sorted and retrieved
|
|
||||||
cost OUT The cost
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
Get cost of these operations:
|
|
||||||
- sort an array of #nrows ROWIDs using qsort
|
|
||||||
- read #nrows records from table in a sweep.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static
|
static
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/**
|
||||||
This file contains declarations for Disk-Sweep MultiRangeRead (DS-MRR)
|
@defgroup DS-MRR declarations
|
||||||
implementation
|
@{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,387 +46,7 @@
|
|||||||
storage and has better performance when reading data in rowid order.
|
storage and has better performance when reading data in rowid order.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class Forward_lifo_buffer;
|
#include "sql_lifo_buffer.h"
|
||||||
class Backward_lifo_buffer;
|
|
||||||
|
|
||||||
class Lifo_buffer
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
/*
|
|
||||||
Data to be written. write() call will assume that (*write_ptr1) points to
|
|
||||||
size1 bytes of data to be written.
|
|
||||||
If write_ptr2 != NULL then the buffer stores pairs, and (*write_ptr2)
|
|
||||||
points to size2 bytes of data that form the second component.
|
|
||||||
*/
|
|
||||||
uchar **write_ptr1;
|
|
||||||
size_t size1;
|
|
||||||
uchar **write_ptr2;
|
|
||||||
size_t size2;
|
|
||||||
|
|
||||||
/*
|
|
||||||
read() will do reading by storing pointer to read data into *read_ptr1 (if
|
|
||||||
the buffer stores atomic elements), or into {*read_ptr1, *read_ptr2} (if
|
|
||||||
the buffer stores pairs).
|
|
||||||
*/
|
|
||||||
uchar **read_ptr1;
|
|
||||||
uchar **read_ptr2;
|
|
||||||
|
|
||||||
uchar *start; /* points to start of buffer space */
|
|
||||||
uchar *end; /* points to just beyond the end of buffer space */
|
|
||||||
public:
|
|
||||||
|
|
||||||
enum enum_direction {
|
|
||||||
BACKWARD=-1, /* buffer is filled/read from bigger to smaller memory addresses */
|
|
||||||
FORWARD=1 /* buffer is filled/read from smaller to bigger memory addresses */
|
|
||||||
};
|
|
||||||
|
|
||||||
virtual enum_direction type() = 0;
|
|
||||||
|
|
||||||
/* Buffer space control functions */
|
|
||||||
void set_buffer_space(uchar *start_arg, uchar *end_arg)
|
|
||||||
{
|
|
||||||
start= start_arg;
|
|
||||||
end= end_arg;
|
|
||||||
TRASH(start, end - start);
|
|
||||||
reset_for_writing();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setup_writing(uchar **data1, size_t len1, uchar **data2, size_t len2)
|
|
||||||
{
|
|
||||||
write_ptr1= data1;
|
|
||||||
size1= len1;
|
|
||||||
write_ptr2= data2;
|
|
||||||
size2= len2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setup_reading(uchar **data1, size_t len1, uchar **data2, size_t len2)
|
|
||||||
{
|
|
||||||
read_ptr1= data1;
|
|
||||||
DBUG_ASSERT(len1 == size1);
|
|
||||||
read_ptr2= data2;
|
|
||||||
DBUG_ASSERT(len2 == size2);
|
|
||||||
}
|
|
||||||
|
|
||||||
//virtual void write_bytes(const uchar *data, size_t bytes)=0;
|
|
||||||
|
|
||||||
virtual bool read() = 0;
|
|
||||||
virtual void write() = 0;
|
|
||||||
bool can_write()
|
|
||||||
{
|
|
||||||
return have_space_for(size1 + (write_ptr2 ? size2 : 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_empty() { return used_size() == 0; }
|
|
||||||
virtual size_t used_size() = 0;
|
|
||||||
|
|
||||||
void sort(qsort2_cmp cmp_func, void *cmp_func_arg)
|
|
||||||
{
|
|
||||||
uint elem_size= size1 + (write_ptr2 ? size2 : 0);
|
|
||||||
uint n_elements= used_size() / elem_size;
|
|
||||||
my_qsort2(used_area(), n_elements, elem_size, cmp_func, cmp_func_arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
virtual void reset_for_writing() = 0;
|
|
||||||
virtual uchar *end_of_space() = 0;
|
|
||||||
bool have_data(size_t bytes)
|
|
||||||
{
|
|
||||||
return (used_size() >= bytes);
|
|
||||||
}
|
|
||||||
virtual bool have_space_for(size_t bytes) = 0;
|
|
||||||
//virtual uchar *read_bytes(size_t bytes) = 0;
|
|
||||||
|
|
||||||
virtual void remove_unused_space(uchar **unused_start, uchar **unused_end)=0;
|
|
||||||
virtual uchar *used_area() = 0;
|
|
||||||
|
|
||||||
class Iterator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual void init(Lifo_buffer *buf) = 0;
|
|
||||||
/*
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
virtual bool read_next()= 0;
|
|
||||||
virtual ~Iterator() {}
|
|
||||||
protected:
|
|
||||||
Lifo_buffer *buf;
|
|
||||||
virtual uchar *get_next(size_t nbytes)=0;
|
|
||||||
};
|
|
||||||
virtual ~Lifo_buffer() {};
|
|
||||||
|
|
||||||
friend class Forward_iterator;
|
|
||||||
friend class Backward_iterator;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Forward_lifo_buffer: public Lifo_buffer
|
|
||||||
{
|
|
||||||
uchar *pos;
|
|
||||||
public:
|
|
||||||
enum_direction type() { return FORWARD; }
|
|
||||||
size_t used_size()
|
|
||||||
{
|
|
||||||
return pos - start;
|
|
||||||
}
|
|
||||||
void reset_for_writing()
|
|
||||||
{
|
|
||||||
pos= start;
|
|
||||||
}
|
|
||||||
uchar *end_of_space() { return pos; }
|
|
||||||
bool have_space_for(size_t bytes)
|
|
||||||
{
|
|
||||||
return (pos + bytes < end);
|
|
||||||
}
|
|
||||||
|
|
||||||
void write()
|
|
||||||
{
|
|
||||||
write_bytes(*write_ptr1, size1);
|
|
||||||
if (write_ptr2)
|
|
||||||
write_bytes(*write_ptr2, size2);
|
|
||||||
}
|
|
||||||
void write_bytes(const uchar *data, size_t bytes)
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(have_space_for(bytes));
|
|
||||||
memcpy(pos, data, bytes);
|
|
||||||
pos += bytes;
|
|
||||||
}
|
|
||||||
uchar *read_bytes(size_t bytes)
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(have_data(bytes));
|
|
||||||
pos= pos - bytes;
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
bool read()
|
|
||||||
{
|
|
||||||
if (!have_data(size1 + (read_ptr2 ? size2 : 0)))
|
|
||||||
return TRUE;
|
|
||||||
if (read_ptr2)
|
|
||||||
*read_ptr2= read_bytes(size2);
|
|
||||||
*read_ptr1= read_bytes(size1);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
Stop using/return the unneded space (the one that we have already wrote
|
|
||||||
to read from).
|
|
||||||
*/
|
|
||||||
void remove_unused_space(uchar **unused_start, uchar **unused_end)
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(0); /* Don't need this yet */
|
|
||||||
}
|
|
||||||
void grow(uchar *unused_start, uchar *unused_end)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
Passed memory area can be meaningfully used for growing the buffer if:
|
|
||||||
- it is adjacent to buffer space we're using
|
|
||||||
- it is on the end towards which we grow.
|
|
||||||
*/
|
|
||||||
DBUG_ASSERT(unused_end >= unused_start);
|
|
||||||
TRASH(unused_start, unused_end - unused_start);
|
|
||||||
DBUG_ASSERT(end == unused_start);
|
|
||||||
end= unused_end;
|
|
||||||
}
|
|
||||||
/* Return pointer to start of the memory area that is occupied by the data */
|
|
||||||
uchar *used_area() { return start; }
|
|
||||||
friend class Forward_iterator;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Forward_iterator : public Lifo_buffer::Iterator
|
|
||||||
{
|
|
||||||
uchar *pos;
|
|
||||||
|
|
||||||
/* Return pointer to next chunk of nbytes bytes and avance over it */
|
|
||||||
uchar *get_next(size_t nbytes)
|
|
||||||
{
|
|
||||||
if (pos - nbytes < ((Forward_lifo_buffer*)buf)->start)
|
|
||||||
return NULL;
|
|
||||||
pos -= nbytes;
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
bool read_next()
|
|
||||||
{
|
|
||||||
uchar *res;
|
|
||||||
if (buf->read_ptr2)
|
|
||||||
{
|
|
||||||
if ((res= get_next(buf->size2)))
|
|
||||||
{
|
|
||||||
*(buf->read_ptr2)= res;
|
|
||||||
*buf->read_ptr1= get_next(buf->size1);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ((res= get_next(buf->size1)))
|
|
||||||
{
|
|
||||||
*(buf->read_ptr1)= res;
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return TRUE; /* EOF */
|
|
||||||
}
|
|
||||||
|
|
||||||
void init(Lifo_buffer *buf_arg)
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(buf_arg->type() == Lifo_buffer::FORWARD);
|
|
||||||
buf= buf_arg;
|
|
||||||
pos= ((Forward_lifo_buffer*)buf)->pos;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Backward_lifo_buffer: public Lifo_buffer
|
|
||||||
{
|
|
||||||
uchar *pos;
|
|
||||||
public:
|
|
||||||
enum_direction type() { return BACKWARD; }
|
|
||||||
|
|
||||||
size_t used_size()
|
|
||||||
{
|
|
||||||
return end - pos;
|
|
||||||
}
|
|
||||||
void reset_for_writing()
|
|
||||||
{
|
|
||||||
pos= end;
|
|
||||||
}
|
|
||||||
uchar *end_of_space() { return end; }
|
|
||||||
bool have_space_for(size_t bytes)
|
|
||||||
{
|
|
||||||
return (pos - bytes >= start);
|
|
||||||
}
|
|
||||||
void write()
|
|
||||||
{
|
|
||||||
if (write_ptr2)
|
|
||||||
write_bytes(*write_ptr2, size2);
|
|
||||||
write_bytes(*write_ptr1, size1);
|
|
||||||
}
|
|
||||||
void write_bytes(const uchar *data, size_t bytes)
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(have_space_for(bytes));
|
|
||||||
pos -= bytes;
|
|
||||||
memcpy(pos, data, bytes);
|
|
||||||
}
|
|
||||||
bool read()
|
|
||||||
{
|
|
||||||
if (!have_data(size1 + (read_ptr2 ? size2 : 0)))
|
|
||||||
return TRUE;
|
|
||||||
*read_ptr1= read_bytes(size1);
|
|
||||||
if (read_ptr2)
|
|
||||||
*read_ptr2= read_bytes(size2);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
uchar *read_bytes(size_t bytes)
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(have_data(bytes));
|
|
||||||
uchar *ret= pos;
|
|
||||||
pos= pos + bytes;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
Stop using/return the unneded space (the one that we have already wrote
|
|
||||||
to and have read from).
|
|
||||||
*/
|
|
||||||
void remove_unused_space(uchar **unused_start, uchar **unused_end)
|
|
||||||
{
|
|
||||||
*unused_start= start;
|
|
||||||
*unused_end= pos;
|
|
||||||
start= pos;
|
|
||||||
}
|
|
||||||
void grow(uchar *unused_start, uchar *unused_end)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
Passed memory area can be meaningfully used for growing the buffer if:
|
|
||||||
- it is adjacent to buffer space we're using
|
|
||||||
- it is on the end towards which we grow.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
DBUG_ASSERT(unused_end >= unused_start);
|
|
||||||
TRASH(unused_start, unused_end - unused_start);
|
|
||||||
DBUG_ASSERT(start == unused_end);
|
|
||||||
start= unused_start;
|
|
||||||
*/
|
|
||||||
DBUG_ASSERT(0); //Not used
|
|
||||||
}
|
|
||||||
/* Return pointer to start of the memory area that is occupied by the data */
|
|
||||||
uchar *used_area() { return pos; }
|
|
||||||
friend class Backward_iterator;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Backward_iterator : public Lifo_buffer::Iterator
|
|
||||||
{
|
|
||||||
uchar *pos;
|
|
||||||
/* Return pointer to next chunk of nbytes bytes and advance over it */
|
|
||||||
uchar *get_next(size_t nbytes)
|
|
||||||
{
|
|
||||||
if (pos + nbytes > ((Backward_lifo_buffer*)buf)->end)
|
|
||||||
return NULL;
|
|
||||||
uchar *res= pos;
|
|
||||||
pos += nbytes;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
bool read_next()
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
Always read the first component first (if the buffer is backwards, we
|
|
||||||
have written the second component first).
|
|
||||||
*/
|
|
||||||
uchar *res;
|
|
||||||
if ((res= get_next(buf->size1)))
|
|
||||||
{
|
|
||||||
*(buf->read_ptr1)= res;
|
|
||||||
if (buf->read_ptr2)
|
|
||||||
*buf->read_ptr2= get_next(buf->size2);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
return TRUE; /* EOF */
|
|
||||||
}
|
|
||||||
void init(Lifo_buffer *buf_arg)
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(buf_arg->type() == Lifo_buffer::BACKWARD);
|
|
||||||
buf= buf_arg;
|
|
||||||
pos= ((Backward_lifo_buffer*)buf)->pos;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
An in-memory buffer used by DS-MRR implementation.
|
|
||||||
- The buffer contains fixed-size elements. The elements are either atomic
|
|
||||||
byte sequences or pairs.
|
|
||||||
- The buffer resides in memory provided by the user. It is possible to
|
|
||||||
= dynamically (ie. between write operations) add ajacent memory space to
|
|
||||||
the buffer
|
|
||||||
= dynamically remove unused space from the buffer.
|
|
||||||
- Buffer can be set to be either "forward" or "backward".
|
|
||||||
|
|
||||||
The intent of the last two properties is to allow to have two buffers on
|
|
||||||
adjacent memory space, one is being read from (and so its space shrinks)
|
|
||||||
while the other is being written to (and so it needs more and more space).
|
|
||||||
|
|
||||||
Illustration of forward buffer operation:
|
|
||||||
|
|
||||||
+-- next read will read from here
|
|
||||||
|
|
|
||||||
| +-- next write will write to here
|
|
||||||
v v
|
|
||||||
*--------------*===============*----------------*
|
|
||||||
| ^ | ^ | |
|
|
||||||
| | read_pos | write_pos |
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
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
|
||||||
@ -440,7 +60,7 @@ public:
|
|||||||
- Key-Ordered Retrieval
|
- Key-Ordered Retrieval
|
||||||
- Rowid-Ordered Retrieval
|
- Rowid-Ordered Retrieval
|
||||||
|
|
||||||
DsMrr_impl will use one of the above strategies, or combination of them,
|
DsMrr_impl will use one of the above strategies, or a combination of them,
|
||||||
according to the following diagram:
|
according to the following diagram:
|
||||||
|
|
||||||
(mrr function calls)
|
(mrr function calls)
|
||||||
@ -470,7 +90,7 @@ public:
|
|||||||
(table records and range_ids)
|
(table records and range_ids)
|
||||||
|
|
||||||
The choice of strategy depends on MRR scan properties, table properties
|
The choice of strategy depends on MRR scan properties, table properties
|
||||||
(whether we're scanning clustered primary key), and @@optimizer_flag
|
(whether we're scanning clustered primary key), and @@optimizer_switch
|
||||||
settings.
|
settings.
|
||||||
|
|
||||||
Key-Ordered Retrieval
|
Key-Ordered Retrieval
|
||||||
@ -541,7 +161,7 @@ private:
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
Secondary handler object. (created when needed, we need it when we need
|
Secondary handler object. (created when needed, we need it when we need
|
||||||
to run both index scan and rnd_pos() at the same time)
|
to run both index scan and rnd_pos() scan at the same time)
|
||||||
*/
|
*/
|
||||||
handler *h2;
|
handler *h2;
|
||||||
|
|
||||||
@ -568,14 +188,13 @@ private:
|
|||||||
uchar *full_buf_end;
|
uchar *full_buf_end;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
When using both rowid and key buffers: the bound between key and rowid
|
When using both rowid and key buffers: the boundary between key and rowid
|
||||||
parts of the buffer. This is the "original" value, actual memory ranges
|
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
|
used by key and rowid parts may be different because of dynamic space
|
||||||
reallocation between them.
|
reallocation between them.
|
||||||
*/
|
*/
|
||||||
uchar *rowid_buffer_end;
|
uchar *rowid_buffer_end;
|
||||||
|
|
||||||
|
|
||||||
/** Index scaning and key buffer-related members **/
|
/** Index scaning and key buffer-related members **/
|
||||||
|
|
||||||
/* TRUE <=> We can get at most one index tuple for a lookup key */
|
/* TRUE <=> We can get at most one index tuple for a lookup key */
|
||||||
@ -689,4 +308,7 @@ private:
|
|||||||
static uint key_buf_seq_next(range_seq_t rseq, KEY_MULTI_RANGE *range);
|
static uint key_buf_seq_next(range_seq_t rseq, KEY_MULTI_RANGE *range);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
@} (end of group DS-MRR declarations)
|
||||||
|
*/
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user