leverage file locks for cache index.json

Signed-off-by: Avi Deitcher <avi@deitcher.net>
This commit is contained in:
Avi Deitcher 2025-06-26 18:12:08 +03:00
parent e6a1de1330
commit 9e4d499119
3 changed files with 41 additions and 2 deletions

View File

@ -6,13 +6,19 @@ package cache
import (
"errors"
"fmt"
"path/filepath"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/match"
"github.com/linuxkit/linuxkit/src/cmd/linuxkit/util"
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
log "github.com/sirupsen/logrus"
)
const (
indexFile = "index.json"
)
// DescriptorWrite writes a descriptor to the cache index; it validates that it has a name
// and replaces any existing one
func (p *Provider) DescriptorWrite(image string, desc v1.Descriptor) error {
@ -25,6 +31,17 @@ func (p *Provider) DescriptorWrite(image string, desc v1.Descriptor) error {
desc.Annotations[imagespec.AnnotationRefName] = image
log.Debugf("writing descriptor for image %s", image)
// get our lock
lock, err := util.Lock(filepath.Join(p.dir, indexFile))
if err != nil {
return fmt.Errorf("unable to lock cache index for writing descriptor for %s: %v", image, err)
}
defer func() {
if err := lock.Unlock(); err != nil {
log.Errorf("unable to close lock for cache index after writing descriptor for %s: %v", image, err)
}
}()
// do we update an existing one? Or create a new one?
if err := p.cache.RemoveDescriptors(match.Name(image)); err != nil {
return fmt.Errorf("unable to remove old descriptors for %s: %v", image, err)
@ -40,6 +57,15 @@ func (p *Provider) DescriptorWrite(image string, desc v1.Descriptor) error {
// RemoveDescriptors removes all descriptors that match the provided matcher.
// It does so in a parallel-access-safe way
func (p *Provider) RemoveDescriptors(matcher match.Matcher) error {
// will be replaced with locking
// get our lock
lock, err := util.Lock(filepath.Join(p.dir, indexFile))
if err != nil {
return fmt.Errorf("unable to lock cache index for removing descriptor for %v: %v", matcher, err)
}
defer func() {
if err := lock.Unlock(); err != nil {
log.Errorf("unable to close lock for cache index after writing descriptor for %v: %v", matcher, err)
}
}()
return p.cache.RemoveDescriptors(matcher)
}

View File

@ -2,9 +2,12 @@ package cache
import (
"fmt"
"path/filepath"
"github.com/google/go-containerregistry/pkg/v1/empty"
"github.com/google/go-containerregistry/pkg/v1/layout"
"github.com/linuxkit/linuxkit/src/cmd/linuxkit/util"
log "github.com/sirupsen/logrus"
)
// Get get or initialize the cache
@ -12,6 +15,15 @@ func Get(cache string) (layout.Path, error) {
// initialize the cache path if needed
p, err := layout.FromPath(cache)
if err != nil {
lock, err := util.Lock(filepath.Join(cache, indexFile))
if err != nil {
return "", fmt.Errorf("unable to lock cache index for writing descriptor for new cache: %v", err)
}
defer func() {
if err := lock.Unlock(); err != nil {
log.Errorf("unable to close lock for cache index after writing descriptor for new cache: %v", err)
}
}()
p, err = layout.Write(cache, empty.Index)
if err != nil {
return p, fmt.Errorf("could not initialize cache at path %s: %v", cache, err)

View File

@ -10,6 +10,7 @@ import (
type Provider struct {
cache layout.Path
store content.Store
dir string
}
// NewProvider create a new CacheProvider based in the provided directory
@ -22,5 +23,5 @@ func NewProvider(dir string) (*Provider, error) {
if err != nil {
return nil, err
}
return &Provider{p, store}, nil
return &Provider{p, store, dir}, nil
}