Skip to content

Commit 7593910

Browse files
authored
Merge pull request #1247 from jeckersb/decompressor-flush-on-drop
unencapsulate: Wrap decompressor and implement Drop
2 parents c94cfdf + f45bfeb commit 7593910

File tree

2 files changed

+38
-22
lines changed

2 files changed

+38
-22
lines changed

ostree-ext/src/container/unencapsulate.rs

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,47 @@ pub async fn unencapsulate(repo: &ostree::Repo, imgref: &OstreeImageReference) -
191191
importer.unencapsulate().await
192192
}
193193

194+
pub(crate) struct Decompressor {
195+
inner: Box<dyn Read + Send + 'static>,
196+
}
197+
198+
impl Read for Decompressor {
199+
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
200+
self.inner.read(buf)
201+
}
202+
}
203+
204+
impl Drop for Decompressor {
205+
fn drop(&mut self) {
206+
// We need to make sure to flush out the decompressor and/or
207+
// tar stream here. For tar, we might not read through the
208+
// entire stream, because the archive has zero-block-markers
209+
// at the end; or possibly because the final entry is filtered
210+
// in filter_tar so we don't advance to read the data. For
211+
// decompressor, zstd:chunked layers will have
212+
// metadata/skippable frames at the end of the stream. That
213+
// data isn't relevant to the tar stream, but if we don't read
214+
// it here then on the skopeo proxy we'll block trying to
215+
// write the end of the stream. That in turn will block our
216+
// client end trying to call FinishPipe, and we end up
217+
// deadlocking ourselves through skopeo.
218+
//
219+
// https://github.com/bootc-dev/bootc/issues/1204
220+
221+
let mut sink = std::io::sink();
222+
match std::io::copy(&mut self.inner, &mut sink) {
223+
Err(e) => tracing::debug!("Ignoring error while dropping decompressor: {e}"),
224+
Ok(0) => { /* We already read everything and are happy */ }
225+
Ok(n) => tracing::debug!("Read extra {n} bytes at end of decompressor stream"),
226+
}
227+
}
228+
}
229+
194230
/// Create a decompressor for this MIME type, given a stream of input.
195231
pub(crate) fn decompressor(
196232
media_type: &oci_image::MediaType,
197233
src: impl Read + Send + 'static,
198-
) -> Result<Box<dyn Read + Send + 'static>> {
234+
) -> Result<Decompressor> {
199235
let r: Box<dyn std::io::Read + Send + 'static> = match media_type {
200236
oci_image::MediaType::ImageLayerZstd => Box::new(zstd::stream::read::Decoder::new(src)?),
201237
oci_image::MediaType::ImageLayerGzip => Box::new(flate2::bufread::GzDecoder::new(
@@ -205,7 +241,7 @@ pub(crate) fn decompressor(
205241
oci_image::MediaType::Other(t) if t.as_str() == DOCKER_TYPE_LAYER_TAR => Box::new(src),
206242
o => anyhow::bail!("Unhandled layer type: {}", o),
207243
};
208-
Ok(r)
244+
Ok(Decompressor { inner: r })
209245
}
210246

211247
/// A wrapper for [`get_blob`] which fetches a layer and decompresses it.

ostree-ext/src/tar/write.rs

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -367,26 +367,6 @@ async fn filter_tar_async(
367367

368368
let r = filter_tar(&mut src, dest, &config, &repo_tmpdir);
369369

370-
// We need to make sure to flush out the decompressor and/or
371-
// tar stream here. For tar, we might not read through the
372-
// entire stream, because the archive has zero-block-markers
373-
// at the end; or possibly because the final entry is filtered
374-
// in filter_tar so we don't advance to read the data. For
375-
// decompressor, zstd:chunked layers will have
376-
// metadata/skippable frames at the end of the stream. That
377-
// data isn't relevant to the tar stream, but if we don't read
378-
// it here then on the skopeo proxy we'll block trying to
379-
// write the end of the stream. That in turn will block our
380-
// client end trying to call FinishPipe, and we end up
381-
// deadlocking ourselves through skopeo.
382-
//
383-
// https://github.com/bootc-dev/bootc/issues/1204
384-
let mut sink = std::io::sink();
385-
let n = std::io::copy(&mut src, &mut sink)?;
386-
if n != 0 {
387-
tracing::debug!("Read extra {n} bytes at end of decompressor stream");
388-
}
389-
390370
Ok(r)
391371
});
392372
let copier = tokio::io::copy(&mut rx_buf, &mut dest);

0 commit comments

Comments
 (0)