github.com/uriddle/docker@v0.0.0-20210926094723-4072e6aeb013/volume/store/store.go (about) 1 package store 2 3 import ( 4 "sync" 5 6 "github.com/Sirupsen/logrus" 7 "github.com/docker/docker/pkg/locker" 8 "github.com/docker/docker/volume" 9 "github.com/docker/docker/volume/drivers" 10 ) 11 12 // New initializes a VolumeStore to keep 13 // reference counting of volumes in the system. 14 func New() *VolumeStore { 15 return &VolumeStore{ 16 locks: &locker.Locker{}, 17 names: make(map[string]volume.Volume), 18 refs: make(map[string][]string), 19 } 20 } 21 22 func (s *VolumeStore) getNamed(name string) (volume.Volume, bool) { 23 s.globalLock.Lock() 24 v, exists := s.names[name] 25 s.globalLock.Unlock() 26 return v, exists 27 } 28 29 func (s *VolumeStore) setNamed(v volume.Volume, ref string) { 30 s.globalLock.Lock() 31 s.names[v.Name()] = v 32 if len(ref) > 0 { 33 s.refs[v.Name()] = append(s.refs[v.Name()], ref) 34 } 35 s.globalLock.Unlock() 36 } 37 38 func (s *VolumeStore) purge(name string) { 39 s.globalLock.Lock() 40 delete(s.names, name) 41 delete(s.refs, name) 42 s.globalLock.Unlock() 43 } 44 45 // VolumeStore is a struct that stores the list of volumes available and keeps track of their usage counts 46 type VolumeStore struct { 47 locks *locker.Locker 48 globalLock sync.Mutex 49 // names stores the volume name -> driver name relationship. 50 // This is used for making lookups faster so we don't have to probe all drivers 51 names map[string]volume.Volume 52 // refs stores the volume name and the list of things referencing it 53 refs map[string][]string 54 } 55 56 // List proxies to all registered volume drivers to get the full list of volumes 57 // If a driver returns a volume that has name which conflicts with a another volume from a different driver, 58 // the first volume is chosen and the conflicting volume is dropped. 59 func (s *VolumeStore) List() ([]volume.Volume, []string, error) { 60 vols, warnings, err := s.list() 61 if err != nil { 62 return nil, nil, &OpErr{Err: err, Op: "list"} 63 } 64 var out []volume.Volume 65 66 for _, v := range vols { 67 name := normaliseVolumeName(v.Name()) 68 69 s.locks.Lock(name) 70 storedV, exists := s.getNamed(name) 71 if !exists { 72 s.setNamed(v, "") 73 } 74 if exists && storedV.DriverName() != v.DriverName() { 75 logrus.Warnf("Volume name %s already exists for driver %s, not including volume returned by %s", v.Name(), storedV.DriverName(), v.DriverName()) 76 s.locks.Unlock(v.Name()) 77 continue 78 } 79 80 out = append(out, v) 81 s.locks.Unlock(v.Name()) 82 } 83 return out, warnings, nil 84 } 85 86 // list goes through each volume driver and asks for its list of volumes. 87 func (s *VolumeStore) list() ([]volume.Volume, []string, error) { 88 drivers, err := volumedrivers.GetAllDrivers() 89 if err != nil { 90 return nil, nil, err 91 } 92 var ( 93 ls []volume.Volume 94 warnings []string 95 ) 96 97 type vols struct { 98 vols []volume.Volume 99 err error 100 driverName string 101 } 102 chVols := make(chan vols, len(drivers)) 103 104 for _, vd := range drivers { 105 go func(d volume.Driver) { 106 vs, err := d.List() 107 if err != nil { 108 chVols <- vols{driverName: d.Name(), err: &OpErr{Err: err, Name: d.Name(), Op: "list"}} 109 return 110 } 111 chVols <- vols{vols: vs} 112 }(vd) 113 } 114 115 badDrivers := make(map[string]struct{}) 116 for i := 0; i < len(drivers); i++ { 117 vs := <-chVols 118 119 if vs.err != nil { 120 warnings = append(warnings, vs.err.Error()) 121 badDrivers[vs.driverName] = struct{}{} 122 logrus.Warn(vs.err) 123 } 124 ls = append(ls, vs.vols...) 125 } 126 127 if len(badDrivers) > 0 { 128 for _, v := range s.names { 129 if _, exists := badDrivers[v.DriverName()]; exists { 130 ls = append(ls, v) 131 } 132 } 133 } 134 return ls, warnings, nil 135 } 136 137 // CreateWithRef creates a volume with the given name and driver and stores the ref 138 // This is just like Create() except we store the reference while holding the lock. 139 // This ensures there's no race between creating a volume and then storing a reference. 140 func (s *VolumeStore) CreateWithRef(name, driverName, ref string, opts map[string]string) (volume.Volume, error) { 141 name = normaliseVolumeName(name) 142 s.locks.Lock(name) 143 defer s.locks.Unlock(name) 144 145 v, err := s.create(name, driverName, opts) 146 if err != nil { 147 return nil, &OpErr{Err: err, Name: name, Op: "create"} 148 } 149 150 s.setNamed(v, ref) 151 return v, nil 152 } 153 154 // Create creates a volume with the given name and driver. 155 func (s *VolumeStore) Create(name, driverName string, opts map[string]string) (volume.Volume, error) { 156 name = normaliseVolumeName(name) 157 s.locks.Lock(name) 158 defer s.locks.Unlock(name) 159 160 v, err := s.create(name, driverName, opts) 161 if err != nil { 162 return nil, &OpErr{Err: err, Name: name, Op: "create"} 163 } 164 s.setNamed(v, "") 165 return v, nil 166 } 167 168 // create asks the given driver to create a volume with the name/opts. 169 // If a volume with the name is already known, it will ask the stored driver for the volume. 170 // If the passed in driver name does not match the driver name which is stored for the given volume name, an error is returned. 171 // It is expected that callers of this function hold any neccessary locks. 172 func (s *VolumeStore) create(name, driverName string, opts map[string]string) (volume.Volume, error) { 173 // Validate the name in a platform-specific manner 174 valid, err := volume.IsVolumeNameValid(name) 175 if err != nil { 176 return nil, err 177 } 178 if !valid { 179 return nil, &OpErr{Err: errInvalidName, Name: name, Op: "create"} 180 } 181 182 if v, exists := s.getNamed(name); exists { 183 if v.DriverName() != driverName && driverName != "" && driverName != volume.DefaultDriverName { 184 return nil, errNameConflict 185 } 186 return v, nil 187 } 188 189 logrus.Debugf("Registering new volume reference: driver %s, name %s", driverName, name) 190 vd, err := volumedrivers.GetDriver(driverName) 191 if err != nil { 192 return nil, &OpErr{Op: "create", Name: name, Err: err} 193 } 194 195 return vd.Create(name, opts) 196 } 197 198 // GetWithRef gets a volume with the given name from the passed in driver and stores the ref 199 // This is just like Get(), but we store the reference while holding the lock. 200 // This makes sure there are no races between checking for the existance of a volume and adding a reference for it 201 func (s *VolumeStore) GetWithRef(name, driverName, ref string) (volume.Volume, error) { 202 name = normaliseVolumeName(name) 203 s.locks.Lock(name) 204 defer s.locks.Unlock(name) 205 206 vd, err := volumedrivers.GetDriver(driverName) 207 if err != nil { 208 return nil, &OpErr{Err: err, Name: name, Op: "get"} 209 } 210 211 v, err := vd.Get(name) 212 if err != nil { 213 return nil, &OpErr{Err: err, Name: name, Op: "get"} 214 } 215 216 s.setNamed(v, ref) 217 return v, nil 218 } 219 220 // Get looks if a volume with the given name exists and returns it if so 221 func (s *VolumeStore) Get(name string) (volume.Volume, error) { 222 name = normaliseVolumeName(name) 223 s.locks.Lock(name) 224 defer s.locks.Unlock(name) 225 226 v, err := s.getVolume(name) 227 if err != nil { 228 return nil, &OpErr{Err: err, Name: name, Op: "get"} 229 } 230 s.setNamed(v, "") 231 return v, nil 232 } 233 234 // get requests the volume, if the driver info is stored it just access that driver, 235 // if the driver is unknown it probes all drivers until it finds the first volume with that name. 236 // it is expected that callers of this function hold any neccessary locks 237 func (s *VolumeStore) getVolume(name string) (volume.Volume, error) { 238 logrus.Debugf("Getting volume reference for name: %s", name) 239 if v, exists := s.names[name]; exists { 240 vd, err := volumedrivers.GetDriver(v.DriverName()) 241 if err != nil { 242 return nil, err 243 } 244 return vd.Get(name) 245 } 246 247 logrus.Debugf("Probing all drivers for volume with name: %s", name) 248 drivers, err := volumedrivers.GetAllDrivers() 249 if err != nil { 250 return nil, err 251 } 252 253 for _, d := range drivers { 254 v, err := d.Get(name) 255 if err != nil { 256 continue 257 } 258 return v, nil 259 } 260 return nil, errNoSuchVolume 261 } 262 263 // Remove removes the requested volume. A volume is not removed if it has any refs 264 func (s *VolumeStore) Remove(v volume.Volume) error { 265 name := normaliseVolumeName(v.Name()) 266 s.locks.Lock(name) 267 defer s.locks.Unlock(name) 268 269 if refs, exists := s.refs[name]; exists && len(refs) > 0 { 270 return &OpErr{Err: errVolumeInUse, Name: v.Name(), Op: "remove", Refs: refs} 271 } 272 273 vd, err := volumedrivers.GetDriver(v.DriverName()) 274 if err != nil { 275 return &OpErr{Err: err, Name: vd.Name(), Op: "remove"} 276 } 277 278 logrus.Debugf("Removing volume reference: driver %s, name %s", v.DriverName(), name) 279 if err := vd.Remove(v); err != nil { 280 return &OpErr{Err: err, Name: name, Op: "remove"} 281 } 282 283 s.purge(name) 284 return nil 285 } 286 287 // Dereference removes the specified reference to the volume 288 func (s *VolumeStore) Dereference(v volume.Volume, ref string) { 289 s.locks.Lock(v.Name()) 290 defer s.locks.Unlock(v.Name()) 291 292 s.globalLock.Lock() 293 defer s.globalLock.Unlock() 294 refs, exists := s.refs[v.Name()] 295 if !exists { 296 return 297 } 298 299 for i, r := range refs { 300 if r == ref { 301 s.refs[v.Name()] = append(s.refs[v.Name()][:i], s.refs[v.Name()][i+1:]...) 302 } 303 } 304 } 305 306 // Refs gets the current list of refs for the given volume 307 func (s *VolumeStore) Refs(v volume.Volume) []string { 308 s.locks.Lock(v.Name()) 309 defer s.locks.Unlock(v.Name()) 310 311 s.globalLock.Lock() 312 defer s.globalLock.Unlock() 313 refs, exists := s.refs[v.Name()] 314 if !exists { 315 return nil 316 } 317 318 refsOut := make([]string, len(refs)) 319 copy(refsOut, refs) 320 return refsOut 321 } 322 323 // FilterByDriver returns the available volumes filtered by driver name 324 func (s *VolumeStore) FilterByDriver(name string) ([]volume.Volume, error) { 325 vd, err := volumedrivers.GetDriver(name) 326 if err != nil { 327 return nil, &OpErr{Err: err, Name: name, Op: "list"} 328 } 329 ls, err := vd.List() 330 if err != nil { 331 return nil, &OpErr{Err: err, Name: name, Op: "list"} 332 } 333 return ls, nil 334 } 335 336 // FilterByUsed returns the available volumes filtered by if they are in use or not. 337 // `used=true` returns only volumes that are being used, while `used=false` returns 338 // only volumes that are not being used. 339 func (s *VolumeStore) FilterByUsed(vols []volume.Volume, used bool) []volume.Volume { 340 return s.filter(vols, func(v volume.Volume) bool { 341 s.locks.Lock(v.Name()) 342 l := len(s.refs[v.Name()]) 343 s.locks.Unlock(v.Name()) 344 if (used && l > 0) || (!used && l == 0) { 345 return true 346 } 347 return false 348 }) 349 } 350 351 // filterFunc defines a function to allow filter volumes in the store 352 type filterFunc func(vol volume.Volume) bool 353 354 // filter returns the available volumes filtered by a filterFunc function 355 func (s *VolumeStore) filter(vols []volume.Volume, f filterFunc) []volume.Volume { 356 var ls []volume.Volume 357 for _, v := range vols { 358 if f(v) { 359 ls = append(ls, v) 360 } 361 } 362 return ls 363 }