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 }) }