diff --git a/snapshot/btrfs/btrfs.go b/snapshot/btrfs/btrfs.go index e9f963b07..e58edb301 100644 --- a/snapshot/btrfs/btrfs.go +++ b/snapshot/btrfs/btrfs.go @@ -103,6 +103,25 @@ func (b *snapshotter) Stat(ctx context.Context, key string) (snapshot.Info, erro return info, nil } +func (o *snapshotter) Update(ctx context.Context, info snapshot.Info, fieldpaths ...string) (snapshot.Info, error) { + ctx, t, err := o.ms.TransactionContext(ctx, true) + if err != nil { + return snapshot.Info{}, err + } + + info, err = storage.UpdateInfo(ctx, info, fieldpaths...) + if err != nil { + t.Rollback() + return snapshot.Info{}, err + } + + if err := t.Commit(); err != nil { + return snapshot.Info{}, err + } + + return info, nil +} + // Usage retrieves the disk usage of the top-level snapshot. func (b *snapshotter) Usage(ctx context.Context, key string) (snapshot.Usage, error) { panic("not implemented") @@ -129,15 +148,15 @@ func (b *snapshotter) Walk(ctx context.Context, fn func(context.Context, snapsho return storage.WalkInfo(ctx, fn) } -func (b *snapshotter) Prepare(ctx context.Context, key, parent string) ([]mount.Mount, error) { - return b.makeSnapshot(ctx, snapshot.KindActive, key, parent) +func (b *snapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + return b.makeSnapshot(ctx, snapshot.KindActive, key, parent, opts) } -func (b *snapshotter) View(ctx context.Context, key, parent string) ([]mount.Mount, error) { - return b.makeSnapshot(ctx, snapshot.KindView, key, parent) +func (b *snapshotter) View(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + return b.makeSnapshot(ctx, snapshot.KindView, key, parent, opts) } -func (b *snapshotter) makeSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string) ([]mount.Mount, error) { +func (b *snapshotter) makeSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string, opts []snapshot.Opt) ([]mount.Mount, error) { ctx, t, err := b.ms.TransactionContext(ctx, true) if err != nil { return nil, err @@ -150,7 +169,7 @@ func (b *snapshotter) makeSnapshot(ctx context.Context, kind snapshot.Kind, key, } }() - s, err := storage.CreateSnapshot(ctx, kind, key, parent) + s, err := storage.CreateSnapshot(ctx, kind, key, parent, opts...) if err != nil { return nil, err } @@ -214,7 +233,7 @@ func (b *snapshotter) mounts(dir string) ([]mount.Mount, error) { }, nil } -func (b *snapshotter) Commit(ctx context.Context, name, key string) (err error) { +func (b *snapshotter) Commit(ctx context.Context, name, key string, opts ...snapshot.Opt) (err error) { ctx, t, err := b.ms.TransactionContext(ctx, true) if err != nil { return err @@ -227,7 +246,7 @@ func (b *snapshotter) Commit(ctx context.Context, name, key string) (err error) } }() - id, err := storage.CommitActive(ctx, key, name, snapshot.Usage{}) // TODO(stevvooe): Resolve a usage value for btrfs + id, err := storage.CommitActive(ctx, key, name, snapshot.Usage{}, opts...) // TODO(stevvooe): Resolve a usage value for btrfs if err != nil { return errors.Wrap(err, "failed to commit") } diff --git a/snapshot/naive/naive.go b/snapshot/naive/naive.go index a78a76145..f2f849cc1 100644 --- a/snapshot/naive/naive.go +++ b/snapshot/naive/naive.go @@ -70,6 +70,25 @@ func (o *snapshotter) Stat(ctx context.Context, key string) (snapshot.Info, erro return info, nil } +func (o *snapshotter) Update(ctx context.Context, info snapshot.Info, fieldpaths ...string) (snapshot.Info, error) { + ctx, t, err := o.ms.TransactionContext(ctx, true) + if err != nil { + return snapshot.Info{}, err + } + + info, err = storage.UpdateInfo(ctx, info, fieldpaths...) + if err != nil { + t.Rollback() + return snapshot.Info{}, err + } + + if err := t.Commit(); err != nil { + return snapshot.Info{}, err + } + + return info, nil +} + func (o *snapshotter) Usage(ctx context.Context, key string) (snapshot.Usage, error) { ctx, t, err := o.ms.TransactionContext(ctx, false) if err != nil { @@ -93,12 +112,12 @@ func (o *snapshotter) Usage(ctx context.Context, key string) (snapshot.Usage, er return usage, nil } -func (o *snapshotter) Prepare(ctx context.Context, key, parent string) ([]mount.Mount, error) { - return o.createSnapshot(ctx, snapshot.KindActive, key, parent) +func (o *snapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + return o.createSnapshot(ctx, snapshot.KindActive, key, parent, opts) } -func (o *snapshotter) View(ctx context.Context, key, parent string) ([]mount.Mount, error) { - return o.createSnapshot(ctx, snapshot.KindView, key, parent) +func (o *snapshotter) View(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + return o.createSnapshot(ctx, snapshot.KindView, key, parent, opts) } // Mounts returns the mounts for the transaction identified by key. Can be @@ -118,7 +137,7 @@ func (o *snapshotter) Mounts(ctx context.Context, key string) ([]mount.Mount, er return o.mounts(s), nil } -func (o *snapshotter) Commit(ctx context.Context, name, key string) error { +func (o *snapshotter) Commit(ctx context.Context, name, key string, opts ...snapshot.Opt) error { ctx, t, err := o.ms.TransactionContext(ctx, true) if err != nil { return err @@ -134,7 +153,7 @@ func (o *snapshotter) Commit(ctx context.Context, name, key string) error { return err } - if _, err := storage.CommitActive(ctx, key, name, snapshot.Usage(usage)); err != nil { + if _, err := storage.CommitActive(ctx, key, name, snapshot.Usage(usage), opts...); err != nil { if rerr := t.Rollback(); rerr != nil { log.G(ctx).WithError(rerr).Warn("Failure rolling back transaction") } @@ -203,7 +222,7 @@ func (o *snapshotter) Walk(ctx context.Context, fn func(context.Context, snapsho return storage.WalkInfo(ctx, fn) } -func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string) ([]mount.Mount, error) { +func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string, opts []snapshot.Opt) ([]mount.Mount, error) { var ( err error path, td string @@ -235,7 +254,7 @@ func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshot.Kind, ke return nil, err } - s, err := storage.CreateSnapshot(ctx, kind, key, parent) + s, err := storage.CreateSnapshot(ctx, kind, key, parent, opts...) if err != nil { if rerr := t.Rollback(); rerr != nil { log.G(ctx).WithError(rerr).Warn("Failure rolling back transaction") diff --git a/snapshot/overlay/overlay.go b/snapshot/overlay/overlay.go index 7d1616bc6..35644b07a 100644 --- a/snapshot/overlay/overlay.go +++ b/snapshot/overlay/overlay.go @@ -89,6 +89,25 @@ func (o *snapshotter) Stat(ctx context.Context, key string) (snapshot.Info, erro return info, nil } +func (o *snapshotter) Update(ctx context.Context, info snapshot.Info, fieldpaths ...string) (snapshot.Info, error) { + ctx, t, err := o.ms.TransactionContext(ctx, true) + if err != nil { + return snapshot.Info{}, err + } + + info, err = storage.UpdateInfo(ctx, info, fieldpaths...) + if err != nil { + t.Rollback() + return snapshot.Info{}, err + } + + if err := t.Commit(); err != nil { + return snapshot.Info{}, err + } + + return info, nil +} + // Usage returns the resources taken by the snapshot identified by key. // // For active snapshots, this will scan the usage of the overlay "diff" (aka @@ -121,12 +140,12 @@ func (o *snapshotter) Usage(ctx context.Context, key string) (snapshot.Usage, er return usage, nil } -func (o *snapshotter) Prepare(ctx context.Context, key, parent string) ([]mount.Mount, error) { - return o.createSnapshot(ctx, snapshot.KindActive, key, parent) +func (o *snapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + return o.createSnapshot(ctx, snapshot.KindActive, key, parent, opts) } -func (o *snapshotter) View(ctx context.Context, key, parent string) ([]mount.Mount, error) { - return o.createSnapshot(ctx, snapshot.KindView, key, parent) +func (o *snapshotter) View(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + return o.createSnapshot(ctx, snapshot.KindView, key, parent, opts) } // Mounts returns the mounts for the transaction identified by key. Can be @@ -146,7 +165,7 @@ func (o *snapshotter) Mounts(ctx context.Context, key string) ([]mount.Mount, er return o.mounts(s), nil } -func (o *snapshotter) Commit(ctx context.Context, name, key string) error { +func (o *snapshotter) Commit(ctx context.Context, name, key string, opts ...snapshot.Opt) error { ctx, t, err := o.ms.TransactionContext(ctx, true) if err != nil { return err @@ -171,7 +190,7 @@ func (o *snapshotter) Commit(ctx context.Context, name, key string) error { return err } - if _, err = storage.CommitActive(ctx, key, name, snapshot.Usage(usage)); err != nil { + if _, err = storage.CommitActive(ctx, key, name, snapshot.Usage(usage), opts...); err != nil { return errors.Wrap(err, "failed to commit snapshot") } return t.Commit() @@ -230,7 +249,7 @@ func (o *snapshotter) Walk(ctx context.Context, fn func(context.Context, snapsho return storage.WalkInfo(ctx, fn) } -func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string) ([]mount.Mount, error) { +func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string, opts []snapshot.Opt) ([]mount.Mount, error) { var ( path string snapshotDir = filepath.Join(o.root, "snapshots") @@ -270,7 +289,7 @@ func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshot.Kind, ke return nil, err } - s, err := storage.CreateSnapshot(ctx, kind, key, parent) + s, err := storage.CreateSnapshot(ctx, kind, key, parent, opts...) if err != nil { if rerr := t.Rollback(); rerr != nil { log.G(ctx).WithError(rerr).Warn("Failure rolling back transaction") diff --git a/snapshot/snapshotter.go b/snapshot/snapshotter.go index c2cd73fc8..35d645000 100644 --- a/snapshot/snapshotter.go +++ b/snapshot/snapshotter.go @@ -2,12 +2,13 @@ package snapshot import ( "context" + "time" "github.com/containerd/containerd/mount" ) // Kind identifies the kind of snapshot. -type Kind int +type Kind uint8 // definitions of snapshot kinds const ( @@ -31,9 +32,12 @@ func (k Kind) String() string { // Info provides information about a particular snapshot. type Info struct { - Kind Kind // active or committed snapshot - Name string // name or key of snapshot - Parent string // name of parent snapshot + Kind Kind // active or committed snapshot + Name string // name or key of snapshot + Parent string // name of parent snapshot + Labels map[string]string // Labels for snapshot + Created time.Time // Created time + Updated time.Time // Last update time } // Usage defines statistics for disk resources consumed by the snapshot. @@ -177,6 +181,11 @@ type Snapshotter interface { // the kind of snapshot. Stat(ctx context.Context, key string) (Info, error) + // Update updates the infor for a snapshot. + // + // Only mutable properties of a snapshot may be updated. + Update(ctx context.Context, info Info, fieldpaths ...string) (Info, error) + // Usage returns the resource usage of an active or committed snapshot // excluding the usage of parent snapshots. // @@ -208,7 +217,7 @@ type Snapshotter interface { // one is done with the transaction, Remove should be called on the key. // // Multiple calls to Prepare or View with the same key should fail. - Prepare(ctx context.Context, key, parent string) ([]mount.Mount, error) + Prepare(ctx context.Context, key, parent string, opts ...Opt) ([]mount.Mount, error) // View behaves identically to Prepare except the result may not be // committed back to the snapshot snapshotter. View returns a readonly view on @@ -223,7 +232,7 @@ type Snapshotter interface { // Commit may not be called on the provided key and will return an error. // To collect the resources associated with key, Remove must be called with // key as the argument. - View(ctx context.Context, key, parent string) ([]mount.Mount, error) + View(ctx context.Context, key, parent string, opts ...Opt) ([]mount.Mount, error) // Commit captures the changes between key and its parent into a snapshot // identified by name. The name can then be used with the snapshotter's other @@ -235,7 +244,7 @@ type Snapshotter interface { // Commit may be called multiple times on the same key. Snapshots created // in this manner will all reference the parent used to start the // transaction. - Commit(ctx context.Context, name, key string) error + Commit(ctx context.Context, name, key string, opts ...Opt) error // Remove the committed or active snapshot by the provided key. // @@ -249,3 +258,14 @@ type Snapshotter interface { // snapshotter, the function will be called. Walk(ctx context.Context, fn func(context.Context, Info) error) error } + +// Opt allows setting mutable snapshot properties on creation +type Opt func(info *Info) error + +// WithLabels adds labels to a created snapshot +func WithLabels(labels map[string]string) Opt { + return func(info *Info) error { + info.Labels = labels + return nil + } +} diff --git a/snapshot/storage/bolt.go b/snapshot/storage/bolt.go index abe997c29..4f0c677ce 100644 --- a/snapshot/storage/bolt.go +++ b/snapshot/storage/bolt.go @@ -4,12 +4,13 @@ import ( "context" "encoding/binary" "fmt" + "strings" + "time" "github.com/boltdb/bolt" "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/metadata/boltutil" "github.com/containerd/containerd/snapshot" - db "github.com/containerd/containerd/snapshot/storage/proto" - "github.com/gogo/protobuf/proto" "github.com/pkg/errors" ) @@ -18,6 +19,12 @@ var ( bucketKeySnapshot = []byte("snapshots") bucketKeyParents = []byte("parents") + bucketKeyID = []byte("id") + bucketKeyParent = []byte("parent") + bucketKeyKind = []byte("kind") + bucketKeyInodes = []byte("inodes") + bucketKeySize = []byte("size") + // ErrNoTransaction is returned when an operation is attempted with // a context which is not inside of a transaction. ErrNoTransaction = errors.New("no transaction in context") @@ -65,24 +72,75 @@ func getParentPrefix(b []byte) uint64 { // GetInfo returns the snapshot Info directly from the metadata. Requires a // context with a storage transaction. func GetInfo(ctx context.Context, key string) (string, snapshot.Info, snapshot.Usage, error) { - var ss db.Snapshot - err := withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { - return getSnapshot(bkt, key, &ss) + var ( + id uint64 + su snapshot.Usage + si = snapshot.Info{ + Name: key, + } + ) + err := withSnapshotBucket(ctx, key, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { + getUsage(bkt, &su) + return readSnapshot(bkt, &id, &si) }) if err != nil { return "", snapshot.Info{}, snapshot.Usage{}, err } - usage := snapshot.Usage{ - Inodes: ss.Inodes, - Size: ss.Size_, - } + return fmt.Sprintf("%d", id), si, su, nil +} - return fmt.Sprint(ss.ID), snapshot.Info{ - Name: key, - Parent: ss.Parent, - Kind: snapshot.Kind(ss.Kind), - }, usage, nil +func UpdateInfo(ctx context.Context, info snapshot.Info, fieldpaths ...string) (snapshot.Info, error) { + updated := snapshot.Info{ + Name: info.Name, + } + err := withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { + sbkt := bkt.Bucket([]byte(info.Name)) + if sbkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "snapshot does not exist") + } + if err := readSnapshot(sbkt, nil, &updated); err != nil { + return err + } + + if len(fieldpaths) > 0 { + for _, path := range fieldpaths { + if strings.HasPrefix(path, "labels.") { + if updated.Labels == nil { + updated.Labels = map[string]string{} + } + + key := strings.TrimPrefix(path, "labels.") + updated.Labels[key] = info.Labels[key] + continue + } + + switch path { + case "labels": + updated.Labels = info.Labels + default: + return errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on snapshot %q", path, info.Name) + } + } + } else { + // Set mutable fields + updated.Labels = info.Labels + } + updated.Updated = time.Now().UTC() + if err := boltutil.WriteTimestamps(sbkt, updated.Created, updated.Updated); err != nil { + return err + } + + if err := boltutil.WriteLabels(sbkt, updated.Labels); err != nil { + return err + } + + return nil + }) + if err != nil { + return snapshot.Info{}, err + } + return updated, nil } // WalkInfo iterates through all metadata Info for the stored snapshots and @@ -91,21 +149,21 @@ func GetInfo(ctx context.Context, key string) (string, snapshot.Info, snapshot.U func WalkInfo(ctx context.Context, fn func(context.Context, snapshot.Info) error) error { return withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { return bkt.ForEach(func(k, v []byte) error { - // skip nested buckets - if v == nil { + // skip non buckets + if v != nil { return nil } - var ss db.Snapshot - if err := proto.Unmarshal(v, &ss); err != nil { - return errors.Wrap(err, "failed to unmarshal snapshot") + var ( + sbkt = bkt.Bucket(k) + si = snapshot.Info{ + Name: string(k), + } + ) + if err := readSnapshot(sbkt, nil, &si); err != nil { + return err } - info := snapshot.Info{ - Name: string(k), - Parent: ss.Parent, - Kind: snapshot.Kind(ss.Kind), - } - return fn(ctx, info) + return fn(ctx, si) }) }) } @@ -114,30 +172,25 @@ func WalkInfo(ctx context.Context, fn func(context.Context, snapshot.Info) error // referenced by the given key. Requires a context with a storage transaction. func GetSnapshot(ctx context.Context, key string) (s Snapshot, err error) { err = withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { - b := bkt.Get([]byte(key)) - if len(b) == 0 { - return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v", key) + sbkt := bkt.Bucket([]byte(key)) + if sbkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "snapshot does not exist") } - var ss db.Snapshot - if err := proto.Unmarshal(b, &ss); err != nil { - return errors.Wrap(err, "failed to unmarshal snapshot") - } + s.ID = fmt.Sprintf("%d", readID(sbkt)) + s.Kind = readKind(sbkt) - if ss.Kind != db.KindActive && ss.Kind != db.KindView { + if s.Kind != snapshot.KindActive && s.Kind != snapshot.KindView { return errors.Wrapf(errdefs.ErrFailedPrecondition, "requested snapshot %v not active or view", key) } - s.ID = fmt.Sprintf("%d", ss.ID) - s.Kind = snapshot.Kind(ss.Kind) - - if ss.Parent != "" { - var parent db.Snapshot - if err := getSnapshot(bkt, ss.Parent, &parent); err != nil { - return errors.Wrap(err, "failed to get parent snapshot") + if parentKey := sbkt.Get(bucketKeyParent); len(parentKey) > 0 { + spbkt := bkt.Bucket(parentKey) + if spbkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "parent does not exist") } - s.ParentIDs, err = parents(bkt, &parent) + s.ParentIDs, err = parents(bkt, spbkt, readID(spbkt)) if err != nil { return errors.Wrap(err, "failed to get parent chain") } @@ -152,30 +205,39 @@ func GetSnapshot(ctx context.Context, key string) (s Snapshot, err error) { } // CreateSnapshot inserts a record for an active or view snapshot with the provided parent. -func CreateSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string) (s Snapshot, err error) { +func CreateSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string, opts ...snapshot.Opt) (s Snapshot, err error) { switch kind { case snapshot.KindActive, snapshot.KindView: default: return Snapshot{}, errors.Wrapf(errdefs.ErrInvalidArgument, "snapshot type %v invalid; only snapshots of type Active or View can be created", kind) } + var base snapshot.Info + for _, opt := range opts { + if err := opt(&base); err != nil { + return Snapshot{}, err + } + } err = createBucketIfNotExists(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { var ( - parentS *db.Snapshot + spbkt *bolt.Bucket ) if parent != "" { - parentS = new(db.Snapshot) - if err := getSnapshot(bkt, parent, parentS); err != nil { - return errors.Wrap(err, "failed to get parent snapshot") + spbkt = bkt.Bucket([]byte(parent)) + if spbkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "missing parent bucket") } - if parentS.Kind != db.KindCommitted { + if readKind(spbkt) != snapshot.KindCommitted { return errors.Wrap(errdefs.ErrInvalidArgument, "parent is not committed snapshot") } } - b := bkt.Get([]byte(key)) - if len(b) != 0 { - return errors.Wrapf(errdefs.ErrAlreadyExists, "snapshot %v", key) + sbkt, err := bkt.CreateBucket([]byte(key)) + if err != nil { + if err == bolt.ErrBucketExists { + err = errors.Wrapf(errdefs.ErrAlreadyExists, "snapshot %v", key) + } + return err } id, err := bkt.NextSequence() @@ -183,23 +245,28 @@ func CreateSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string) return errors.Wrap(err, "unable to get identifier") } - ss := db.Snapshot{ - ID: id, - Parent: parent, - Kind: db.Kind(kind), + t := time.Now().UTC() + si := snapshot.Info{ + Parent: parent, + Kind: kind, + Labels: base.Labels, + Created: t, + Updated: t, } - if err := putSnapshot(bkt, key, &ss); err != nil { + if err := putSnapshot(sbkt, id, si); err != nil { return err } - if parentS != nil { + if spbkt != nil { + pid := readID(spbkt) + // Store a backlink from the key to the parent. Store the snapshot name // as the value to allow following the backlink to the snapshot value. - if err := pbkt.Put(parentKey(parentS.ID, ss.ID), []byte(key)); err != nil { + if err := pbkt.Put(parentKey(pid, id), []byte(key)); err != nil { return errors.Wrap(err, "failed to write parent link") } - s.ParentIDs, err = parents(bkt, parentS) + s.ParentIDs, err = parents(bkt, spbkt, pid) if err != nil { return errors.Wrap(err, "failed to get parent chain") } @@ -219,47 +286,50 @@ func CreateSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string) // Remove removes a snapshot from the metastore. The string identifier for the // snapshot is returned as well as the kind. The provided context must contain a // writable transaction. -func Remove(ctx context.Context, key string) (id string, k snapshot.Kind, err error) { - err = withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { - var ss db.Snapshot - b := bkt.Get([]byte(key)) - if len(b) == 0 { +func Remove(ctx context.Context, key string) (string, snapshot.Kind, error) { + var ( + id uint64 + si snapshot.Info + ) + + if err := withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { + sbkt := bkt.Bucket([]byte(key)) + if sbkt == nil { return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v", key) } - if err := proto.Unmarshal(b, &ss); err != nil { - return errors.Wrap(err, "failed to unmarshal snapshot") + if err := readSnapshot(sbkt, &id, &si); err != nil { + errors.Wrapf(err, "failed to read snapshot %s", key) } if pbkt != nil { - k, _ := pbkt.Cursor().Seek(parentPrefixKey(ss.ID)) - if getParentPrefix(k) == ss.ID { + k, _ := pbkt.Cursor().Seek(parentPrefixKey(id)) + if getParentPrefix(k) == id { return errors.Errorf("cannot remove snapshot with child") } - if ss.Parent != "" { - var ps db.Snapshot - if err := getSnapshot(bkt, ss.Parent, &ps); err != nil { - return errors.Wrap(err, "failed to get parent snapshot") + if si.Parent != "" { + spbkt := bkt.Bucket([]byte(si.Parent)) + if spbkt == nil { + return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v", key) } - if err := pbkt.Delete(parentKey(ps.ID, ss.ID)); err != nil { - return errors.Wrap(err, "failed to delte parent link") + if err := pbkt.Delete(parentKey(readID(spbkt), id)); err != nil { + return errors.Wrap(err, "failed to delete parent link") } } } - if err := bkt.Delete([]byte(key)); err != nil { + if err := bkt.DeleteBucket([]byte(key)); err != nil { return errors.Wrap(err, "failed to delete snapshot") } - id = fmt.Sprintf("%d", ss.ID) - k = snapshot.Kind(ss.Kind) - return nil - }) + }); err != nil { + return "", 0, err + } - return + return fmt.Sprintf("%d", id), si.Kind, nil } // CommitActive renames the active snapshot transaction referenced by `key` @@ -268,52 +338,94 @@ func Remove(ctx context.Context, key string) (id string, k snapshot.Kind, err er // lookup or removal. The returned string identifier for the committed snapshot // is the same identifier of the original active snapshot. The provided context // must contain a writable transaction. -func CommitActive(ctx context.Context, key, name string, usage snapshot.Usage) (id string, err error) { - err = withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { - b := bkt.Get([]byte(name)) - if len(b) != 0 { - return errors.Wrapf(errdefs.ErrAlreadyExists, "committed snapshot %v", name) +func CommitActive(ctx context.Context, key, name string, usage snapshot.Usage, opts ...snapshot.Opt) (string, error) { + var ( + id uint64 + base snapshot.Info + ) + for _, opt := range opts { + if err := opt(&base); err != nil { + return "", err + } + } + + if err := withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { + dbkt, err := bkt.CreateBucket([]byte(name)) + if err != nil { + if err == bolt.ErrBucketExists { + err = errdefs.ErrAlreadyExists + } + return errors.Wrapf(err, "committed snapshot %v", name) + } + sbkt := bkt.Bucket([]byte(key)) + if sbkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "failed to get active snapshot") } - var ss db.Snapshot - if err := getSnapshot(bkt, key, &ss); err != nil { - return errors.Wrap(err, "failed to get active snapshot") + var si snapshot.Info + if err := readSnapshot(sbkt, &id, &si); err != nil { + return errors.Wrap(err, "failed to read snapshot") } - if ss.Kind != db.KindActive { + + if si.Kind != snapshot.KindActive { return errors.Wrapf(errdefs.ErrFailedPrecondition, "snapshot %v is not active", name) } + si.Kind = snapshot.KindCommitted + si.Created = time.Now().UTC() + si.Updated = si.Created - ss.Kind = db.KindCommitted - ss.Inodes = usage.Inodes - ss.Size_ = usage.Size + // Replace labels, do not inherit + si.Labels = base.Labels - if err := putSnapshot(bkt, name, &ss); err != nil { + if err := putSnapshot(dbkt, id, si); err != nil { return err } - if err := bkt.Delete([]byte(key)); err != nil { + if err := putUsage(dbkt, usage); err != nil { + return err + } + if err := bkt.DeleteBucket([]byte(key)); err != nil { return errors.Wrap(err, "failed to delete active") } - if ss.Parent != "" { - var ps db.Snapshot - if err := getSnapshot(bkt, ss.Parent, &ps); err != nil { - return errors.Wrap(err, "failed to get parent snapshot") + if si.Parent != "" { + spbkt := bkt.Bucket([]byte(si.Parent)) + if spbkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "missing parent") } + pid := readID(spbkt) // Updates parent back link to use new key - if err := pbkt.Put(parentKey(ps.ID, ss.ID), []byte(name)); err != nil { + if err := pbkt.Put(parentKey(pid, id), []byte(name)); err != nil { return errors.Wrap(err, "failed to update parent link") } } - id = fmt.Sprintf("%d", ss.ID) - return nil - }) - if err != nil { + }); err != nil { return "", err } - return + return fmt.Sprintf("%d", id), nil +} + +func withSnapshotBucket(ctx context.Context, key string, fn func(context.Context, *bolt.Bucket, *bolt.Bucket) error) error { + t, ok := ctx.Value(transactionKey{}).(*boltFileTransactor) + if !ok { + return ErrNoTransaction + } + bkt := t.tx.Bucket(bucketKeyStorageVersion) + if bkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "bucket does not exist") + } + bkt = bkt.Bucket(bucketKeySnapshot) + if bkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "snapshots bucket does not exist") + } + bkt = bkt.Bucket([]byte(key)) + if bkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "snapshot does not exist") + } + + return fn(ctx, bkt, bkt.Bucket(bucketKeyParents)) } func withBucket(ctx context.Context, fn func(context.Context, *bolt.Bucket, *bolt.Bucket) error) error { @@ -349,41 +461,133 @@ func createBucketIfNotExists(ctx context.Context, fn func(context.Context, *bolt return fn(ctx, sbkt, pbkt) } -func parents(bkt *bolt.Bucket, parent *db.Snapshot) (parents []string, err error) { +func parents(bkt, pbkt *bolt.Bucket, parent uint64) (parents []string, err error) { for { - parents = append(parents, fmt.Sprintf("%d", parent.ID)) + parents = append(parents, fmt.Sprintf("%d", parent)) - if parent.Parent == "" { + parentKey := pbkt.Get(bucketKeyParent) + if len(parentKey) == 0 { return } - - var ps db.Snapshot - if err := getSnapshot(bkt, parent.Parent, &ps); err != nil { - return nil, errors.Wrap(err, "failed to get parent snapshot") + pbkt = bkt.Bucket(parentKey) + if pbkt == nil { + return nil, errors.Wrap(errdefs.ErrNotFound, "missing parent") } - parent = &ps + + parent = readID(pbkt) } } -func getSnapshot(bkt *bolt.Bucket, key string, ss *db.Snapshot) error { - b := bkt.Get([]byte(key)) - if len(b) == 0 { - return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v", key) +func readKind(bkt *bolt.Bucket) (k snapshot.Kind) { + kind := bkt.Get(bucketKeyKind) + if len(kind) == 1 { + k = snapshot.Kind(kind[0]) } - if err := proto.Unmarshal(b, ss); err != nil { - return errors.Wrap(err, "failed to unmarshal snapshot") + return +} + +func readID(bkt *bolt.Bucket) uint64 { + id, _ := binary.Uvarint(bkt.Get(bucketKeyID)) + return id +} + +func readSnapshot(bkt *bolt.Bucket, id *uint64, si *snapshot.Info) error { + if id != nil { + *id = readID(bkt) } + if si != nil { + si.Kind = readKind(bkt) + si.Parent = string(bkt.Get(bucketKeyParent)) + + if err := boltutil.ReadTimestamps(bkt, &si.Created, &si.Updated); err != nil { + return err + } + + labels, err := boltutil.ReadLabels(bkt) + if err != nil { + return err + } + si.Labels = labels + } + return nil } -func putSnapshot(bkt *bolt.Bucket, key string, ss *db.Snapshot) error { - b, err := proto.Marshal(ss) +func putSnapshot(bkt *bolt.Bucket, id uint64, si snapshot.Info) error { + idEncoded, err := encodeID(id) if err != nil { - return errors.Wrap(err, "failed to marshal snapshot") + return err } - if err := bkt.Put([]byte(key), b); err != nil { - return errors.Wrap(err, "failed to save snapshot") + updates := [][2][]byte{ + {bucketKeyID, idEncoded}, + {bucketKeyKind, []byte{byte(si.Kind)}}, + } + if si.Parent != "" { + updates = append(updates, [2][]byte{bucketKeyParent, []byte(si.Parent)}) + } + for _, v := range updates { + if err := bkt.Put(v[0], v[1]); err != nil { + return err + } + } + if err := boltutil.WriteTimestamps(bkt, si.Created, si.Updated); err != nil { + return err + } + + if err := boltutil.WriteLabels(bkt, si.Labels); err != nil { + return err + } + + return nil +} + +func getUsage(bkt *bolt.Bucket, usage *snapshot.Usage) { + usage.Inodes, _ = binary.Varint(bkt.Get(bucketKeyInodes)) + usage.Size, _ = binary.Varint(bkt.Get(bucketKeySize)) +} + +func putUsage(bkt *bolt.Bucket, usage snapshot.Usage) error { + for _, v := range []struct { + key []byte + value int64 + }{ + {bucketKeyInodes, usage.Inodes}, + {bucketKeySize, usage.Size}, + } { + e, err := encodeSize(v.value) + if err != nil { + return err + } + if err := bkt.Put(v.key, e); err != nil { + return err + } } return nil } + +func encodeSize(size int64) ([]byte, error) { + var ( + buf [binary.MaxVarintLen64]byte + sizeEncoded []byte = buf[:] + ) + sizeEncoded = sizeEncoded[:binary.PutVarint(sizeEncoded, size)] + + if len(sizeEncoded) == 0 { + return nil, fmt.Errorf("failed encoding size = %v", size) + } + return sizeEncoded, nil +} + +func encodeID(id uint64) ([]byte, error) { + var ( + buf [binary.MaxVarintLen64]byte + idEncoded []byte = buf[:] + ) + idEncoded = idEncoded[:binary.PutUvarint(idEncoded, id)] + + if len(idEncoded) == 0 { + return nil, fmt.Errorf("failed encoding id = %v", id) + } + return idEncoded, nil +} diff --git a/snapshot/storage/bolt_test.go b/snapshot/storage/bolt_test.go index cacbab270..a3e73a6d5 100644 --- a/snapshot/storage/bolt_test.go +++ b/snapshot/storage/bolt_test.go @@ -5,8 +5,7 @@ import ( "testing" // Does not require root but flag must be defined for snapshot tests - "github.com/containerd/containerd/snapshot" - "github.com/containerd/containerd/snapshot/storage/proto" + _ "github.com/containerd/containerd/testutil" ) @@ -16,34 +15,6 @@ func TestMetastore(t *testing.T) { }) } -// TestKidnConversion ensures we can blindly cast from protobuf types. -func TestKindConversion(t *testing.T) { - for _, testcase := range []struct { - s snapshot.Kind - p proto.Kind - }{ - { - s: snapshot.KindView, - p: proto.KindView, - }, - { - s: snapshot.KindActive, - p: proto.KindActive, - }, - { - s: snapshot.KindCommitted, - p: proto.KindCommitted, - }, - } { - if testcase.s != snapshot.Kind(testcase.p) { - t.Fatalf("snapshot kind value cast failed: %v != %v", testcase.s, testcase.p) - } - if testcase.p != proto.Kind(testcase.s) { - t.Fatalf("proto kind value cast failed: %v != %v", testcase.s, testcase.p) - } - } -} - func BenchmarkSuite(b *testing.B) { Benchmarks(b, "BoltDBBench", func(root string) (*MetaStore, error) { return NewMetaStore(filepath.Join(root, "metadata.db")) diff --git a/snapshot/storage/metastore_test.go b/snapshot/storage/metastore_test.go index 9aa164f66..91455a295 100644 --- a/snapshot/storage/metastore_test.go +++ b/snapshot/storage/metastore_test.go @@ -2,9 +2,11 @@ package storage import ( "context" + "fmt" "io/ioutil" "os" "testing" + "time" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/snapshot" @@ -40,6 +42,7 @@ func MetaStoreSuite(t *testing.T, name string, meta func(root string) (*MetaStor t.Run("Remove", makeTest(t, name, meta, inWriteTransaction(testRemove))) t.Run("RemoveNotExist", makeTest(t, name, meta, inWriteTransaction(testRemoveNotExist))) t.Run("RemoveWithChildren", makeTest(t, name, meta, inWriteTransaction(testRemoveWithChildren))) + t.Run("ParentIDs", makeTest(t, name, meta, inWriteTransaction(testParents))) } // makeTest creates a testsuite with a writable transaction @@ -236,6 +239,9 @@ func testGetInfo(ctx context.Context, t *testing.T, ms *MetaStore) { if err != nil { t.Fatalf("GetInfo on %v failed: %+v", key, err) } + // TODO: Check timestamp range + info.Created = time.Time{} + info.Updated = time.Time{} assert.Equal(t, expected, info) } } @@ -251,6 +257,9 @@ func testWalk(ctx context.Context, t *testing.T, ms *MetaStore) { if _, ok := found[info.Name]; ok { return errors.Errorf("entry already encountered") } + // TODO: Check time range + info.Created = time.Time{} + info.Updated = time.Time{} found[info.Name] = info return nil }) @@ -545,3 +554,86 @@ func testRemoveNotExist(ctx context.Context, t *testing.T, ms *MetaStore) { _, _, err := Remove(ctx, "does-not-exist") assertNotExist(t, err) } + +func testParents(ctx context.Context, t *testing.T, ms *MetaStore) { + if err := basePopulate(ctx, ms); err != nil { + t.Fatalf("Populate failed: %+v", err) + } + + testcases := []struct { + Name string + Parents int + }{ + {"committed-1", 0}, + {"committed-2", 1}, + {"active-1", 0}, + {"active-2", 1}, + {"active-3", 2}, + {"view-1", 0}, + {"view-2", 2}, + } + + for _, tc := range testcases { + name := tc.Name + expectedID := "" + expectedParents := []string{} + for i := tc.Parents; i >= 0; i-- { + sid, info, _, err := GetInfo(ctx, name) + if err != nil { + t.Fatalf("Failed to get snapshot %s: %v", tc.Name, err) + } + var ( + id string + parents []string + ) + if info.Kind == snapshot.KindCommitted { + // When commited, create view and resolve from view + nid := fmt.Sprintf("test-%s-%d", tc.Name, i) + s, err := CreateSnapshot(ctx, snapshot.KindView, nid, name) + if err != nil { + t.Fatalf("Failed to get snapshot %s: %v", tc.Name, err) + } + if len(s.ParentIDs) != i+1 { + t.Fatalf("Unexpected number of parents for view of %s: %d, expected %d", name, len(s.ParentIDs), i+1) + } + id = s.ParentIDs[0] + parents = s.ParentIDs[1:] + } else { + s, err := GetSnapshot(ctx, name) + if err != nil { + t.Fatalf("Failed to get snapshot %s: %v", tc.Name, err) + } + if len(s.ParentIDs) != i { + t.Fatalf("Unexpected number of parents for %s: %d, expected %d", name, len(s.ParentIDs), i) + } + + id = s.ID + parents = s.ParentIDs + } + if sid != id { + t.Fatalf("Info ID mismatched resolved snapshot ID for %s, %s vs %s", name, sid, id) + } + + if expectedID != "" { + if id != expectedID { + t.Errorf("Unexpected ID of parent: %s, expected %s", id, expectedID) + } + } + + if len(expectedParents) > 0 { + for j := range expectedParents { + if parents[j] != expectedParents[j] { + t.Errorf("Unexpected ID in parent array at %d: %s, expected %s", j, parents[j], expectedParents[j]) + } + } + } + + if i > 0 { + name = info.Parent + expectedID = parents[0] + expectedParents = parents[1:] + } + + } + } +} diff --git a/snapshot/storage/proto/record.pb.go b/snapshot/storage/proto/record.pb.go deleted file mode 100644 index bfaa67d0b..000000000 --- a/snapshot/storage/proto/record.pb.go +++ /dev/null @@ -1,506 +0,0 @@ -// Code generated by protoc-gen-gogo. -// source: github.com/containerd/containerd/snapshot/storage/proto/record.proto -// DO NOT EDIT! - -/* - Package proto is a generated protocol buffer package. - - It is generated from these files: - github.com/containerd/containerd/snapshot/storage/proto/record.proto - - It has these top-level messages: - Snapshot -*/ -package proto - -import proto1 "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" -import _ "github.com/gogo/protobuf/gogoproto" - -import strings "strings" -import reflect "reflect" - -import io "io" - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto1.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto1.GoGoProtoPackageIsVersion2 // please upgrade the proto package - -type Kind int32 - -const ( - KindUnknown Kind = 0 - KindView Kind = 1 - KindActive Kind = 2 - KindCommitted Kind = 3 -) - -var Kind_name = map[int32]string{ - 0: "UNKNOWN", - 1: "VIEW", - 2: "ACTIVE", - 3: "COMMITTED", -} -var Kind_value = map[string]int32{ - "UNKNOWN": 0, - "VIEW": 1, - "ACTIVE": 2, - "COMMITTED": 3, -} - -func (x Kind) String() string { - return proto1.EnumName(Kind_name, int32(x)) -} -func (Kind) EnumDescriptor() ([]byte, []int) { return fileDescriptorRecord, []int{0} } - -// Snapshot defines the storage type for a snapshot in the -// metadata store. -type Snapshot struct { - ID uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - Parent string `protobuf:"bytes,2,opt,name=parent,proto3" json:"parent,omitempty"` - Kind Kind `protobuf:"varint,4,opt,name=kind,proto3,enum=containerd.snapshot.v1.Kind" json:"kind,omitempty"` - // inodes stores the number inodes in use for the snapshot. - // - // Only valid for committed snapshots. - Inodes int64 `protobuf:"varint,6,opt,name=inodes,proto3" json:"inodes,omitempty"` - // Size reports the disk used by the snapshot, excluding the parents. - // - // Only valid for committed snapshots, active snapshots must read the - // current usage from the disk. - Size_ int64 `protobuf:"varint,7,opt,name=size,proto3" json:"size,omitempty"` -} - -func (m *Snapshot) Reset() { *m = Snapshot{} } -func (*Snapshot) ProtoMessage() {} -func (*Snapshot) Descriptor() ([]byte, []int) { return fileDescriptorRecord, []int{0} } - -func init() { - proto1.RegisterType((*Snapshot)(nil), "containerd.snapshot.v1.Snapshot") - proto1.RegisterEnum("containerd.snapshot.v1.Kind", Kind_name, Kind_value) -} -func (m *Snapshot) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Snapshot) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - if m.ID != 0 { - dAtA[i] = 0x8 - i++ - i = encodeVarintRecord(dAtA, i, uint64(m.ID)) - } - if len(m.Parent) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintRecord(dAtA, i, uint64(len(m.Parent))) - i += copy(dAtA[i:], m.Parent) - } - if m.Kind != 0 { - dAtA[i] = 0x20 - i++ - i = encodeVarintRecord(dAtA, i, uint64(m.Kind)) - } - if m.Inodes != 0 { - dAtA[i] = 0x30 - i++ - i = encodeVarintRecord(dAtA, i, uint64(m.Inodes)) - } - if m.Size_ != 0 { - dAtA[i] = 0x38 - i++ - i = encodeVarintRecord(dAtA, i, uint64(m.Size_)) - } - return i, nil -} - -func encodeFixed64Record(dAtA []byte, offset int, v uint64) int { - dAtA[offset] = uint8(v) - dAtA[offset+1] = uint8(v >> 8) - dAtA[offset+2] = uint8(v >> 16) - dAtA[offset+3] = uint8(v >> 24) - dAtA[offset+4] = uint8(v >> 32) - dAtA[offset+5] = uint8(v >> 40) - dAtA[offset+6] = uint8(v >> 48) - dAtA[offset+7] = uint8(v >> 56) - return offset + 8 -} -func encodeFixed32Record(dAtA []byte, offset int, v uint32) int { - dAtA[offset] = uint8(v) - dAtA[offset+1] = uint8(v >> 8) - dAtA[offset+2] = uint8(v >> 16) - dAtA[offset+3] = uint8(v >> 24) - return offset + 4 -} -func encodeVarintRecord(dAtA []byte, offset int, v uint64) int { - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return offset + 1 -} -func (m *Snapshot) Size() (n int) { - var l int - _ = l - if m.ID != 0 { - n += 1 + sovRecord(uint64(m.ID)) - } - l = len(m.Parent) - if l > 0 { - n += 1 + l + sovRecord(uint64(l)) - } - if m.Kind != 0 { - n += 1 + sovRecord(uint64(m.Kind)) - } - if m.Inodes != 0 { - n += 1 + sovRecord(uint64(m.Inodes)) - } - if m.Size_ != 0 { - n += 1 + sovRecord(uint64(m.Size_)) - } - return n -} - -func sovRecord(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n -} -func sozRecord(x uint64) (n int) { - return sovRecord(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (this *Snapshot) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&Snapshot{`, - `ID:` + fmt.Sprintf("%v", this.ID) + `,`, - `Parent:` + fmt.Sprintf("%v", this.Parent) + `,`, - `Kind:` + fmt.Sprintf("%v", this.Kind) + `,`, - `Inodes:` + fmt.Sprintf("%v", this.Inodes) + `,`, - `Size_:` + fmt.Sprintf("%v", this.Size_) + `,`, - `}`, - }, "") - return s -} -func valueToStringRecord(v interface{}) string { - rv := reflect.ValueOf(v) - if rv.IsNil() { - return "nil" - } - pv := reflect.Indirect(rv).Interface() - return fmt.Sprintf("*%v", pv) -} -func (m *Snapshot) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRecord - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Snapshot: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Snapshot: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType) - } - m.ID = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRecord - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.ID |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Parent", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRecord - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthRecord - } - postIndex := iNdEx + intStringLen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Parent = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Kind", wireType) - } - m.Kind = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRecord - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Kind |= (Kind(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 6: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Inodes", wireType) - } - m.Inodes = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRecord - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Inodes |= (int64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 7: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Size_", wireType) - } - m.Size_ = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRecord - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Size_ |= (int64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipRecord(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthRecord - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipRecord(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowRecord - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowRecord - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - return iNdEx, nil - case 1: - iNdEx += 8 - return iNdEx, nil - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowRecord - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - iNdEx += length - if length < 0 { - return 0, ErrInvalidLengthRecord - } - return iNdEx, nil - case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowRecord - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - innerWire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - innerWireType := int(innerWire & 0x7) - if innerWireType == 4 { - break - } - next, err := skipRecord(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil - case 4: - return iNdEx, nil - case 5: - iNdEx += 4 - return iNdEx, nil - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - } - panic("unreachable") -} - -var ( - ErrInvalidLengthRecord = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowRecord = fmt.Errorf("proto: integer overflow") -) - -func init() { - proto1.RegisterFile("github.com/containerd/containerd/snapshot/storage/proto/record.proto", fileDescriptorRecord) -} - -var fileDescriptorRecord = []byte{ - // 364 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x90, 0xbb, 0xae, 0xd3, 0x30, - 0x18, 0xc7, 0xe3, 0x9c, 0x28, 0xe7, 0xd4, 0x94, 0x12, 0x2c, 0x14, 0x45, 0x51, 0x65, 0x2c, 0xa6, - 0x88, 0x21, 0xe1, 0xf2, 0x04, 0xbd, 0x0d, 0x51, 0xd5, 0x56, 0x0a, 0xbd, 0xcc, 0x69, 0x6c, 0xa5, - 0x56, 0x55, 0xbb, 0x4a, 0x4c, 0x2b, 0x31, 0x31, 0x56, 0x79, 0x02, 0x96, 0x4c, 0xf0, 0x14, 0x3c, - 0x41, 0x47, 0x46, 0x26, 0x44, 0xf3, 0x24, 0x28, 0x69, 0x11, 0x0c, 0x67, 0xfb, 0x5f, 0x7e, 0xf6, - 0xf7, 0xe9, 0x83, 0xc3, 0x94, 0xab, 0xcd, 0xc7, 0xb5, 0x9f, 0xc8, 0x5d, 0x90, 0x48, 0xa1, 0x62, - 0x2e, 0x58, 0x46, 0xff, 0x97, 0xb9, 0x88, 0xf7, 0xf9, 0x46, 0xaa, 0x20, 0x57, 0x32, 0x8b, 0x53, - 0x16, 0xec, 0x33, 0xa9, 0x64, 0x90, 0xb1, 0x44, 0x66, 0xd4, 0x6f, 0x0c, 0xb2, 0xff, 0xf1, 0xfe, - 0x5f, 0xde, 0x3f, 0xbc, 0x75, 0x5f, 0xa4, 0x32, 0x95, 0x57, 0xbe, 0x56, 0x57, 0xfa, 0xd5, 0x17, - 0x00, 0x1f, 0x3e, 0xdc, 0x28, 0x64, 0x43, 0x9d, 0x53, 0x07, 0x10, 0xe0, 0x19, 0x7d, 0xb3, 0xfa, - 0xf5, 0x52, 0x0f, 0x87, 0x91, 0xce, 0x29, 0xb2, 0xa1, 0xb9, 0x8f, 0x33, 0x26, 0x94, 0xa3, 0x13, - 0xe0, 0xb5, 0xa2, 0x9b, 0x43, 0x6f, 0xa0, 0xb1, 0xe5, 0x82, 0x3a, 0x06, 0x01, 0x5e, 0xe7, 0x5d, - 0xd7, 0x7f, 0x7c, 0xb2, 0x3f, 0xe6, 0x82, 0x46, 0x0d, 0x59, 0xff, 0xc4, 0x85, 0xa4, 0x2c, 0x77, - 0x4c, 0x02, 0xbc, 0xbb, 0xe8, 0xe6, 0x10, 0x82, 0x46, 0xce, 0x3f, 0x31, 0xe7, 0xbe, 0x49, 0x1b, - 0xfd, 0xfa, 0x04, 0xa0, 0x51, 0x3f, 0x45, 0x5d, 0x78, 0xbf, 0x98, 0x8e, 0xa7, 0xb3, 0xd5, 0xd4, - 0xd2, 0xdc, 0x67, 0x45, 0x49, 0x9e, 0xd4, 0xf1, 0x42, 0x6c, 0x85, 0x3c, 0x0a, 0x64, 0x43, 0x63, - 0x19, 0x8e, 0x56, 0x16, 0x70, 0xdb, 0x45, 0x49, 0x1e, 0xea, 0x6a, 0xc9, 0xd9, 0x11, 0xb9, 0xd0, - 0xec, 0x0d, 0xe6, 0xe1, 0x72, 0x64, 0xe9, 0x6e, 0xa7, 0x28, 0x09, 0xac, 0x9b, 0x5e, 0xa2, 0xf8, - 0x81, 0x21, 0x02, 0x5b, 0x83, 0xd9, 0x64, 0x12, 0xce, 0xe7, 0xa3, 0xa1, 0x75, 0xe7, 0x3e, 0x2f, - 0x4a, 0xf2, 0xb4, 0xae, 0x07, 0x72, 0xb7, 0xe3, 0x4a, 0x31, 0xea, 0xb6, 0x4f, 0x5f, 0xb1, 0xf6, - 0xfd, 0x1b, 0x6e, 0x36, 0xe8, 0x3b, 0xe7, 0x0b, 0xd6, 0x7e, 0x5e, 0xb0, 0xf6, 0xb9, 0xc2, 0xe0, - 0x5c, 0x61, 0xf0, 0xa3, 0xc2, 0xe0, 0x77, 0x85, 0xc1, 0xda, 0x6c, 0xce, 0xf8, 0xfe, 0x4f, 0x00, - 0x00, 0x00, 0xff, 0xff, 0x61, 0xef, 0x92, 0x3d, 0xbc, 0x01, 0x00, 0x00, -} diff --git a/snapshot/storage/proto/record.proto b/snapshot/storage/proto/record.proto deleted file mode 100644 index 50a462a07..000000000 --- a/snapshot/storage/proto/record.proto +++ /dev/null @@ -1,34 +0,0 @@ -syntax = "proto3"; - -package containerd.snapshot.v1; - -import "gogoproto/gogo.proto"; - -enum Kind { - option (gogoproto.goproto_enum_prefix) = false; - option (gogoproto.enum_customname) = "Kind"; - - UNKNOWN = 0 [(gogoproto.enumvalue_customname) = "KindUnknown"]; - VIEW = 1 [(gogoproto.enumvalue_customname) = "KindView"]; - ACTIVE = 2 [(gogoproto.enumvalue_customname) = "KindActive"]; - COMMITTED = 3 [(gogoproto.enumvalue_customname) = "KindCommitted"]; -} - -// Snapshot defines the storage type for a snapshot in the -// metadata store. -message Snapshot { - uint64 id = 1; - string parent = 2; - Kind kind = 4; - - // inodes stores the number inodes in use for the snapshot. - // - // Only valid for committed snapshots. - int64 inodes = 6; - - // Size reports the disk used by the snapshot, excluding the parents. - // - // Only valid for committed snapshots, active snapshots must read the - // current usage from the disk. - int64 size = 7; -}