Merge pull request #18834 from dmcgowan/layerstore-refactor-rw-layer

Layerstore refactor rw layer
This commit is contained in:
Brian Goff 2015-12-24 08:02:15 -05:00
Родитель 824a865e41 54f8ba7e9e
Коммит d08ac6e256
19 изменённых файлов: 460 добавлений и 302 удалений

Просмотреть файл

@ -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()

9
layer/layer_unix.go Normal file
Просмотреть файл

@ -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--