-
Notifications
You must be signed in to change notification settings - Fork 77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
iterator: unify behavior and implement prev
and to_last
to all Iterators
#184
base: master
Are you sure you want to change the base?
Conversation
* update prev and to last Signed-off-by: GanZiheng <[email protected]> * update Signed-off-by: GanZiheng <[email protected]> * add tests Signed-off-by: GanZiheng <[email protected]>
…v` and `to_last` to `Iterator` (#5) * simply update iterator and need refine Signed-off-by: GanZiheng <[email protected]> * update table iterator Signed-off-by: GanZiheng <[email protected]> * update skl iterator Signed-off-by: GanZiheng <[email protected]> * update concat iterator Signed-off-by: GanZiheng <[email protected]> * fix clippy Signed-off-by: GanZiheng <[email protected]> * update pending writes Signed-off-by: GanZiheng <[email protected]> * update merge iterator Signed-off-by: GanZiheng <[email protected]>
Why not define |
Currently, |
Codecov Report
@@ Coverage Diff @@
## master #184 +/- ##
==========================================
+ Coverage 89.32% 90.52% +1.19%
==========================================
Files 39 39
Lines 8752 9487 +735
==========================================
+ Hits 7818 8588 +770
+ Misses 934 899 -35 |
Signed-off-by: GanZiheng <[email protected]>
prev
and to_last
to all Iteratorsprev
and to_last
to all Iterators
Signed-off-by: GanZiheng <[email protected]>
Signed-off-by: GanZiheng <[email protected]>
Signed-off-by: GanZiheng <[email protected]>
Signed-off-by: GanZiheng <[email protected]>
/// Just like `parse_item`, but used for `prev`. | ||
/// | ||
/// This function advances the iterator. | ||
fn parse_item_for_prev(&mut self) -> bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we reuse parse_item
by passing a parameter to indicate the direction?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we can combine parse_item
and parse_item_for_prev
once the logic is reviewed.
src/iterator.rs
Outdated
let key_with_ts = key_with_ts(key, self.item().version); | ||
|
||
// TODO: Consider add direction flag to avoid seek. | ||
self.table_iter.seek(&key_with_ts); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why seek
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since parse_item
and parse_item_for_prev
would advance and retreat the table_iter
inside the Iterator
respectively, what we should do in case of next
after next
and prev
after next
are different. We may add flag or update parse_item
and parse_item_for_prev
to avoid seek.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a flag current_direction
to indicate the "direction" of the iterator. If the last operation is prev
, it will be set to false, and we will advance the inner iterator double times in that case if we call next
subsequently.
Signed-off-by: GanZiheng <[email protected]>
Generally LGTM. But I wonder if there is any use case inside AgateDB that we will need to do both forward iterating and backward iterating on a single iterator? If not, we can use const generics to implement forward/backward iterator using one piece of code. It will also simplifies the case on how to seek. |
Previously, AgateDB has both forward and reverse iterators, but once the kind of iterator is determined, it could only go ahead but cannot go back. Current I support both forward and reverse iterator to go back. |
Yes, so I'm wondering whether this is necessary... I can hardly come up with a use case that users want to change direction on-the-fly. |
In fact, that's because RocksDB supports it and TiKV needs it 🤣. |
Signed-off-by: GanZiheng [email protected]
Unify all kinds of iterators which implement the
AgateIterator
trait.Suppose we have another two extra elements in the data which the iterator iterates over, one is before the original first element, called
before first
, and another is after the last original element, namelyafter last
.prev
, we will arrivebefore first
, andvalid
will return false;next
, we will arriveafter last
, andvalid
will return false;before first
, if we callprev
, nothing will change, and if we callnext
, we will move to the first element;after last
, if we callnext
, nothing will change, and if we callprev
, we will move to the last element;When entries are set but not committed yet, they will stay in
pending_writes
of the transaction, and if we buildPendingWritesIterator
to iterate over them, the timestamp of each entry is set to read timestamp of the transaction. So, we may get duplicate keys inMergeIterator
ofIterator
generated byTransaction
.However, the logic ofprev
inMergeIterator
is complicated if there exists duplicated keys. So I also update the timestamp appended to key. When writing an entry, we will appendcommit timestamp * 10
to the key and we will useread timestamp * 10 + 5
to search an entry or buildPendingWritesIterator
.Since all keys are different in
PendingWritesIterator
and other iterators respectively, to a specific key, there may be at most one pair of identical keys in all iterators. We can simplify logic ofMergeIterator
with this limitation.