github.com/lusis/distribution@v2.0.1+incompatible/registry/storage/driver/inmemory/driver.go (about)

     1  package inmemory
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	"sync"
     9  	"time"
    10  
    11  	storagedriver "github.com/docker/distribution/registry/storage/driver"
    12  	"github.com/docker/distribution/registry/storage/driver/base"
    13  	"github.com/docker/distribution/registry/storage/driver/factory"
    14  )
    15  
    16  const driverName = "inmemory"
    17  
    18  func init() {
    19  	factory.Register(driverName, &inMemoryDriverFactory{})
    20  }
    21  
    22  // inMemoryDriverFacotry implements the factory.StorageDriverFactory interface.
    23  type inMemoryDriverFactory struct{}
    24  
    25  func (factory *inMemoryDriverFactory) Create(parameters map[string]interface{}) (storagedriver.StorageDriver, error) {
    26  	return New(), nil
    27  }
    28  
    29  type driver struct {
    30  	root  *dir
    31  	mutex sync.RWMutex
    32  }
    33  
    34  // baseEmbed allows us to hide the Base embed.
    35  type baseEmbed struct {
    36  	base.Base
    37  }
    38  
    39  // Driver is a storagedriver.StorageDriver implementation backed by a local map.
    40  // Intended solely for example and testing purposes.
    41  type Driver struct {
    42  	baseEmbed // embedded, hidden base driver.
    43  }
    44  
    45  var _ storagedriver.StorageDriver = &Driver{}
    46  
    47  // New constructs a new Driver.
    48  func New() *Driver {
    49  	return &Driver{
    50  		baseEmbed: baseEmbed{
    51  			Base: base.Base{
    52  				StorageDriver: &driver{
    53  					root: &dir{
    54  						common: common{
    55  							p:   "/",
    56  							mod: time.Now(),
    57  						},
    58  					},
    59  				},
    60  			},
    61  		},
    62  	}
    63  }
    64  
    65  // Implement the storagedriver.StorageDriver interface.
    66  
    67  func (d *driver) Name() string {
    68  	return driverName
    69  }
    70  
    71  // GetContent retrieves the content stored at "path" as a []byte.
    72  func (d *driver) GetContent(path string) ([]byte, error) {
    73  	d.mutex.RLock()
    74  	defer d.mutex.RUnlock()
    75  
    76  	rc, err := d.ReadStream(path, 0)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  	defer rc.Close()
    81  
    82  	return ioutil.ReadAll(rc)
    83  }
    84  
    85  // PutContent stores the []byte content at a location designated by "path".
    86  func (d *driver) PutContent(p string, contents []byte) error {
    87  	d.mutex.Lock()
    88  	defer d.mutex.Unlock()
    89  
    90  	f, err := d.root.mkfile(p)
    91  	if err != nil {
    92  		// TODO(stevvooe): Again, we need to clarify when this is not a
    93  		// directory in StorageDriver API.
    94  		return fmt.Errorf("not a file")
    95  	}
    96  
    97  	f.truncate()
    98  	f.WriteAt(contents, 0)
    99  
   100  	return nil
   101  }
   102  
   103  // ReadStream retrieves an io.ReadCloser for the content stored at "path" with a
   104  // given byte offset.
   105  func (d *driver) ReadStream(path string, offset int64) (io.ReadCloser, error) {
   106  	d.mutex.RLock()
   107  	defer d.mutex.RUnlock()
   108  
   109  	if offset < 0 {
   110  		return nil, storagedriver.InvalidOffsetError{Path: path, Offset: offset}
   111  	}
   112  
   113  	path = normalize(path)
   114  	found := d.root.find(path)
   115  
   116  	if found.path() != path {
   117  		return nil, storagedriver.PathNotFoundError{Path: path}
   118  	}
   119  
   120  	if found.isdir() {
   121  		return nil, fmt.Errorf("%q is a directory", path)
   122  	}
   123  
   124  	return ioutil.NopCloser(found.(*file).sectionReader(offset)), nil
   125  }
   126  
   127  // WriteStream stores the contents of the provided io.ReadCloser at a location
   128  // designated by the given path.
   129  func (d *driver) WriteStream(path string, offset int64, reader io.Reader) (nn int64, err error) {
   130  	d.mutex.Lock()
   131  	defer d.mutex.Unlock()
   132  
   133  	if offset < 0 {
   134  		return 0, storagedriver.InvalidOffsetError{Path: path, Offset: offset}
   135  	}
   136  
   137  	normalized := normalize(path)
   138  
   139  	f, err := d.root.mkfile(normalized)
   140  	if err != nil {
   141  		return 0, fmt.Errorf("not a file")
   142  	}
   143  
   144  	// Unlock while we are reading from the source, in case we are reading
   145  	// from the same mfs instance. This can be fixed by a more granular
   146  	// locking model.
   147  	d.mutex.Unlock()
   148  	d.mutex.RLock() // Take the readlock to block other writers.
   149  	var buf bytes.Buffer
   150  
   151  	nn, err = buf.ReadFrom(reader)
   152  	if err != nil {
   153  		// TODO(stevvooe): This condition is odd and we may need to clarify:
   154  		// we've read nn bytes from reader but have written nothing to the
   155  		// backend. What is the correct return value? Really, the caller needs
   156  		// to know that the reader has been advanced and reattempting the
   157  		// operation is incorrect.
   158  		d.mutex.RUnlock()
   159  		d.mutex.Lock()
   160  		return nn, err
   161  	}
   162  
   163  	d.mutex.RUnlock()
   164  	d.mutex.Lock()
   165  	f.WriteAt(buf.Bytes(), offset)
   166  	return nn, err
   167  }
   168  
   169  // Stat returns info about the provided path.
   170  func (d *driver) Stat(path string) (storagedriver.FileInfo, error) {
   171  	d.mutex.RLock()
   172  	defer d.mutex.RUnlock()
   173  
   174  	normalized := normalize(path)
   175  	found := d.root.find(path)
   176  
   177  	if found.path() != normalized {
   178  		return nil, storagedriver.PathNotFoundError{Path: path}
   179  	}
   180  
   181  	fi := storagedriver.FileInfoFields{
   182  		Path:    path,
   183  		IsDir:   found.isdir(),
   184  		ModTime: found.modtime(),
   185  	}
   186  
   187  	if !fi.IsDir {
   188  		fi.Size = int64(len(found.(*file).data))
   189  	}
   190  
   191  	return storagedriver.FileInfoInternal{FileInfoFields: fi}, nil
   192  }
   193  
   194  // List returns a list of the objects that are direct descendants of the given
   195  // path.
   196  func (d *driver) List(path string) ([]string, error) {
   197  	d.mutex.RLock()
   198  	defer d.mutex.RUnlock()
   199  
   200  	normalized := normalize(path)
   201  
   202  	found := d.root.find(normalized)
   203  
   204  	if !found.isdir() {
   205  		return nil, fmt.Errorf("not a directory") // TODO(stevvooe): Need error type for this...
   206  	}
   207  
   208  	entries, err := found.(*dir).list(normalized)
   209  
   210  	if err != nil {
   211  		switch err {
   212  		case errNotExists:
   213  			return nil, storagedriver.PathNotFoundError{Path: path}
   214  		case errIsNotDir:
   215  			return nil, fmt.Errorf("not a directory")
   216  		default:
   217  			return nil, err
   218  		}
   219  	}
   220  
   221  	return entries, nil
   222  }
   223  
   224  // Move moves an object stored at sourcePath to destPath, removing the original
   225  // object.
   226  func (d *driver) Move(sourcePath string, destPath string) error {
   227  	d.mutex.Lock()
   228  	defer d.mutex.Unlock()
   229  
   230  	normalizedSrc, normalizedDst := normalize(sourcePath), normalize(destPath)
   231  
   232  	err := d.root.move(normalizedSrc, normalizedDst)
   233  	switch err {
   234  	case errNotExists:
   235  		return storagedriver.PathNotFoundError{Path: destPath}
   236  	default:
   237  		return err
   238  	}
   239  }
   240  
   241  // Delete recursively deletes all objects stored at "path" and its subpaths.
   242  func (d *driver) Delete(path string) error {
   243  	d.mutex.Lock()
   244  	defer d.mutex.Unlock()
   245  
   246  	normalized := normalize(path)
   247  
   248  	err := d.root.delete(normalized)
   249  	switch err {
   250  	case errNotExists:
   251  		return storagedriver.PathNotFoundError{Path: path}
   252  	default:
   253  		return err
   254  	}
   255  }
   256  
   257  // URLFor returns a URL which may be used to retrieve the content stored at the given path.
   258  // May return an UnsupportedMethodErr in certain StorageDriver implementations.
   259  func (d *driver) URLFor(path string, options map[string]interface{}) (string, error) {
   260  	return "", storagedriver.ErrUnsupportedMethod
   261  }