Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mariadb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
4f56acb6
Commit
4f56acb6
authored
Sep 28, 2010
by
Sergey Petrunya
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Better comments, move Lifo_buffer to separate file.
parent
3066c377
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
77 additions
and
464 deletions
+77
-464
sql/CMakeLists.txt
sql/CMakeLists.txt
+1
-0
sql/Makefile.am
sql/Makefile.am
+1
-0
sql/handler.h
sql/handler.h
+4
-0
sql/multi_range_read.cc
sql/multi_range_read.cc
+60
-75
sql/multi_range_read.h
sql/multi_range_read.h
+11
-389
No files found.
sql/CMakeLists.txt
View file @
4f56acb6
...
...
@@ -63,6 +63,7 @@ SET (SQL_SOURCE
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_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_map.cc sql_parse.cc sql_partition.cc sql_plugin.cc
sql_prepare.cc sql_rename.cc
...
...
sql/Makefile.am
View file @
4f56acb6
...
...
@@ -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
\
sql_select.h structs.h table.h sql_udf.h hash_filo.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
\
log_event.h rpl_record.h
\
log_event_old.h rpl_record_old.h
\
...
...
sql/handler.h
View file @
4f56acb6
...
...
@@ -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.
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.
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
...
...
sql/multi_range_read.cc
View file @
4f56acb6
...
...
@@ -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
);
/*
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
;
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
);
/*
At start, alloc all of the buffer for rowids. Key sorting code will grab a
piece if necessary.
At start, alloc all of the buffer for rowids. When/if key sorting code
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_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
{This is an internal function of DiskSweep MRR implementation}
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
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
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,
properly ordered
@retval other Error
*/
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_ASSERT
(
rowid_buffer
.
is_empty
());
rowid_buffer
.
reset
_for_writing
();
rowid_buffer
.
reset
();
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
;
//if (do_sort_keys && key_buffer.is_reverse())
// key_buffer.flip();
while
(
rowid_buffer
.
can_write
())
{
if
(
do_sort_keys
)
...
...
@@ -652,18 +648,21 @@ equals:
return
0
;
}
int
DsMrr_impl
::
key_tuple_cmp_reverse
(
void
*
arg
,
uchar
*
key1
,
uchar
*
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.
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
)
...
...
@@ -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
SYNOPSIS
DsMrr_impl::dsmrr_fill_key_buffer()
Enumerate the input range (=key) sequence, fill the key buffer with
(lookup_key, range_id) pairs and sort it.
DESCRIPTION
DS-MRR/CPK: Enumerate the input range (=key) sequence, fill the key buffe
r
(lookup_key, range_id) pairs and sort.
When this function returns, either
- key buffer is non-empty, o
r
- 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
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
()
...
...
@@ -778,7 +774,7 @@ void DsMrr_impl::dsmrr_fill_key_buffer()
identical_key_it
=
&
backward_key_it
;
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
,
is_mrr_assoc
?
(
uchar
**
)
&
range_info_ptr
:
NULL
,
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
()
...
...
@@ -837,30 +833,25 @@ void DsMrr_impl::reallocate_buffer_space()
}
/*
/*
*
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
@param range_info OUT identifier of range that the returned record belongs to
@note
This function walks over key buffer and does index reads, i.e. it produces
{current_record, range_id} pairs.
The function has the same call contract like multi_range_read_next()'s.
We actually iterate nested sequences:
We actually iterate over nested sequences:
- a disjoint sequence of index ranges
- each range has multiple records
- each record goes into multiple identical ranges.
RETURN
0 OK, next record was successfully read
HA_ERR_END_OF_FILE End of records
Other Some other error
@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
)
...
...
@@ -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
)
...
...
@@ -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
SYNOPSIS
DsMrr_impl::check_cpk_scan()
keyno Index that will be used
mrr_flags
@param thd
@param keyno Index that will be used
@param mrr_flags
DESCRIPTION
Check if key/flags allow DS-MRR/CPK strategy to be used.
RETURN
TRUE DS-MRR/CPK should be used
FALSE Otherwise
@retval TRUE DS-MRR/CPK should be used
@retval FALSE Otherwise
*/
bool
DsMrr_impl
::
check_cpk_scan
(
THD
*
thd
,
uint
keyno
,
uint
mrr_flags
)
...
...
@@ -1414,16 +1402,13 @@ bool DsMrr_impl::get_disk_sweep_mrr_cost(uint keynr, ha_rows rows, uint flags,
/*
Get cost of one sort-and-sweep step
SYNOPSIS
get_sort_and_sweep_cost()
table Table being accessed
nrows Number of rows to be sorted and retrieved
cost OUT The cost
DESCRIPTION
Get cost of these operations:
It consists of two parts:
- sort an array of #nrows ROWIDs using qsort
- read #nrows records from table in a sweep.
@param table Table being accessed
@param nrows Number of rows to be sorted and retrieved
@param cost OUT The cost of scan
*/
static
...
...
sql/multi_range_read.h
View file @
4f56acb6
/*
This file contains declarations for Disk-Sweep MultiRangeRead (DS-MRR)
implementation
/*
*
@defgroup DS-MRR declarations
@{
*/
/**
...
...
@@ -46,387 +46,7 @@
storage and has better performance when reading data in rowid order.
*/
class
Forward_lifo_buffer
;
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.
*/
#include "sql_lifo_buffer.h"
/*
DS-MRR implementation for one table. Create/use one object of this class for
...
...
@@ -440,7 +60,7 @@ public:
- Key-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:
(mrr function calls)
...
...
@@ -470,7 +90,7 @@ public:
(table records and range_ids)
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.
Key-Ordered Retrieval
...
...
@@ -541,7 +161,7 @@ private:
/*
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
;
...
...
@@ -568,14 +188,13 @@ private:
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 bound
ary
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
;
/** Index scaning and key buffer-related members **/
/* 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
);
};
/**
@} (end of group DS-MRR declarations)
*/
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment