Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move locking responsibility from store.go to the container/image/layer stores #1395

Merged
merged 32 commits into from
Oct 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
749be71
Copy methods from included interfaces directly into rwContainerStore
mtrmac Oct 12, 2022
243ec61
Replace containerStore.{RLock,Unlock} with {startReading,stopReading}
mtrmac Oct 12, 2022
dcefc6d
Replace containerStore.{Lock,Unlock} with {startWriting,stopWriting}
mtrmac Oct 12, 2022
607ceb6
Avoid a warning that is now reported
mtrmac Oct 12, 2022
a64b85d
Remove completely unused methods from rwContainerStore
mtrmac Oct 12, 2022
409ee3e
Remove unused lockfile forwarders from rwContainerStore API
mtrmac Oct 12, 2022
58f1120
Remove Load() and ReloadIfChanged() from rwContainerStore API
mtrmac Oct 12, 2022
4c55fad
Remove Save() from rwContainerStore API
mtrmac Oct 12, 2022
b44c193
Remove Lock/Unlock methods from rwContainerStore
mtrmac Oct 12, 2022
adae72b
Move containerStore.ReloadIfChanged
mtrmac Oct 12, 2022
9844aa3
Copy methods from included interfaces directly into *ImageStore
mtrmac Oct 12, 2022
a047bc1
Replace imageStore.{RLock,Unlock} with {startReading,stopReading}
mtrmac Oct 12, 2022
2f68ba2
Replace imageStore.{Lock,Unlock} with {startWriting,stopWriting}
mtrmac Oct 12, 2022
d312f1d
Move the writing lock methods from roImageStore to rwImageStore
mtrmac Oct 12, 2022
19659d9
Remove a completely unused method from roImageStore
mtrmac Oct 12, 2022
77ab6e4
Remove unused lockfile forwarders from roImageStore API
mtrmac Oct 12, 2022
097e954
Remove Load() and ReloadIfChanged() from roImageStore API
mtrmac Oct 12, 2022
5f6642c
Remove a redundant rwImageStore.Save() call
mtrmac Oct 12, 2022
8af42de
Remove Save() from rwImageStore API
mtrmac Oct 12, 2022
360bfae
Remove Lock/Unlock methods from imageStore
mtrmac Oct 12, 2022
8db2532
Move imageStore.ReloadIfChanged
mtrmac Oct 12, 2022
d5b48be
Copy methods from included interfaces directly into *LayerStore
mtrmac Oct 12, 2022
c4089b6
Replace layerStore.{RLock,Unlock} with {startReading,stopReading}
mtrmac Oct 12, 2022
f9678cd
Replace layerStore.{Lock,Unlock} with {startWriting,stopWriting}
mtrmac Oct 12, 2022
c935245
Move the writing lock methods from roLayerStore to rwLayerStore
mtrmac Oct 12, 2022
124e526
Remove a completely unused method from roLayerStore
mtrmac Oct 12, 2022
5791a56
Remove unused lockfile forwarders from roLayerStore API
mtrmac Oct 13, 2022
ee97086
Remove Modified() from the roLayerStore API
mtrmac Oct 13, 2022
328ccce
Remove Load() and ReloadIfChanged() from roLayerStore API
mtrmac Oct 13, 2022
d2defdb
Remove Save() from rwLayerStore API
mtrmac Oct 13, 2022
dbe5fe3
Remove Lock/Unlock methods from layerStore
mtrmac Oct 13, 2022
d0ad132
Move layerStore.{ReloadIfChanged,Modified}
mtrmac Oct 13, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
143 changes: 95 additions & 48 deletions containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -163,6 +176,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 {
Expand All @@ -183,6 +267,8 @@ func (r *containerStore) datapath(id, key string) string {
return filepath.Join(r.datadir(id), makeBigDataBaseName(key))
}

// 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()
Expand Down Expand Up @@ -221,8 +307,10 @@ func (r *containerStore) Load() error {
return nil
}

// Save saves the contents of the store to disk. It should be called with
// the lock held.
func (r *containerStore) Save() error {
if !r.Locked() {
if !r.lockfile.Locked() {
return errors.New("container store is not locked")
}
rpath := r.containerspath()
Expand All @@ -236,7 +324,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) {
Expand All @@ -255,8 +343,10 @@ func newContainerStore(dir string) (rwContainerStore, error) {
bylayer: make(map[string]*Container),
byname: make(map[string]*Container),
}
cstore.Lock()
defer cstore.Unlock()
if err := cstore.startWritingWithReload(false); err != nil {
return nil, err
}
defer cstore.stopWriting()
if err := cstore.Load(); err != nil {
return nil, err
}
Expand Down Expand Up @@ -595,46 +685,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
}