RWLayer will now have more operations and be protected through a referenced type rather than always looked up by string in the layer store.
Separates creation of RWLayer (write capture layer) from mounting of the layer.
This allows mount labels to be applied after creation and allowing RWLayer objects to have the same lifespan as a container without performance regressions from requiring mount.
Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
| ... | ... |
@@ -145,7 +145,7 @@ func (daemon *Daemon) exportContainerRw(container *container.Container) (archive |
| 145 | 145 |
} |
| 146 | 146 |
return ioutils.NewReadCloserWrapper(archive, func() error {
|
| 147 | 147 |
archive.Close() |
| 148 |
- return daemon.layerStore.Unmount(container.ID) |
|
| 148 |
+ return container.RWLayer.Unmount() |
|
| 149 | 149 |
}), |
| 150 | 150 |
nil |
| 151 | 151 |
} |
| ... | ... |
@@ -98,7 +98,7 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro |
| 98 | 98 |
} |
| 99 | 99 |
} |
| 100 | 100 |
|
| 101 |
- m, err := daemon.layerStore.Metadata(c.ID) |
|
| 101 |
+ m, err := c.RWLayer.Metadata() |
|
| 102 | 102 |
if err != nil {
|
| 103 | 103 |
return derr.ErrorCodeGetLayerMetadata.WithArgs(err) |
| 104 | 104 |
} |
| ... | ... |
@@ -7,6 +7,7 @@ import ( |
| 7 | 7 |
"github.com/docker/docker/container" |
| 8 | 8 |
derr "github.com/docker/docker/errors" |
| 9 | 9 |
"github.com/docker/docker/image" |
| 10 |
+ "github.com/docker/docker/layer" |
|
| 10 | 11 |
"github.com/docker/docker/pkg/idtools" |
| 11 | 12 |
"github.com/docker/docker/pkg/stringid" |
| 12 | 13 |
"github.com/docker/docker/volume" |
| ... | ... |
@@ -95,6 +96,11 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig) (*container.Con |
| 95 | 95 |
} |
| 96 | 96 |
}() |
| 97 | 97 |
|
| 98 |
+ // Set RWLayer for container after mount labels have been set |
|
| 99 |
+ if err := daemon.setRWLayer(container); err != nil {
|
|
| 100 |
+ return nil, err |
|
| 101 |
+ } |
|
| 102 |
+ |
|
| 98 | 103 |
if err := daemon.createContainerPlatformSpecificSettings(container, params.Config, params.HostConfig, img); err != nil {
|
| 99 | 104 |
return nil, err |
| 100 | 105 |
} |
| ... | ... |
@@ -126,6 +132,24 @@ func (daemon *Daemon) generateSecurityOpt(ipcMode containertypes.IpcMode, pidMod |
| 126 | 126 |
return nil, nil |
| 127 | 127 |
} |
| 128 | 128 |
|
| 129 |
+func (daemon *Daemon) setRWLayer(container *container.Container) error {
|
|
| 130 |
+ var layerID layer.ChainID |
|
| 131 |
+ if container.ImageID != "" {
|
|
| 132 |
+ img, err := daemon.imageStore.Get(container.ImageID) |
|
| 133 |
+ if err != nil {
|
|
| 134 |
+ return err |
|
| 135 |
+ } |
|
| 136 |
+ layerID = img.RootFS.ChainID() |
|
| 137 |
+ } |
|
| 138 |
+ rwLayer, err := daemon.layerStore.CreateRWLayer(container.ID, layerID, container.MountLabel, daemon.setupInitLayer) |
|
| 139 |
+ if err != nil {
|
|
| 140 |
+ return err |
|
| 141 |
+ } |
|
| 142 |
+ container.RWLayer = rwLayer |
|
| 143 |
+ |
|
| 144 |
+ return nil |
|
| 145 |
+} |
|
| 146 |
+ |
|
| 129 | 147 |
// VolumeCreate creates a volume with the specified name, driver, and opts |
| 130 | 148 |
// This is called directly from the remote API |
| 131 | 149 |
func (daemon *Daemon) VolumeCreate(name, driverName string, opts map[string]string) (*types.Volume, error) {
|
| ... | ... |
@@ -323,6 +323,13 @@ func (daemon *Daemon) restore() error {
|
| 323 | 323 |
continue |
| 324 | 324 |
} |
| 325 | 325 |
|
| 326 |
+ rwlayer, err := daemon.layerStore.GetRWLayer(container.ID) |
|
| 327 |
+ if err != nil {
|
|
| 328 |
+ logrus.Errorf("Failed to load container mount %v: %v", id, err)
|
|
| 329 |
+ continue |
|
| 330 |
+ } |
|
| 331 |
+ container.RWLayer = rwlayer |
|
| 332 |
+ |
|
| 326 | 333 |
// Ignore the container if it does not support the current driver being used by the graph |
| 327 | 334 |
if (container.Driver == "" && currentDriver == "aufs") || container.Driver == currentDriver {
|
| 328 | 335 |
logrus.Debugf("Loaded container %v", container.ID)
|
| ... | ... |
@@ -961,19 +968,7 @@ func (daemon *Daemon) Shutdown() error {
|
| 961 | 961 |
// Mount sets container.BaseFS |
| 962 | 962 |
// (is it not set coming in? why is it unset?) |
| 963 | 963 |
func (daemon *Daemon) Mount(container *container.Container) error {
|
| 964 |
- var layerID layer.ChainID |
|
| 965 |
- if container.ImageID != "" {
|
|
| 966 |
- img, err := daemon.imageStore.Get(container.ImageID) |
|
| 967 |
- if err != nil {
|
|
| 968 |
- return err |
|
| 969 |
- } |
|
| 970 |
- layerID = img.RootFS.ChainID() |
|
| 971 |
- } |
|
| 972 |
- rwlayer, err := daemon.layerStore.Mount(container.ID, layerID, container.GetMountLabel(), daemon.setupInitLayer) |
|
| 973 |
- if err != nil {
|
|
| 974 |
- return err |
|
| 975 |
- } |
|
| 976 |
- dir, err := rwlayer.Path() |
|
| 964 |
+ dir, err := container.RWLayer.Mount(container.GetMountLabel()) |
|
| 977 | 965 |
if err != nil {
|
| 978 | 966 |
return err |
| 979 | 967 |
} |
| ... | ... |
@@ -990,13 +985,12 @@ func (daemon *Daemon) Mount(container *container.Container) error {
|
| 990 | 990 |
} |
| 991 | 991 |
} |
| 992 | 992 |
container.BaseFS = dir // TODO: combine these fields |
| 993 |
- container.RWLayer = rwlayer |
|
| 994 | 993 |
return nil |
| 995 | 994 |
} |
| 996 | 995 |
|
| 997 | 996 |
// Unmount unsets the container base filesystem |
| 998 | 997 |
func (daemon *Daemon) Unmount(container *container.Container) {
|
| 999 |
- if err := daemon.layerStore.Unmount(container.ID); err != nil {
|
|
| 998 |
+ if err := container.RWLayer.Unmount(); err != nil {
|
|
| 1000 | 999 |
logrus.Errorf("Error unmounting container %s: %s", container.ID, err)
|
| 1001 | 1000 |
} |
| 1002 | 1001 |
} |
| ... | ... |
@@ -1029,7 +1023,7 @@ func (daemon *Daemon) unsubscribeToContainerStats(c *container.Container, ch cha |
| 1029 | 1029 |
} |
| 1030 | 1030 |
|
| 1031 | 1031 |
func (daemon *Daemon) changes(container *container.Container) ([]archive.Change, error) {
|
| 1032 |
- return daemon.layerStore.Changes(container.ID) |
|
| 1032 |
+ return container.RWLayer.Changes() |
|
| 1033 | 1033 |
} |
| 1034 | 1034 |
|
| 1035 | 1035 |
// TagImage creates a tag in the repository reponame, pointing to the image named |
| ... | ... |
@@ -130,7 +130,7 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemo |
| 130 | 130 |
return derr.ErrorCodeRmFS.WithArgs(container.ID, err) |
| 131 | 131 |
} |
| 132 | 132 |
|
| 133 |
- metadata, err := daemon.layerStore.DeleteMount(container.ID) |
|
| 133 |
+ metadata, err := daemon.layerStore.ReleaseRWLayer(container.RWLayer) |
|
| 134 | 134 |
layer.LogReleaseMetadata(metadata) |
| 135 | 135 |
if err != nil && err != layer.ErrMountDoesNotExist {
|
| 136 | 136 |
return derr.ErrorCodeRmDriverFS.WithArgs(daemon.driver, container.ID, err) |
| ... | ... |
@@ -163,7 +163,7 @@ func (daemon *Daemon) getInspectData(container *container.Container, size bool) |
| 163 | 163 |
|
| 164 | 164 |
contJSONBase.GraphDriver.Name = container.Driver |
| 165 | 165 |
|
| 166 |
- graphDriverData, err := daemon.layerStore.Metadata(container.ID) |
|
| 166 |
+ graphDriverData, err := container.RWLayer.Metadata() |
|
| 167 | 167 |
if err != nil {
|
| 168 | 168 |
return nil, err |
| 169 | 169 |
} |
| ... | ... |
@@ -12,7 +12,6 @@ import ( |
| 12 | 12 |
"github.com/docker/distribution/digest" |
| 13 | 13 |
"github.com/docker/docker/image" |
| 14 | 14 |
"github.com/docker/docker/layer" |
| 15 |
- "github.com/docker/docker/pkg/archive" |
|
| 16 | 15 |
"github.com/docker/docker/pkg/progress" |
| 17 | 16 |
"golang.org/x/net/context" |
| 18 | 17 |
) |
| ... | ... |
@@ -115,25 +114,18 @@ func (ls *mockLayerStore) Get(chainID layer.ChainID) (layer.Layer, error) {
|
| 115 | 115 |
func (ls *mockLayerStore) Release(l layer.Layer) ([]layer.Metadata, error) {
|
| 116 | 116 |
return []layer.Metadata{}, nil
|
| 117 | 117 |
} |
| 118 |
- |
|
| 119 |
-func (ls *mockLayerStore) Mount(id string, parent layer.ChainID, label string, init layer.MountInit) (layer.RWLayer, error) {
|
|
| 118 |
+func (ls *mockLayerStore) CreateRWLayer(string, layer.ChainID, string, layer.MountInit) (layer.RWLayer, error) {
|
|
| 120 | 119 |
return nil, errors.New("not implemented")
|
| 121 | 120 |
} |
| 122 | 121 |
|
| 123 |
-func (ls *mockLayerStore) Unmount(id string) error {
|
|
| 124 |
- return errors.New("not implemented")
|
|
| 125 |
-} |
|
| 126 |
- |
|
| 127 |
-func (ls *mockLayerStore) DeleteMount(id string) ([]layer.Metadata, error) {
|
|
| 122 |
+func (ls *mockLayerStore) GetRWLayer(string) (layer.RWLayer, error) {
|
|
| 128 | 123 |
return nil, errors.New("not implemented")
|
| 129 |
-} |
|
| 130 | 124 |
|
| 131 |
-func (ls *mockLayerStore) Changes(id string) ([]archive.Change, error) {
|
|
| 132 |
- return nil, errors.New("not implemented")
|
|
| 133 | 125 |
} |
| 134 | 126 |
|
| 135 |
-func (ls *mockLayerStore) Metadata(id string) (map[string]string, error) {
|
|
| 127 |
+func (ls *mockLayerStore) ReleaseRWLayer(layer.RWLayer) ([]layer.Metadata, error) {
|
|
| 136 | 128 |
return nil, errors.New("not implemented")
|
| 129 |
+ |
|
| 137 | 130 |
} |
| 138 | 131 |
|
| 139 | 132 |
type mockDownloadDescriptor struct {
|
| ... | ... |
@@ -31,6 +31,11 @@ var ( |
| 31 | 31 |
// attempted on a mount layer which does not exist. |
| 32 | 32 |
ErrMountDoesNotExist = errors.New("mount does not exist")
|
| 33 | 33 |
|
| 34 |
+ // ErrMountNameConflict is used when a mount is attempted |
|
| 35 |
+ // to be created but there is already a mount with the name |
|
| 36 |
+ // used for creation. |
|
| 37 |
+ ErrMountNameConflict = errors.New("mount already exists with name")
|
|
| 38 |
+ |
|
| 34 | 39 |
// ErrActiveMount is used when an operation on a |
| 35 | 40 |
// mount is attempted but the layer is still |
| 36 | 41 |
// mounted and the operation cannot be performed. |
| ... | ... |
@@ -103,18 +108,33 @@ type Layer interface {
|
| 103 | 103 |
type RWLayer interface {
|
| 104 | 104 |
TarStreamer |
| 105 | 105 |
|
| 106 |
- // Path returns the filesystem path to the writable |
|
| 107 |
- // layer. |
|
| 108 |
- Path() (string, error) |
|
| 106 |
+ // Name of mounted layer |
|
| 107 |
+ Name() string |
|
| 109 | 108 |
|
| 110 | 109 |
// Parent returns the layer which the writable |
| 111 | 110 |
// layer was created from. |
| 112 | 111 |
Parent() Layer |
| 113 | 112 |
|
| 113 |
+ // Mount mounts the RWLayer and returns the filesystem path |
|
| 114 |
+ // the to the writable layer. |
|
| 115 |
+ Mount(mountLabel string) (string, error) |
|
| 116 |
+ |
|
| 117 |
+ // Unmount unmounts the RWLayer. This should be called |
|
| 118 |
+ // for every mount. If there are multiple mount calls |
|
| 119 |
+ // this operation will only decrement the internal mount counter. |
|
| 120 |
+ Unmount() error |
|
| 121 |
+ |
|
| 114 | 122 |
// Size represents the size of the writable layer |
| 115 | 123 |
// as calculated by the total size of the files |
| 116 | 124 |
// changed in the mutable layer. |
| 117 | 125 |
Size() (int64, error) |
| 126 |
+ |
|
| 127 |
+ // Changes returns the set of changes for the mutable layer |
|
| 128 |
+ // from the base layer. |
|
| 129 |
+ Changes() ([]archive.Change, error) |
|
| 130 |
+ |
|
| 131 |
+ // Metadata returns the low level metadata for the mutable layer |
|
| 132 |
+ Metadata() (map[string]string, error) |
|
| 118 | 133 |
} |
| 119 | 134 |
|
| 120 | 135 |
// Metadata holds information about a |
| ... | ... |
@@ -147,11 +167,9 @@ type Store interface {
|
| 147 | 147 |
Get(ChainID) (Layer, error) |
| 148 | 148 |
Release(Layer) ([]Metadata, error) |
| 149 | 149 |
|
| 150 |
- Mount(id string, parent ChainID, label string, init MountInit) (RWLayer, error) |
|
| 151 |
- Unmount(id string) error |
|
| 152 |
- DeleteMount(id string) ([]Metadata, error) |
|
| 153 |
- Changes(id string) ([]archive.Change, error) |
|
| 154 |
- Metadata(id string) (map[string]string, error) |
|
| 150 |
+ CreateRWLayer(id string, parent ChainID, mountLabel string, initFunc MountInit) (RWLayer, error) |
|
| 151 |
+ GetRWLayer(id string) (RWLayer, error) |
|
| 152 |
+ ReleaseRWLayer(RWLayer) ([]Metadata, error) |
|
| 155 | 153 |
} |
| 156 | 154 |
|
| 157 | 155 |
// MetadataTransaction represents functions for setting layer metadata |
| ... | ... |
@@ -5,7 +5,6 @@ import ( |
| 5 | 5 |
"fmt" |
| 6 | 6 |
"io" |
| 7 | 7 |
"io/ioutil" |
| 8 |
- "runtime" |
|
| 9 | 8 |
"sync" |
| 10 | 9 |
|
| 11 | 10 |
"github.com/Sirupsen/logrus" |
| ... | ... |
@@ -144,6 +143,7 @@ func (ls *layerStore) loadMount(mount string) error {
|
| 144 | 144 |
mountID: mountID, |
| 145 | 145 |
initID: initID, |
| 146 | 146 |
layerStore: ls, |
| 147 |
+ references: map[RWLayer]*referencedRWLayer{},
|
|
| 147 | 148 |
} |
| 148 | 149 |
|
| 149 | 150 |
if parent != "" {
|
| ... | ... |
@@ -382,78 +382,15 @@ func (ls *layerStore) Release(l Layer) ([]Metadata, error) {
|
| 382 | 382 |
return ls.releaseLayer(layer) |
| 383 | 383 |
} |
| 384 | 384 |
|
| 385 |
-func (ls *layerStore) mount(m *mountedLayer, mountLabel string) error {
|
|
| 386 |
- dir, err := ls.driver.Get(m.mountID, mountLabel) |
|
| 387 |
- if err != nil {
|
|
| 388 |
- return err |
|
| 389 |
- } |
|
| 390 |
- m.path = dir |
|
| 391 |
- m.activityCount++ |
|
| 392 |
- |
|
| 393 |
- return nil |
|
| 394 |
-} |
|
| 395 |
- |
|
| 396 |
-func (ls *layerStore) saveMount(mount *mountedLayer) error {
|
|
| 397 |
- if err := ls.store.SetMountID(mount.name, mount.mountID); err != nil {
|
|
| 398 |
- return err |
|
| 399 |
- } |
|
| 400 |
- |
|
| 401 |
- if mount.initID != "" {
|
|
| 402 |
- if err := ls.store.SetInitID(mount.name, mount.initID); err != nil {
|
|
| 403 |
- return err |
|
| 404 |
- } |
|
| 405 |
- } |
|
| 406 |
- |
|
| 407 |
- if mount.parent != nil {
|
|
| 408 |
- if err := ls.store.SetMountParent(mount.name, mount.parent.chainID); err != nil {
|
|
| 409 |
- return err |
|
| 410 |
- } |
|
| 411 |
- } |
|
| 412 |
- |
|
| 413 |
- ls.mounts[mount.name] = mount |
|
| 414 |
- |
|
| 415 |
- return nil |
|
| 416 |
-} |
|
| 417 |
- |
|
| 418 |
-func (ls *layerStore) initMount(graphID, parent, mountLabel string, initFunc MountInit) (string, error) {
|
|
| 419 |
- // Use "<graph-id>-init" to maintain compatibility with graph drivers |
|
| 420 |
- // which are expecting this layer with this special name. If all |
|
| 421 |
- // graph drivers can be updated to not rely on knowing about this layer |
|
| 422 |
- // then the initID should be randomly generated. |
|
| 423 |
- initID := fmt.Sprintf("%s-init", graphID)
|
|
| 424 |
- |
|
| 425 |
- if err := ls.driver.Create(initID, parent, mountLabel); err != nil {
|
|
| 426 |
- return "", err |
|
| 427 |
- } |
|
| 428 |
- p, err := ls.driver.Get(initID, "") |
|
| 429 |
- if err != nil {
|
|
| 430 |
- return "", err |
|
| 431 |
- } |
|
| 432 |
- |
|
| 433 |
- if err := initFunc(p); err != nil {
|
|
| 434 |
- ls.driver.Put(initID) |
|
| 435 |
- return "", err |
|
| 436 |
- } |
|
| 437 |
- |
|
| 438 |
- if err := ls.driver.Put(initID); err != nil {
|
|
| 439 |
- return "", err |
|
| 440 |
- } |
|
| 441 |
- |
|
| 442 |
- return initID, nil |
|
| 443 |
-} |
|
| 444 |
- |
|
| 445 |
-func (ls *layerStore) Mount(name string, parent ChainID, mountLabel string, initFunc MountInit) (l RWLayer, err error) {
|
|
| 385 |
+func (ls *layerStore) CreateRWLayer(name string, parent ChainID, mountLabel string, initFunc MountInit) (RWLayer, error) {
|
|
| 446 | 386 |
ls.mountL.Lock() |
| 447 | 387 |
defer ls.mountL.Unlock() |
| 448 | 388 |
m, ok := ls.mounts[name] |
| 449 | 389 |
if ok {
|
| 450 |
- // Check if has path |
|
| 451 |
- if err := ls.mount(m, mountLabel); err != nil {
|
|
| 452 |
- return nil, err |
|
| 453 |
- } |
|
| 454 |
- return m, nil |
|
| 390 |
+ return nil, ErrMountNameConflict |
|
| 455 | 391 |
} |
| 456 | 392 |
|
| 393 |
+ var err error |
|
| 457 | 394 |
var pid string |
| 458 | 395 |
var p *roLayer |
| 459 | 396 |
if string(parent) != "" {
|
| ... | ... |
@@ -473,17 +410,12 @@ func (ls *layerStore) Mount(name string, parent ChainID, mountLabel string, init |
| 473 | 473 |
}() |
| 474 | 474 |
} |
| 475 | 475 |
|
| 476 |
- mountID := name |
|
| 477 |
- if runtime.GOOS != "windows" {
|
|
| 478 |
- // windows has issues if container ID doesn't match mount ID |
|
| 479 |
- mountID = stringid.GenerateRandomID() |
|
| 480 |
- } |
|
| 481 |
- |
|
| 482 | 476 |
m = &mountedLayer{
|
| 483 | 477 |
name: name, |
| 484 | 478 |
parent: p, |
| 485 |
- mountID: mountID, |
|
| 479 |
+ mountID: ls.mountID(name), |
|
| 486 | 480 |
layerStore: ls, |
| 481 |
+ references: map[RWLayer]*referencedRWLayer{},
|
|
| 487 | 482 |
} |
| 488 | 483 |
|
| 489 | 484 |
if initFunc != nil {
|
| ... | ... |
@@ -502,44 +434,35 @@ func (ls *layerStore) Mount(name string, parent ChainID, mountLabel string, init |
| 502 | 502 |
return nil, err |
| 503 | 503 |
} |
| 504 | 504 |
|
| 505 |
- if err = ls.mount(m, mountLabel); err != nil {
|
|
| 506 |
- return nil, err |
|
| 507 |
- } |
|
| 508 |
- |
|
| 509 |
- return m, nil |
|
| 505 |
+ return m.getReference(), nil |
|
| 510 | 506 |
} |
| 511 | 507 |
|
| 512 |
-func (ls *layerStore) Unmount(name string) error {
|
|
| 508 |
+func (ls *layerStore) GetRWLayer(id string) (RWLayer, error) {
|
|
| 513 | 509 |
ls.mountL.Lock() |
| 514 | 510 |
defer ls.mountL.Unlock() |
| 515 |
- |
|
| 516 |
- m := ls.mounts[name] |
|
| 517 |
- if m == nil {
|
|
| 518 |
- return ErrMountDoesNotExist |
|
| 519 |
- } |
|
| 520 |
- |
|
| 521 |
- m.activityCount-- |
|
| 522 |
- |
|
| 523 |
- if err := ls.driver.Put(m.mountID); err != nil {
|
|
| 524 |
- return err |
|
| 511 |
+ mount, ok := ls.mounts[id] |
|
| 512 |
+ if !ok {
|
|
| 513 |
+ return nil, ErrMountDoesNotExist |
|
| 525 | 514 |
} |
| 526 | 515 |
|
| 527 |
- return nil |
|
| 516 |
+ return mount.getReference(), nil |
|
| 528 | 517 |
} |
| 529 | 518 |
|
| 530 |
-func (ls *layerStore) DeleteMount(name string) ([]Metadata, error) {
|
|
| 519 |
+func (ls *layerStore) ReleaseRWLayer(l RWLayer) ([]Metadata, error) {
|
|
| 531 | 520 |
ls.mountL.Lock() |
| 532 | 521 |
defer ls.mountL.Unlock() |
| 533 |
- |
|
| 534 |
- m := ls.mounts[name] |
|
| 535 |
- if m == nil {
|
|
| 536 |
- return nil, ErrMountDoesNotExist |
|
| 522 |
+ m, ok := ls.mounts[l.Name()] |
|
| 523 |
+ if !ok {
|
|
| 524 |
+ return []Metadata{}, nil
|
|
| 537 | 525 |
} |
| 538 |
- if m.activityCount > 0 {
|
|
| 539 |
- return nil, ErrActiveMount |
|
| 526 |
+ |
|
| 527 |
+ if err := m.deleteReference(l); err != nil {
|
|
| 528 |
+ return nil, err |
|
| 540 | 529 |
} |
| 541 | 530 |
|
| 542 |
- delete(ls.mounts, name) |
|
| 531 |
+ if m.hasReferences() {
|
|
| 532 |
+ return []Metadata{}, nil
|
|
| 533 |
+ } |
|
| 543 | 534 |
|
| 544 | 535 |
if err := ls.driver.Remove(m.mountID); err != nil {
|
| 545 | 536 |
logrus.Errorf("Error removing mounted layer %s: %s", m.name, err)
|
| ... | ... |
@@ -558,6 +481,8 @@ func (ls *layerStore) DeleteMount(name string) ([]Metadata, error) {
|
| 558 | 558 |
return nil, err |
| 559 | 559 |
} |
| 560 | 560 |
|
| 561 |
+ delete(ls.mounts, m.Name()) |
|
| 562 |
+ |
|
| 561 | 563 |
ls.layerL.Lock() |
| 562 | 564 |
defer ls.layerL.Unlock() |
| 563 | 565 |
if m.parent != nil {
|
| ... | ... |
@@ -567,18 +492,53 @@ func (ls *layerStore) DeleteMount(name string) ([]Metadata, error) {
|
| 567 | 567 |
return []Metadata{}, nil
|
| 568 | 568 |
} |
| 569 | 569 |
|
| 570 |
-func (ls *layerStore) Changes(name string) ([]archive.Change, error) {
|
|
| 571 |
- ls.mountL.Lock() |
|
| 572 |
- m := ls.mounts[name] |
|
| 573 |
- ls.mountL.Unlock() |
|
| 574 |
- if m == nil {
|
|
| 575 |
- return nil, ErrMountDoesNotExist |
|
| 570 |
+func (ls *layerStore) saveMount(mount *mountedLayer) error {
|
|
| 571 |
+ if err := ls.store.SetMountID(mount.name, mount.mountID); err != nil {
|
|
| 572 |
+ return err |
|
| 576 | 573 |
} |
| 577 |
- pid := m.initID |
|
| 578 |
- if pid == "" && m.parent != nil {
|
|
| 579 |
- pid = m.parent.cacheID |
|
| 574 |
+ |
|
| 575 |
+ if mount.initID != "" {
|
|
| 576 |
+ if err := ls.store.SetInitID(mount.name, mount.initID); err != nil {
|
|
| 577 |
+ return err |
|
| 578 |
+ } |
|
| 580 | 579 |
} |
| 581 |
- return ls.driver.Changes(m.mountID, pid) |
|
| 580 |
+ |
|
| 581 |
+ if mount.parent != nil {
|
|
| 582 |
+ if err := ls.store.SetMountParent(mount.name, mount.parent.chainID); err != nil {
|
|
| 583 |
+ return err |
|
| 584 |
+ } |
|
| 585 |
+ } |
|
| 586 |
+ |
|
| 587 |
+ ls.mounts[mount.name] = mount |
|
| 588 |
+ |
|
| 589 |
+ return nil |
|
| 590 |
+} |
|
| 591 |
+ |
|
| 592 |
+func (ls *layerStore) initMount(graphID, parent, mountLabel string, initFunc MountInit) (string, error) {
|
|
| 593 |
+ // Use "<graph-id>-init" to maintain compatibility with graph drivers |
|
| 594 |
+ // which are expecting this layer with this special name. If all |
|
| 595 |
+ // graph drivers can be updated to not rely on knowing about this layer |
|
| 596 |
+ // then the initID should be randomly generated. |
|
| 597 |
+ initID := fmt.Sprintf("%s-init", graphID)
|
|
| 598 |
+ |
|
| 599 |
+ if err := ls.driver.Create(initID, parent, mountLabel); err != nil {
|
|
| 600 |
+ return "", err |
|
| 601 |
+ } |
|
| 602 |
+ p, err := ls.driver.Get(initID, "") |
|
| 603 |
+ if err != nil {
|
|
| 604 |
+ return "", err |
|
| 605 |
+ } |
|
| 606 |
+ |
|
| 607 |
+ if err := initFunc(p); err != nil {
|
|
| 608 |
+ ls.driver.Put(initID) |
|
| 609 |
+ return "", err |
|
| 610 |
+ } |
|
| 611 |
+ |
|
| 612 |
+ if err := ls.driver.Put(initID); err != nil {
|
|
| 613 |
+ return "", err |
|
| 614 |
+ } |
|
| 615 |
+ |
|
| 616 |
+ return initID, nil |
|
| 582 | 617 |
} |
| 583 | 618 |
|
| 584 | 619 |
func (ls *layerStore) assembleTar(graphID string, metadata io.ReadCloser, size *int64) (io.ReadCloser, error) {
|
| ... | ... |
@@ -621,17 +581,6 @@ func (ls *layerStore) assembleTar(graphID string, metadata io.ReadCloser, size * |
| 621 | 621 |
return pR, nil |
| 622 | 622 |
} |
| 623 | 623 |
|
| 624 |
-// Metadata returns the low level metadata from the mount with the given name |
|
| 625 |
-func (ls *layerStore) Metadata(name string) (map[string]string, error) {
|
|
| 626 |
- ls.mountL.Lock() |
|
| 627 |
- m := ls.mounts[name] |
|
| 628 |
- ls.mountL.Unlock() |
|
| 629 |
- if m == nil {
|
|
| 630 |
- return nil, ErrMountDoesNotExist |
|
| 631 |
- } |
|
| 632 |
- return ls.driver.GetMetadata(m.mountID) |
|
| 633 |
-} |
|
| 634 |
- |
|
| 635 | 624 |
type naiveDiffPathDriver struct {
|
| 636 | 625 |
graphdriver.Driver |
| 637 | 626 |
} |
| ... | ... |
@@ -82,12 +82,12 @@ type layerInit func(root string) error |
| 82 | 82 |
|
| 83 | 83 |
func createLayer(ls Store, parent ChainID, layerFunc layerInit) (Layer, error) {
|
| 84 | 84 |
containerID := stringid.GenerateRandomID() |
| 85 |
- mount, err := ls.Mount(containerID, parent, "", nil) |
|
| 85 |
+ mount, err := ls.CreateRWLayer(containerID, parent, "", nil) |
|
| 86 | 86 |
if err != nil {
|
| 87 | 87 |
return nil, err |
| 88 | 88 |
} |
| 89 | 89 |
|
| 90 |
- path, err := mount.Path() |
|
| 90 |
+ path, err := mount.Mount("")
|
|
| 91 | 91 |
if err != nil {
|
| 92 | 92 |
return nil, err |
| 93 | 93 |
} |
| ... | ... |
@@ -107,11 +107,11 @@ func createLayer(ls Store, parent ChainID, layerFunc layerInit) (Layer, error) {
|
| 107 | 107 |
return nil, err |
| 108 | 108 |
} |
| 109 | 109 |
|
| 110 |
- if err := ls.Unmount(containerID); err != nil {
|
|
| 110 |
+ if err := mount.Unmount(); err != nil {
|
|
| 111 | 111 |
return nil, err |
| 112 | 112 |
} |
| 113 | 113 |
|
| 114 |
- if _, err := ls.DeleteMount(containerID); err != nil {
|
|
| 114 |
+ if _, err := ls.ReleaseRWLayer(mount); err != nil {
|
|
| 115 | 115 |
return nil, err |
| 116 | 116 |
} |
| 117 | 117 |
|
| ... | ... |
@@ -171,6 +171,13 @@ func getCachedLayer(l Layer) *roLayer {
|
| 171 | 171 |
return l.(*roLayer) |
| 172 | 172 |
} |
| 173 | 173 |
|
| 174 |
+func getMountLayer(l RWLayer) *mountedLayer {
|
|
| 175 |
+ if rl, ok := l.(*referencedRWLayer); ok {
|
|
| 176 |
+ return rl.mountedLayer |
|
| 177 |
+ } |
|
| 178 |
+ return l.(*mountedLayer) |
|
| 179 |
+} |
|
| 180 |
+ |
|
| 174 | 181 |
func createMetadata(layers ...Layer) []Metadata {
|
| 175 | 182 |
metadata := make([]Metadata, len(layers)) |
| 176 | 183 |
for i := range layers {
|
| ... | ... |
@@ -270,12 +277,12 @@ func TestMountAndRegister(t *testing.T) {
|
| 270 | 270 |
size, _ := layer.Size() |
| 271 | 271 |
t.Logf("Layer size: %d", size)
|
| 272 | 272 |
|
| 273 |
- mount2, err := ls.Mount("new-test-mount", layer.ChainID(), "", nil)
|
|
| 273 |
+ mount2, err := ls.CreateRWLayer("new-test-mount", layer.ChainID(), "", nil)
|
|
| 274 | 274 |
if err != nil {
|
| 275 | 275 |
t.Fatal(err) |
| 276 | 276 |
} |
| 277 | 277 |
|
| 278 |
- path2, err := mount2.Path() |
|
| 278 |
+ path2, err := mount2.Mount("")
|
|
| 279 | 279 |
if err != nil {
|
| 280 | 280 |
t.Fatal(err) |
| 281 | 281 |
} |
| ... | ... |
@@ -289,11 +296,11 @@ func TestMountAndRegister(t *testing.T) {
|
| 289 | 289 |
t.Fatalf("Wrong file data, expected %q, got %q", expected, string(b))
|
| 290 | 290 |
} |
| 291 | 291 |
|
| 292 |
- if err := ls.Unmount("new-test-mount"); err != nil {
|
|
| 292 |
+ if err := mount2.Unmount(); err != nil {
|
|
| 293 | 293 |
t.Fatal(err) |
| 294 | 294 |
} |
| 295 | 295 |
|
| 296 |
- if _, err := ls.DeleteMount("new-test-mount"); err != nil {
|
|
| 296 |
+ if _, err := ls.ReleaseRWLayer(mount2); err != nil {
|
|
| 297 | 297 |
t.Fatal(err) |
| 298 | 298 |
} |
| 299 | 299 |
} |
| ... | ... |
@@ -370,12 +377,12 @@ func TestStoreRestore(t *testing.T) {
|
| 370 | 370 |
t.Fatal(err) |
| 371 | 371 |
} |
| 372 | 372 |
|
| 373 |
- m, err := ls.Mount("some-mount_name", layer3.ChainID(), "", nil)
|
|
| 373 |
+ m, err := ls.CreateRWLayer("some-mount_name", layer3.ChainID(), "", nil)
|
|
| 374 | 374 |
if err != nil {
|
| 375 | 375 |
t.Fatal(err) |
| 376 | 376 |
} |
| 377 | 377 |
|
| 378 |
- path, err := m.Path() |
|
| 378 |
+ path, err := m.Mount("")
|
|
| 379 | 379 |
if err != nil {
|
| 380 | 380 |
t.Fatal(err) |
| 381 | 381 |
} |
| ... | ... |
@@ -383,11 +390,14 @@ func TestStoreRestore(t *testing.T) {
|
| 383 | 383 |
if err := ioutil.WriteFile(filepath.Join(path, "testfile.txt"), []byte("nothing here"), 0644); err != nil {
|
| 384 | 384 |
t.Fatal(err) |
| 385 | 385 |
} |
| 386 |
+ assertActivityCount(t, m, 1) |
|
| 386 | 387 |
|
| 387 |
- if err := ls.Unmount("some-mount_name"); err != nil {
|
|
| 388 |
+ if err := m.Unmount(); err != nil {
|
|
| 388 | 389 |
t.Fatal(err) |
| 389 | 390 |
} |
| 390 | 391 |
|
| 392 |
+ assertActivityCount(t, m, 0) |
|
| 393 |
+ |
|
| 391 | 394 |
ls2, err := NewStore(ls.(*layerStore).store, ls.(*layerStore).driver) |
| 392 | 395 |
if err != nil {
|
| 393 | 396 |
t.Fatal(err) |
| ... | ... |
@@ -400,18 +410,39 @@ func TestStoreRestore(t *testing.T) {
|
| 400 | 400 |
|
| 401 | 401 |
assertLayerEqual(t, layer3b, layer3) |
| 402 | 402 |
|
| 403 |
- // Mount again with same name, should already be loaded |
|
| 404 |
- m2, err := ls2.Mount("some-mount_name", layer3b.ChainID(), "", nil)
|
|
| 405 |
- if err != nil {
|
|
| 403 |
+ // Create again with same name, should return error |
|
| 404 |
+ if _, err := ls2.CreateRWLayer("some-mount_name", layer3b.ChainID(), "", nil); err == nil {
|
|
| 405 |
+ t.Fatal("Expected error creating mount with same name")
|
|
| 406 |
+ } else if err != ErrMountNameConflict {
|
|
| 406 | 407 |
t.Fatal(err) |
| 407 | 408 |
} |
| 408 | 409 |
|
| 409 |
- path2, err := m2.Path() |
|
| 410 |
+ m2, err := ls2.GetRWLayer("some-mount_name")
|
|
| 410 | 411 |
if err != nil {
|
| 411 | 412 |
t.Fatal(err) |
| 412 | 413 |
} |
| 413 | 414 |
|
| 414 |
- b, err := ioutil.ReadFile(filepath.Join(path2, "testfile.txt")) |
|
| 415 |
+ if mountPath, err := m2.Mount(""); err != nil {
|
|
| 416 |
+ t.Fatal(err) |
|
| 417 |
+ } else if path != mountPath {
|
|
| 418 |
+ t.Fatalf("Unexpected path %s, expected %s", mountPath, path)
|
|
| 419 |
+ } |
|
| 420 |
+ |
|
| 421 |
+ assertActivityCount(t, m2, 1) |
|
| 422 |
+ |
|
| 423 |
+ if mountPath, err := m2.Mount(""); err != nil {
|
|
| 424 |
+ t.Fatal(err) |
|
| 425 |
+ } else if path != mountPath {
|
|
| 426 |
+ t.Fatalf("Unexpected path %s, expected %s", mountPath, path)
|
|
| 427 |
+ } |
|
| 428 |
+ assertActivityCount(t, m2, 2) |
|
| 429 |
+ if err := m2.Unmount(); err != nil {
|
|
| 430 |
+ t.Fatal(err) |
|
| 431 |
+ } |
|
| 432 |
+ |
|
| 433 |
+ assertActivityCount(t, m2, 1) |
|
| 434 |
+ |
|
| 435 |
+ b, err := ioutil.ReadFile(filepath.Join(path, "testfile.txt")) |
|
| 415 | 436 |
if err != nil {
|
| 416 | 437 |
t.Fatal(err) |
| 417 | 438 |
} |
| ... | ... |
@@ -419,11 +450,19 @@ func TestStoreRestore(t *testing.T) {
|
| 419 | 419 |
t.Fatalf("Unexpected content %q, expected %q", string(b), expected)
|
| 420 | 420 |
} |
| 421 | 421 |
|
| 422 |
- if err := ls2.Unmount("some-mount_name"); err != nil {
|
|
| 422 |
+ if err := m2.Unmount(); err != nil {
|
|
| 423 |
+ t.Fatal(err) |
|
| 424 |
+ } |
|
| 425 |
+ |
|
| 426 |
+ assertActivityCount(t, m2, 0) |
|
| 427 |
+ |
|
| 428 |
+ if metadata, err := ls2.ReleaseRWLayer(m2); err != nil {
|
|
| 423 | 429 |
t.Fatal(err) |
| 430 |
+ } else if len(metadata) != 0 {
|
|
| 431 |
+ t.Fatalf("Unexpectedly deleted layers: %#v", metadata)
|
|
| 424 | 432 |
} |
| 425 | 433 |
|
| 426 |
- if metadata, err := ls2.DeleteMount("some-mount_name"); err != nil {
|
|
| 434 |
+ if metadata, err := ls2.ReleaseRWLayer(m2); err != nil {
|
|
| 427 | 435 |
t.Fatal(err) |
| 428 | 436 |
} else if len(metadata) != 0 {
|
| 429 | 437 |
t.Fatalf("Unexpectedly deleted layers: %#v", metadata)
|
| ... | ... |
@@ -627,6 +666,13 @@ func assertReferences(t *testing.T, references ...Layer) {
|
| 627 | 627 |
} |
| 628 | 628 |
} |
| 629 | 629 |
|
| 630 |
+func assertActivityCount(t *testing.T, l RWLayer, expected int) {
|
|
| 631 |
+ rl := l.(*referencedRWLayer) |
|
| 632 |
+ if rl.activityCount != expected {
|
|
| 633 |
+ t.Fatalf("Unexpected activity count %d, expected %d", rl.activityCount, expected)
|
|
| 634 |
+ } |
|
| 635 |
+} |
|
| 636 |
+ |
|
| 630 | 637 |
func TestRegisterExistingLayer(t *testing.T) {
|
| 631 | 638 |
ls, cleanup := newTestStore(t) |
| 632 | 639 |
defer cleanup() |
| ... | ... |
@@ -89,3 +89,8 @@ func (ls *layerStore) RegisterDiffID(graphID string, size int64) (Layer, error) |
| 89 | 89 |
|
| 90 | 90 |
return layer.getReference(), nil |
| 91 | 91 |
} |
| 92 |
+ |
|
| 93 |
+func (ls *layerStore) mountID(name string) string {
|
|
| 94 |
+ // windows has issues if container ID doesn't match mount ID |
|
| 95 |
+ return name |
|
| 96 |
+} |
| ... | ... |
@@ -14,30 +14,33 @@ import ( |
| 14 | 14 |
"github.com/vbatts/tar-split/tar/storage" |
| 15 | 15 |
) |
| 16 | 16 |
|
| 17 |
-func (ls *layerStore) MountByGraphID(name string, graphID string, parent ChainID) (l RWLayer, err error) {
|
|
| 17 |
+// CreateRWLayerByGraphID creates a RWLayer in the layer store using |
|
| 18 |
+// the provided name with the given graphID. To get the RWLayer |
|
| 19 |
+// after migration the layer may be retrieved by the given name. |
|
| 20 |
+func (ls *layerStore) CreateRWLayerByGraphID(name string, graphID string, parent ChainID) (err error) {
|
|
| 18 | 21 |
ls.mountL.Lock() |
| 19 | 22 |
defer ls.mountL.Unlock() |
| 20 | 23 |
m, ok := ls.mounts[name] |
| 21 | 24 |
if ok {
|
| 22 | 25 |
if m.parent.chainID != parent {
|
| 23 |
- return nil, errors.New("name conflict, mismatched parent")
|
|
| 26 |
+ return errors.New("name conflict, mismatched parent")
|
|
| 24 | 27 |
} |
| 25 | 28 |
if m.mountID != graphID {
|
| 26 |
- return nil, errors.New("mount already exists")
|
|
| 29 |
+ return errors.New("mount already exists")
|
|
| 27 | 30 |
} |
| 28 | 31 |
|
| 29 |
- return m, nil |
|
| 32 |
+ return nil |
|
| 30 | 33 |
} |
| 31 | 34 |
|
| 32 | 35 |
if !ls.driver.Exists(graphID) {
|
| 33 |
- return nil, errors.New("graph ID does not exist")
|
|
| 36 |
+ return errors.New("graph ID does not exist")
|
|
| 34 | 37 |
} |
| 35 | 38 |
|
| 36 | 39 |
var p *roLayer |
| 37 | 40 |
if string(parent) != "" {
|
| 38 | 41 |
p = ls.get(parent) |
| 39 | 42 |
if p == nil {
|
| 40 |
- return nil, ErrLayerDoesNotExist |
|
| 43 |
+ return ErrLayerDoesNotExist |
|
| 41 | 44 |
} |
| 42 | 45 |
|
| 43 | 46 |
// Release parent chain if error |
| ... | ... |
@@ -57,6 +60,7 @@ func (ls *layerStore) MountByGraphID(name string, graphID string, parent ChainID |
| 57 | 57 |
parent: p, |
| 58 | 58 |
mountID: graphID, |
| 59 | 59 |
layerStore: ls, |
| 60 |
+ references: map[RWLayer]*referencedRWLayer{},
|
|
| 60 | 61 |
} |
| 61 | 62 |
|
| 62 | 63 |
// Check for existing init layer |
| ... | ... |
@@ -66,15 +70,10 @@ func (ls *layerStore) MountByGraphID(name string, graphID string, parent ChainID |
| 66 | 66 |
} |
| 67 | 67 |
|
| 68 | 68 |
if err = ls.saveMount(m); err != nil {
|
| 69 |
- return nil, err |
|
| 70 |
- } |
|
| 71 |
- |
|
| 72 |
- // TODO: provide a mount label |
|
| 73 |
- if err = ls.mount(m, ""); err != nil {
|
|
| 74 |
- return nil, err |
|
| 69 |
+ return err |
|
| 75 | 70 |
} |
| 76 | 71 |
|
| 77 |
- return m, nil |
|
| 72 |
+ return nil |
|
| 78 | 73 |
} |
| 79 | 74 |
|
| 80 | 75 |
func (ls *layerStore) migrateLayer(tx MetadataTransaction, tarDataFile string, layer *roLayer) error {
|
| ... | ... |
@@ -303,12 +303,20 @@ func TestMountMigration(t *testing.T) {
|
| 303 | 303 |
t.Fatal(err) |
| 304 | 304 |
} |
| 305 | 305 |
|
| 306 |
- rwLayer1, err := ls.(*layerStore).MountByGraphID("migration-mount", containerID, layer1.ChainID())
|
|
| 306 |
+ if err := ls.(*layerStore).CreateRWLayerByGraphID("migration-mount", containerID, layer1.ChainID()); err != nil {
|
|
| 307 |
+ t.Fatal(err) |
|
| 308 |
+ } |
|
| 309 |
+ |
|
| 310 |
+ rwLayer1, err := ls.GetRWLayer("migration-mount")
|
|
| 307 | 311 |
if err != nil {
|
| 308 | 312 |
t.Fatal(err) |
| 309 | 313 |
} |
| 310 | 314 |
|
| 311 |
- changes, err := ls.Changes("migration-mount")
|
|
| 315 |
+ if _, err := rwLayer1.Mount(""); err != nil {
|
|
| 316 |
+ t.Fatal(err) |
|
| 317 |
+ } |
|
| 318 |
+ |
|
| 319 |
+ changes, err := rwLayer1.Changes() |
|
| 312 | 320 |
if err != nil {
|
| 313 | 321 |
t.Fatal(err) |
| 314 | 322 |
} |
| ... | ... |
@@ -341,39 +349,63 @@ func TestMountMigration(t *testing.T) {
|
| 341 | 341 |
Kind: archive.ChangeAdd, |
| 342 | 342 |
}) |
| 343 | 343 |
|
| 344 |
- if expectedCount := 1; rwLayer1.(*mountedLayer).activityCount != expectedCount {
|
|
| 345 |
- t.Fatalf("Wrong activity count %d, expected %d", rwLayer1.(*mountedLayer).activityCount, expectedCount)
|
|
| 344 |
+ assertActivityCount(t, rwLayer1, 1) |
|
| 345 |
+ |
|
| 346 |
+ if _, err := ls.CreateRWLayer("migration-mount", layer1.ChainID(), "", nil); err == nil {
|
|
| 347 |
+ t.Fatal("Expected error creating mount with same name")
|
|
| 348 |
+ } else if err != ErrMountNameConflict {
|
|
| 349 |
+ t.Fatal(err) |
|
| 346 | 350 |
} |
| 347 | 351 |
|
| 348 |
- rwLayer2, err := ls.Mount("migration-mount", layer1.ChainID(), "", nil)
|
|
| 352 |
+ rwLayer2, err := ls.GetRWLayer("migration-mount")
|
|
| 349 | 353 |
if err != nil {
|
| 350 | 354 |
t.Fatal(err) |
| 351 | 355 |
} |
| 352 | 356 |
|
| 353 |
- if rwLayer1 != rwLayer2 {
|
|
| 354 |
- t.Fatalf("Wrong rwlayer %v, expected %v", rwLayer2, rwLayer1)
|
|
| 357 |
+ if getMountLayer(rwLayer1) != getMountLayer(rwLayer2) {
|
|
| 358 |
+ t.Fatal("Expected same layer from get with same name as from migrate")
|
|
| 359 |
+ } |
|
| 360 |
+ |
|
| 361 |
+ if _, err := rwLayer2.Mount(""); err != nil {
|
|
| 362 |
+ t.Fatal(err) |
|
| 355 | 363 |
} |
| 356 | 364 |
|
| 357 |
- if expectedCount := 2; rwLayer2.(*mountedLayer).activityCount != expectedCount {
|
|
| 358 |
- t.Fatalf("Wrong activity count %d, expected %d", rwLayer2.(*mountedLayer).activityCount, expectedCount)
|
|
| 365 |
+ assertActivityCount(t, rwLayer2, 1) |
|
| 366 |
+ assertActivityCount(t, rwLayer1, 1) |
|
| 367 |
+ |
|
| 368 |
+ if _, err := rwLayer2.Mount(""); err != nil {
|
|
| 369 |
+ t.Fatal(err) |
|
| 359 | 370 |
} |
| 360 | 371 |
|
| 372 |
+ assertActivityCount(t, rwLayer2, 2) |
|
| 373 |
+ assertActivityCount(t, rwLayer1, 1) |
|
| 374 |
+ |
|
| 361 | 375 |
if metadata, err := ls.Release(layer1); err != nil {
|
| 362 | 376 |
t.Fatal(err) |
| 363 | 377 |
} else if len(metadata) > 0 {
|
| 364 | 378 |
t.Fatalf("Expected no layers to be deleted, deleted %#v", metadata)
|
| 365 | 379 |
} |
| 366 | 380 |
|
| 367 |
- if err := ls.Unmount("migration-mount"); err != nil {
|
|
| 381 |
+ if err := rwLayer1.Unmount(); err != nil {
|
|
| 382 |
+ t.Fatal(err) |
|
| 383 |
+ } |
|
| 384 |
+ assertActivityCount(t, rwLayer2, 2) |
|
| 385 |
+ assertActivityCount(t, rwLayer1, 0) |
|
| 386 |
+ |
|
| 387 |
+ if _, err := ls.ReleaseRWLayer(rwLayer1); err != nil {
|
|
| 388 |
+ t.Fatal(err) |
|
| 389 |
+ } |
|
| 390 |
+ |
|
| 391 |
+ if err := rwLayer2.Unmount(); err != nil {
|
|
| 368 | 392 |
t.Fatal(err) |
| 369 | 393 |
} |
| 370 |
- if _, err := ls.DeleteMount("migration-mount"); err == nil {
|
|
| 394 |
+ if _, err := ls.ReleaseRWLayer(rwLayer2); err == nil {
|
|
| 371 | 395 |
t.Fatal("Expected error deleting active mount")
|
| 372 | 396 |
} |
| 373 |
- if err := ls.Unmount("migration-mount"); err != nil {
|
|
| 397 |
+ if err := rwLayer2.Unmount(); err != nil {
|
|
| 374 | 398 |
t.Fatal(err) |
| 375 | 399 |
} |
| 376 |
- metadata, err := ls.DeleteMount("migration-mount")
|
|
| 400 |
+ metadata, err := ls.ReleaseRWLayer(rwLayer2) |
|
| 377 | 401 |
if err != nil {
|
| 378 | 402 |
t.Fatal(err) |
| 379 | 403 |
} |
| ... | ... |
@@ -27,12 +27,12 @@ func TestMountInit(t *testing.T) {
|
| 27 | 27 |
return initfile.ApplyFile(root) |
| 28 | 28 |
} |
| 29 | 29 |
|
| 30 |
- m, err := ls.Mount("fun-mount", layer.ChainID(), "", mountInit)
|
|
| 30 |
+ m, err := ls.CreateRWLayer("fun-mount", layer.ChainID(), "", mountInit)
|
|
| 31 | 31 |
if err != nil {
|
| 32 | 32 |
t.Fatal(err) |
| 33 | 33 |
} |
| 34 | 34 |
|
| 35 |
- path, err := m.Path() |
|
| 35 |
+ path, err := m.Mount("")
|
|
| 36 | 36 |
if err != nil {
|
| 37 | 37 |
t.Fatal(err) |
| 38 | 38 |
} |
| ... | ... |
@@ -80,12 +80,12 @@ func TestMountSize(t *testing.T) {
|
| 80 | 80 |
return newTestFile("file-init", contentInit, 0777).ApplyFile(root)
|
| 81 | 81 |
} |
| 82 | 82 |
|
| 83 |
- m, err := ls.Mount("mount-size", layer.ChainID(), "", mountInit)
|
|
| 83 |
+ m, err := ls.CreateRWLayer("mount-size", layer.ChainID(), "", mountInit)
|
|
| 84 | 84 |
if err != nil {
|
| 85 | 85 |
t.Fatal(err) |
| 86 | 86 |
} |
| 87 | 87 |
|
| 88 |
- path, err := m.Path() |
|
| 88 |
+ path, err := m.Mount("")
|
|
| 89 | 89 |
if err != nil {
|
| 90 | 90 |
t.Fatal(err) |
| 91 | 91 |
} |
| ... | ... |
@@ -125,12 +125,12 @@ func TestMountChanges(t *testing.T) {
|
| 125 | 125 |
return initfile.ApplyFile(root) |
| 126 | 126 |
} |
| 127 | 127 |
|
| 128 |
- m, err := ls.Mount("mount-changes", layer.ChainID(), "", mountInit)
|
|
| 128 |
+ m, err := ls.CreateRWLayer("mount-changes", layer.ChainID(), "", mountInit)
|
|
| 129 | 129 |
if err != nil {
|
| 130 | 130 |
t.Fatal(err) |
| 131 | 131 |
} |
| 132 | 132 |
|
| 133 |
- path, err := m.Path() |
|
| 133 |
+ path, err := m.Mount("")
|
|
| 134 | 134 |
if err != nil {
|
| 135 | 135 |
t.Fatal(err) |
| 136 | 136 |
} |
| ... | ... |
@@ -155,7 +155,7 @@ func TestMountChanges(t *testing.T) {
|
| 155 | 155 |
t.Fatal(err) |
| 156 | 156 |
} |
| 157 | 157 |
|
| 158 |
- changes, err := ls.Changes("mount-changes")
|
|
| 158 |
+ changes, err := m.Changes() |
|
| 159 | 159 |
if err != nil {
|
| 160 | 160 |
t.Fatal(err) |
| 161 | 161 |
} |
| ... | ... |
@@ -1,15 +1,20 @@ |
| 1 | 1 |
package layer |
| 2 | 2 |
|
| 3 |
-import "io" |
|
| 3 |
+import ( |
|
| 4 |
+ "io" |
|
| 5 |
+ "sync" |
|
| 6 |
+ |
|
| 7 |
+ "github.com/docker/docker/pkg/archive" |
|
| 8 |
+) |
|
| 4 | 9 |
|
| 5 | 10 |
type mountedLayer struct {
|
| 6 |
- name string |
|
| 7 |
- mountID string |
|
| 8 |
- initID string |
|
| 9 |
- parent *roLayer |
|
| 10 |
- path string |
|
| 11 |
- layerStore *layerStore |
|
| 12 |
- activityCount int |
|
| 11 |
+ name string |
|
| 12 |
+ mountID string |
|
| 13 |
+ initID string |
|
| 14 |
+ parent *roLayer |
|
| 15 |
+ layerStore *layerStore |
|
| 16 |
+ |
|
| 17 |
+ references map[RWLayer]*referencedRWLayer |
|
| 13 | 18 |
} |
| 14 | 19 |
|
| 15 | 20 |
func (ml *mountedLayer) cacheParent() string {
|
| ... | ... |
@@ -30,11 +35,8 @@ func (ml *mountedLayer) TarStream() (io.ReadCloser, error) {
|
| 30 | 30 |
return archiver, nil |
| 31 | 31 |
} |
| 32 | 32 |
|
| 33 |
-func (ml *mountedLayer) Path() (string, error) {
|
|
| 34 |
- if ml.path == "" {
|
|
| 35 |
- return "", ErrNotMounted |
|
| 36 |
- } |
|
| 37 |
- return ml.path, nil |
|
| 33 |
+func (ml *mountedLayer) Name() string {
|
|
| 34 |
+ return ml.name |
|
| 38 | 35 |
} |
| 39 | 36 |
|
| 40 | 37 |
func (ml *mountedLayer) Parent() Layer {
|
| ... | ... |
@@ -47,6 +49,96 @@ func (ml *mountedLayer) Parent() Layer {
|
| 47 | 47 |
return nil |
| 48 | 48 |
} |
| 49 | 49 |
|
| 50 |
+func (ml *mountedLayer) Mount(mountLabel string) (string, error) {
|
|
| 51 |
+ return ml.layerStore.driver.Get(ml.mountID, mountLabel) |
|
| 52 |
+} |
|
| 53 |
+ |
|
| 54 |
+func (ml *mountedLayer) Unmount() error {
|
|
| 55 |
+ return ml.layerStore.driver.Put(ml.mountID) |
|
| 56 |
+} |
|
| 57 |
+ |
|
| 50 | 58 |
func (ml *mountedLayer) Size() (int64, error) {
|
| 51 | 59 |
return ml.layerStore.driver.DiffSize(ml.mountID, ml.cacheParent()) |
| 52 | 60 |
} |
| 61 |
+ |
|
| 62 |
+func (ml *mountedLayer) Changes() ([]archive.Change, error) {
|
|
| 63 |
+ return ml.layerStore.driver.Changes(ml.mountID, ml.cacheParent()) |
|
| 64 |
+} |
|
| 65 |
+ |
|
| 66 |
+func (ml *mountedLayer) Metadata() (map[string]string, error) {
|
|
| 67 |
+ return ml.layerStore.driver.GetMetadata(ml.mountID) |
|
| 68 |
+} |
|
| 69 |
+ |
|
| 70 |
+func (ml *mountedLayer) getReference() RWLayer {
|
|
| 71 |
+ ref := &referencedRWLayer{
|
|
| 72 |
+ mountedLayer: ml, |
|
| 73 |
+ } |
|
| 74 |
+ ml.references[ref] = ref |
|
| 75 |
+ |
|
| 76 |
+ return ref |
|
| 77 |
+} |
|
| 78 |
+ |
|
| 79 |
+func (ml *mountedLayer) hasReferences() bool {
|
|
| 80 |
+ return len(ml.references) > 0 |
|
| 81 |
+} |
|
| 82 |
+ |
|
| 83 |
+func (ml *mountedLayer) deleteReference(ref RWLayer) error {
|
|
| 84 |
+ rl, ok := ml.references[ref] |
|
| 85 |
+ if !ok {
|
|
| 86 |
+ return ErrLayerNotRetained |
|
| 87 |
+ } |
|
| 88 |
+ |
|
| 89 |
+ if err := rl.release(); err != nil {
|
|
| 90 |
+ return err |
|
| 91 |
+ } |
|
| 92 |
+ delete(ml.references, ref) |
|
| 93 |
+ |
|
| 94 |
+ return nil |
|
| 95 |
+} |
|
| 96 |
+ |
|
| 97 |
+type referencedRWLayer struct {
|
|
| 98 |
+ *mountedLayer |
|
| 99 |
+ |
|
| 100 |
+ activityL sync.Mutex |
|
| 101 |
+ activityCount int |
|
| 102 |
+} |
|
| 103 |
+ |
|
| 104 |
+func (rl *referencedRWLayer) release() error {
|
|
| 105 |
+ rl.activityL.Lock() |
|
| 106 |
+ defer rl.activityL.Unlock() |
|
| 107 |
+ |
|
| 108 |
+ if rl.activityCount > 0 {
|
|
| 109 |
+ return ErrActiveMount |
|
| 110 |
+ } |
|
| 111 |
+ |
|
| 112 |
+ rl.activityCount = -1 |
|
| 113 |
+ |
|
| 114 |
+ return nil |
|
| 115 |
+} |
|
| 116 |
+ |
|
| 117 |
+func (rl *referencedRWLayer) Mount(mountLabel string) (string, error) {
|
|
| 118 |
+ rl.activityL.Lock() |
|
| 119 |
+ defer rl.activityL.Unlock() |
|
| 120 |
+ |
|
| 121 |
+ if rl.activityCount == -1 {
|
|
| 122 |
+ return "", ErrLayerNotRetained |
|
| 123 |
+ } |
|
| 124 |
+ |
|
| 125 |
+ rl.activityCount++ |
|
| 126 |
+ return rl.mountedLayer.Mount(mountLabel) |
|
| 127 |
+} |
|
| 128 |
+ |
|
| 129 |
+func (rl *referencedRWLayer) Unmount() error {
|
|
| 130 |
+ rl.activityL.Lock() |
|
| 131 |
+ defer rl.activityL.Unlock() |
|
| 132 |
+ |
|
| 133 |
+ if rl.activityCount == 0 {
|
|
| 134 |
+ return ErrNotMounted |
|
| 135 |
+ } |
|
| 136 |
+ if rl.activityCount == -1 {
|
|
| 137 |
+ return ErrLayerNotRetained |
|
| 138 |
+ } |
|
| 139 |
+ rl.activityCount-- |
|
| 140 |
+ |
|
| 141 |
+ return rl.mountedLayer.Unmount() |
|
| 142 |
+} |
| ... | ... |
@@ -24,8 +24,7 @@ type graphIDRegistrar interface {
|
| 24 | 24 |
} |
| 25 | 25 |
|
| 26 | 26 |
type graphIDMounter interface {
|
| 27 |
- MountByGraphID(string, string, layer.ChainID) (layer.RWLayer, error) |
|
| 28 |
- Unmount(string) error |
|
| 27 |
+ CreateRWLayerByGraphID(string, string, layer.ChainID) error |
|
| 29 | 28 |
} |
| 30 | 29 |
|
| 31 | 30 |
const ( |
| ... | ... |
@@ -172,13 +171,7 @@ func migrateContainers(root string, ls graphIDMounter, is image.Store, imageMapp |
| 172 | 172 |
return err |
| 173 | 173 |
} |
| 174 | 174 |
|
| 175 |
- _, err = ls.MountByGraphID(id, id, img.RootFS.ChainID()) |
|
| 176 |
- if err != nil {
|
|
| 177 |
- return err |
|
| 178 |
- } |
|
| 179 |
- |
|
| 180 |
- err = ls.Unmount(id) |
|
| 181 |
- if err != nil {
|
|
| 175 |
+ if err := ls.CreateRWLayerByGraphID(id, id, img.RootFS.ChainID()); err != nil {
|
|
| 182 | 176 |
return err |
| 183 | 177 |
} |
| 184 | 178 |
|
| ... | ... |
@@ -338,10 +338,9 @@ type mockMounter struct {
|
| 338 | 338 |
count int |
| 339 | 339 |
} |
| 340 | 340 |
|
| 341 |
-func (r *mockMounter) MountByGraphID(name string, graphID string, parent layer.ChainID) (layer.RWLayer, error) {
|
|
| 341 |
+func (r *mockMounter) CreateRWLayerByGraphID(name string, graphID string, parent layer.ChainID) error {
|
|
| 342 | 342 |
r.mounts = append(r.mounts, mountInfo{name, graphID, string(parent)})
|
| 343 |
- r.count++ |
|
| 344 |
- return nil, nil |
|
| 343 |
+ return nil |
|
| 345 | 344 |
} |
| 346 | 345 |
func (r *mockMounter) Unmount(string) error {
|
| 347 | 346 |
r.count-- |