Forráskód Böngészése

Merge pull request #29153 from aaronlehmann/volume-refs-map

volume: Use a map of maps for VolumeStore.refs
Antonio Murdaca 8 éve
szülő
commit
fa45184713
1 módosított fájl, 42 hozzáadás és 26 törlés
  1. 42 26
      volume/store/store.go

+ 42 - 26
volume/store/store.go

@@ -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