github.com/ncdc/docker@v0.10.1-0.20160129113957-6c6729ef5b74/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 if v, err := vd.Get(name); err == nil { 196 return v, nil 197 } 198 return vd.Create(name, opts) 199 } 200 201 // GetWithRef gets a volume with the given name from the passed in driver and stores the ref 202 // This is just like Get(), but we store the reference while holding the lock. 203 // This makes sure there are no races between checking for the existance of a volume and adding a reference for it 204 func (s *VolumeStore) GetWithRef(name, driverName, ref string) (volume.Volume, error) { 205 name = normaliseVolumeName(name) 206 s.locks.Lock(name) 207 defer s.locks.Unlock(name) 208 209 vd, err := volumedrivers.GetDriver(driverName) 210 if err != nil { 211 return nil, &OpErr{Err: err, Name: name, Op: "get"} 212 } 213 214 v, err := vd.Get(name) 215 if err != nil { 216 return nil, &OpErr{Err: err, Name: name, Op: "get"} 217 } 218 219 s.setNamed(v, ref) 220 return v, nil 221 } 222 223 // Get looks if a volume with the given name exists and returns it if so 224 func (s *VolumeStore) Get(name string) (volume.Volume, error) { 225 name = normaliseVolumeName(name) 226 s.locks.Lock(name) 227 defer s.locks.Unlock(name) 228 229 v, err := s.getVolume(name) 230 if err != nil { 231 return nil, &OpErr{Err: err, Name: name, Op: "get"} 232 } 233 s.setNamed(v, "") 234 return v, nil 235 } 236 237 // get requests the volume, if the driver info is stored it just access that driver, 238 // if the driver is unknown it probes all drivers until it finds the first volume with that name. 239 // it is expected that callers of this function hold any neccessary locks 240 func (s *VolumeStore) getVolume(name string) (volume.Volume, error) { 241 logrus.Debugf("Getting volume reference for name: %s", name) 242 if v, exists := s.names[name]; exists { 243 vd, err := volumedrivers.GetDriver(v.DriverName()) 244 if err != nil { 245 return nil, err 246 } 247 return vd.Get(name) 248 } 249 250 logrus.Debugf("Probing all drivers for volume with name: %s", name) 251 drivers, err := volumedrivers.GetAllDrivers() 252 if err != nil { 253 return nil, err 254 } 255 256 for _, d := range drivers { 257 v, err := d.Get(name) 258 if err != nil { 259 continue 260 } 261 return v, nil 262 } 263 return nil, errNoSuchVolume 264 } 265 266 // Remove removes the requested volume. A volume is not removed if it has any refs 267 func (s *VolumeStore) Remove(v volume.Volume) error { 268 name := normaliseVolumeName(v.Name()) 269 s.locks.Lock(name) 270 defer s.locks.Unlock(name) 271 272 if refs, exists := s.refs[name]; exists && len(refs) > 0 { 273 return &OpErr{Err: errVolumeInUse, Name: v.Name(), Op: "remove", Refs: refs} 274 } 275 276 vd, err := volumedrivers.GetDriver(v.DriverName()) 277 if err != nil { 278 return &OpErr{Err: err, Name: vd.Name(), Op: "remove"} 279 } 280 281 logrus.Debugf("Removing volume reference: driver %s, name %s", v.DriverName(), name) 282 if err := vd.Remove(v); err != nil { 283 return &OpErr{Err: err, Name: name, Op: "remove"} 284 } 285 286 s.purge(name) 287 return nil 288 } 289 290 // Dereference removes the specified reference to the volume 291 func (s *VolumeStore) Dereference(v volume.Volume, ref string) { 292 s.locks.Lock(v.Name()) 293 defer s.locks.Unlock(v.Name()) 294 295 s.globalLock.Lock() 296 defer s.globalLock.Unlock() 297 refs, exists := s.refs[v.Name()] 298 if !exists { 299 return 300 } 301 302 for i, r := range refs { 303 if r == ref { 304 s.refs[v.Name()] = append(s.refs[v.Name()][:i], s.refs[v.Name()][i+1:]...) 305 } 306 } 307 } 308 309 // Refs gets the current list of refs for the given volume 310 func (s *VolumeStore) Refs(v volume.Volume) []string { 311 s.locks.Lock(v.Name()) 312 defer s.locks.Unlock(v.Name()) 313 314 s.globalLock.Lock() 315 defer s.globalLock.Unlock() 316 refs, exists := s.refs[v.Name()] 317 if !exists { 318 return nil 319 } 320 321 refsOut := make([]string, len(refs)) 322 copy(refsOut, refs) 323 return refsOut 324 } 325 326 // FilterByDriver returns the available volumes filtered by driver name 327 func (s *VolumeStore) FilterByDriver(name string) ([]volume.Volume, error) { 328 vd, err := volumedrivers.GetDriver(name) 329 if err != nil { 330 return nil, &OpErr{Err: err, Name: name, Op: "list"} 331 } 332 ls, err := vd.List() 333 if err != nil { 334 return nil, &OpErr{Err: err, Name: name, Op: "list"} 335 } 336 return ls, nil 337 } 338 339 // FilterByUsed returns the available volumes filtered by if they are in use or not. 340 // `used=true` returns only volumes that are being used, while `used=false` returns 341 // only volumes that are not being used. 342 func (s *VolumeStore) FilterByUsed(vols []volume.Volume, used bool) []volume.Volume { 343 return s.filter(vols, func(v volume.Volume) bool { 344 s.locks.Lock(v.Name()) 345 l := len(s.refs[v.Name()]) 346 s.locks.Unlock(v.Name()) 347 if (used && l > 0) || (!used && l == 0) { 348 return true 349 } 350 return false 351 }) 352 } 353 354 // filterFunc defines a function to allow filter volumes in the store 355 type filterFunc func(vol volume.Volume) bool 356 357 // filter returns the available volumes filtered by a filterFunc function 358 func (s *VolumeStore) filter(vols []volume.Volume, f filterFunc) []volume.Volume { 359 var ls []volume.Volume 360 for _, v := range vols { 361 if f(v) { 362 ls = append(ls, v) 363 } 364 } 365 return ls 366 }