Skip to content

Commit 53196a8

Browse files
committed
Optimize write_vectored for BufWriter
If the underlying writer does not support efficient vectored output, do it differently: always try to coalesce the slices in the buffer until one comes that does not fit entirely. Flush the buffer before the first slice if needed.
1 parent 5d5ff84 commit 53196a8

File tree

1 file changed

+50
-12
lines changed

1 file changed

+50
-12
lines changed

library/std/src/io/buffered/bufwriter.rs

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -328,19 +328,57 @@ impl<W: Write> Write for BufWriter<W> {
328328
}
329329

330330
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
331-
let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
332-
if self.buf.len() + total_len > self.buf.capacity() {
333-
self.flush_buf()?;
334-
}
335-
// FIXME: Why no len > capacity? Why not buffer len == capacity? #72919
336-
if total_len >= self.buf.capacity() {
337-
self.panicked = true;
338-
let r = self.get_mut().write_vectored(bufs);
339-
self.panicked = false;
340-
r
331+
if self.get_ref().is_write_vectored() {
332+
let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
333+
if self.buf.len() + total_len > self.buf.capacity() {
334+
self.flush_buf()?;
335+
}
336+
if total_len >= self.buf.capacity() {
337+
self.panicked = true;
338+
let r = self.get_mut().write_vectored(bufs);
339+
self.panicked = false;
340+
r
341+
} else {
342+
bufs.iter().for_each(|b| self.buf.extend_from_slice(b));
343+
Ok(total_len)
344+
}
341345
} else {
342-
bufs.iter().for_each(|b| self.buf.extend_from_slice(b));
343-
Ok(total_len)
346+
let mut total_written = 0;
347+
let mut iter = bufs.iter();
348+
if let Some(buf) = iter.by_ref().find(|&buf| !buf.is_empty()) {
349+
// This is the first non-empty slice to write, so if it does
350+
// not fit in the buffer, we still get to flush and proceed.
351+
if self.buf.len() + buf.len() > self.buf.capacity() {
352+
self.flush_buf()?;
353+
}
354+
if buf.len() >= self.buf.capacity() {
355+
// The slice is at least as large as the buffering capacity,
356+
// so it's better to write it directly, bypassing the buffer.
357+
self.panicked = true;
358+
let r = self.get_mut().write(buf);
359+
self.panicked = false;
360+
return r;
361+
} else {
362+
self.buf.extend_from_slice(buf);
363+
total_written += buf.len();
364+
}
365+
debug_assert!(total_written != 0);
366+
}
367+
for buf in iter {
368+
if buf.len() >= self.buf.capacity() {
369+
// This slice should be written directly, but we have
370+
// already buffered some of the input. Bail out,
371+
// expecting it to be handled as the first slice in the
372+
// next call to write_vectored.
373+
break;
374+
} else {
375+
total_written += self.write_to_buf(buf);
376+
if self.buf.capacity() == self.buf.len() {
377+
break;
378+
}
379+
}
380+
}
381+
Ok(total_written)
344382
}
345383
}
346384

0 commit comments

Comments
 (0)