зеркало из 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 {
|
||||
archive.Close()
|
||||
return daemon.layerStore.Unmount(container.ID)
|
||||
return container.RWLayer.Unmount()
|
||||
}),
|
||||
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 {
|
||||
return derr.ErrorCodeGetLayerMetadata.WithArgs(err)
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/docker/docker/container"
|
||||
derr "github.com/docker/docker/errors"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"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.
|
||||
func (daemon *Daemon) create(params types.ContainerCreateConfig) (*container.Container, error) {
|
||||
func (daemon *Daemon) create(params types.ContainerCreateConfig) (retC *container.Container, retErr error) {
|
||||
var (
|
||||
container *container.Container
|
||||
img *image.Image
|
||||
imgID image.ID
|
||||
err error
|
||||
retErr error
|
||||
)
|
||||
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -126,6 +135,24 @@ func (daemon *Daemon) generateSecurityOpt(ipcMode containertypes.IpcMode, pidMod
|
|||
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
|
||||
// This is called directly from the remote API
|
||||
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
|
||||
}
|
||||
|
||||
// Register makes a container object usable by the daemon as <container.ID>
|
||||
func (daemon *Daemon) Register(container *container.Container) error {
|
||||
func (daemon *Daemon) registerName(container *container.Container) error {
|
||||
if daemon.Exists(container.ID) {
|
||||
return fmt.Errorf("Container is already loaded")
|
||||
}
|
||||
if err := validateID(container.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := daemon.ensureName(container); err != nil {
|
||||
return err
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
if container.Config.OpenStdin {
|
||||
container.NewInputPipes()
|
||||
|
@ -277,21 +289,6 @@ func (daemon *Daemon) Register(container *container.Container) error {
|
|||
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 {
|
||||
type cr struct {
|
||||
container *container.Container
|
||||
|
@ -323,6 +320,13 @@ func (daemon *Daemon) restore() error {
|
|||
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
|
||||
if (container.Driver == "" && currentDriver == "aufs") || container.Driver == currentDriver {
|
||||
logrus.Debugf("Loaded container %v", container.ID)
|
||||
|
@ -361,6 +365,10 @@ func (daemon *Daemon) restore() error {
|
|||
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 {
|
||||
logrus.Errorf("Failed to register container %s: %s", container.ID, err)
|
||||
|
@ -961,19 +969,7 @@ func (daemon *Daemon) Shutdown() error {
|
|||
// Mount sets container.BaseFS
|
||||
// (is it not set coming in? why is it unset?)
|
||||
func (daemon *Daemon) Mount(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.Mount(container.ID, layerID, container.GetMountLabel(), daemon.setupInitLayer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dir, err := rwlayer.Path()
|
||||
dir, err := container.RWLayer.Mount(container.GetMountLabel())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -990,13 +986,12 @@ func (daemon *Daemon) Mount(container *container.Container) error {
|
|||
}
|
||||
}
|
||||
container.BaseFS = dir // TODO: combine these fields
|
||||
container.RWLayer = rwlayer
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unmount unsets the container base filesystem
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -1029,7 +1024,7 @@ func (daemon *Daemon) unsubscribeToContainerStats(c *container.Container, ch cha
|
|||
}
|
||||
|
||||
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
|
||||
|
@ -1398,14 +1393,13 @@ func tempDir(rootDir string, rootUID, rootGID int) (string, error) {
|
|||
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()
|
||||
if err := parseSecurityOpt(container, hostConfig); err != nil {
|
||||
container.Unlock()
|
||||
return err
|
||||
}
|
||||
container.Unlock()
|
||||
defer container.Unlock()
|
||||
return parseSecurityOpt(container, hostConfig)
|
||||
}
|
||||
|
||||
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
|
||||
// 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 {
|
||||
|
|
|
@ -130,7 +130,7 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemo
|
|||
return derr.ErrorCodeRmFS.WithArgs(container.ID, err)
|
||||
}
|
||||
|
||||
metadata, err := daemon.layerStore.DeleteMount(container.ID)
|
||||
metadata, err := daemon.layerStore.ReleaseRWLayer(container.RWLayer)
|
||||
layer.LogReleaseMetadata(metadata)
|
||||
if err != nil && err != layer.ErrMountDoesNotExist {
|
||||
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
|
||||
|
||||
graphDriverData, err := daemon.layerStore.Metadata(container.ID)
|
||||
graphDriverData, err := container.RWLayer.Metadata()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -31,6 +31,9 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.Hos
|
|||
// creating a container, not during start.
|
||||
if hostConfig != nil {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import (
|
|||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"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) {
|
||||
return []layer.Metadata{}, nil
|
||||
}
|
||||
|
||||
func (ls *mockLayerStore) Mount(id string, parent layer.ChainID, label string, init layer.MountInit) (layer.RWLayer, error) {
|
||||
func (ls *mockLayerStore) CreateRWLayer(string, layer.ChainID, string, layer.MountInit) (layer.RWLayer, error) {
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (ls *mockLayerStore) Unmount(id string) error {
|
||||
return errors.New("not implemented")
|
||||
func (ls *mockLayerStore) GetRWLayer(string) (layer.RWLayer, error) {
|
||||
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")
|
||||
}
|
||||
|
||||
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 {
|
||||
|
|
|
@ -31,6 +31,11 @@ var (
|
|||
// attempted on a mount layer which 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
|
||||
// mount is attempted but the layer is still
|
||||
// mounted and the operation cannot be performed.
|
||||
|
@ -103,18 +108,33 @@ type Layer interface {
|
|||
type RWLayer interface {
|
||||
TarStreamer
|
||||
|
||||
// Path returns the filesystem path to the writable
|
||||
// layer.
|
||||
Path() (string, error)
|
||||
// Name of mounted layer
|
||||
Name() string
|
||||
|
||||
// Parent returns the layer which the writable
|
||||
// layer was created from.
|
||||
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
|
||||
// as calculated by the total size of the files
|
||||
// changed in the mutable layer.
|
||||
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
|
||||
|
@ -147,11 +167,9 @@ type Store interface {
|
|||
Get(ChainID) (Layer, error)
|
||||
Release(Layer) ([]Metadata, error)
|
||||
|
||||
Mount(id string, parent ChainID, label string, init MountInit) (RWLayer, error)
|
||||
Unmount(id string) error
|
||||
DeleteMount(id string) ([]Metadata, error)
|
||||
Changes(id string) ([]archive.Change, error)
|
||||
Metadata(id string) (map[string]string, error)
|
||||
CreateRWLayer(id string, parent ChainID, mountLabel string, initFunc MountInit) (RWLayer, error)
|
||||
GetRWLayer(id string) (RWLayer, error)
|
||||
ReleaseRWLayer(RWLayer) ([]Metadata, error)
|
||||
}
|
||||
|
||||
// MetadataTransaction represents functions for setting layer metadata
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
|
@ -144,6 +143,7 @@ func (ls *layerStore) loadMount(mount string) error {
|
|||
mountID: mountID,
|
||||
initID: initID,
|
||||
layerStore: ls,
|
||||
references: map[RWLayer]*referencedRWLayer{},
|
||||
}
|
||||
|
||||
if parent != "" {
|
||||
|
@ -382,15 +382,114 @@ func (ls *layerStore) Release(l Layer) ([]Metadata, error) {
|
|||
return ls.releaseLayer(layer)
|
||||
}
|
||||
|
||||
func (ls *layerStore) mount(m *mountedLayer, mountLabel string) error {
|
||||
dir, err := ls.driver.Get(m.mountID, mountLabel)
|
||||
if err != nil {
|
||||
return err
|
||||
func (ls *layerStore) CreateRWLayer(name string, parent ChainID, mountLabel string, initFunc MountInit) (RWLayer, error) {
|
||||
ls.mountL.Lock()
|
||||
defer ls.mountL.Unlock()
|
||||
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 {
|
||||
|
@ -442,145 +541,6 @@ func (ls *layerStore) initMount(graphID, parent, mountLabel string, initFunc Mou
|
|||
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) {
|
||||
type diffPathDriver interface {
|
||||
DiffPath(string) (string, func() error, error)
|
||||
|
@ -621,17 +581,6 @@ func (ls *layerStore) assembleTar(graphID string, metadata io.ReadCloser, size *
|
|||
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 {
|
||||
graphdriver.Driver
|
||||
}
|
||||
|
|
|
@ -82,12 +82,12 @@ type layerInit func(root string) error
|
|||
|
||||
func createLayer(ls Store, parent ChainID, layerFunc layerInit) (Layer, error) {
|
||||
containerID := stringid.GenerateRandomID()
|
||||
mount, err := ls.Mount(containerID, parent, "", nil)
|
||||
mount, err := ls.CreateRWLayer(containerID, parent, "", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
path, err := mount.Path()
|
||||
path, err := mount.Mount("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -107,11 +107,11 @@ func createLayer(ls Store, parent ChainID, layerFunc layerInit) (Layer, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err := ls.Unmount(containerID); err != nil {
|
||||
if err := mount.Unmount(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := ls.DeleteMount(containerID); err != nil {
|
||||
if _, err := ls.ReleaseRWLayer(mount); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -171,6 +171,13 @@ func getCachedLayer(l Layer) *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 {
|
||||
metadata := make([]Metadata, len(layers))
|
||||
for i := range layers {
|
||||
|
@ -270,12 +277,12 @@ func TestMountAndRegister(t *testing.T) {
|
|||
size, _ := layer.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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
path2, err := mount2.Path()
|
||||
path2, err := mount2.Mount("")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -289,11 +296,11 @@ func TestMountAndRegister(t *testing.T) {
|
|||
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)
|
||||
}
|
||||
|
||||
if _, err := ls.DeleteMount("new-test-mount"); err != nil {
|
||||
if _, err := ls.ReleaseRWLayer(mount2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -370,12 +377,12 @@ func TestStoreRestore(t *testing.T) {
|
|||
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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
path, err := m.Path()
|
||||
path, err := m.Mount("")
|
||||
if err != nil {
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
|
||||
assertActivityCount(t, m, 0)
|
||||
|
||||
ls2, err := NewStore(ls.(*layerStore).store, ls.(*layerStore).driver)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -400,18 +410,39 @@ func TestStoreRestore(t *testing.T) {
|
|||
|
||||
assertLayerEqual(t, layer3b, layer3)
|
||||
|
||||
// Mount again with same name, should already be loaded
|
||||
m2, err := ls2.Mount("some-mount_name", layer3b.ChainID(), "", nil)
|
||||
// Create again with same name, should return error
|
||||
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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
path2, err := m2.Path()
|
||||
if err != nil {
|
||||
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, 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)
|
||||
}
|
||||
|
||||
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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -419,11 +450,19 @@ func TestStoreRestore(t *testing.T) {
|
|||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
} else if len(metadata) != 0 {
|
||||
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) {
|
||||
ls, cleanup := newTestStore(t)
|
||||
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
|
||||
}
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
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()
|
||||
defer ls.mountL.Unlock()
|
||||
m, ok := ls.mounts[name]
|
||||
if ok {
|
||||
if m.parent.chainID != parent {
|
||||
return nil, errors.New("name conflict, mismatched parent")
|
||||
return errors.New("name conflict, mismatched parent")
|
||||
}
|
||||
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) {
|
||||
return nil, errors.New("graph ID does not exist")
|
||||
return errors.New("graph ID does not exist")
|
||||
}
|
||||
|
||||
var p *roLayer
|
||||
if string(parent) != "" {
|
||||
p = ls.get(parent)
|
||||
if p == nil {
|
||||
return nil, ErrLayerDoesNotExist
|
||||
return ErrLayerDoesNotExist
|
||||
}
|
||||
|
||||
// Release parent chain if error
|
||||
|
@ -57,6 +60,7 @@ func (ls *layerStore) MountByGraphID(name string, graphID string, parent ChainID
|
|||
parent: p,
|
||||
mountID: graphID,
|
||||
layerStore: ls,
|
||||
references: map[RWLayer]*referencedRWLayer{},
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: provide a mount label
|
||||
if err = ls.mount(m, ""); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return m, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ls *layerStore) migrateLayer(tx MetadataTransaction, tarDataFile string, layer *roLayer) error {
|
||||
|
|
|
@ -303,12 +303,20 @@ func TestMountMigration(t *testing.T) {
|
|||
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 {
|
||||
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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -341,39 +349,63 @@ func TestMountMigration(t *testing.T) {
|
|||
Kind: archive.ChangeAdd,
|
||||
})
|
||||
|
||||
if expectedCount := 1; rwLayer1.(*mountedLayer).activityCount != expectedCount {
|
||||
t.Fatalf("Wrong activity count %d, expected %d", rwLayer1.(*mountedLayer).activityCount, expectedCount)
|
||||
assertActivityCount(t, rwLayer1, 1)
|
||||
|
||||
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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if rwLayer1 != rwLayer2 {
|
||||
t.Fatalf("Wrong rwlayer %v, expected %v", rwLayer2, rwLayer1)
|
||||
if getMountLayer(rwLayer1) != getMountLayer(rwLayer2) {
|
||||
t.Fatal("Expected same layer from get with same name as from migrate")
|
||||
}
|
||||
|
||||
if expectedCount := 2; rwLayer2.(*mountedLayer).activityCount != expectedCount {
|
||||
t.Fatalf("Wrong activity count %d, expected %d", rwLayer2.(*mountedLayer).activityCount, expectedCount)
|
||||
if _, err := rwLayer2.Mount(""); err != nil {
|
||||
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 {
|
||||
t.Fatal(err)
|
||||
} else if len(metadata) > 0 {
|
||||
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)
|
||||
}
|
||||
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")
|
||||
}
|
||||
if err := ls.Unmount("migration-mount"); err != nil {
|
||||
if err := rwLayer2.Unmount(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
metadata, err := ls.DeleteMount("migration-mount")
|
||||
metadata, err := ls.ReleaseRWLayer(rwLayer2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -27,12 +27,12 @@ func TestMountInit(t *testing.T) {
|
|||
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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
path, err := m.Path()
|
||||
path, err := m.Mount("")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -80,12 +80,12 @@ func TestMountSize(t *testing.T) {
|
|||
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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
path, err := m.Path()
|
||||
path, err := m.Mount("")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -125,12 +125,12 @@ func TestMountChanges(t *testing.T) {
|
|||
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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
path, err := m.Path()
|
||||
path, err := m.Mount("")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ func TestMountChanges(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
changes, err := ls.Changes("mount-changes")
|
||||
changes, err := m.Changes()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -1,15 +1,20 @@
|
|||
package layer
|
||||
|
||||
import "io"
|
||||
import (
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
)
|
||||
|
||||
type mountedLayer struct {
|
||||
name string
|
||||
mountID string
|
||||
initID string
|
||||
parent *roLayer
|
||||
path string
|
||||
layerStore *layerStore
|
||||
activityCount int
|
||||
name string
|
||||
mountID string
|
||||
initID string
|
||||
parent *roLayer
|
||||
layerStore *layerStore
|
||||
|
||||
references map[RWLayer]*referencedRWLayer
|
||||
}
|
||||
|
||||
func (ml *mountedLayer) cacheParent() string {
|
||||
|
@ -30,11 +35,8 @@ func (ml *mountedLayer) TarStream() (io.ReadCloser, error) {
|
|||
return archiver, nil
|
||||
}
|
||||
|
||||
func (ml *mountedLayer) Path() (string, error) {
|
||||
if ml.path == "" {
|
||||
return "", ErrNotMounted
|
||||
}
|
||||
return ml.path, nil
|
||||
func (ml *mountedLayer) Name() string {
|
||||
return ml.name
|
||||
}
|
||||
|
||||
func (ml *mountedLayer) Parent() Layer {
|
||||
|
@ -47,6 +49,96 @@ func (ml *mountedLayer) Parent() Layer {
|
|||
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) {
|
||||
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 {
|
||||
MountByGraphID(string, string, layer.ChainID) (layer.RWLayer, error)
|
||||
Unmount(string) error
|
||||
CreateRWLayerByGraphID(string, string, layer.ChainID) error
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -172,13 +171,7 @@ func migrateContainers(root string, ls graphIDMounter, is image.Store, imageMapp
|
|||
return err
|
||||
}
|
||||
|
||||
_, err = ls.MountByGraphID(id, id, img.RootFS.ChainID())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = ls.Unmount(id)
|
||||
if err != nil {
|
||||
if err := ls.CreateRWLayerByGraphID(id, id, img.RootFS.ChainID()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -338,10 +338,9 @@ type mockMounter struct {
|
|||
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.count++
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
func (r *mockMounter) Unmount(string) error {
|
||||
r.count--
|
||||
|
|
Загрузка…
Ссылка в новой задаче