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

tikv-ctl: refactor with debug API. #2377

Merged
merged 25 commits into from
Oct 18, 2017
Merged

tikv-ctl: refactor with debug API. #2377

merged 25 commits into from
Oct 18, 2017

Conversation

hicqu
Copy link
Contributor

@hicqu hicqu commented Oct 12, 2017

Now tikv-ctl uses debug API so that it can work in both remote mode and local mode.

@hicqu hicqu requested a review from overvenus October 12, 2017 05:25
@@ -53,6 +55,13 @@ quick_error!{
}
}

#[derive(PartialEq, Debug)]
pub struct RegionInfo(
Copy link
Member

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.

@@ -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<()> {
Copy link
Member

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.

Copy link
Contributor Author

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?

Copy link
Contributor

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.

Copy link
Contributor

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.

Copy link
Contributor

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.

Copy link
Contributor Author

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.

@@ -63,6 +72,27 @@ impl Debugger {
Debugger { engines }
}

pub fn get_all_regions(&self, db: DBType, cf: &str) -> Result<Vec<u64>> {
Copy link
Member

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?

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";
Copy link
Member

Choose a reason for hiding this comment

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

Use Path::join instead.

@hicqu
Copy link
Contributor Author

hicqu commented Oct 12, 2017

@BusyJay @overvenus , PTAL again, thanks.

use tikv::raftstore::store::debug::{Debugger, RegionInfo};
use tikv::storage::{ALL_CFS, CF_DEFAULT, CF_LOCK, CF_RAFT, CF_WRITE};

enum DebugExecutor {
Copy link
Contributor

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?

@@ -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>> {
Copy link
Member

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?

Copy link
Contributor Author

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?

None => dump_all_region_size(&db, cf_name),
let cfs = matches
.value_of("cf")
.map_or(ALL_CFS.to_vec(), |cf| vec![cf]);
Copy link
Member

Choose a reason for hiding this comment

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

map_or_else

println!("value: {}", value);
}

fn region_size(&self, region_id: u64, cfs: Vec<&str>) {
Copy link
Member

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.


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);
Copy link
Member

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?

@siddontang
Copy link
Contributor

PTAL @overvenus @BusyJay

I use some long options, for avoid name conflict.
@hicqu
Copy link
Contributor Author

hicqu commented Oct 13, 2017

@BusyJay @overvenus , PTAL thanks.

Arg::with_name("hex-to-escaped")
.short("h")
.long("from-hex")
Copy link
Member

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.

@@ -496,39 +503,44 @@ fn main() {
.about("print the range db range")
.arg(
Arg::with_name("from")
.short("f")
.long("from")
Copy link
Member

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.

host: Option<&str>,
) -> Box<DebugExecutor> {
match (host, db) {
(Some(_), Some(_)) => {
Copy link
Member

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.

}

trait DebugExecutor {
fn dump_key_value(&self, cf: &str, key: Vec<u8>) {
Copy link
Member

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.

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());
Copy link
Member

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);
Copy link
Member

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.

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.

@hicqu
Copy link
Contributor Author

hicqu commented Oct 16, 2017

@BusyJay @overvenus PTAL, thanks.

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 {
Copy link
Member

Choose a reason for hiding this comment

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

Why not -> !?

Copy link
Contributor Author

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.

Copy link
Member

@overvenus overvenus left a comment

Choose a reason for hiding this comment

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

LGTM

use tikv::storage::{ALL_CFS, CF_DEFAULT, CF_LOCK, CF_WRITE};

fn perror_and_exit<E: Error, T>(e: E) -> T {
eprintln!("{}", e);
Copy link
Member

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.

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.
Copy link
Member

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?

Copy link
Contributor Author

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.

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();
Copy link
Member

Choose a reason for hiding this comment

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

Why escape?

Copy link
Contributor Author

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.

Copy link
Member

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.

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));
Copy link
Member

Choose a reason for hiding this comment

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

Why not use "{:?}"?

return;
}
(Some(region_local_1), Some(region_local_2)) => {
let start_key = keys::data_key(region_local_1.get_region().get_start_key());
Copy link
Member

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 ==?

Copy link
Contributor Author

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.

Copy link
Member

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.

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);
Copy link
Member

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.

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);
Copy link
Member

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

Copy link
Contributor Author

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 DBIterators stop? I think it's OK if the future lib can deconstruct those DBIterators correctly.

Copy link
Contributor Author

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.

@@ -248,131 +705,78 @@ fn main() {
println!("{}", &unescape(escaped).to_hex().to_uppercase());
return;
}
_ => {}
Copy link
Member

Choose a reason for hiding this comment

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

Should use unreachable!().

Copy link
Member

@BusyJay BusyJay left a comment

Choose a reason for hiding this comment

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

rest LGTM

}
}
if cfs.contains(&CF_DEFAULT) {
for value_info in mvcc.take_values().into_iter() {
Copy link
Member

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?

Copy link
Contributor Author

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.

Copy link
Member

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()?

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 {
Copy link
Member

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.

@BusyJay
Copy link
Member

BusyJay commented Oct 17, 2017

LGTM, @zhangjinpeng1987 PTAL, you may have different thoughts on command diff_region.

@hicqu
Copy link
Contributor Author

hicqu commented Oct 18, 2017

@BusyJay @zhangjinpeng1987 , PTAL thanks.

@hicqu
Copy link
Contributor Author

hicqu commented Oct 18, 2017

/run-all-test

Copy link
Member

@zhangjinpeng87 zhangjinpeng87 left a comment

Choose a reason for hiding this comment

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

LGTM

@hicqu
Copy link
Contributor Author

hicqu commented Oct 18, 2017

/run-all-test

1 similar comment
@hicqu
Copy link
Contributor Author

hicqu commented Oct 18, 2017

/run-all-test

@hicqu hicqu merged commit e57a49c into master Oct 18, 2017
@hicqu hicqu deleted the qupeng/debug-client branch October 18, 2017 12:49
hicqu added a commit to hicqu/tikv that referenced this pull request Jan 10, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants