github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/volume/store/store.go (about)

     1  package store
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"net"
     7  	"os"
     8  	"path/filepath"
     9  	"sync"
    10  	"time"
    11  
    12  	"github.com/pkg/errors"
    13  
    14  	"github.com/Sirupsen/logrus"
    15  	"github.com/boltdb/bolt"
    16  	"github.com/docker/docker/pkg/locker"
    17  	"github.com/docker/docker/volume"
    18  	"github.com/docker/docker/volume/drivers"
    19  )
    20  
    21  const (
    22  	volumeDataDir    = "volumes"
    23  	volumeBucketName = "volumes"
    24  )
    25  
    26  type volumeMetadata struct {
    27  	Name    string
    28  	Labels  map[string]string
    29  	Options map[string]string
    30  }
    31  
    32  type volumeWrapper struct {
    33  	volume.Volume
    34  	labels  map[string]string
    35  	scope   string
    36  	options map[string]string
    37  }
    38  
    39  func (v volumeWrapper) Options() map[string]string {
    40  	options := map[string]string{}
    41  	for key, value := range v.options {
    42  		options[key] = value
    43  	}
    44  	return options
    45  }
    46  
    47  func (v volumeWrapper) Labels() map[string]string {
    48  	return v.labels
    49  }
    50  
    51  func (v volumeWrapper) Scope() string {
    52  	return v.scope
    53  }
    54  
    55  func (v volumeWrapper) CachedPath() string {
    56  	if vv, ok := v.Volume.(interface {
    57  		CachedPath() string
    58  	}); ok {
    59  		return vv.CachedPath()
    60  	}
    61  	return v.Volume.Path()
    62  }
    63  
    64  // New initializes a VolumeStore to keep
    65  // reference counting of volumes in the system.
    66  func New(rootPath string) (*VolumeStore, error) {
    67  	vs := &VolumeStore{
    68  		locks:   &locker.Locker{},
    69  		names:   make(map[string]volume.Volume),
    70  		refs:    make(map[string]map[string]struct{}),
    71  		labels:  make(map[string]map[string]string),
    72  		options: make(map[string]map[string]string),
    73  	}
    74  
    75  	if rootPath != "" {
    76  		// initialize metadata store
    77  		volPath := filepath.Join(rootPath, volumeDataDir)
    78  		if err := os.MkdirAll(volPath, 750); err != nil {
    79  			return nil, err
    80  		}
    81  
    82  		dbPath := filepath.Join(volPath, "metadata.db")
    83  
    84  		var err error
    85  		vs.db, err = bolt.Open(dbPath, 0600, &bolt.Options{Timeout: 1 * time.Second})
    86  		if err != nil {
    87  			return nil, errors.Wrap(err, "error while opening volume store metadata database")
    88  		}
    89  
    90  		// initialize volumes bucket
    91  		if err := vs.db.Update(func(tx *bolt.Tx) error {
    92  			if _, err := tx.CreateBucketIfNotExists([]byte(volumeBucketName)); err != nil {
    93  				return errors.Wrap(err, "error while setting up volume store metadata database")
    94  			}
    95  
    96  			return nil
    97  		}); err != nil {
    98  			return nil, err
    99  		}
   100  	}
   101  
   102  	return vs, nil
   103  }
   104  
   105  func (s *VolumeStore) getNamed(name string) (volume.Volume, bool) {
   106  	s.globalLock.RLock()
   107  	v, exists := s.names[name]
   108  	s.globalLock.RUnlock()
   109  	return v, exists
   110  }
   111  
   112  func (s *VolumeStore) setNamed(v volume.Volume, ref string) {
   113  	name := v.Name()
   114  
   115  	s.globalLock.Lock()
   116  	s.names[name] = v
   117  	if len(ref) > 0 {
   118  		if s.refs[name] == nil {
   119  			s.refs[name] = make(map[string]struct{})
   120  		}
   121  		s.refs[name][ref] = struct{}{}
   122  	}
   123  	s.globalLock.Unlock()
   124  }
   125  
   126  // hasRef returns true if the given name has at least one ref.
   127  // Callers of this function are expected to hold the name lock.
   128  func (s *VolumeStore) hasRef(name string) bool {
   129  	s.globalLock.RLock()
   130  	l := len(s.refs[name])
   131  	s.globalLock.RUnlock()
   132  	return l > 0
   133  }
   134  
   135  // getRefs gets the list of refs for a given name
   136  // Callers of this function are expected to hold the name lock.
   137  func (s *VolumeStore) getRefs(name string) []string {
   138  	s.globalLock.RLock()
   139  	defer s.globalLock.RUnlock()
   140  
   141  	refs := make([]string, 0, len(s.refs[name]))
   142  	for r := range s.refs[name] {
   143  		refs = append(refs, r)
   144  	}
   145  
   146  	return refs
   147  }
   148  
   149  // Purge allows the cleanup of internal data on docker in case
   150  // the internal data is out of sync with volumes driver plugins.
   151  func (s *VolumeStore) Purge(name string) {
   152  	s.globalLock.Lock()
   153  	delete(s.names, name)
   154  	delete(s.refs, name)
   155  	delete(s.labels, name)
   156  	delete(s.options, name)
   157  	s.globalLock.Unlock()
   158  }
   159  
   160  // VolumeStore is a struct that stores the list of volumes available and keeps track of their usage counts
   161  type VolumeStore struct {
   162  	// locks ensures that only one action is being performed on a particular volume at a time without locking the entire store
   163  	// since actions on volumes can be quite slow, this ensures the store is free to handle requests for other volumes.
   164  	locks *locker.Locker
   165  	// globalLock is used to protect access to mutable structures used by the store object
   166  	globalLock sync.RWMutex
   167  	// names stores the volume name -> volume relationship.
   168  	// This is used for making lookups faster so we don't have to probe all drivers
   169  	names map[string]volume.Volume
   170  	// refs stores the volume name and the list of things referencing it
   171  	refs map[string]map[string]struct{}
   172  	// labels stores volume labels for each volume
   173  	labels map[string]map[string]string
   174  	// options stores volume options for each volume
   175  	options map[string]map[string]string
   176  	db      *bolt.DB
   177  }
   178  
   179  // List proxies to all registered volume drivers to get the full list of volumes
   180  // If a driver returns a volume that has name which conflicts with another volume from a different driver,
   181  // the first volume is chosen and the conflicting volume is dropped.
   182  func (s *VolumeStore) List() ([]volume.Volume, []string, error) {
   183  	vols, warnings, err := s.list()
   184  	if err != nil {
   185  		return nil, nil, &OpErr{Err: err, Op: "list"}
   186  	}
   187  	var out []volume.Volume
   188  
   189  	for _, v := range vols {
   190  		name := normaliseVolumeName(v.Name())
   191  
   192  		s.locks.Lock(name)
   193  		storedV, exists := s.getNamed(name)
   194  		// Note: it's not safe to populate the cache here because the volume may have been
   195  		// deleted before we acquire a lock on its name
   196  		if exists && storedV.DriverName() != v.DriverName() {
   197  			logrus.Warnf("Volume name %s already exists for driver %s, not including volume returned by %s", v.Name(), storedV.DriverName(), v.DriverName())
   198  			s.locks.Unlock(v.Name())
   199  			continue
   200  		}
   201  
   202  		out = append(out, v)
   203  		s.locks.Unlock(v.Name())
   204  	}
   205  	return out, warnings, nil
   206  }
   207  
   208  // list goes through each volume driver and asks for its list of volumes.
   209  func (s *VolumeStore) list() ([]volume.Volume, []string, error) {
   210  	var (
   211  		ls       []volume.Volume
   212  		warnings []string
   213  	)
   214  
   215  	drivers, err := volumedrivers.GetAllDrivers()
   216  	if err != nil {
   217  		return nil, nil, err
   218  	}
   219  
   220  	type vols struct {
   221  		vols       []volume.Volume
   222  		err        error
   223  		driverName string
   224  	}
   225  	chVols := make(chan vols, len(drivers))
   226  
   227  	for _, vd := range drivers {
   228  		go func(d volume.Driver) {
   229  			vs, err := d.List()
   230  			if err != nil {
   231  				chVols <- vols{driverName: d.Name(), err: &OpErr{Err: err, Name: d.Name(), Op: "list"}}
   232  				return
   233  			}
   234  			for i, v := range vs {
   235  				s.globalLock.RLock()
   236  				vs[i] = volumeWrapper{v, s.labels[v.Name()], d.Scope(), s.options[v.Name()]}
   237  				s.globalLock.RUnlock()
   238  			}
   239  
   240  			chVols <- vols{vols: vs}
   241  		}(vd)
   242  	}
   243  
   244  	badDrivers := make(map[string]struct{})
   245  	for i := 0; i < len(drivers); i++ {
   246  		vs := <-chVols
   247  
   248  		if vs.err != nil {
   249  			warnings = append(warnings, vs.err.Error())
   250  			badDrivers[vs.driverName] = struct{}{}
   251  			logrus.Warn(vs.err)
   252  		}
   253  		ls = append(ls, vs.vols...)
   254  	}
   255  
   256  	if len(badDrivers) > 0 {
   257  		s.globalLock.RLock()
   258  		for _, v := range s.names {
   259  			if _, exists := badDrivers[v.DriverName()]; exists {
   260  				ls = append(ls, v)
   261  			}
   262  		}
   263  		s.globalLock.RUnlock()
   264  	}
   265  	return ls, warnings, nil
   266  }
   267  
   268  // CreateWithRef creates a volume with the given name and driver and stores the ref
   269  // This ensures there's no race between creating a volume and then storing a reference.
   270  func (s *VolumeStore) CreateWithRef(name, driverName, ref string, opts, labels map[string]string) (volume.Volume, error) {
   271  	name = normaliseVolumeName(name)
   272  	s.locks.Lock(name)
   273  	defer s.locks.Unlock(name)
   274  
   275  	v, err := s.create(name, driverName, opts, labels)
   276  	if err != nil {
   277  		return nil, &OpErr{Err: err, Name: name, Op: "create"}
   278  	}
   279  
   280  	s.setNamed(v, ref)
   281  	return v, nil
   282  }
   283  
   284  // Create creates a volume with the given name and driver.
   285  // This is just like CreateWithRef() except we don't store a reference while holding the lock.
   286  func (s *VolumeStore) Create(name, driverName string, opts, labels map[string]string) (volume.Volume, error) {
   287  	return s.CreateWithRef(name, driverName, "", opts, labels)
   288  }
   289  
   290  // checkConflict checks the local cache for name collisions with the passed in name,
   291  // for existing volumes with the same name but in a different driver.
   292  // This is used by `Create` as a best effort to prevent name collisions for volumes.
   293  // If a matching volume is found that is not a conflict that is returned so the caller
   294  // does not need to perform an additional lookup.
   295  // When no matching volume is found, both returns will be nil
   296  //
   297  // Note: This does not probe all the drivers for name collisions because v1 plugins
   298  // are very slow, particularly if the plugin is down, and cause other issues,
   299  // particularly around locking the store.
   300  // TODO(cpuguy83): With v2 plugins this shouldn't be a problem. Could also potentially
   301  // use a connect timeout for this kind of check to ensure we aren't blocking for a
   302  // long time.
   303  func (s *VolumeStore) checkConflict(name, driverName string) (volume.Volume, error) {
   304  	// check the local cache
   305  	v, _ := s.getNamed(name)
   306  	if v == nil {
   307  		return nil, nil
   308  	}
   309  
   310  	vDriverName := v.DriverName()
   311  	var conflict bool
   312  	if driverName != "" && vDriverName != driverName {
   313  		conflict = true
   314  	}
   315  
   316  	// let's check if the found volume ref
   317  	// is stale by checking with the driver if it still exists
   318  	exists, err := volumeExists(v)
   319  	if err != nil {
   320  		return nil, errors.Wrapf(errNameConflict, "found reference to volume '%s' in driver '%s', but got an error while checking the driver: %v", name, vDriverName, err)
   321  	}
   322  
   323  	if exists {
   324  		if conflict {
   325  			return nil, errors.Wrapf(errNameConflict, "driver '%s' already has volume '%s'", vDriverName, name)
   326  		}
   327  		return v, nil
   328  	}
   329  
   330  	if s.hasRef(v.Name()) {
   331  		// Containers are referencing this volume but it doesn't seem to exist anywhere.
   332  		// Return a conflict error here, the user can fix this with `docker volume rm -f`
   333  		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)
   334  	}
   335  
   336  	// doesn't exist, so purge it from the cache
   337  	s.Purge(name)
   338  	return nil, nil
   339  }
   340  
   341  // volumeExists returns if the volume is still present in the driver.
   342  // An error is returned if there was an issue communicating with the driver.
   343  func volumeExists(v volume.Volume) (bool, error) {
   344  	vd, err := volumedrivers.GetDriver(v.DriverName())
   345  	if err != nil {
   346  		return false, errors.Wrapf(err, "error while checking if volume %q exists in driver %q", v.Name(), v.DriverName())
   347  	}
   348  	exists, err := vd.Get(v.Name())
   349  	if err != nil {
   350  		err = errors.Cause(err)
   351  		if _, ok := err.(net.Error); ok {
   352  			return false, errors.Wrapf(err, "error while checking if volume %q exists in driver %q", v.Name(), v.DriverName())
   353  		}
   354  
   355  		// At this point, the error could be anything from the driver, such as "no such volume"
   356  		// Let's not check an error here, and instead check if the driver returned a volume
   357  	}
   358  	if exists == nil {
   359  		return false, nil
   360  	}
   361  	return true, nil
   362  }
   363  
   364  // create asks the given driver to create a volume with the name/opts.
   365  // If a volume with the name is already known, it will ask the stored driver for the volume.
   366  // If the passed in driver name does not match the driver name which is stored
   367  //  for the given volume name, an error is returned after checking if the reference is stale.
   368  // If the reference is stale, it will be purged and this create can continue.
   369  // It is expected that callers of this function hold any necessary locks.
   370  func (s *VolumeStore) create(name, driverName string, opts, labels map[string]string) (volume.Volume, error) {
   371  	// Validate the name in a platform-specific manner
   372  	valid, err := volume.IsVolumeNameValid(name)
   373  	if err != nil {
   374  		return nil, err
   375  	}
   376  	if !valid {
   377  		return nil, &OpErr{Err: errInvalidName, Name: name, Op: "create"}
   378  	}
   379  
   380  	v, err := s.checkConflict(name, driverName)
   381  	if err != nil {
   382  		return nil, err
   383  	}
   384  
   385  	if v != nil {
   386  		return v, nil
   387  	}
   388  
   389  	// Since there isn't a specified driver name, let's see if any of the existing drivers have this volume name
   390  	if driverName == "" {
   391  		v, _ := s.getVolume(name)
   392  		if v != nil {
   393  			return v, nil
   394  		}
   395  	}
   396  
   397  	vd, err := volumedrivers.CreateDriver(driverName)
   398  
   399  	if err != nil {
   400  		return nil, &OpErr{Op: "create", Name: name, Err: err}
   401  	}
   402  
   403  	logrus.Debugf("Registering new volume reference: driver %q, name %q", vd.Name(), name)
   404  
   405  	if v, _ := vd.Get(name); v != nil {
   406  		return v, nil
   407  	}
   408  	v, err = vd.Create(name, opts)
   409  	if err != nil {
   410  		return nil, err
   411  	}
   412  	s.globalLock.Lock()
   413  	s.labels[name] = labels
   414  	s.options[name] = opts
   415  	s.refs[name] = make(map[string]struct{})
   416  	s.globalLock.Unlock()
   417  
   418  	if s.db != nil {
   419  		metadata := &volumeMetadata{
   420  			Name:    name,
   421  			Labels:  labels,
   422  			Options: opts,
   423  		}
   424  
   425  		volData, err := json.Marshal(metadata)
   426  		if err != nil {
   427  			return nil, err
   428  		}
   429  
   430  		if err := s.db.Update(func(tx *bolt.Tx) error {
   431  			b := tx.Bucket([]byte(volumeBucketName))
   432  			err := b.Put([]byte(name), volData)
   433  			return err
   434  		}); err != nil {
   435  			return nil, errors.Wrap(err, "error while persisting volume metadata")
   436  		}
   437  	}
   438  
   439  	return volumeWrapper{v, labels, vd.Scope(), opts}, nil
   440  }
   441  
   442  // GetWithRef gets a volume with the given name from the passed in driver and stores the ref
   443  // This is just like Get(), but we store the reference while holding the lock.
   444  // This makes sure there are no races between checking for the existence of a volume and adding a reference for it
   445  func (s *VolumeStore) GetWithRef(name, driverName, ref string) (volume.Volume, error) {
   446  	name = normaliseVolumeName(name)
   447  	s.locks.Lock(name)
   448  	defer s.locks.Unlock(name)
   449  
   450  	vd, err := volumedrivers.GetDriver(driverName)
   451  	if err != nil {
   452  		return nil, &OpErr{Err: err, Name: name, Op: "get"}
   453  	}
   454  
   455  	v, err := vd.Get(name)
   456  	if err != nil {
   457  		return nil, &OpErr{Err: err, Name: name, Op: "get"}
   458  	}
   459  
   460  	s.setNamed(v, ref)
   461  
   462  	s.globalLock.RLock()
   463  	defer s.globalLock.RUnlock()
   464  	return volumeWrapper{v, s.labels[name], vd.Scope(), s.options[name]}, nil
   465  }
   466  
   467  // Get looks if a volume with the given name exists and returns it if so
   468  func (s *VolumeStore) Get(name string) (volume.Volume, error) {
   469  	name = normaliseVolumeName(name)
   470  	s.locks.Lock(name)
   471  	defer s.locks.Unlock(name)
   472  
   473  	v, err := s.getVolume(name)
   474  	if err != nil {
   475  		return nil, &OpErr{Err: err, Name: name, Op: "get"}
   476  	}
   477  	s.setNamed(v, "")
   478  	return v, nil
   479  }
   480  
   481  // getVolume requests the volume, if the driver info is stored it just accesses that driver,
   482  // if the driver is unknown it probes all drivers until it finds the first volume with that name.
   483  // it is expected that callers of this function hold any necessary locks
   484  func (s *VolumeStore) getVolume(name string) (volume.Volume, error) {
   485  	labels := map[string]string{}
   486  	options := map[string]string{}
   487  
   488  	if s.db != nil {
   489  		// get meta
   490  		if err := s.db.Update(func(tx *bolt.Tx) error {
   491  			b := tx.Bucket([]byte(volumeBucketName))
   492  			data := b.Get([]byte(name))
   493  
   494  			if string(data) == "" {
   495  				return nil
   496  			}
   497  
   498  			var meta volumeMetadata
   499  			buf := bytes.NewBuffer(data)
   500  
   501  			if err := json.NewDecoder(buf).Decode(&meta); err != nil {
   502  				return err
   503  			}
   504  			labels = meta.Labels
   505  			options = meta.Options
   506  
   507  			return nil
   508  		}); err != nil {
   509  			return nil, err
   510  		}
   511  	}
   512  
   513  	logrus.Debugf("Getting volume reference for name: %s", name)
   514  	s.globalLock.RLock()
   515  	v, exists := s.names[name]
   516  	s.globalLock.RUnlock()
   517  	if exists {
   518  		vd, err := volumedrivers.GetDriver(v.DriverName())
   519  		if err != nil {
   520  			return nil, err
   521  		}
   522  		vol, err := vd.Get(name)
   523  		if err != nil {
   524  			return nil, err
   525  		}
   526  		return volumeWrapper{vol, labels, vd.Scope(), options}, nil
   527  	}
   528  
   529  	logrus.Debugf("Probing all drivers for volume with name: %s", name)
   530  	drivers, err := volumedrivers.GetAllDrivers()
   531  	if err != nil {
   532  		return nil, err
   533  	}
   534  
   535  	for _, d := range drivers {
   536  		v, err := d.Get(name)
   537  		if err != nil {
   538  			continue
   539  		}
   540  
   541  		return volumeWrapper{v, labels, d.Scope(), options}, nil
   542  	}
   543  	return nil, errNoSuchVolume
   544  }
   545  
   546  // Remove removes the requested volume. A volume is not removed if it has any refs
   547  func (s *VolumeStore) Remove(v volume.Volume) error {
   548  	name := normaliseVolumeName(v.Name())
   549  	s.locks.Lock(name)
   550  	defer s.locks.Unlock(name)
   551  
   552  	if s.hasRef(name) {
   553  		return &OpErr{Err: errVolumeInUse, Name: v.Name(), Op: "remove", Refs: s.getRefs(name)}
   554  	}
   555  
   556  	vd, err := volumedrivers.RemoveDriver(v.DriverName())
   557  	if err != nil {
   558  		return &OpErr{Err: err, Name: vd.Name(), Op: "remove"}
   559  	}
   560  
   561  	logrus.Debugf("Removing volume reference: driver %s, name %s", v.DriverName(), name)
   562  	vol := unwrapVolume(v)
   563  	if err := vd.Remove(vol); err != nil {
   564  		return &OpErr{Err: err, Name: name, Op: "remove"}
   565  	}
   566  
   567  	s.Purge(name)
   568  	return nil
   569  }
   570  
   571  // Dereference removes the specified reference to the volume
   572  func (s *VolumeStore) Dereference(v volume.Volume, ref string) {
   573  	name := v.Name()
   574  
   575  	s.locks.Lock(name)
   576  	defer s.locks.Unlock(name)
   577  
   578  	s.globalLock.Lock()
   579  	defer s.globalLock.Unlock()
   580  
   581  	if s.refs[name] != nil {
   582  		delete(s.refs[name], ref)
   583  	}
   584  }
   585  
   586  // Refs gets the current list of refs for the given volume
   587  func (s *VolumeStore) Refs(v volume.Volume) []string {
   588  	name := v.Name()
   589  
   590  	s.locks.Lock(name)
   591  	defer s.locks.Unlock(name)
   592  
   593  	return s.getRefs(name)
   594  }
   595  
   596  // FilterByDriver returns the available volumes filtered by driver name
   597  func (s *VolumeStore) FilterByDriver(name string) ([]volume.Volume, error) {
   598  	vd, err := volumedrivers.GetDriver(name)
   599  	if err != nil {
   600  		return nil, &OpErr{Err: err, Name: name, Op: "list"}
   601  	}
   602  	ls, err := vd.List()
   603  	if err != nil {
   604  		return nil, &OpErr{Err: err, Name: name, Op: "list"}
   605  	}
   606  	for i, v := range ls {
   607  		options := map[string]string{}
   608  		s.globalLock.RLock()
   609  		for key, value := range s.options[v.Name()] {
   610  			options[key] = value
   611  		}
   612  		ls[i] = volumeWrapper{v, s.labels[v.Name()], vd.Scope(), options}
   613  		s.globalLock.RUnlock()
   614  	}
   615  	return ls, nil
   616  }
   617  
   618  // FilterByUsed returns the available volumes filtered by if they are in use or not.
   619  // `used=true` returns only volumes that are being used, while `used=false` returns
   620  // only volumes that are not being used.
   621  func (s *VolumeStore) FilterByUsed(vols []volume.Volume, used bool) []volume.Volume {
   622  	return s.filter(vols, func(v volume.Volume) bool {
   623  		s.locks.Lock(v.Name())
   624  		hasRef := s.hasRef(v.Name())
   625  		s.locks.Unlock(v.Name())
   626  		if used == hasRef {
   627  			return true
   628  		}
   629  		return false
   630  	})
   631  }
   632  
   633  // filterFunc defines a function to allow filter volumes in the store
   634  type filterFunc func(vol volume.Volume) bool
   635  
   636  // filter returns the available volumes filtered by a filterFunc function
   637  func (s *VolumeStore) filter(vols []volume.Volume, f filterFunc) []volume.Volume {
   638  	var ls []volume.Volume
   639  	for _, v := range vols {
   640  		if f(v) {
   641  			ls = append(ls, v)
   642  		}
   643  	}
   644  	return ls
   645  }
   646  
   647  func unwrapVolume(v volume.Volume) volume.Volume {
   648  	if vol, ok := v.(volumeWrapper); ok {
   649  		return vol.Volume
   650  	}
   651  
   652  	return v
   653  }