@@ -124,6 +124,12 @@ func (l *safeLayer) DiffID() (v1.Hash, error) { return l.inner.DiffID
124124func (l * safeLayer ) Size () (int64 , error ) { return l .inner .Size () }
125125func (l * safeLayer ) MediaType () (types.MediaType , error ) { return l .inner .MediaType () }
126126
127+ // Compressed returns a reader for the layer's compressed bytes. If the layer is
128+ // already cached on disk (by digest), it opens and returns that file. Otherwise
129+ // it uses singleflight so only one goroutine calls the inner Compressed() and
130+ // drains the stream (allowing the inner cache to write the file); all callers
131+ // then wait for the file to be ready and open it. This avoids races when
132+ // multiple goroutines request the same layer.
127133func (l * safeLayer ) Compressed () (io.ReadCloser , error ) {
128134 digest , err := l .inner .Digest ()
129135 if err != nil {
@@ -133,12 +139,15 @@ func (l *safeLayer) Compressed() (io.ReadCloser, error) {
133139 if _ , err := os .Stat (path ); err == nil {
134140 return os .Open (path )
135141 }
142+ // Only one goroutine runs the inner work; others block on the same key.
136143 key := "compressed:" + digest .String ()
137144 v , err , _ := l .flight .Do (key , func () (any , error ) {
138145 rc , err := l .inner .Compressed ()
139146 if err != nil {
140147 return nil , err
141148 }
149+ // Drain the stream in a goroutine so the inner cache can write the file.
150+ // We signal when done so callers can open the file instead of the stream.
142151 ready := make (chan struct {})
143152 go func () {
144153 _ , _ = io .Copy (io .Discard , rc )
@@ -154,6 +163,9 @@ func (l *safeLayer) Compressed() (io.ReadCloser, error) {
154163 return os .Open (path )
155164}
156165
166+ // Uncompressed returns a reader for the layer's uncompressed bytes. Same pattern
167+ // as Compressed but uses diffID for the cache path and singleflight key, since
168+ // uncompressed content is keyed by diffID rather than digest.
157169func (l * safeLayer ) Uncompressed () (io.ReadCloser , error ) {
158170 diffID , err := l .inner .DiffID ()
159171 if err != nil {
@@ -163,12 +175,14 @@ func (l *safeLayer) Uncompressed() (io.ReadCloser, error) {
163175 if _ , err := os .Stat (path ); err == nil {
164176 return os .Open (path )
165177 }
178+ // Only one goroutine runs the inner work; others block on the same key.
166179 key := "uncompressed:" + diffID .String ()
167180 v , err , _ := l .flight .Do (key , func () (any , error ) {
168181 rc , err := l .inner .Uncompressed ()
169182 if err != nil {
170183 return nil , err
171184 }
185+ // Drain the stream in a goroutine so the inner cache can write the file.
172186 ready := make (chan struct {})
173187 go func () {
174188 _ , _ = io .Copy (io .Discard , rc )
0 commit comments