X Tutup
Skip to content

Commit 78bd07a

Browse files
Merge pull request containerd#1746 from AkihiroSuda/split-differ-interface
diff: resplit Applier from Differ
2 parents 13733b6 + b763777 commit 78bd07a

File tree

13 files changed

+228
-147
lines changed

13 files changed

+228
-147
lines changed

client.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222
"github.com/containerd/containerd/containers"
2323
"github.com/containerd/containerd/content"
2424
"github.com/containerd/containerd/dialer"
25-
"github.com/containerd/containerd/diff"
2625
"github.com/containerd/containerd/errdefs"
2726
"github.com/containerd/containerd/images"
2827
"github.com/containerd/containerd/namespaces"
@@ -412,7 +411,7 @@ func (c *Client) ImageService() images.Store {
412411
}
413412

414413
// DiffService returns the underlying Differ
415-
func (c *Client) DiffService() diff.Differ {
414+
func (c *Client) DiffService() DiffService {
416415
return NewDiffServiceFromClient(diffapi.NewDiffClient(c.conn))
417416
}
418417

cmd/containerd/builtins.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package main
22

33
// register containerd builtins here
44
import (
5-
_ "github.com/containerd/containerd/diff/walking"
5+
_ "github.com/containerd/containerd/diff/walking/plugin"
66
_ "github.com/containerd/containerd/gc/scheduler"
77
_ "github.com/containerd/containerd/services/containers"
88
_ "github.com/containerd/containerd/services/content"

cmd/ctr/commands/snapshots/snapshots.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ var diffCommand = cli.Command{
129129
}
130130

131131
if idB == "" {
132-
desc, err = rootfs.Diff(ctx, idA, snapshotter, client.DiffService(), opts...)
132+
desc, err = rootfs.CreateDiff(ctx, idA, snapshotter, client.DiffService(), opts...)
133133
if err != nil {
134134
return err
135135
}
@@ -145,7 +145,7 @@ var diffCommand = cli.Command{
145145
if err != nil {
146146
return err
147147
}
148-
desc, err = ds.DiffMounts(ctx, a, b, opts...)
148+
desc, err = ds.Compare(ctx, a, b, opts...)
149149
if err != nil {
150150
return err
151151
}

diff.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
11
package containerd
22

33
import (
4+
"context"
5+
46
diffapi "github.com/containerd/containerd/api/services/diff/v1"
57
"github.com/containerd/containerd/api/types"
68
"github.com/containerd/containerd/diff"
79
"github.com/containerd/containerd/mount"
810
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
9-
"golang.org/x/net/context"
1011
)
1112

13+
// DiffService handles the computation and application of diffs
14+
type DiffService interface {
15+
diff.Comparer
16+
diff.Applier
17+
}
18+
1219
// NewDiffServiceFromClient returns a new diff service which communicates
1320
// over a GRPC connection.
14-
func NewDiffServiceFromClient(client diffapi.DiffClient) diff.Differ {
21+
func NewDiffServiceFromClient(client diffapi.DiffClient) DiffService {
1522
return &diffRemote{
1623
client: client,
1724
}
@@ -33,7 +40,7 @@ func (r *diffRemote) Apply(ctx context.Context, diff ocispec.Descriptor, mounts
3340
return toDescriptor(resp.Applied), nil
3441
}
3542

36-
func (r *diffRemote) DiffMounts(ctx context.Context, a, b []mount.Mount, opts ...diff.Opt) (ocispec.Descriptor, error) {
43+
func (r *diffRemote) Compare(ctx context.Context, a, b []mount.Mount, opts ...diff.Opt) (ocispec.Descriptor, error) {
3744
var config diff.Config
3845
for _, opt := range opts {
3946
if err := opt(&config); err != nil {

diff/apply/apply.go

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package apply
2+
3+
import (
4+
"context"
5+
"io"
6+
"io/ioutil"
7+
"time"
8+
9+
"github.com/containerd/containerd/archive"
10+
"github.com/containerd/containerd/archive/compression"
11+
"github.com/containerd/containerd/content"
12+
"github.com/containerd/containerd/diff"
13+
"github.com/containerd/containerd/errdefs"
14+
"github.com/containerd/containerd/images"
15+
"github.com/containerd/containerd/log"
16+
"github.com/containerd/containerd/mount"
17+
digest "github.com/opencontainers/go-digest"
18+
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
19+
"github.com/pkg/errors"
20+
"github.com/sirupsen/logrus"
21+
)
22+
23+
// NewFileSystemApplier returns an applier which simply mounts
24+
// and applies diff onto the mounted filesystem.
25+
func NewFileSystemApplier(cs content.Store) diff.Applier {
26+
return &fsApplier{
27+
store: cs,
28+
}
29+
}
30+
31+
type fsApplier struct {
32+
store content.Store
33+
}
34+
35+
var emptyDesc = ocispec.Descriptor{}
36+
37+
// Apply applies the content associated with the provided digests onto the
38+
// provided mounts. Archive content will be extracted and decompressed if
39+
// necessary.
40+
func (s *fsApplier) Apply(ctx context.Context, desc ocispec.Descriptor, mounts []mount.Mount) (d ocispec.Descriptor, err error) {
41+
t1 := time.Now()
42+
defer func() {
43+
if err == nil {
44+
log.G(ctx).WithFields(logrus.Fields{
45+
"d": time.Now().Sub(t1),
46+
"dgst": desc.Digest,
47+
"size": desc.Size,
48+
"media": desc.MediaType,
49+
}).Debugf("diff applied")
50+
}
51+
}()
52+
53+
isCompressed, err := images.IsCompressedDiff(ctx, desc.MediaType)
54+
if err != nil {
55+
return emptyDesc, errors.Wrapf(errdefs.ErrNotImplemented, "unsupported diff media type: %v", desc.MediaType)
56+
}
57+
58+
var ocidesc ocispec.Descriptor
59+
if err := mount.WithTempMount(ctx, mounts, func(root string) error {
60+
ra, err := s.store.ReaderAt(ctx, desc.Digest)
61+
if err != nil {
62+
return errors.Wrap(err, "failed to get reader from content store")
63+
}
64+
defer ra.Close()
65+
66+
r := content.NewReader(ra)
67+
if isCompressed {
68+
ds, err := compression.DecompressStream(r)
69+
if err != nil {
70+
return err
71+
}
72+
defer ds.Close()
73+
r = ds
74+
}
75+
76+
digester := digest.Canonical.Digester()
77+
rc := &readCounter{
78+
r: io.TeeReader(r, digester.Hash()),
79+
}
80+
81+
if _, err := archive.Apply(ctx, root, rc); err != nil {
82+
return err
83+
}
84+
85+
// Read any trailing data
86+
if _, err := io.Copy(ioutil.Discard, rc); err != nil {
87+
return err
88+
}
89+
90+
ocidesc = ocispec.Descriptor{
91+
MediaType: ocispec.MediaTypeImageLayer,
92+
Size: rc.c,
93+
Digest: digester.Digest(),
94+
}
95+
return nil
96+
97+
}); err != nil {
98+
return emptyDesc, err
99+
}
100+
return ocidesc, nil
101+
}
102+
103+
type readCounter struct {
104+
r io.Reader
105+
c int64
106+
}
107+
108+
func (rc *readCounter) Read(p []byte) (n int, err error) {
109+
n, err = rc.r.Read(p)
110+
rc.c += int64(n)
111+
return
112+
}

diff/diff.go

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package diff
22

33
import (
4+
"context"
5+
46
"github.com/containerd/containerd/mount"
57
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
6-
"golang.org/x/net/context"
78
)
89

910
// Config is used to hold parameters needed for a diff operation
@@ -24,21 +25,24 @@ type Config struct {
2425
// Opt is used to configure a diff operation
2526
type Opt func(*Config) error
2627

27-
// Differ allows the apply and creation of filesystem diffs between mounts
28-
type Differ interface {
28+
// Comparer allows creation of filesystem diffs between mounts
29+
type Comparer interface {
30+
// Compare computes the difference between two mounts and returns a
31+
// descriptor for the computed diff. The options can provide
32+
// a ref which can be used to track the content creation of the diff.
33+
// The media type which is used to determine the format of the created
34+
// content can also be provided as an option.
35+
Compare(ctx context.Context, lower, upper []mount.Mount, opts ...Opt) (ocispec.Descriptor, error)
36+
}
37+
38+
// Applier allows applying diffs between mounts
39+
type Applier interface {
2940
// Apply applies the content referred to by the given descriptor to
3041
// the provided mount. The method of applying is based on the
3142
// implementation and content descriptor. For example, in the common
3243
// case the descriptor is a file system difference in tar format,
3344
// that tar would be applied on top of the mounts.
3445
Apply(ctx context.Context, desc ocispec.Descriptor, mount []mount.Mount) (ocispec.Descriptor, error)
35-
36-
// DiffMounts computes the difference between two mounts and returns a
37-
// descriptor for the computed diff. The options can provide
38-
// a ref which can be used to track the content creation of the diff.
39-
// The media type which is used to determine the format of the created
40-
// content can also be provided as an option.
41-
DiffMounts(ctx context.Context, lower, upper []mount.Mount, opts ...Opt) (ocispec.Descriptor, error)
4246
}
4347

4448
// WithMediaType sets the media type to use for creating the diff, without

0 commit comments

Comments
 (0)
X Tutup