-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
tikv-ctl: refactor with debug API. #2377
Conversation
src/raftstore/store/debug.rs
Outdated
@@ -53,6 +55,13 @@ quick_error!{ | |||
} | |||
} | |||
|
|||
#[derive(PartialEq, Debug)] | |||
pub struct RegionInfo( |
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.
Use struct instead of tuple struct.
src/raftstore/store/debug.rs
Outdated
@@ -186,6 +209,38 @@ impl Debugger { | |||
compact_range(db, handle, start, end, false); | |||
Ok(()) | |||
} | |||
|
|||
/// Set a region to tombstone by manual. | |||
pub fn tombstone_region(&self, region: u64, conf_ver: u64) -> Result<()> { |
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.
Mark a region as tombstone doesn't (and shouldn't) require a running TiKV instance, otherwise the updated region will probably be overwritten by the running instance.
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, so there is no tombstone_region
API in server/service/debug.rs
, and tombstone command in tikv-ctl.rs
doesn't support remote mode either. I just put the code here. If it's confuse, which place to place this function is better?
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.
The function name confused me, which looks like a get function, but here is a set function, a bad name.
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.
Maybe we should get the current region epoch from PD and then set the tombstone with it.
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 you use another PR to support this feature?
This PR is only for refactor.
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.
Got it. I will raise this in next PR, pass a PDClient
into this function, and move this code to tikv-ctl.rs
.
src/raftstore/store/debug.rs
Outdated
@@ -63,6 +72,27 @@ impl Debugger { | |||
Debugger { engines } | |||
} | |||
|
|||
pub fn get_all_regions(&self, db: DBType, cf: &str) -> Result<Vec<u64>> { |
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 what case will db be DBType::Raft?
src/bin/tikv-ctl.rs
Outdated
let raft_db = if let Some(raftdb_path) = matches.value_of("raftdb") { | ||
Arc::new(util::rocksdb::open(raftdb_path, &[CF_DEFAULT]).unwrap()) | ||
} else { | ||
let raftdb_path = path.to_string() + "../raft"; |
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.
Use Path::join
instead.
@BusyJay @overvenus , PTAL again, thanks. |
src/bin/tikv-ctl.rs
Outdated
use tikv::raftstore::store::debug::{Debugger, RegionInfo}; | ||
use tikv::storage::{ALL_CFS, CF_DEFAULT, CF_LOCK, CF_RAFT, CF_WRITE}; | ||
|
||
enum DebugExecutor { |
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.
is it better to define an Executor trait so we can avoid following match
in many functions?
src/raftstore/store/debug.rs
Outdated
@@ -63,6 +85,23 @@ impl Debugger { | |||
Debugger { engines } | |||
} | |||
|
|||
/// Get all region id in the specified CF, only used for KV rocksdb. | |||
pub fn get_all_regions(&self, cf: &str) -> Result<Vec<u64>> { |
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 what case cf
is not CF_RAFT
?
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.
For now there is not because we only have get_region_info
using it. However, I think maybe we will need to get regions from other CFs in future. So keep the CF as an argument is better?
src/bin/tikv-ctl.rs
Outdated
None => dump_all_region_size(&db, cf_name), | ||
let cfs = matches | ||
.value_of("cf") | ||
.map_or(ALL_CFS.to_vec(), |cf| vec![cf]); |
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.
map_or_else
src/bin/tikv-ctl.rs
Outdated
println!("value: {}", value); | ||
} | ||
|
||
fn region_size(&self, region_id: u64, cfs: Vec<&str>) { |
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.
Weird name. It feels like it's going to return the region size. Maybe verb+noun
is a better choice.
src/bin/tikv-ctl.rs
Outdated
|
||
fn region_info(&self, region_id: u64, skip_tombstone: bool) { | ||
let region_info = self.get_region_info(region_id); | ||
Self::show_region_info(region_id, region_info, skip_tombstone); |
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 it in a separate function?
PTAL @overvenus @BusyJay |
I use some long options, for avoid name conflict.
…peng/debug-client
@BusyJay @overvenus , PTAL thanks. |
src/bin/tikv-ctl.rs
Outdated
Arg::with_name("hex-to-escaped") | ||
.short("h") | ||
.long("from-hex") |
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 "to-escaped" is more appropriate.
src/bin/tikv-ctl.rs
Outdated
@@ -496,39 +503,44 @@ fn main() { | |||
.about("print the range db range") | |||
.arg( | |||
Arg::with_name("from") | |||
.short("f") | |||
.long("from") |
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 also keep the short flag.
src/bin/tikv-ctl.rs
Outdated
host: Option<&str>, | ||
) -> Box<DebugExecutor> { | ||
match (host, db) { | ||
(Some(_), Some(_)) => { |
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 L67~L74 is unreachable.
src/bin/tikv-ctl.rs
Outdated
} | ||
|
||
trait DebugExecutor { | ||
fn dump_key_value(&self, cf: &str, key: Vec<u8>) { |
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.
dump_value
is more appropriate for key is not printed out.
src/bin/tikv-ctl.rs
Outdated
let sizes = self.get_region_size(region, cfs); | ||
if sizes.len() > 1 { | ||
let total_size = sizes.iter().map(|t| t.1).sum::<usize>() as u64; | ||
println!("total region number: {}", sizes.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.
What does it mean by "region number"?
|
||
fn dump_all_region_info(&self, skip_tombstone: bool) { | ||
for region in self.get_all_meta_regions() { | ||
self.dump_region_info(region, skip_tombstone); |
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 you need to print region id before display its information.
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.
fixed.
@BusyJay @overvenus PTAL, thanks. |
c9e3916
to
82eb209
Compare
src/bin/tikv-ctl.rs
Outdated
use tikv::raftstore::store::debug::{Debugger, RegionInfo}; | ||
use tikv::storage::{ALL_CFS, CF_DEFAULT, CF_LOCK, CF_WRITE}; | ||
|
||
fn perror_and_exit<E: Error, T>(e: E) -> T { |
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 -> !
?
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.
So unwrap_or_else
can't accept it as argument.
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
src/bin/tikv-ctl.rs
Outdated
use tikv::storage::{ALL_CFS, CF_DEFAULT, CF_LOCK, CF_WRITE}; | ||
|
||
fn perror_and_exit<E: Error, T>(e: E) -> T { | ||
eprintln!("{}", e); |
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.
The error may be confusing because it lacks context information.
src/bin/tikv-ctl.rs
Outdated
if start_ts.map_or(true, |ts| write_info.get_start_ts() == ts) && | ||
commit_ts.map_or(true, |ts| write_info.get_commit_ts() == ts) | ||
{ | ||
// FIXME: short_value is lost in kvproto. |
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 it a problem?
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.
The pb WriteInfo
has not short_value
field, so we can't show that.
src/bin/tikv-ctl.rs
Outdated
let mut lock_info = mvcc.take_lock(); | ||
if start_ts.map_or(true, |ts| lock_info.get_lock_version() == ts) { | ||
// FIXME: "lock type" is lost in kvproto. | ||
let pk = escape(lock_info.get_primary_lock()).into_bytes(); |
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 escape
?
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 primary key points another valid data key in rocksdb? So we escape it in order to we can easily pass it into another tikv-ctl command, such as print
.
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.
Output protobuf message in debug format will do that automatically.
src/bin/tikv-ctl.rs
Outdated
let k = escape(lock_info.get_key()).into_bytes(); | ||
lock_info.set_primary_lock(pk); | ||
lock_info.set_key(k); | ||
println!("\tlock cf value: {}", print_to_string(&lock_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.
Why not use "{:?}"?
src/bin/tikv-ctl.rs
Outdated
return; | ||
} | ||
(Some(region_local_1), Some(region_local_2)) => { | ||
let start_key = keys::data_key(region_local_1.get_region().get_start_key()); |
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 it be checked by ==
?
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.
Compare two metapb.Region
will also compare them peers
, but here we only need to compare data in them.
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 they should be same if two regions is going to be the same.
src/bin/tikv-ctl.rs
Outdated
let mvcc_infos_1 = self.get_mvcc_infos(start_key.clone(), end_key.clone(), 0); | ||
let mvcc_infos_2 = rhs_debug_executor.get_mvcc_infos(start_key, end_key, 0); | ||
let cmp_future = mvcc_infos_1.zip(mvcc_infos_2).for_each(|(item_1, item_2)| { | ||
let (key1, mvcc1) = (escape(&item_1.0), item_1.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.
escape
is needed only when they are not equal.
src/bin/tikv-ctl.rs
Outdated
let (key1, mvcc1) = (escape(&item_1.0), item_1.1); | ||
let (key2, mvcc2) = (escape(&item_2.0), item_2.1); | ||
if key1 != key2 { | ||
let err_msg = format!("db1 cur key: {}, db2 cur key: {}", key1, key2); |
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.
Is it OK to return early here? /cc @zhangjinpeng1987
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 you mean we return a future::err
here but not a future::ok
, which causes the steping on the DBIterator
s stop? I think it's OK if the future lib can deconstruct those DBIterator
s correctly.
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 need to print all different keys.
src/bin/tikv-ctl.rs
Outdated
@@ -248,131 +705,78 @@ fn main() { | |||
println!("{}", &unescape(escaped).to_hex().to_uppercase()); | |||
return; | |||
} | |||
_ => {} |
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 use unreachable!()
.
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.
rest LGTM
src/bin/tikv-ctl.rs
Outdated
} | ||
} | ||
if cfs.contains(&CF_DEFAULT) { | ||
for value_info in mvcc.take_values().into_iter() { |
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.
Does for value_info in mvcc.take_values()
work?
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.
No, IntoIterator
is implemented for &RepeatedField
but not RepeatedField
.
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 for value_info in mvcc.get_values()
?
src/bin/tikv-ctl.rs
Outdated
use tikv::raftstore::store::debug::{Debugger, RegionInfo}; | ||
use tikv::storage::{ALL_CFS, CF_DEFAULT, CF_LOCK, CF_WRITE}; | ||
|
||
fn perror_and_exit<E: Error, T>(prefix: &str, e: E) -> T { |
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 OK to use !
now.
LGTM, @zhangjinpeng1987 PTAL, you may have different thoughts on command |
@BusyJay @zhangjinpeng1987 , PTAL thanks. |
/run-all-test |
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
/run-all-test |
1 similar comment
/run-all-test |
Now tikv-ctl uses debug API so that it can work in both remote mode and local mode.