github.com/endocode/docker@v1.4.2-0.20160113120958-46eb4700391e/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]string), 18 refs: make(map[string][]string), 19 } 20 } 21 22 func (s *VolumeStore) getNamed(name string) (string, bool) { 23 s.globalLock.Lock() 24 driverName, exists := s.names[name] 25 s.globalLock.Unlock() 26 return driverName, exists 27 } 28 29 func (s *VolumeStore) setNamed(name, driver, ref string) { 30 s.globalLock.Lock() 31 s.names[name] = driver 32 if len(ref) > 0 { 33 s.refs[name] = append(s.refs[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]string 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 driverName, exists := s.getNamed(name) 71 if !exists { 72 s.setNamed(name, v.DriverName(), "") 73 } 74 if exists && driverName != v.DriverName() { 75 logrus.Warnf("Volume name %s already exists for driver %s, not including volume returned by %s", v.Name(), 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 } 101 chVols := make(chan vols, len(drivers)) 102 103 for _, vd := range drivers { 104 go func(d volume.Driver) { 105 vs, err := d.List() 106 if err != nil { 107 chVols <- vols{err: &OpErr{Err: err, Name: d.Name(), Op: "list"}} 108 return 109 } 110 chVols <- vols{vols: vs} 111 }(vd) 112 } 113 114 for i := 0; i < len(drivers); i++ { 115 vs := <-chVols 116 117 if vs.err != nil { 118 warnings = append(warnings, vs.err.Error()) 119 logrus.Warn(vs.err) 120 continue 121 } 122 ls = append(ls, vs.vols...) 123 } 124 return ls, warnings, nil 125 } 126 127 // CreateWithRef creates a volume with the given name and driver and stores the ref 128 // This is just like Create() except we store the reference while holding the lock. 129 // This ensures there's no race between creating a volume and then storing a reference. 130 func (s *VolumeStore) CreateWithRef(name, driverName, ref string, opts map[string]string) (volume.Volume, error) { 131 name = normaliseVolumeName(name) 132 s.locks.Lock(name) 133 defer s.locks.Unlock(name) 134 135 v, err := s.create(name, driverName, opts) 136 if err != nil { 137 return nil, &OpErr{Err: err, Name: name, Op: "create"} 138 } 139 140 s.setNamed(name, v.DriverName(), ref) 141 return v, nil 142 } 143 144 // Create creates a volume with the given name and driver. 145 func (s *VolumeStore) Create(name, driverName string, opts map[string]string) (volume.Volume, error) { 146 name = normaliseVolumeName(name) 147 s.locks.Lock(name) 148 defer s.locks.Unlock(name) 149 150 v, err := s.create(name, driverName, opts) 151 if err != nil { 152 return nil, &OpErr{Err: err, Name: name, Op: "create"} 153 } 154 s.setNamed(name, v.DriverName(), "") 155 return v, nil 156 } 157 158 // create asks the given driver to create a volume with the name/opts. 159 // If a volume with the name is already known, it will ask the stored driver for the volume. 160 // If the passed in driver name does not match the driver name which is stored for the given volume name, an error is returned. 161 // It is expected that callers of this function hold any neccessary locks. 162 func (s *VolumeStore) create(name, driverName string, opts map[string]string) (volume.Volume, error) { 163 // Validate the name in a platform-specific manner 164 valid, err := volume.IsVolumeNameValid(name) 165 if err != nil { 166 return nil, err 167 } 168 if !valid { 169 return nil, &OpErr{Err: errInvalidName, Name: name, Op: "create"} 170 } 171 172 vdName, exists := s.getNamed(name) 173 if exists { 174 if vdName != driverName && driverName != "" && driverName != volume.DefaultDriverName { 175 return nil, errNameConflict 176 } 177 driverName = vdName 178 } 179 180 logrus.Debugf("Registering new volume reference: driver %s, name %s", driverName, name) 181 vd, err := volumedrivers.GetDriver(driverName) 182 if err != nil { 183 return nil, &OpErr{Op: "create", Name: name, Err: err} 184 } 185 186 if v, err := vd.Get(name); err == nil { 187 return v, nil 188 } 189 return vd.Create(name, opts) 190 } 191 192 // GetWithRef gets a volume with the given name from the passed in driver and stores the ref 193 // This is just like Get(), but we store the reference while holding the lock. 194 // This makes sure there are no races between checking for the existance of a volume and adding a reference for it 195 func (s *VolumeStore) GetWithRef(name, driverName, ref string) (volume.Volume, error) { 196 name = normaliseVolumeName(name) 197 s.locks.Lock(name) 198 defer s.locks.Unlock(name) 199 200 vd, err := volumedrivers.GetDriver(driverName) 201 if err != nil { 202 return nil, &OpErr{Err: err, Name: name, Op: "get"} 203 } 204 205 v, err := vd.Get(name) 206 if err != nil { 207 return nil, &OpErr{Err: err, Name: name, Op: "get"} 208 } 209 210 s.setNamed(name, v.DriverName(), ref) 211 return v, nil 212 } 213 214 // Get looks if a volume with the given name exists and returns it if so 215 func (s *VolumeStore) Get(name string) (volume.Volume, error) { 216 name = normaliseVolumeName(name) 217 s.locks.Lock(name) 218 defer s.locks.Unlock(name) 219 220 v, err := s.getVolume(name) 221 if err != nil { 222 return nil, &OpErr{Err: err, Name: name, Op: "get"} 223 } 224 return v, nil 225 } 226 227 // get requests the volume, if the driver info is stored it just access that driver, 228 // if the driver is unknown it probes all drivers until it finds the first volume with that name. 229 // it is expected that callers of this function hold any neccessary locks 230 func (s *VolumeStore) getVolume(name string) (volume.Volume, error) { 231 logrus.Debugf("Getting volume reference for name: %s", name) 232 if vdName, exists := s.names[name]; exists { 233 vd, err := volumedrivers.GetDriver(vdName) 234 if err != nil { 235 return nil, err 236 } 237 return vd.Get(name) 238 } 239 240 logrus.Debugf("Probing all drivers for volume with name: %s", name) 241 drivers, err := volumedrivers.GetAllDrivers() 242 if err != nil { 243 return nil, err 244 } 245 246 for _, d := range drivers { 247 v, err := d.Get(name) 248 if err != nil { 249 continue 250 } 251 return v, nil 252 } 253 return nil, errNoSuchVolume 254 } 255 256 // Remove removes the requested volume. A volume is not removed if it has any refs 257 func (s *VolumeStore) Remove(v volume.Volume) error { 258 name := normaliseVolumeName(v.Name()) 259 s.locks.Lock(name) 260 defer s.locks.Unlock(name) 261 262 if refs, exists := s.refs[name]; exists && len(refs) > 0 { 263 return &OpErr{Err: errVolumeInUse, Name: v.Name(), Op: "remove", Refs: refs} 264 } 265 266 vd, err := volumedrivers.GetDriver(v.DriverName()) 267 if err != nil { 268 return &OpErr{Err: err, Name: vd.Name(), Op: "remove"} 269 } 270 271 logrus.Debugf("Removing volume reference: driver %s, name %s", v.DriverName(), name) 272 if err := vd.Remove(v); err != nil { 273 return &OpErr{Err: err, Name: name, Op: "remove"} 274 } 275 276 s.purge(name) 277 return nil 278 } 279 280 // Dereference removes the specified reference to the volume 281 func (s *VolumeStore) Dereference(v volume.Volume, ref string) { 282 s.locks.Lock(v.Name()) 283 defer s.locks.Unlock(v.Name()) 284 285 s.globalLock.Lock() 286 refs, exists := s.refs[v.Name()] 287 if !exists { 288 return 289 } 290 291 for i, r := range refs { 292 if r == ref { 293 s.refs[v.Name()] = append(s.refs[v.Name()][:i], s.refs[v.Name()][i+1:]...) 294 } 295 } 296 s.globalLock.Unlock() 297 } 298 299 // Refs gets the current list of refs for the given volume 300 func (s *VolumeStore) Refs(v volume.Volume) []string { 301 s.locks.Lock(v.Name()) 302 defer s.locks.Unlock(v.Name()) 303 304 s.globalLock.Lock() 305 defer s.globalLock.Unlock() 306 refs, exists := s.refs[v.Name()] 307 if !exists { 308 return nil 309 } 310 311 refsOut := make([]string, len(refs)) 312 copy(refsOut, refs) 313 return refsOut 314 } 315 316 // FilterByDriver returns the available volumes filtered by driver name 317 func (s *VolumeStore) FilterByDriver(name string) ([]volume.Volume, error) { 318 vd, err := volumedrivers.GetDriver(name) 319 if err != nil { 320 return nil, &OpErr{Err: err, Name: name, Op: "list"} 321 } 322 ls, err := vd.List() 323 if err != nil { 324 return nil, &OpErr{Err: err, Name: name, Op: "list"} 325 } 326 return ls, nil 327 } 328 329 // FilterByUsed returns the available volumes filtered by if they are not in use 330 func (s *VolumeStore) FilterByUsed(vols []volume.Volume) []volume.Volume { 331 return s.filter(vols, func(v volume.Volume) bool { 332 s.locks.Lock(v.Name()) 333 defer s.locks.Unlock(v.Name()) 334 return len(s.refs[v.Name()]) == 0 335 }) 336 } 337 338 // filterFunc defines a function to allow filter volumes in the store 339 type filterFunc func(vol volume.Volume) bool 340 341 // filter returns the available volumes filtered by a filterFunc function 342 func (s *VolumeStore) filter(vols []volume.Volume, f filterFunc) []volume.Volume { 343 var ls []volume.Volume 344 for _, v := range vols { 345 if f(v) { 346 ls = append(ls, v) 347 } 348 } 349 return ls 350 }