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  }