@@ -22,7 +22,7 @@ use futures::StreamExt;
2222use tracing:: instrument;
2323
2424use crate :: backend:: { Vm , VmBackend } ;
25- use crate :: types:: { OutputSink , SnapshotId , VmConfig } ;
25+ use crate :: types:: { OutputSink , SnapshotId , SnapshotLabel , VmConfig } ;
2626
2727/// Docker-based VM backend.
2828///
@@ -308,20 +308,22 @@ impl Vm for DockerVm {
308308 }
309309
310310 #[ instrument( skip( self ) ) ]
311- async fn snapshot ( & mut self , label : & str ) -> Result < SnapshotId > {
311+ async fn snapshot ( & mut self , label : & SnapshotLabel ) -> Result < SnapshotId > {
312312 let cid = self
313313 . container_id
314314 . as_deref ( )
315315 . context ( "container already destroyed" ) ?;
316- let parts: Vec < & str > = label. splitn ( 2 , ':' ) . collect ( ) ;
317- // A bare label (no explicit `repo:tag`) is an ephemeral, uncached
318- // snapshot. Tag it with the unique container id rather than a shared
319- // `:latest`: concurrent sibling leaf steps off the same parent all
320- // commit ephemeral snapshots, and racing to write the same
321- // `ephemeral:latest` image fails the loser of the race in dockerd.
322- let ( repo, tag) = match parts. as_slice ( ) {
323- [ r, v] => ( * r, * v) ,
324- _ => ( label, cid) ,
316+ // An ephemeral, uncached snapshot is committed under a unique tag (the
317+ // container id) rather than a shared `:latest`: concurrent sibling leaf
318+ // steps off the same parent all commit ephemeral snapshots, and racing
319+ // to write the same `ephemeral:latest` image fails the loser of the
320+ // race in dockerd. A cached snapshot parses its cache key as `repo:tag`.
321+ let ( repo, tag) = match label {
322+ SnapshotLabel :: Ephemeral => ( "ephemeral" , cid) ,
323+ SnapshotLabel :: Cached ( key) => match key. split_once ( ':' ) {
324+ Some ( ( r, v) ) => ( r, v) ,
325+ None => ( key. as_str ( ) , cid) ,
326+ } ,
325327 } ;
326328 let opts = CommitContainerOptions {
327329 container : cid,
0 commit comments