Skip to content

Commit c007d3e

Browse files
committed
cat: avoid pipe() if stdout is pipe
1 parent 00a2cb5 commit c007d3e

File tree

1 file changed

+33
-22
lines changed

1 file changed

+33
-22
lines changed

src/uu/cat/src/splice.rs

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,32 +24,43 @@ pub(super) fn write_fast_using_splice<R: FdReadable, S: AsRawFd + AsFd>(
2424
write_fd: &S,
2525
) -> CatResult<bool> {
2626
use nix::fcntl::{FcntlArg, fcntl};
27-
let (pipe_rd, pipe_wr) = pipe()?;
28-
// improve performance
29-
let _ = fcntl(
30-
write_fd,
31-
FcntlArg::F_SETPIPE_SZ(MAX_ROOTLESS_PIPE_SIZE as i32),
32-
);
33-
34-
loop {
35-
match splice(&handle.reader, &pipe_wr, MAX_ROOTLESS_PIPE_SIZE) {
36-
Ok(n) => {
37-
if n == 0 {
38-
return Ok(false);
27+
const FIRST_PIPE_SIZE: usize = 64 * 1024;
28+
if splice(&handle.reader, &write_fd, FIRST_PIPE_SIZE).is_ok() {
29+
// fcntl improves performance for large file which is large overhead for small files
30+
let _ = fcntl(
31+
write_fd,
32+
FcntlArg::F_SETPIPE_SZ(MAX_ROOTLESS_PIPE_SIZE as i32),
33+
);
34+
loop {
35+
match splice(&handle.reader, &write_fd, MAX_ROOTLESS_PIPE_SIZE) {
36+
Ok(1..) => {}
37+
Ok(0) => return Ok(false),
38+
Err(_) => return Ok(true),
39+
}
40+
}
41+
} else {
42+
// output is not pipe. Needs broker to use splice() which is high cost for small files
43+
let (pipe_rd, pipe_wr) = pipe()?;
44+
loop {
45+
match splice(&handle.reader, &pipe_wr, MAX_ROOTLESS_PIPE_SIZE) {
46+
Ok(n) => {
47+
if n == 0 {
48+
return Ok(false);
49+
}
50+
if splice_exact(&pipe_rd, write_fd, n).is_err() {
51+
// If the first splice manages to copy to the intermediate
52+
// pipe, but the second splice to stdout fails for some reason
53+
// we can recover by copying the data that we have from the
54+
// intermediate pipe to stdout using normal read/write. Then
55+
// we tell the caller to fall back.
56+
copy_exact(&pipe_rd, write_fd, n)?;
57+
return Ok(true);
58+
}
3959
}
40-
if splice_exact(&pipe_rd, write_fd, n).is_err() {
41-
// If the first splice manages to copy to the intermediate
42-
// pipe, but the second splice to stdout fails for some reason
43-
// we can recover by copying the data that we have from the
44-
// intermediate pipe to stdout using normal read/write. Then
45-
// we tell the caller to fall back.
46-
copy_exact(&pipe_rd, write_fd, n)?;
60+
Err(_) => {
4761
return Ok(true);
4862
}
4963
}
50-
Err(_) => {
51-
return Ok(true);
52-
}
5364
}
5465
}
5566
}

0 commit comments

Comments
 (0)