Skip to content
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

feat(storage): support reverse scan #12570

Merged
merged 31 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
da97cfe
tmp commit
Little-Wallace Mar 20, 2024
b139383
refactor code
Little-Wallace Mar 20, 2024
f4b5eca
rev iterator
Little-Wallace Mar 20, 2024
af91a74
fix check
Little-Wallace Apr 15, 2024
27c4bb9
add test
Little-Wallace Apr 15, 2024
40d7711
fix test
Little-Wallace Apr 15, 2024
8367c90
remove core
Little-Wallace Apr 15, 2024
6c88003
Merge branch 'main' into reverse-iter
Little-Wallace May 9, 2024
11f48f9
fix conflict
Little-Wallace May 9, 2024
d8360cc
revert user key refactor
Little-Wallace May 9, 2024
b89d706
add micro benchmark
Little-Wallace May 10, 2024
c94b648
add ut
Little-Wallace May 10, 2024
02d8825
fix format
Little-Wallace May 10, 2024
a8f563a
refactor iterator builder
Little-Wallace May 14, 2024
849da4b
refactor
Little-Wallace May 16, 2024
3c82812
refactor interface
Little-Wallace May 16, 2024
3ccc35c
Merge branch 'main' into reverse-iter
Little-Wallace May 16, 2024
059e527
fix conflict
Little-Wallace May 16, 2024
c0343b4
fix format
Little-Wallace May 16, 2024
c7d7adf
add ut
Little-Wallace May 17, 2024
4289518
fix check
Little-Wallace May 17, 2024
349b617
fix corner case
Little-Wallace May 17, 2024
5632104
fix scan bound
Little-Wallace May 17, 2024
9615962
Merge branch 'main' into reverse-iter
Little-Wallace May 20, 2024
7c6217b
fix fmt
Little-Wallace May 20, 2024
16b1719
fix warn
Little-Wallace May 20, 2024
c2c0164
Merge branch 'main' into reverse-iter
Little-Wallace May 20, 2024
2420d15
address comment
Little-Wallace May 21, 2024
d0c0fd4
Merge branch 'main' into reverse-iter
Little-Wallace May 21, 2024
fa29061
fix conflict
Little-Wallace May 21, 2024
4dd8d3f
fix check
Little-Wallace May 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 79 additions & 52 deletions src/storage/src/hummock/iterator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,82 @@ impl<'a, B: RustIteratorBuilder> FromRustIterator<'a, B> {
table_id,
}
}

async fn seek_inner<'b>(&'b mut self, key: FullKey<&'b [u8]>) -> HummockResult<()> {
match self.table_id.cmp(&key.user_key.table_id) {
std::cmp::Ordering::Less => {
self.iter = None;
return Ok(());
}
std::cmp::Ordering::Greater => {
return self.rewind().await;
}
_ => {}
}
let mut iter = B::seek(self.inner, key.user_key.table_key);
match iter.next() {
Some((first_key, first_value)) => {
if first_key.eq(&key.user_key.table_key) && self.epoch > key.epoch_with_gap {
// The semantic of `seek_fn` will ensure that `first_key` >= table_key of `key`.
// At the beginning we have checked that `self.table_id` >= table_id of `key`.
match iter.next() {
Some((next_key, next_value)) => {
assert_gt!(next_key, first_key);
self.iter =
Some((RustIteratorOfBuilder::Seek(iter), next_key, next_value));
}
None => {
self.iter = None;
}
}
} else {
self.iter = Some((RustIteratorOfBuilder::Seek(iter), first_key, first_value));
}
}
None => {
self.iter = None;
}
}
Ok(())
}

async fn rev_seek_inner<'b>(&'b mut self, key: FullKey<&'b [u8]>) -> HummockResult<()> {
match self.table_id.cmp(&key.user_key.table_id) {
std::cmp::Ordering::Less => {
return self.rewind().await;
}
std::cmp::Ordering::Greater => {
self.iter = None;
return Ok(());
}
_ => {}
}
let mut iter = B::seek(self.inner, key.user_key.table_key);
match iter.next() {
Some((first_key, first_value)) => {
if first_key.eq(&key.user_key.table_key) && self.epoch < key.epoch_with_gap {
// The semantic of `seek_fn` will ensure that `first_key` >= table_key of `key`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nits: should be first_key <= table_key of key in the comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

// At the beginning we have checked that `self.table_id` >= table_id of `key`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nits: should be self.table_id <= table_id of key in the comment

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

match iter.next() {
Some((next_key, next_value)) => {
assert_lt!(next_key, first_key);
self.iter =
Some((RustIteratorOfBuilder::Seek(iter), next_key, next_value));
}
None => {
self.iter = None;
}
}
} else {
self.iter = Some((RustIteratorOfBuilder::Seek(iter), first_key, first_value));
}
}
None => {
self.iter = None;
}
}
Ok(())
}
}

