dotcloud/docker

View on GitHub
volume/service/restore.go

Summary

Maintainability
B
4 hrs
Test Coverage
package service // import "github.com/docker/docker/volume/service"

import (
    "context"
    "sync"

    "github.com/containerd/log"
    "github.com/docker/docker/volume"
    bolt "go.etcd.io/bbolt"
)

// restore is called when a new volume store is created.
// It's primary purpose is to ensure that all drivers' refcounts are set based
// on known volumes after a restart.
// This only attempts to track volumes that are actually stored in the on-disk db.
// It does not probe the available drivers to find anything that may have been added
// out of band.
func (s *VolumeStore) restore() {
    var ls []volumeMetadata
    s.db.View(func(tx *bolt.Tx) error {
        ls = listMeta(tx)
        return nil
    })
    ctx := context.Background()

    chRemove := make(chan *volumeMetadata, len(ls))
    var wg sync.WaitGroup
    for _, meta := range ls {
        wg.Add(1)
        // this is potentially a very slow operation, so do it in a goroutine
        go func(meta volumeMetadata) {
            defer wg.Done()

            var v volume.Volume
            var err error
            if meta.Driver != "" {
                v, err = lookupVolume(ctx, s.drivers, meta.Driver, meta.Name)
                if err != nil && err != errNoSuchVolume {
                    log.G(ctx).WithError(err).WithField("driver", meta.Driver).WithField("volume", meta.Name).Warn("Error restoring volume")
                    return
                }
                if v == nil {
                    // doesn't exist in the driver, remove it from the db
                    chRemove <- &meta
                    return
                }
            } else {
                v, err = s.getVolume(ctx, meta.Name, meta.Driver)
                if err != nil {
                    if err == errNoSuchVolume {
                        chRemove <- &meta
                    }
                    return
                }

                meta.Driver = v.DriverName()
                if err := s.setMeta(v.Name(), meta); err != nil {
                    log.G(ctx).WithError(err).WithField("driver", meta.Driver).WithField("volume", v.Name()).Warn("Error updating volume metadata on restore")
                }
            }

            // increment driver refcount
            s.drivers.CreateDriver(meta.Driver)

            // cache the volume
            s.globalLock.Lock()
            s.options[v.Name()] = meta.Options
            s.labels[v.Name()] = meta.Labels
            s.names[v.Name()] = v
            s.refs[v.Name()] = make(map[string]struct{})
            s.globalLock.Unlock()
        }(meta)
    }

    wg.Wait()
    close(chRemove)
    s.db.Update(func(tx *bolt.Tx) error {
        for meta := range chRemove {
            if err := removeMeta(tx, meta.Name); err != nil {
                log.G(ctx).WithField("volume", meta.Name).Warnf("Error removing stale entry from volume db: %v", err)
            }
        }
        return nil
    })
}