Skip to content

Commit

Permalink
Add Cleanup to snapshot API
Browse files Browse the repository at this point in the history
Cleanup is an optional method a snapshotter may implement.
Cleanup can be used to cleanup resources after a snapshot
has been removed. This function allows a snapshotter to defer
longer resource cleanup until after snapshot removals are
completed. Adding this to the API allows proxy snapshotters
to leverage this enhancement.

Signed-off-by: Derek McGowan <derek@mcgstyle.net>
  • Loading branch information
dmcgowan committed Jan 7, 2020
1 parent b95fa01 commit 123af61
Show file tree
Hide file tree
Showing 8 changed files with 354 additions and 70 deletions.
15 changes: 15 additions & 0 deletions api/next.pb.txt
Expand Up @@ -3446,6 +3446,16 @@ file {
json_name: "inodes"
}
}
message_type {
name: "CleanupRequest"
field {
name: "snapshotter"
number: 1
label: LABEL_OPTIONAL
type: TYPE_STRING
json_name: "snapshotter"
}
}
enum_type {
name: "Kind"
value {
Expand Down Expand Up @@ -3529,6 +3539,11 @@ file {
input_type: ".containerd.services.snapshots.v1.UsageRequest"
output_type: ".containerd.services.snapshots.v1.UsageResponse"
}
method {
name: "Cleanup"
input_type: ".containerd.services.snapshots.v1.CleanupRequest"
output_type: ".google.protobuf.Empty"
}
}
options {
go_package: "github.com/containerd/containerd/api/services/snapshots/v1;snapshots"
Expand Down
345 changes: 280 additions & 65 deletions api/services/snapshots/v1/snapshots.pb.go

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions api/services/snapshots/v1/snapshots.proto
Expand Up @@ -21,6 +21,7 @@ service Snapshots {
rpc Update(UpdateSnapshotRequest) returns (UpdateSnapshotResponse);
rpc List(ListSnapshotsRequest) returns (stream ListSnapshotsResponse);
rpc Usage(UsageRequest) returns (UsageResponse);
rpc Cleanup(CleanupRequest) returns (google.protobuf.Empty);
}

message PrepareSnapshotRequest {
Expand Down Expand Up @@ -160,3 +161,7 @@ message UsageResponse {
int64 size = 1;
int64 inodes = 2;
}

message CleanupRequest {
string snapshotter = 1;
}
13 changes: 13 additions & 0 deletions contrib/snapshotservice/service.go
Expand Up @@ -163,6 +163,19 @@ func (s service) Usage(ctx context.Context, ur *snapshotsapi.UsageRequest) (*sna
}, nil
}

func (s service) Cleanup(ctx context.Context, cr *snapshotsapi.CleanupRequest) (*ptypes.Empty, error) {
c, ok := s.sn.(snapshots.Cleaner)
if !ok {
return nil, errdefs.ToGRPCf(errdefs.ErrNotImplemented, "snapshotter does not implement Cleanup method")
}

if err := c.Cleanup(ctx); err != nil {
return nil, errdefs.ToGRPC(err)
}

return empty, nil
}

func fromKind(kind snapshots.Kind) snapshotsapi.Kind {
if kind == snapshots.KindActive {
return snapshotsapi.KindActive
Expand Down
9 changes: 4 additions & 5 deletions metadata/snapshot.go
Expand Up @@ -791,18 +791,17 @@ func validateSnapshot(info *snapshots.Info) error {
return nil
}

type cleaner interface {
Cleanup(ctx context.Context) error
}

func (s *snapshotter) garbageCollect(ctx context.Context) (d time.Duration, err error) {
s.l.Lock()
t1 := time.Now()
defer func() {
s.l.Unlock()
if err == nil {
if c, ok := s.Snapshotter.(cleaner); ok {
if c, ok := s.Snapshotter.(snapshots.Cleaner); ok {
err = c.Cleanup(ctx)
if errdefs.IsNotImplemented(err) {
err = nil
}
}
}
if err == nil {
Expand Down
19 changes: 19 additions & 0 deletions services/snapshots/service.go
Expand Up @@ -255,6 +255,25 @@ func (s *service) Usage(ctx context.Context, ur *snapshotsapi.UsageRequest) (*sn
return fromUsage(usage), nil
}

func (s *service) Cleanup(ctx context.Context, cr *snapshotsapi.CleanupRequest) (*ptypes.Empty, error) {
sn, err := s.getSnapshotter(cr.Snapshotter)
if err != nil {
return nil, err
}

c, ok := sn.(snapshots.Cleaner)
if !ok {
return nil, errdefs.ToGRPCf(errdefs.ErrNotImplemented, "snapshotter does not implement Cleanup method")
}

err = c.Cleanup(ctx)
if err != nil {
return nil, errdefs.ToGRPC(err)
}

return empty, nil
}

func fromKind(kind snapshots.Kind) snapshotsapi.Kind {
if kind == snapshots.KindActive {
return snapshotsapi.KindActive
Expand Down
7 changes: 7 additions & 0 deletions snapshots/proxy/proxy.go
Expand Up @@ -184,6 +184,13 @@ func (p *proxySnapshotter) Close() error {
return nil
}

func (p *proxySnapshotter) Cleanup(ctx context.Context) error {
_, err := p.client.Cleanup(ctx, &snapshotsapi.CleanupRequest{
Snapshotter: p.snapshotterName,
})
return errdefs.FromGRPC(err)
}

func toKind(kind snapshotsapi.Kind) snapshots.Kind {
if kind == snapshotsapi.KindActive {
return snapshots.KindActive
Expand Down
11 changes: 11 additions & 0 deletions snapshots/snapshotter.go
Expand Up @@ -341,6 +341,17 @@ type Snapshotter interface {
Close() error
}

// Cleaner defines a type capable of performing asynchronous resource cleanup.
// The Cleaner interface should be used by snapshotters which implement fast
// removal and deferred resource cleanup. This prevents snapshots from needing
// to perform lengthy resource cleanup before acknowledging a snapshot key
// has been removed and available for re-use. This is also useful when
// performing multi-key removal with the intent of cleaning up all the
// resources after each snapshot key has been removed.
type Cleaner interface {
Cleanup(ctx context.Context) error
}

// Opt allows setting mutable snapshot properties on creation
type Opt func(info *Info) error

Expand Down

0 comments on commit 123af61

Please sign in to comment.