##// END OF EJS Templates
rust-status: add bare `hg status` support in hg-core...
rust-status: add bare `hg status` support in hg-core A lot of performance remains to be gained, most notably by doing more things in parallel, but also by caching, not falling back to Python but switching to another regex engine, etc.. I have measured on multiple repositories that this change, when in combination with the next two patches, improve bare `hg status` performance, and has no observable impact when falling back (because it does so early). On the Netbeans repository: C: 840ms Rust+C: 556ms Mozilla Central with the one pattern that causes a fallback removed: C: 2.315s Rust+C: 1.700 s Differential Revision: https://phab.mercurial-scm.org/D7929

File last commit:

r44270:ce088b38 default
r45015:c8891bca default
Show More
attachio.rs
114 lines | 3.7 KiB | application/rls-services+xml | RustLexer
// Copyright 2018 Yuya Nishihara <yuya@tcha.org>
//
// This software may be used and distributed according to the terms of the
// GNU General Public License version 2 or any later version.
//! Functions to send client-side fds over the command server channel.
use futures::{Async, Future, Poll};
use std::io;
use std::os::unix::io::AsRawFd;
use tokio_hglib::codec::ChannelMessage;
use tokio_hglib::protocol::MessageLoop;
use tokio_hglib::{Client, Connection};
use super::message;
use super::procutil;
/// Future to send client-side fds over the command server channel.
///
/// This works as follows:
/// 1. Client sends "attachio" request.
/// 2. Server sends back 1-byte input request.
/// 3. Client sends fds with 1-byte dummy payload in response.
/// 4. Server returns the number of the fds received.
///
/// If the stderr is omitted, it will be redirected to the stdout. This
/// allows us to attach the pager stdin to both stdout and stderr, and
/// dispose of the client-side handle once attached.
#[must_use = "futures do nothing unless polled"]
pub struct AttachIo<C, I, O, E>
where
C: Connection,
{
msg_loop: MessageLoop<C>,
stdin: I,
stdout: O,
stderr: Option<E>,
}
impl<C, I, O, E> AttachIo<C, I, O, E>
where
C: Connection + AsRawFd,
I: AsRawFd,
O: AsRawFd,
E: AsRawFd,
{
pub fn with_client(
client: Client<C>,
stdin: I,
stdout: O,
stderr: Option<E>,
) -> AttachIo<C, I, O, E> {
let msg_loop = MessageLoop::start(client, b"attachio");
AttachIo {
msg_loop,
stdin,
stdout,
stderr,
}
}
}
impl<C, I, O, E> Future for AttachIo<C, I, O, E>
where
C: Connection + AsRawFd,
I: AsRawFd,
O: AsRawFd,
E: AsRawFd,
{
type Item = Client<C>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
loop {
let (client, msg) = try_ready!(self.msg_loop.poll());
match msg {
ChannelMessage::Data(b'r', data) => {
let fd_cnt = message::parse_result_code(data)?;
if fd_cnt == 3 {
return Ok(Async::Ready(client));
} else {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"unexpected attachio result",
));
}
}
ChannelMessage::Data(..) => {
// just ignore data sent to uninteresting (optional) channel
self.msg_loop = MessageLoop::resume(client);
}
ChannelMessage::InputRequest(1) => {
// this may fail with EWOULDBLOCK in theory, but the
// payload is quite small, and the send buffer should
// be empty so the operation will complete immediately
let sock_fd = client.as_raw_fd();
let ifd = self.stdin.as_raw_fd();
let ofd = self.stdout.as_raw_fd();
let efd = self.stderr.as_ref().map_or(ofd, |f| f.as_raw_fd());
procutil::send_raw_fds(sock_fd, &[ifd, ofd, efd])?;
self.msg_loop = MessageLoop::resume(client);
}
ChannelMessage::InputRequest(..)
| ChannelMessage::LineRequest(..)
| ChannelMessage::SystemRequest(..) => {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"unsupported request while attaching io",
));
}
}
}
}
}