uucore: simplify fallback when splice failed

This commit is contained in:
oech3
2026-04-21 00:26:03 +09:00
committed by Daniel Hofstetter
parent 29982b242d
commit 50957e1319
2 changed files with 8 additions and 47 deletions
-14
View File
@@ -51,20 +51,6 @@ mod tests {
.unwrap()
}
#[cfg(any(target_os = "linux", target_os = "android"))]
#[test]
fn test_copy_exact() {
let (mut pipe_read, mut pipe_write) = pipes::pipe().unwrap();
let data = b"Hello, world!";
let n = pipe_write.write(data).unwrap();
assert_eq!(n, data.len());
let mut buf = [0; 1024];
let n = copy_exact(&pipe_read, &pipe_write, data.len()).unwrap();
let n2 = pipe_read.read(&mut buf).unwrap();
assert_eq!(n, n2);
assert_eq!(&buf[..n], data);
}
#[test]
#[cfg(unix)]
fn test_copy_stream() {
+8 -33
View File
@@ -28,8 +28,6 @@ pub trait FdWritable: Write + AsFd + AsRawFd {}
impl<T> FdWritable for T where T: Write + AsFd + AsRawFd {}
const BUF_SIZE: usize = 1024 * 16;
/// Conversion from a `rustix::io::Errno` into our `Error` which implements `UError`.
impl From<rustix::io::Errno> for Error {
fn from(error: rustix::io::Errno) -> Self {
@@ -55,7 +53,7 @@ where
{
// If we're on Linux or Android, try to use the splice() system call
// for faster writing. If it works, we're done.
if !splice_write(src, &dest.as_fd())? {
if !splice_write(src, dest)? {
return Ok(());
}
@@ -78,17 +76,17 @@ where
/// - `source` - source handle
/// - `dest` - destination handle
#[inline]
pub(crate) fn splice_write<R, S>(source: &R, dest: &S) -> UResult<bool>
pub(crate) fn splice_write<R, S>(source: &R, dest: &mut S) -> UResult<bool>
where
R: Read + AsFd + AsRawFd,
S: AsRawFd + AsFd,
S: AsRawFd + AsFd + Write,
{
let (pipe_rd, pipe_wr) = pipe()?;
let (pipe_rd, pipe_wr) = pipe()?; // todo: bypass this if input or output is pipe. We use this mostly for stream.
// improve throughput
// no need to increase pipe size of input fd since
// - sender with splice probably increased size already
// - sender without splice is bottleneck
let _ = rustix::pipe::fcntl_setpipe_size(dest, MAX_ROOTLESS_PIPE_SIZE);
let _ = rustix::pipe::fcntl_setpipe_size(&mut *dest, MAX_ROOTLESS_PIPE_SIZE);
loop {
match splice(&source, &pipe_wr, MAX_ROOTLESS_PIPE_SIZE) {
@@ -100,7 +98,9 @@ where
// we can recover by copying the data that we have from the
// intermediate pipe to stdout using normal read/write. Then
// we tell the caller to fall back.
copy_exact(&pipe_rd, dest, n)?;
let mut drain = Vec::with_capacity(n); // bounded by pipe size
pipe_rd.take(n as u64).read_to_end(&mut drain)?;
dest.write_all(&drain)?;
return Ok(true);
}
}
@@ -108,28 +108,3 @@ where
}
}
}
/// Move exactly `num_bytes` bytes from `read_fd` to `write_fd` using the `read`
/// and `write` calls.
#[cfg(any(target_os = "linux", target_os = "android"))]
pub(crate) fn copy_exact(
read_fd: &impl AsFd,
write_fd: &impl AsFd,
num_bytes: usize,
) -> std::io::Result<usize> {
let mut left = num_bytes;
let mut buf = [0; BUF_SIZE];
let mut total_written = 0;
while left > 0 {
let n_read = rustix::io::read(read_fd, &mut buf)?;
assert_ne!(n_read, 0, "unexpected end of pipe");
let mut written = 0;
while written < n_read {
let n = rustix::io::write(write_fd, &buf[written..n_read])?;
written += n;
}
total_written += written;
left -= n_read;
}
Ok(total_written)
}