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
debug: add scan_mvcc support. #2335
Conversation
@overvenus , PTAL, thanks. |
src/server/service/debug.rs
Outdated
Ok(_) => Ok(dealer.0.unwrap()), | ||
Err(e) => Err((dealer.0.unwrap(), e)), | ||
}; | ||
future::result(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.
I think result
is enough.
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.
pool.spawn_fn
requires a closure returning Future
, so I believe we need future::result(...)
.
src/raftstore/store/debug.rs
Outdated
fn mvcc_kvs(&self, cf: CfName, from: Vec<u8>, to: Vec<u8>) -> Receiver<Kv> { | ||
let (tx, rx) = channel::<Kv>(); | ||
let db = self.engines.kv_engine.clone(); | ||
thread::spawn(move || -> 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.
Please spawn threads with names.
src/raftstore/store/debug.rs
Outdated
let db = self.engines.kv_engine.clone(); | ||
thread::spawn(move || -> Result<()> { | ||
for kv in &mut try!(gen_mvcc_iter(db.as_ref(), cf, &from, &to)) { | ||
box_try!(tx.send(kv)); |
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 if let Err(_) = tx.send() { 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.
We also need to call gen_mvcc_iter
in the thread closure, which also returns a Result
.
So let the closure return a Result
is better?
src/server/service/debug.rs
Outdated
mvcc_resp.set_info(mvcc); | ||
|
||
let sink = self.0.take().unwrap(); | ||
match sink.send((mvcc_resp, WriteFlags::default())).wait() { |
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.
Attach an RpcContext
to MvccKVToSink
and spawn the sink.send()
, so that we dont need to call wait()
.
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.
Because sink.send
is called in other threads in pool
and RpcContext
can't Send
, I think we can't do this.
src/server/service/debug.rs
Outdated
Ok(mut sink) => { | ||
let f = future::poll_fn(move || sink.close()) | ||
.map_err(|e| Service::on_grpc_error("scan_mvcc", e)); | ||
Box::new(f) as Box<Future<Item = (), Error = ()> + Send> |
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 spawning f
here is fine.
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 tried but the RpcContext
is not Send
, so I can't call ctx.spawn(f)
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.
I mean call ctx.spwan()
here, so f
does not need to cast a BoxFuture
.
src/raftstore/store/debug.rs
Outdated
let (tx, rx) = channel::<Kv>(); | ||
let db = self.engines.kv_engine.clone(); | ||
thread::Builder::new() | ||
.name(format!("scan_mvcc_{}", 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.
I think you can use thd_name!()
.
src/raftstore/store/debug.rs
Outdated
@@ -151,6 +166,206 @@ impl Debugger { | |||
Err(e) => Err(box_err!(e)), | |||
} | |||
} | |||
|
|||
pub fn scan_mvcc<D, E>(&self, req: ScanMvccRequest, dealer: &mut D) -> 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.
How about passing a futures::sync::mpsc::UnboundedSender<MvccInfo>
?
let (tx, rx) = unbounded();
self
.pool
.spwan(
ok(self.debugger.clone())
.and_then(|debugger| debugger.scan_mvcc(req, tx)
)
.forgot();
let f = sink.send_all(rx).and_then(|sink| poll_fn(sink.close()));
ctx.spawn(f);
src/raftstore/store/debug.rs
Outdated
#[test] | ||
fn test_scan_mvcc() { | ||
struct MvccCounter(usize); | ||
impl MvccKVDealer for MvccCounter { |
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 add a test in test_servics.rs .
@overvenus , Now we don't need useless |
@BusyJay , PTAL, thanks. |
PTAL @BusyJay @overvenus |
src/raftstore/store/debug.rs
Outdated
if limit != 0 && count >= limit { | ||
break; | ||
} | ||
if count >= 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.
Remove it.
src/raftstore/store/debug.rs
Outdated
|
||
let mut mvcc_infos: BTreeMap<Vec<u8>, (MvccInfo, bool, bool, bool)> = BTreeMap::new(); | ||
let (mut want_lock, mut want_default, mut want_write) = (true, true, true); | ||
let (mut m_l, mut m_d, mut m_w) = (None, None, None); |
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 need a better name.
src/raftstore/store/debug.rs
Outdated
break; | ||
} | ||
if want_lock { | ||
if let Ok(kv) = lock_rx.recv() { |
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 can use select!()
[1].
src/raftstore/store/debug.rs
Outdated
} | ||
want_write = false; | ||
} | ||
for key in mvcc_infos.keys().cloned().collect::<Vec<_>>() { |
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 entry()
[1]?
[1] https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.entry
src/raftstore/store/debug.rs
Outdated
want_write = false; | ||
} | ||
for key in mvcc_infos.keys().cloned().collect::<Vec<_>>() { | ||
let mvcc_and_flags = mvcc_infos.remove(&key).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.
See also OccupiedEntry::remove_entry()
[1].
[1] https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.entry
src/raftstore/store/debug.rs
Outdated
} | ||
m_w = Some(key); | ||
} else { | ||
m_w = Some(vec![0xffu8]); |
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 '0xffu8' mean?
/run-all-test |
@BusyJay , PTAL, thanks. |
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
@BusyJay PTAL thanks. |
PTAL @BusyJay |
src/raftstore/store/debug.rs
Outdated
/// Compact the cf[start..end) in the db **by manual**. | ||
pub fn scan_mvcc(&self, mut req: ScanMvccRequest) -> Result<MvccInfoIterator> { | ||
let from_key = req.take_from_key(); | ||
let to_key = Some(req.take_to_key()).into_iter().find(|k| !k.is_empty()); |
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 if else instead.
src/server/service/debug.rs
Outdated
.map(|_| ()) | ||
}) | ||
.map_err(|e| Service::on_grpc_error("scan_mvcc", &e)) | ||
.wait(); |
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 wait?
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.
Because DBIterator
is !Send
so that we can't use it directly in spawn
.
src/server/service/debug.rs
Outdated
.wait(); | ||
result | ||
}; | ||
self.pool.spawn_fn(future).forget(); |
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.
You can use spawn
instead of spawn_fn
.
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 spawn
needs a Future
instead of Closure returns Future
. But if the future contains any DBIterator
, it can't be Send
, so that it can't spawn
.
@BusyJay , PTAL thanks. |
@BusyJay , PTAL, thanks. |
LGTM, though I think |
/run-integration-tests |
PTAL @overvenus |
… qupeng/debug-scan-mvcc
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/raftstore/store/debug.rs
Outdated
mvcc_info.set_values(values); | ||
}, | ||
Ordering::Greater => {} | ||
_ => 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.
If there is a bug, it's reachable. So should return all those keys instead of panic.
src/raftstore/store/keys.rs
Outdated
@@ -199,6 +200,11 @@ pub fn origin_key(key: &[u8]) -> &[u8] { | |||
&key[DATA_PREFIX_KEY.len()..] | |||
} | |||
|
|||
/// The caller should ensure the key is a timestamped key. | |||
pub fn truncate_ts(key: &[u8]) -> &[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.
The function should be put in types.rs
. All function in this file has nothing related to MVCC.
@overvenus , PTAL again, thanks. |
}, | ||
Ordering::Greater => {} | ||
_ => { | ||
let err_msg = format!( |
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.
/cc @disksing, is an error message or listing all the related kvs better help with debuging?
/run-all-test |
This PR add support for debug ScanMvcc API.