mirror of
https://github.com/MariaDB/server.git
synced 2025-01-18 13:02:28 +01:00
354 lines
8.7 KiB
Text
354 lines
8.7 KiB
Text
|
|
||
|
This file describes how MySQL index navigation commands are translated into
|
||
|
RocksDB index navigation commands.
|
||
|
|
||
|
Index tuples are shown as
|
||
|
|
||
|
( kv )-aaa-pkN
|
||
|
|
||
|
here
|
||
|
* '(kv)' is the 4-byte index number.
|
||
|
* '-' is just for readability
|
||
|
* everything that follows the '-' is mem-comparable form of the key.
|
||
|
In ascii encoding, aaa < bbb < ccc < xxx.
|
||
|
|
||
|
Tuples that start with '#' do not exist in the database. They are only shown
|
||
|
to demonstrate where Seek() calls end up with.
|
||
|
|
||
|
== HA_READ_KEY_EXACT, forward CF ==
|
||
|
|
||
|
(kv-1)-xxx-pk
|
||
|
# ( kv )-aaa <-- "kv-aaa" doesn't exist in the database, but it would be
|
||
|
here.
|
||
|
( kv )-aaa-pk <--- Seek("kv-aaa") will put us here on the next record.
|
||
|
( kv )-aaa-pk2
|
||
|
( kv )-bbb-...
|
||
|
|
||
|
RocksDB calls:
|
||
|
|
||
|
it->Seek(kv);
|
||
|
if (it->Valid() && kd->covers_key(..) && kd->cmp_full_keys(...))
|
||
|
return record.
|
||
|
|
||
|
== HA_READ_KEY_EXACT, backward CF ==
|
||
|
|
||
|
When we need to seek to a tuple that is a prefix of a full key:
|
||
|
|
||
|
(kv+1)-xxx-pk
|
||
|
( kv )-ccc-pk
|
||
|
( kv )-bbb-pk3
|
||
|
( kv )-bbb-pk2
|
||
|
( kv )-bbb-pk1 < -- We need to be here
|
||
|
# ( kv )-bbb <---we call Seek(kv-bbb)
|
||
|
( kv )-aaa-pk ... and end up here. Should call it->Prev().
|
||
|
|
||
|
There is a special case when (kv)-bbb-pk1 is the last record in the CF, and
|
||
|
we get invalid iterator. Then, we need to call SeekToLast().
|
||
|
|
||
|
Another kind of special case is when we need to seek to the full value.
|
||
|
Suppose, the lookup tuple is kv-bbb-pk1:
|
||
|
|
||
|
(kv+1)-xxx-pk
|
||
|
( kv )-ccc-pk
|
||
|
( kv )-bbb-pk3
|
||
|
( kv )-bbb-pk2
|
||
|
( kv )-bbb-pk1 < -- Seek(kv-bbb-pk1)
|
||
|
( kv )-bbb-pk0
|
||
|
|
||
|
Then, Seek(kv-bbb-pk1) will position us exactly the tuple we need, and we
|
||
|
won't need to call it->Prev(). If we get an invalid iterator, there is no
|
||
|
need to call SeekToLast().
|
||
|
|
||
|
RocksDB calls:
|
||
|
|
||
|
it->Seek(tuple);
|
||
|
|
||
|
if (!using_full_key)
|
||
|
{
|
||
|
if (!it->Valid())
|
||
|
it->SeekToLast();
|
||
|
else
|
||
|
it->Prev();
|
||
|
}
|
||
|
|
||
|
if (it->Valid() && kd->covers_key(..) && kd->cmp_full_keys(...))
|
||
|
return record.
|
||
|
|
||
|
== HA_READ_KEY_OR_NEXT, forward CF ==
|
||
|
|
||
|
This is finding min(key) such that key >= lookup_tuple.
|
||
|
|
||
|
If lookup tuple is kv-bbb:
|
||
|
|
||
|
( kv )-aaa-pk
|
||
|
# ( kv )-bbb <-- "kv-bbb" doesn't exist in the database, but it would be
|
||
|
here.
|
||
|
( kv )-bbb-pk1 <--- Seek("kv-bbb") will put us here on the next record.
|
||
|
( kv )-bbb-pk2
|
||
|
( kv )-bbb-...
|
||
|
|
||
|
RocksDB calls:
|
||
|
|
||
|
Seek(kv);
|
||
|
if (it->Valid() && kd->covers_key(..) && kd->cmp_full_keys(...))
|
||
|
return record.
|
||
|
|
||
|
== HA_READ_KEY_OR_NEXT, backward CF ==
|
||
|
|
||
|
When specified key tuple is a key prefix:
|
||
|
|
||
|
(kv+1)-xxx-pk
|
||
|
( kv )-ccc-pk
|
||
|
( kv )-bbb-pk3
|
||
|
( kv )-bbb-pk2
|
||
|
( kv )-bbb-pk1 < -- We need to be here (or above)
|
||
|
# ( kv )-bbb <---we call Seek(kv-bbb)
|
||
|
( kv )-aaa-pk ... and end up here. Should call it->Prev().
|
||
|
|
||
|
There is a special case when (kv)-bbb-pk1 is the last record in the CF, and
|
||
|
we get invalid iterator. Then, we need to call SeekToLast().
|
||
|
|
||
|
Another kind of special case is when we need to seek to the full value.
|
||
|
Suppose, the lookup tuple is kv-bbb-pk1:
|
||
|
|
||
|
(kv+1)-xxx-pk
|
||
|
( kv )-ccc-pk
|
||
|
( kv )-bbb-pk3
|
||
|
( kv )-bbb-pk2
|
||
|
( kv )-bbb-pk1 < -- Seek(kv-bbb-pk1)
|
||
|
( kv )-bbb-pk0
|
||
|
|
||
|
Then, Seek(kv-bbb-pk1) may position us exactly at the tuple we need, and we
|
||
|
won't need to call it->Prev().
|
||
|
If kv-bbb-pk1 is not present in the database, we will be positioned on
|
||
|
kv-bbb-pk0, and we will need to call it->Prev().
|
||
|
If we get an invalid iterator, we DO need to call SeekToLast().
|
||
|
|
||
|
RocksDB calls:
|
||
|
|
||
|
Seek(...);
|
||
|
|
||
|
if (!it->Valid())
|
||
|
it->SeekToLast();
|
||
|
else
|
||
|
{
|
||
|
if (!using_full_key ||
|
||
|
!(kd->covers_key(...) || kd->cmp_full_keys(...))
|
||
|
it->Prev();
|
||
|
}
|
||
|
|
||
|
if (it->Valid() && kd->covers_key(..))
|
||
|
return record.
|
||
|
|
||
|
== HA_READ_AFTER_KEY, forward CF ==
|
||
|
|
||
|
This is finding min(key) such that key > lookup_key.
|
||
|
|
||
|
Suppose lookup_key = kv-bbb
|
||
|
|
||
|
( kv )-aaa-pk
|
||
|
# ( kv )-bbb
|
||
|
( kv )-bbb-pk1 <--- Seek("kv-bbb") will put us here. We need to
|
||
|
( kv )-bbb-pk2 get to the value that is next after 'bbb'.
|
||
|
( kv )-bbb-pk3
|
||
|
( kv )-bbb-pk4
|
||
|
( kv )-bbb-pk5
|
||
|
( kv )-ccc-pkN <-- That is, we need to be here.
|
||
|
|
||
|
However, we don't know that the next value is kv-ccc. Instead, we seek to the
|
||
|
first value that strictly greater than 'kv-bbb'. It is Successor(kv-bbb).
|
||
|
|
||
|
It doesn't matter if we're using a full extended key or not.
|
||
|
|
||
|
RocksDB calls:
|
||
|
|
||
|
Seek(Successor(kv-bbb));
|
||
|
if (it->Valid() && kd->covers_key(it.key()))
|
||
|
return record;
|
||
|
|
||
|
Note that the code is the same as with HA_READ_KEY_OR_NEXT, except that
|
||
|
we seek to Successor($lookup_key) instead of $lookup_key itself.
|
||
|
|
||
|
== HA_READ_AFTER_KEY, backward CF ==
|
||
|
|
||
|
Suppose, the lookup key is 'kv-bbb':
|
||
|
|
||
|
(kv+1)-xxx-pk
|
||
|
( kv )-ccc-pk7
|
||
|
( kv )-ccc-pk6 <-- We need to be here.
|
||
|
# Successor(kv-bbb) <-- We get here when we call Seek(Successor(kv-bbb))
|
||
|
( kv )-bbb-pk5 and we will need to call Prev() (*)
|
||
|
( kv )-bbb-pk4
|
||
|
( kv )-bbb-pk3
|
||
|
( kv )-bbb-pk2
|
||
|
( kv )-bbb-pk1
|
||
|
# ( kv )-bbb <-- We would get here if we called Seek(kv-bbb).
|
||
|
( kv )-aaa-pk
|
||
|
|
||
|
(*) - unless Successor(kv-bbb)=(kv-ccc), and Seek(kv-ccc) hits the row. In
|
||
|
that case, we won't need to call Prev().
|
||
|
|
||
|
RocksDB calls:
|
||
|
|
||
|
Seek(Successor(kv-bbb));
|
||
|
if (!it->Valid())
|
||
|
{
|
||
|
/*
|
||
|
We may get EOF if rows with 'kv-bbb' (below the Successor... line in the
|
||
|
diagram) do not exist. This doesn't mean that rows with values kv-ccc
|
||
|
do not exist.
|
||
|
*/
|
||
|
it->SeekToLast();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (!using_full_key ||
|
||
|
!kd->value_matches_prefix(...))
|
||
|
{
|
||
|
it->Prev();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (it->Valid() && kd->covers_key(...))
|
||
|
return record.
|
||
|
|
||
|
Note that the code is the same as with HA_READ_KEY_OR_NEXT, except that
|
||
|
we seek to Successor($lookup_key) instead of $lookup_key itself.
|
||
|
|
||
|
|
||
|
== HA_READ_BEFORE_KEY, forward CF ==
|
||
|
|
||
|
This is finding max(key) such that key < lookup_tuple.
|
||
|
|
||
|
Suppose, lookup_tuple=kv-bbb.
|
||
|
|
||
|
( kv )-aaa-pk1
|
||
|
( kv )-aaa-pk2
|
||
|
( kv )-aaa-pk3 <-- Need to be here.
|
||
|
# ( kv )-bbb
|
||
|
( kv )-bbb-pk4 <-- Seek("kv-bbb") will put us here.
|
||
|
( kv )-bbb-pk5
|
||
|
( kv )-bbb-pk6
|
||
|
|
||
|
1. Seek(kv-bbb) will put us at kv-bbb-pk4 (or return an invalid iterator
|
||
|
if kv-bbb-pk4 and subsequent rows do not exist in the db).
|
||
|
2. We will need to call Prev() to get to the record before.
|
||
|
(if there is no record before kv-bbb, then we can't find a record).
|
||
|
|
||
|
It doesn't matter if we're using a full extended key or not.
|
||
|
|
||
|
RocksDB calls:
|
||
|
|
||
|
it->Seek(kv-bbb);
|
||
|
if (it->Valid())
|
||
|
it->Prev();
|
||
|
else
|
||
|
it->SeekToLast();
|
||
|
|
||
|
if (it->Valid() && kd->covers_key(...))
|
||
|
return record;
|
||
|
|
||
|
|
||
|
== HA_READ_BEFORE_KEY, backward CF ==
|
||
|
|
||
|
This is finding max(key) such that key < lookup_tuple.
|
||
|
Suppose, lookup_tuple=kv-bbb, a prefix of the full key.
|
||
|
|
||
|
( kv )-bbb-pk6
|
||
|
( kv )-bbb-pk5
|
||
|
( kv )-bbb-pk4
|
||
|
# ( kv )-bbb
|
||
|
( kv )-aaa-pk3 <-- Need to be here, and Seek("kv-bbb") will put us here
|
||
|
( kv )-aaa-pk2
|
||
|
( kv )-aaa-pk1
|
||
|
|
||
|
If the lookup tuple is a full key (e.g. kv-bbb-pk4), and the key is present in
|
||
|
the database, the iterator will be positioned on the key. We will need to call
|
||
|
Next() to get the next key.
|
||
|
|
||
|
RocksDB calls:
|
||
|
|
||
|
it->Seek(kv-bbb);
|
||
|
|
||
|
if (it->Valid() && using_full_key &&
|
||
|
kd->value_matches_prefix(...))
|
||
|
{
|
||
|
/* We are using full key and we've hit an exact match */
|
||
|
it->Next();
|
||
|
}
|
||
|
|
||
|
if (it->Valid() && kd->covers_key(...))
|
||
|
return record;
|
||
|
|
||
|
== HA_READ_PREFIX_LAST, forward CF ==
|
||
|
|
||
|
Find the last record with the specified index prefix lookup_tuple.
|
||
|
|
||
|
Suppose, lookup_tuple='kv-bbb'
|
||
|
|
||
|
( kv )-aaa-pk2
|
||
|
( kv )-aaa-pk3
|
||
|
# ( kv )-bbb
|
||
|
( kv )-bbb-pk4
|
||
|
( kv )-bbb-pk5
|
||
|
( kv )-bbb-pk6
|
||
|
( kv )-bbb-pk7 <--- Need to be here.
|
||
|
# ( kv )-ccc
|
||
|
( kv )-ccc-pk8 <-- Seek(Successor(kv-bbb)) will get us here. will need
|
||
|
( kv )-ccc-pk9 to call Prev().
|
||
|
|
||
|
RocksDB calls:
|
||
|
|
||
|
Seek(Successor(kv-bbb));
|
||
|
if (!it->Valid())
|
||
|
it->SeekToLast();
|
||
|
else
|
||
|
it->Prev();
|
||
|
|
||
|
if (it->Valid() && kd->covers_key(...))
|
||
|
{
|
||
|
if (!cmp_full_keys(lookup_tuple)) // not needed in _OR_PREV
|
||
|
{
|
||
|
// the record's prefix matches lookup_tuple.
|
||
|
return record;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
== HA_READ_PREFIX_LAST, backward CF ==
|
||
|
|
||
|
Suppose, lookup_tuple='kv-bbb'
|
||
|
|
||
|
( kv )-ccc-pk9
|
||
|
( kv )-ccc-pk8
|
||
|
# ( kv )-ccc <-- 2. Seek(Successor(kv-bbb)) will point here
|
||
|
and it will fall down to the next row.
|
||
|
( kv )-bbb-pk7 <--- 1. Need to be here.
|
||
|
( kv )-bbb-pk6
|
||
|
( kv )-bbb-pk5
|
||
|
( kv )-bbb-pk4
|
||
|
# ( kv )-bbb
|
||
|
( kv )-aaa-pk3
|
||
|
( kv )-aaa-pk2
|
||
|
|
||
|
|
||
|
RocksDB calls:
|
||
|
|
||
|
it->Seek(Successor(kv-bbb));
|
||
|
|
||
|
if (using_full_key && it->Valid() && !cmp_full_keys(Sucessor(lookup_key)))
|
||
|
it->Next();
|
||
|
|
||
|
if (it->Valid() && kd->covers_key(..))
|
||
|
{
|
||
|
if (!cmp_full_keys(...)) // not needed in _OR_PREV
|
||
|
{
|
||
|
// the record's prefix matches lookup_tuple.
|
||
|
return record;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
== HA_READ_PREFIX_LAST_OR_PREV, forward or backward CF ==
|
||
|
|
||
|
This is just like HA_READ_PREFIX_LAST but we don't need to check that the key
|
||
|
we've got is in the search prefix. (search for "not needed in _OR_PREV" above)
|