Attempted to add new feature flag: `memfile-size-output`: Which will pre- or post- set the size of `stdout` to the correct buffer size, allowing consumers of `collect`"s stdout pipe to know the size just like a file. However, `ftruncate()` always fails on stdout. Before re-enabling the feature, we must find out how to set the size of a pipe, if/when you even can, and what syscall(s) you need to do it with.
# Decreases memory-handling function calls, resulting in less "used" memory and faster allocation speeds at the "cost" of mapping a huge amount of virtual memory.
# Decreases memory-handling function calls, resulting in less "used" memory and faster allocation speeds at the "cost" of mapping a huge amount of virtual memory.
error!("Size too large (over max by {}) (max {})",to-(i64::MAXasu64),i64::MAX);
}else{
trace!("Setting {fd} size to {to}");
}
}
ifcfg!(debug_assertions){
i64::try_from(to).map_err(|_|io::Error::new(io::ErrorKind::InvalidInput,"Size too large for ftruncate() offset"))?
}else{
toasi64
}
};
matchunsafe{ftruncate(fd,to)}{
-1=>Err(io::Error::last_os_error()),
_=>Ok(())
}
}
//TODO: How to `ftruncate()` stdout only once... If try_get_size succeeds, we want to do it then. If it doesn't, we want to do it when `stdin` as been consumed an we know the size of the memory-file... `RunOnce` won't work unless we can give it an argument....
#[allow(unused_mut)]
letmutset_stdout_len={
cfg_if!{
if#[cfg(feature="memfile-size-output")]{
if_trace!(warn!("Feature `memfile-size-output` is not yet stable and will cause crash."));
constSTDOUT: memfile::fd::RawFileDescriptor=unsafe{memfile::fd::RawFileDescriptor::new_unchecked(libc::STDOUT_FILENO)};//TODO: Get this from `std::io::Stdout.as_raw_fd()` instead.
//TODO: XXX: Even if this actually works, is it safe to do this? Won't the consumer try to read `value` bytes before we've written them? Perhaps remove pre-setting entirely...
matchbuffsz{
y@Some(refvalue)=>{
letvalue=value.get();
set_stdout_len(value).wrap_err("Failed to set stdout len to that of stdin")
.with_section(||value.header("Stdin len was calculated as"))
.with_warning(||"This is a pre-setting")?;
y
},
n=>n,
}
}else{buffsz}.or_else(DEFAULT_BUFFER_SIZE);
if_trace!(ifletSome(buf)=buffsz.as_ref(){
if_trace!(ifletSome(buf)=buffsz.as_ref(){
trace!("Failed to determine input size: preallocating to {}",buf);
trace!("Failed to determine input size: preallocating to {}",buf);
}else{
}else{
@ -305,6 +428,11 @@ mod work {
};
};
if_trace!(info!("collected {} from stdin. starting write.",read));
if_trace!(info!("collected {} from stdin. starting write.",read));
// TODO: XXX: Currently causes crash. But if we can get this to work, leaving this in is definitely safe (as opposed to the pre-setting (see above.))
set_stdout_len(read)
.wrap_err(eyre!("Failed to `ftruncate()` stdout after collection of {read} bytes"))
.with_note(||"Was not pre-set")?;
letwritten=
letwritten=
io::copy(&mutfile,&mutio::stdout().lock())
io::copy(&mutfile,&mutio::stdout().lock())
.with_section(||read.header("Bytes read from stdin"))
.with_section(||read.header("Bytes read from stdin"))