Skip to content

Commit 094e497

Browse files
Robert  Collinsrbtcollins
Robert Collins
authored andcommitted
Fixes rust-lang#2748 by filling the streaming buffers fully
Diagnosis by Daniel. Code by Robert.
1 parent 8e632bb commit 094e497

File tree

1 file changed

+23
-11
lines changed

1 file changed

+23
-11
lines changed

src/dist/component/package.rs

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//! for installing from a directory or tarball to an installation
33
//! prefix, represented by a `Components` instance.
44
5+
use std::cmp::min;
56
use std::collections::{HashMap, HashSet};
67
use std::fmt;
78
use std::io::{self, ErrorKind as IOErrorKind, Read};
@@ -364,16 +365,19 @@ fn unpack_without_first_dir<'a, R: Read>(
364365
continue;
365366
}
366367

368+
struct SenderEntry<'a, 'b, R: std::io::Read> {
369+
sender: Box<dyn FnMut(Vec<u8>) -> bool + 'a>,
370+
entry: tar::Entry<'b, R>,
371+
read: usize,
372+
}
373+
367374
/// true if either no sender_entry was provided, or the incremental file
368375
/// has been fully dispatched.
369376
fn flush_ios<'a, R: std::io::Read, P: AsRef<Path>>(
370377
mut budget: &mut MemoryBudget,
371378
io_executor: &dyn Executor,
372379
mut directories: &mut HashMap<PathBuf, DirStatus>,
373-
mut sender_entry: Option<&mut (
374-
Box<dyn FnMut(Vec<u8>) -> bool + 'a>,
375-
&mut tar::Entry<'_, R>,
376-
)>,
380+
mut sender_entry: Option<&mut SenderEntry<'a, '_, R>>,
377381
full_path: P,
378382
) -> Result<bool> {
379383
let mut result = sender_entry.is_none();
@@ -384,16 +388,19 @@ fn unpack_without_first_dir<'a, R: Read>(
384388
trigger_children(&*io_executor, &mut directories, &mut budget, op)?;
385389
}
386390
// Maybe stream a file incrementally
387-
if let Some((sender, entry)) = sender_entry.as_mut() {
391+
if let Some(sender) = sender_entry.as_mut() {
388392
if budget.available() as u64 >= IO_CHUNK_SIZE {
389-
let mut v = vec![0; IO_CHUNK_SIZE as usize];
390-
let len = entry.read(&mut v)?;
393+
let chunk_size = min(IO_CHUNK_SIZE, sender.entry.size() - sender.read as u64);
394+
let mut v = vec![0; chunk_size as usize];
395+
let len = v.len();
391396
if len == 0 {
392397
result = true;
398+
} else {
399+
sender.entry.read_exact(&mut v)?;
400+
sender.read += v.len();
393401
}
394-
v.resize(len, 0);
395402
budget.claim_chunk(len);
396-
if !sender(v) {
403+
if !(sender.sender)(v) {
397404
bail!(format!(
398405
"IO receiver for '{}' disconnected",
399406
full_path.as_ref().display()
@@ -519,8 +526,13 @@ fn unpack_without_first_dir<'a, R: Read>(
519526
}
520527
}
521528

522-
let mut incremental_file_sender = incremental_file_sender
523-
.map(|incremental_file_sender| (incremental_file_sender, &mut entry));
529+
let mut incremental_file_sender = incremental_file_sender.map(|incremental_file_sender| {
530+
(SenderEntry {
531+
sender: incremental_file_sender,
532+
entry,
533+
read: 0,
534+
})
535+
});
524536

525537
// monitor io queue and feed in the content of the file (if needed)
526538
while !flush_ios(

0 commit comments

Comments
 (0)