3434use crate :: container:: store:: LayerProgress ;
3535
3636use super :: * ;
37- use anyhow:: Context as _;
3837use containers_image_proxy:: { ImageProxy , OpenedImage } ;
3938use fn_error_context:: context;
40- use futures_util:: { Future , FutureExt , TryFutureExt as _ } ;
39+ use futures_util:: { Future , FutureExt } ;
4140use oci_spec:: image:: { self as oci_image, Digest } ;
41+ use std:: io:: Read ;
4242use std:: sync:: { Arc , Mutex } ;
4343use tokio:: {
4444 io:: { AsyncBufRead , AsyncRead } ,
@@ -191,80 +191,30 @@ pub async fn unencapsulate(repo: &ostree::Repo, imgref: &OstreeImageReference) -
191191 importer. unencapsulate ( ) . await
192192}
193193
194- /// Take an async AsyncBufRead and handle decompression for it, returning
195- /// a wrapped AsyncBufRead implementation.
196- /// This is implemented with a background thread using a pipe-to-self,
197- /// and so there is an additional Future object returned that is a "driver"
198- /// task and must also be checked for errors.
199- pub ( crate ) fn decompress_bridge (
200- src : impl tokio:: io:: AsyncBufRead + Send + Unpin + ' static ,
201- is_zstd : bool ,
202- ) -> Result < (
203- // This one is the input reader
204- impl tokio:: io:: AsyncBufRead + Send + Unpin + ' static ,
205- // And this represents the worker thread doing copying
206- impl Future < Output = Result < ( ) > > + Send + Unpin + ' static ,
207- ) > {
208- // We use a plain unix pipe() because it's just a very convenient
209- // way to bridge arbitrarily between sync and async with a worker
210- // thread. Yes, it involves going through the kernel, but
211- // eventually we'll replace all this logic with podman anyways.
212- let ( tx, rx) = tokio:: net:: unix:: pipe:: pipe ( ) ?;
213- let task = tokio:: task:: spawn_blocking ( move || -> Result < ( ) > {
214- // Convert the write half of the pipe() into a regular blocking file descriptor
215- let tx = tx. into_blocking_fd ( ) ?;
216- let mut tx = std:: fs:: File :: from ( tx) ;
217- // Convert the async input back to synchronous.
218- let src = tokio_util:: io:: SyncIoBridge :: new ( src) ;
219- let bufr = std:: io:: BufReader :: new ( src) ;
220- // Wrap the input in a decompressor; I originally tried to make
221- // this function take a function pointer, but yeah that was painful
222- // with the type system.
223- let mut src: Box < dyn std:: io:: Read > = if is_zstd {
224- Box :: new ( zstd:: stream:: read:: Decoder :: new ( bufr) ?)
225- } else {
226- Box :: new ( flate2:: bufread:: GzDecoder :: new ( bufr) )
227- } ;
228- // We don't care about the number of bytes copied
229- let _n: u64 = std:: io:: copy ( & mut src, & mut tx) . context ( "Copying for decompression" ) ?;
230- Ok ( ( ) )
231- } )
232- // Flatten the nested Result<Result<>>
233- . map ( crate :: tokio_util:: flatten_anyhow) ;
234- // And return the pair of futures
235- Ok ( ( tokio:: io:: BufReader :: new ( rx) , task) )
236- }
237-
238194/// Create a decompressor for this MIME type, given a stream of input.
239- fn new_async_decompressor (
195+ pub ( crate ) fn decompressor (
240196 media_type : & oci_image:: MediaType ,
241- src : impl AsyncBufRead + Send + Unpin + ' static ,
242- ) -> Result < (
243- Box < dyn AsyncBufRead + Send + Unpin + ' static > ,
244- impl Future < Output = Result < ( ) > > + Send + Unpin + ' static ,
245- ) > {
246- let r: (
247- Box < dyn AsyncBufRead + Send + Unpin + ' static > ,
248- Box < dyn Future < Output = Result < ( ) > > + Send + Unpin + ' static > ,
249- ) = match media_type {
197+ src : impl Read + Send + ' static ,
198+ ) -> Result < Box < dyn Read + Send + ' static > > {
199+ let r: Box < dyn std:: io:: Read + Send + ' static > = match media_type {
250200 m @ ( oci_image:: MediaType :: ImageLayerGzip | oci_image:: MediaType :: ImageLayerZstd ) => {
251- let is_zstd = matches ! ( m, oci_image:: MediaType :: ImageLayerZstd ) ;
252- let ( r, driver) = decompress_bridge ( src, is_zstd) ?;
253- ( Box :: new ( r) , Box :: new ( driver) as _ )
254- }
255- oci_image:: MediaType :: ImageLayer => {
256- ( Box :: new ( src) , Box :: new ( futures_util:: future:: ready ( Ok ( ( ) ) ) ) )
257- }
258- oci_image:: MediaType :: Other ( t) if t. as_str ( ) == DOCKER_TYPE_LAYER_TAR => {
259- ( Box :: new ( src) , Box :: new ( futures_util:: future:: ready ( Ok ( ( ) ) ) ) )
201+ if matches ! ( m, oci_image:: MediaType :: ImageLayerZstd ) {
202+ Box :: new ( zstd:: stream:: read:: Decoder :: new ( src) ?)
203+ } else {
204+ Box :: new ( flate2:: bufread:: GzDecoder :: new ( std:: io:: BufReader :: new (
205+ src,
206+ ) ) )
207+ }
260208 }
209+ oci_image:: MediaType :: ImageLayer => Box :: new ( src) ,
210+ oci_image:: MediaType :: Other ( t) if t. as_str ( ) == DOCKER_TYPE_LAYER_TAR => Box :: new ( src) ,
261211 o => anyhow:: bail!( "Unhandled layer type: {}" , o) ,
262212 } ;
263213 Ok ( r)
264214}
265215
266216/// A wrapper for [`get_blob`] which fetches a layer and decompresses it.
267- pub ( crate ) async fn fetch_layer_decompress < ' a > (
217+ pub ( crate ) async fn fetch_layer < ' a > (
268218 proxy : & ' a ImageProxy ,
269219 img : & OpenedImage ,
270220 manifest : & oci_image:: ImageManifest ,
@@ -275,12 +225,13 @@ pub(crate) async fn fetch_layer_decompress<'a>(
275225) -> Result < (
276226 Box < dyn AsyncBufRead + Send + Unpin > ,
277227 impl Future < Output = Result < ( ) > > + ' a ,
228+ oci_image:: MediaType ,
278229) > {
279230 use futures_util:: future:: Either ;
280231 tracing:: debug!( "fetching {}" , layer. digest( ) ) ;
281232 let layer_index = manifest. layers ( ) . iter ( ) . position ( |x| x == layer) . unwrap ( ) ;
282233 let ( blob, driver, size) ;
283- let media_type: & oci_image:: MediaType ;
234+ let media_type: oci_image:: MediaType ;
284235 match transport_src {
285236 Transport :: ContainerStorage => {
286237 let layer_info = layer_info
@@ -290,12 +241,12 @@ pub(crate) async fn fetch_layer_decompress<'a>(
290241 anyhow ! ( "blobid position {layer_index} exceeds diffid count {n_layers}" )
291242 } ) ?;
292243 size = layer_blob. size ;
293- media_type = & layer_blob. media_type ;
244+ media_type = layer_blob. media_type . clone ( ) ;
294245 ( blob, driver) = proxy. get_blob ( img, & layer_blob. digest , size) . await ?;
295246 }
296247 _ => {
297248 size = layer. size ( ) ;
298- media_type = layer. media_type ( ) ;
249+ media_type = layer. media_type ( ) . clone ( ) ;
299250 ( blob, driver) = proxy. get_blob ( img, layer. digest ( ) , size) . await ?;
300251 }
301252 } ;
@@ -316,13 +267,10 @@ pub(crate) async fn fetch_layer_decompress<'a>(
316267 progress. send_replace ( Some ( status) ) ;
317268 }
318269 } ;
319- let ( reader, compression_driver) = new_async_decompressor ( media_type, readprogress) ?;
320- let driver = driver. and_then ( |( ) | compression_driver) ;
270+ let reader = Box :: new ( readprogress) ;
321271 let driver = futures_util:: future:: join ( readproxy, driver) . map ( |r| r. 1 ) ;
322- Ok ( ( reader, Either :: Left ( driver) ) )
272+ Ok ( ( reader, Either :: Left ( driver) , media_type ) )
323273 } else {
324- let ( blob, compression_driver) = new_async_decompressor ( media_type, blob) ?;
325- let driver = driver. and_then ( |( ) | compression_driver) ;
326- Ok ( ( blob, Either :: Right ( driver) ) )
274+ Ok ( ( Box :: new ( blob) , Either :: Right ( driver) , media_type) )
327275 }
328276}
0 commit comments