impl<'a, B: RustIteratorBuilder> HummockIterator for FromRustIterator<'a, B> {
Expand Down Expand Up @@ -426,59 +502,10 @@ impl<'a, B: RustIteratorBuilder> HummockIterator for FromRustIterator<'a, B> {
}

async fn seek<'b>(&'b mut self, key: FullKey<&'b [u8]>) -> HummockResult<()> {
match self.table_id.cmp(&key.user_key.table_id) {
std::cmp::Ordering::Less => match Self::Direction::direction() {
DirectionEnum::Forward => {
self.iter = None;
return Ok(());
}
DirectionEnum::Backward => {
return self.rewind().await;
}
},
std::cmp::Ordering::Greater => match Self::Direction::direction() {
DirectionEnum::Forward => {
return self.rewind().await;
}
DirectionEnum::Backward => {
self.iter = None;
return Ok(());
}
},
_ => {}
match Self::Direction::direction() {
DirectionEnum::Forward => self.seek_inner(key).await,
DirectionEnum::Backward => self.rev_seek_inner(key).await,
}
let mut iter = B::seek(self.inner, key.user_key.table_key);
match iter.next() {
Some((first_key, first_value)) => {
if first_key.eq(&key.user_key.table_key) && self.epoch > key.epoch_with_gap {
// The semantic of `seek_fn` will ensure that `first_key` >= table_key of `key`.
// At the beginning we have checked that `self.table_id` >= table_id of `key`.
match iter.next() {
Some((next_key, next_value)) => {
match Self::Direction::direction() {
DirectionEnum::Forward => {
assert_gt!(next_key, first_key);
}
DirectionEnum::Backward => {
assert_lt!(next_key, first_key);
}
}
self.iter =
Some((RustIteratorOfBuilder::Seek(iter), next_key, next_value));
}
None => {
self.iter = None;
}
}
} else {
self.iter = Some((RustIteratorOfBuilder::Seek(iter), first_key, first_value));
}
}
None => {
self.iter = None;
}
}
Ok(())
}

fn collect_local_statistic(&self, _stats: &mut StoreLocalStatistic) {}
Expand Down
3 changes: 2 additions & 1 deletion src/storage/src/hummock/store/version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@

use std::cmp::Ordering;
use std::collections::vec_deque::VecDeque;
use std::collections::HashSet;
use std::collections::{HashMap, HashSet};
use std::iter::once;
use std::ops::Bound::Included;
use std::sync::Arc;
use std::time::Instant;
Expand Down
8 changes: 4 additions & 4 deletions src/storage/src/mem_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1106,7 +1106,7 @@ mod tests {
.unwrap();
check_data(&mut iter, &ordered_test_data).await;

// Test seek with a later epoch, the first key is not skipped
// Test seek with a later epoch, the first key is skipped
let later_epoch = EpochWithGap::new_from_epoch(TEST_EPOCH.next_epoch());
let seek_idx = 500;
iter.seek(FullKey {
Expand All @@ -1119,9 +1119,9 @@ mod tests {
.await
.unwrap();
let rev_seek_idx = ordered_test_data.len() - seek_idx - 1;
check_data(&mut iter, &ordered_test_data[rev_seek_idx..]).await;
check_data(&mut iter, &ordered_test_data[rev_seek_idx + 1..]).await;

// Test seek with a earlier epoch, the first key is skipped
// Test seek with a earlier epoch, the first key is not skipped
let early_epoch = EpochWithGap::new_from_epoch(TEST_EPOCH.prev_epoch());
let seek_idx = 500;
iter.seek(FullKey {
Expand All @@ -1134,7 +1134,7 @@ mod tests {
.await
.unwrap();
let rev_seek_idx = ordered_test_data.len() - seek_idx - 1;
check_data(&mut iter, &ordered_test_data[(rev_seek_idx + 1)..]).await;
check_data(&mut iter, &ordered_test_data[rev_seek_idx..]).await;

drop(iter);
mem_table.insert(get_key(10001), "value1".into()).unwrap();
Expand Down
Loading