Browse code

Refactor use of graphdriver.Differ

Some graphdrivers are Differs and type assertions are made
in various places throughout the project. Differ offers some
convenience in generating/applying diffs of filesystem layers
but for most graphdrivers another code path is taken.

This patch brings all of the logic related to filesystem
diffs in one place, and simplifies the implementation of some
common types like Image, Daemon, and Container.

Signed-off-by: Josh Hawn <josh.hawn@docker.com>

Josh Hawn authored on 2014/09/11 12:30:52
Showing 12 changed files
... ...
@@ -313,7 +313,8 @@ func collectFileInfo(sourceDir string) (*FileInfo, error) {
313 313
 	return root, nil
314 314
 }
315 315
 
316
-// Compare two directories and generate an array of Change objects describing the changes
316
+// ChangesDirs compares two directories and generates an array of Change objects describing the changes.
317
+// If oldDir is "", then all files in newDir will be Add-Changes.
317 318
 func ChangesDirs(newDir, oldDir string) ([]Change, error) {
318 319
 	var (
319 320
 		oldRoot, newRoot *FileInfo
... ...
@@ -321,7 +322,9 @@ func ChangesDirs(newDir, oldDir string) ([]Change, error) {
321 321
 		errs             = make(chan error, 2)
322 322
 	)
323 323
 	go func() {
324
-		oldRoot, err1 = collectFileInfo(oldDir)
324
+		if oldDir != "" {
325
+			oldRoot, err1 = collectFileInfo(oldDir)
326
+		}
325 327
 		errs <- err1
326 328
 	}()
327 329
 	go func() {
... ...
@@ -18,7 +18,6 @@ import (
18 18
 
19 19
 	"github.com/docker/docker/archive"
20 20
 	"github.com/docker/docker/daemon/execdriver"
21
-	"github.com/docker/docker/daemon/graphdriver"
22 21
 	"github.com/docker/docker/engine"
23 22
 	"github.com/docker/docker/image"
24 23
 	"github.com/docker/docker/links"
... ...
@@ -755,21 +754,13 @@ func (container *Container) GetSize() (int64, int64) {
755 755
 	}
756 756
 	defer container.Unmount()
757 757
 
758
-	if differ, ok := driver.(graphdriver.Differ); ok {
759
-		sizeRw, err = differ.DiffSize(container.ID)
760
-		if err != nil {
761
-			log.Errorf("Warning: driver %s couldn't return diff size of container %s: %s", driver, container.ID, err)
762
-			// FIXME: GetSize should return an error. Not changing it now in case
763
-			// there is a side-effect.
764
-			sizeRw = -1
765
-		}
766
-	} else {
767
-		changes, _ := container.changes()
768
-		if changes != nil {
769
-			sizeRw = archive.ChangesSize(container.basefs, changes)
770
-		} else {
771
-			sizeRw = -1
772
-		}
758
+	initID := fmt.Sprintf("%s-init", container.ID)
759
+	sizeRw, err = driver.DiffSize(container.ID, initID)
760
+	if err != nil {
761
+		log.Errorf("Warning: driver %s couldn't return diff size of container %s: %s", driver, container.ID, err)
762
+		// FIXME: GetSize should return an error. Not changing it now in case
763
+		// there is a side-effect.
764
+		sizeRw = -1
773 765
 	}
774 766
 
775 767
 	if _, err = os.Stat(container.basefs); err != nil {
... ...
@@ -937,46 +937,13 @@ func (daemon *Daemon) Unmount(container *Container) error {
937 937
 }
938 938
 
939 939
 func (daemon *Daemon) Changes(container *Container) ([]archive.Change, error) {
940
-	if differ, ok := daemon.driver.(graphdriver.Differ); ok {
941
-		return differ.Changes(container.ID)
942
-	}
943
-	cDir, err := daemon.driver.Get(container.ID, "")
944
-	if err != nil {
945
-		return nil, fmt.Errorf("Error getting container rootfs %s from driver %s: %s", container.ID, container.daemon.driver, err)
946
-	}
947
-	defer daemon.driver.Put(container.ID)
948
-	initDir, err := daemon.driver.Get(container.ID+"-init", "")
949
-	if err != nil {
950
-		return nil, fmt.Errorf("Error getting container init rootfs %s from driver %s: %s", container.ID, container.daemon.driver, err)
951
-	}
952
-	defer daemon.driver.Put(container.ID + "-init")
953
-	return archive.ChangesDirs(cDir, initDir)
940
+	initID := fmt.Sprintf("%s-init", container.ID)
941
+	return daemon.driver.Changes(container.ID, initID)
954 942
 }
955 943
 
956 944
 func (daemon *Daemon) Diff(container *Container) (archive.Archive, error) {
957
-	if differ, ok := daemon.driver.(graphdriver.Differ); ok {
958
-		return differ.Diff(container.ID)
959
-	}
960
-
961
-	changes, err := daemon.Changes(container)
962
-	if err != nil {
963
-		return nil, err
964
-	}
965
-
966
-	cDir, err := daemon.driver.Get(container.ID, "")
967
-	if err != nil {
968
-		return nil, fmt.Errorf("Error getting container rootfs %s from driver %s: %s", container.ID, container.daemon.driver, err)
969
-	}
970
-
971
-	archive, err := archive.ExportChanges(cDir, changes)
972
-	if err != nil {
973
-		return nil, err
974
-	}
975
-	return ioutils.NewReadCloserWrapper(archive, func() error {
976
-		err := archive.Close()
977
-		daemon.driver.Put(container.ID)
978
-		return err
979
-	}), nil
945
+	initID := fmt.Sprintf("%s-init", container.ID)
946
+	return daemon.driver.Diff(container.ID, initID)
980 947
 }
981 948
 
982 949
 func (daemon *Daemon) Run(c *Container, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
... ...
@@ -294,23 +294,44 @@ func (a *Driver) Put(id string) {
294 294
 	}
295 295
 }
296 296
 
297
-// Returns an archive of the contents for the id
298
-func (a *Driver) Diff(id string) (archive.Archive, error) {
297
+// Diff produces an archive of the changes between the specified
298
+// layer and its parent layer which may be "".
299
+func (a *Driver) Diff(id, parent string) (archive.Archive, error) {
300
+	// AUFS doesn't need the parent layer to produce a diff.
299 301
 	return archive.TarWithOptions(path.Join(a.rootPath(), "diff", id), &archive.TarOptions{
300 302
 		Compression: archive.Uncompressed,
301 303
 	})
302 304
 }
303 305
 
304
-func (a *Driver) ApplyDiff(id string, diff archive.ArchiveReader) error {
306
+func (a *Driver) applyDiff(id string, diff archive.ArchiveReader) error {
305 307
 	return archive.Untar(diff, path.Join(a.rootPath(), "diff", id), nil)
306 308
 }
307 309
 
308
-// Returns the size of the contents for the id
309
-func (a *Driver) DiffSize(id string) (int64, error) {
310
+// DiffSize calculates the changes between the specified id
311
+// and its parent and returns the size in bytes of the changes
312
+// relative to its base filesystem directory.
313
+func (a *Driver) DiffSize(id, parent string) (bytes int64, err error) {
314
+	// AUFS doesn't need the parent layer to calculate the diff size.
310 315
 	return utils.TreeSize(path.Join(a.rootPath(), "diff", id))
311 316
 }
312 317
 
313
-func (a *Driver) Changes(id string) ([]archive.Change, error) {
318
+// ApplyDiff extracts the changeset from the given diff into the
319
+// layer with the specified id and parent, returning the size of the
320
+// new layer in bytes.
321
+func (a *Driver) ApplyDiff(id, parent string, diff archive.ArchiveReader) (bytes int64, err error) {
322
+	// AUFS doesn't need the parent id to apply the diff.
323
+	if err = a.applyDiff(id, diff); err != nil {
324
+		return
325
+	}
326
+
327
+	return a.DiffSize(id, parent)
328
+}
329
+
330
+// Changes produces a list of changes between the specified layer
331
+// and its parent layer. If parent is "", then all changes will be ADD changes.
332
+func (a *Driver) Changes(id, parent string) ([]archive.Change, error) {
333
+	// AUFS doesn't have snapshots, so we need to get changes from all parent
334
+	// layers.
314 335
 	layers, err := a.getParentLayerPaths(id)
315 336
 	if err != nil {
316 337
 		return nil, err
... ...
@@ -323,9 +344,6 @@ func (a *Driver) getParentLayerPaths(id string) ([]string, error) {
323 323
 	if err != nil {
324 324
 		return nil, err
325 325
 	}
326
-	if len(parentIds) == 0 {
327
-		return nil, fmt.Errorf("Dir %s does not have any parent layers", id)
328
-	}
329 326
 	layers := make([]string, len(parentIds))
330 327
 
331 328
 	// Get the diff paths for all the parent ids
... ...
@@ -330,7 +330,7 @@ func TestGetDiff(t *testing.T) {
330 330
 	}
331 331
 	f.Close()
332 332
 
333
-	a, err := d.Diff("1")
333
+	a, err := d.Diff("1", "")
334 334
 	if err != nil {
335 335
 		t.Fatal(err)
336 336
 	}
... ...
@@ -374,7 +374,7 @@ func TestChanges(t *testing.T) {
374 374
 		t.Fatal(err)
375 375
 	}
376 376
 
377
-	changes, err := d.Changes("2")
377
+	changes, err := d.Changes("2", "")
378 378
 	if err != nil {
379 379
 		t.Fatal(err)
380 380
 	}
... ...
@@ -413,7 +413,7 @@ func TestChanges(t *testing.T) {
413 413
 		t.Fatal(err)
414 414
 	}
415 415
 
416
-	changes, err = d.Changes("3")
416
+	changes, err = d.Changes("3", "")
417 417
 	if err != nil {
418 418
 		t.Fatal(err)
419 419
 	}
... ...
@@ -465,7 +465,7 @@ func TestDiffSize(t *testing.T) {
465 465
 		t.Fatal(err)
466 466
 	}
467 467
 
468
-	diffSize, err := d.DiffSize("1")
468
+	diffSize, err := d.DiffSize("1", "")
469 469
 	if err != nil {
470 470
 		t.Fatal(err)
471 471
 	}
... ...
@@ -507,7 +507,7 @@ func TestChildDiffSize(t *testing.T) {
507 507
 		t.Fatal(err)
508 508
 	}
509 509
 
510
-	diffSize, err := d.DiffSize("1")
510
+	diffSize, err := d.DiffSize("1", "")
511 511
 	if err != nil {
512 512
 		t.Fatal(err)
513 513
 	}
... ...
@@ -519,7 +519,7 @@ func TestChildDiffSize(t *testing.T) {
519 519
 		t.Fatal(err)
520 520
 	}
521 521
 
522
-	diffSize, err = d.DiffSize("2")
522
+	diffSize, err = d.DiffSize("2", "")
523 523
 	if err != nil {
524 524
 		t.Fatal(err)
525 525
 	}
... ...
@@ -602,7 +602,7 @@ func TestApplyDiff(t *testing.T) {
602 602
 	}
603 603
 	f.Close()
604 604
 
605
-	diff, err := d.Diff("1")
605
+	diff, err := d.Diff("1", "")
606 606
 	if err != nil {
607 607
 		t.Fatal(err)
608 608
 	}
... ...
@@ -614,7 +614,7 @@ func TestApplyDiff(t *testing.T) {
614 614
 		t.Fatal(err)
615 615
 	}
616 616
 
617
-	if err := d.ApplyDiff("3", diff); err != nil {
617
+	if err := d.applyDiff("3", diff); err != nil {
618 618
 		t.Fatal(err)
619 619
 	}
620 620
 
... ...
@@ -44,9 +44,11 @@ func Init(home string, options []string) (graphdriver.Driver, error) {
44 44
 		return nil, err
45 45
 	}
46 46
 
47
-	return &Driver{
47
+	driver := &Driver{
48 48
 		home: home,
49
-	}, nil
49
+	}
50
+
51
+	return graphdriver.NewGenericDriverWrapper(driver), nil
50 52
 }
51 53
 
52 54
 type Driver struct {
... ...
@@ -43,7 +43,7 @@ func Init(home string, options []string) (graphdriver.Driver, error) {
43 43
 		home:      home,
44 44
 	}
45 45
 
46
-	return d, nil
46
+	return graphdriver.NewGenericDriverWrapper(d), nil
47 47
 }
48 48
 
49 49
 func (d *Driver) String() string {
... ...
@@ -19,26 +19,55 @@ const (
19 19
 
20 20
 type InitFunc func(root string, options []string) (Driver, error)
21 21
 
22
-type Driver interface {
22
+// GenericDriver defines the basic capabilities of a driver.
23
+type GenericDriver interface {
24
+	// String returns a string representation of this driver.
23 25
 	String() string
24 26
 
27
+	// Create creates a new, empty, filesystem layer with the
28
+	// specified id and parent. Parent may be "".
25 29
 	Create(id, parent string) error
30
+	// Remove attepmts to remove the filesystem layer with this id.
26 31
 	Remove(id string) error
27 32
 
33
+	// Get returns the mountpoint for the layered filesystem referred
34
+	// to by this id. You can optionally specify a mountLabel or "".
35
+	// Returns the absolute path to the mounted layered filesystem.
28 36
 	Get(id, mountLabel string) (dir string, err error)
37
+	// Put releases the system resources for the specified id,
38
+	// e.g, unmounting layered filesystem.
29 39
 	Put(id string)
40
+	// Exists returns whether a filesystem layer with the specified
41
+	// ID exists on this driver.
30 42
 	Exists(id string) bool
31 43
 
44
+	// Status returns a set of key-value pairs which give low
45
+	// level diagnostic status about this driver.
32 46
 	Status() [][2]string
33 47
 
48
+	// Cleanup performs necessary tasks to release resources
49
+	// held by the driver, e.g., unmounting all layered filesystems
50
+	// known to this driver.
34 51
 	Cleanup() error
35 52
 }
36 53
 
37
-type Differ interface {
38
-	Diff(id string) (archive.Archive, error)
39
-	Changes(id string) ([]archive.Change, error)
40
-	ApplyDiff(id string, diff archive.ArchiveReader) error
41
-	DiffSize(id string) (bytes int64, err error)
54
+type Driver interface {
55
+	GenericDriver
56
+
57
+	// Diff produces an archive of the changes between the specified
58
+	// layer and its parent layer which may be "".
59
+	Diff(id, parent string) (archive.Archive, error)
60
+	// Changes produces a list of changes between the specified layer
61
+	// and its parent layer. If parent is "", then all changes will be ADD changes.
62
+	Changes(id, parent string) ([]archive.Change, error)
63
+	// ApplyDiff extracts the changeset from the given diff into the
64
+	// layer with the specified id and parent, returning the size of the
65
+	// new layer in bytes.
66
+	ApplyDiff(id, parent string, diff archive.ArchiveReader) (bytes int64, err error)
67
+	// DiffSize calculates the changes between the specified id
68
+	// and its parent and returns the size in bytes of the changes
69
+	// relative to its base filesystem directory.
70
+	DiffSize(id, parent string) (bytes int64, err error)
42 71
 }
43 72
 
44 73
 var (
45 74
new file mode 100644
... ...
@@ -0,0 +1,162 @@
0
+package graphdriver
1
+
2
+import (
3
+	"fmt"
4
+	"time"
5
+
6
+	"github.com/docker/docker/archive"
7
+	"github.com/docker/docker/pkg/ioutils"
8
+	"github.com/docker/docker/pkg/log"
9
+	"github.com/docker/docker/utils"
10
+)
11
+
12
+// GenericDriverWrapper takes a generic Driver and adds the
13
+// capability of the following methods which it doesn't
14
+// support on its own:
15
+//     Diff(id, parent string) (archive.Archive, error)
16
+//     Changes(id, parent string) ([]archive.Change, error)
17
+//     ApplyDiff(id, parent string, diff archive.ArchiveReader) (bytes int64, err error)
18
+//     DiffSize(id, parent string) (bytes int64, err error)
19
+// Notably, the AUFS driver doesn't need to be wrapped like this.
20
+type GenericDriverWrapper struct {
21
+	GenericDriver
22
+}
23
+
24
+// NewGenericDriverWrapper returns a fully functional driver that wraps the given GenericDriver.
25
+func NewGenericDriverWrapper(driver GenericDriver) Driver {
26
+	return &GenericDriverWrapper{GenericDriver: driver}
27
+}
28
+
29
+// Diff produces an archive of the changes between the specified
30
+// layer and its parent layer which may be "".
31
+func (gdw *GenericDriverWrapper) Diff(id, parent string) (arch archive.Archive, err error) {
32
+	driver := gdw.GenericDriver
33
+
34
+	layerFs, err := driver.Get(id, "")
35
+	if err != nil {
36
+		return nil, err
37
+	}
38
+
39
+	defer func() {
40
+		if err != nil {
41
+			driver.Put(id)
42
+		}
43
+	}()
44
+
45
+	if parent == "" {
46
+		archive, err := archive.Tar(layerFs, archive.Uncompressed)
47
+		if err != nil {
48
+			return nil, err
49
+		}
50
+		return ioutils.NewReadCloserWrapper(archive, func() error {
51
+			err := archive.Close()
52
+			driver.Put(id)
53
+			return err
54
+		}), nil
55
+	}
56
+
57
+	parentFs, err := driver.Get(parent, "")
58
+	if err != nil {
59
+		return nil, err
60
+	}
61
+	defer driver.Put(parent)
62
+
63
+	changes, err := archive.ChangesDirs(layerFs, parentFs)
64
+	if err != nil {
65
+		return nil, err
66
+	}
67
+
68
+	archive, err := archive.ExportChanges(layerFs, changes)
69
+	if err != nil {
70
+		return nil, err
71
+	}
72
+
73
+	return ioutils.NewReadCloserWrapper(archive, func() error {
74
+		err := archive.Close()
75
+		driver.Put(id)
76
+		return err
77
+	}), nil
78
+}
79
+
80
+// Changes produces a list of changes between the specified layer
81
+// and its parent layer. If parent is "", then all changes will be ADD changes.
82
+func (gdw *GenericDriverWrapper) Changes(id, parent string) ([]archive.Change, error) {
83
+	driver := gdw.GenericDriver
84
+
85
+	layerFs, err := driver.Get(id, "")
86
+	if err != nil {
87
+		return nil, err
88
+	}
89
+	defer driver.Put(id)
90
+
91
+	parentFs := ""
92
+
93
+	if parent != "" {
94
+		parentFs, err = driver.Get(parent, "")
95
+		if err != nil {
96
+			return nil, err
97
+		}
98
+		defer driver.Put(parent)
99
+	}
100
+
101
+	return archive.ChangesDirs(layerFs, parentFs)
102
+}
103
+
104
+// ApplyDiff extracts the changeset from the given diff into the
105
+// layer with the specified id and parent, returning the size of the
106
+// new layer in bytes.
107
+func (gdw *GenericDriverWrapper) ApplyDiff(id, parent string, diff archive.ArchiveReader) (bytes int64, err error) {
108
+	driver := gdw.GenericDriver
109
+
110
+	// Mount the root filesystem so we can apply the diff/layer.
111
+	layerFs, err := driver.Get(id, "")
112
+	if err != nil {
113
+		return
114
+	}
115
+	defer driver.Put(id)
116
+
117
+	start := time.Now().UTC()
118
+	log.Debugf("Start untar layer")
119
+	if err = archive.ApplyLayer(layerFs, diff); err != nil {
120
+		return
121
+	}
122
+	log.Debugf("Untar time: %vs", time.Now().UTC().Sub(start).Seconds())
123
+
124
+	if parent == "" {
125
+		return utils.TreeSize(layerFs)
126
+	}
127
+
128
+	parentFs, err := driver.Get(parent, "")
129
+	if err != nil {
130
+		err = fmt.Errorf("Driver %s failed to get image parent %s: %s", driver, parent, err)
131
+		return
132
+	}
133
+	defer driver.Put(parent)
134
+
135
+	changes, err := archive.ChangesDirs(layerFs, parentFs)
136
+	if err != nil {
137
+		return
138
+	}
139
+
140
+	return archive.ChangesSize(layerFs, changes), nil
141
+}
142
+
143
+// DiffSize calculates the changes between the specified layer
144
+// and its parent and returns the size in bytes of the changes
145
+// relative to its base filesystem directory.
146
+func (gdw *GenericDriverWrapper) DiffSize(id, parent string) (bytes int64, err error) {
147
+	driver := gdw.GenericDriver
148
+
149
+	changes, err := gdw.Changes(id, parent)
150
+	if err != nil {
151
+		return
152
+	}
153
+
154
+	layerFs, err := driver.Get(id, "")
155
+	if err != nil {
156
+		return
157
+	}
158
+	defer driver.Put(id)
159
+
160
+	return archive.ChangesSize(layerFs, changes), nil
161
+}
... ...
@@ -19,7 +19,7 @@ func Init(home string, options []string) (graphdriver.Driver, error) {
19 19
 	d := &Driver{
20 20
 		home: home,
21 21
 	}
22
-	return d, nil
22
+	return graphdriver.NewGenericDriverWrapper(d), nil
23 23
 }
24 24
 
25 25
 type Driver struct {
... ...
@@ -100,27 +100,9 @@ func (graph *Graph) Get(name string) (*image.Image, error) {
100 100
 	img.SetGraph(graph)
101 101
 
102 102
 	if img.Size < 0 {
103
-		rootfs, err := graph.driver.Get(img.ID, "")
103
+		size, err := graph.driver.DiffSize(img.ID, img.Parent)
104 104
 		if err != nil {
105
-			return nil, fmt.Errorf("Driver %s failed to get image rootfs %s: %s", graph.driver, img.ID, err)
106
-		}
107
-		defer graph.driver.Put(img.ID)
108
-
109
-		var size int64
110
-		if img.Parent == "" {
111
-			if size, err = utils.TreeSize(rootfs); err != nil {
112
-				return nil, err
113
-			}
114
-		} else {
115
-			parentFs, err := graph.driver.Get(img.Parent, "")
116
-			if err != nil {
117
-				return nil, err
118
-			}
119
-			changes, err := archive.ChangesDirs(rootfs, parentFs)
120
-			if err != nil {
121
-				return nil, err
122
-			}
123
-			size = archive.ChangesSize(rootfs, changes)
105
+			return nil, fmt.Errorf("unable to calculate size of image id %q: %s", img.ID, err)
124 106
 		}
125 107
 
126 108
 		img.Size = size
... ...
@@ -197,14 +179,9 @@ func (graph *Graph) Register(img *image.Image, jsonData []byte, layerData archiv
197 197
 	if err := graph.driver.Create(img.ID, img.Parent); err != nil {
198 198
 		return fmt.Errorf("Driver %s failed to create image rootfs %s: %s", graph.driver, img.ID, err)
199 199
 	}
200
-	// Mount the root filesystem so we can apply the diff/layer
201
-	rootfs, err := graph.driver.Get(img.ID, "")
202
-	if err != nil {
203
-		return fmt.Errorf("Driver %s failed to get image rootfs %s: %s", graph.driver, img.ID, err)
204
-	}
205
-	defer graph.driver.Put(img.ID)
200
+	// Apply the diff/layer
206 201
 	img.SetGraph(graph)
207
-	if err := image.StoreImage(img, jsonData, layerData, tmp, rootfs); err != nil {
202
+	if err := image.StoreImage(img, jsonData, layerData, tmp); err != nil {
208 203
 		return err
209 204
 	}
210 205
 	// Commit
... ...
@@ -10,8 +10,6 @@ import (
10 10
 	"time"
11 11
 
12 12
 	"github.com/docker/docker/archive"
13
-	"github.com/docker/docker/daemon/graphdriver"
14
-	"github.com/docker/docker/pkg/ioutils"
15 13
 	"github.com/docker/docker/pkg/log"
16 14
 	"github.com/docker/docker/runconfig"
17 15
 	"github.com/docker/docker/utils"
... ...
@@ -72,51 +70,18 @@ func LoadImage(root string) (*Image, error) {
72 72
 	return img, nil
73 73
 }
74 74
 
75
-func StoreImage(img *Image, jsonData []byte, layerData archive.ArchiveReader, root, layer string) error {
75
+func StoreImage(img *Image, jsonData []byte, layerData archive.ArchiveReader, root string) error {
76 76
 	// Store the layer
77 77
 	var (
78 78
 		size   int64
79 79
 		err    error
80 80
 		driver = img.graph.Driver()
81 81
 	)
82
-	if err := os.MkdirAll(layer, 0755); err != nil {
83
-		return err
84
-	}
85 82
 
86 83
 	// If layerData is not nil, unpack it into the new layer
87 84
 	if layerData != nil {
88
-		if differ, ok := driver.(graphdriver.Differ); ok {
89
-			if err := differ.ApplyDiff(img.ID, layerData); err != nil {
90
-				return err
91
-			}
92
-
93
-			if size, err = differ.DiffSize(img.ID); err != nil {
94
-				return err
95
-			}
96
-		} else {
97
-			start := time.Now().UTC()
98
-			log.Debugf("Start untar layer")
99
-			if err := archive.ApplyLayer(layer, layerData); err != nil {
100
-				return err
101
-			}
102
-			log.Debugf("Untar time: %vs", time.Now().UTC().Sub(start).Seconds())
103
-
104
-			if img.Parent == "" {
105
-				if size, err = utils.TreeSize(layer); err != nil {
106
-					return err
107
-				}
108
-			} else {
109
-				parent, err := driver.Get(img.Parent, "")
110
-				if err != nil {
111
-					return err
112
-				}
113
-				defer driver.Put(img.Parent)
114
-				changes, err := archive.ChangesDirs(layer, parent)
115
-				if err != nil {
116
-					return err
117
-				}
118
-				size = archive.ChangesSize(layer, changes)
119
-			}
85
+		if size, err = driver.ApplyDiff(img.ID, img.Parent, layerData); err != nil {
86
+			return err
120 87
 		}
121 88
 	}
122 89
 
... ...
@@ -178,52 +143,10 @@ func (img *Image) TarLayer() (arch archive.Archive, err error) {
178 178
 	if img.graph == nil {
179 179
 		return nil, fmt.Errorf("Can't load storage driver for unregistered image %s", img.ID)
180 180
 	}
181
-	driver := img.graph.Driver()
182
-	if differ, ok := driver.(graphdriver.Differ); ok {
183
-		return differ.Diff(img.ID)
184
-	}
185
-
186
-	imgFs, err := driver.Get(img.ID, "")
187
-	if err != nil {
188
-		return nil, err
189
-	}
190
-
191
-	defer func() {
192
-		if err != nil {
193
-			driver.Put(img.ID)
194
-		}
195
-	}()
196 181
 
197
-	if img.Parent == "" {
198
-		archive, err := archive.Tar(imgFs, archive.Uncompressed)
199
-		if err != nil {
200
-			return nil, err
201
-		}
202
-		return ioutils.NewReadCloserWrapper(archive, func() error {
203
-			err := archive.Close()
204
-			driver.Put(img.ID)
205
-			return err
206
-		}), nil
207
-	}
182
+	driver := img.graph.Driver()
208 183
 
209
-	parentFs, err := driver.Get(img.Parent, "")
210
-	if err != nil {
211
-		return nil, err
212
-	}
213
-	defer driver.Put(img.Parent)
214
-	changes, err := archive.ChangesDirs(imgFs, parentFs)
215
-	if err != nil {
216
-		return nil, err
217
-	}
218
-	archive, err := archive.ExportChanges(imgFs, changes)
219
-	if err != nil {
220
-		return nil, err
221
-	}
222
-	return ioutils.NewReadCloserWrapper(archive, func() error {
223
-		err := archive.Close()
224
-		driver.Put(img.ID)
225
-		return err
226
-	}), nil
184
+	return driver.Diff(img.ID, img.Parent)
227 185
 }
228 186
 
229 187
 // Image includes convenience proxy functions to its graph