Merge pull request #29664 from cpuguy83/fix_bolt_usage

Fix usage of boltdb in volume restore
This commit is contained in:
Anusha Ragunathan 2016-12-22 13:53:04 -08:00 committed by GitHub
commit d25186a625
2 changed files with 33 additions and 31 deletions

View File

@ -3,17 +3,13 @@ package store
import ( import (
"encoding/json" "encoding/json"
"github.com/Sirupsen/logrus"
"github.com/boltdb/bolt" "github.com/boltdb/bolt"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
var volumeBucketName = []byte("volumes") var volumeBucketName = []byte("volumes")
type dbEntry struct {
Key []byte
Value []byte
}
type volumeMetadata struct { type volumeMetadata struct {
Name string Name string
Driver string Driver string
@ -67,12 +63,26 @@ func removeMeta(tx *bolt.Tx, name string) error {
return errors.Wrap(b.Delete([]byte(name)), "error removing volume metadata") return errors.Wrap(b.Delete([]byte(name)), "error removing volume metadata")
} }
func listEntries(tx *bolt.Tx) []*dbEntry { // listMeta is used during restore to get the list of volume metadata
var entries []*dbEntry // from the on-disk database.
// Any errors that occur are only logged.
func listMeta(tx *bolt.Tx) []volumeMetadata {
var ls []volumeMetadata
b := tx.Bucket(volumeBucketName) b := tx.Bucket(volumeBucketName)
b.ForEach(func(k, v []byte) error { b.ForEach(func(k, v []byte) error {
entries = append(entries, &dbEntry{k, v}) if len(v) == 0 {
// don't try to unmarshal an empty value
return nil
}
var m volumeMetadata
if err := json.Unmarshal(v, &m); err != nil {
// Just log the error
logrus.Errorf("Error while reading volume metadata for volume %q: %v", string(k), err)
return nil
}
ls = append(ls, m)
return nil return nil
}) })
return entries return ls
} }

View File

@ -1,7 +1,6 @@
package store package store
import ( import (
"encoding/json"
"sync" "sync"
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
@ -17,45 +16,38 @@ import (
// It does not probe the available drivers to find anything that may have been added // It does not probe the available drivers to find anything that may have been added
// out of band. // out of band.
func (s *VolumeStore) restore() { func (s *VolumeStore) restore() {
var entries []*dbEntry var ls []volumeMetadata
s.db.View(func(tx *bolt.Tx) error { s.db.View(func(tx *bolt.Tx) error {
entries = listEntries(tx) ls = listMeta(tx)
return nil return nil
}) })
chRemove := make(chan []byte, len(entries)) chRemove := make(chan *volumeMetadata, len(ls))
var wg sync.WaitGroup var wg sync.WaitGroup
for _, entry := range entries { for _, meta := range ls {
wg.Add(1) wg.Add(1)
// this is potentially a very slow operation, so do it in a goroutine // this is potentially a very slow operation, so do it in a goroutine
go func(entry *dbEntry) { go func(meta volumeMetadata) {
defer wg.Done() 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 v volume.Volume
var err error var err error
if meta.Driver != "" { if meta.Driver != "" {
v, err = lookupVolume(meta.Driver, string(entry.Key)) v, err = lookupVolume(meta.Driver, meta.Name)
if err != nil && err != errNoSuchVolume { if err != nil && err != errNoSuchVolume {
logrus.WithError(err).WithField("driver", meta.Driver).WithField("volume", string(entry.Key)).Warn("Error restoring volume") logrus.WithError(err).WithField("driver", meta.Driver).WithField("volume", meta.Name).Warn("Error restoring volume")
return return
} }
if v == nil { if v == nil {
// doesn't exist in the driver, remove it from the db // doesn't exist in the driver, remove it from the db
chRemove <- entry.Key chRemove <- &meta
return return
} }
} else { } else {
v, err = s.getVolume(string(entry.Key)) v, err = s.getVolume(meta.Name)
if err != nil { if err != nil {
if err == errNoSuchVolume { if err == errNoSuchVolume {
chRemove <- entry.Key chRemove <- &meta
} }
return return
} }
@ -75,15 +67,15 @@ func (s *VolumeStore) restore() {
s.labels[v.Name()] = meta.Labels s.labels[v.Name()] = meta.Labels
s.names[v.Name()] = v s.names[v.Name()] = v
s.globalLock.Unlock() s.globalLock.Unlock()
}(entry) }(meta)
} }
wg.Wait() wg.Wait()
close(chRemove) close(chRemove)
s.db.Update(func(tx *bolt.Tx) error { s.db.Update(func(tx *bolt.Tx) error {
for k := range chRemove { for meta := range chRemove {
if err := removeMeta(tx, string(k)); err != nil { if err := removeMeta(tx, meta.Name); err != nil {
logrus.Warnf("Error removing stale entry from volume db: %v", err) logrus.WithField("volume", meta.Name).Warnf("Error removing stale entry from volume db: %v", err)
} }
} }
return nil return nil