1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00
moby--moby/volume/store/restore.go
Brian Goff 6ef1060cd0 Fix volume plugin refecounting on daemon restart
Ensures all known volumes (known b/c they are persisted to disk) have
their volume drivers refcounted properly.

In testing this, I found an issue with `--live-restore` (required since
currently the provided volume plugin doesn't keep state on restart)
where restorted plugins did not have a plugin client loaded causing a
panic when trying to use the plugin.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-12-16 10:14:06 -05:00

91 lines
2.5 KiB
Go

package store
import (
"encoding/json"
"sync"
"github.com/Sirupsen/logrus"
"github.com/boltdb/bolt"
"github.com/docker/docker/volume"
"github.com/docker/docker/volume/drivers"
)
// 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 entries []*dbEntry
s.db.View(func(tx *bolt.Tx) error {
entries = listEntries(tx)
return nil
})
chRemove := make(chan []byte, len(entries))
var wg sync.WaitGroup
for _, entry := range entries {
wg.Add(1)
// this is potentially a very slow operation, so do it in a goroutine
go func(entry *dbEntry) {
defer wg.Done()
var meta volumeMetadata
if len(entry.Value) != 0 {
if err := json.Unmarshal(entry.Value, &meta); err != nil {
logrus.Errorf("Error while reading volume metadata for volume %q: %v", string(entry.Key), err)
// don't return here, we can try with `getVolume` below
}
}
var v volume.Volume
var err error
if meta.Driver != "" {
v, err = lookupVolume(meta.Driver, string(entry.Key))
if err != nil && err != errNoSuchVolume {
logrus.WithError(err).WithField("driver", meta.Driver).WithField("volume", string(entry.Key)).Warn("Error restoring volume")
return
}
if v == nil {
// doesn't exist in the driver, remove it from the db
chRemove <- entry.Key
return
}
} else {
v, err = s.getVolume(string(entry.Key))
if err != nil {
if err == errNoSuchVolume {
chRemove <- entry.Key
}
return
}
meta.Driver = v.DriverName()
if err := s.setMeta(v.Name(), meta); err != nil {
logrus.WithError(err).WithField("driver", meta.Driver).WithField("volume", v.Name()).Warn("Error updating volume metadata on restore")
}
}
// increment driver refcount
volumedrivers.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.globalLock.Unlock()
}(entry)
}
wg.Wait()
close(chRemove)
s.db.Update(func(tx *bolt.Tx) error {
for k := range chRemove {
if err := removeMeta(tx, string(k)); err != nil {
logrus.Warnf("Error removing stale entry from volume db: %v", err)
}
}
return nil
})
}