Allows layers to be partially pulled and resumed
Adds a sort of contrived test for resumable pulls
This commit is contained in:
parent
73d6e8af84
commit
50d64ac63a
4 changed files with 271 additions and 59 deletions
|
@ -5,7 +5,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/docker-registry"
|
||||
|
@ -39,20 +38,49 @@ type ObjectStore interface {
|
|||
}
|
||||
|
||||
// Layer is a generic image layer interface.
|
||||
// A Layer may only be written to once
|
||||
// A Layer may not be written to if it is already complete.
|
||||
type Layer interface {
|
||||
// Reader returns an io.ReadCloser which reads the contents of the layer
|
||||
Reader() (io.ReadCloser, error)
|
||||
// Reader returns a LayerReader or an error if the layer has not been
|
||||
// written to or is currently being written to.
|
||||
Reader() (LayerReader, error)
|
||||
|
||||
// Writer returns an io.WriteCloser which may write the contents of the
|
||||
// layer. This method may only be called once per Layer, and the contents
|
||||
// are made available on Close
|
||||
Writer() (io.WriteCloser, error)
|
||||
// Writer returns a LayerWriter or an error if the layer has been fully
|
||||
// written to or is currently being written to.
|
||||
Writer() (LayerWriter, error)
|
||||
|
||||
// Wait blocks until the Layer can be read from
|
||||
// Wait blocks until the Layer can be read from.
|
||||
Wait() error
|
||||
}
|
||||
|
||||
// LayerReader is a read-only handle to a Layer, which exposes the CurrentSize
|
||||
// and full Size in addition to implementing the io.ReadCloser interface.
|
||||
type LayerReader interface {
|
||||
io.ReadCloser
|
||||
|
||||
// CurrentSize returns the number of bytes written to the underlying Layer
|
||||
CurrentSize() int
|
||||
|
||||
// Size returns the full size of the underlying Layer
|
||||
Size() int
|
||||
}
|
||||
|
||||
// LayerWriter is a write-only handle to a Layer, which exposes the CurrentSize
|
||||
// and full Size in addition to implementing the io.WriteCloser interface.
|
||||
// SetSize must be called on this LayerWriter before it can be written to.
|
||||
type LayerWriter interface {
|
||||
io.WriteCloser
|
||||
|
||||
// CurrentSize returns the number of bytes written to the underlying Layer
|
||||
CurrentSize() int
|
||||
|
||||
// Size returns the full size of the underlying Layer
|
||||
Size() int
|
||||
|
||||
// SetSize sets the full size of the underlying Layer.
|
||||
// This must be called before any calls to Write
|
||||
SetSize(int) error
|
||||
}
|
||||
|
||||
// memoryObjectStore is an in-memory implementation of the ObjectStore interface
|
||||
type memoryObjectStore struct {
|
||||
mutex *sync.Mutex
|
||||
|
@ -93,67 +121,113 @@ func (objStore *memoryObjectStore) Layer(dgst digest.Digest) (Layer, error) {
|
|||
}
|
||||
|
||||
type memoryLayer struct {
|
||||
cond *sync.Cond
|
||||
buffer *bytes.Buffer
|
||||
written bool
|
||||
cond *sync.Cond
|
||||
contents []byte
|
||||
expectedSize int
|
||||
writing bool
|
||||
}
|
||||
|
||||
func (ml *memoryLayer) Writer() (io.WriteCloser, error) {
|
||||
func (ml *memoryLayer) Reader() (LayerReader, error) {
|
||||
ml.cond.L.Lock()
|
||||
defer ml.cond.L.Unlock()
|
||||
|
||||
if ml.buffer != nil {
|
||||
if !ml.written {
|
||||
return nil, ErrLayerLocked
|
||||
}
|
||||
return nil, ErrLayerAlreadyExists
|
||||
}
|
||||
|
||||
ml.buffer = new(bytes.Buffer)
|
||||
return &memoryLayerWriter{cond: ml.cond, buffer: ml.buffer, done: &ml.written}, nil
|
||||
}
|
||||
|
||||
func (ml *memoryLayer) Reader() (io.ReadCloser, error) {
|
||||
ml.cond.L.Lock()
|
||||
defer ml.cond.L.Unlock()
|
||||
|
||||
if ml.buffer == nil {
|
||||
if ml.contents == nil {
|
||||
return nil, fmt.Errorf("Layer has not been written to yet")
|
||||
}
|
||||
if !ml.written {
|
||||
if ml.writing {
|
||||
return nil, ErrLayerLocked
|
||||
}
|
||||
|
||||
return ioutil.NopCloser(bytes.NewReader(ml.buffer.Bytes())), nil
|
||||
return &memoryLayerReader{ml: ml, reader: bytes.NewReader(ml.contents)}, nil
|
||||
}
|
||||
|
||||
func (ml *memoryLayer) Writer() (LayerWriter, error) {
|
||||
ml.cond.L.Lock()
|
||||
defer ml.cond.L.Unlock()
|
||||
|
||||
if ml.contents != nil {
|
||||
if ml.writing {
|
||||
return nil, ErrLayerLocked
|
||||
}
|
||||
if ml.expectedSize == len(ml.contents) {
|
||||
return nil, ErrLayerAlreadyExists
|
||||
}
|
||||
} else {
|
||||
ml.contents = make([]byte, 0)
|
||||
}
|
||||
|
||||
ml.writing = true
|
||||
return &memoryLayerWriter{ml: ml, buffer: bytes.NewBuffer(ml.contents)}, nil
|
||||
}
|
||||
|
||||
func (ml *memoryLayer) Wait() error {
|
||||
ml.cond.L.Lock()
|
||||
defer ml.cond.L.Unlock()
|
||||
|
||||
if ml.buffer == nil {
|
||||
if ml.contents == nil {
|
||||
return fmt.Errorf("No writer to wait on")
|
||||
}
|
||||
|
||||
for !ml.written {
|
||||
for ml.writing {
|
||||
ml.cond.Wait()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type memoryLayerReader struct {
|
||||
ml *memoryLayer
|
||||
reader *bytes.Reader
|
||||
}
|
||||
|
||||
func (mlr *memoryLayerReader) Read(p []byte) (int, error) {
|
||||
return mlr.reader.Read(p)
|
||||
}
|
||||
|
||||
func (mlr *memoryLayerReader) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mlr *memoryLayerReader) CurrentSize() int {
|
||||
return len(mlr.ml.contents)
|
||||
}
|
||||
|
||||
func (mlr *memoryLayerReader) Size() int {
|
||||
return mlr.ml.expectedSize
|
||||
}
|
||||
|
||||
type memoryLayerWriter struct {
|
||||
cond *sync.Cond
|
||||
ml *memoryLayer
|
||||
buffer *bytes.Buffer
|
||||
done *bool
|
||||
}
|
||||
|
||||
func (mlw *memoryLayerWriter) Write(p []byte) (int, error) {
|
||||
return mlw.buffer.Write(p)
|
||||
if mlw.ml.expectedSize == 0 {
|
||||
return 0, fmt.Errorf("Must set size before writing to layer")
|
||||
}
|
||||
wrote, err := mlw.buffer.Write(p)
|
||||
mlw.ml.contents = mlw.buffer.Bytes()
|
||||
return wrote, err
|
||||
}
|
||||
|
||||
func (mlw *memoryLayerWriter) Close() error {
|
||||
*mlw.done = true
|
||||
mlw.cond.Broadcast()
|
||||
mlw.ml.writing = false
|
||||
mlw.ml.cond.Broadcast()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mlw *memoryLayerWriter) CurrentSize() int {
|
||||
return len(mlw.ml.contents)
|
||||
}
|
||||
|
||||
func (mlw *memoryLayerWriter) Size() int {
|
||||
return mlw.ml.expectedSize
|
||||
}
|
||||
|
||||
func (mlw *memoryLayerWriter) SetSize(size int) error {
|
||||
if !mlw.ml.writing {
|
||||
return fmt.Errorf("Layer is closed for writing")
|
||||
}
|
||||
mlw.ml.expectedSize = size
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue