|
@@ -67,7 +67,7 @@ func New(rootPath string) (*VolumeStore, error) {
|
|
vs := &VolumeStore{
|
|
vs := &VolumeStore{
|
|
locks: &locker.Locker{},
|
|
locks: &locker.Locker{},
|
|
names: make(map[string]volume.Volume),
|
|
names: make(map[string]volume.Volume),
|
|
- refs: make(map[string][]string),
|
|
|
|
|
|
+ refs: make(map[string]map[string]struct{}),
|
|
labels: make(map[string]map[string]string),
|
|
labels: make(map[string]map[string]string),
|
|
options: make(map[string]map[string]string),
|
|
options: make(map[string]map[string]string),
|
|
}
|
|
}
|
|
@@ -110,20 +110,39 @@ func (s *VolumeStore) getNamed(name string) (volume.Volume, bool) {
|
|
}
|
|
}
|
|
|
|
|
|
func (s *VolumeStore) setNamed(v volume.Volume, ref string) {
|
|
func (s *VolumeStore) setNamed(v volume.Volume, ref string) {
|
|
|
|
+ name := v.Name()
|
|
|
|
+
|
|
s.globalLock.Lock()
|
|
s.globalLock.Lock()
|
|
- s.names[v.Name()] = v
|
|
|
|
|
|
+ s.names[name] = v
|
|
if len(ref) > 0 {
|
|
if len(ref) > 0 {
|
|
- s.refs[v.Name()] = append(s.refs[v.Name()], ref)
|
|
|
|
|
|
+ if s.refs[name] == nil {
|
|
|
|
+ s.refs[name] = make(map[string]struct{})
|
|
|
|
+ }
|
|
|
|
+ s.refs[name][ref] = struct{}{}
|
|
}
|
|
}
|
|
s.globalLock.Unlock()
|
|
s.globalLock.Unlock()
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// hasRef returns true if the given name has at least one ref.
|
|
|
|
+// Callers of this function are expected to hold the name lock.
|
|
|
|
+func (s *VolumeStore) hasRef(name string) bool {
|
|
|
|
+ s.globalLock.RLock()
|
|
|
|
+ l := len(s.refs[name])
|
|
|
|
+ s.globalLock.RUnlock()
|
|
|
|
+ return l > 0
|
|
|
|
+}
|
|
|
|
+
|
|
// getRefs gets the list of refs for a given name
|
|
// getRefs gets the list of refs for a given name
|
|
// Callers of this function are expected to hold the name lock.
|
|
// Callers of this function are expected to hold the name lock.
|
|
func (s *VolumeStore) getRefs(name string) []string {
|
|
func (s *VolumeStore) getRefs(name string) []string {
|
|
s.globalLock.RLock()
|
|
s.globalLock.RLock()
|
|
- refs := s.refs[name]
|
|
|
|
- s.globalLock.RUnlock()
|
|
|
|
|
|
+ defer s.globalLock.RUnlock()
|
|
|
|
+
|
|
|
|
+ refs := make([]string, 0, len(s.refs[name]))
|
|
|
|
+ for r := range s.refs[name] {
|
|
|
|
+ refs = append(refs, r)
|
|
|
|
+ }
|
|
|
|
+
|
|
return refs
|
|
return refs
|
|
}
|
|
}
|
|
|
|
|
|
@@ -149,7 +168,7 @@ type VolumeStore struct {
|
|
// This is used for making lookups faster so we don't have to probe all drivers
|
|
// This is used for making lookups faster so we don't have to probe all drivers
|
|
names map[string]volume.Volume
|
|
names map[string]volume.Volume
|
|
// refs stores the volume name and the list of things referencing it
|
|
// refs stores the volume name and the list of things referencing it
|
|
- refs map[string][]string
|
|
|
|
|
|
+ refs map[string]map[string]struct{}
|
|
// labels stores volume labels for each volume
|
|
// labels stores volume labels for each volume
|
|
labels map[string]map[string]string
|
|
labels map[string]map[string]string
|
|
// options stores volume options for each volume
|
|
// options stores volume options for each volume
|
|
@@ -308,7 +327,7 @@ func (s *VolumeStore) checkConflict(name, driverName string) (volume.Volume, err
|
|
return v, nil
|
|
return v, nil
|
|
}
|
|
}
|
|
|
|
|
|
- if len(s.getRefs(v.Name())) > 0 {
|
|
|
|
|
|
+ if s.hasRef(v.Name()) {
|
|
// Containers are referencing this volume but it doesn't seem to exist anywhere.
|
|
// Containers are referencing this volume but it doesn't seem to exist anywhere.
|
|
// Return a conflict error here, the user can fix this with `docker volume rm -f`
|
|
// Return a conflict error here, the user can fix this with `docker volume rm -f`
|
|
return nil, errors.Wrapf(errNameConflict, "found references to volume '%s' in driver '%s' but the volume was not found in the driver -- you may need to remove containers referencing this volume or force remove the volume to re-create it", name, vDriverName)
|
|
return nil, errors.Wrapf(errNameConflict, "found references to volume '%s' in driver '%s' but the volume was not found in the driver -- you may need to remove containers referencing this volume or force remove the volume to re-create it", name, vDriverName)
|
|
@@ -393,6 +412,7 @@ func (s *VolumeStore) create(name, driverName string, opts, labels map[string]st
|
|
s.globalLock.Lock()
|
|
s.globalLock.Lock()
|
|
s.labels[name] = labels
|
|
s.labels[name] = labels
|
|
s.options[name] = opts
|
|
s.options[name] = opts
|
|
|
|
+ s.refs[name] = make(map[string]struct{})
|
|
s.globalLock.Unlock()
|
|
s.globalLock.Unlock()
|
|
|
|
|
|
if s.db != nil {
|
|
if s.db != nil {
|
|
@@ -529,9 +549,8 @@ func (s *VolumeStore) Remove(v volume.Volume) error {
|
|
s.locks.Lock(name)
|
|
s.locks.Lock(name)
|
|
defer s.locks.Unlock(name)
|
|
defer s.locks.Unlock(name)
|
|
|
|
|
|
- refs := s.getRefs(name)
|
|
|
|
- if len(refs) > 0 {
|
|
|
|
- return &OpErr{Err: errVolumeInUse, Name: v.Name(), Op: "remove", Refs: refs}
|
|
|
|
|
|
+ if s.hasRef(name) {
|
|
|
|
+ return &OpErr{Err: errVolumeInUse, Name: v.Name(), Op: "remove", Refs: s.getRefs(name)}
|
|
}
|
|
}
|
|
|
|
|
|
vd, err := volumedrivers.RemoveDriver(v.DriverName())
|
|
vd, err := volumedrivers.RemoveDriver(v.DriverName())
|
|
@@ -551,30 +570,27 @@ func (s *VolumeStore) Remove(v volume.Volume) error {
|
|
|
|
|
|
// Dereference removes the specified reference to the volume
|
|
// Dereference removes the specified reference to the volume
|
|
func (s *VolumeStore) Dereference(v volume.Volume, ref string) {
|
|
func (s *VolumeStore) Dereference(v volume.Volume, ref string) {
|
|
- s.locks.Lock(v.Name())
|
|
|
|
- defer s.locks.Unlock(v.Name())
|
|
|
|
|
|
+ name := v.Name()
|
|
|
|
+
|
|
|
|
+ s.locks.Lock(name)
|
|
|
|
+ defer s.locks.Unlock(name)
|
|
|
|
|
|
s.globalLock.Lock()
|
|
s.globalLock.Lock()
|
|
defer s.globalLock.Unlock()
|
|
defer s.globalLock.Unlock()
|
|
- var refs []string
|
|
|
|
|
|
|
|
- for _, r := range s.refs[v.Name()] {
|
|
|
|
- if r != ref {
|
|
|
|
- refs = append(refs, r)
|
|
|
|
- }
|
|
|
|
|
|
+ if s.refs[name] != nil {
|
|
|
|
+ delete(s.refs[name], ref)
|
|
}
|
|
}
|
|
- s.refs[v.Name()] = refs
|
|
|
|
}
|
|
}
|
|
|
|
|
|
// Refs gets the current list of refs for the given volume
|
|
// Refs gets the current list of refs for the given volume
|
|
func (s *VolumeStore) Refs(v volume.Volume) []string {
|
|
func (s *VolumeStore) Refs(v volume.Volume) []string {
|
|
- s.locks.Lock(v.Name())
|
|
|
|
- defer s.locks.Unlock(v.Name())
|
|
|
|
|
|
+ name := v.Name()
|
|
|
|
+
|
|
|
|
+ s.locks.Lock(name)
|
|
|
|
+ defer s.locks.Unlock(name)
|
|
|
|
|
|
- refs := s.getRefs(v.Name())
|
|
|
|
- refsOut := make([]string, len(refs))
|
|
|
|
- copy(refsOut, refs)
|
|
|
|
- return refsOut
|
|
|
|
|
|
+ return s.getRefs(name)
|
|
}
|
|
}
|
|
|
|
|
|
// FilterByDriver returns the available volumes filtered by driver name
|
|
// FilterByDriver returns the available volumes filtered by driver name
|
|
@@ -605,9 +621,9 @@ func (s *VolumeStore) FilterByDriver(name string) ([]volume.Volume, error) {
|
|
func (s *VolumeStore) FilterByUsed(vols []volume.Volume, used bool) []volume.Volume {
|
|
func (s *VolumeStore) FilterByUsed(vols []volume.Volume, used bool) []volume.Volume {
|
|
return s.filter(vols, func(v volume.Volume) bool {
|
|
return s.filter(vols, func(v volume.Volume) bool {
|
|
s.locks.Lock(v.Name())
|
|
s.locks.Lock(v.Name())
|
|
- l := len(s.getRefs(v.Name()))
|
|
|
|
|
|
+ hasRef := s.hasRef(v.Name())
|
|
s.locks.Unlock(v.Name())
|
|
s.locks.Unlock(v.Name())
|
|
- if (used && l > 0) || (!used && l == 0) {
|
|
|
|
|
|
+ if used == hasRef {
|
|
return true
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
return false
|