github.com/tompao/docker@v1.9.1/volume/store/store.go (about)

     1  package store
     2  
     3  import (
     4  	"errors"
     5  	"sync"
     6  
     7  	"github.com/Sirupsen/logrus"
     8  	"github.com/docker/docker/volume"
     9  	"github.com/docker/docker/volume/drivers"
    10  )
    11  
    12  var (
    13  	// ErrVolumeInUse is a typed error returned when trying to remove a volume that is currently in use by a container
    14  	ErrVolumeInUse = errors.New("volume is in use")
    15  	// ErrNoSuchVolume is a typed error returned if the requested volume doesn't exist in the volume store
    16  	ErrNoSuchVolume = errors.New("no such volume")
    17  )
    18  
    19  // New initializes a VolumeStore to keep
    20  // reference counting of volumes in the system.
    21  func New() *VolumeStore {
    22  	return &VolumeStore{
    23  		vols: make(map[string]*volumeCounter),
    24  	}
    25  }
    26  
    27  // VolumeStore is a struct that stores the list of volumes available and keeps track of their usage counts
    28  type VolumeStore struct {
    29  	vols map[string]*volumeCounter
    30  	mu   sync.Mutex
    31  }
    32  
    33  // volumeCounter keeps track of references to a volume
    34  type volumeCounter struct {
    35  	volume.Volume
    36  	count uint
    37  }
    38  
    39  // AddAll adds a list of volumes to the store
    40  func (s *VolumeStore) AddAll(vols []volume.Volume) {
    41  	for _, v := range vols {
    42  		s.vols[v.Name()] = &volumeCounter{v, 0}
    43  	}
    44  }
    45  
    46  // Create tries to find an existing volume with the given name or create a new one from the passed in driver
    47  func (s *VolumeStore) Create(name, driverName string, opts map[string]string) (volume.Volume, error) {
    48  	s.mu.Lock()
    49  	if vc, exists := s.vols[name]; exists {
    50  		v := vc.Volume
    51  		s.mu.Unlock()
    52  		return v, nil
    53  	}
    54  	s.mu.Unlock()
    55  	logrus.Debugf("Registering new volume reference: driver %s, name %s", driverName, name)
    56  
    57  	vd, err := volumedrivers.GetDriver(driverName)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  
    62  	v, err := vd.Create(name, opts)
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  
    67  	s.mu.Lock()
    68  	s.vols[v.Name()] = &volumeCounter{v, 0}
    69  	s.mu.Unlock()
    70  
    71  	return v, nil
    72  }
    73  
    74  // Get looks if a volume with the given name exists and returns it if so
    75  func (s *VolumeStore) Get(name string) (volume.Volume, error) {
    76  	s.mu.Lock()
    77  	defer s.mu.Unlock()
    78  	vc, exists := s.vols[name]
    79  	if !exists {
    80  		return nil, ErrNoSuchVolume
    81  	}
    82  	return vc.Volume, nil
    83  }
    84  
    85  // Remove removes the requested volume. A volume is not removed if the usage count is > 0
    86  func (s *VolumeStore) Remove(v volume.Volume) error {
    87  	s.mu.Lock()
    88  	defer s.mu.Unlock()
    89  	name := v.Name()
    90  	logrus.Debugf("Removing volume reference: driver %s, name %s", v.DriverName(), name)
    91  	vc, exists := s.vols[name]
    92  	if !exists {
    93  		return ErrNoSuchVolume
    94  	}
    95  
    96  	if vc.count > 0 {
    97  		return ErrVolumeInUse
    98  	}
    99  
   100  	vd, err := volumedrivers.GetDriver(vc.DriverName())
   101  	if err != nil {
   102  		return err
   103  	}
   104  	if err := vd.Remove(vc.Volume); err != nil {
   105  		return err
   106  	}
   107  	delete(s.vols, name)
   108  	return nil
   109  }
   110  
   111  // Increment increments the usage count of the passed in volume by 1
   112  func (s *VolumeStore) Increment(v volume.Volume) {
   113  	s.mu.Lock()
   114  	defer s.mu.Unlock()
   115  	logrus.Debugf("Incrementing volume reference: driver %s, name %s", v.DriverName(), v.Name())
   116  
   117  	vc, exists := s.vols[v.Name()]
   118  	if !exists {
   119  		s.vols[v.Name()] = &volumeCounter{v, 1}
   120  		return
   121  	}
   122  	vc.count++
   123  }
   124  
   125  // Decrement decrements the usage count of the passed in volume by 1
   126  func (s *VolumeStore) Decrement(v volume.Volume) {
   127  	s.mu.Lock()
   128  	defer s.mu.Unlock()
   129  	logrus.Debugf("Decrementing volume reference: driver %s, name %s", v.DriverName(), v.Name())
   130  
   131  	vc, exists := s.vols[v.Name()]
   132  	if !exists {
   133  		return
   134  	}
   135  	if vc.count == 0 {
   136  		return
   137  	}
   138  	vc.count--
   139  }
   140  
   141  // Count returns the usage count of the passed in volume
   142  func (s *VolumeStore) Count(v volume.Volume) uint {
   143  	s.mu.Lock()
   144  	defer s.mu.Unlock()
   145  	vc, exists := s.vols[v.Name()]
   146  	if !exists {
   147  		return 0
   148  	}
   149  	return vc.count
   150  }
   151  
   152  // List returns all the available volumes
   153  func (s *VolumeStore) List() []volume.Volume {
   154  	s.mu.Lock()
   155  	defer s.mu.Unlock()
   156  	var ls []volume.Volume
   157  	for _, vc := range s.vols {
   158  		ls = append(ls, vc.Volume)
   159  	}
   160  	return ls
   161  }
   162  
   163  // FilterByDriver returns the available volumes filtered by driver name
   164  func (s *VolumeStore) FilterByDriver(name string) []volume.Volume {
   165  	return s.filter(byDriver(name))
   166  }
   167  
   168  // filterFunc defines a function to allow filter volumes in the store
   169  type filterFunc func(vol volume.Volume) bool
   170  
   171  // byDriver generates a filterFunc to filter volumes by their driver name
   172  func byDriver(name string) filterFunc {
   173  	return func(vol volume.Volume) bool {
   174  		return vol.DriverName() == name
   175  	}
   176  }
   177  
   178  // filter returns the available volumes filtered by a filterFunc function
   179  func (s *VolumeStore) filter(f filterFunc) []volume.Volume {
   180  	s.mu.Lock()
   181  	defer s.mu.Unlock()
   182  	var ls []volume.Volume
   183  	for _, vc := range s.vols {
   184  		if f(vc.Volume) {
   185  			ls = append(ls, vc.Volume)
   186  		}
   187  	}
   188  	return ls
   189  }