зеркало из https://github.com/microsoft/docker.git
Merge pull request #18834 from dmcgowan/layerstore-refactor-rw-layer
Layerstore refactor rw layer
This commit is contained in:
Коммит
d08ac6e256
|
@ -145,7 +145,7 @@ func (daemon *Daemon) exportContainerRw(container *container.Container) (archive
|
||||||
}
|
}
|
||||||
return ioutils.NewReadCloserWrapper(archive, func() error {
|
return ioutils.NewReadCloserWrapper(archive, func() error {
|
||||||
archive.Close()
|
archive.Close()
|
||||||
return daemon.layerStore.Unmount(container.ID)
|
return container.RWLayer.Unmount()
|
||||||
}),
|
}),
|
||||||
nil
|
nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,7 +98,7 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m, err := daemon.layerStore.Metadata(c.ID)
|
m, err := c.RWLayer.Metadata()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return derr.ErrorCodeGetLayerMetadata.WithArgs(err)
|
return derr.ErrorCodeGetLayerMetadata.WithArgs(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/docker/docker/container"
|
"github.com/docker/docker/container"
|
||||||
derr "github.com/docker/docker/errors"
|
derr "github.com/docker/docker/errors"
|
||||||
"github.com/docker/docker/image"
|
"github.com/docker/docker/image"
|
||||||
|
"github.com/docker/docker/layer"
|
||||||
"github.com/docker/docker/pkg/idtools"
|
"github.com/docker/docker/pkg/idtools"
|
||||||
"github.com/docker/docker/pkg/stringid"
|
"github.com/docker/docker/pkg/stringid"
|
||||||
"github.com/docker/docker/volume"
|
"github.com/docker/docker/volume"
|
||||||
|
@ -41,13 +42,12 @@ func (daemon *Daemon) ContainerCreate(params types.ContainerCreateConfig) (types
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create creates a new container from the given configuration with a given name.
|
// Create creates a new container from the given configuration with a given name.
|
||||||
func (daemon *Daemon) create(params types.ContainerCreateConfig) (*container.Container, error) {
|
func (daemon *Daemon) create(params types.ContainerCreateConfig) (retC *container.Container, retErr error) {
|
||||||
var (
|
var (
|
||||||
container *container.Container
|
container *container.Container
|
||||||
img *image.Image
|
img *image.Image
|
||||||
imgID image.ID
|
imgID image.ID
|
||||||
err error
|
err error
|
||||||
retErr error
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if params.Config.Image != "" {
|
if params.Config.Image != "" {
|
||||||
|
@ -73,6 +73,15 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig) (*container.Con
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
if err := daemon.setSecurityOptions(container, params.HostConfig); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set RWLayer for container after mount labels have been set
|
||||||
|
if err := daemon.setRWLayer(container); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if err := daemon.Register(container); err != nil {
|
if err := daemon.Register(container); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -126,6 +135,24 @@ func (daemon *Daemon) generateSecurityOpt(ipcMode containertypes.IpcMode, pidMod
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (daemon *Daemon) setRWLayer(container *container.Container) error {
|
||||||
|
var layerID layer.ChainID
|
||||||
|
if container.ImageID != "" {
|
||||||
|
img, err := daemon.imageStore.Get(container.ImageID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
layerID = img.RootFS.ChainID()
|
||||||
|
}
|
||||||
|
rwLayer, err := daemon.layerStore.CreateRWLayer(container.ID, layerID, container.MountLabel, daemon.setupInitLayer)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
container.RWLayer = rwLayer
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// VolumeCreate creates a volume with the specified name, driver, and opts
|
// VolumeCreate creates a volume with the specified name, driver, and opts
|
||||||
// This is called directly from the remote API
|
// This is called directly from the remote API
|
||||||
func (daemon *Daemon) VolumeCreate(name, driverName string, opts map[string]string) (*types.Volume, error) {
|
func (daemon *Daemon) VolumeCreate(name, driverName string, opts map[string]string) (*types.Volume, error) {
|
||||||
|
|
|
@ -226,18 +226,30 @@ func (daemon *Daemon) load(id string) (*container.Container, error) {
|
||||||
return container, nil
|
return container, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register makes a container object usable by the daemon as <container.ID>
|
func (daemon *Daemon) registerName(container *container.Container) error {
|
||||||
func (daemon *Daemon) Register(container *container.Container) error {
|
|
||||||
if daemon.Exists(container.ID) {
|
if daemon.Exists(container.ID) {
|
||||||
return fmt.Errorf("Container is already loaded")
|
return fmt.Errorf("Container is already loaded")
|
||||||
}
|
}
|
||||||
if err := validateID(container.ID); err != nil {
|
if err := validateID(container.ID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := daemon.ensureName(container); err != nil {
|
if container.Name == "" {
|
||||||
return err
|
name, err := daemon.generateNewName(container.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
container.Name = name
|
||||||
|
|
||||||
|
if err := container.ToDiskLocking(); err != nil {
|
||||||
|
logrus.Errorf("Error saving container name to disk: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register makes a container object usable by the daemon as <container.ID>
|
||||||
|
func (daemon *Daemon) Register(container *container.Container) error {
|
||||||
// Attach to stdout and stderr
|
// Attach to stdout and stderr
|
||||||
if container.Config.OpenStdin {
|
if container.Config.OpenStdin {
|
||||||
container.NewInputPipes()
|
container.NewInputPipes()
|
||||||
|
@ -277,21 +289,6 @@ func (daemon *Daemon) Register(container *container.Container) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) ensureName(container *container.Container) error {
|
|
||||||
if container.Name == "" {
|
|
||||||
name, err := daemon.generateNewName(container.ID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
container.Name = name
|
|
||||||
|
|
||||||
if err := container.ToDiskLocking(); err != nil {
|
|
||||||
logrus.Errorf("Error saving container name to disk: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (daemon *Daemon) restore() error {
|
func (daemon *Daemon) restore() error {
|
||||||
type cr struct {
|
type cr struct {
|
||||||
container *container.Container
|
container *container.Container
|
||||||
|
@ -323,6 +320,13 @@ func (daemon *Daemon) restore() error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rwlayer, err := daemon.layerStore.GetRWLayer(container.ID)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("Failed to load container mount %v: %v", id, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
container.RWLayer = rwlayer
|
||||||
|
|
||||||
// Ignore the container if it does not support the current driver being used by the graph
|
// Ignore the container if it does not support the current driver being used by the graph
|
||||||
if (container.Driver == "" && currentDriver == "aufs") || container.Driver == currentDriver {
|
if (container.Driver == "" && currentDriver == "aufs") || container.Driver == currentDriver {
|
||||||
logrus.Debugf("Loaded container %v", container.ID)
|
logrus.Debugf("Loaded container %v", container.ID)
|
||||||
|
@ -361,6 +365,10 @@ func (daemon *Daemon) restore() error {
|
||||||
logrus.Debugf("Setting default id - %s", err)
|
logrus.Debugf("Setting default id - %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if err := daemon.registerName(container); err != nil {
|
||||||
|
logrus.Errorf("Failed to register container %s: %s", container.ID, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if err := daemon.Register(container); err != nil {
|
if err := daemon.Register(container); err != nil {
|
||||||
logrus.Errorf("Failed to register container %s: %s", container.ID, err)
|
logrus.Errorf("Failed to register container %s: %s", container.ID, err)
|
||||||
|
@ -961,19 +969,7 @@ func (daemon *Daemon) Shutdown() error {
|
||||||
// Mount sets container.BaseFS
|
// Mount sets container.BaseFS
|
||||||
// (is it not set coming in? why is it unset?)
|
// (is it not set coming in? why is it unset?)
|
||||||
func (daemon *Daemon) Mount(container *container.Container) error {
|
func (daemon *Daemon) Mount(container *container.Container) error {
|
||||||
var layerID layer.ChainID
|
dir, err := container.RWLayer.Mount(container.GetMountLabel())
|
||||||
if container.ImageID != "" {
|
|
||||||
img, err := daemon.imageStore.Get(container.ImageID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
layerID = img.RootFS.ChainID()
|
|
||||||
}
|
|
||||||
rwlayer, err := daemon.layerStore.Mount(container.ID, layerID, container.GetMountLabel(), daemon.setupInitLayer)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
dir, err := rwlayer.Path()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -990,13 +986,12 @@ func (daemon *Daemon) Mount(container *container.Container) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
container.BaseFS = dir // TODO: combine these fields
|
container.BaseFS = dir // TODO: combine these fields
|
||||||
container.RWLayer = rwlayer
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unmount unsets the container base filesystem
|
// Unmount unsets the container base filesystem
|
||||||
func (daemon *Daemon) Unmount(container *container.Container) {
|
func (daemon *Daemon) Unmount(container *container.Container) {
|
||||||
if err := daemon.layerStore.Unmount(container.ID); err != nil {
|
if err := container.RWLayer.Unmount(); err != nil {
|
||||||
logrus.Errorf("Error unmounting container %s: %s", container.ID, err)
|
logrus.Errorf("Error unmounting container %s: %s", container.ID, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1029,7 +1024,7 @@ func (daemon *Daemon) unsubscribeToContainerStats(c *container.Container, ch cha
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) changes(container *container.Container) ([]archive.Change, error) {
|
func (daemon *Daemon) changes(container *container.Container) ([]archive.Change, error) {
|
||||||
return daemon.layerStore.Changes(container.ID)
|
return container.RWLayer.Changes()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TagImage creates a tag in the repository reponame, pointing to the image named
|
// TagImage creates a tag in the repository reponame, pointing to the image named
|
||||||
|
@ -1398,14 +1393,13 @@ func tempDir(rootDir string, rootUID, rootGID int) (string, error) {
|
||||||
return tmpDir, idtools.MkdirAllAs(tmpDir, 0700, rootUID, rootGID)
|
return tmpDir, idtools.MkdirAllAs(tmpDir, 0700, rootUID, rootGID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) setHostConfig(container *container.Container, hostConfig *containertypes.HostConfig) error {
|
func (daemon *Daemon) setSecurityOptions(container *container.Container, hostConfig *containertypes.HostConfig) error {
|
||||||
container.Lock()
|
container.Lock()
|
||||||
if err := parseSecurityOpt(container, hostConfig); err != nil {
|
defer container.Unlock()
|
||||||
container.Unlock()
|
return parseSecurityOpt(container, hostConfig)
|
||||||
return err
|
}
|
||||||
}
|
|
||||||
container.Unlock()
|
|
||||||
|
|
||||||
|
func (daemon *Daemon) setHostConfig(container *container.Container, hostConfig *containertypes.HostConfig) error {
|
||||||
// Do not lock while creating volumes since this could be calling out to external plugins
|
// Do not lock while creating volumes since this could be calling out to external plugins
|
||||||
// Don't want to block other actions, like `docker ps` because we're waiting on an external plugin
|
// Don't want to block other actions, like `docker ps` because we're waiting on an external plugin
|
||||||
if err := daemon.registerMountPoints(container, hostConfig); err != nil {
|
if err := daemon.registerMountPoints(container, hostConfig); err != nil {
|
||||||
|
|
|
@ -130,7 +130,7 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemo
|
||||||
return derr.ErrorCodeRmFS.WithArgs(container.ID, err)
|
return derr.ErrorCodeRmFS.WithArgs(container.ID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata, err := daemon.layerStore.DeleteMount(container.ID)
|
metadata, err := daemon.layerStore.ReleaseRWLayer(container.RWLayer)
|
||||||
layer.LogReleaseMetadata(metadata)
|
layer.LogReleaseMetadata(metadata)
|
||||||
if err != nil && err != layer.ErrMountDoesNotExist {
|
if err != nil && err != layer.ErrMountDoesNotExist {
|
||||||
return derr.ErrorCodeRmDriverFS.WithArgs(daemon.driver, container.ID, err)
|
return derr.ErrorCodeRmDriverFS.WithArgs(daemon.driver, container.ID, err)
|
||||||
|
|
|
@ -163,7 +163,7 @@ func (daemon *Daemon) getInspectData(container *container.Container, size bool)
|
||||||
|
|
||||||
contJSONBase.GraphDriver.Name = container.Driver
|
contJSONBase.GraphDriver.Name = container.Driver
|
||||||
|
|
||||||
graphDriverData, err := daemon.layerStore.Metadata(container.ID)
|
graphDriverData, err := container.RWLayer.Metadata()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,9 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.Hos
|
||||||
// creating a container, not during start.
|
// creating a container, not during start.
|
||||||
if hostConfig != nil {
|
if hostConfig != nil {
|
||||||
logrus.Warn("DEPRECATED: Setting host configuration options when the container starts is deprecated and will be removed in Docker 1.12")
|
logrus.Warn("DEPRECATED: Setting host configuration options when the container starts is deprecated and will be removed in Docker 1.12")
|
||||||
|
if err := daemon.setSecurityOptions(container, hostConfig); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if err := daemon.setHostConfig(container, hostConfig); err != nil {
|
if err := daemon.setHostConfig(container, hostConfig); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ import (
|
||||||
"github.com/docker/distribution/digest"
|
"github.com/docker/distribution/digest"
|
||||||
"github.com/docker/docker/image"
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/layer"
|
"github.com/docker/docker/layer"
|
||||||
"github.com/docker/docker/pkg/archive"
|
|
||||||
"github.com/docker/docker/pkg/progress"
|
"github.com/docker/docker/pkg/progress"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
@ -115,25 +114,18 @@ func (ls *mockLayerStore) Get(chainID layer.ChainID) (layer.Layer, error) {
|
||||||
func (ls *mockLayerStore) Release(l layer.Layer) ([]layer.Metadata, error) {
|
func (ls *mockLayerStore) Release(l layer.Layer) ([]layer.Metadata, error) {
|
||||||
return []layer.Metadata{}, nil
|
return []layer.Metadata{}, nil
|
||||||
}
|
}
|
||||||
|
func (ls *mockLayerStore) CreateRWLayer(string, layer.ChainID, string, layer.MountInit) (layer.RWLayer, error) {
|
||||||
func (ls *mockLayerStore) Mount(id string, parent layer.ChainID, label string, init layer.MountInit) (layer.RWLayer, error) {
|
|
||||||
return nil, errors.New("not implemented")
|
return nil, errors.New("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ls *mockLayerStore) Unmount(id string) error {
|
func (ls *mockLayerStore) GetRWLayer(string) (layer.RWLayer, error) {
|
||||||
return errors.New("not implemented")
|
return nil, errors.New("not implemented")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ls *mockLayerStore) DeleteMount(id string) ([]layer.Metadata, error) {
|
func (ls *mockLayerStore) ReleaseRWLayer(layer.RWLayer) ([]layer.Metadata, error) {
|
||||||
return nil, errors.New("not implemented")
|
return nil, errors.New("not implemented")
|
||||||
}
|
|
||||||
|
|
||||||
func (ls *mockLayerStore) Changes(id string) ([]archive.Change, error) {
|
|
||||||
return nil, errors.New("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ls *mockLayerStore) Metadata(id string) (map[string]string, error) {
|
|
||||||
return nil, errors.New("not implemented")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type mockDownloadDescriptor struct {
|
type mockDownloadDescriptor struct {
|
||||||
|
|
|
@ -31,6 +31,11 @@ var (
|
||||||
// attempted on a mount layer which does not exist.
|
// attempted on a mount layer which does not exist.
|
||||||
ErrMountDoesNotExist = errors.New("mount does not exist")
|
ErrMountDoesNotExist = errors.New("mount does not exist")
|
||||||
|
|
||||||
|
// ErrMountNameConflict is used when a mount is attempted
|
||||||
|
// to be created but there is already a mount with the name
|
||||||
|
// used for creation.
|
||||||
|
ErrMountNameConflict = errors.New("mount already exists with name")
|
||||||
|
|
||||||
// ErrActiveMount is used when an operation on a
|
// ErrActiveMount is used when an operation on a
|
||||||
// mount is attempted but the layer is still
|
// mount is attempted but the layer is still
|
||||||
// mounted and the operation cannot be performed.
|
// mounted and the operation cannot be performed.
|
||||||
|
@ -103,18 +108,33 @@ type Layer interface {
|
||||||
type RWLayer interface {
|
type RWLayer interface {
|
||||||
TarStreamer
|
TarStreamer
|
||||||
|
|
||||||
// Path returns the filesystem path to the writable
|
// Name of mounted layer
|
||||||
// layer.
|
Name() string
|
||||||
Path() (string, error)
|
|
||||||
|
|
||||||
// Parent returns the layer which the writable
|
// Parent returns the layer which the writable
|
||||||
// layer was created from.
|
// layer was created from.
|
||||||
Parent() Layer
|
Parent() Layer
|
||||||
|
|
||||||
|
// Mount mounts the RWLayer and returns the filesystem path
|
||||||
|
// the to the writable layer.
|
||||||
|
Mount(mountLabel string) (string, error)
|
||||||
|
|
||||||
|
// Unmount unmounts the RWLayer. This should be called
|
||||||
|
// for every mount. If there are multiple mount calls
|
||||||
|
// this operation will only decrement the internal mount counter.
|
||||||
|
Unmount() error
|
||||||
|
|
||||||
// Size represents the size of the writable layer
|
// Size represents the size of the writable layer
|
||||||
// as calculated by the total size of the files
|
// as calculated by the total size of the files
|
||||||
// changed in the mutable layer.
|
// changed in the mutable layer.
|
||||||
Size() (int64, error)
|
Size() (int64, error)
|
||||||
|
|
||||||
|
// Changes returns the set of changes for the mutable layer
|
||||||
|
// from the base layer.
|
||||||
|
Changes() ([]archive.Change, error)
|
||||||
|
|
||||||
|
// Metadata returns the low level metadata for the mutable layer
|
||||||
|
Metadata() (map[string]string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Metadata holds information about a
|
// Metadata holds information about a
|
||||||
|
@ -147,11 +167,9 @@ type Store interface {
|
||||||
Get(ChainID) (Layer, error)
|
Get(ChainID) (Layer, error)
|
||||||
Release(Layer) ([]Metadata, error)
|
Release(Layer) ([]Metadata, error)
|
||||||
|
|
||||||
Mount(id string, parent ChainID, label string, init MountInit) (RWLayer, error)
|
CreateRWLayer(id string, parent ChainID, mountLabel string, initFunc MountInit) (RWLayer, error)
|
||||||
Unmount(id string) error
|
GetRWLayer(id string) (RWLayer, error)
|
||||||
DeleteMount(id string) ([]Metadata, error)
|
ReleaseRWLayer(RWLayer) ([]Metadata, error)
|
||||||
Changes(id string) ([]archive.Change, error)
|
|
||||||
Metadata(id string) (map[string]string, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MetadataTransaction represents functions for setting layer metadata
|
// MetadataTransaction represents functions for setting layer metadata
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"runtime"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
@ -144,6 +143,7 @@ func (ls *layerStore) loadMount(mount string) error {
|
||||||
mountID: mountID,
|
mountID: mountID,
|
||||||
initID: initID,
|
initID: initID,
|
||||||
layerStore: ls,
|
layerStore: ls,
|
||||||
|
references: map[RWLayer]*referencedRWLayer{},
|
||||||
}
|
}
|
||||||
|
|
||||||
if parent != "" {
|
if parent != "" {
|
||||||
|
@ -382,15 +382,114 @@ func (ls *layerStore) Release(l Layer) ([]Metadata, error) {
|
||||||
return ls.releaseLayer(layer)
|
return ls.releaseLayer(layer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ls *layerStore) mount(m *mountedLayer, mountLabel string) error {
|
func (ls *layerStore) CreateRWLayer(name string, parent ChainID, mountLabel string, initFunc MountInit) (RWLayer, error) {
|
||||||
dir, err := ls.driver.Get(m.mountID, mountLabel)
|
ls.mountL.Lock()
|
||||||
if err != nil {
|
defer ls.mountL.Unlock()
|
||||||
return err
|
m, ok := ls.mounts[name]
|
||||||
|
if ok {
|
||||||
|
return nil, ErrMountNameConflict
|
||||||
}
|
}
|
||||||
m.path = dir
|
|
||||||
m.activityCount++
|
|
||||||
|
|
||||||
return nil
|
var err error
|
||||||
|
var pid string
|
||||||
|
var p *roLayer
|
||||||
|
if string(parent) != "" {
|
||||||
|
p = ls.get(parent)
|
||||||
|
if p == nil {
|
||||||
|
return nil, ErrLayerDoesNotExist
|
||||||
|
}
|
||||||
|
pid = p.cacheID
|
||||||
|
|
||||||
|
// Release parent chain if error
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
ls.layerL.Lock()
|
||||||
|
ls.releaseLayer(p)
|
||||||
|
ls.layerL.Unlock()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
m = &mountedLayer{
|
||||||
|
name: name,
|
||||||
|
parent: p,
|
||||||
|
mountID: ls.mountID(name),
|
||||||
|
layerStore: ls,
|
||||||
|
references: map[RWLayer]*referencedRWLayer{},
|
||||||
|
}
|
||||||
|
|
||||||
|
if initFunc != nil {
|
||||||
|
pid, err = ls.initMount(m.mountID, pid, mountLabel, initFunc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
m.initID = pid
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = ls.driver.Create(m.mountID, pid, ""); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = ls.saveMount(m); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.getReference(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *layerStore) GetRWLayer(id string) (RWLayer, error) {
|
||||||
|
ls.mountL.Lock()
|
||||||
|
defer ls.mountL.Unlock()
|
||||||
|
mount, ok := ls.mounts[id]
|
||||||
|
if !ok {
|
||||||
|
return nil, ErrMountDoesNotExist
|
||||||
|
}
|
||||||
|
|
||||||
|
return mount.getReference(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *layerStore) ReleaseRWLayer(l RWLayer) ([]Metadata, error) {
|
||||||
|
ls.mountL.Lock()
|
||||||
|
defer ls.mountL.Unlock()
|
||||||
|
m, ok := ls.mounts[l.Name()]
|
||||||
|
if !ok {
|
||||||
|
return []Metadata{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.deleteReference(l); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.hasReferences() {
|
||||||
|
return []Metadata{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ls.driver.Remove(m.mountID); err != nil {
|
||||||
|
logrus.Errorf("Error removing mounted layer %s: %s", m.name, err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.initID != "" {
|
||||||
|
if err := ls.driver.Remove(m.initID); err != nil {
|
||||||
|
logrus.Errorf("Error removing init layer %s: %s", m.name, err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ls.store.RemoveMount(m.name); err != nil {
|
||||||
|
logrus.Errorf("Error removing mount metadata: %s: %s", m.name, err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(ls.mounts, m.Name())
|
||||||
|
|
||||||
|
ls.layerL.Lock()
|
||||||
|
defer ls.layerL.Unlock()
|
||||||
|
if m.parent != nil {
|
||||||
|
return ls.releaseLayer(m.parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
return []Metadata{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ls *layerStore) saveMount(mount *mountedLayer) error {
|
func (ls *layerStore) saveMount(mount *mountedLayer) error {
|
||||||
|
@ -442,145 +541,6 @@ func (ls *layerStore) initMount(graphID, parent, mountLabel string, initFunc Mou
|
||||||
return initID, nil
|
return initID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ls *layerStore) Mount(name string, parent ChainID, mountLabel string, initFunc MountInit) (l RWLayer, err error) {
|
|
||||||
ls.mountL.Lock()
|
|
||||||
defer ls.mountL.Unlock()
|
|
||||||
m, ok := ls.mounts[name]
|
|
||||||
if ok {
|
|
||||||
// Check if has path
|
|
||||||
if err := ls.mount(m, mountLabel); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var pid string
|
|
||||||
var p *roLayer
|
|
||||||
if string(parent) != "" {
|
|
||||||
p = ls.get(parent)
|
|
||||||
if p == nil {
|
|
||||||
return nil, ErrLayerDoesNotExist
|
|
||||||
}
|
|
||||||
pid = p.cacheID
|
|
||||||
|
|
||||||
// Release parent chain if error
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
ls.layerL.Lock()
|
|
||||||
ls.releaseLayer(p)
|
|
||||||
ls.layerL.Unlock()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
mountID := name
|
|
||||||
if runtime.GOOS != "windows" {
|
|
||||||
// windows has issues if container ID doesn't match mount ID
|
|
||||||
mountID = stringid.GenerateRandomID()
|
|
||||||
}
|
|
||||||
|
|
||||||
m = &mountedLayer{
|
|
||||||
name: name,
|
|
||||||
parent: p,
|
|
||||||
mountID: mountID,
|
|
||||||
layerStore: ls,
|
|
||||||
}
|
|
||||||
|
|
||||||
if initFunc != nil {
|
|
||||||
pid, err = ls.initMount(m.mountID, pid, mountLabel, initFunc)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
m.initID = pid
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = ls.driver.Create(m.mountID, pid, ""); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = ls.saveMount(m); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = ls.mount(m, mountLabel); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ls *layerStore) Unmount(name string) error {
|
|
||||||
ls.mountL.Lock()
|
|
||||||
defer ls.mountL.Unlock()
|
|
||||||
|
|
||||||
m := ls.mounts[name]
|
|
||||||
if m == nil {
|
|
||||||
return ErrMountDoesNotExist
|
|
||||||
}
|
|
||||||
|
|
||||||
m.activityCount--
|
|
||||||
|
|
||||||
if err := ls.driver.Put(m.mountID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ls *layerStore) DeleteMount(name string) ([]Metadata, error) {
|
|
||||||
ls.mountL.Lock()
|
|
||||||
defer ls.mountL.Unlock()
|
|
||||||
|
|
||||||
m := ls.mounts[name]
|
|
||||||
if m == nil {
|
|
||||||
return nil, ErrMountDoesNotExist
|
|
||||||
}
|
|
||||||
if m.activityCount > 0 {
|
|
||||||
return nil, ErrActiveMount
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(ls.mounts, name)
|
|
||||||
|
|
||||||
if err := ls.driver.Remove(m.mountID); err != nil {
|
|
||||||
logrus.Errorf("Error removing mounted layer %s: %s", m.name, err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if m.initID != "" {
|
|
||||||
if err := ls.driver.Remove(m.initID); err != nil {
|
|
||||||
logrus.Errorf("Error removing init layer %s: %s", m.name, err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ls.store.RemoveMount(m.name); err != nil {
|
|
||||||
logrus.Errorf("Error removing mount metadata: %s: %s", m.name, err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ls.layerL.Lock()
|
|
||||||
defer ls.layerL.Unlock()
|
|
||||||
if m.parent != nil {
|
|
||||||
return ls.releaseLayer(m.parent)
|
|
||||||
}
|
|
||||||
|
|
||||||
return []Metadata{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ls *layerStore) Changes(name string) ([]archive.Change, error) {
|
|
||||||
ls.mountL.Lock()
|
|
||||||
m := ls.mounts[name]
|
|
||||||
ls.mountL.Unlock()
|
|
||||||
if m == nil {
|
|
||||||
return nil, ErrMountDoesNotExist
|
|
||||||
}
|
|
||||||
pid := m.initID
|
|
||||||
if pid == "" && m.parent != nil {
|
|
||||||
pid = m.parent.cacheID
|
|
||||||
}
|
|
||||||
return ls.driver.Changes(m.mountID, pid)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ls *layerStore) assembleTar(graphID string, metadata io.ReadCloser, size *int64) (io.ReadCloser, error) {
|
func (ls *layerStore) assembleTar(graphID string, metadata io.ReadCloser, size *int64) (io.ReadCloser, error) {
|
||||||
type diffPathDriver interface {
|
type diffPathDriver interface {
|
||||||
DiffPath(string) (string, func() error, error)
|
DiffPath(string) (string, func() error, error)
|
||||||
|
@ -621,17 +581,6 @@ func (ls *layerStore) assembleTar(graphID string, metadata io.ReadCloser, size *
|
||||||
return pR, nil
|
return pR, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Metadata returns the low level metadata from the mount with the given name
|
|
||||||
func (ls *layerStore) Metadata(name string) (map[string]string, error) {
|
|
||||||
ls.mountL.Lock()
|
|
||||||
m := ls.mounts[name]
|
|
||||||
ls.mountL.Unlock()
|
|
||||||
if m == nil {
|
|
||||||
return nil, ErrMountDoesNotExist
|
|
||||||
}
|
|
||||||
return ls.driver.GetMetadata(m.mountID)
|
|
||||||
}
|
|
||||||
|
|
||||||
type naiveDiffPathDriver struct {
|
type naiveDiffPathDriver struct {
|
||||||
graphdriver.Driver
|
graphdriver.Driver
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,12 +82,12 @@ type layerInit func(root string) error
|
||||||
|
|
||||||
func createLayer(ls Store, parent ChainID, layerFunc layerInit) (Layer, error) {
|
func createLayer(ls Store, parent ChainID, layerFunc layerInit) (Layer, error) {
|
||||||
containerID := stringid.GenerateRandomID()
|
containerID := stringid.GenerateRandomID()
|
||||||
mount, err := ls.Mount(containerID, parent, "", nil)
|
mount, err := ls.CreateRWLayer(containerID, parent, "", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
path, err := mount.Path()
|
path, err := mount.Mount("")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -107,11 +107,11 @@ func createLayer(ls Store, parent ChainID, layerFunc layerInit) (Layer, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ls.Unmount(containerID); err != nil {
|
if err := mount.Unmount(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := ls.DeleteMount(containerID); err != nil {
|
if _, err := ls.ReleaseRWLayer(mount); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,6 +171,13 @@ func getCachedLayer(l Layer) *roLayer {
|
||||||
return l.(*roLayer)
|
return l.(*roLayer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getMountLayer(l RWLayer) *mountedLayer {
|
||||||
|
if rl, ok := l.(*referencedRWLayer); ok {
|
||||||
|
return rl.mountedLayer
|
||||||
|
}
|
||||||
|
return l.(*mountedLayer)
|
||||||
|
}
|
||||||
|
|
||||||
func createMetadata(layers ...Layer) []Metadata {
|
func createMetadata(layers ...Layer) []Metadata {
|
||||||
metadata := make([]Metadata, len(layers))
|
metadata := make([]Metadata, len(layers))
|
||||||
for i := range layers {
|
for i := range layers {
|
||||||
|
@ -270,12 +277,12 @@ func TestMountAndRegister(t *testing.T) {
|
||||||
size, _ := layer.Size()
|
size, _ := layer.Size()
|
||||||
t.Logf("Layer size: %d", size)
|
t.Logf("Layer size: %d", size)
|
||||||
|
|
||||||
mount2, err := ls.Mount("new-test-mount", layer.ChainID(), "", nil)
|
mount2, err := ls.CreateRWLayer("new-test-mount", layer.ChainID(), "", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
path2, err := mount2.Path()
|
path2, err := mount2.Mount("")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -289,11 +296,11 @@ func TestMountAndRegister(t *testing.T) {
|
||||||
t.Fatalf("Wrong file data, expected %q, got %q", expected, string(b))
|
t.Fatalf("Wrong file data, expected %q, got %q", expected, string(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ls.Unmount("new-test-mount"); err != nil {
|
if err := mount2.Unmount(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := ls.DeleteMount("new-test-mount"); err != nil {
|
if _, err := ls.ReleaseRWLayer(mount2); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -370,12 +377,12 @@ func TestStoreRestore(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
m, err := ls.Mount("some-mount_name", layer3.ChainID(), "", nil)
|
m, err := ls.CreateRWLayer("some-mount_name", layer3.ChainID(), "", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
path, err := m.Path()
|
path, err := m.Mount("")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -383,11 +390,14 @@ func TestStoreRestore(t *testing.T) {
|
||||||
if err := ioutil.WriteFile(filepath.Join(path, "testfile.txt"), []byte("nothing here"), 0644); err != nil {
|
if err := ioutil.WriteFile(filepath.Join(path, "testfile.txt"), []byte("nothing here"), 0644); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
assertActivityCount(t, m, 1)
|
||||||
|
|
||||||
if err := ls.Unmount("some-mount_name"); err != nil {
|
if err := m.Unmount(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assertActivityCount(t, m, 0)
|
||||||
|
|
||||||
ls2, err := NewStore(ls.(*layerStore).store, ls.(*layerStore).driver)
|
ls2, err := NewStore(ls.(*layerStore).store, ls.(*layerStore).driver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -400,18 +410,39 @@ func TestStoreRestore(t *testing.T) {
|
||||||
|
|
||||||
assertLayerEqual(t, layer3b, layer3)
|
assertLayerEqual(t, layer3b, layer3)
|
||||||
|
|
||||||
// Mount again with same name, should already be loaded
|
// Create again with same name, should return error
|
||||||
m2, err := ls2.Mount("some-mount_name", layer3b.ChainID(), "", nil)
|
if _, err := ls2.CreateRWLayer("some-mount_name", layer3b.ChainID(), "", nil); err == nil {
|
||||||
|
t.Fatal("Expected error creating mount with same name")
|
||||||
|
} else if err != ErrMountNameConflict {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m2, err := ls2.GetRWLayer("some-mount_name")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
path2, err := m2.Path()
|
if mountPath, err := m2.Mount(""); err != nil {
|
||||||
if err != nil {
|
t.Fatal(err)
|
||||||
|
} else if path != mountPath {
|
||||||
|
t.Fatalf("Unexpected path %s, expected %s", mountPath, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertActivityCount(t, m2, 1)
|
||||||
|
|
||||||
|
if mountPath, err := m2.Mount(""); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if path != mountPath {
|
||||||
|
t.Fatalf("Unexpected path %s, expected %s", mountPath, path)
|
||||||
|
}
|
||||||
|
assertActivityCount(t, m2, 2)
|
||||||
|
if err := m2.Unmount(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
b, err := ioutil.ReadFile(filepath.Join(path2, "testfile.txt"))
|
assertActivityCount(t, m2, 1)
|
||||||
|
|
||||||
|
b, err := ioutil.ReadFile(filepath.Join(path, "testfile.txt"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -419,11 +450,19 @@ func TestStoreRestore(t *testing.T) {
|
||||||
t.Fatalf("Unexpected content %q, expected %q", string(b), expected)
|
t.Fatalf("Unexpected content %q, expected %q", string(b), expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ls2.Unmount("some-mount_name"); err != nil {
|
if err := m2.Unmount(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if metadata, err := ls2.DeleteMount("some-mount_name"); err != nil {
|
assertActivityCount(t, m2, 0)
|
||||||
|
|
||||||
|
if metadata, err := ls2.ReleaseRWLayer(m2); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if len(metadata) != 0 {
|
||||||
|
t.Fatalf("Unexpectedly deleted layers: %#v", metadata)
|
||||||
|
}
|
||||||
|
|
||||||
|
if metadata, err := ls2.ReleaseRWLayer(m2); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if len(metadata) != 0 {
|
} else if len(metadata) != 0 {
|
||||||
t.Fatalf("Unexpectedly deleted layers: %#v", metadata)
|
t.Fatalf("Unexpectedly deleted layers: %#v", metadata)
|
||||||
|
@ -627,6 +666,13 @@ func assertReferences(t *testing.T, references ...Layer) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func assertActivityCount(t *testing.T, l RWLayer, expected int) {
|
||||||
|
rl := l.(*referencedRWLayer)
|
||||||
|
if rl.activityCount != expected {
|
||||||
|
t.Fatalf("Unexpected activity count %d, expected %d", rl.activityCount, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestRegisterExistingLayer(t *testing.T) {
|
func TestRegisterExistingLayer(t *testing.T) {
|
||||||
ls, cleanup := newTestStore(t)
|
ls, cleanup := newTestStore(t)
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
// +build linux freebsd darwin
|
||||||
|
|
||||||
|
package layer
|
||||||
|
|
||||||
|
import "github.com/docker/docker/pkg/stringid"
|
||||||
|
|
||||||
|
func (ls *layerStore) mountID(name string) string {
|
||||||
|
return stringid.GenerateRandomID()
|
||||||
|
}
|
|
@ -89,3 +89,8 @@ func (ls *layerStore) RegisterDiffID(graphID string, size int64) (Layer, error)
|
||||||
|
|
||||||
return layer.getReference(), nil
|
return layer.getReference(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ls *layerStore) mountID(name string) string {
|
||||||
|
// windows has issues if container ID doesn't match mount ID
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
|
@ -14,30 +14,33 @@ import (
|
||||||
"github.com/vbatts/tar-split/tar/storage"
|
"github.com/vbatts/tar-split/tar/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (ls *layerStore) MountByGraphID(name string, graphID string, parent ChainID) (l RWLayer, err error) {
|
// CreateRWLayerByGraphID creates a RWLayer in the layer store using
|
||||||
|
// the provided name with the given graphID. To get the RWLayer
|
||||||
|
// after migration the layer may be retrieved by the given name.
|
||||||
|
func (ls *layerStore) CreateRWLayerByGraphID(name string, graphID string, parent ChainID) (err error) {
|
||||||
ls.mountL.Lock()
|
ls.mountL.Lock()
|
||||||
defer ls.mountL.Unlock()
|
defer ls.mountL.Unlock()
|
||||||
m, ok := ls.mounts[name]
|
m, ok := ls.mounts[name]
|
||||||
if ok {
|
if ok {
|
||||||
if m.parent.chainID != parent {
|
if m.parent.chainID != parent {
|
||||||
return nil, errors.New("name conflict, mismatched parent")
|
return errors.New("name conflict, mismatched parent")
|
||||||
}
|
}
|
||||||
if m.mountID != graphID {
|
if m.mountID != graphID {
|
||||||
return nil, errors.New("mount already exists")
|
return errors.New("mount already exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
return m, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ls.driver.Exists(graphID) {
|
if !ls.driver.Exists(graphID) {
|
||||||
return nil, errors.New("graph ID does not exist")
|
return errors.New("graph ID does not exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
var p *roLayer
|
var p *roLayer
|
||||||
if string(parent) != "" {
|
if string(parent) != "" {
|
||||||
p = ls.get(parent)
|
p = ls.get(parent)
|
||||||
if p == nil {
|
if p == nil {
|
||||||
return nil, ErrLayerDoesNotExist
|
return ErrLayerDoesNotExist
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release parent chain if error
|
// Release parent chain if error
|
||||||
|
@ -57,6 +60,7 @@ func (ls *layerStore) MountByGraphID(name string, graphID string, parent ChainID
|
||||||
parent: p,
|
parent: p,
|
||||||
mountID: graphID,
|
mountID: graphID,
|
||||||
layerStore: ls,
|
layerStore: ls,
|
||||||
|
references: map[RWLayer]*referencedRWLayer{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for existing init layer
|
// Check for existing init layer
|
||||||
|
@ -66,15 +70,10 @@ func (ls *layerStore) MountByGraphID(name string, graphID string, parent ChainID
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = ls.saveMount(m); err != nil {
|
if err = ls.saveMount(m); err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: provide a mount label
|
return nil
|
||||||
if err = ls.mount(m, ""); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return m, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ls *layerStore) migrateLayer(tx MetadataTransaction, tarDataFile string, layer *roLayer) error {
|
func (ls *layerStore) migrateLayer(tx MetadataTransaction, tarDataFile string, layer *roLayer) error {
|
||||||
|
|
|
@ -303,12 +303,20 @@ func TestMountMigration(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
rwLayer1, err := ls.(*layerStore).MountByGraphID("migration-mount", containerID, layer1.ChainID())
|
if err := ls.(*layerStore).CreateRWLayerByGraphID("migration-mount", containerID, layer1.ChainID()); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rwLayer1, err := ls.GetRWLayer("migration-mount")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
changes, err := ls.Changes("migration-mount")
|
if _, err := rwLayer1.Mount(""); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
changes, err := rwLayer1.Changes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -341,39 +349,63 @@ func TestMountMigration(t *testing.T) {
|
||||||
Kind: archive.ChangeAdd,
|
Kind: archive.ChangeAdd,
|
||||||
})
|
})
|
||||||
|
|
||||||
if expectedCount := 1; rwLayer1.(*mountedLayer).activityCount != expectedCount {
|
assertActivityCount(t, rwLayer1, 1)
|
||||||
t.Fatalf("Wrong activity count %d, expected %d", rwLayer1.(*mountedLayer).activityCount, expectedCount)
|
|
||||||
|
if _, err := ls.CreateRWLayer("migration-mount", layer1.ChainID(), "", nil); err == nil {
|
||||||
|
t.Fatal("Expected error creating mount with same name")
|
||||||
|
} else if err != ErrMountNameConflict {
|
||||||
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
rwLayer2, err := ls.Mount("migration-mount", layer1.ChainID(), "", nil)
|
rwLayer2, err := ls.GetRWLayer("migration-mount")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if rwLayer1 != rwLayer2 {
|
if getMountLayer(rwLayer1) != getMountLayer(rwLayer2) {
|
||||||
t.Fatalf("Wrong rwlayer %v, expected %v", rwLayer2, rwLayer1)
|
t.Fatal("Expected same layer from get with same name as from migrate")
|
||||||
}
|
}
|
||||||
|
|
||||||
if expectedCount := 2; rwLayer2.(*mountedLayer).activityCount != expectedCount {
|
if _, err := rwLayer2.Mount(""); err != nil {
|
||||||
t.Fatalf("Wrong activity count %d, expected %d", rwLayer2.(*mountedLayer).activityCount, expectedCount)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assertActivityCount(t, rwLayer2, 1)
|
||||||
|
assertActivityCount(t, rwLayer1, 1)
|
||||||
|
|
||||||
|
if _, err := rwLayer2.Mount(""); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertActivityCount(t, rwLayer2, 2)
|
||||||
|
assertActivityCount(t, rwLayer1, 1)
|
||||||
|
|
||||||
if metadata, err := ls.Release(layer1); err != nil {
|
if metadata, err := ls.Release(layer1); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if len(metadata) > 0 {
|
} else if len(metadata) > 0 {
|
||||||
t.Fatalf("Expected no layers to be deleted, deleted %#v", metadata)
|
t.Fatalf("Expected no layers to be deleted, deleted %#v", metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ls.Unmount("migration-mount"); err != nil {
|
if err := rwLayer1.Unmount(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if _, err := ls.DeleteMount("migration-mount"); err == nil {
|
assertActivityCount(t, rwLayer2, 2)
|
||||||
|
assertActivityCount(t, rwLayer1, 0)
|
||||||
|
|
||||||
|
if _, err := ls.ReleaseRWLayer(rwLayer1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := rwLayer2.Unmount(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if _, err := ls.ReleaseRWLayer(rwLayer2); err == nil {
|
||||||
t.Fatal("Expected error deleting active mount")
|
t.Fatal("Expected error deleting active mount")
|
||||||
}
|
}
|
||||||
if err := ls.Unmount("migration-mount"); err != nil {
|
if err := rwLayer2.Unmount(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
metadata, err := ls.DeleteMount("migration-mount")
|
metadata, err := ls.ReleaseRWLayer(rwLayer2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,12 +27,12 @@ func TestMountInit(t *testing.T) {
|
||||||
return initfile.ApplyFile(root)
|
return initfile.ApplyFile(root)
|
||||||
}
|
}
|
||||||
|
|
||||||
m, err := ls.Mount("fun-mount", layer.ChainID(), "", mountInit)
|
m, err := ls.CreateRWLayer("fun-mount", layer.ChainID(), "", mountInit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
path, err := m.Path()
|
path, err := m.Mount("")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -80,12 +80,12 @@ func TestMountSize(t *testing.T) {
|
||||||
return newTestFile("file-init", contentInit, 0777).ApplyFile(root)
|
return newTestFile("file-init", contentInit, 0777).ApplyFile(root)
|
||||||
}
|
}
|
||||||
|
|
||||||
m, err := ls.Mount("mount-size", layer.ChainID(), "", mountInit)
|
m, err := ls.CreateRWLayer("mount-size", layer.ChainID(), "", mountInit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
path, err := m.Path()
|
path, err := m.Mount("")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -125,12 +125,12 @@ func TestMountChanges(t *testing.T) {
|
||||||
return initfile.ApplyFile(root)
|
return initfile.ApplyFile(root)
|
||||||
}
|
}
|
||||||
|
|
||||||
m, err := ls.Mount("mount-changes", layer.ChainID(), "", mountInit)
|
m, err := ls.CreateRWLayer("mount-changes", layer.ChainID(), "", mountInit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
path, err := m.Path()
|
path, err := m.Mount("")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -155,7 +155,7 @@ func TestMountChanges(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
changes, err := ls.Changes("mount-changes")
|
changes, err := m.Changes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,20 @@
|
||||||
package layer
|
package layer
|
||||||
|
|
||||||
import "io"
|
import (
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/docker/docker/pkg/archive"
|
||||||
|
)
|
||||||
|
|
||||||
type mountedLayer struct {
|
type mountedLayer struct {
|
||||||
name string
|
name string
|
||||||
mountID string
|
mountID string
|
||||||
initID string
|
initID string
|
||||||
parent *roLayer
|
parent *roLayer
|
||||||
path string
|
layerStore *layerStore
|
||||||
layerStore *layerStore
|
|
||||||
activityCount int
|
references map[RWLayer]*referencedRWLayer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ml *mountedLayer) cacheParent() string {
|
func (ml *mountedLayer) cacheParent() string {
|
||||||
|
@ -30,11 +35,8 @@ func (ml *mountedLayer) TarStream() (io.ReadCloser, error) {
|
||||||
return archiver, nil
|
return archiver, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ml *mountedLayer) Path() (string, error) {
|
func (ml *mountedLayer) Name() string {
|
||||||
if ml.path == "" {
|
return ml.name
|
||||||
return "", ErrNotMounted
|
|
||||||
}
|
|
||||||
return ml.path, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ml *mountedLayer) Parent() Layer {
|
func (ml *mountedLayer) Parent() Layer {
|
||||||
|
@ -47,6 +49,96 @@ func (ml *mountedLayer) Parent() Layer {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ml *mountedLayer) Mount(mountLabel string) (string, error) {
|
||||||
|
return ml.layerStore.driver.Get(ml.mountID, mountLabel)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ml *mountedLayer) Unmount() error {
|
||||||
|
return ml.layerStore.driver.Put(ml.mountID)
|
||||||
|
}
|
||||||
|
|
||||||
func (ml *mountedLayer) Size() (int64, error) {
|
func (ml *mountedLayer) Size() (int64, error) {
|
||||||
return ml.layerStore.driver.DiffSize(ml.mountID, ml.cacheParent())
|
return ml.layerStore.driver.DiffSize(ml.mountID, ml.cacheParent())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ml *mountedLayer) Changes() ([]archive.Change, error) {
|
||||||
|
return ml.layerStore.driver.Changes(ml.mountID, ml.cacheParent())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ml *mountedLayer) Metadata() (map[string]string, error) {
|
||||||
|
return ml.layerStore.driver.GetMetadata(ml.mountID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ml *mountedLayer) getReference() RWLayer {
|
||||||
|
ref := &referencedRWLayer{
|
||||||
|
mountedLayer: ml,
|
||||||
|
}
|
||||||
|
ml.references[ref] = ref
|
||||||
|
|
||||||
|
return ref
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ml *mountedLayer) hasReferences() bool {
|
||||||
|
return len(ml.references) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ml *mountedLayer) deleteReference(ref RWLayer) error {
|
||||||
|
rl, ok := ml.references[ref]
|
||||||
|
if !ok {
|
||||||
|
return ErrLayerNotRetained
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := rl.release(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
delete(ml.references, ref)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type referencedRWLayer struct {
|
||||||
|
*mountedLayer
|
||||||
|
|
||||||
|
activityL sync.Mutex
|
||||||
|
activityCount int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rl *referencedRWLayer) release() error {
|
||||||
|
rl.activityL.Lock()
|
||||||
|
defer rl.activityL.Unlock()
|
||||||
|
|
||||||
|
if rl.activityCount > 0 {
|
||||||
|
return ErrActiveMount
|
||||||
|
}
|
||||||
|
|
||||||
|
rl.activityCount = -1
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rl *referencedRWLayer) Mount(mountLabel string) (string, error) {
|
||||||
|
rl.activityL.Lock()
|
||||||
|
defer rl.activityL.Unlock()
|
||||||
|
|
||||||
|
if rl.activityCount == -1 {
|
||||||
|
return "", ErrLayerNotRetained
|
||||||
|
}
|
||||||
|
|
||||||
|
rl.activityCount++
|
||||||
|
return rl.mountedLayer.Mount(mountLabel)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rl *referencedRWLayer) Unmount() error {
|
||||||
|
rl.activityL.Lock()
|
||||||
|
defer rl.activityL.Unlock()
|
||||||
|
|
||||||
|
if rl.activityCount == 0 {
|
||||||
|
return ErrNotMounted
|
||||||
|
}
|
||||||
|
if rl.activityCount == -1 {
|
||||||
|
return ErrLayerNotRetained
|
||||||
|
}
|
||||||
|
rl.activityCount--
|
||||||
|
|
||||||
|
return rl.mountedLayer.Unmount()
|
||||||
|
}
|
||||||
|
|
|
@ -24,8 +24,7 @@ type graphIDRegistrar interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type graphIDMounter interface {
|
type graphIDMounter interface {
|
||||||
MountByGraphID(string, string, layer.ChainID) (layer.RWLayer, error)
|
CreateRWLayerByGraphID(string, string, layer.ChainID) error
|
||||||
Unmount(string) error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -172,13 +171,7 @@ func migrateContainers(root string, ls graphIDMounter, is image.Store, imageMapp
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = ls.MountByGraphID(id, id, img.RootFS.ChainID())
|
if err := ls.CreateRWLayerByGraphID(id, id, img.RootFS.ChainID()); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = ls.Unmount(id)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -338,10 +338,9 @@ type mockMounter struct {
|
||||||
count int
|
count int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *mockMounter) MountByGraphID(name string, graphID string, parent layer.ChainID) (layer.RWLayer, error) {
|
func (r *mockMounter) CreateRWLayerByGraphID(name string, graphID string, parent layer.ChainID) error {
|
||||||
r.mounts = append(r.mounts, mountInfo{name, graphID, string(parent)})
|
r.mounts = append(r.mounts, mountInfo{name, graphID, string(parent)})
|
||||||
r.count++
|
return nil
|
||||||
return nil, nil
|
|
||||||
}
|
}
|
||||||
func (r *mockMounter) Unmount(string) error {
|
func (r *mockMounter) Unmount(string) error {
|
||||||
r.count--
|
r.count--
|
||||||
|
|
Загрузка…
Ссылка в новой задаче