Move boltdb implementation to storage package
Removes storage interface and replaces with storage functions. Signed-off-by: Derek McGowan <derek@mcgstyle.net>
This commit is contained in:
parent
8affca40bb
commit
b319ba7c5a
12 changed files with 373 additions and 404 deletions
|
@ -12,7 +12,6 @@ import (
|
||||||
"github.com/containerd/containerd/plugin"
|
"github.com/containerd/containerd/plugin"
|
||||||
"github.com/containerd/containerd/snapshot"
|
"github.com/containerd/containerd/snapshot"
|
||||||
"github.com/containerd/containerd/snapshot/storage"
|
"github.com/containerd/containerd/snapshot/storage"
|
||||||
"github.com/containerd/containerd/snapshot/storage/boltdb"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/stevvooe/go-btrfs"
|
"github.com/stevvooe/go-btrfs"
|
||||||
)
|
)
|
||||||
|
@ -32,13 +31,7 @@ func init() {
|
||||||
// TODO: check device for root
|
// TODO: check device for root
|
||||||
return nil, errors.Errorf("btrfs requires \"device\" configuration")
|
return nil, errors.Errorf("btrfs requires \"device\" configuration")
|
||||||
}
|
}
|
||||||
|
return NewSnapshotter(conf.Device, root)
|
||||||
ms, err := boltdb.NewMetaStore(ic.Context, filepath.Join(root, "metadata.db"))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewSnapshotter(conf.Device, root, ms)
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -46,10 +39,10 @@ func init() {
|
||||||
type Snapshotter struct {
|
type Snapshotter struct {
|
||||||
device string // maybe we can resolve it with path?
|
device string // maybe we can resolve it with path?
|
||||||
root string // root provides paths for internal storage.
|
root string // root provides paths for internal storage.
|
||||||
ms storage.MetaStore
|
ms *storage.MetaStore
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSnapshotter(device, root string, ms storage.MetaStore) (snapshot.Snapshotter, error) {
|
func NewSnapshotter(device, root string) (snapshot.Snapshotter, error) {
|
||||||
var (
|
var (
|
||||||
active = filepath.Join(root, "active")
|
active = filepath.Join(root, "active")
|
||||||
snapshots = filepath.Join(root, "snapshots")
|
snapshots = filepath.Join(root, "snapshots")
|
||||||
|
@ -63,6 +56,10 @@ func NewSnapshotter(device, root string, ms storage.MetaStore) (snapshot.Snapsho
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ms, err := storage.NewMetaStore(filepath.Join(root, "metadata.db"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return &Snapshotter{
|
return &Snapshotter{
|
||||||
device: device,
|
device: device,
|
||||||
|
@ -82,7 +79,7 @@ func (b *Snapshotter) Stat(ctx context.Context, key string) (snapshot.Info, erro
|
||||||
return snapshot.Info{}, err
|
return snapshot.Info{}, err
|
||||||
}
|
}
|
||||||
defer t.Rollback()
|
defer t.Rollback()
|
||||||
return b.ms.Stat(ctx, key)
|
return storage.GetInfo(ctx, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Walk the committed snapshots.
|
// Walk the committed snapshots.
|
||||||
|
@ -92,7 +89,7 @@ func (b *Snapshotter) Walk(ctx context.Context, fn func(context.Context, snapsho
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer t.Rollback()
|
defer t.Rollback()
|
||||||
return b.ms.Walk(ctx, fn)
|
return storage.WalkInfo(ctx, fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Snapshotter) Prepare(ctx context.Context, key, parent string) ([]containerd.Mount, error) {
|
func (b *Snapshotter) Prepare(ctx context.Context, key, parent string) ([]containerd.Mount, error) {
|
||||||
|
@ -116,7 +113,7 @@ func (b *Snapshotter) makeActive(ctx context.Context, key, parent string, readon
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
a, err := b.ms.CreateActive(ctx, key, parent, readonly)
|
a, err := storage.CreateActive(ctx, key, parent, readonly)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -187,7 +184,7 @@ func (b *Snapshotter) Commit(ctx context.Context, name, key string) (err error)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
id, err := b.ms.Commit(ctx, key, name)
|
id, err := storage.CommitActive(ctx, key, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to commit")
|
return errors.Wrap(err, "failed to commit")
|
||||||
}
|
}
|
||||||
|
@ -225,7 +222,7 @@ func (b *Snapshotter) Mounts(ctx context.Context, key string) ([]containerd.Moun
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
a, err := b.ms.GetActive(ctx, key)
|
a, err := storage.GetActive(ctx, key)
|
||||||
t.Rollback()
|
t.Rollback()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to get active snapshot")
|
return nil, errors.Wrap(err, "failed to get active snapshot")
|
||||||
|
@ -260,7 +257,7 @@ func (b *Snapshotter) Remove(ctx context.Context, key string) (err error) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
id, k, err := b.ms.Remove(ctx, key)
|
id, k, err := storage.Remove(ctx, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to remove snapshot")
|
return errors.Wrap(err, "failed to remove snapshot")
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
|
|
||||||
"github.com/containerd/containerd"
|
"github.com/containerd/containerd"
|
||||||
"github.com/containerd/containerd/snapshot"
|
"github.com/containerd/containerd/snapshot"
|
||||||
"github.com/containerd/containerd/snapshot/storage/boltdb"
|
|
||||||
"github.com/containerd/containerd/snapshot/testsuite"
|
"github.com/containerd/containerd/snapshot/testsuite"
|
||||||
"github.com/containerd/containerd/testutil"
|
"github.com/containerd/containerd/testutil"
|
||||||
)
|
)
|
||||||
|
@ -23,11 +22,7 @@ const (
|
||||||
func boltSnapshotter(t *testing.T) func(context.Context, string) (snapshot.Snapshotter, func(), error) {
|
func boltSnapshotter(t *testing.T) func(context.Context, string) (snapshot.Snapshotter, func(), error) {
|
||||||
return func(ctx context.Context, root string) (snapshot.Snapshotter, func(), error) {
|
return func(ctx context.Context, root string) (snapshot.Snapshotter, func(), error) {
|
||||||
device := setupBtrfsLoopbackDevice(t, root)
|
device := setupBtrfsLoopbackDevice(t, root)
|
||||||
store, err := boltdb.NewMetaStore(ctx, filepath.Join(root, "metadata.db"))
|
snapshotter, err := NewSnapshotter(device.deviceName, root)
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
snapshotter, err := NewSnapshotter(device.deviceName, root, store)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ import (
|
||||||
"github.com/containerd/containerd/plugin"
|
"github.com/containerd/containerd/plugin"
|
||||||
"github.com/containerd/containerd/snapshot"
|
"github.com/containerd/containerd/snapshot"
|
||||||
"github.com/containerd/containerd/snapshot/storage"
|
"github.com/containerd/containerd/snapshot/storage"
|
||||||
"github.com/containerd/containerd/snapshot/storage/boltdb"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -21,19 +20,14 @@ func init() {
|
||||||
plugin.Register("snapshot-overlay", &plugin.Registration{
|
plugin.Register("snapshot-overlay", &plugin.Registration{
|
||||||
Type: plugin.SnapshotPlugin,
|
Type: plugin.SnapshotPlugin,
|
||||||
Init: func(ic *plugin.InitContext) (interface{}, error) {
|
Init: func(ic *plugin.InitContext) (interface{}, error) {
|
||||||
root := filepath.Join(ic.Root, "snapshot", "overlay")
|
return NewSnapshotter(filepath.Join(ic.Root, "snapshot", "overlay"))
|
||||||
ms, err := boltdb.NewMetaStore(ic.Context, filepath.Join(root, "metadata.db"))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return NewSnapshotter(root, ms)
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type Snapshotter struct {
|
type Snapshotter struct {
|
||||||
root string
|
root string
|
||||||
ms storage.MetaStore
|
ms *storage.MetaStore
|
||||||
}
|
}
|
||||||
|
|
||||||
type activeSnapshot struct {
|
type activeSnapshot struct {
|
||||||
|
@ -43,11 +37,16 @@ type activeSnapshot struct {
|
||||||
readonly bool
|
readonly bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSnapshotter(root string, ms storage.MetaStore) (snapshot.Snapshotter, error) {
|
func NewSnapshotter(root string) (snapshot.Snapshotter, error) {
|
||||||
if err := os.MkdirAll(root, 0700); err != nil {
|
if err := os.MkdirAll(root, 0700); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := os.MkdirAll(filepath.Join(root, "snapshots"), 0700); err != nil {
|
ms, err := storage.NewMetaStore(filepath.Join(root, "metadata.db"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.Mkdir(filepath.Join(root, "snapshots"), 0700); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +67,7 @@ func (o *Snapshotter) Stat(ctx context.Context, key string) (snapshot.Info, erro
|
||||||
return snapshot.Info{}, err
|
return snapshot.Info{}, err
|
||||||
}
|
}
|
||||||
defer t.Rollback()
|
defer t.Rollback()
|
||||||
return o.ms.Stat(ctx, key)
|
return storage.GetInfo(ctx, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Snapshotter) Prepare(ctx context.Context, key, parent string) ([]containerd.Mount, error) {
|
func (o *Snapshotter) Prepare(ctx context.Context, key, parent string) ([]containerd.Mount, error) {
|
||||||
|
@ -88,7 +87,7 @@ func (o *Snapshotter) Mounts(ctx context.Context, key string) ([]containerd.Moun
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
active, err := o.ms.GetActive(ctx, key)
|
active, err := storage.GetActive(ctx, key)
|
||||||
t.Rollback()
|
t.Rollback()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to get active mount")
|
return nil, errors.Wrap(err, "failed to get active mount")
|
||||||
|
@ -101,7 +100,7 @@ func (o *Snapshotter) Commit(ctx context.Context, name, key string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := o.ms.Commit(ctx, key, name); err != nil {
|
if _, err := storage.CommitActive(ctx, key, name); err != nil {
|
||||||
if rerr := t.Rollback(); rerr != nil {
|
if rerr := t.Rollback(); rerr != nil {
|
||||||
log.G(ctx).WithError(rerr).Warn("Failure rolling back transaction")
|
log.G(ctx).WithError(rerr).Warn("Failure rolling back transaction")
|
||||||
}
|
}
|
||||||
|
@ -125,7 +124,7 @@ func (o *Snapshotter) Remove(ctx context.Context, key string) (err error) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
id, _, err := o.ms.Remove(ctx, key)
|
id, _, err := storage.Remove(ctx, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to remove")
|
return errors.Wrap(err, "failed to remove")
|
||||||
}
|
}
|
||||||
|
@ -160,7 +159,7 @@ func (o *Snapshotter) Walk(ctx context.Context, fn func(context.Context, snapsho
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer t.Rollback()
|
defer t.Rollback()
|
||||||
return o.ms.Walk(ctx, fn)
|
return storage.WalkInfo(ctx, fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Snapshotter) createActive(ctx context.Context, key, parent string, readonly bool) ([]containerd.Mount, error) {
|
func (o *Snapshotter) createActive(ctx context.Context, key, parent string, readonly bool) ([]containerd.Mount, error) {
|
||||||
|
@ -202,7 +201,7 @@ func (o *Snapshotter) createActive(ctx context.Context, key, parent string, read
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
active, err := o.ms.CreateActive(ctx, key, parent, readonly)
|
active, err := storage.CreateActive(ctx, key, parent, readonly)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if rerr := t.Rollback(); rerr != nil {
|
if rerr := t.Rollback(); rerr != nil {
|
||||||
log.G(ctx).WithError(rerr).Warn("Failure rolling back transaction")
|
log.G(ctx).WithError(rerr).Warn("Failure rolling back transaction")
|
||||||
|
@ -211,7 +210,7 @@ func (o *Snapshotter) createActive(ctx context.Context, key, parent string, read
|
||||||
}
|
}
|
||||||
|
|
||||||
path = filepath.Join(snapshotDir, active.ID)
|
path = filepath.Join(snapshotDir, active.ID)
|
||||||
if err := os.Rename(td, path); err != nil {
|
if err = os.Rename(td, path); err != nil {
|
||||||
if rerr := t.Rollback(); rerr != nil {
|
if rerr := t.Rollback(); rerr != nil {
|
||||||
log.G(ctx).WithError(rerr).Warn("Failure rolling back transaction")
|
log.G(ctx).WithError(rerr).Warn("Failure rolling back transaction")
|
||||||
}
|
}
|
||||||
|
@ -219,7 +218,7 @@ func (o *Snapshotter) createActive(ctx context.Context, key, parent string, read
|
||||||
}
|
}
|
||||||
td = ""
|
td = ""
|
||||||
|
|
||||||
if err := t.Commit(); err != nil {
|
if err = t.Commit(); err != nil {
|
||||||
return nil, errors.Wrap(err, "commit failed")
|
return nil, errors.Wrap(err, "commit failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,17 +11,13 @@ import (
|
||||||
|
|
||||||
"github.com/containerd/containerd"
|
"github.com/containerd/containerd"
|
||||||
"github.com/containerd/containerd/snapshot"
|
"github.com/containerd/containerd/snapshot"
|
||||||
"github.com/containerd/containerd/snapshot/storage/boltdb"
|
"github.com/containerd/containerd/snapshot/storage"
|
||||||
"github.com/containerd/containerd/snapshot/testsuite"
|
"github.com/containerd/containerd/snapshot/testsuite"
|
||||||
"github.com/containerd/containerd/testutil"
|
"github.com/containerd/containerd/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func boltSnapshotter(ctx context.Context, root string) (snapshot.Snapshotter, func(), error) {
|
func newSnapshotter(ctx context.Context, root string) (snapshot.Snapshotter, func(), error) {
|
||||||
store, err := boltdb.NewMetaStore(ctx, filepath.Join(root, "metadata.db"))
|
snapshotter, err := NewSnapshotter(root)
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
snapshotter, err := NewSnapshotter(root, store)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -31,7 +27,7 @@ func boltSnapshotter(ctx context.Context, root string) (snapshot.Snapshotter, fu
|
||||||
|
|
||||||
func TestOverlay(t *testing.T) {
|
func TestOverlay(t *testing.T) {
|
||||||
testutil.RequiresRoot(t)
|
testutil.RequiresRoot(t)
|
||||||
testsuite.SnapshotterSuite(t, "Overlay", boltSnapshotter)
|
testsuite.SnapshotterSuite(t, "Overlay", newSnapshotter)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOverlayMounts(t *testing.T) {
|
func TestOverlayMounts(t *testing.T) {
|
||||||
|
@ -41,7 +37,7 @@ func TestOverlayMounts(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(root)
|
defer os.RemoveAll(root)
|
||||||
o, _, err := boltSnapshotter(ctx, root)
|
o, _, err := newSnapshotter(ctx, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
|
@ -77,7 +73,7 @@ func TestOverlayCommit(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(root)
|
defer os.RemoveAll(root)
|
||||||
o, _, err := boltSnapshotter(ctx, root)
|
o, _, err := newSnapshotter(ctx, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
|
@ -106,7 +102,7 @@ func TestOverlayOverlayMount(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(root)
|
defer os.RemoveAll(root)
|
||||||
o, _, err := boltSnapshotter(ctx, root)
|
o, _, err := newSnapshotter(ctx, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
|
@ -160,7 +156,7 @@ func getBasePath(ctx context.Context, sn snapshot.Snapshotter, root, key string)
|
||||||
}
|
}
|
||||||
defer t.Rollback()
|
defer t.Rollback()
|
||||||
|
|
||||||
active, err := o.ms.GetActive(ctx, key)
|
active, err := storage.GetActive(ctx, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -175,7 +171,7 @@ func getParents(ctx context.Context, sn snapshot.Snapshotter, root, key string)
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
defer t.Rollback()
|
defer t.Rollback()
|
||||||
active, err := o.ms.GetActive(ctx, key)
|
active, err := storage.GetActive(ctx, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -194,7 +190,7 @@ func TestOverlayOverlayRead(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(root)
|
defer os.RemoveAll(root)
|
||||||
o, _, err := boltSnapshotter(ctx, root)
|
o, _, err := newSnapshotter(ctx, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
|
@ -246,7 +242,7 @@ func TestOverlayView(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(root)
|
defer os.RemoveAll(root)
|
||||||
o, _, err := boltSnapshotter(ctx, root)
|
o, _, err := newSnapshotter(ctx, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package boltdb
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -7,7 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/boltdb/bolt"
|
"github.com/boltdb/bolt"
|
||||||
"github.com/containerd/containerd/snapshot"
|
"github.com/containerd/containerd/snapshot"
|
||||||
"github.com/containerd/containerd/snapshot/storage"
|
db "github.com/containerd/containerd/snapshot/storage/proto"
|
||||||
"github.com/gogo/protobuf/proto"
|
"github.com/gogo/protobuf/proto"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
@ -23,91 +23,14 @@ type boltFileTransactor struct {
|
||||||
tx *bolt.Tx
|
tx *bolt.Tx
|
||||||
}
|
}
|
||||||
|
|
||||||
type boltMetastore struct {
|
func (bft *boltFileTransactor) Rollback() error {
|
||||||
dbfile string
|
defer bft.db.Close()
|
||||||
|
return bft.tx.Rollback()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMetaStore returns a snapshot MetaStore for storage of metadata related to
|
func (bft *boltFileTransactor) Commit() error {
|
||||||
// a snapshot driver backed by a bolt file database. This implementation is
|
defer bft.db.Close()
|
||||||
// strongly consistent and does all metadata changes in a transaction to prevent
|
return bft.tx.Commit()
|
||||||
// against process crashes causing inconsistent metadata state.
|
|
||||||
func NewMetaStore(ctx context.Context, dbfile string) (storage.MetaStore, error) {
|
|
||||||
return &boltMetastore{
|
|
||||||
dbfile: dbfile,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ms *boltFileTransactor) Rollback() error {
|
|
||||||
defer ms.db.Close()
|
|
||||||
return ms.tx.Rollback()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ms *boltFileTransactor) Commit() error {
|
|
||||||
defer ms.db.Close()
|
|
||||||
return ms.tx.Commit()
|
|
||||||
}
|
|
||||||
|
|
||||||
type transactionKey struct{}
|
|
||||||
|
|
||||||
func (ms *boltMetastore) TransactionContext(ctx context.Context, writable bool) (context.Context, storage.Transactor, error) {
|
|
||||||
db, err := bolt.Open(ms.dbfile, 0600, nil)
|
|
||||||
if err != nil {
|
|
||||||
return ctx, nil, errors.Wrap(err, "failed to open database file")
|
|
||||||
}
|
|
||||||
|
|
||||||
tx, err := db.Begin(writable)
|
|
||||||
if err != nil {
|
|
||||||
return ctx, nil, errors.Wrap(err, "failed to start transaction")
|
|
||||||
}
|
|
||||||
|
|
||||||
t := &boltFileTransactor{
|
|
||||||
db: db,
|
|
||||||
tx: tx,
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = context.WithValue(ctx, transactionKey{}, t)
|
|
||||||
|
|
||||||
return ctx, t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ms *boltMetastore) withBucket(ctx context.Context, fn func(context.Context, *bolt.Bucket, *bolt.Bucket) error) error {
|
|
||||||
t, ok := ctx.Value(transactionKey{}).(*boltFileTransactor)
|
|
||||||
if !ok {
|
|
||||||
return errors.Errorf("no transaction in context")
|
|
||||||
}
|
|
||||||
bkt := t.tx.Bucket(bucketKeyStorageVersion)
|
|
||||||
if bkt == nil {
|
|
||||||
return errors.Wrap(snapshot.ErrSnapshotNotExist, "bucket does not exist")
|
|
||||||
}
|
|
||||||
return fn(ctx, bkt.Bucket(bucketKeySnapshot), bkt.Bucket(bucketKeyParents))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ms *boltMetastore) createBucketIfNotExists(ctx context.Context, fn func(context.Context, *bolt.Bucket, *bolt.Bucket) error) error {
|
|
||||||
t, ok := ctx.Value(transactionKey{}).(*boltFileTransactor)
|
|
||||||
if !ok {
|
|
||||||
return errors.Errorf("no transaction in context")
|
|
||||||
}
|
|
||||||
|
|
||||||
bkt, err := t.tx.CreateBucketIfNotExists(bucketKeyStorageVersion)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to create version bucket")
|
|
||||||
}
|
|
||||||
sbkt, err := bkt.CreateBucketIfNotExists(bucketKeySnapshot)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to create snapshots bucket")
|
|
||||||
}
|
|
||||||
pbkt, err := bkt.CreateBucketIfNotExists(bucketKeyParents)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to create snapshots bucket")
|
|
||||||
}
|
|
||||||
return fn(ctx, sbkt, pbkt)
|
|
||||||
}
|
|
||||||
|
|
||||||
func fromProtoKind(k Kind) snapshot.Kind {
|
|
||||||
if k == KindActive {
|
|
||||||
return snapshot.KindActive
|
|
||||||
}
|
|
||||||
return snapshot.KindCommitted
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// parentKey returns a composite key of the parent and child identifiers. The
|
// parentKey returns a composite key of the parent and child identifiers. The
|
||||||
|
@ -134,9 +57,11 @@ func getParentPrefix(b []byte) uint64 {
|
||||||
return parent
|
return parent
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *boltMetastore) Stat(ctx context.Context, key string) (snapshot.Info, error) {
|
// GetInfo returns the snapshot Info directly from the metadata. Requires a
|
||||||
var ss Snapshot
|
// context with a storage transaction.
|
||||||
err := ms.withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error {
|
func GetInfo(ctx context.Context, key string) (snapshot.Info, error) {
|
||||||
|
var ss db.Snapshot
|
||||||
|
err := withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error {
|
||||||
return getSnapshot(bkt, key, &ss)
|
return getSnapshot(bkt, key, &ss)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -151,14 +76,17 @@ func (ms *boltMetastore) Stat(ctx context.Context, key string) (snapshot.Info, e
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *boltMetastore) Walk(ctx context.Context, fn func(context.Context, snapshot.Info) error) error {
|
// WalkInfo iterates through all metadata Info for the stored snapshots and
|
||||||
return ms.withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error {
|
// calls the provided function for each. Requires a context with a storage
|
||||||
|
// transaction.
|
||||||
|
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 {
|
return bkt.ForEach(func(k, v []byte) error {
|
||||||
// skip nested buckets
|
// skip nested buckets
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var ss Snapshot
|
var ss db.Snapshot
|
||||||
if err := proto.Unmarshal(v, &ss); err != nil {
|
if err := proto.Unmarshal(v, &ss); err != nil {
|
||||||
return errors.Wrap(err, "failed to unmarshal snapshot")
|
return errors.Wrap(err, "failed to unmarshal snapshot")
|
||||||
}
|
}
|
||||||
|
@ -174,18 +102,23 @@ func (ms *boltMetastore) Walk(ctx context.Context, fn func(context.Context, snap
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *boltMetastore) CreateActive(ctx context.Context, key, parent string, readonly bool) (a storage.Active, err error) {
|
// CreateActive creates a new active snapshot transaction referenced by
|
||||||
err = ms.createBucketIfNotExists(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error {
|
// the provided key. The new active snapshot will have the provided
|
||||||
|
// parent. If the readonly option is given, the active snapshot will be
|
||||||
|
// marked as readonly and can only be removed, and not committed. The
|
||||||
|
// provided context must contain a writable transaction.
|
||||||
|
func CreateActive(ctx context.Context, key, parent string, readonly bool) (a Active, err error) {
|
||||||
|
err = createBucketIfNotExists(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error {
|
||||||
var (
|
var (
|
||||||
parentS *Snapshot
|
parentS *db.Snapshot
|
||||||
)
|
)
|
||||||
if parent != "" {
|
if parent != "" {
|
||||||
parentS = new(Snapshot)
|
parentS = new(db.Snapshot)
|
||||||
if err := getSnapshot(bkt, parent, parentS); err != nil {
|
if err := getSnapshot(bkt, parent, parentS); err != nil {
|
||||||
return errors.Wrap(err, "failed to get parent snapshot")
|
return errors.Wrap(err, "failed to get parent snapshot")
|
||||||
}
|
}
|
||||||
|
|
||||||
if parentS.Kind != KindCommitted {
|
if parentS.Kind != db.KindCommitted {
|
||||||
return errors.Wrap(snapshot.ErrSnapshotNotCommitted, "parent is not committed snapshot")
|
return errors.Wrap(snapshot.ErrSnapshotNotCommitted, "parent is not committed snapshot")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -199,10 +132,10 @@ func (ms *boltMetastore) CreateActive(ctx context.Context, key, parent string, r
|
||||||
return errors.Wrap(err, "unable to get identifier")
|
return errors.Wrap(err, "unable to get identifier")
|
||||||
}
|
}
|
||||||
|
|
||||||
ss := Snapshot{
|
ss := db.Snapshot{
|
||||||
ID: id,
|
ID: id,
|
||||||
Parent: parent,
|
Parent: parent,
|
||||||
Kind: KindActive,
|
Kind: db.KindActive,
|
||||||
Readonly: readonly,
|
Readonly: readonly,
|
||||||
}
|
}
|
||||||
if err := putSnapshot(bkt, key, &ss); err != nil {
|
if err := putSnapshot(bkt, key, &ss); err != nil {
|
||||||
|
@ -216,7 +149,7 @@ func (ms *boltMetastore) CreateActive(ctx context.Context, key, parent string, r
|
||||||
return errors.Wrap(err, "failed to write parent link")
|
return errors.Wrap(err, "failed to write parent link")
|
||||||
}
|
}
|
||||||
|
|
||||||
a.ParentIDs, err = ms.parents(bkt, parentS)
|
a.ParentIDs, err = parents(bkt, parentS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to get parent chain")
|
return errors.Wrap(err, "failed to get parent chain")
|
||||||
}
|
}
|
||||||
|
@ -228,24 +161,26 @@ func (ms *boltMetastore) CreateActive(ctx context.Context, key, parent string, r
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return storage.Active{}, err
|
return Active{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *boltMetastore) GetActive(ctx context.Context, key string) (a storage.Active, err error) {
|
// GetActive returns the metadata for the active snapshot transaction referenced
|
||||||
err = ms.withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error {
|
// by the given key. Requires a context with a storage transaction.
|
||||||
|
func GetActive(ctx context.Context, key string) (a Active, err error) {
|
||||||
|
err = withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error {
|
||||||
b := bkt.Get([]byte(key))
|
b := bkt.Get([]byte(key))
|
||||||
if len(b) == 0 {
|
if len(b) == 0 {
|
||||||
return snapshot.ErrSnapshotNotExist
|
return snapshot.ErrSnapshotNotExist
|
||||||
}
|
}
|
||||||
|
|
||||||
var ss Snapshot
|
var ss db.Snapshot
|
||||||
if err := proto.Unmarshal(b, &ss); err != nil {
|
if err := proto.Unmarshal(b, &ss); err != nil {
|
||||||
return errors.Wrap(err, "failed to unmarshal snapshot")
|
return errors.Wrap(err, "failed to unmarshal snapshot")
|
||||||
}
|
}
|
||||||
if ss.Kind != KindActive {
|
if ss.Kind != db.KindActive {
|
||||||
return snapshot.ErrSnapshotNotActive
|
return snapshot.ErrSnapshotNotActive
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,12 +188,12 @@ func (ms *boltMetastore) GetActive(ctx context.Context, key string) (a storage.A
|
||||||
a.Readonly = ss.Readonly
|
a.Readonly = ss.Readonly
|
||||||
|
|
||||||
if ss.Parent != "" {
|
if ss.Parent != "" {
|
||||||
var parent Snapshot
|
var parent db.Snapshot
|
||||||
if err := getSnapshot(bkt, ss.Parent, &parent); err != nil {
|
if err := getSnapshot(bkt, ss.Parent, &parent); err != nil {
|
||||||
return errors.Wrap(err, "failed to get parent snapshot")
|
return errors.Wrap(err, "failed to get parent snapshot")
|
||||||
}
|
}
|
||||||
|
|
||||||
a.ParentIDs, err = ms.parents(bkt, &parent)
|
a.ParentIDs, err = parents(bkt, &parent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to get parent chain")
|
return errors.Wrap(err, "failed to get parent chain")
|
||||||
}
|
}
|
||||||
|
@ -266,33 +201,18 @@ func (ms *boltMetastore) GetActive(ctx context.Context, key string) (a storage.A
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return storage.Active{}, err
|
return Active{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *boltMetastore) parents(bkt *bolt.Bucket, parent *Snapshot) (parents []string, err error) {
|
// Remove removes a snapshot from the metastore. The string identifier for the
|
||||||
for {
|
// snapshot is returned as well as the kind. The provided context must contain a
|
||||||
parents = append(parents, fmt.Sprintf("%d", parent.ID))
|
// writable transaction.
|
||||||
|
func Remove(ctx context.Context, key string) (id string, k snapshot.Kind, err error) {
|
||||||
if parent.Parent == "" {
|
err = withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error {
|
||||||
return
|
var ss db.Snapshot
|
||||||
}
|
|
||||||
|
|
||||||
var ps Snapshot
|
|
||||||
if err := getSnapshot(bkt, parent.Parent, &ps); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "failed to get parent snapshot")
|
|
||||||
}
|
|
||||||
parent = &ps
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ms *boltMetastore) Remove(ctx context.Context, key string) (id string, k snapshot.Kind, err error) {
|
|
||||||
err = ms.withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error {
|
|
||||||
var ss Snapshot
|
|
||||||
b := bkt.Get([]byte(key))
|
b := bkt.Get([]byte(key))
|
||||||
if len(b) == 0 {
|
if len(b) == 0 {
|
||||||
return snapshot.ErrSnapshotNotExist
|
return snapshot.ErrSnapshotNotExist
|
||||||
|
@ -309,7 +229,7 @@ func (ms *boltMetastore) Remove(ctx context.Context, key string) (id string, k s
|
||||||
}
|
}
|
||||||
|
|
||||||
if ss.Parent != "" {
|
if ss.Parent != "" {
|
||||||
var ps Snapshot
|
var ps db.Snapshot
|
||||||
if err := getSnapshot(bkt, ss.Parent, &ps); err != nil {
|
if err := getSnapshot(bkt, ss.Parent, &ps); err != nil {
|
||||||
return errors.Wrap(err, "failed to get parent snapshot")
|
return errors.Wrap(err, "failed to get parent snapshot")
|
||||||
}
|
}
|
||||||
|
@ -333,25 +253,31 @@ func (ms *boltMetastore) Remove(ctx context.Context, key string) (id string, k s
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *boltMetastore) Commit(ctx context.Context, key, name string) (id string, err error) {
|
// CommitActive renames the active snapshot transaction referenced by `key`
|
||||||
err = ms.withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error {
|
// as a committed snapshot referenced by `Name`. The resulting snapshot will be
|
||||||
|
// committed and readonly. The `key` reference will no longer be available for
|
||||||
|
// 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) (id string, err error) {
|
||||||
|
err = withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error {
|
||||||
b := bkt.Get([]byte(name))
|
b := bkt.Get([]byte(name))
|
||||||
if len(b) != 0 {
|
if len(b) != 0 {
|
||||||
return errors.Wrap(snapshot.ErrSnapshotExist, "committed name already exists")
|
return errors.Wrap(snapshot.ErrSnapshotExist, "committed name already exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
var ss Snapshot
|
var ss db.Snapshot
|
||||||
if err := getSnapshot(bkt, key, &ss); err != nil {
|
if err := getSnapshot(bkt, key, &ss); err != nil {
|
||||||
return errors.Wrap(err, "failed to get active snapshot")
|
return errors.Wrap(err, "failed to get active snapshot")
|
||||||
}
|
}
|
||||||
if ss.Kind != KindActive {
|
if ss.Kind != db.KindActive {
|
||||||
return snapshot.ErrSnapshotNotActive
|
return snapshot.ErrSnapshotNotActive
|
||||||
}
|
}
|
||||||
if ss.Readonly {
|
if ss.Readonly {
|
||||||
return errors.Errorf("active snapshot is readonly")
|
return errors.Errorf("active snapshot is readonly")
|
||||||
}
|
}
|
||||||
|
|
||||||
ss.Kind = KindCommitted
|
ss.Kind = db.KindCommitted
|
||||||
ss.Readonly = true
|
ss.Readonly = true
|
||||||
|
|
||||||
if err := putSnapshot(bkt, name, &ss); err != nil {
|
if err := putSnapshot(bkt, name, &ss); err != nil {
|
||||||
|
@ -372,7 +298,65 @@ func (ms *boltMetastore) Commit(ctx context.Context, key, name string) (id strin
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSnapshot(bkt *bolt.Bucket, key string, ss *Snapshot) error {
|
func withBucket(ctx context.Context, fn func(context.Context, *bolt.Bucket, *bolt.Bucket) error) error {
|
||||||
|
t, ok := ctx.Value(transactionKey{}).(*boltFileTransactor)
|
||||||
|
if !ok {
|
||||||
|
return errors.Errorf("no transaction in context")
|
||||||
|
}
|
||||||
|
bkt := t.tx.Bucket(bucketKeyStorageVersion)
|
||||||
|
if bkt == nil {
|
||||||
|
return errors.Wrap(snapshot.ErrSnapshotNotExist, "bucket does not exist")
|
||||||
|
}
|
||||||
|
return fn(ctx, bkt.Bucket(bucketKeySnapshot), bkt.Bucket(bucketKeyParents))
|
||||||
|
}
|
||||||
|
|
||||||
|
func createBucketIfNotExists(ctx context.Context, fn func(context.Context, *bolt.Bucket, *bolt.Bucket) error) error {
|
||||||
|
t, ok := ctx.Value(transactionKey{}).(*boltFileTransactor)
|
||||||
|
if !ok {
|
||||||
|
return errors.Errorf("no transaction in context")
|
||||||
|
}
|
||||||
|
|
||||||
|
bkt, err := t.tx.CreateBucketIfNotExists(bucketKeyStorageVersion)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to create version bucket")
|
||||||
|
}
|
||||||
|
sbkt, err := bkt.CreateBucketIfNotExists(bucketKeySnapshot)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to create snapshots bucket")
|
||||||
|
}
|
||||||
|
pbkt, err := bkt.CreateBucketIfNotExists(bucketKeyParents)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to create snapshots bucket")
|
||||||
|
}
|
||||||
|
return fn(ctx, sbkt, pbkt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func fromProtoKind(k db.Kind) snapshot.Kind {
|
||||||
|
if k == db.KindActive {
|
||||||
|
return snapshot.KindActive
|
||||||
|
}
|
||||||
|
return snapshot.KindCommitted
|
||||||
|
}
|
||||||
|
|
||||||
|
func parents(bkt *bolt.Bucket, parent *db.Snapshot) (parents []string, err error) {
|
||||||
|
for {
|
||||||
|
parents = append(parents, fmt.Sprintf("%d", parent.ID))
|
||||||
|
|
||||||
|
if parent.Parent == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var ps db.Snapshot
|
||||||
|
if err := getSnapshot(bkt, parent.Parent, &ps); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to get parent snapshot")
|
||||||
|
}
|
||||||
|
parent = &ps
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSnapshot(bkt *bolt.Bucket, key string, ss *db.Snapshot) error {
|
||||||
b := bkt.Get([]byte(key))
|
b := bkt.Get([]byte(key))
|
||||||
if len(b) == 0 {
|
if len(b) == 0 {
|
||||||
return snapshot.ErrSnapshotNotExist
|
return snapshot.ErrSnapshotNotExist
|
||||||
|
@ -383,7 +367,7 @@ func getSnapshot(bkt *bolt.Bucket, key string, ss *Snapshot) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func putSnapshot(bkt *bolt.Bucket, key string, ss *Snapshot) error {
|
func putSnapshot(bkt *bolt.Bucket, key string, ss *db.Snapshot) error {
|
||||||
b, err := proto.Marshal(ss)
|
b, err := proto.Marshal(ss)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to marshal snapshot")
|
return errors.Wrap(err, "failed to marshal snapshot")
|
21
snapshot/storage/bolt_test.go
Normal file
21
snapshot/storage/bolt_test.go
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
// Does not require root but flag must be defined for snapshot tests
|
||||||
|
_ "github.com/containerd/containerd/testutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMetastore(t *testing.T) {
|
||||||
|
MetaStoreSuite(t, "Metastore", func(root string) (*MetaStore, error) {
|
||||||
|
return NewMetaStore(filepath.Join(root, "metadata.db"))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSuite(b *testing.B) {
|
||||||
|
Benchmarks(b, "BoltDBBench", func(root string) (*MetaStore, error) {
|
||||||
|
return NewMetaStore(filepath.Join(root, "metadata.db"))
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,25 +0,0 @@
|
||||||
package boltdb
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/containerd/containerd/snapshot/storage"
|
|
||||||
"github.com/containerd/containerd/snapshot/storage/testsuite"
|
|
||||||
|
|
||||||
// Does not require root but flag must be defined for snapshot tests
|
|
||||||
_ "github.com/containerd/containerd/testutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestBoltDB(t *testing.T) {
|
|
||||||
testsuite.MetaStoreSuite(t, "BoltDB", func(ctx context.Context, root string) (storage.MetaStore, error) {
|
|
||||||
return NewMetaStore(ctx, filepath.Join(root, "metadata.db"))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkSuite(b *testing.B) {
|
|
||||||
testsuite.Benchmarks(b, "BoltDBBench", func(ctx context.Context, root string) (storage.MetaStore, error) {
|
|
||||||
return NewMetaStore(ctx, filepath.Join(root, "metadata.db"))
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -3,51 +3,10 @@ package storage
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/containerd/containerd/snapshot"
|
"github.com/boltdb/bolt"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MetaStore is used to store metadata related to a snapshot driver. The
|
|
||||||
// MetaStore is intended to store metadata related to name, state and
|
|
||||||
// parentage. Using the MetaStore is not required to implement a snapshot
|
|
||||||
// driver but can be used to handle the persistence and transactional
|
|
||||||
// complexities of a driver implementation.
|
|
||||||
type MetaStore interface {
|
|
||||||
// TransactionContext creates a new transaction context.
|
|
||||||
TransactionContext(ctx context.Context, writable bool) (context.Context, Transactor, error)
|
|
||||||
|
|
||||||
// Stat returns the snapshot stat Info directly from
|
|
||||||
// the metadata.
|
|
||||||
Stat(ctx context.Context, key string) (snapshot.Info, error)
|
|
||||||
|
|
||||||
// Walk iterates through all metadata for the stored
|
|
||||||
// snapshots and calls the provided function for each.
|
|
||||||
Walk(ctx context.Context, fn func(context.Context, snapshot.Info) error) error
|
|
||||||
|
|
||||||
// CreateActive creates a new active snapshot transaction referenced by
|
|
||||||
// the provided key. The new active snapshot will have the provided
|
|
||||||
// parent. If the readonly option is given, the active snapshot will be
|
|
||||||
// marked as readonly and can only be removed, and not committed. The
|
|
||||||
// provided context must contain a writable transaction.
|
|
||||||
CreateActive(ctx context.Context, key, parent string, readonly bool) (Active, error)
|
|
||||||
|
|
||||||
// GetActive returns the metadata for the active snapshot transaction
|
|
||||||
// referenced by the given key.
|
|
||||||
GetActive(ctx context.Context, key string) (Active, error)
|
|
||||||
|
|
||||||
// Remove removes a snapshot from the metastore. The provided context
|
|
||||||
// must contain a writable transaction. The string identifier for the
|
|
||||||
// snapshot is returned as well as the kind.
|
|
||||||
Remove(ctx context.Context, key string) (string, snapshot.Kind, error)
|
|
||||||
|
|
||||||
// Commit renames the active snapshot transaction referenced by `key`
|
|
||||||
// as a committed snapshot referenced by `Name`. The resulting snapshot
|
|
||||||
// will be committed and readonly. The `key` reference will no longer
|
|
||||||
// be available for lookup or removal. The returned string identifier
|
|
||||||
// for the committed snapshot is the same identifier of the original
|
|
||||||
// active snapshot.
|
|
||||||
Commit(ctx context.Context, key, name string) (string, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transactor is used to finalize an active transaction.
|
// Transactor is used to finalize an active transaction.
|
||||||
type Transactor interface {
|
type Transactor interface {
|
||||||
// Commit commits any changes made during the transaction.
|
// Commit commits any changes made during the transaction.
|
||||||
|
@ -67,3 +26,46 @@ type Active struct {
|
||||||
ParentIDs []string
|
ParentIDs []string
|
||||||
Readonly bool
|
Readonly bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MetaStore is used to store metadata related to a snapshot driver. The
|
||||||
|
// MetaStore is intended to store metadata related to name, state and
|
||||||
|
// parentage. Using the MetaStore is not required to implement a snapshot
|
||||||
|
// driver but can be used to handle the persistence and transactional
|
||||||
|
// complexities of a driver implementation.
|
||||||
|
type MetaStore struct {
|
||||||
|
dbfile string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMetaStore returns a snapshot MetaStore for storage of metadata related to
|
||||||
|
// a snapshot driver backed by a bolt file database. This implementation is
|
||||||
|
// strongly consistent and does all metadata changes in a transaction to prevent
|
||||||
|
// against process crashes causing inconsistent metadata state.
|
||||||
|
func NewMetaStore(dbfile string) (*MetaStore, error) {
|
||||||
|
return &MetaStore{
|
||||||
|
dbfile: dbfile,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type transactionKey struct{}
|
||||||
|
|
||||||
|
// TransactionContext creates a new transaction context.
|
||||||
|
func (ms *MetaStore) TransactionContext(ctx context.Context, writable bool) (context.Context, Transactor, error) {
|
||||||
|
db, err := bolt.Open(ms.dbfile, 0600, nil)
|
||||||
|
if err != nil {
|
||||||
|
return ctx, nil, errors.Wrap(err, "failed to open database file")
|
||||||
|
}
|
||||||
|
|
||||||
|
tx, err := db.Begin(writable)
|
||||||
|
if err != nil {
|
||||||
|
return ctx, nil, errors.Wrap(err, "failed to start transaction")
|
||||||
|
}
|
||||||
|
|
||||||
|
t := &boltFileTransactor{
|
||||||
|
db: db,
|
||||||
|
tx: tx,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = context.WithValue(ctx, transactionKey{}, t)
|
||||||
|
|
||||||
|
return ctx, t, nil
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package testsuite
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -6,13 +6,11 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/containerd/containerd/snapshot/storage"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Benchmarks returns a benchmark suite using the provided metadata store
|
// Benchmarks returns a benchmark suite using the provided metadata store
|
||||||
// creation method
|
// creation method
|
||||||
func Benchmarks(b *testing.B, name string, metaFn func(context.Context, string) (storage.MetaStore, error)) {
|
func Benchmarks(b *testing.B, name string, metaFn metaFactory) {
|
||||||
b.Run("StatActive", makeBench(b, name, metaFn, statActiveBenchmark))
|
b.Run("StatActive", makeBench(b, name, metaFn, statActiveBenchmark))
|
||||||
b.Run("StatCommitted", makeBench(b, name, metaFn, statCommittedBenchmark))
|
b.Run("StatCommitted", makeBench(b, name, metaFn, statCommittedBenchmark))
|
||||||
b.Run("CreateActive", makeBench(b, name, metaFn, createActiveBenchmark))
|
b.Run("CreateActive", makeBench(b, name, metaFn, createActiveBenchmark))
|
||||||
|
@ -24,7 +22,7 @@ func Benchmarks(b *testing.B, name string, metaFn func(context.Context, string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeBench creates a benchmark with a writable transaction
|
// makeBench creates a benchmark with a writable transaction
|
||||||
func makeBench(b *testing.B, name string, metaFn func(context.Context, string) (storage.MetaStore, error), fn func(context.Context, *testing.B, storage.MetaStore)) func(b *testing.B) {
|
func makeBench(b *testing.B, name string, metaFn metaFactory, fn func(context.Context, *testing.B, *MetaStore)) func(b *testing.B) {
|
||||||
return func(b *testing.B) {
|
return func(b *testing.B) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
tmpDir, err := ioutil.TempDir("", "metastore-bench-"+name+"-")
|
tmpDir, err := ioutil.TempDir("", "metastore-bench-"+name+"-")
|
||||||
|
@ -33,7 +31,7 @@ func makeBench(b *testing.B, name string, metaFn func(context.Context, string) (
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(tmpDir)
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
ms, err := metaFn(ctx, tmpDir)
|
ms, err := metaFn(tmpDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -49,7 +47,7 @@ func makeBench(b *testing.B, name string, metaFn func(context.Context, string) (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func openCloseWritable(b *testing.B, name string, metaFn func(context.Context, string) (storage.MetaStore, error)) func(b *testing.B) {
|
func openCloseWritable(b *testing.B, name string, metaFn metaFactory) func(b *testing.B) {
|
||||||
return func(b *testing.B) {
|
return func(b *testing.B) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
tmpDir, err := ioutil.TempDir("", "metastore-bench-"+name+"-")
|
tmpDir, err := ioutil.TempDir("", "metastore-bench-"+name+"-")
|
||||||
|
@ -58,7 +56,7 @@ func openCloseWritable(b *testing.B, name string, metaFn func(context.Context, s
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(tmpDir)
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
ms, err := metaFn(ctx, tmpDir)
|
ms, err := metaFn(tmpDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -77,7 +75,7 @@ func openCloseWritable(b *testing.B, name string, metaFn func(context.Context, s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func openCloseReadonly(b *testing.B, name string, metaFn func(context.Context, string) (storage.MetaStore, error)) func(b *testing.B) {
|
func openCloseReadonly(b *testing.B, name string, metaFn metaFactory) func(b *testing.B) {
|
||||||
return func(b *testing.B) {
|
return func(b *testing.B) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
tmpDir, err := ioutil.TempDir("", "metastore-bench-"+name+"-")
|
tmpDir, err := ioutil.TempDir("", "metastore-bench-"+name+"-")
|
||||||
|
@ -86,7 +84,7 @@ func openCloseReadonly(b *testing.B, name string, metaFn func(context.Context, s
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(tmpDir)
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
ms, err := metaFn(ctx, tmpDir)
|
ms, err := metaFn(tmpDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -105,112 +103,112 @@ func openCloseReadonly(b *testing.B, name string, metaFn func(context.Context, s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createActiveFromBase(ctx context.Context, ms storage.MetaStore, active, base string) error {
|
func createActiveFromBase(ctx context.Context, ms *MetaStore, active, base string) error {
|
||||||
if _, err := ms.CreateActive(ctx, "bottom", "", false); err != nil {
|
if _, err := CreateActive(ctx, "bottom", "", false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := ms.Commit(ctx, "bottom", base); err != nil {
|
if _, err := CommitActive(ctx, "bottom", base); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := ms.CreateActive(ctx, active, base, false)
|
_, err := CreateActive(ctx, active, base, false)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func statActiveBenchmark(ctx context.Context, b *testing.B, ms storage.MetaStore) {
|
func statActiveBenchmark(ctx context.Context, b *testing.B, ms *MetaStore) {
|
||||||
if err := createActiveFromBase(ctx, ms, "active", "base"); err != nil {
|
if err := createActiveFromBase(ctx, ms, "active", "base"); err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_, err := ms.Stat(ctx, "active")
|
_, err := GetInfo(ctx, "active")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func statCommittedBenchmark(ctx context.Context, b *testing.B, ms storage.MetaStore) {
|
func statCommittedBenchmark(ctx context.Context, b *testing.B, ms *MetaStore) {
|
||||||
if err := createActiveFromBase(ctx, ms, "active", "base"); err != nil {
|
if err := createActiveFromBase(ctx, ms, "active", "base"); err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
if _, err := ms.Commit(ctx, "active", "committed"); err != nil {
|
if _, err := CommitActive(ctx, "active", "committed"); err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_, err := ms.Stat(ctx, "committed")
|
_, err := GetInfo(ctx, "committed")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createActiveBenchmark(ctx context.Context, b *testing.B, ms storage.MetaStore) {
|
func createActiveBenchmark(ctx context.Context, b *testing.B, ms *MetaStore) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
if _, err := ms.CreateActive(ctx, "active", "", false); err != nil {
|
if _, err := CreateActive(ctx, "active", "", false); err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
b.StopTimer()
|
b.StopTimer()
|
||||||
if _, _, err := ms.Remove(ctx, "active"); err != nil {
|
if _, _, err := Remove(ctx, "active"); err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
b.StartTimer()
|
b.StartTimer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeBenchmark(ctx context.Context, b *testing.B, ms storage.MetaStore) {
|
func removeBenchmark(ctx context.Context, b *testing.B, ms *MetaStore) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
b.StopTimer()
|
b.StopTimer()
|
||||||
if _, err := ms.CreateActive(ctx, "active", "", false); err != nil {
|
if _, err := CreateActive(ctx, "active", "", false); err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
b.StartTimer()
|
b.StartTimer()
|
||||||
if _, _, err := ms.Remove(ctx, "active"); err != nil {
|
if _, _, err := Remove(ctx, "active"); err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func commitBenchmark(ctx context.Context, b *testing.B, ms storage.MetaStore) {
|
func commitBenchmark(ctx context.Context, b *testing.B, ms *MetaStore) {
|
||||||
b.StopTimer()
|
b.StopTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
if _, err := ms.CreateActive(ctx, "active", "", false); err != nil {
|
if _, err := CreateActive(ctx, "active", "", false); err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
b.StartTimer()
|
b.StartTimer()
|
||||||
if _, err := ms.Commit(ctx, "active", "committed"); err != nil {
|
if _, err := CommitActive(ctx, "active", "committed"); err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
b.StopTimer()
|
b.StopTimer()
|
||||||
if _, _, err := ms.Remove(ctx, "committed"); err != nil {
|
if _, _, err := Remove(ctx, "committed"); err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getActiveBenchmark(ctx context.Context, b *testing.B, ms storage.MetaStore) {
|
func getActiveBenchmark(ctx context.Context, b *testing.B, ms *MetaStore) {
|
||||||
var base string
|
var base string
|
||||||
for i := 1; i <= 10; i++ {
|
for i := 1; i <= 10; i++ {
|
||||||
if _, err := ms.CreateActive(ctx, "tmp", base, false); err != nil {
|
if _, err := CreateActive(ctx, "tmp", base, false); err != nil {
|
||||||
b.Fatalf("create active failed: %+v", err)
|
b.Fatalf("create active failed: %+v", err)
|
||||||
}
|
}
|
||||||
base = fmt.Sprintf("base-%d", i)
|
base = fmt.Sprintf("base-%d", i)
|
||||||
if _, err := ms.Commit(ctx, "tmp", base); err != nil {
|
if _, err := CommitActive(ctx, "tmp", base); err != nil {
|
||||||
b.Fatalf("commit failed: %+v", err)
|
b.Fatalf("commit failed: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := ms.CreateActive(ctx, "active", base, false); err != nil {
|
if _, err := CreateActive(ctx, "active", base, false); err != nil {
|
||||||
b.Fatalf("create active failed: %+v", err)
|
b.Fatalf("create active failed: %+v", err)
|
||||||
}
|
}
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
if _, err := ms.GetActive(ctx, "active"); err != nil {
|
if _, err := GetActive(ctx, "active"); err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package testsuite
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -7,22 +7,21 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/containerd/containerd/snapshot"
|
"github.com/containerd/containerd/snapshot"
|
||||||
"github.com/containerd/containerd/snapshot/storage"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
type testFunc func(context.Context, *testing.T, storage.MetaStore)
|
type testFunc func(context.Context, *testing.T, *MetaStore)
|
||||||
|
|
||||||
type metaFactory func(context.Context, string) (storage.MetaStore, error)
|
type metaFactory func(string) (*MetaStore, error)
|
||||||
|
|
||||||
type populateFunc func(context.Context, storage.MetaStore) error
|
type populateFunc func(context.Context, *MetaStore) error
|
||||||
|
|
||||||
// MetaStoreSuite runs a test suite on the metastore given a factory function.
|
// MetaStoreSuite runs a test suite on the metastore given a factory function.
|
||||||
func MetaStoreSuite(t *testing.T, name string, meta func(ctx context.Context, root string) (storage.MetaStore, error)) {
|
func MetaStoreSuite(t *testing.T, name string, meta func(root string) (*MetaStore, error)) {
|
||||||
t.Run("Stat", makeTest(t, name, meta, inReadTransaction(testStat, basePopulate)))
|
t.Run("GetInfo", makeTest(t, name, meta, inReadTransaction(testGetInfo, basePopulate)))
|
||||||
t.Run("StatNotExist", makeTest(t, name, meta, inReadTransaction(testStatNotExist, basePopulate)))
|
t.Run("GetInfoNotExist", makeTest(t, name, meta, inReadTransaction(testGetInfoNotExist, basePopulate)))
|
||||||
t.Run("StatEmptyDB", makeTest(t, name, meta, inReadTransaction(testStatNotExist, nil)))
|
t.Run("GetInfoEmptyDB", makeTest(t, name, meta, inReadTransaction(testGetInfoNotExist, nil)))
|
||||||
t.Run("Walk", makeTest(t, name, meta, inReadTransaction(testWalk, basePopulate)))
|
t.Run("Walk", makeTest(t, name, meta, inReadTransaction(testWalk, basePopulate)))
|
||||||
t.Run("GetActive", makeTest(t, name, meta, testGetActive))
|
t.Run("GetActive", makeTest(t, name, meta, testGetActive))
|
||||||
t.Run("GetActiveNotExist", makeTest(t, name, meta, inReadTransaction(testGetActiveNotExist, basePopulate)))
|
t.Run("GetActiveNotExist", makeTest(t, name, meta, inReadTransaction(testGetActiveNotExist, basePopulate)))
|
||||||
|
@ -52,7 +51,7 @@ func makeTest(t *testing.T, name string, metaFn metaFactory, fn testFunc) func(t
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(tmpDir)
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
ms, err := metaFn(ctx, tmpDir)
|
ms, err := metaFn(tmpDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -62,7 +61,7 @@ func makeTest(t *testing.T, name string, metaFn metaFactory, fn testFunc) func(t
|
||||||
}
|
}
|
||||||
|
|
||||||
func inReadTransaction(fn testFunc, pf populateFunc) testFunc {
|
func inReadTransaction(fn testFunc, pf populateFunc) testFunc {
|
||||||
return func(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
return func(ctx context.Context, t *testing.T, ms *MetaStore) {
|
||||||
if pf != nil {
|
if pf != nil {
|
||||||
ctx, tx, err := ms.TransactionContext(ctx, true)
|
ctx, tx, err := ms.TransactionContext(ctx, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -97,7 +96,7 @@ func inReadTransaction(fn testFunc, pf populateFunc) testFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
func inWriteTransaction(fn testFunc) testFunc {
|
func inWriteTransaction(fn testFunc) testFunc {
|
||||||
return func(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
return func(ctx context.Context, t *testing.T, ms *MetaStore) {
|
||||||
ctx, tx, err := ms.TransactionContext(ctx, true)
|
ctx, tx, err := ms.TransactionContext(ctx, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Failed to start transaction: %+v", err)
|
t.Fatal("Failed to start transaction: %+v", err)
|
||||||
|
@ -125,32 +124,32 @@ func inWriteTransaction(fn testFunc) testFunc {
|
||||||
// - "active-3": active with parent "committed-2"
|
// - "active-3": active with parent "committed-2"
|
||||||
// - "active-4": readonly active without parent"
|
// - "active-4": readonly active without parent"
|
||||||
// - "active-5": readonly active with parent "committed-2"
|
// - "active-5": readonly active with parent "committed-2"
|
||||||
func basePopulate(ctx context.Context, ms storage.MetaStore) error {
|
func basePopulate(ctx context.Context, ms *MetaStore) error {
|
||||||
if _, err := ms.CreateActive(ctx, "committed-tmp-1", "", false); err != nil {
|
if _, err := CreateActive(ctx, "committed-tmp-1", "", false); err != nil {
|
||||||
return errors.Wrap(err, "failed to create active")
|
return errors.Wrap(err, "failed to create active")
|
||||||
}
|
}
|
||||||
if _, err := ms.Commit(ctx, "committed-tmp-1", "committed-1"); err != nil {
|
if _, err := CommitActive(ctx, "committed-tmp-1", "committed-1"); err != nil {
|
||||||
return errors.Wrap(err, "failed to create active")
|
return errors.Wrap(err, "failed to create active")
|
||||||
}
|
}
|
||||||
if _, err := ms.CreateActive(ctx, "committed-tmp-2", "committed-1", false); err != nil {
|
if _, err := CreateActive(ctx, "committed-tmp-2", "committed-1", false); err != nil {
|
||||||
return errors.Wrap(err, "failed to create active")
|
return errors.Wrap(err, "failed to create active")
|
||||||
}
|
}
|
||||||
if _, err := ms.Commit(ctx, "committed-tmp-2", "committed-2"); err != nil {
|
if _, err := CommitActive(ctx, "committed-tmp-2", "committed-2"); err != nil {
|
||||||
return errors.Wrap(err, "failed to create active")
|
return errors.Wrap(err, "failed to create active")
|
||||||
}
|
}
|
||||||
if _, err := ms.CreateActive(ctx, "active-1", "", false); err != nil {
|
if _, err := CreateActive(ctx, "active-1", "", false); err != nil {
|
||||||
return errors.Wrap(err, "failed to create active")
|
return errors.Wrap(err, "failed to create active")
|
||||||
}
|
}
|
||||||
if _, err := ms.CreateActive(ctx, "active-2", "committed-1", false); err != nil {
|
if _, err := CreateActive(ctx, "active-2", "committed-1", false); err != nil {
|
||||||
return errors.Wrap(err, "failed to create active")
|
return errors.Wrap(err, "failed to create active")
|
||||||
}
|
}
|
||||||
if _, err := ms.CreateActive(ctx, "active-3", "committed-2", false); err != nil {
|
if _, err := CreateActive(ctx, "active-3", "committed-2", false); err != nil {
|
||||||
return errors.Wrap(err, "failed to create active")
|
return errors.Wrap(err, "failed to create active")
|
||||||
}
|
}
|
||||||
if _, err := ms.CreateActive(ctx, "active-4", "", true); err != nil {
|
if _, err := CreateActive(ctx, "active-4", "", true); err != nil {
|
||||||
return errors.Wrap(err, "failed to create active")
|
return errors.Wrap(err, "failed to create active")
|
||||||
}
|
}
|
||||||
if _, err := ms.CreateActive(ctx, "active-5", "committed-2", true); err != nil {
|
if _, err := CreateActive(ctx, "active-5", "committed-2", true); err != nil {
|
||||||
return errors.Wrap(err, "failed to create active")
|
return errors.Wrap(err, "failed to create active")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -237,24 +236,24 @@ func assertExist(t *testing.T, err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testStat(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
func testGetInfo(ctx context.Context, t *testing.T, ms *MetaStore) {
|
||||||
for key, expected := range baseInfo {
|
for key, expected := range baseInfo {
|
||||||
info, err := ms.Stat(ctx, key)
|
info, err := GetInfo(ctx, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Stat on %v failed: %+v", key, err)
|
t.Fatalf("GetInfo on %v failed: %+v", key, err)
|
||||||
}
|
}
|
||||||
assert.Equal(t, expected, info)
|
assert.Equal(t, expected, info)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testStatNotExist(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
func testGetInfoNotExist(ctx context.Context, t *testing.T, ms *MetaStore) {
|
||||||
_, err := ms.Stat(ctx, "active-not-exist")
|
_, err := GetInfo(ctx, "active-not-exist")
|
||||||
assertNotExist(t, err)
|
assertNotExist(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testWalk(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
func testWalk(ctx context.Context, t *testing.T, ms *MetaStore) {
|
||||||
found := map[string]snapshot.Info{}
|
found := map[string]snapshot.Info{}
|
||||||
err := ms.Walk(ctx, func(ctx context.Context, info snapshot.Info) error {
|
err := WalkInfo(ctx, func(ctx context.Context, info snapshot.Info) error {
|
||||||
if _, ok := found[info.Name]; ok {
|
if _, ok := found[info.Name]; ok {
|
||||||
return errors.Errorf("entry already encountered")
|
return errors.Errorf("entry already encountered")
|
||||||
}
|
}
|
||||||
|
@ -267,13 +266,13 @@ func testWalk(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
||||||
assert.Equal(t, baseInfo, found)
|
assert.Equal(t, baseInfo, found)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testGetActive(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
func testGetActive(ctx context.Context, t *testing.T, ms *MetaStore) {
|
||||||
activeMap := map[string]storage.Active{}
|
activeMap := map[string]Active{}
|
||||||
populate := func(ctx context.Context, ms storage.MetaStore) error {
|
populate := func(ctx context.Context, ms *MetaStore) error {
|
||||||
if _, err := ms.CreateActive(ctx, "committed-tmp-1", "", false); err != nil {
|
if _, err := CreateActive(ctx, "committed-tmp-1", "", false); err != nil {
|
||||||
return errors.Wrap(err, "failed to create active")
|
return errors.Wrap(err, "failed to create active")
|
||||||
}
|
}
|
||||||
if _, err := ms.Commit(ctx, "committed-tmp-1", "committed-1"); err != nil {
|
if _, err := CommitActive(ctx, "committed-tmp-1", "committed-1"); err != nil {
|
||||||
return errors.Wrap(err, "failed to create active")
|
return errors.Wrap(err, "failed to create active")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,7 +298,7 @@ func testGetActive(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
||||||
Readonly: true,
|
Readonly: true,
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
active, err := ms.CreateActive(ctx, opts.Name, opts.Parent, opts.Readonly)
|
active, err := CreateActive(ctx, opts.Name, opts.Parent, opts.Readonly)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to create active")
|
return errors.Wrap(err, "failed to create active")
|
||||||
}
|
}
|
||||||
|
@ -308,9 +307,9 @@ func testGetActive(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
test := func(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
test := func(ctx context.Context, t *testing.T, ms *MetaStore) {
|
||||||
for key, expected := range activeMap {
|
for key, expected := range activeMap {
|
||||||
active, err := ms.GetActive(ctx, key)
|
active, err := GetActive(ctx, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Failed to get active: %+v", err)
|
t.Fatal("Failed to get active: %+v", err)
|
||||||
}
|
}
|
||||||
|
@ -321,18 +320,18 @@ func testGetActive(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
||||||
inReadTransaction(test, populate)(ctx, t, ms)
|
inReadTransaction(test, populate)(ctx, t, ms)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testGetActiveCommitted(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
func testGetActiveCommitted(ctx context.Context, t *testing.T, ms *MetaStore) {
|
||||||
_, err := ms.GetActive(ctx, "committed-1")
|
_, err := GetActive(ctx, "committed-1")
|
||||||
assertNotActive(t, err)
|
assertNotActive(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testGetActiveNotExist(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
func testGetActiveNotExist(ctx context.Context, t *testing.T, ms *MetaStore) {
|
||||||
_, err := ms.GetActive(ctx, "active-not-exist")
|
_, err := GetActive(ctx, "active-not-exist")
|
||||||
assertNotExist(t, err)
|
assertNotExist(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCreateActive(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
func testCreateActive(ctx context.Context, t *testing.T, ms *MetaStore) {
|
||||||
a1, err := ms.CreateActive(ctx, "active-1", "", false)
|
a1, err := CreateActive(ctx, "active-1", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -340,7 +339,7 @@ func testCreateActive(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
||||||
t.Fatal("Expected writable active")
|
t.Fatal("Expected writable active")
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := ms.CreateActive(ctx, "active-2", "", true)
|
a2, err := CreateActive(ctx, "active-2", "", true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -351,7 +350,7 @@ func testCreateActive(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
||||||
t.Fatal("Expected readonly active")
|
t.Fatal("Expected readonly active")
|
||||||
}
|
}
|
||||||
|
|
||||||
commitID, err := ms.Commit(ctx, "active-1", "committed-1")
|
commitID, err := CommitActive(ctx, "active-1", "committed-1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -359,7 +358,7 @@ func testCreateActive(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
||||||
t.Fatal("Snapshot identifier must not change on commit")
|
t.Fatal("Snapshot identifier must not change on commit")
|
||||||
}
|
}
|
||||||
|
|
||||||
a3, err := ms.CreateActive(ctx, "active-3", "committed-1", false)
|
a3, err := CreateActive(ctx, "active-3", "committed-1", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -376,7 +375,7 @@ func testCreateActive(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
||||||
t.Fatal("Expected writable active")
|
t.Fatal("Expected writable active")
|
||||||
}
|
}
|
||||||
|
|
||||||
a4, err := ms.CreateActive(ctx, "active-4", "committed-1", true)
|
a4, err := CreateActive(ctx, "active-4", "committed-1", true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -394,31 +393,31 @@ func testCreateActive(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCreateActiveExist(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
func testCreateActiveExist(ctx context.Context, t *testing.T, ms *MetaStore) {
|
||||||
if err := basePopulate(ctx, ms); err != nil {
|
if err := basePopulate(ctx, ms); err != nil {
|
||||||
t.Fatalf("Populate failed: %+v", err)
|
t.Fatalf("Populate failed: %+v", err)
|
||||||
}
|
}
|
||||||
_, err := ms.CreateActive(ctx, "active-1", "", false)
|
_, err := CreateActive(ctx, "active-1", "", false)
|
||||||
assertExist(t, err)
|
assertExist(t, err)
|
||||||
_, err = ms.CreateActive(ctx, "committed-1", "", false)
|
_, err = CreateActive(ctx, "committed-1", "", false)
|
||||||
assertExist(t, err)
|
assertExist(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCreateActiveNotExist(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
func testCreateActiveNotExist(ctx context.Context, t *testing.T, ms *MetaStore) {
|
||||||
_, err := ms.CreateActive(ctx, "active-1", "does-not-exist", false)
|
_, err := CreateActive(ctx, "active-1", "does-not-exist", false)
|
||||||
assertNotExist(t, err)
|
assertNotExist(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCreateActiveFromActive(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
func testCreateActiveFromActive(ctx context.Context, t *testing.T, ms *MetaStore) {
|
||||||
if err := basePopulate(ctx, ms); err != nil {
|
if err := basePopulate(ctx, ms); err != nil {
|
||||||
t.Fatalf("Populate failed: %+v", err)
|
t.Fatalf("Populate failed: %+v", err)
|
||||||
}
|
}
|
||||||
_, err := ms.CreateActive(ctx, "active-new", "active-1", false)
|
_, err := CreateActive(ctx, "active-new", "active-1", false)
|
||||||
assertNotCommitted(t, err)
|
assertNotCommitted(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCommit(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
func testCommit(ctx context.Context, t *testing.T, ms *MetaStore) {
|
||||||
a1, err := ms.CreateActive(ctx, "active-1", "", false)
|
a1, err := CreateActive(ctx, "active-1", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -426,7 +425,7 @@ func testCommit(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
||||||
t.Fatal("Expected writable active")
|
t.Fatal("Expected writable active")
|
||||||
}
|
}
|
||||||
|
|
||||||
commitID, err := ms.Commit(ctx, "active-1", "committed-1")
|
commitID, err := CommitActive(ctx, "active-1", "committed-1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -434,50 +433,50 @@ func testCommit(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
||||||
t.Fatal("Snapshot identifier must not change on commit")
|
t.Fatal("Snapshot identifier must not change on commit")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = ms.GetActive(ctx, "active-1")
|
_, err = GetActive(ctx, "active-1")
|
||||||
assertNotExist(t, err)
|
assertNotExist(t, err)
|
||||||
_, err = ms.GetActive(ctx, "committed-1")
|
_, err = GetActive(ctx, "committed-1")
|
||||||
assertNotActive(t, err)
|
assertNotActive(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCommitNotExist(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
func testCommitNotExist(ctx context.Context, t *testing.T, ms *MetaStore) {
|
||||||
_, err := ms.Commit(ctx, "active-not-exist", "committed-1")
|
_, err := CommitActive(ctx, "active-not-exist", "committed-1")
|
||||||
assertNotExist(t, err)
|
assertNotExist(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCommitExist(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
func testCommitExist(ctx context.Context, t *testing.T, ms *MetaStore) {
|
||||||
if err := basePopulate(ctx, ms); err != nil {
|
if err := basePopulate(ctx, ms); err != nil {
|
||||||
t.Fatalf("Populate failed: %+v", err)
|
t.Fatalf("Populate failed: %+v", err)
|
||||||
}
|
}
|
||||||
_, err := ms.Commit(ctx, "active-1", "committed-1")
|
_, err := CommitActive(ctx, "active-1", "committed-1")
|
||||||
assertExist(t, err)
|
assertExist(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCommitCommitted(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
func testCommitCommitted(ctx context.Context, t *testing.T, ms *MetaStore) {
|
||||||
if err := basePopulate(ctx, ms); err != nil {
|
if err := basePopulate(ctx, ms); err != nil {
|
||||||
t.Fatalf("Populate failed: %+v", err)
|
t.Fatalf("Populate failed: %+v", err)
|
||||||
}
|
}
|
||||||
_, err := ms.Commit(ctx, "committed-1", "committed-3")
|
_, err := CommitActive(ctx, "committed-1", "committed-3")
|
||||||
assertNotActive(t, err)
|
assertNotActive(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCommitReadonly(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
func testCommitReadonly(ctx context.Context, t *testing.T, ms *MetaStore) {
|
||||||
if err := basePopulate(ctx, ms); err != nil {
|
if err := basePopulate(ctx, ms); err != nil {
|
||||||
t.Fatalf("Populate failed: %+v", err)
|
t.Fatalf("Populate failed: %+v", err)
|
||||||
}
|
}
|
||||||
_, err := ms.Commit(ctx, "active-5", "committed-3")
|
_, err := CommitActive(ctx, "active-5", "committed-3")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("Expected error committing readonly active")
|
t.Fatal("Expected error committing readonly active")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRemove(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
func testRemove(ctx context.Context, t *testing.T, ms *MetaStore) {
|
||||||
a1, err := ms.CreateActive(ctx, "active-1", "", false)
|
a1, err := CreateActive(ctx, "active-1", "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
commitID, err := ms.Commit(ctx, "active-1", "committed-1")
|
commitID, err := CommitActive(ctx, "active-1", "committed-1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -485,20 +484,20 @@ func testRemove(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
||||||
t.Fatal("Snapshot identifier must not change on commit")
|
t.Fatal("Snapshot identifier must not change on commit")
|
||||||
}
|
}
|
||||||
|
|
||||||
a2, err := ms.CreateActive(ctx, "active-2", "committed-1", true)
|
a2, err := CreateActive(ctx, "active-2", "committed-1", true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
a3, err := ms.CreateActive(ctx, "active-3", "committed-1", true)
|
a3, err := CreateActive(ctx, "active-3", "committed-1", true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err = ms.Remove(ctx, "active-1")
|
_, _, err = Remove(ctx, "active-1")
|
||||||
assertNotExist(t, err)
|
assertNotExist(t, err)
|
||||||
|
|
||||||
r3, k3, err := ms.Remove(ctx, "active-3")
|
r3, k3, err := Remove(ctx, "active-3")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -509,7 +508,7 @@ func testRemove(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
||||||
t.Fatal("Expected active kind, got %v", k3)
|
t.Fatal("Expected active kind, got %v", k3)
|
||||||
}
|
}
|
||||||
|
|
||||||
r2, k2, err := ms.Remove(ctx, "active-2")
|
r2, k2, err := Remove(ctx, "active-2")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -520,7 +519,7 @@ func testRemove(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
||||||
t.Fatal("Expected active kind, got %v", k2)
|
t.Fatal("Expected active kind, got %v", k2)
|
||||||
}
|
}
|
||||||
|
|
||||||
r1, k1, err := ms.Remove(ctx, "committed-1")
|
r1, k1, err := Remove(ctx, "committed-1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -532,21 +531,21 @@ func testRemove(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRemoveWithChildren(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
func testRemoveWithChildren(ctx context.Context, t *testing.T, ms *MetaStore) {
|
||||||
if err := basePopulate(ctx, ms); err != nil {
|
if err := basePopulate(ctx, ms); err != nil {
|
||||||
t.Fatalf("Populate failed: %+v", err)
|
t.Fatalf("Populate failed: %+v", err)
|
||||||
}
|
}
|
||||||
_, _, err := ms.Remove(ctx, "committed-1")
|
_, _, err := Remove(ctx, "committed-1")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected removal of snapshot with children to error")
|
t.Fatalf("Expected removal of snapshot with children to error")
|
||||||
}
|
}
|
||||||
_, _, err = ms.Remove(ctx, "committed-1")
|
_, _, err = Remove(ctx, "committed-1")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Expected removal of snapshot with children to error")
|
t.Fatalf("Expected removal of snapshot with children to error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRemoveNotExist(ctx context.Context, t *testing.T, ms storage.MetaStore) {
|
func testRemoveNotExist(ctx context.Context, t *testing.T, ms *MetaStore) {
|
||||||
_, _, err := ms.Remove(ctx, "does-not-exist")
|
_, _, err := Remove(ctx, "does-not-exist")
|
||||||
assertNotExist(t, err)
|
assertNotExist(t, err)
|
||||||
}
|
}
|
|
@ -1,19 +1,19 @@
|
||||||
// Code generated by protoc-gen-gogo.
|
// Code generated by protoc-gen-gogo.
|
||||||
// source: github.com/containerd/containerd/snapshot/storage/boltdb/record.proto
|
// source: github.com/containerd/containerd/snapshot/storage/proto/record.proto
|
||||||
// DO NOT EDIT!
|
// DO NOT EDIT!
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Package boltdb is a generated protocol buffer package.
|
Package proto is a generated protocol buffer package.
|
||||||
|
|
||||||
It is generated from these files:
|
It is generated from these files:
|
||||||
github.com/containerd/containerd/snapshot/storage/boltdb/record.proto
|
github.com/containerd/containerd/snapshot/storage/proto/record.proto
|
||||||
|
|
||||||
It has these top-level messages:
|
It has these top-level messages:
|
||||||
Snapshot
|
Snapshot
|
||||||
*/
|
*/
|
||||||
package boltdb
|
package proto
|
||||||
|
|
||||||
import proto "github.com/gogo/protobuf/proto"
|
import proto1 "github.com/gogo/protobuf/proto"
|
||||||
import fmt "fmt"
|
import fmt "fmt"
|
||||||
import math "math"
|
import math "math"
|
||||||
import _ "github.com/gogo/protobuf/gogoproto"
|
import _ "github.com/gogo/protobuf/gogoproto"
|
||||||
|
@ -24,7 +24,7 @@ import reflect "reflect"
|
||||||
import io "io"
|
import io "io"
|
||||||
|
|
||||||
// Reference imports to suppress errors if they are not otherwise used.
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
var _ = proto.Marshal
|
var _ = proto1.Marshal
|
||||||
var _ = fmt.Errorf
|
var _ = fmt.Errorf
|
||||||
var _ = math.Inf
|
var _ = math.Inf
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ var _ = math.Inf
|
||||||
// is compatible with the proto package it is being compiled against.
|
// is compatible with the proto package it is being compiled against.
|
||||||
// A compilation error at this line likely means your copy of the
|
// A compilation error at this line likely means your copy of the
|
||||||
// proto package needs to be updated.
|
// proto package needs to be updated.
|
||||||
const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
|
const _ = proto1.GoGoProtoPackageIsVersion2 // please upgrade the proto package
|
||||||
|
|
||||||
// Kind defines the kind of snapshot.
|
// Kind defines the kind of snapshot.
|
||||||
type Kind int32
|
type Kind int32
|
||||||
|
@ -54,10 +54,12 @@ var Kind_value = map[string]int32{
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x Kind) String() string {
|
func (x Kind) String() string {
|
||||||
return proto.EnumName(Kind_name, int32(x))
|
return proto1.EnumName(Kind_name, int32(x))
|
||||||
}
|
}
|
||||||
func (Kind) EnumDescriptor() ([]byte, []int) { return fileDescriptorRecord, []int{0} }
|
func (Kind) EnumDescriptor() ([]byte, []int) { return fileDescriptorRecord, []int{0} }
|
||||||
|
|
||||||
|
// Snapshot defines the storage type for a snapshot in the
|
||||||
|
// metadata store.
|
||||||
type Snapshot struct {
|
type Snapshot struct {
|
||||||
ID uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
ID uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||||
Parent string `protobuf:"bytes,2,opt,name=parent,proto3" json:"parent,omitempty"`
|
Parent string `protobuf:"bytes,2,opt,name=parent,proto3" json:"parent,omitempty"`
|
||||||
|
@ -70,8 +72,8 @@ func (*Snapshot) ProtoMessage() {}
|
||||||
func (*Snapshot) Descriptor() ([]byte, []int) { return fileDescriptorRecord, []int{0} }
|
func (*Snapshot) Descriptor() ([]byte, []int) { return fileDescriptorRecord, []int{0} }
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
proto.RegisterType((*Snapshot)(nil), "containerd.v1.Snapshot")
|
proto1.RegisterType((*Snapshot)(nil), "containerd.v1.Snapshot")
|
||||||
proto.RegisterEnum("containerd.v1.Kind", Kind_name, Kind_value)
|
proto1.RegisterEnum("containerd.v1.Kind", Kind_name, Kind_value)
|
||||||
}
|
}
|
||||||
func (m *Snapshot) Marshal() (dAtA []byte, err error) {
|
func (m *Snapshot) Marshal() (dAtA []byte, err error) {
|
||||||
size := m.Size()
|
size := m.Size()
|
||||||
|
@ -440,29 +442,28 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
proto.RegisterFile("github.com/containerd/containerd/snapshot/storage/boltdb/record.proto", fileDescriptorRecord)
|
proto1.RegisterFile("github.com/containerd/containerd/snapshot/storage/proto/record.proto", fileDescriptorRecord)
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileDescriptorRecord = []byte{
|
var fileDescriptorRecord = []byte{
|
||||||
// 309 bytes of a gzipped FileDescriptorProto
|
// 304 bytes of a gzipped FileDescriptorProto
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x72, 0x4d, 0xcf, 0x2c, 0xc9,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x72, 0x49, 0xcf, 0x2c, 0xc9,
|
||||||
0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d,
|
0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d,
|
||||||
0x4a, 0x41, 0x66, 0x16, 0xe7, 0x25, 0x16, 0x14, 0x67, 0xe4, 0x97, 0xe8, 0x17, 0x97, 0xe4, 0x17,
|
0x4a, 0x41, 0x66, 0x16, 0xe7, 0x25, 0x16, 0x14, 0x67, 0xe4, 0x97, 0xe8, 0x17, 0x97, 0xe4, 0x17,
|
||||||
0x25, 0xa6, 0xa7, 0xea, 0x27, 0xe5, 0xe7, 0x94, 0xa4, 0x24, 0xe9, 0x17, 0xa5, 0x26, 0xe7, 0x17,
|
0x25, 0xa6, 0xa7, 0xea, 0x17, 0x14, 0xe5, 0x97, 0xe4, 0xeb, 0x17, 0xa5, 0x26, 0xe7, 0x17, 0xa5,
|
||||||
0xa5, 0xe8, 0x15, 0x14, 0xe5, 0x97, 0xe4, 0x0b, 0xf1, 0x22, 0x34, 0xe8, 0x95, 0x19, 0x4a, 0x89,
|
0xe8, 0x81, 0x39, 0x42, 0xbc, 0x08, 0xf5, 0x7a, 0x65, 0x86, 0x52, 0x22, 0xe9, 0xf9, 0xe9, 0xf9,
|
||||||
0xa4, 0xe7, 0xa7, 0xe7, 0x83, 0x65, 0xf4, 0x41, 0x2c, 0x88, 0x22, 0xa5, 0x7a, 0x2e, 0x8e, 0x60,
|
0x10, 0x65, 0x20, 0x16, 0x44, 0x91, 0x52, 0x3d, 0x17, 0x47, 0x30, 0xd4, 0x2c, 0x21, 0x31, 0x2e,
|
||||||
0xa8, 0x61, 0x42, 0x62, 0x5c, 0x4c, 0x99, 0x29, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x2c, 0x4e, 0x6c,
|
0xa6, 0xcc, 0x14, 0x09, 0x46, 0x05, 0x46, 0x0d, 0x16, 0x27, 0xb6, 0x47, 0xf7, 0xe4, 0x99, 0x3c,
|
||||||
0x8f, 0xee, 0xc9, 0x33, 0x79, 0xba, 0x04, 0x31, 0x65, 0xa6, 0x08, 0x89, 0x71, 0xb1, 0x15, 0x24,
|
0x5d, 0x82, 0x98, 0x32, 0x53, 0x84, 0xc4, 0xb8, 0xd8, 0x0a, 0x12, 0x8b, 0x52, 0xf3, 0x4a, 0x24,
|
||||||
0x16, 0xa5, 0xe6, 0x95, 0x48, 0x30, 0x29, 0x30, 0x6a, 0x70, 0x06, 0x41, 0x79, 0x42, 0xea, 0x5c,
|
0x98, 0x14, 0x18, 0x35, 0x38, 0x83, 0xa0, 0x3c, 0x21, 0x75, 0x2e, 0x96, 0xec, 0xcc, 0xbc, 0x14,
|
||||||
0x2c, 0xd9, 0x99, 0x79, 0x29, 0x12, 0x2c, 0x0a, 0x8c, 0x1a, 0x7c, 0x46, 0xc2, 0x7a, 0x28, 0xf6,
|
0x09, 0x16, 0x05, 0x46, 0x0d, 0x3e, 0x23, 0x61, 0x3d, 0x14, 0xfb, 0xf4, 0xbc, 0x33, 0xf3, 0x52,
|
||||||
0xe9, 0x79, 0x67, 0xe6, 0xa5, 0x04, 0x81, 0x15, 0x08, 0x49, 0x71, 0x71, 0x14, 0xa5, 0x26, 0xa6,
|
0x82, 0xc0, 0x0a, 0x84, 0xa4, 0xb8, 0x38, 0x8a, 0x52, 0x13, 0x53, 0xf2, 0xf3, 0x72, 0x2a, 0x25,
|
||||||
0xe4, 0xe7, 0xe5, 0x54, 0x4a, 0xb0, 0x2a, 0x30, 0x6a, 0x70, 0x04, 0xc1, 0xf9, 0x5a, 0x41, 0x5c,
|
0x58, 0x15, 0x18, 0x35, 0x38, 0x82, 0xe0, 0x7c, 0xad, 0x20, 0x2e, 0x16, 0x6f, 0x88, 0x1a, 0x36,
|
||||||
0x2c, 0xde, 0x10, 0x35, 0x6c, 0x8e, 0xce, 0x21, 0x9e, 0x61, 0xae, 0x02, 0x0c, 0x52, 0x7c, 0x5d,
|
0x47, 0xe7, 0x10, 0xcf, 0x30, 0x57, 0x01, 0x06, 0x29, 0xbe, 0xae, 0xb9, 0x0a, 0x5c, 0x20, 0x51,
|
||||||
0x73, 0x15, 0xb8, 0x40, 0xa2, 0x8e, 0xc9, 0x25, 0x99, 0x65, 0xa9, 0x42, 0x0a, 0x5c, 0x9c, 0xce,
|
0xc7, 0xe4, 0x92, 0xcc, 0xb2, 0x54, 0x21, 0x05, 0x2e, 0x4e, 0x67, 0x7f, 0x5f, 0x5f, 0xcf, 0x90,
|
||||||
0xfe, 0xbe, 0xbe, 0x9e, 0x21, 0x21, 0xae, 0x2e, 0x02, 0x8c, 0x52, 0x82, 0x5d, 0x73, 0x15, 0x78,
|
0x10, 0x57, 0x17, 0x01, 0x46, 0x29, 0xc1, 0xae, 0xb9, 0x0a, 0xbc, 0x20, 0x69, 0xe7, 0xfc, 0xdc,
|
||||||
0x41, 0xd2, 0xce, 0xf9, 0xb9, 0xb9, 0x99, 0x25, 0x25, 0xa9, 0x29, 0x52, 0x3c, 0x1d, 0x8b, 0xe5,
|
0xdc, 0xcc, 0x92, 0x92, 0xd4, 0x14, 0x29, 0x9e, 0x8e, 0xc5, 0x72, 0x0c, 0xbb, 0x96, 0xc8, 0x81,
|
||||||
0x18, 0x76, 0x2d, 0x91, 0x03, 0x9b, 0xe5, 0x24, 0x71, 0xe2, 0xa1, 0x1c, 0xc3, 0x8d, 0x87, 0x72,
|
0xcd, 0x72, 0x92, 0x38, 0xf1, 0x50, 0x8e, 0xe1, 0xc6, 0x43, 0x39, 0x86, 0x86, 0x47, 0x72, 0x8c,
|
||||||
0x0c, 0x0d, 0x8f, 0xe4, 0x18, 0x4f, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23,
|
0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0x63, 0x12, 0x1b, 0xd8,
|
||||||
0x39, 0xc6, 0x24, 0x36, 0xb0, 0xaf, 0x8d, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x73, 0x89, 0x2b,
|
0xd7, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xbb, 0x89, 0x2c, 0x37, 0x62, 0x01, 0x00, 0x00,
|
||||||
0x02, 0x63, 0x01, 0x00, 0x00,
|
|
||||||
}
|
}
|
|
@ -16,6 +16,8 @@ enum Kind {
|
||||||
COMMITTED = 1 [(gogoproto.enumvalue_customname) = "KindCommitted"];
|
COMMITTED = 1 [(gogoproto.enumvalue_customname) = "KindCommitted"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Snapshot defines the storage type for a snapshot in the
|
||||||
|
// metadata store.
|
||||||
message Snapshot {
|
message Snapshot {
|
||||||
uint64 id = 1 [(gogoproto.customname) = "ID"];
|
uint64 id = 1 [(gogoproto.customname) = "ID"];
|
||||||
string parent = 2;
|
string parent = 2;
|
Loading…
Reference in a new issue