Files
buildkit/cache/blobs_linux_test.go
T
Tonis Tiigi 55e52126dc cache: serialize blob computation writers
Use the cache record ID as a stable ingest reference and wait for an
existing writer through content.OpenWriter. Retry external differ calls
on writer contention because their content writer is not directly
accessible.

Do not abort failed stable-reference ingests after closing them, as
another waiter may already own the transaction. Truncate resumed
ingests before recomputing and create fresh compressor state for every
differ attempt.

Also ensure the overlaybd and Windows differ paths release their writers
on failure.

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2026-09-21 15:57:50 -07:00

49 lines
1.2 KiB
Go

package cache
import (
"testing"
"github.com/containerd/containerd/v2/core/content"
"github.com/containerd/containerd/v2/core/mount"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
)
func TestTryComputeOverlayBlobWaitsForStableRef(t *testing.T) {
t.Parallel()
expected := errors.New("truncate failed")
writer := &truncateFailureWriter{err: expected}
store := &retryWriterStore{failures: 2, writer: writer}
sr := &immutableRef{cacheRecord: &cacheRecord{cm: &cacheManager{ContentStore: store}}}
_, ok, err := sr.tryComputeOverlayBlob(t.Context(), nil, []mount.Mount{{Type: "bind", Source: t.TempDir()}}, "application/test", "record", nil)
require.ErrorIs(t, err, expected)
require.False(t, ok)
require.Equal(t, []string{"record", "record", "record"}, store.references())
require.True(t, writer.closed)
require.Zero(t, store.abortCount(), "a stable ingest reference must not be aborted after close")
}
func (s *retryWriterStore) abortCount() int {
s.mu.Lock()
defer s.mu.Unlock()
return s.aborts
}
type truncateFailureWriter struct {
content.Writer
err error
closed bool
}
func (w *truncateFailureWriter) Truncate(int64) error {
return w.err
}
func (w *truncateFailureWriter) Close() error {
w.closed = true
return nil
}