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
raftstore: init half split region #2790
raftstore: init half split region #2790
Conversation
The test failed.
|
} | ||
|
||
impl HalfStatus { | ||
pub fn on_split_check(&mut self, key: &[u8], value_size: u64) -> 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.
should_split
seems better.
@@ -123,19 +123,26 @@ impl<'a> MergedIterator<'a> { | |||
/// Split checking task. | |||
pub struct Task { | |||
region: Region, | |||
auto_check: 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.
auto_check = false
can mean a lot of things, I prefer to define an enum explicitly like:
enum SplitType {
AutoSplit,
HalfSplit,
}
others => panic!("expect split check result, but got {:?}", others), | ||
} | ||
} | ||
drop(rx); |
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.
Seems it will be dropped automatically?
let region = &task.region; | ||
let mut split_ctx = | ||
self.coprocessor | ||
.new_split_check_status(region, &self.engine, task.is_auto_split()); |
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 not just pass the split type? It seems pointless to define an enum and convert it to bool again.
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.
We'd like to use the enum instead of bool until we need to support more split algorithms
assert_eq!(region.get_start_key(), left.get_start_key()); | ||
assert_eq!(right.get_start_key(), left.get_end_key()); | ||
assert_eq!(region.get_end_key(), right.get_end_key()); | ||
assert_eq!(pd_client.get_region(&max_key).unwrap(), right); |
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.
It's not clear what you are trying to test in this two lines, why not just test the start/end keys of left and right one by one?
… of approximate size
…tikv into raftstore/half_split_region
src/raftstore/coprocessor/config.rs
Outdated
@@ -27,10 +27,12 @@ pub struct Config { | |||
/// be region_split_size (or a little bit smaller). | |||
pub region_max_size: ReadableSize, | |||
pub region_split_size: ReadableSize, | |||
pub half_split_bucket_size: ReadableSize, |
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.
what is this config used for?
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.
It's used for computing region's mid_key(split_key), this value has a direct influence on split_key
We will merge master && fix conflicts after pingcap/kvproto#229 merged |
src/raftstore/store/store.rs
Outdated
region_id, | ||
region_epoch, | ||
} => { | ||
let peer = match self.region_peers.get(®ion_id) { |
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.
Don't handle message here directly, this is a dispatch function.
src/raftstore/store/store.rs
Outdated
|
||
if !peer.is_leader() { | ||
// region on this store is no longer leader, skipped. | ||
info!( |
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.
s/info/warn
src/raftstore/store/store.rs
Outdated
|
||
let region = peer.region(); | ||
if util::is_epoch_stale(®ion_epoch, region.get_region_epoch()) { | ||
info!("[region {}] receive a stale halfsplit message", region_id); |
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.
s/info/warn
} | ||
|
||
fn test_half_split_region<T: Simulator>(cluster: &mut Cluster<T>) { | ||
let item_len = 74; |
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.
Please add a comment for this magic number.
let mut status = Status::default(); | ||
status.auto_split = auto_split; | ||
status | ||
} |
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.
Add a new line below.
#[derive(Default)] | ||
pub struct Status { | ||
// For TableCheckObserver | ||
table: Option<TableStatus>, | ||
// For SizeCheckObserver | ||
size: Option<SizeStatus>, | ||
// For HalfCheckObserver TODO: |
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.
What is the TODO
?
self.cur_bucket_size += current_len; | ||
} | ||
|
||
fn check_and_adjust_buckets_num(&mut self) { |
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.
It takes me a while to figure out what does this do, maybe a simpler way is to increase the bucket size exponentially.
|
||
pub fn split_key(self) -> Option<Vec<u8>> { | ||
let mid = self.buckets.len() / 2; | ||
if mid == 0 { |
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.
buckets.get()
will take care of this.
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.
It's used to check if self.buckets.len() <= 1
here
PTAL |
friendly ping @overvenus @BusyJay @huachaohuang |
if mid == 0 { | ||
None | ||
} else { | ||
self.buckets.get(mid).cloned() |
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.
How about remove
? So we don't need the cloned()
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.
It seems to cost more since remove
will shift all elements after it to the left?
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.
How about swap_remove
?
} | ||
|
||
#[derive(Debug)] | ||
pub enum SplitType { |
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.
How about making the Task an enum?
pub enum Task {
Auto(Region),
Manual(Region),
}
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 don't think so since all tasks will share the same Region
struct.
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.
Then we only need a bool.
src/raftstore/coprocessor/config.rs
Outdated
@@ -31,6 +31,7 @@ pub struct Config { | |||
|
|||
/// Default region split size. | |||
pub const SPLIT_SIZE_MB: u64 = 96; | |||
pub const HALF_SPLIT_BUCKET_SIZE_MB: u64 = 1; |
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.
Looks like an unused const.
tests/raftstore/pd.rs
Outdated
@@ -522,6 +522,24 @@ impl TestPdClient { | |||
}); | |||
} | |||
|
|||
pub fn half_split_region(&self, src_region: metapb::Region) { | |||
self.set_rule(box move |region: &metapb::Region, _: &metapb::Peer| { |
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.
Please fix merge conflicts.
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.
It's blocked by pingcap/kvproto#229 @disksing
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 is this conflict blocked by kvproto?
tests/raftstore/pd.rs
Outdated
@@ -522,6 +522,24 @@ impl TestPdClient { | |||
}); | |||
} | |||
|
|||
pub fn half_split_region(&self, src_region: metapb::Region) { | |||
self.set_rule(box move |region: &metapb::Region, _: &metapb::Peer| { |
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 is this conflict blocked by kvproto?
if half_split_bucket_size == 0 { | ||
half_split_bucket_size = 1; | ||
} else if half_split_bucket_size > bucket_size_limit { | ||
half_split_bucket_size = bucket_size_limit; |
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.
It doesn't seem possible that the bucket size will exceed 512MB here.
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 do check here in case someday the region's max size increase too much.
impl SplitCheckObserver for HalfCheckObserver { | ||
fn new_split_check_status( | ||
&self, | ||
_ctx: &mut ObserverContext, |
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 think we can get_region_approximate_size
and then we can find a split key faster.
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.
In our last test, get_region_approximate_size
may not be as accurate as expected.
if mid == 0 { | ||
None | ||
} else { | ||
Some(self.buckets.swap_remove(mid)) |
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 use swap_remove here?
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.
avoid get(mid).clone()
let mut half_split_bucket_size = region_size_limit / BUCKET_NUMBER_LIMIT as u64; | ||
let bucket_size_limit = ReadableSize::mb(BUCKET_SIZE_LIMIT_MB).0; | ||
if half_split_bucket_size == 0 { | ||
half_split_bucket_size = 1; |
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.
bucket size is 1 byte here? too small?
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 think it is mainly for tests.
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.
It only happens when max_region_size is smaller than 1K
can you unify auto_split, auto_check? are they different? |
self.buckets.push(key.to_vec()); | ||
self.cur_bucket_size = 0; | ||
} | ||
self.cur_bucket_size += current_len; |
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.
current_len
is a bit confused here, I think you can just add the length of the key and value here.
let mut half_split_bucket_size = region_size_limit / BUCKET_NUMBER_LIMIT as u64; | ||
let bucket_size_limit = ReadableSize::mb(BUCKET_SIZE_LIMIT_MB).0; | ||
if half_split_bucket_size == 0 { | ||
half_split_bucket_size = 1; |
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 think it is mainly for tests.
} | ||
// Approximate size of memtable is inaccurate for small data, | ||
// we flush it to SST so we can use the size properties instead. | ||
engine.flush(true).unwrap(); |
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.
But you don't use approximate size now.
tests/raftstore/pd.rs
Outdated
} | ||
|
||
impl Operator { | ||
fn make_region_heartbeat_response( | ||
&self, | ||
region_id: u64, | ||
region: &metapb::Region, |
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 do you need to change this?
@@ -165,6 +170,9 @@ impl Operator { | |||
} | |||
unreachable!() | |||
} | |||
Operator::HalfSplitRegion { ref region_epoch } => { | |||
region.get_region_epoch() != region_epoch |
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.
What if it is a stale epoch?
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.
do not send split command @huachaohuang
@@ -123,19 +123,26 @@ impl<'a> MergedIterator<'a> { | |||
/// Split checking task. | |||
pub struct Task { | |||
region: Region, | |||
auto: 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.
auto_split
is more clear.
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.
LGTM
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.
LGTM
dev
test
@overvenus @BusyJay PTAL