Merge pull request #7989 from jlhawn/graphdriver_differ_refactor
Refactor use of graphdriver.Differ
This commit is contained in:
commit
37b3b34afa
|
@ -313,7 +313,8 @@ func collectFileInfo(sourceDir string) (*FileInfo, error) {
|
||||||
return root, nil
|
return root, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare two directories and generate an array of Change objects describing the changes
|
// ChangesDirs compares two directories and generates an array of Change objects describing the changes.
|
||||||
|
// If oldDir is "", then all files in newDir will be Add-Changes.
|
||||||
func ChangesDirs(newDir, oldDir string) ([]Change, error) {
|
func ChangesDirs(newDir, oldDir string) ([]Change, error) {
|
||||||
var (
|
var (
|
||||||
oldRoot, newRoot *FileInfo
|
oldRoot, newRoot *FileInfo
|
||||||
|
@ -321,7 +322,9 @@ func ChangesDirs(newDir, oldDir string) ([]Change, error) {
|
||||||
errs = make(chan error, 2)
|
errs = make(chan error, 2)
|
||||||
)
|
)
|
||||||
go func() {
|
go func() {
|
||||||
oldRoot, err1 = collectFileInfo(oldDir)
|
if oldDir != "" {
|
||||||
|
oldRoot, err1 = collectFileInfo(oldDir)
|
||||||
|
}
|
||||||
errs <- err1
|
errs <- err1
|
||||||
}()
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
|
|
|
@ -18,7 +18,6 @@ import (
|
||||||
|
|
||||||
"github.com/docker/docker/archive"
|
"github.com/docker/docker/archive"
|
||||||
"github.com/docker/docker/daemon/execdriver"
|
"github.com/docker/docker/daemon/execdriver"
|
||||||
"github.com/docker/docker/daemon/graphdriver"
|
|
||||||
"github.com/docker/docker/engine"
|
"github.com/docker/docker/engine"
|
||||||
"github.com/docker/docker/image"
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/links"
|
"github.com/docker/docker/links"
|
||||||
|
@ -755,21 +754,13 @@ func (container *Container) GetSize() (int64, int64) {
|
||||||
}
|
}
|
||||||
defer container.Unmount()
|
defer container.Unmount()
|
||||||
|
|
||||||
if differ, ok := driver.(graphdriver.Differ); ok {
|
initID := fmt.Sprintf("%s-init", container.ID)
|
||||||
sizeRw, err = differ.DiffSize(container.ID)
|
sizeRw, err = driver.DiffSize(container.ID, initID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Warning: driver %s couldn't return diff size of container %s: %s", driver, container.ID, err)
|
log.Errorf("Warning: driver %s couldn't return diff size of container %s: %s", driver, container.ID, err)
|
||||||
// FIXME: GetSize should return an error. Not changing it now in case
|
// FIXME: GetSize should return an error. Not changing it now in case
|
||||||
// there is a side-effect.
|
// there is a side-effect.
|
||||||
sizeRw = -1
|
sizeRw = -1
|
||||||
}
|
|
||||||
} else {
|
|
||||||
changes, _ := container.changes()
|
|
||||||
if changes != nil {
|
|
||||||
sizeRw = archive.ChangesSize(container.basefs, changes)
|
|
||||||
} else {
|
|
||||||
sizeRw = -1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = os.Stat(container.basefs); err != nil {
|
if _, err = os.Stat(container.basefs); err != nil {
|
||||||
|
|
|
@ -935,46 +935,13 @@ func (daemon *Daemon) Unmount(container *Container) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) Changes(container *Container) ([]archive.Change, error) {
|
func (daemon *Daemon) Changes(container *Container) ([]archive.Change, error) {
|
||||||
if differ, ok := daemon.driver.(graphdriver.Differ); ok {
|
initID := fmt.Sprintf("%s-init", container.ID)
|
||||||
return differ.Changes(container.ID)
|
return daemon.driver.Changes(container.ID, initID)
|
||||||
}
|
|
||||||
cDir, err := daemon.driver.Get(container.ID, "")
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Error getting container rootfs %s from driver %s: %s", container.ID, container.daemon.driver, err)
|
|
||||||
}
|
|
||||||
defer daemon.driver.Put(container.ID)
|
|
||||||
initDir, err := daemon.driver.Get(container.ID+"-init", "")
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Error getting container init rootfs %s from driver %s: %s", container.ID, container.daemon.driver, err)
|
|
||||||
}
|
|
||||||
defer daemon.driver.Put(container.ID + "-init")
|
|
||||||
return archive.ChangesDirs(cDir, initDir)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) Diff(container *Container) (archive.Archive, error) {
|
func (daemon *Daemon) Diff(container *Container) (archive.Archive, error) {
|
||||||
if differ, ok := daemon.driver.(graphdriver.Differ); ok {
|
initID := fmt.Sprintf("%s-init", container.ID)
|
||||||
return differ.Diff(container.ID)
|
return daemon.driver.Diff(container.ID, initID)
|
||||||
}
|
|
||||||
|
|
||||||
changes, err := daemon.Changes(container)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cDir, err := daemon.driver.Get(container.ID, "")
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Error getting container rootfs %s from driver %s: %s", container.ID, container.daemon.driver, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
archive, err := archive.ExportChanges(cDir, changes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return ioutils.NewReadCloserWrapper(archive, func() error {
|
|
||||||
err := archive.Close()
|
|
||||||
daemon.driver.Put(container.ID)
|
|
||||||
return err
|
|
||||||
}), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) Run(c *Container, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
|
func (daemon *Daemon) Run(c *Container, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
|
||||||
|
|
|
@ -294,23 +294,44 @@ func (a *Driver) Put(id string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns an archive of the contents for the id
|
// Diff produces an archive of the changes between the specified
|
||||||
func (a *Driver) Diff(id string) (archive.Archive, error) {
|
// layer and its parent layer which may be "".
|
||||||
|
func (a *Driver) Diff(id, parent string) (archive.Archive, error) {
|
||||||
|
// AUFS doesn't need the parent layer to produce a diff.
|
||||||
return archive.TarWithOptions(path.Join(a.rootPath(), "diff", id), &archive.TarOptions{
|
return archive.TarWithOptions(path.Join(a.rootPath(), "diff", id), &archive.TarOptions{
|
||||||
Compression: archive.Uncompressed,
|
Compression: archive.Uncompressed,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Driver) ApplyDiff(id string, diff archive.ArchiveReader) error {
|
func (a *Driver) applyDiff(id string, diff archive.ArchiveReader) error {
|
||||||
return archive.Untar(diff, path.Join(a.rootPath(), "diff", id), nil)
|
return archive.Untar(diff, path.Join(a.rootPath(), "diff", id), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the size of the contents for the id
|
// DiffSize calculates the changes between the specified id
|
||||||
func (a *Driver) DiffSize(id string) (int64, error) {
|
// and its parent and returns the size in bytes of the changes
|
||||||
|
// relative to its base filesystem directory.
|
||||||
|
func (a *Driver) DiffSize(id, parent string) (bytes int64, err error) {
|
||||||
|
// AUFS doesn't need the parent layer to calculate the diff size.
|
||||||
return utils.TreeSize(path.Join(a.rootPath(), "diff", id))
|
return utils.TreeSize(path.Join(a.rootPath(), "diff", id))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Driver) Changes(id string) ([]archive.Change, error) {
|
// ApplyDiff extracts the changeset from the given diff into the
|
||||||
|
// layer with the specified id and parent, returning the size of the
|
||||||
|
// new layer in bytes.
|
||||||
|
func (a *Driver) ApplyDiff(id, parent string, diff archive.ArchiveReader) (bytes int64, err error) {
|
||||||
|
// AUFS doesn't need the parent id to apply the diff.
|
||||||
|
if err = a.applyDiff(id, diff); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.DiffSize(id, parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Changes produces a list of changes between the specified layer
|
||||||
|
// and its parent layer. If parent is "", then all changes will be ADD changes.
|
||||||
|
func (a *Driver) Changes(id, parent string) ([]archive.Change, error) {
|
||||||
|
// AUFS doesn't have snapshots, so we need to get changes from all parent
|
||||||
|
// layers.
|
||||||
layers, err := a.getParentLayerPaths(id)
|
layers, err := a.getParentLayerPaths(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -323,9 +344,6 @@ func (a *Driver) getParentLayerPaths(id string) ([]string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(parentIds) == 0 {
|
|
||||||
return nil, fmt.Errorf("Dir %s does not have any parent layers", id)
|
|
||||||
}
|
|
||||||
layers := make([]string, len(parentIds))
|
layers := make([]string, len(parentIds))
|
||||||
|
|
||||||
// Get the diff paths for all the parent ids
|
// Get the diff paths for all the parent ids
|
||||||
|
|
|
@ -330,7 +330,7 @@ func TestGetDiff(t *testing.T) {
|
||||||
}
|
}
|
||||||
f.Close()
|
f.Close()
|
||||||
|
|
||||||
a, err := d.Diff("1")
|
a, err := d.Diff("1", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -374,7 +374,7 @@ func TestChanges(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
changes, err := d.Changes("2")
|
changes, err := d.Changes("2", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -413,7 +413,7 @@ func TestChanges(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
changes, err = d.Changes("3")
|
changes, err = d.Changes("3", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -465,7 +465,7 @@ func TestDiffSize(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
diffSize, err := d.DiffSize("1")
|
diffSize, err := d.DiffSize("1", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -507,7 +507,7 @@ func TestChildDiffSize(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
diffSize, err := d.DiffSize("1")
|
diffSize, err := d.DiffSize("1", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -519,7 +519,7 @@ func TestChildDiffSize(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
diffSize, err = d.DiffSize("2")
|
diffSize, err = d.DiffSize("2", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -602,7 +602,7 @@ func TestApplyDiff(t *testing.T) {
|
||||||
}
|
}
|
||||||
f.Close()
|
f.Close()
|
||||||
|
|
||||||
diff, err := d.Diff("1")
|
diff, err := d.Diff("1", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -614,7 +614,7 @@ func TestApplyDiff(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := d.ApplyDiff("3", diff); err != nil {
|
if err := d.applyDiff("3", diff); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,9 +44,11 @@ func Init(home string, options []string) (graphdriver.Driver, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Driver{
|
driver := &Driver{
|
||||||
home: home,
|
home: home,
|
||||||
}, nil
|
}
|
||||||
|
|
||||||
|
return graphdriver.NaiveDiffDriver(driver), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Driver struct {
|
type Driver struct {
|
||||||
|
|
|
@ -43,7 +43,7 @@ func Init(home string, options []string) (graphdriver.Driver, error) {
|
||||||
home: home,
|
home: home,
|
||||||
}
|
}
|
||||||
|
|
||||||
return d, nil
|
return graphdriver.NaiveDiffDriver(d), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Driver) String() string {
|
func (d *Driver) String() string {
|
||||||
|
|
|
@ -19,26 +19,56 @@ const (
|
||||||
|
|
||||||
type InitFunc func(root string, options []string) (Driver, error)
|
type InitFunc func(root string, options []string) (Driver, error)
|
||||||
|
|
||||||
type Driver interface {
|
// ProtoDriver defines the basic capabilities of a driver.
|
||||||
|
// This interface exists solely to be a minimum set of methods
|
||||||
|
// for client code which choose not to implement the entire Driver
|
||||||
|
// interface and use the NaiveDiffDriver wrapper constructor.
|
||||||
|
//
|
||||||
|
// Use of ProtoDriver directly by client code is not recommended.
|
||||||
|
type ProtoDriver interface {
|
||||||
|
// String returns a string representation of this driver.
|
||||||
String() string
|
String() string
|
||||||
|
// Create creates a new, empty, filesystem layer with the
|
||||||
|
// specified id and parent. Parent may be "".
|
||||||
Create(id, parent string) error
|
Create(id, parent string) error
|
||||||
|
// Remove attempts to remove the filesystem layer with this id.
|
||||||
Remove(id string) error
|
Remove(id string) error
|
||||||
|
// Get returns the mountpoint for the layered filesystem referred
|
||||||
|
// to by this id. You can optionally specify a mountLabel or "".
|
||||||
|
// Returns the absolute path to the mounted layered filesystem.
|
||||||
Get(id, mountLabel string) (dir string, err error)
|
Get(id, mountLabel string) (dir string, err error)
|
||||||
|
// Put releases the system resources for the specified id,
|
||||||
|
// e.g, unmounting layered filesystem.
|
||||||
Put(id string)
|
Put(id string)
|
||||||
|
// Exists returns whether a filesystem layer with the specified
|
||||||
|
// ID exists on this driver.
|
||||||
Exists(id string) bool
|
Exists(id string) bool
|
||||||
|
// Status returns a set of key-value pairs which give low
|
||||||
|
// level diagnostic status about this driver.
|
||||||
Status() [][2]string
|
Status() [][2]string
|
||||||
|
// Cleanup performs necessary tasks to release resources
|
||||||
|
// held by the driver, e.g., unmounting all layered filesystems
|
||||||
|
// known to this driver.
|
||||||
Cleanup() error
|
Cleanup() error
|
||||||
}
|
}
|
||||||
|
|
||||||
type Differ interface {
|
// Driver is the interface for layered/snapshot file system drivers.
|
||||||
Diff(id string) (archive.Archive, error)
|
type Driver interface {
|
||||||
Changes(id string) ([]archive.Change, error)
|
ProtoDriver
|
||||||
ApplyDiff(id string, diff archive.ArchiveReader) error
|
// Diff produces an archive of the changes between the specified
|
||||||
DiffSize(id string) (bytes int64, err error)
|
// layer and its parent layer which may be "".
|
||||||
|
Diff(id, parent string) (archive.Archive, error)
|
||||||
|
// Changes produces a list of changes between the specified layer
|
||||||
|
// and its parent layer. If parent is "", then all changes will be ADD changes.
|
||||||
|
Changes(id, parent string) ([]archive.Change, error)
|
||||||
|
// ApplyDiff extracts the changeset from the given diff into the
|
||||||
|
// layer with the specified id and parent, returning the size of the
|
||||||
|
// new layer in bytes.
|
||||||
|
ApplyDiff(id, parent string, diff archive.ArchiveReader) (bytes int64, err error)
|
||||||
|
// DiffSize calculates the changes between the specified id
|
||||||
|
// and its parent and returns the size in bytes of the changes
|
||||||
|
// relative to its base filesystem directory.
|
||||||
|
DiffSize(id, parent string) (bytes int64, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
package graphdriver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/docker/docker/archive"
|
||||||
|
"github.com/docker/docker/pkg/ioutils"
|
||||||
|
"github.com/docker/docker/pkg/log"
|
||||||
|
"github.com/docker/docker/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
// naiveDiffDriver takes a ProtoDriver and adds the
|
||||||
|
// capability of the Diffing methods which it may or may not
|
||||||
|
// support on its own. See the comment on the exported
|
||||||
|
// NaiveDiffDriver function below.
|
||||||
|
// Notably, the AUFS driver doesn't need to be wrapped like this.
|
||||||
|
type naiveDiffDriver struct {
|
||||||
|
ProtoDriver
|
||||||
|
}
|
||||||
|
|
||||||
|
// NaiveDiffDriver returns a fully functional driver that wraps the
|
||||||
|
// given ProtoDriver and adds the capability of the following methods which
|
||||||
|
// it may or may not support on its own:
|
||||||
|
// Diff(id, parent string) (archive.Archive, error)
|
||||||
|
// Changes(id, parent string) ([]archive.Change, error)
|
||||||
|
// ApplyDiff(id, parent string, diff archive.ArchiveReader) (bytes int64, err error)
|
||||||
|
// DiffSize(id, parent string) (bytes int64, err error)
|
||||||
|
func NaiveDiffDriver(driver ProtoDriver) Driver {
|
||||||
|
return &naiveDiffDriver{ProtoDriver: driver}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Diff produces an archive of the changes between the specified
|
||||||
|
// layer and its parent layer which may be "".
|
||||||
|
func (gdw *naiveDiffDriver) Diff(id, parent string) (arch archive.Archive, err error) {
|
||||||
|
driver := gdw.ProtoDriver
|
||||||
|
|
||||||
|
layerFs, err := driver.Get(id, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
driver.Put(id)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if parent == "" {
|
||||||
|
archive, err := archive.Tar(layerFs, archive.Uncompressed)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ioutils.NewReadCloserWrapper(archive, func() error {
|
||||||
|
err := archive.Close()
|
||||||
|
driver.Put(id)
|
||||||
|
return err
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
parentFs, err := driver.Get(parent, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer driver.Put(parent)
|
||||||
|
|
||||||
|
changes, err := archive.ChangesDirs(layerFs, parentFs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
archive, err := archive.ExportChanges(layerFs, changes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ioutils.NewReadCloserWrapper(archive, func() error {
|
||||||
|
err := archive.Close()
|
||||||
|
driver.Put(id)
|
||||||
|
return err
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Changes produces a list of changes between the specified layer
|
||||||
|
// and its parent layer. If parent is "", then all changes will be ADD changes.
|
||||||
|
func (gdw *naiveDiffDriver) Changes(id, parent string) ([]archive.Change, error) {
|
||||||
|
driver := gdw.ProtoDriver
|
||||||
|
|
||||||
|
layerFs, err := driver.Get(id, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer driver.Put(id)
|
||||||
|
|
||||||
|
parentFs := ""
|
||||||
|
|
||||||
|
if parent != "" {
|
||||||
|
parentFs, err = driver.Get(parent, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer driver.Put(parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
return archive.ChangesDirs(layerFs, parentFs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyDiff extracts the changeset from the given diff into the
|
||||||
|
// layer with the specified id and parent, returning the size of the
|
||||||
|
// new layer in bytes.
|
||||||
|
func (gdw *naiveDiffDriver) ApplyDiff(id, parent string, diff archive.ArchiveReader) (bytes int64, err error) {
|
||||||
|
driver := gdw.ProtoDriver
|
||||||
|
|
||||||
|
// Mount the root filesystem so we can apply the diff/layer.
|
||||||
|
layerFs, err := driver.Get(id, "")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer driver.Put(id)
|
||||||
|
|
||||||
|
start := time.Now().UTC()
|
||||||
|
log.Debugf("Start untar layer")
|
||||||
|
if err = archive.ApplyLayer(layerFs, diff); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debugf("Untar time: %vs", time.Now().UTC().Sub(start).Seconds())
|
||||||
|
|
||||||
|
if parent == "" {
|
||||||
|
return utils.TreeSize(layerFs)
|
||||||
|
}
|
||||||
|
|
||||||
|
parentFs, err := driver.Get(parent, "")
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Driver %s failed to get image parent %s: %s", driver, parent, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer driver.Put(parent)
|
||||||
|
|
||||||
|
changes, err := archive.ChangesDirs(layerFs, parentFs)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return archive.ChangesSize(layerFs, changes), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DiffSize calculates the changes between the specified layer
|
||||||
|
// and its parent and returns the size in bytes of the changes
|
||||||
|
// relative to its base filesystem directory.
|
||||||
|
func (gdw *naiveDiffDriver) DiffSize(id, parent string) (bytes int64, err error) {
|
||||||
|
driver := gdw.ProtoDriver
|
||||||
|
|
||||||
|
changes, err := gdw.Changes(id, parent)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
layerFs, err := driver.Get(id, "")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer driver.Put(id)
|
||||||
|
|
||||||
|
return archive.ChangesSize(layerFs, changes), nil
|
||||||
|
}
|
|
@ -19,7 +19,7 @@ func Init(home string, options []string) (graphdriver.Driver, error) {
|
||||||
d := &Driver{
|
d := &Driver{
|
||||||
home: home,
|
home: home,
|
||||||
}
|
}
|
||||||
return d, nil
|
return graphdriver.NaiveDiffDriver(d), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Driver struct {
|
type Driver struct {
|
||||||
|
|
|
@ -100,27 +100,9 @@ func (graph *Graph) Get(name string) (*image.Image, error) {
|
||||||
img.SetGraph(graph)
|
img.SetGraph(graph)
|
||||||
|
|
||||||
if img.Size < 0 {
|
if img.Size < 0 {
|
||||||
rootfs, err := graph.driver.Get(img.ID, "")
|
size, err := graph.driver.DiffSize(img.ID, img.Parent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Driver %s failed to get image rootfs %s: %s", graph.driver, img.ID, err)
|
return nil, fmt.Errorf("unable to calculate size of image id %q: %s", img.ID, err)
|
||||||
}
|
|
||||||
defer graph.driver.Put(img.ID)
|
|
||||||
|
|
||||||
var size int64
|
|
||||||
if img.Parent == "" {
|
|
||||||
if size, err = utils.TreeSize(rootfs); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
parentFs, err := graph.driver.Get(img.Parent, "")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
changes, err := archive.ChangesDirs(rootfs, parentFs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
size = archive.ChangesSize(rootfs, changes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
img.Size = size
|
img.Size = size
|
||||||
|
@ -197,14 +179,9 @@ func (graph *Graph) Register(img *image.Image, jsonData []byte, layerData archiv
|
||||||
if err := graph.driver.Create(img.ID, img.Parent); err != nil {
|
if err := graph.driver.Create(img.ID, img.Parent); err != nil {
|
||||||
return fmt.Errorf("Driver %s failed to create image rootfs %s: %s", graph.driver, img.ID, err)
|
return fmt.Errorf("Driver %s failed to create image rootfs %s: %s", graph.driver, img.ID, err)
|
||||||
}
|
}
|
||||||
// Mount the root filesystem so we can apply the diff/layer
|
// Apply the diff/layer
|
||||||
rootfs, err := graph.driver.Get(img.ID, "")
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Driver %s failed to get image rootfs %s: %s", graph.driver, img.ID, err)
|
|
||||||
}
|
|
||||||
defer graph.driver.Put(img.ID)
|
|
||||||
img.SetGraph(graph)
|
img.SetGraph(graph)
|
||||||
if err := image.StoreImage(img, jsonData, layerData, tmp, rootfs); err != nil {
|
if err := image.StoreImage(img, jsonData, layerData, tmp); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Commit
|
// Commit
|
||||||
|
|
|
@ -10,8 +10,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/docker/archive"
|
"github.com/docker/docker/archive"
|
||||||
"github.com/docker/docker/daemon/graphdriver"
|
|
||||||
"github.com/docker/docker/pkg/ioutils"
|
|
||||||
"github.com/docker/docker/pkg/log"
|
"github.com/docker/docker/pkg/log"
|
||||||
"github.com/docker/docker/runconfig"
|
"github.com/docker/docker/runconfig"
|
||||||
"github.com/docker/docker/utils"
|
"github.com/docker/docker/utils"
|
||||||
|
@ -72,51 +70,18 @@ func LoadImage(root string) (*Image, error) {
|
||||||
return img, nil
|
return img, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func StoreImage(img *Image, jsonData []byte, layerData archive.ArchiveReader, root, layer string) error {
|
func StoreImage(img *Image, jsonData []byte, layerData archive.ArchiveReader, root string) error {
|
||||||
// Store the layer
|
// Store the layer
|
||||||
var (
|
var (
|
||||||
size int64
|
size int64
|
||||||
err error
|
err error
|
||||||
driver = img.graph.Driver()
|
driver = img.graph.Driver()
|
||||||
)
|
)
|
||||||
if err := os.MkdirAll(layer, 0755); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// If layerData is not nil, unpack it into the new layer
|
// If layerData is not nil, unpack it into the new layer
|
||||||
if layerData != nil {
|
if layerData != nil {
|
||||||
if differ, ok := driver.(graphdriver.Differ); ok {
|
if size, err = driver.ApplyDiff(img.ID, img.Parent, layerData); err != nil {
|
||||||
if err := differ.ApplyDiff(img.ID, layerData); err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if size, err = differ.DiffSize(img.ID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
start := time.Now().UTC()
|
|
||||||
log.Debugf("Start untar layer")
|
|
||||||
if err := archive.ApplyLayer(layer, layerData); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Debugf("Untar time: %vs", time.Now().UTC().Sub(start).Seconds())
|
|
||||||
|
|
||||||
if img.Parent == "" {
|
|
||||||
if size, err = utils.TreeSize(layer); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
parent, err := driver.Get(img.Parent, "")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer driver.Put(img.Parent)
|
|
||||||
changes, err := archive.ChangesDirs(layer, parent)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
size = archive.ChangesSize(layer, changes)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,52 +143,10 @@ func (img *Image) TarLayer() (arch archive.Archive, err error) {
|
||||||
if img.graph == nil {
|
if img.graph == nil {
|
||||||
return nil, fmt.Errorf("Can't load storage driver for unregistered image %s", img.ID)
|
return nil, fmt.Errorf("Can't load storage driver for unregistered image %s", img.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
driver := img.graph.Driver()
|
driver := img.graph.Driver()
|
||||||
if differ, ok := driver.(graphdriver.Differ); ok {
|
|
||||||
return differ.Diff(img.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
imgFs, err := driver.Get(img.ID, "")
|
return driver.Diff(img.ID, img.Parent)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
driver.Put(img.ID)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if img.Parent == "" {
|
|
||||||
archive, err := archive.Tar(imgFs, archive.Uncompressed)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return ioutils.NewReadCloserWrapper(archive, func() error {
|
|
||||||
err := archive.Close()
|
|
||||||
driver.Put(img.ID)
|
|
||||||
return err
|
|
||||||
}), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
parentFs, err := driver.Get(img.Parent, "")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer driver.Put(img.Parent)
|
|
||||||
changes, err := archive.ChangesDirs(imgFs, parentFs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
archive, err := archive.ExportChanges(imgFs, changes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return ioutils.NewReadCloserWrapper(archive, func() error {
|
|
||||||
err := archive.Close()
|
|
||||||
driver.Put(img.ID)
|
|
||||||
return err
|
|
||||||
}), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Image includes convenience proxy functions to its graph
|
// Image includes convenience proxy functions to its graph
|
||||||
|
|
Loading…
Reference in New Issue