Make extraction cancellable for bin and tar based formats ()

Extraction wasn't cancellable by `cancel_on_user_sig_term` used in `entry` since it calls `block_in_place`.

This PR adds cancellation support to it by adding a `static` variable `OnceCell` to `wait_on_cancellation_signal` so that once it returns `Ok(())`, all other calls to it after that point also returns `Ok(())` immediately.

`StreamReadable`, which is used in cancellation process, then stores a boxed future of `wait_on_cancellation_signal` and polled it in `BufReader::fill_buf`.

Note that for zip, the extraction process takes `File` instead of `StreamReadable` due to `io::Seek` requirement, so it cancelling during extraction for zip is still not possible.

This PR also optimized `extract_bin` and `extract_zip` by using `StreamReadable::copy` introduced to this PR instead of `io::copy`, which allocates an internal buffer on stack, which imposes extra copy.

It also fixed `StreamReadable::fill_buf` by ensuring that empty buffer is only returned on eof.

* Make `wait_on_cancellation_signal` pub
* Enable feature `parking_lot` of dep tokio
* Mod `wait_on_cancellation_signal`: Use `OnceCell` internally
   to archive the effect that once call to it return `Ok(())`, all calls to
   it after that also returns `Ok(())`.
* Impl `From<BinstallError>` for `io::Error`
* Impl cancellation on user signal in `StreamReadable`
* Fix err msg when cancelling during extraction in `ops::resolve`
* Optimize: Impl & use `StreamReadable::copy`
   which is same as `io::copy` but does not allocate any internal buffer
   since `StreamReadable` is buffered.
* Fix `next_stream`: Return non-empty bytes on `Ok(Some(bytes))`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
Jiahao XU 2022-10-13 11:31:13 +11:00 committed by GitHub
parent fdc617d870
commit aa6012baae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 109 additions and 20 deletions
crates/binstalk/src

View file

@ -1,4 +1,5 @@
use std::{
io,
path::PathBuf,
process::{ExitCode, ExitStatus, Termination},
};
@ -99,7 +100,7 @@ pub enum BinstallError {
/// - Exit: 74
#[error(transparent)]
#[diagnostic(severity(error), code(binstall::io))]
Io(std::io::Error),
Io(io::Error),
/// An error interacting with the crates.io API.
///
@ -392,8 +393,8 @@ impl Termination for BinstallError {
}
}
impl From<std::io::Error> for BinstallError {
fn from(err: std::io::Error) -> Self {
impl From<io::Error> for BinstallError {
fn from(err: io::Error) -> Self {
if err.get_ref().is_some() {
let kind = err.kind();
@ -404,9 +405,18 @@ impl From<std::io::Error> for BinstallError {
inner
.downcast()
.map(|b| *b)
.unwrap_or_else(|err| BinstallError::Io(std::io::Error::new(kind, err)))
.unwrap_or_else(|err| BinstallError::Io(io::Error::new(kind, err)))
} else {
BinstallError::Io(err)
}
}
}
impl From<BinstallError> for io::Error {
fn from(e: BinstallError) -> io::Error {
match e {
BinstallError::Io(io_error) => io_error,
e => io::Error::new(io::ErrorKind::Other, e),
}
}
}