From 8f9607eed58e5be25b574faa975d19e834f637bd Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Tue, 25 Jun 2024 07:12:30 -0700 Subject: [PATCH] Use the transactor interface in metadata The boltdb instance in metadata is only used for getting transactions and can also be overriden via the context to have a wider control of the transaction boundary. Using the transactor interface allows callers of metadata to have more control of the transaction lifecycle. Since boltdb must be fsync'ed on commit, operations which perform many database operations can be costly and slow. While providing transactor via context can be used to group together operations, it does not provide a way to manage the commit fsyncs more globally. Signed-off-by: Derek McGowan --- core/metadata/bolt.go | 7 ++++--- core/metadata/content.go | 13 +++++++------ core/metadata/db.go | 9 +++++---- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/core/metadata/bolt.go b/core/metadata/bolt.go index 9edfab565..50f26f254 100644 --- a/core/metadata/bolt.go +++ b/core/metadata/bolt.go @@ -33,14 +33,15 @@ func WithTransactionContext(ctx context.Context, tx *bolt.Tx) context.Context { return context.WithValue(ctx, transactionKey{}, tx) } -type transactor interface { +// Transactor is the database interface for running transactions +type Transactor interface { View(fn func(*bolt.Tx) error) error Update(fn func(*bolt.Tx) error) error } // view gets a bolt db transaction either from the context // or starts a new one with the provided bolt database. -func view(ctx context.Context, db transactor, fn func(*bolt.Tx) error) error { +func view(ctx context.Context, db Transactor, fn func(*bolt.Tx) error) error { tx, ok := ctx.Value(transactionKey{}).(*bolt.Tx) if !ok { return db.View(fn) @@ -50,7 +51,7 @@ func view(ctx context.Context, db transactor, fn func(*bolt.Tx) error) error { // update gets a writable bolt db transaction either from the context // or starts a new one with the provided bolt database. -func update(ctx context.Context, db transactor, fn func(*bolt.Tx) error) error { +func update(ctx context.Context, db Transactor, fn func(*bolt.Tx) error) error { tx, ok := ctx.Value(transactionKey{}).(*bolt.Tx) if !ok { return db.Update(fn) diff --git a/core/metadata/content.go b/core/metadata/content.go index 7768332f6..bc42d6ca3 100644 --- a/core/metadata/content.go +++ b/core/metadata/content.go @@ -25,16 +25,17 @@ import ( "sync/atomic" "time" - "github.com/containerd/containerd/v2/core/content" - "github.com/containerd/containerd/v2/core/metadata/boltutil" - "github.com/containerd/containerd/v2/pkg/filters" - "github.com/containerd/containerd/v2/pkg/labels" - "github.com/containerd/containerd/v2/pkg/namespaces" "github.com/containerd/errdefs" "github.com/containerd/log" digest "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" bolt "go.etcd.io/bbolt" + + "github.com/containerd/containerd/v2/core/content" + "github.com/containerd/containerd/v2/core/metadata/boltutil" + "github.com/containerd/containerd/v2/pkg/filters" + "github.com/containerd/containerd/v2/pkg/labels" + "github.com/containerd/containerd/v2/pkg/namespaces" ) type contentStore struct { @@ -487,7 +488,7 @@ type namespacedWriter struct { ctx context.Context ref string namespace string - db transactor + db Transactor provider interface { content.Provider content.Ingester diff --git a/core/metadata/db.go b/core/metadata/db.go index efef07460..25752397a 100644 --- a/core/metadata/db.go +++ b/core/metadata/db.go @@ -27,14 +27,15 @@ import ( "time" eventstypes "github.com/containerd/containerd/api/events" + "github.com/containerd/log" + bolt "go.etcd.io/bbolt" + "github.com/containerd/containerd/v2/core/content" "github.com/containerd/containerd/v2/core/events" "github.com/containerd/containerd/v2/core/snapshots" "github.com/containerd/containerd/v2/internal/cleanup" "github.com/containerd/containerd/v2/pkg/gc" "github.com/containerd/containerd/v2/pkg/namespaces" - "github.com/containerd/log" - bolt "go.etcd.io/bbolt" ) const ( @@ -80,7 +81,7 @@ type dbOptions struct { // while proxying data shared across namespaces to backend // datastores for content and snapshots. type DB struct { - db *bolt.DB + db Transactor ss map[string]*snapshotter cs *contentStore @@ -115,7 +116,7 @@ type DB struct { // NewDB creates a new metadata database using the provided // bolt database, content store, and snapshotters. -func NewDB(db *bolt.DB, cs content.Store, ss map[string]snapshots.Snapshotter, opts ...DBOpt) *DB { +func NewDB(db Transactor, cs content.Store, ss map[string]snapshots.Snapshotter, opts ...DBOpt) *DB { m := &DB{ db: db, ss: make(map[string]*snapshotter, len(ss)),