diff --git a/containers.go b/containers.go index 9d8b9fa038..d7af80ad29 100644 --- a/containers.go +++ b/containers.go @@ -68,11 +68,24 @@ type Container struct { // rwContainerStore provides bookkeeping for information about Containers. type rwContainerStore interface { - fileBasedStore metadataStore containerBigDataStore flaggableStore + // startWriting makes sure the store is fresh, and locks it for writing. + // If this succeeds, the caller MUST call stopWriting(). + startWriting() error + + // stopWriting releases locks obtained by startWriting. + stopWriting() + + // startReading makes sure the store is fresh, and locks it for reading. + // If this succeeds, the caller MUST call stopReading(). + startReading() error + + // stopReading releases locks obtained by startReading. + stopReading() + // Create creates a container that has a specified ID (or generates a // random one if an empty value is supplied) and optional names, // based on the specified image, using the specified layer as its @@ -173,6 +186,77 @@ func (c *Container) MountOpts() []string { } } +// startWritingWithReload makes sure the store is fresh if canReload, and locks it for writing. +// If this succeeds, the caller MUST call stopWriting(). +// +// This is an internal implementation detail of containerStore construction, every other caller +// should use startWriting() instead. +func (r *containerStore) startWritingWithReload(canReload bool) error { + r.lockfile.Lock() + succeeded := false + defer func() { + if !succeeded { + r.lockfile.Unlock() + } + }() + + if canReload { + if err := r.reloadIfChanged(); err != nil { + return err + } + } + + succeeded = true + return nil +} + +// startWriting makes sure the store is fresh, and locks it for writing. +// If this succeeds, the caller MUST call stopWriting(). +func (r *containerStore) startWriting() error { + return r.startWritingWithReload(true) +} + +// stopWriting releases locks obtained by startWriting. +func (r *containerStore) stopWriting() { + r.lockfile.Unlock() +} + +// startReading makes sure the store is fresh, and locks it for reading. +// If this succeeds, the caller MUST call stopReading(). +func (r *containerStore) startReading() error { + r.lockfile.RLock() + succeeded := false + defer func() { + if !succeeded { + r.lockfile.Unlock() + } + }() + + if err := r.reloadIfChanged(); err != nil { + return err + } + + succeeded = true + return nil +} + +// stopReading releases locks obtained by startReading. +func (r *containerStore) stopReading() { + r.lockfile.Unlock() +} + +// reloadIfChanged reloads the contents of the store from disk if it is changed. +func (r *containerStore) reloadIfChanged() error { + r.loadMut.Lock() + defer r.loadMut.Unlock() + + modified, err := r.lockfile.Modified() + if err == nil && modified { + return r.load() + } + return err +} + func (r *containerStore) Containers() ([]Container, error) { containers := make([]Container, len(r.containers)) for i := range r.containers { @@ -193,7 +277,9 @@ func (r *containerStore) datapath(id, key string) string { return filepath.Join(r.datadir(id), makeBigDataBaseName(key)) } -func (r *containerStore) Load() error { +// load reloads the contents of the store from disk. It should be called +// with the lock held. +func (r *containerStore) load() error { needSave := false rpath := r.containerspath() data, err := os.ReadFile(rpath) @@ -226,13 +312,15 @@ func (r *containerStore) Load() error { r.bylayer = layers r.byname = names if needSave { - return r.Save() + return r.save() } return nil } -func (r *containerStore) Save() error { - if !r.Locked() { +// save saves the contents of the store to disk. It should be called with +// the lock held. +func (r *containerStore) save() error { + if !r.lockfile.Locked() { return errors.New("container store is not locked") } rpath := r.containerspath() @@ -246,7 +334,7 @@ func (r *containerStore) Save() error { if err := ioutils.AtomicWriteFile(rpath, jdata, 0600); err != nil { return err } - return r.Touch() + return r.lockfile.Touch() } func newContainerStore(dir string) (rwContainerStore, error) { @@ -265,9 +353,11 @@ func newContainerStore(dir string) (rwContainerStore, error) { bylayer: make(map[string]*Container), byname: make(map[string]*Container), } - cstore.Lock() - defer cstore.Unlock() - if err := cstore.Load(); err != nil { + if err := cstore.startWritingWithReload(false); err != nil { + return nil, err + } + defer cstore.stopWriting() + if err := cstore.load(); err != nil { return nil, err } return &cstore, nil @@ -294,7 +384,7 @@ func (r *containerStore) ClearFlag(id string, flag string) error { return ErrContainerUnknown } delete(container.Flags, flag) - return r.Save() + return r.save() } func (r *containerStore) SetFlag(id string, flag string, value interface{}) error { @@ -306,7 +396,7 @@ func (r *containerStore) SetFlag(id string, flag string, value interface{}) erro container.Flags = make(map[string]interface{}) } container.Flags[flag] = value - return r.Save() + return r.save() } func (r *containerStore) Create(id string, names []string, image, layer, metadata string, options *ContainerOptions) (container *Container, err error) { @@ -363,7 +453,7 @@ func (r *containerStore) Create(id string, names []string, image, layer, metadat for _, name := range names { r.byname[name] = container } - err = r.Save() + err = r.save() container = copyContainer(container) } return container, err @@ -379,7 +469,7 @@ func (r *containerStore) Metadata(id string) (string, error) { func (r *containerStore) SetMetadata(id, metadata string) error { if container, ok := r.lookup(id); ok { container.Metadata = metadata - return r.Save() + return r.save() } return ErrContainerUnknown } @@ -421,7 +511,7 @@ func (r *containerStore) updateNames(id string, names []string, op updateNameOpe r.byname[name] = container } container.Names = names - return r.Save() + return r.save() } func (r *containerStore) Delete(id string) error { @@ -453,7 +543,7 @@ func (r *containerStore) Delete(id string) error { r.containers = append(r.containers[:toDeleteIndex], r.containers[toDeleteIndex+1:]...) } } - if err := r.Save(); err != nil { + if err := r.save(); err != nil { return err } if err := os.RemoveAll(r.datadir(id)); err != nil { @@ -600,7 +690,7 @@ func (r *containerStore) SetBigData(id, key string, data []byte) error { save = true } if save { - err = r.Save() + err = r.save() } } return err @@ -618,46 +708,3 @@ func (r *containerStore) Wipe() error { } return nil } - -func (r *containerStore) Lock() { - r.lockfile.Lock() -} - -func (r *containerStore) RLock() { - r.lockfile.RLock() -} - -func (r *containerStore) Unlock() { - r.lockfile.Unlock() -} - -func (r *containerStore) Touch() error { - return r.lockfile.Touch() -} - -func (r *containerStore) Modified() (bool, error) { - return r.lockfile.Modified() -} - -func (r *containerStore) IsReadWrite() bool { - return r.lockfile.IsReadWrite() -} - -func (r *containerStore) TouchedSince(when time.Time) bool { - return r.lockfile.TouchedSince(when) -} - -func (r *containerStore) Locked() bool { - return r.lockfile.Locked() -} - -func (r *containerStore) ReloadIfChanged() error { - r.loadMut.Lock() - defer r.loadMut.Unlock() - - modified, err := r.Modified() - if err == nil && modified { - return r.Load() - } - return err -} diff --git a/images.go b/images.go index 50559f0dca..6cb9a630bd 100644 --- a/images.go +++ b/images.go @@ -96,10 +96,16 @@ type Image struct { // roImageStore provides bookkeeping for information about Images. type roImageStore interface { - roFileBasedStore roMetadataStore roBigDataStore + // startReading makes sure the store is fresh, and locks it for reading. + // If this succeeds, the caller MUST call stopReading(). + startReading() error + + // stopReading releases locks obtained by startReading. + stopReading() + // Exists checks if there is an image with the given ID or name. Exists(id string) bool @@ -119,11 +125,17 @@ type roImageStore interface { // rwImageStore provides bookkeeping for information about Images. type rwImageStore interface { roImageStore - rwFileBasedStore rwMetadataStore rwImageBigDataStore flaggableStore + // startWriting makes sure the store is fresh, and locks it for writing. + // If this succeeds, the caller MUST call stopWriting(). + startWriting() error + + // stopWriting releases locks obtained by startWriting. + stopWriting() + // Create creates an image that has a specified ID (or a random one) and // optional names, using the specified layer as its topmost (hopefully // read-only) layer. That layer can be referenced by multiple images. @@ -193,6 +205,88 @@ func copyImageSlice(slice []*Image) []*Image { return nil } +// startWritingWithReload makes sure the store is fresh if canReload, and locks it for writing. +// If this succeeds, the caller MUST call stopWriting(). +// +// This is an internal implementation detail of imageStore construction, every other caller +// should use startReading() instead. +func (r *imageStore) startWritingWithReload(canReload bool) error { + r.lockfile.Lock() + succeeded := false + defer func() { + if !succeeded { + r.lockfile.Unlock() + } + }() + + if canReload { + if err := r.reloadIfChanged(); err != nil { + return err + } + } + + succeeded = true + return nil +} + +// startWriting makes sure the store is fresh, and locks it for writing. +// If this succeeds, the caller MUST call stopWriting(). +func (r *imageStore) startWriting() error { + return r.startWritingWithReload(false) +} + +// stopWriting releases locks obtained by startWriting. +func (r *imageStore) stopWriting() { + r.lockfile.Unlock() +} + +// startReadingWithReload makes sure the store is fresh if canReload, and locks it for reading. +// If this succeeds, the caller MUST call stopReading(). +// +// This is an internal implementation detail of imageStore construction, every other caller +// should use startReading() instead. +func (r *imageStore) startReadingWithReload(canReload bool) error { + r.lockfile.RLock() + succeeded := false + defer func() { + if !succeeded { + r.lockfile.Unlock() + } + }() + + if canReload { + if err := r.reloadIfChanged(); err != nil { + return err + } + } + + succeeded = true + return nil +} + +// startReading makes sure the store is fresh, and locks it for reading. +// If this succeeds, the caller MUST call stopReading(). +func (r *imageStore) startReading() error { + return r.startReadingWithReload(true) +} + +// stopReading releases locks obtained by startReading. +func (r *imageStore) stopReading() { + r.lockfile.Unlock() +} + +// reloadIfChanged reloads the contents of the store from disk if it is changed. +func (r *imageStore) reloadIfChanged() error { + r.loadMut.Lock() + defer r.loadMut.Unlock() + + modified, err := r.lockfile.Modified() + if err == nil && modified { + return r.load() + } + return err +} + func (r *imageStore) Images() ([]Image, error) { images := make([]Image, len(r.images)) for i := range r.images { @@ -253,7 +347,9 @@ func (i *Image) recomputeDigests() error { return nil } -func (r *imageStore) Load() error { +// load reloads the contents of the store from disk. It should be called +// with the lock held. +func (r *imageStore) load() error { shouldSave := false rpath := r.imagespath() data, err := os.ReadFile(rpath) @@ -288,10 +384,10 @@ func (r *imageStore) Load() error { list := digests[digest] digests[digest] = append(list, image) } - image.ReadOnly = !r.IsReadWrite() + image.ReadOnly = !r.lockfile.IsReadWrite() } } - if shouldSave && (!r.IsReadWrite() || !r.Locked()) { + if shouldSave && (!r.lockfile.IsReadWrite() || !r.lockfile.Locked()) { return ErrDuplicateImageNames } r.images = images @@ -300,16 +396,18 @@ func (r *imageStore) Load() error { r.byname = names r.bydigest = digests if shouldSave { - return r.Save() + return r.save() } return nil } -func (r *imageStore) Save() error { - if !r.IsReadWrite() { +// save saves the contents of the store to disk. It should be called with +// the lock held. +func (r *imageStore) save() error { + if !r.lockfile.IsReadWrite() { return fmt.Errorf("not allowed to modify the image store at %q: %w", r.imagespath(), ErrStoreIsReadOnly) } - if !r.Locked() { + if !r.lockfile.Locked() { return errors.New("image store is not locked for writing") } rpath := r.imagespath() @@ -323,7 +421,7 @@ func (r *imageStore) Save() error { if err := ioutils.AtomicWriteFile(rpath, jdata, 0600); err != nil { return err } - return r.Touch() + return r.lockfile.Touch() } func newImageStore(dir string) (rwImageStore, error) { @@ -342,9 +440,11 @@ func newImageStore(dir string) (rwImageStore, error) { byname: make(map[string]*Image), bydigest: make(map[digest.Digest][]*Image), } - istore.Lock() - defer istore.Unlock() - if err := istore.Load(); err != nil { + if err := istore.startWritingWithReload(false); err != nil { + return nil, err + } + defer istore.stopWriting() + if err := istore.load(); err != nil { return nil, err } return &istore, nil @@ -363,9 +463,11 @@ func newROImageStore(dir string) (roImageStore, error) { byname: make(map[string]*Image), bydigest: make(map[digest.Digest][]*Image), } - istore.RLock() - defer istore.Unlock() - if err := istore.Load(); err != nil { + if err := istore.startReadingWithReload(false); err != nil { + return nil, err + } + defer istore.stopReading() + if err := istore.load(); err != nil { return nil, err } return &istore, nil @@ -384,7 +486,7 @@ func (r *imageStore) lookup(id string) (*Image, bool) { } func (r *imageStore) ClearFlag(id string, flag string) error { - if !r.IsReadWrite() { + if !r.lockfile.IsReadWrite() { return fmt.Errorf("not allowed to clear flags on images at %q: %w", r.imagespath(), ErrStoreIsReadOnly) } image, ok := r.lookup(id) @@ -392,11 +494,11 @@ func (r *imageStore) ClearFlag(id string, flag string) error { return fmt.Errorf("locating image with ID %q: %w", id, ErrImageUnknown) } delete(image.Flags, flag) - return r.Save() + return r.save() } func (r *imageStore) SetFlag(id string, flag string, value interface{}) error { - if !r.IsReadWrite() { + if !r.lockfile.IsReadWrite() { return fmt.Errorf("not allowed to set flags on images at %q: %w", r.imagespath(), ErrStoreIsReadOnly) } image, ok := r.lookup(id) @@ -407,11 +509,11 @@ func (r *imageStore) SetFlag(id string, flag string, value interface{}) error { image.Flags = make(map[string]interface{}) } image.Flags[flag] = value - return r.Save() + return r.save() } func (r *imageStore) Create(id string, names []string, layer, metadata string, created time.Time, searchableDigest digest.Digest) (image *Image, err error) { - if !r.IsReadWrite() { + if !r.lockfile.IsReadWrite() { return nil, fmt.Errorf("not allowed to create new images at %q: %w", r.imagespath(), ErrStoreIsReadOnly) } if id == "" { @@ -464,7 +566,7 @@ func (r *imageStore) Create(id string, names []string, layer, metadata string, c list := r.bydigest[digest] r.bydigest[digest] = append(list, image) } - err = r.Save() + err = r.save() image = copyImage(image) return image, err } @@ -472,7 +574,7 @@ func (r *imageStore) Create(id string, names []string, layer, metadata string, c func (r *imageStore) addMappedTopLayer(id, layer string) error { if image, ok := r.lookup(id); ok { image.MappedTopLayers = append(image.MappedTopLayers, layer) - return r.Save() + return r.save() } return fmt.Errorf("locating image with ID %q: %w", id, ErrImageUnknown) } @@ -485,7 +587,7 @@ func (r *imageStore) removeMappedTopLayer(id, layer string) error { if initialLen == len(image.MappedTopLayers) { return nil } - return r.Save() + return r.save() } return fmt.Errorf("locating image with ID %q: %w", id, ErrImageUnknown) } @@ -498,12 +600,12 @@ func (r *imageStore) Metadata(id string) (string, error) { } func (r *imageStore) SetMetadata(id, metadata string) error { - if !r.IsReadWrite() { + if !r.lockfile.IsReadWrite() { return fmt.Errorf("not allowed to modify image metadata at %q: %w", r.imagespath(), ErrStoreIsReadOnly) } if image, ok := r.lookup(id); ok { image.Metadata = metadata - return r.Save() + return r.save() } return fmt.Errorf("locating image with ID %q: %w", id, ErrImageUnknown) } @@ -530,7 +632,7 @@ func (r *imageStore) RemoveNames(id string, names []string) error { } func (r *imageStore) updateNames(id string, names []string, op updateNameOperation) error { - if !r.IsReadWrite() { + if !r.lockfile.IsReadWrite() { return fmt.Errorf("not allowed to change image name assignments at %q: %w", r.imagespath(), ErrStoreIsReadOnly) } image, ok := r.lookup(id) @@ -553,11 +655,11 @@ func (r *imageStore) updateNames(id string, names []string, op updateNameOperati image.addNameToHistory(name) } image.Names = names - return r.Save() + return r.save() } func (r *imageStore) Delete(id string) error { - if !r.IsReadWrite() { + if !r.lockfile.IsReadWrite() { return fmt.Errorf("not allowed to delete images at %q: %w", r.imagespath(), ErrStoreIsReadOnly) } image, ok := r.lookup(id) @@ -594,7 +696,7 @@ func (r *imageStore) Delete(id string) error { r.images = append(r.images[:toDeleteIndex], r.images[toDeleteIndex+1:]...) } } - if err := r.Save(); err != nil { + if err := r.save(); err != nil { return err } if err := os.RemoveAll(r.datadir(id)); err != nil { @@ -693,7 +795,7 @@ func (r *imageStore) SetBigData(id, key string, data []byte, digestManifest func if key == "" { return fmt.Errorf("can't set empty name for image big data item: %w", ErrInvalidBigDataName) } - if !r.IsReadWrite() { + if !r.lockfile.IsReadWrite() { return fmt.Errorf("not allowed to save data items associated with images at %q: %w", r.imagespath(), ErrStoreIsReadOnly) } image, ok := r.lookup(id) @@ -767,14 +869,14 @@ func (r *imageStore) SetBigData(id, key string, data []byte, digestManifest func } } if save { - err = r.Save() + err = r.save() } } return err } func (r *imageStore) Wipe() error { - if !r.IsReadWrite() { + if !r.lockfile.IsReadWrite() { return fmt.Errorf("not allowed to delete images at %q: %w", r.imagespath(), ErrStoreIsReadOnly) } ids := make([]string, 0, len(r.byid)) @@ -788,46 +890,3 @@ func (r *imageStore) Wipe() error { } return nil } - -func (r *imageStore) Lock() { - r.lockfile.Lock() -} - -func (r *imageStore) RLock() { - r.lockfile.RLock() -} - -func (r *imageStore) Unlock() { - r.lockfile.Unlock() -} - -func (r *imageStore) Touch() error { - return r.lockfile.Touch() -} - -func (r *imageStore) Modified() (bool, error) { - return r.lockfile.Modified() -} - -func (r *imageStore) IsReadWrite() bool { - return r.lockfile.IsReadWrite() -} - -func (r *imageStore) TouchedSince(when time.Time) bool { - return r.lockfile.TouchedSince(when) -} - -func (r *imageStore) Locked() bool { - return r.lockfile.Locked() -} - -func (r *imageStore) ReloadIfChanged() error { - r.loadMut.Lock() - defer r.loadMut.Unlock() - - modified, err := r.Modified() - if err == nil && modified { - return r.Load() - } - return err -} diff --git a/images_test.go b/images_test.go index 01594c11fa..016c5639d2 100644 --- a/images_test.go +++ b/images_test.go @@ -16,10 +16,11 @@ func newTestImageStore(t *testing.T) rwImageStore { } func addTestImage(t *testing.T, store rwImageStore, id string, names []string) { - store.Lock() - defer store.Unlock() + err := store.startWriting() + require.NoError(t, err) + defer store.stopWriting() - _, err := store.Create( + _, err = store.Create( id, []string{}, "", "", time.Now(), digest.FromString(""), ) @@ -70,8 +71,8 @@ func TestHistoryNames(t *testing.T) { require.Equal(t, secondImage.NamesHistory[1], "2") // And When - store.Lock() - defer store.Unlock() + require.NoError(t, store.startWriting()) + defer store.stopWriting() require.Nil(t, store.SetNames(firstImageID, []string{"1", "2", "3", "4"})) // Then diff --git a/layers.go b/layers.go index e1fa41ea60..f16e32727e 100644 --- a/layers.go +++ b/layers.go @@ -141,10 +141,16 @@ type DiffOptions struct { // name, and keeping track of parent-child relationships, along with a list of // all known layers. type roLayerStore interface { - roFileBasedStore roMetadataStore roLayerBigDataStore + // startReading makes sure the store is fresh, and locks it for reading. + // If this succeeds, the caller MUST call stopReading(). + startReading() error + + // stopReading releases locks obtained by startReading. + stopReading() + // Exists checks if a layer with the specified name or ID is known. Exists(id string) bool @@ -194,11 +200,17 @@ type roLayerStore interface { // all known layers. type rwLayerStore interface { roLayerStore - rwFileBasedStore rwMetadataStore flaggableStore rwLayerBigDataStore + // startWriting makes sure the store is fresh, and locks it for writing. + // If this succeeds, the caller MUST call stopWriting(). + startWriting() error + + // stopWriting releases locks obtained by startWriting. + stopWriting() + // Create creates a new layer, optionally giving it a specified ID rather than // a randomly-generated one, either inheriting data from another specified // layer or the empty base layer. The new layer can optionally be given names @@ -314,6 +326,122 @@ func copyLayer(l *Layer) *Layer { } } +// startWritingWithReload makes sure the store is fresh if canReload, and locks it for writing. +// If this succeeds, the caller MUST call stopWriting(). +// +// This is an internal implementation detail of layerStore construction, every other caller +// should use startWriting() instead. +func (r *layerStore) startWritingWithReload(canReload bool) error { + r.lockfile.Lock() + succeeded := false + defer func() { + if !succeeded { + r.lockfile.Unlock() + } + }() + + if canReload { + if err := r.reloadIfChanged(); err != nil { + return err + } + } + + succeeded = true + return nil +} + +// startWriting makes sure the store is fresh, and locks it for writing. +// If this succeeds, the caller MUST call stopWriting(). +func (r *layerStore) startWriting() error { + return r.startWritingWithReload(false) +} + +// stopWriting releases locks obtained by startWriting. +func (r *layerStore) stopWriting() { + r.lockfile.Unlock() +} + +// startReadingWithReload makes sure the store is fresh if canReload, and locks it for reading. +// If this succeeds, the caller MUST call stopReading(). +// +// This is an internal implementation detail of layerStore construction, every other caller +// should use startReading() instead. +func (r *layerStore) startReadingWithReload(canReload bool) error { + r.lockfile.RLock() + succeeded := false + defer func() { + if !succeeded { + r.lockfile.Unlock() + } + }() + + if canReload { + if err := r.reloadIfChanged(); err != nil { + return err + } + } + + succeeded = true + return nil +} + +// startReading makes sure the store is fresh, and locks it for reading. +// If this succeeds, the caller MUST call stopReading(). +func (r *layerStore) startReading() error { + return r.startReadingWithReload(true) +} + +// stopReading releases locks obtained by startReading. +func (r *layerStore) stopReading() { + r.lockfile.Unlock() +} + +// modified() checks if the most recent writer was a party other than the +// last recorded writer. It should only be called with the lock held. +func (r *layerStore) modified() (bool, error) { + var mmodified, tmodified bool + lmodified, err := r.lockfile.Modified() + if err != nil { + return lmodified, err + } + if r.lockfile.IsReadWrite() { + r.mountsLockfile.RLock() + defer r.mountsLockfile.Unlock() + mmodified, err = r.mountsLockfile.Modified() + if err != nil { + return lmodified, err + } + } + + if lmodified || mmodified { + return true, nil + } + + // If the layers.json file has been modified manually, then we have to + // reload the storage in any case. + info, err := os.Stat(r.layerspath()) + if err != nil && !os.IsNotExist(err) { + return false, fmt.Errorf("stat layers file: %w", err) + } + if info != nil { + tmodified = info.ModTime() != r.layerspathModified + } + + return tmodified, nil +} + +// reloadIfChanged reloads the contents of the store from disk if it is changed. +func (r *layerStore) reloadIfChanged() error { + r.loadMut.Lock() + defer r.loadMut.Unlock() + + modified, err := r.modified() + if err == nil && modified { + return r.load() + } + return err +} + func (r *layerStore) Layers() ([]Layer, error) { layers := make([]Layer, len(r.layers)) for i := range r.layers { @@ -330,7 +458,9 @@ func (r *layerStore) layerspath() string { return filepath.Join(r.layerdir, "layers.json") } -func (r *layerStore) Load() error { +// load reloads the contents of the store from disk. It should be called +// with the lock held. +func (r *layerStore) load() error { shouldSave := false rpath := r.layerspath() info, err := os.Stat(rpath) @@ -351,7 +481,7 @@ func (r *layerStore) Load() error { names := make(map[string]*Layer) compressedsums := make(map[digest.Digest][]string) uncompressedsums := make(map[digest.Digest][]string) - if r.IsReadWrite() { + if r.lockfile.IsReadWrite() { selinux.ClearLabels() } if err = json.Unmarshal(data, &layers); len(data) == 0 || err == nil { @@ -375,11 +505,11 @@ func (r *layerStore) Load() error { if layer.MountLabel != "" { selinux.ReserveLabel(layer.MountLabel) } - layer.ReadOnly = !r.IsReadWrite() + layer.ReadOnly = !r.lockfile.IsReadWrite() } err = nil } - if shouldSave && (!r.IsReadWrite() || !r.Locked()) { + if shouldSave && (!r.lockfile.IsReadWrite() || !r.lockfile.Locked()) { return ErrDuplicateLayerNames } r.layers = layers @@ -390,7 +520,7 @@ func (r *layerStore) Load() error { r.byuncompressedsum = uncompressedsums // Load and merge information about which layers are mounted, and where. - if r.IsReadWrite() { + if r.lockfile.IsReadWrite() { r.mountsLockfile.RLock() defer r.mountsLockfile.Unlock() if err = r.loadMounts(); err != nil { @@ -400,7 +530,7 @@ func (r *layerStore) Load() error { // Last step: as we’re writable, try to remove anything that a previous // user of this storage area marked for deletion but didn't manage to // actually delete. - if r.Locked() { + if r.lockfile.Locked() { for _, layer := range r.layers { if layer.Flags == nil { layer.Flags = make(map[string]interface{}) @@ -460,7 +590,9 @@ func (r *layerStore) loadMounts() error { return err } -func (r *layerStore) Save() error { +// save saves the contents of the store to disk. It should be called with +// the lock held. +func (r *layerStore) save() error { r.mountsLockfile.Lock() defer r.mountsLockfile.Unlock() if err := r.saveLayers(); err != nil { @@ -470,10 +602,10 @@ func (r *layerStore) Save() error { } func (r *layerStore) saveLayers() error { - if !r.IsReadWrite() { + if !r.lockfile.IsReadWrite() { return fmt.Errorf("not allowed to modify the layer store at %q: %w", r.layerspath(), ErrStoreIsReadOnly) } - if !r.Locked() { + if !r.lockfile.Locked() { return errors.New("layer store is not locked for writing") } rpath := r.layerspath() @@ -487,11 +619,11 @@ func (r *layerStore) saveLayers() error { if err := ioutils.AtomicWriteFile(rpath, jldata, 0600); err != nil { return err } - return r.Touch() + return r.lockfile.Touch() } func (r *layerStore) saveMounts() error { - if !r.IsReadWrite() { + if !r.lockfile.IsReadWrite() { return fmt.Errorf("not allowed to modify the layer store at %q: %w", r.layerspath(), ErrStoreIsReadOnly) } if !r.mountsLockfile.Locked() { @@ -549,9 +681,11 @@ func (s *store) newLayerStore(rundir string, layerdir string, driver drivers.Dri bymount: make(map[string]*Layer), byname: make(map[string]*Layer), } - rlstore.Lock() - defer rlstore.Unlock() - if err := rlstore.Load(); err != nil { + if err := rlstore.startWritingWithReload(false); err != nil { + return nil, err + } + defer rlstore.stopWriting() + if err := rlstore.load(); err != nil { return nil, err } return &rlstore, nil @@ -572,9 +706,11 @@ func newROLayerStore(rundir string, layerdir string, driver drivers.Driver) (roL bymount: make(map[string]*Layer), byname: make(map[string]*Layer), } - rlstore.RLock() - defer rlstore.Unlock() - if err := rlstore.Load(); err != nil { + if err := rlstore.startReadingWithReload(false); err != nil { + return nil, err + } + defer rlstore.stopReading() + if err := rlstore.load(); err != nil { return nil, err } return &rlstore, nil @@ -607,7 +743,7 @@ func (r *layerStore) Size(name string) (int64, error) { } func (r *layerStore) ClearFlag(id string, flag string) error { - if !r.IsReadWrite() { + if !r.lockfile.IsReadWrite() { return fmt.Errorf("not allowed to clear flags on layers at %q: %w", r.layerspath(), ErrStoreIsReadOnly) } layer, ok := r.lookup(id) @@ -615,11 +751,11 @@ func (r *layerStore) ClearFlag(id string, flag string) error { return ErrLayerUnknown } delete(layer.Flags, flag) - return r.Save() + return r.save() } func (r *layerStore) SetFlag(id string, flag string, value interface{}) error { - if !r.IsReadWrite() { + if !r.lockfile.IsReadWrite() { return fmt.Errorf("not allowed to set flags on layers at %q: %w", r.layerspath(), ErrStoreIsReadOnly) } layer, ok := r.lookup(id) @@ -630,7 +766,7 @@ func (r *layerStore) SetFlag(id string, flag string, value interface{}) error { layer.Flags = make(map[string]interface{}) } layer.Flags[flag] = value - return r.Save() + return r.save() } func (r *layerStore) Status() ([][2]string, error) { @@ -684,7 +820,7 @@ func (r *layerStore) PutAdditionalLayer(id string, parentLayer *Layer, names []s if layer.UncompressedDigest != "" { r.byuncompressedsum[layer.UncompressedDigest] = append(r.byuncompressedsum[layer.UncompressedDigest], layer.ID) } - if err := r.Save(); err != nil { + if err := r.save(); err != nil { if err2 := r.driver.Remove(id); err2 != nil { logrus.Errorf("While recovering from a failure to save layers, error deleting layer %#v: %v", id, err2) } @@ -694,7 +830,7 @@ func (r *layerStore) PutAdditionalLayer(id string, parentLayer *Layer, names []s } func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLabel string, options map[string]string, moreOptions *LayerOptions, writeable bool, flags map[string]interface{}, diff io.Reader) (*Layer, int64, error) { - if !r.IsReadWrite() { + if !r.lockfile.IsReadWrite() { return nil, -1, fmt.Errorf("not allowed to create new layers at %q: %w", r.layerspath(), ErrStoreIsReadOnly) } if err := os.MkdirAll(r.rundir, 0700); err != nil { @@ -812,7 +948,7 @@ func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLab } }() - err := r.Save() + err := r.save() if err != nil { cleanupFailureContext = "saving incomplete layer metadata" return nil, -1, err @@ -878,7 +1014,7 @@ func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLab } } delete(layer.Flags, incompleteFlag) - err = r.Save() + err = r.save() if err != nil { cleanupFailureContext = "saving finished layer metadata" return nil, -1, err @@ -899,7 +1035,7 @@ func (r *layerStore) Create(id string, parent *Layer, names []string, mountLabel } func (r *layerStore) Mounted(id string) (int, error) { - if !r.IsReadWrite() { + if !r.lockfile.IsReadWrite() { return 0, fmt.Errorf("no mount information for layers at %q: %w", r.mountspath(), ErrStoreIsReadOnly) } r.mountsLockfile.RLock() @@ -929,7 +1065,7 @@ func (r *layerStore) Mount(id string, options drivers.MountOpts) (string, error) // You are not allowed to mount layers from readonly stores if they // are not mounted read/only. - if !r.IsReadWrite() && !hasReadOnlyOpt(options.Options) { + if !r.lockfile.IsReadWrite() && !hasReadOnlyOpt(options.Options) { return "", fmt.Errorf("not allowed to update mount locations for layers at %q: %w", r.mountspath(), ErrStoreIsReadOnly) } r.mountsLockfile.Lock() @@ -979,7 +1115,7 @@ func (r *layerStore) Mount(id string, options drivers.MountOpts) (string, error) } func (r *layerStore) Unmount(id string, force bool) (bool, error) { - if !r.IsReadWrite() { + if !r.lockfile.IsReadWrite() { return false, fmt.Errorf("not allowed to update mount locations for layers at %q: %w", r.mountspath(), ErrStoreIsReadOnly) } r.mountsLockfile.Lock() @@ -1017,7 +1153,7 @@ func (r *layerStore) Unmount(id string, force bool) (bool, error) { } func (r *layerStore) ParentOwners(id string) (uids, gids []int, err error) { - if !r.IsReadWrite() { + if !r.lockfile.IsReadWrite() { return nil, nil, fmt.Errorf("no mount information for layers at %q: %w", r.mountspath(), ErrStoreIsReadOnly) } r.mountsLockfile.RLock() @@ -1105,7 +1241,7 @@ func (r *layerStore) RemoveNames(id string, names []string) error { } func (r *layerStore) updateNames(id string, names []string, op updateNameOperation) error { - if !r.IsReadWrite() { + if !r.lockfile.IsReadWrite() { return fmt.Errorf("not allowed to change layer name assignments at %q: %w", r.layerspath(), ErrStoreIsReadOnly) } layer, ok := r.lookup(id) @@ -1127,7 +1263,7 @@ func (r *layerStore) updateNames(id string, names []string, op updateNameOperati r.byname[name] = layer } layer.Names = names - return r.Save() + return r.save() } func (r *layerStore) datadir(id string) string { @@ -1153,7 +1289,7 @@ func (r *layerStore) SetBigData(id, key string, data io.Reader) error { if key == "" { return fmt.Errorf("can't set empty name for layer big data item: %w", ErrInvalidBigDataName) } - if !r.IsReadWrite() { + if !r.lockfile.IsReadWrite() { return fmt.Errorf("not allowed to save data items associated with layers at %q: %w", r.layerspath(), ErrStoreIsReadOnly) } layer, ok := r.lookup(id) @@ -1191,7 +1327,7 @@ func (r *layerStore) SetBigData(id, key string, data io.Reader) error { } if addName { layer.BigDataNames = append(layer.BigDataNames, key) - return r.Save() + return r.save() } return nil } @@ -1212,12 +1348,12 @@ func (r *layerStore) Metadata(id string) (string, error) { } func (r *layerStore) SetMetadata(id, metadata string) error { - if !r.IsReadWrite() { + if !r.lockfile.IsReadWrite() { return fmt.Errorf("not allowed to modify layer metadata at %q: %w", r.layerspath(), ErrStoreIsReadOnly) } if layer, ok := r.lookup(id); ok { layer.Metadata = metadata - return r.Save() + return r.save() } return ErrLayerUnknown } @@ -1238,7 +1374,7 @@ func layerHasIncompleteFlag(layer *Layer) bool { } func (r *layerStore) deleteInternal(id string) error { - if !r.IsReadWrite() { + if !r.lockfile.IsReadWrite() { return fmt.Errorf("not allowed to delete layers at %q: %w", r.layerspath(), ErrStoreIsReadOnly) } layer, ok := r.lookup(id) @@ -1251,7 +1387,7 @@ func (r *layerStore) deleteInternal(id string) error { layer.Flags = make(map[string]interface{}) } layer.Flags[incompleteFlag] = true - if err := r.Save(); err != nil { + if err := r.save(); err != nil { return err } } @@ -1354,7 +1490,7 @@ func (r *layerStore) Delete(id string) error { if err := r.deleteInternal(id); err != nil { return err } - return r.Save() + return r.save() } func (r *layerStore) Exists(id string) bool { @@ -1370,7 +1506,7 @@ func (r *layerStore) Get(id string) (*Layer, error) { } func (r *layerStore) Wipe() error { - if !r.IsReadWrite() { + if !r.lockfile.IsReadWrite() { return fmt.Errorf("not allowed to delete layers at %q: %w", r.layerspath(), ErrStoreIsReadOnly) } ids := make([]string, 0, len(r.byid)) @@ -1635,7 +1771,7 @@ func (r *layerStore) ApplyDiff(to string, diff io.Reader) (size int64, err error } func (r *layerStore) applyDiffWithOptions(to string, layerOptions *LayerOptions, diff io.Reader) (size int64, err error) { - if !r.IsReadWrite() { + if !r.lockfile.IsReadWrite() { return -1, fmt.Errorf("not allowed to modify layer contents at %q: %w", r.layerspath(), ErrStoreIsReadOnly) } @@ -1777,7 +1913,7 @@ func (r *layerStore) applyDiffWithOptions(to string, layerOptions *LayerOptions, return layer.GIDs[i] < layer.GIDs[j] }) - err = r.Save() + err = r.save() return size, err } @@ -1818,7 +1954,7 @@ func (r *layerStore) ApplyDiffFromStagingDirectory(id, stagingDirectory string, layer.UncompressedDigest = diffOutput.UncompressedDigest layer.UncompressedSize = diffOutput.Size layer.Metadata = diffOutput.Metadata - if err = r.Save(); err != nil { + if err = r.save(); err != nil { return err } for k, v := range diffOutput.BigData { @@ -1859,7 +1995,7 @@ func (r *layerStore) ApplyDiffWithDiffer(to string, options *drivers.ApplyDiffOp } layer.UIDs = output.UIDs layer.GIDs = output.GIDs - err = r.Save() + err = r.save() return &output, err } @@ -1891,77 +2027,6 @@ func (r *layerStore) LayersByUncompressedDigest(d digest.Digest) ([]Layer, error return r.layersByDigestMap(r.byuncompressedsum, d) } -func (r *layerStore) Lock() { - r.lockfile.Lock() -} - -func (r *layerStore) RLock() { - r.lockfile.RLock() -} - -func (r *layerStore) Unlock() { - r.lockfile.Unlock() -} - -func (r *layerStore) Touch() error { - return r.lockfile.Touch() -} - -func (r *layerStore) Modified() (bool, error) { - var mmodified, tmodified bool - lmodified, err := r.lockfile.Modified() - if err != nil { - return lmodified, err - } - if r.IsReadWrite() { - r.mountsLockfile.RLock() - defer r.mountsLockfile.Unlock() - mmodified, err = r.mountsLockfile.Modified() - if err != nil { - return lmodified, err - } - } - - if lmodified || mmodified { - return true, nil - } - - // If the layers.json file has been modified manually, then we have to - // reload the storage in any case. - info, err := os.Stat(r.layerspath()) - if err != nil && !os.IsNotExist(err) { - return false, fmt.Errorf("stat layers file: %w", err) - } - if info != nil { - tmodified = info.ModTime() != r.layerspathModified - } - - return tmodified, nil -} - -func (r *layerStore) IsReadWrite() bool { - return r.lockfile.IsReadWrite() -} - -func (r *layerStore) TouchedSince(when time.Time) bool { - return r.lockfile.TouchedSince(when) -} - -func (r *layerStore) Locked() bool { - return r.lockfile.Locked() -} - -func (r *layerStore) ReloadIfChanged() error { - r.loadMut.Lock() - defer r.loadMut.Unlock() - - modified, err := r.Modified() - if err == nil && modified { - return r.Load() - } - return err -} - func closeAll(closes ...func() error) (rErr error) { for _, f := range closes { if err := f(); err != nil { diff --git a/store.go b/store.go index a9bbbf2e15..b94b2a7f83 100644 --- a/store.go +++ b/store.go @@ -50,36 +50,6 @@ var ( storesLock sync.Mutex ) -// roFileBasedStore wraps up the methods of the various types of file-based -// data stores that we implement which are needed for both read-only and -// read-write files. -type roFileBasedStore interface { - Locker - - // Load reloads the contents of the store from disk. It should be called - // with the lock held. - Load() error - - // ReloadIfChanged reloads the contents of the store from disk if it is changed. - ReloadIfChanged() error -} - -// rwFileBasedStore wraps up the methods of various types of file-based data -// stores that we implement using read-write files. -type rwFileBasedStore interface { - // Save saves the contents of the store to disk. It should be called with - // the lock held, and Touch() should be called afterward before releasing the - // lock. - Save() error -} - -// fileBasedStore wraps up the common methods of various types of file-based -// data stores that we implement. -type fileBasedStore interface { - roFileBasedStore - rwFileBasedStore -} - // roMetadataStore wraps a method for reading metadata associated with an ID. type roMetadataStore interface { // Metadata reads metadata associated with an item with the specified ID. @@ -965,6 +935,59 @@ func (s *store) allLayerStores() ([]roLayerStore, error) { return append([]roLayerStore{primary}, additional...), nil } +// readAllLayerStores processes allLayerStores() in order: +// It locks the store for reading, checks for updates, and calls +// +// (done, err) := fn(store) +// +// until the callback returns done == true, and returns the data from the callback. +// +// If reading any layer store fails, it immediately returns (true, err). +// +// If all layer stores are processed without setting done == true, it returns (false, nil). +// +// Typical usage: +// +// var res T = failureValue +// if done, err := s.readAllLayerStores(store, func(…) { +// … +// }; done { +// return res, err +// } +func (s *store) readAllLayerStores(fn func(store roLayerStore) (bool, error)) (bool, error) { + layerStores, err := s.allLayerStores() + if err != nil { + return true, err + } + for _, s := range layerStores { + store := s + if err := store.startReading(); err != nil { + return true, err + } + defer store.stopReading() + if done, err := fn(store); done { + return true, err + } + } + return false, nil +} + +// writeToLayerStore is a helper for working with store.getLayerStore(): +// It locks the store for writing, checks for updates, and calls fn() +// It returns the return value of fn, or its own error initializing the store. +func (s *store) writeToLayerStore(fn func(store rwLayerStore) error) error { + store, err := s.getLayerStore() + if err != nil { + return err + } + + if err := store.startWriting(); err != nil { + return err + } + defer store.stopWriting() + return fn(store) +} + // getImageStore obtains and returns a handle to the writable image store object // used by the Store. func (s *store) getImageStore() (rwImageStore, error) { @@ -998,6 +1021,59 @@ func (s *store) allImageStores() ([]roImageStore, error) { return append([]roImageStore{primary}, additional...), nil } +// readAllImageStores processes allImageStores() in order: +// It locks the store for reading, checks for updates, and calls +// +// (done, err) := fn(store) +// +// until the callback returns done == true, and returns the data from the callback. +// +// If reading any Image store fails, it immediately returns (true, err). +// +// If all Image stores are processed without setting done == true, it returns (false, nil). +// +// Typical usage: +// +// var res T = failureValue +// if done, err := s.readAllImageStores(store, func(…) { +// … +// }; done { +// return res, err +// } +func (s *store) readAllImageStores(fn func(store roImageStore) (bool, error)) (bool, error) { + ImageStores, err := s.allImageStores() + if err != nil { + return true, err + } + for _, s := range ImageStores { + store := s + if err := store.startReading(); err != nil { + return true, err + } + defer store.stopReading() + if done, err := fn(store); done { + return true, err + } + } + return false, nil +} + +// writeToImageStore is a convenience helper for working with store.getImageStore(): +// It locks the store for writing, checks for updates, and calls fn() +// It returns the return value of fn, or its own error initializing the store. +func (s *store) writeToImageStore(fn func(store rwImageStore) error) error { + store, err := s.getImageStore() + if err != nil { + return err + } + + if err := store.startWriting(); err != nil { + return err + } + defer store.stopWriting() + return fn(store) +} + // getContainerStore obtains and returns a handle to the container store object // used by the Store. func (s *store) getContainerStore() (rwContainerStore, error) { @@ -1007,6 +1083,55 @@ func (s *store) getContainerStore() (rwContainerStore, error) { return nil, ErrLoadError } +// writeToContainerStore is a convenience helper for working with store.getContainerStore(): +// It locks the store for writing, checks for updates, and calls fn() +// It returns the return value of fn, or its own error initializing the store. +func (s *store) writeToContainerStore(fn func(store rwContainerStore) error) error { + store, err := s.getContainerStore() + if err != nil { + return err + } + + if err := store.startWriting(); err != nil { + return err + } + defer store.stopWriting() + return fn(store) +} + +// writeToAllStores is a convenience helper for writing to all three stores: +// It locks the stores for writing, checks for updates, and calls fn(). +// It returns the return value of fn, or its own error initializing the stores. +func (s *store) writeToAllStores(fn func(rlstore rwLayerStore, ristore rwImageStore, rcstore rwContainerStore) error) error { + rlstore, err := s.getLayerStore() + if err != nil { + return err + } + ristore, err := s.getImageStore() + if err != nil { + return err + } + rcstore, err := s.getContainerStore() + if err != nil { + return err + } + + if err := rlstore.startWriting(); err != nil { + return err + } + defer rlstore.stopWriting() + if err := ristore.startWriting(); err != nil { + return err + } + defer ristore.stopWriting() + if err := rcstore.startWriting(); err != nil { + return err + } + defer rcstore.stopWriting() + + return fn(rlstore, ristore, rcstore) +} + func (s *store) canUseShifting(uidmap, gidmap []idtools.IDMap) bool { if s.graphDriver == nil || !s.graphDriver.SupportsShifting() { return false @@ -1034,16 +1159,14 @@ func (s *store) PutLayer(id, parent string, names []string, mountLabel string, w if err != nil { return nil, -1, err } - rlstore.Lock() - defer rlstore.Unlock() - if err := rlstore.ReloadIfChanged(); err != nil { + if err := rlstore.startWriting(); err != nil { return nil, -1, err } - rcstore.Lock() - defer rcstore.Unlock() - if err := rcstore.ReloadIfChanged(); err != nil { + defer rlstore.stopWriting() + if err := rcstore.startWriting(); err != nil { return nil, -1, err } + defer rcstore.stopWriting() if options == nil { options = &LayerOptions{} } @@ -1060,11 +1183,10 @@ func (s *store) PutLayer(id, parent string, names []string, mountLabel string, w for _, l := range append([]roLayerStore{rlstore}, rlstores...) { lstore := l if lstore != rlstore { - lstore.RLock() - defer lstore.Unlock() - if err := lstore.ReloadIfChanged(); err != nil { + if err := lstore.startReading(); err != nil { return nil, -1, err } + defer lstore.stopReading() } if l, err := lstore.Get(parent); err == nil && l != nil { ilayer = l @@ -1132,21 +1254,22 @@ func (s *store) CreateImage(id string, names []string, layer, metadata string, o return nil, err } var ilayer *Layer - for _, s := range append([]roLayerStore{lstore}, lstores...) { - store := s - if store == lstore { - store.Lock() - } else { - store.RLock() - } - defer store.Unlock() - err := store.ReloadIfChanged() - if err != nil { - return nil, err - } - ilayer, err = store.Get(layer) - if err == nil { - break + if err := lstore.startWriting(); err != nil { + return nil, err + } + defer lstore.stopWriting() + ilayer, err = lstore.Get(layer) + if err != nil { + for _, s := range lstores { + store := s + if err := store.startReading(); err != nil { + return nil, err + } + defer store.stopReading() + ilayer, err = store.Get(layer) + if err == nil { + break + } } } if ilayer == nil { @@ -1155,22 +1278,18 @@ func (s *store) CreateImage(id string, names []string, layer, metadata string, o layer = ilayer.ID } - ristore, err := s.getImageStore() - if err != nil { - return nil, err - } - ristore.Lock() - defer ristore.Unlock() - if err := ristore.ReloadIfChanged(); err != nil { - return nil, err - } - - creationDate := time.Now().UTC() - if options != nil && !options.CreationDate.IsZero() { - creationDate = options.CreationDate - } + var res *Image + err := s.writeToImageStore(func(ristore rwImageStore) error { + creationDate := time.Now().UTC() + if options != nil && !options.CreationDate.IsZero() { + creationDate = options.CreationDate + } - return ristore.Create(id, names, layer, metadata, creationDate, options.Digest) + var err error + res, err = ristore.Create(id, names, layer, metadata, creationDate, options.Digest) + return err + }) + return res, err } func (s *store) imageTopLayerForMapping(image *Image, ristore roImageStore, createMappedLayer bool, rlstore rwLayerStore, lstores []roLayerStore, options types.IDMappingOptions) (*Layer, error) { @@ -1195,11 +1314,10 @@ func (s *store) imageTopLayerForMapping(image *Image, ristore roImageStore, crea for _, s := range allStores { store := s if store != rlstore { - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { + if err := store.startReading(); err != nil { return nil, err } + defer store.stopReading() } // Walk the top layer list. for _, candidate := range append([]string{image.TopLayer}, image.MappedTopLayers...) { @@ -1332,26 +1450,29 @@ func (s *store) CreateContainer(id string, names []string, image, layer, metadat if err != nil { return nil, err } - rlstore.Lock() - defer rlstore.Unlock() - if err := rlstore.ReloadIfChanged(); err != nil { + if err := rlstore.startWriting(); err != nil { return nil, err } - for _, s := range append([]roImageStore{istore}, istores...) { - store := s - if store == istore { - store.Lock() - } else { - store.RLock() - } - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { - return nil, err - } - cimage, err = store.Get(image) - if err == nil { - imageHomeStore = store - break + defer rlstore.stopWriting() + if err := istore.startWriting(); err != nil { + return nil, err + } + defer istore.stopWriting() + cimage, err = istore.Get(image) + if err == nil { + imageHomeStore = istore + } else { + for _, s := range istores { + store := s + if err := store.startReading(); err != nil { + return nil, err + } + defer store.stopReading() + cimage, err = store.Get(image) + if err == nil { + imageHomeStore = store + break + } } } if cimage == nil { @@ -1389,11 +1510,10 @@ func (s *store) CreateContainer(id string, names []string, image, layer, metadat } } } else { - rlstore.Lock() - defer rlstore.Unlock() - if err := rlstore.ReloadIfChanged(); err != nil { + if err := rlstore.startWriting(); err != nil { return nil, err } + defer rlstore.stopWriting() if !options.HostUIDMapping && len(options.UIDMap) == 0 { uidMap = s.uidMap } @@ -1445,118 +1565,79 @@ func (s *store) CreateContainer(id string, names []string, image, layer, metadat return nil, err } layer = clayer.ID - rcstore, err := s.getContainerStore() - if err != nil { - return nil, err - } - rcstore.Lock() - defer rcstore.Unlock() - if err := rcstore.ReloadIfChanged(); err != nil { - return nil, err - } - options.IDMappingOptions = types.IDMappingOptions{ - HostUIDMapping: len(options.UIDMap) == 0, - HostGIDMapping: len(options.GIDMap) == 0, - UIDMap: copyIDMap(options.UIDMap), - GIDMap: copyIDMap(options.GIDMap), - } - container, err := rcstore.Create(id, names, imageID, layer, metadata, options) - if err != nil || container == nil { - if err2 := rlstore.Delete(layer); err2 != nil { - if err == nil { - err = fmt.Errorf("deleting layer %#v: %w", layer, err2) - } else { - logrus.Errorf("While recovering from a failure to create a container, error deleting layer %#v: %v", layer, err2) + + var container *Container + err = s.writeToContainerStore(func(rcstore rwContainerStore) error { + options.IDMappingOptions = types.IDMappingOptions{ + HostUIDMapping: len(options.UIDMap) == 0, + HostGIDMapping: len(options.GIDMap) == 0, + UIDMap: copyIDMap(options.UIDMap), + GIDMap: copyIDMap(options.GIDMap), + } + var err error + container, err = rcstore.Create(id, names, imageID, layer, metadata, options) + if err != nil || container == nil { + if err2 := rlstore.Delete(layer); err2 != nil { + if err == nil { + err = fmt.Errorf("deleting layer %#v: %w", layer, err2) + } else { + logrus.Errorf("While recovering from a failure to create a container, error deleting layer %#v: %v", layer, err2) + } } } - } + return err + }) return container, err } func (s *store) SetMetadata(id, metadata string) error { - rlstore, err := s.getLayerStore() - if err != nil { - return err - } - ristore, err := s.getImageStore() - if err != nil { - return err - } - rcstore, err := s.getContainerStore() - if err != nil { - return err - } - - rlstore.Lock() - defer rlstore.Unlock() - if err := rlstore.ReloadIfChanged(); err != nil { - return err - } - ristore.Lock() - defer ristore.Unlock() - if err := ristore.ReloadIfChanged(); err != nil { - return err - } - rcstore.Lock() - defer rcstore.Unlock() - if err := rcstore.ReloadIfChanged(); err != nil { - return err - } - - if rlstore.Exists(id) { - return rlstore.SetMetadata(id, metadata) - } - if ristore.Exists(id) { - return ristore.SetMetadata(id, metadata) - } - if rcstore.Exists(id) { - return rcstore.SetMetadata(id, metadata) - } - return ErrNotAnID + return s.writeToAllStores(func(rlstore rwLayerStore, ristore rwImageStore, rcstore rwContainerStore) error { + if rlstore.Exists(id) { + return rlstore.SetMetadata(id, metadata) + } + if ristore.Exists(id) { + return ristore.SetMetadata(id, metadata) + } + if rcstore.Exists(id) { + return rcstore.SetMetadata(id, metadata) + } + return ErrNotAnID + }) } func (s *store) Metadata(id string) (string, error) { - layerStores, err := s.allLayerStores() - if err != nil { - return "", err - } - for _, s := range layerStores { - store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { - return "", err - } + var res string + + if done, err := s.readAllLayerStores(func(store roLayerStore) (bool, error) { if store.Exists(id) { - return store.Metadata(id) + var err error + res, err = store.Metadata(id) + return true, err } + return false, nil + }); done { + return res, err } - imageStores, err := s.allImageStores() - if err != nil { - return "", err - } - for _, s := range imageStores { - store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { - return "", err - } + if done, err := s.readAllImageStores(func(store roImageStore) (bool, error) { if store.Exists(id) { - return store.Metadata(id) + var err error + res, err = store.Metadata(id) + return true, err } + return false, nil + }); done { + return res, err } cstore, err := s.getContainerStore() if err != nil { return "", err } - cstore.RLock() - defer cstore.Unlock() - if err := cstore.ReloadIfChanged(); err != nil { + if err := cstore.startReading(); err != nil { return "", err } + defer cstore.stopReading() if cstore.Exists(id) { return cstore.Metadata(id) } @@ -1564,86 +1645,65 @@ func (s *store) Metadata(id string) (string, error) { } func (s *store) ListImageBigData(id string) ([]string, error) { - imageStores, err := s.allImageStores() - if err != nil { - return nil, err - } - for _, s := range imageStores { - store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { - return nil, err - } + var res []string + if done, err := s.readAllImageStores(func(store roImageStore) (bool, error) { bigDataNames, err := store.BigDataNames(id) if err == nil { - return bigDataNames, err + res = bigDataNames + return true, nil } + return false, nil + }); done { + return res, err } return nil, fmt.Errorf("locating image with ID %q: %w", id, ErrImageUnknown) } func (s *store) ImageBigDataSize(id, key string) (int64, error) { - imageStores, err := s.allImageStores() - if err != nil { - return -1, err - } - for _, s := range imageStores { - store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { - return -1, err - } + var res int64 = -1 + if done, err := s.readAllImageStores(func(store roImageStore) (bool, error) { size, err := store.BigDataSize(id, key) if err == nil { - return size, nil + res = size + return true, nil } + return false, nil + }); done { + return res, err } return -1, ErrSizeUnknown } func (s *store) ImageBigDataDigest(id, key string) (digest.Digest, error) { - imageStores, err := s.allImageStores() - if err != nil { - return "", err - } - for _, r := range imageStores { - ristore := r - ristore.RLock() - defer ristore.Unlock() - if err := ristore.ReloadIfChanged(); err != nil { - return "", err - } + var res digest.Digest + if done, err := s.readAllImageStores(func(ristore roImageStore) (bool, error) { d, err := ristore.BigDataDigest(id, key) if err == nil && d.Validate() == nil { - return d, nil + res = d + return true, nil } + return false, nil + }); done { + return res, err } return "", ErrDigestUnknown } func (s *store) ImageBigData(id, key string) ([]byte, error) { - imageStores, err := s.allImageStores() - if err != nil { - return nil, err - } - foundImage := false - for _, s := range imageStores { - store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { - return nil, err - } + var res []byte + if done, err := s.readAllImageStores(func(store roImageStore) (bool, error) { data, err := store.BigData(id, key) if err == nil { - return data, nil + res = data + return true, nil } if store.Exists(id) { foundImage = true } + return false, nil + }); done { + return res, err } if foundImage { return nil, fmt.Errorf("locating item named %q for image with ID %q (consider removing the image to resolve the issue): %w", key, id, os.ErrNotExist) @@ -1654,25 +1714,20 @@ func (s *store) ImageBigData(id, key string) ([]byte, error) { // ListLayerBigData retrieves a list of the (possibly large) chunks of // named data associated with an layer. func (s *store) ListLayerBigData(id string) ([]string, error) { - layerStores, err := s.allLayerStores() - if err != nil { - return nil, err - } foundLayer := false - for _, s := range layerStores { - store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { - return nil, err - } + var res []string + if done, err := s.readAllLayerStores(func(store roLayerStore) (bool, error) { data, err := store.BigDataNames(id) if err == nil { - return data, nil + res = data + return true, nil } if store.Exists(id) { foundLayer = true } + return false, nil + }); done { + return res, err } if foundLayer { return nil, fmt.Errorf("locating big data for layer with ID %q: %w", id, os.ErrNotExist) @@ -1683,25 +1738,20 @@ func (s *store) ListLayerBigData(id string) ([]string, error) { // LayerBigData retrieves a (possibly large) chunk of named data // associated with a layer. func (s *store) LayerBigData(id, key string) (io.ReadCloser, error) { - layerStores, err := s.allLayerStores() - if err != nil { - return nil, err - } foundLayer := false - for _, s := range layerStores { - store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { - return nil, err - } + var res io.ReadCloser + if done, err := s.readAllLayerStores(func(store roLayerStore) (bool, error) { data, err := store.BigData(id, key) if err == nil { - return data, nil + res = data + return true, nil } if store.Exists(id) { foundLayer = true } + return false, nil + }); done { + return res, err } if foundLayer { return nil, fmt.Errorf("locating item named %q for layer with ID %q: %w", key, id, os.ErrNotExist) @@ -1712,32 +1762,15 @@ func (s *store) LayerBigData(id, key string) (io.ReadCloser, error) { // SetLayerBigData stores a (possibly large) chunk of named data // associated with a layer. func (s *store) SetLayerBigData(id, key string, data io.Reader) error { - store, err := s.getLayerStore() - if err != nil { - return err - } - - store.Lock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { - return err - } - return store.SetBigData(id, key, data) + return s.writeToLayerStore(func(store rwLayerStore) error { + return store.SetBigData(id, key, data) + }) } func (s *store) SetImageBigData(id, key string, data []byte, digestManifest func([]byte) (digest.Digest, error)) error { - ristore, err := s.getImageStore() - if err != nil { - return err - } - - ristore.Lock() - defer ristore.Unlock() - if err := ristore.ReloadIfChanged(); err != nil { - return err - } - - return ristore.SetBigData(id, key, data, digestManifest) + return s.writeToImageStore(func(ristore rwImageStore) error { + return ristore.SetBigData(id, key, data, digestManifest) + }) } func (s *store) ImageSize(id string) (int64, error) { @@ -1747,11 +1780,10 @@ func (s *store) ImageSize(id string) (int64, error) { } for _, s := range layerStores { store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { + if err := store.startReading(); err != nil { return -1, err } + defer store.stopReading() } imageStores, err := s.allImageStores() @@ -1763,11 +1795,10 @@ func (s *store) ImageSize(id string) (int64, error) { var image *Image for _, s := range imageStores { store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { + if err := store.startReading(); err != nil { return -1, err } + defer store.stopReading() if image, err = store.Get(id); err == nil { imageStore = store break @@ -1847,11 +1878,10 @@ func (s *store) ContainerSize(id string) (int64, error) { } for _, s := range layerStores { store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { + if err := store.startReading(); err != nil { return -1, err } + defer store.stopReading() } // Get the location of the container directory and container run directory. @@ -1869,11 +1899,10 @@ func (s *store) ContainerSize(id string) (int64, error) { if err != nil { return -1, err } - rcstore.RLock() - defer rcstore.Unlock() - if err := rcstore.ReloadIfChanged(); err != nil { + if err := rcstore.startReading(); err != nil { return -1, err } + defer rcstore.stopReading() // Read the container record. container, err := rcstore.Get(id) @@ -1931,11 +1960,10 @@ func (s *store) ListContainerBigData(id string) ([]string, error) { return nil, err } - rcstore.RLock() - defer rcstore.Unlock() - if err := rcstore.ReloadIfChanged(); err != nil { + if err := rcstore.startReading(); err != nil { return nil, err } + defer rcstore.stopReading() return rcstore.BigDataNames(id) } @@ -1945,11 +1973,10 @@ func (s *store) ContainerBigDataSize(id, key string) (int64, error) { if err != nil { return -1, err } - rcstore.RLock() - defer rcstore.Unlock() - if err := rcstore.ReloadIfChanged(); err != nil { + if err := rcstore.startReading(); err != nil { return -1, err } + defer rcstore.stopReading() return rcstore.BigDataSize(id, key) } @@ -1958,11 +1985,10 @@ func (s *store) ContainerBigDataDigest(id, key string) (digest.Digest, error) { if err != nil { return "", err } - rcstore.RLock() - defer rcstore.Unlock() - if err := rcstore.ReloadIfChanged(); err != nil { + if err := rcstore.startReading(); err != nil { return "", err } + defer rcstore.stopReading() return rcstore.BigDataDigest(id, key) } @@ -1971,74 +1997,51 @@ func (s *store) ContainerBigData(id, key string) ([]byte, error) { if err != nil { return nil, err } - rcstore.RLock() - defer rcstore.Unlock() - if err := rcstore.ReloadIfChanged(); err != nil { + if err := rcstore.startReading(); err != nil { return nil, err } + defer rcstore.stopReading() return rcstore.BigData(id, key) } func (s *store) SetContainerBigData(id, key string, data []byte) error { - rcstore, err := s.getContainerStore() - if err != nil { - return err - } - rcstore.Lock() - defer rcstore.Unlock() - if err := rcstore.ReloadIfChanged(); err != nil { - return err - } - return rcstore.SetBigData(id, key, data) + return s.writeToContainerStore(func(rcstore rwContainerStore) error { + return rcstore.SetBigData(id, key, data) + }) } func (s *store) Exists(id string) bool { - layerStores, err := s.allLayerStores() - if err != nil { - return false - } - for _, s := range layerStores { - store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { - return false - } + var res = false + + if done, _ := s.readAllLayerStores(func(store roLayerStore) (bool, error) { if store.Exists(id) { - return true + res = true + return true, nil } + return false, nil + }); done { + return res } - imageStores, err := s.allImageStores() - if err != nil { - return false - } - for _, s := range imageStores { - store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { - return false - } + if done, _ := s.readAllImageStores(func(store roImageStore) (bool, error) { if store.Exists(id) { - return true + res = true + return true, nil } + return false, nil + }); done { + return res } rcstore, err := s.getContainerStore() if err != nil { return false } - rcstore.RLock() - defer rcstore.Unlock() - if err := rcstore.ReloadIfChanged(); err != nil { + if err := rcstore.startReading(); err != nil { return false } - if rcstore.Exists(id) { - return true - } - - return false + defer rcstore.stopReading() + return rcstore.Exists(id) } func dedupeNames(names []string) []string { @@ -2069,16 +2072,12 @@ func (s *store) RemoveNames(id string, names []string) error { func (s *store) updateNames(id string, names []string, op updateNameOperation) error { deduped := dedupeNames(names) - rlstore, err := s.getLayerStore() - if err != nil { - return err - } - rlstore.Lock() - defer rlstore.Unlock() - if err := rlstore.ReloadIfChanged(); err != nil { - return err - } - if rlstore.Exists(id) { + layerFound := false + if err := s.writeToLayerStore(func(rlstore rwLayerStore) error { + if !rlstore.Exists(id) { + return nil + } + layerFound = true switch op { case setNames: return rlstore.SetNames(id, deduped) @@ -2089,17 +2088,18 @@ func (s *store) updateNames(id string, names []string, op updateNameOperation) e default: return errInvalidUpdateNameOperation } + }); err != nil || layerFound { + return err } ristore, err := s.getImageStore() if err != nil { return err } - ristore.Lock() - defer ristore.Unlock() - if err := ristore.ReloadIfChanged(); err != nil { + if err := ristore.startWriting(); err != nil { return err } + defer ristore.stopWriting() if ristore.Exists(id) { switch op { case setNames: @@ -2120,34 +2120,26 @@ func (s *store) updateNames(id string, names []string, op updateNameOperation) e } for _, s := range ristores { store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { + if err := store.startReading(); err != nil { return err } + defer store.stopReading() if i, err := store.Get(id); err == nil { if len(deduped) > 1 { // Do not want to create image name in R/W storage deduped = deduped[1:] } _, err := ristore.Create(id, deduped, i.TopLayer, i.Metadata, i.Created, i.Digest) - if err == nil { - return ristore.Save() - } return err } } - rcstore, err := s.getContainerStore() - if err != nil { - return err - } - rcstore.Lock() - defer rcstore.Unlock() - if err := rcstore.ReloadIfChanged(); err != nil { - return err - } - if rcstore.Exists(id) { + containerFound := false + if err := s.writeToContainerStore(func(rcstore rwContainerStore) error { + if !rcstore.Exists(id) { + return nil + } + containerFound = true switch op { case setNames: return rcstore.SetNames(id, deduped) @@ -2158,52 +2150,44 @@ func (s *store) updateNames(id string, names []string, op updateNameOperation) e default: return errInvalidUpdateNameOperation } + }); err != nil || containerFound { + return err } + return ErrLayerUnknown } func (s *store) Names(id string) ([]string, error) { - layerStores, err := s.allLayerStores() - if err != nil { - return nil, err - } - for _, s := range layerStores { - store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { - return nil, err - } + var res []string + + if done, err := s.readAllLayerStores(func(store roLayerStore) (bool, error) { if l, err := store.Get(id); l != nil && err == nil { - return l.Names, nil + res = l.Names + return true, nil } + return false, nil + }); done { + return res, err } - imageStores, err := s.allImageStores() - if err != nil { - return nil, err - } - for _, s := range imageStores { - store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { - return nil, err - } + if done, err := s.readAllImageStores(func(store roImageStore) (bool, error) { if i, err := store.Get(id); i != nil && err == nil { - return i.Names, nil + res = i.Names + return true, nil } + return false, nil + }); done { + return res, err } rcstore, err := s.getContainerStore() if err != nil { return nil, err } - rcstore.RLock() - defer rcstore.Unlock() - if err := rcstore.ReloadIfChanged(); err != nil { + if err := rcstore.startReading(); err != nil { return nil, err } + defer rcstore.stopReading() if c, err := rcstore.Get(id); c != nil && err == nil { return c.Names, nil } @@ -2211,47 +2195,36 @@ func (s *store) Names(id string) ([]string, error) { } func (s *store) Lookup(name string) (string, error) { - layerStores, err := s.allLayerStores() - if err != nil { - return "", err - } - for _, s := range layerStores { - store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { - return "", err - } + var res string + + if done, err := s.readAllLayerStores(func(store roLayerStore) (bool, error) { if l, err := store.Get(name); l != nil && err == nil { - return l.ID, nil + res = l.ID + return true, nil } + return false, nil + }); done { + return res, err } - imageStores, err := s.allImageStores() - if err != nil { - return "", err - } - for _, s := range imageStores { - store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { - return "", err - } + if done, err := s.readAllImageStores(func(store roImageStore) (bool, error) { if i, err := store.Get(name); i != nil && err == nil { - return i.ID, nil + res = i.ID + return true, nil } + return false, nil + }); done { + return res, err } cstore, err := s.getContainerStore() if err != nil { return "", err } - cstore.RLock() - defer cstore.Unlock() - if err := cstore.ReloadIfChanged(); err != nil { + if err := cstore.startReading(); err != nil { return "", err } + defer cstore.stopReading() if c, err := cstore.Get(name); c != nil && err == nil { return c.ID, nil } @@ -2260,417 +2233,286 @@ func (s *store) Lookup(name string) (string, error) { } func (s *store) DeleteLayer(id string) error { - rlstore, err := s.getLayerStore() - if err != nil { - return err - } - ristore, err := s.getImageStore() - if err != nil { - return err - } - rcstore, err := s.getContainerStore() - if err != nil { - return err - } - - rlstore.Lock() - defer rlstore.Unlock() - if err := rlstore.ReloadIfChanged(); err != nil { - return err - } - ristore.Lock() - defer ristore.Unlock() - if err := ristore.ReloadIfChanged(); err != nil { - return err - } - rcstore.Lock() - defer rcstore.Unlock() - if err := rcstore.ReloadIfChanged(); err != nil { - return err - } - - if rlstore.Exists(id) { - if l, err := rlstore.Get(id); err != nil { - id = l.ID - } - layers, err := rlstore.Layers() - if err != nil { - return err - } - for _, layer := range layers { - if layer.Parent == id { - return fmt.Errorf("used by layer %v: %w", layer.ID, ErrLayerHasChildren) + return s.writeToAllStores(func(rlstore rwLayerStore, ristore rwImageStore, rcstore rwContainerStore) error { + if rlstore.Exists(id) { + if l, err := rlstore.Get(id); err != nil { + id = l.ID } - } - images, err := ristore.Images() - if err != nil { - return err - } - - for _, image := range images { - if image.TopLayer == id { - return fmt.Errorf("layer %v used by image %v: %w", id, image.ID, ErrLayerUsedByImage) + layers, err := rlstore.Layers() + if err != nil { + return err } - if stringutils.InSlice(image.MappedTopLayers, id) { - // No write access to the image store, fail before the layer is deleted - if _, ok := ristore.(*imageStore); !ok { - return fmt.Errorf("layer %v used by image %v: %w", id, image.ID, ErrLayerUsedByImage) + for _, layer := range layers { + if layer.Parent == id { + return fmt.Errorf("used by layer %v: %w", layer.ID, ErrLayerHasChildren) } } - } - containers, err := rcstore.Containers() - if err != nil { - return err - } - for _, container := range containers { - if container.LayerID == id { - return fmt.Errorf("layer %v used by container %v: %w", id, container.ID, ErrLayerUsedByContainer) + images, err := ristore.Images() + if err != nil { + return err } - } - if err := rlstore.Delete(id); err != nil { - return fmt.Errorf("delete layer %v: %w", id, err) - } - // The check here is used to avoid iterating the images if we don't need to. - // There is already a check above for the imageStore to be writeable when the layer is part of MappedTopLayers. - if istore, ok := ristore.(*imageStore); ok { for _, image := range images { + if image.TopLayer == id { + return fmt.Errorf("layer %v used by image %v: %w", id, image.ID, ErrLayerUsedByImage) + } if stringutils.InSlice(image.MappedTopLayers, id) { - if err = istore.removeMappedTopLayer(image.ID, id); err != nil { - return fmt.Errorf("remove mapped top layer %v from image %v: %w", id, image.ID, err) + // No write access to the image store, fail before the layer is deleted + if _, ok := ristore.(*imageStore); !ok { + return fmt.Errorf("layer %v used by image %v: %w", id, image.ID, ErrLayerUsedByImage) + } + } + } + containers, err := rcstore.Containers() + if err != nil { + return err + } + for _, container := range containers { + if container.LayerID == id { + return fmt.Errorf("layer %v used by container %v: %w", id, container.ID, ErrLayerUsedByContainer) + } + } + if err := rlstore.Delete(id); err != nil { + return fmt.Errorf("delete layer %v: %w", id, err) + } + + // The check here is used to avoid iterating the images if we don't need to. + // There is already a check above for the imageStore to be writeable when the layer is part of MappedTopLayers. + if istore, ok := ristore.(*imageStore); ok { + for _, image := range images { + if stringutils.InSlice(image.MappedTopLayers, id) { + if err = istore.removeMappedTopLayer(image.ID, id); err != nil { + return fmt.Errorf("remove mapped top layer %v from image %v: %w", id, image.ID, err) + } } } } + return nil } - return nil - } - return ErrNotALayer + return ErrNotALayer + }) } func (s *store) DeleteImage(id string, commit bool) (layers []string, err error) { - rlstore, err := s.getLayerStore() - if err != nil { - return nil, err - } - ristore, err := s.getImageStore() - if err != nil { - return nil, err - } - rcstore, err := s.getContainerStore() - if err != nil { - return nil, err - } - - rlstore.Lock() - defer rlstore.Unlock() - if err := rlstore.ReloadIfChanged(); err != nil { - return nil, err - } - ristore.Lock() - defer ristore.Unlock() - if err := ristore.ReloadIfChanged(); err != nil { - return nil, err - } - rcstore.Lock() - defer rcstore.Unlock() - if err := rcstore.ReloadIfChanged(); err != nil { - return nil, err - } layersToRemove := []string{} - if ristore.Exists(id) { - image, err := ristore.Get(id) - if err != nil { - return nil, err - } - id = image.ID - containers, err := rcstore.Containers() - if err != nil { - return nil, err - } - aContainerByImage := make(map[string]string) - for _, container := range containers { - aContainerByImage[container.ImageID] = container.ID - } - if container, ok := aContainerByImage[id]; ok { - return nil, fmt.Errorf("image used by %v: %w", container, ErrImageUsedByContainer) - } - images, err := ristore.Images() - if err != nil { - return nil, err - } - layers, err := rlstore.Layers() - if err != nil { - return nil, err - } - childrenByParent := make(map[string][]string) - for _, layer := range layers { - childrenByParent[layer.Parent] = append(childrenByParent[layer.Parent], layer.ID) - } - otherImagesTopLayers := make(map[string]struct{}) - for _, img := range images { - if img.ID != id { - otherImagesTopLayers[img.TopLayer] = struct{}{} - for _, layerID := range img.MappedTopLayers { - otherImagesTopLayers[layerID] = struct{}{} - } + if err := s.writeToAllStores(func(rlstore rwLayerStore, ristore rwImageStore, rcstore rwContainerStore) error { + if ristore.Exists(id) { + image, err := ristore.Get(id) + if err != nil { + return err } - } - if commit { - if err = ristore.Delete(id); err != nil { - return nil, err + id = image.ID + containers, err := rcstore.Containers() + if err != nil { + return err } - } - layer := image.TopLayer - layersToRemoveMap := make(map[string]struct{}) - layersToRemove = append(layersToRemove, image.MappedTopLayers...) - for _, mappedTopLayer := range image.MappedTopLayers { - layersToRemoveMap[mappedTopLayer] = struct{}{} - } - for layer != "" { - if rcstore.Exists(layer) { - break + aContainerByImage := make(map[string]string) + for _, container := range containers { + aContainerByImage[container.ImageID] = container.ID } - if _, used := otherImagesTopLayers[layer]; used { - break + if container, ok := aContainerByImage[id]; ok { + return fmt.Errorf("image used by %v: %w", container, ErrImageUsedByContainer) + } + images, err := ristore.Images() + if err != nil { + return err + } + layers, err := rlstore.Layers() + if err != nil { + return err } - parent := "" - if l, err := rlstore.Get(layer); err == nil { - parent = l.Parent + childrenByParent := make(map[string][]string) + for _, layer := range layers { + childrenByParent[layer.Parent] = append(childrenByParent[layer.Parent], layer.ID) } - hasChildrenNotBeingRemoved := func() bool { - layersToCheck := []string{layer} - if layer == image.TopLayer { - layersToCheck = append(layersToCheck, image.MappedTopLayers...) + otherImagesTopLayers := make(map[string]struct{}) + for _, img := range images { + if img.ID != id { + otherImagesTopLayers[img.TopLayer] = struct{}{} + for _, layerID := range img.MappedTopLayers { + otherImagesTopLayers[layerID] = struct{}{} + } + } + } + if commit { + if err = ristore.Delete(id); err != nil { + return err + } + } + layer := image.TopLayer + layersToRemoveMap := make(map[string]struct{}) + layersToRemove = append(layersToRemove, image.MappedTopLayers...) + for _, mappedTopLayer := range image.MappedTopLayers { + layersToRemoveMap[mappedTopLayer] = struct{}{} + } + for layer != "" { + if rcstore.Exists(layer) { + break } - for _, layer := range layersToCheck { - if childList := childrenByParent[layer]; len(childList) > 0 { - for _, child := range childList { - if _, childIsSlatedForRemoval := layersToRemoveMap[child]; childIsSlatedForRemoval { - continue + if _, used := otherImagesTopLayers[layer]; used { + break + } + parent := "" + if l, err := rlstore.Get(layer); err == nil { + parent = l.Parent + } + hasChildrenNotBeingRemoved := func() bool { + layersToCheck := []string{layer} + if layer == image.TopLayer { + layersToCheck = append(layersToCheck, image.MappedTopLayers...) + } + for _, layer := range layersToCheck { + if childList := childrenByParent[layer]; len(childList) > 0 { + for _, child := range childList { + if _, childIsSlatedForRemoval := layersToRemoveMap[child]; childIsSlatedForRemoval { + continue + } + return true } - return true } } + return false } - return false - } - if hasChildrenNotBeingRemoved() { - break + if hasChildrenNotBeingRemoved() { + break + } + layersToRemove = append(layersToRemove, layer) + layersToRemoveMap[layer] = struct{}{} + layer = parent } - layersToRemove = append(layersToRemove, layer) - layersToRemoveMap[layer] = struct{}{} - layer = parent + } else { + return ErrNotAnImage } - } else { - return nil, ErrNotAnImage - } - if commit { - for _, layer := range layersToRemove { - if err = rlstore.Delete(layer); err != nil { - return nil, err + if commit { + for _, layer := range layersToRemove { + if err = rlstore.Delete(layer); err != nil { + return err + } } } + return nil + }); err != nil { + return nil, err } return layersToRemove, nil } func (s *store) DeleteContainer(id string) error { - rlstore, err := s.getLayerStore() - if err != nil { - return err - } - ristore, err := s.getImageStore() - if err != nil { - return err - } - rcstore, err := s.getContainerStore() - if err != nil { - return err - } - - rlstore.Lock() - defer rlstore.Unlock() - if err := rlstore.ReloadIfChanged(); err != nil { - return err - } - ristore.Lock() - defer ristore.Unlock() - if err := ristore.ReloadIfChanged(); err != nil { - return err - } - rcstore.Lock() - defer rcstore.Unlock() - if err := rcstore.ReloadIfChanged(); err != nil { - return err - } - - if !rcstore.Exists(id) { - return ErrNotAContainer - } + return s.writeToAllStores(func(rlstore rwLayerStore, ristore rwImageStore, rcstore rwContainerStore) error { + if !rcstore.Exists(id) { + return ErrNotAContainer + } - container, err := rcstore.Get(id) - if err != nil { - return ErrNotAContainer - } + container, err := rcstore.Get(id) + if err != nil { + return ErrNotAContainer + } - errChan := make(chan error) - var wg sync.WaitGroup + errChan := make(chan error) + var wg sync.WaitGroup - if rlstore.Exists(container.LayerID) { + if rlstore.Exists(container.LayerID) { + wg.Add(1) + go func() { + errChan <- rlstore.Delete(container.LayerID) + wg.Done() + }() + } wg.Add(1) go func() { - errChan <- rlstore.Delete(container.LayerID) + errChan <- rcstore.Delete(id) wg.Done() }() - } - wg.Add(1) - go func() { - errChan <- rcstore.Delete(id) - wg.Done() - }() - middleDir := s.graphDriverName + "-containers" - gcpath := filepath.Join(s.GraphRoot(), middleDir, container.ID) - wg.Add(1) - go func() { - defer wg.Done() - // attempt a simple rm -rf first - err := os.RemoveAll(gcpath) - if err == nil { - errChan <- nil - return - } - // and if it fails get to the more complicated cleanup - errChan <- system.EnsureRemoveAll(gcpath) - }() + middleDir := s.graphDriverName + "-containers" + gcpath := filepath.Join(s.GraphRoot(), middleDir, container.ID) + wg.Add(1) + go func() { + defer wg.Done() + // attempt a simple rm -rf first + err := os.RemoveAll(gcpath) + if err == nil { + errChan <- nil + return + } + // and if it fails get to the more complicated cleanup + errChan <- system.EnsureRemoveAll(gcpath) + }() - rcpath := filepath.Join(s.RunRoot(), middleDir, container.ID) - wg.Add(1) - go func() { - defer wg.Done() - // attempt a simple rm -rf first - err := os.RemoveAll(rcpath) - if err == nil { - errChan <- nil - return - } - // and if it fails get to the more complicated cleanup - errChan <- system.EnsureRemoveAll(rcpath) - }() + rcpath := filepath.Join(s.RunRoot(), middleDir, container.ID) + wg.Add(1) + go func() { + defer wg.Done() + // attempt a simple rm -rf first + err := os.RemoveAll(rcpath) + if err == nil { + errChan <- nil + return + } + // and if it fails get to the more complicated cleanup + errChan <- system.EnsureRemoveAll(rcpath) + }() - go func() { - wg.Wait() - close(errChan) - }() + go func() { + wg.Wait() + close(errChan) + }() - var errors []error - for err := range errChan { - if err != nil { - errors = append(errors, err) + var errors []error + for err := range errChan { + if err != nil { + errors = append(errors, err) + } } - } - return multierror.Append(nil, errors...).ErrorOrNil() + return multierror.Append(nil, errors...).ErrorOrNil() + }) } func (s *store) Delete(id string) error { - rlstore, err := s.getLayerStore() - if err != nil { - return err - } - ristore, err := s.getImageStore() - if err != nil { - return err - } - rcstore, err := s.getContainerStore() - if err != nil { - return err - } - - rlstore.Lock() - defer rlstore.Unlock() - if err := rlstore.ReloadIfChanged(); err != nil { - return err - } - ristore.Lock() - defer ristore.Unlock() - if err := ristore.ReloadIfChanged(); err != nil { - return err - } - rcstore.Lock() - defer rcstore.Unlock() - if err := rcstore.ReloadIfChanged(); err != nil { - return err - } - - if rcstore.Exists(id) { - if container, err := rcstore.Get(id); err == nil { - if rlstore.Exists(container.LayerID) { - if err = rlstore.Delete(container.LayerID); err != nil { - return err - } - if err = rcstore.Delete(id); err != nil { - return err - } - middleDir := s.graphDriverName + "-containers" - gcpath := filepath.Join(s.GraphRoot(), middleDir, container.ID, "userdata") - if err = os.RemoveAll(gcpath); err != nil { - return err - } - rcpath := filepath.Join(s.RunRoot(), middleDir, container.ID, "userdata") - if err = os.RemoveAll(rcpath); err != nil { - return err + return s.writeToAllStores(func(rlstore rwLayerStore, ristore rwImageStore, rcstore rwContainerStore) error { + if rcstore.Exists(id) { + if container, err := rcstore.Get(id); err == nil { + if rlstore.Exists(container.LayerID) { + if err = rlstore.Delete(container.LayerID); err != nil { + return err + } + if err = rcstore.Delete(id); err != nil { + return err + } + middleDir := s.graphDriverName + "-containers" + gcpath := filepath.Join(s.GraphRoot(), middleDir, container.ID, "userdata") + if err = os.RemoveAll(gcpath); err != nil { + return err + } + rcpath := filepath.Join(s.RunRoot(), middleDir, container.ID, "userdata") + if err = os.RemoveAll(rcpath); err != nil { + return err + } + return nil } - return nil + return ErrNotALayer } - return ErrNotALayer } - } - if ristore.Exists(id) { - return ristore.Delete(id) - } - if rlstore.Exists(id) { - return rlstore.Delete(id) - } - return ErrLayerUnknown + if ristore.Exists(id) { + return ristore.Delete(id) + } + if rlstore.Exists(id) { + return rlstore.Delete(id) + } + return ErrLayerUnknown + }) } func (s *store) Wipe() error { - rcstore, err := s.getContainerStore() - if err != nil { - return err - } - ristore, err := s.getImageStore() - if err != nil { - return err - } - rlstore, err := s.getLayerStore() - if err != nil { - return err - } - - rlstore.Lock() - defer rlstore.Unlock() - if err := rlstore.ReloadIfChanged(); err != nil { - return err - } - ristore.Lock() - defer ristore.Unlock() - if err := ristore.ReloadIfChanged(); err != nil { - return err - } - rcstore.Lock() - defer rcstore.Unlock() - if err := rcstore.ReloadIfChanged(); err != nil { - return err - } - - if err = rcstore.Wipe(); err != nil { - return err - } - if err = ristore.Wipe(); err != nil { - return err - } - return rlstore.Wipe() + return s.writeToAllStores(func(rlstore rwLayerStore, ristore rwImageStore, rcstore rwContainerStore) error { + if err := rcstore.Wipe(); err != nil { + return err + } + if err := ristore.Wipe(); err != nil { + return err + } + return rlstore.Wipe() + }) } func (s *store) Status() ([][2]string, error) { @@ -2693,11 +2535,10 @@ func (s *store) mount(id string, options drivers.MountOpts) (string, error) { s.graphLock.Lock() defer s.graphLock.Unlock() - rlstore.Lock() - defer rlstore.Unlock() - if err := rlstore.ReloadIfChanged(); err != nil { + if err := rlstore.startWriting(); err != nil { return "", err } + defer rlstore.stopWriting() modified, err := s.graphLock.Modified() if err != nil { @@ -2773,11 +2614,10 @@ func (s *store) Mounted(id string) (int, error) { if err != nil { return 0, err } - rlstore.RLock() - defer rlstore.Unlock() - if err := rlstore.ReloadIfChanged(); err != nil { + if err := rlstore.startReading(); err != nil { return 0, err } + defer rlstore.stopReading() return rlstore.Mounted(id) } @@ -2794,56 +2634,44 @@ func (s *store) Unmount(id string, force bool) (bool, error) { if layerID, err := s.ContainerLayerID(id); err == nil { id = layerID } - rlstore, err := s.getLayerStore() - if err != nil { - return false, err - } - rlstore.Lock() - defer rlstore.Unlock() - if err := rlstore.ReloadIfChanged(); err != nil { - return false, err - } - if rlstore.Exists(id) { - return rlstore.Unmount(id, force) - } - return false, ErrLayerUnknown + var res bool + err := s.writeToLayerStore(func(rlstore rwLayerStore) error { + if rlstore.Exists(id) { + var err error + res, err = rlstore.Unmount(id, force) + return err + } + return ErrLayerUnknown + }) + return res, err } func (s *store) Changes(from, to string) ([]archive.Change, error) { - layerStores, err := s.allLayerStores() - if err != nil { - return nil, err - } - - for _, s := range layerStores { - store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { - return nil, err - } + var res []archive.Change + if done, err := s.readAllLayerStores(func(store roLayerStore) (bool, error) { if store.Exists(to) { - return store.Changes(from, to) + var err error + res, err = store.Changes(from, to) + return true, err } + return false, nil + }); done { + return res, err } return nil, ErrLayerUnknown } func (s *store) DiffSize(from, to string) (int64, error) { - layerStores, err := s.allLayerStores() - if err != nil { - return -1, err - } - for _, s := range layerStores { - store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { - return -1, err - } + var res int64 = -1 + if done, err := s.readAllLayerStores(func(store roLayerStore) (bool, error) { if store.Exists(to) { - return store.DiffSize(from, to) + var err error + res, err = store.DiffSize(from, to) + return true, err } + return false, nil + }); done { + return res, err } return -1, ErrLayerUnknown } @@ -2877,9 +2705,7 @@ func (s *store) Diff(from, to string, options *DiffOptions) (io.ReadCloser, erro for _, s := range layerStores { store := s - store.RLock() - if err := store.ReloadIfChanged(); err != nil { - store.Unlock() + if err := store.startReading(); err != nil { return nil, err } if store.Exists(to) { @@ -2887,117 +2713,87 @@ func (s *store) Diff(from, to string, options *DiffOptions) (io.ReadCloser, erro if rc != nil && err == nil { wrapped := ioutils.NewReadCloserWrapper(rc, func() error { err := rc.Close() - store.Unlock() + store.stopReading() return err }) return wrapped, nil } - store.Unlock() + store.stopReading() return rc, err } - store.Unlock() + store.stopReading() } return nil, ErrLayerUnknown } func (s *store) ApplyDiffFromStagingDirectory(to, stagingDirectory string, diffOutput *drivers.DriverWithDifferOutput, options *drivers.ApplyDiffOpts) error { - rlstore, err := s.getLayerStore() - if err != nil { - return err - } - rlstore.Lock() - defer rlstore.Unlock() - if err := rlstore.ReloadIfChanged(); err != nil { - return err - } - if !rlstore.Exists(to) { - return ErrLayerUnknown - } - return rlstore.ApplyDiffFromStagingDirectory(to, stagingDirectory, diffOutput, options) + return s.writeToLayerStore(func(rlstore rwLayerStore) error { + if !rlstore.Exists(to) { + return ErrLayerUnknown + } + return rlstore.ApplyDiffFromStagingDirectory(to, stagingDirectory, diffOutput, options) + }) } func (s *store) CleanupStagingDirectory(stagingDirectory string) error { - rlstore, err := s.getLayerStore() - if err != nil { - return err - } - rlstore.Lock() - defer rlstore.Unlock() - if err := rlstore.ReloadIfChanged(); err != nil { - return err - } - return rlstore.CleanupStagingDirectory(stagingDirectory) + return s.writeToLayerStore(func(rlstore rwLayerStore) error { + return rlstore.CleanupStagingDirectory(stagingDirectory) + }) } func (s *store) ApplyDiffWithDiffer(to string, options *drivers.ApplyDiffOpts, differ drivers.Differ) (*drivers.DriverWithDifferOutput, error) { - rlstore, err := s.getLayerStore() - if err != nil { - return nil, err - } - rlstore.Lock() - defer rlstore.Unlock() - if err := rlstore.ReloadIfChanged(); err != nil { - return nil, err - } - if to != "" && !rlstore.Exists(to) { - return nil, ErrLayerUnknown - } - return rlstore.ApplyDiffWithDiffer(to, options, differ) + var res *drivers.DriverWithDifferOutput + err := s.writeToLayerStore(func(rlstore rwLayerStore) error { + if to != "" && !rlstore.Exists(to) { + return ErrLayerUnknown + } + var err error + res, err = rlstore.ApplyDiffWithDiffer(to, options, differ) + return err + }) + return res, err } func (s *store) DifferTarget(id string) (string, error) { - rlstore, err := s.getLayerStore() - if err != nil { - return "", err - } - rlstore.Lock() - defer rlstore.Unlock() - if err := rlstore.ReloadIfChanged(); err != nil { - return "", err - } - if rlstore.Exists(id) { - return rlstore.DifferTarget(id) - } - return "", ErrLayerUnknown + var res string + err := s.writeToLayerStore(func(rlstore rwLayerStore) error { + if rlstore.Exists(id) { + var err error + res, err = rlstore.DifferTarget(id) + return err + } + return ErrLayerUnknown + }) + return res, err } func (s *store) ApplyDiff(to string, diff io.Reader) (int64, error) { - rlstore, err := s.getLayerStore() - if err != nil { - return -1, err - } - rlstore.Lock() - defer rlstore.Unlock() - if err := rlstore.ReloadIfChanged(); err != nil { - return -1, err - } - if rlstore.Exists(to) { - return rlstore.ApplyDiff(to, diff) - } - return -1, ErrLayerUnknown + var res int64 = -1 + err := s.writeToLayerStore(func(rlstore rwLayerStore) error { + if rlstore.Exists(to) { + var err error + res, err = rlstore.ApplyDiff(to, diff) + return err + } + return ErrLayerUnknown + }) + return res, err } func (s *store) layersByMappedDigest(m func(roLayerStore, digest.Digest) ([]Layer, error), d digest.Digest) ([]Layer, error) { - layerStores, err := s.allLayerStores() - if err != nil { - return nil, err - } var layers []Layer - for _, s := range layerStores { - store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { - return nil, err - } + if _, err := s.readAllLayerStores(func(store roLayerStore) (bool, error) { storeLayers, err := m(store, d) if err != nil { if !errors.Is(err, ErrLayerUnknown) { - return nil, err + return true, err } - continue + return false, nil } layers = append(layers, storeLayers...) + return false, nil + }); err != nil { + return nil, err } if len(layers) == 0 { return nil, ErrLayerUnknown @@ -3020,20 +2816,16 @@ func (s *store) LayersByUncompressedDigest(d digest.Digest) ([]Layer, error) { } func (s *store) LayerSize(id string) (int64, error) { - layerStores, err := s.allLayerStores() - if err != nil { - return -1, err - } - for _, s := range layerStores { - store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { - return -1, err - } + var res int64 = -1 + if done, err := s.readAllLayerStores(func(store roLayerStore) (bool, error) { if store.Exists(id) { - return store.Size(id) + var err error + res, err = store.Size(id) + return true, err } + return false, nil + }); done { + return res, err } return -1, ErrLayerUnknown } @@ -3043,11 +2835,10 @@ func (s *store) LayerParentOwners(id string) ([]int, []int, error) { if err != nil { return nil, nil, err } - rlstore.RLock() - defer rlstore.Unlock() - if err := rlstore.ReloadIfChanged(); err != nil { + if err := rlstore.startReading(); err != nil { return nil, nil, err } + defer rlstore.stopReading() if rlstore.Exists(id) { return rlstore.ParentOwners(id) } @@ -3063,16 +2854,14 @@ func (s *store) ContainerParentOwners(id string) ([]int, []int, error) { if err != nil { return nil, nil, err } - rlstore.RLock() - defer rlstore.Unlock() - if err := rlstore.ReloadIfChanged(); err != nil { + if err := rlstore.startReading(); err != nil { return nil, nil, err } - rcstore.RLock() - defer rcstore.Unlock() - if err := rcstore.ReloadIfChanged(); err != nil { + defer rlstore.stopReading() + if err := rcstore.startReading(); err != nil { return nil, nil, err } + defer rcstore.stopReading() container, err := rcstore.Get(id) if err != nil { return nil, nil, err @@ -3090,11 +2879,10 @@ func (s *store) Layers() ([]Layer, error) { } layers, err := func() ([]Layer, error) { - lstore.Lock() - defer lstore.Unlock() - if err := lstore.Load(); err != nil { + if err := lstore.startWriting(); err != nil { return nil, err } + defer lstore.stopWriting() return lstore.Layers() }() if err != nil { @@ -3108,11 +2896,10 @@ func (s *store) Layers() ([]Layer, error) { for _, s := range lstores { store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { + if err := store.startReading(); err != nil { return nil, err } + defer store.stopReading() storeLayers, err := store.Layers() if err != nil { return nil, err @@ -3123,23 +2910,16 @@ func (s *store) Layers() ([]Layer, error) { } func (s *store) Images() ([]Image, error) { - imageStores, err := s.allImageStores() - if err != nil { - return nil, err - } var images []Image - for _, s := range imageStores { - store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { - return nil, err - } + if _, err := s.readAllImageStores(func(store roImageStore) (bool, error) { storeImages, err := store.Images() if err != nil { - return nil, err + return true, err } images = append(images, storeImages...) + return false, nil + }); err != nil { + return nil, err } return images, nil } @@ -3150,31 +2930,25 @@ func (s *store) Containers() ([]Container, error) { return nil, err } - rcstore.RLock() - defer rcstore.Unlock() - if err := rcstore.ReloadIfChanged(); err != nil { + if err := rcstore.startReading(); err != nil { return nil, err } + defer rcstore.stopReading() return rcstore.Containers() } func (s *store) Layer(id string) (*Layer, error) { - layerStores, err := s.allLayerStores() - if err != nil { - return nil, err - } - for _, s := range layerStores { - store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { - return nil, err - } + var res *Layer + if done, err := s.readAllLayerStores(func(store roLayerStore) (bool, error) { layer, err := store.Get(id) if err == nil { - return layer, nil + res = layer + return true, nil } + return false, nil + }); done { + return res, err } return nil, ErrLayerUnknown } @@ -3223,11 +2997,10 @@ func (al *additionalLayer) PutAs(id, parent string, names []string) (*Layer, err if err != nil { return nil, err } - rlstore.Lock() - defer rlstore.Unlock() - if err := rlstore.ReloadIfChanged(); err != nil { + if err := rlstore.startWriting(); err != nil { return nil, err } + defer rlstore.stopWriting() rlstores, err := al.s.getROLayerStores() if err != nil { return nil, err @@ -3237,11 +3010,10 @@ func (al *additionalLayer) PutAs(id, parent string, names []string) (*Layer, err if parent != "" { for _, lstore := range append([]roLayerStore{rlstore}, rlstores...) { if lstore != rlstore { - lstore.RLock() - defer lstore.Unlock() - if err := lstore.ReloadIfChanged(); err != nil { + if err := lstore.startReading(); err != nil { return nil, err } + defer lstore.stopReading() } parentLayer, err = lstore.Get(parent) if err == nil { @@ -3261,21 +3033,16 @@ func (al *additionalLayer) Release() { } func (s *store) Image(id string) (*Image, error) { - imageStores, err := s.allImageStores() - if err != nil { - return nil, err - } - for _, s := range imageStores { - store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { - return nil, err - } + var res *Image + if done, err := s.readAllImageStores(func(store roImageStore) (bool, error) { image, err := store.Get(id) if err == nil { - return image, nil + res = image + return true, nil } + return false, nil + }); done { + return res, err } return nil, fmt.Errorf("locating image with ID %q: %w", id, ErrImageUnknown) } @@ -3286,48 +3053,35 @@ func (s *store) ImagesByTopLayer(id string) ([]*Image, error) { return nil, err } - imageStores, err := s.allImageStores() - if err != nil { - return nil, err - } images := []*Image{} - for _, s := range imageStores { - store := s - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { - return nil, err - } + if _, err := s.readAllImageStores(func(store roImageStore) (bool, error) { imageList, err := store.Images() if err != nil { - return nil, err + return true, err } for _, image := range imageList { if image.TopLayer == layer.ID || stringutils.InSlice(image.MappedTopLayers, layer.ID) { images = append(images, &image) } } + return false, nil + }); err != nil { + return nil, err } return images, nil } func (s *store) ImagesByDigest(d digest.Digest) ([]*Image, error) { - imageStores, err := s.allImageStores() - if err != nil { - return nil, err - } images := []*Image{} - for _, store := range imageStores { - store.RLock() - defer store.Unlock() - if err := store.ReloadIfChanged(); err != nil { - return nil, err - } + if _, err := s.readAllImageStores(func(store roImageStore) (bool, error) { imageList, err := store.ByDigest(d) if err != nil && !errors.Is(err, ErrImageUnknown) { - return nil, err + return true, err } images = append(images, imageList...) + return false, nil + }); err != nil { + return nil, err } return images, nil } @@ -3337,11 +3091,10 @@ func (s *store) Container(id string) (*Container, error) { if err != nil { return nil, err } - rcstore.RLock() - defer rcstore.Unlock() - if err := rcstore.ReloadIfChanged(); err != nil { + if err := rcstore.startReading(); err != nil { return nil, err } + defer rcstore.stopReading() return rcstore.Get(id) } @@ -3351,11 +3104,10 @@ func (s *store) ContainerLayerID(id string) (string, error) { if err != nil { return "", err } - rcstore.RLock() - defer rcstore.Unlock() - if err := rcstore.ReloadIfChanged(); err != nil { + if err := rcstore.startReading(); err != nil { return "", err } + defer rcstore.stopReading() container, err := rcstore.Get(id) if err != nil { return "", err @@ -3372,11 +3124,10 @@ func (s *store) ContainerByLayer(id string) (*Container, error) { if err != nil { return nil, err } - rcstore.RLock() - defer rcstore.Unlock() - if err := rcstore.ReloadIfChanged(); err != nil { + if err := rcstore.startReading(); err != nil { return nil, err } + defer rcstore.stopReading() containerList, err := rcstore.Containers() if err != nil { return nil, err @@ -3395,11 +3146,10 @@ func (s *store) ContainerDirectory(id string) (string, error) { if err != nil { return "", err } - rcstore.RLock() - defer rcstore.Unlock() - if err := rcstore.ReloadIfChanged(); err != nil { + if err := rcstore.startReading(); err != nil { return "", err } + defer rcstore.stopReading() id, err = rcstore.Lookup(id) if err != nil { @@ -3420,11 +3170,10 @@ func (s *store) ContainerRunDirectory(id string) (string, error) { return "", err } - rcstore.RLock() - defer rcstore.Unlock() - if err := rcstore.ReloadIfChanged(); err != nil { + if err := rcstore.startReading(); err != nil { return "", err } + defer rcstore.stopReading() id, err = rcstore.Lookup(id) if err != nil { @@ -3481,7 +3230,6 @@ func (s *store) FromContainerRunDirectory(id, file string) ([]byte, error) { func (s *store) Shutdown(force bool) ([]string, error) { mounted := []string{} - modified := false rlstore, err := s.getLayerStore() if err != nil { @@ -3491,11 +3239,10 @@ func (s *store) Shutdown(force bool) ([]string, error) { s.graphLock.Lock() defer s.graphLock.Unlock() - rlstore.Lock() - defer rlstore.Unlock() - if err := rlstore.ReloadIfChanged(); err != nil { + if err := rlstore.startWriting(); err != nil { return nil, err } + defer rlstore.stopWriting() layers, err := rlstore.Layers() if err != nil { @@ -3515,7 +3262,6 @@ func (s *store) Shutdown(force bool) ([]string, error) { } break } - modified = true } } } @@ -3531,16 +3277,6 @@ func (s *store) Shutdown(force bool) ([]string, error) { err = fmt.Errorf("(graphLock.Touch failed: %v) %w", err2, err) } } - modified = true - } - if modified { - if err2 := rlstore.Touch(); err2 != nil { - if err == nil { - err = err2 - } else { - err = fmt.Errorf("rlstore.Touch failed: %v) %w", err2, err) - } - } } return mounted, err }