Update metadata interfaces for containers and leases
Add more thorough dirty checking across all types which may be deleted and hold references. Signed-off-by: Derek McGowan <derek@mcgstyle.net>
This commit is contained in:
@@ -20,6 +20,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
@@ -35,14 +36,14 @@ import (
|
||||
// LeaseManager manages the create/delete lifecycle of leases
|
||||
// and also returns existing leases
|
||||
type LeaseManager struct {
|
||||
tx *bolt.Tx
|
||||
db *DB
|
||||
}
|
||||
|
||||
// NewLeaseManager creates a new lease manager for managing leases using
|
||||
// the provided database transaction.
|
||||
func NewLeaseManager(tx *bolt.Tx) *LeaseManager {
|
||||
func NewLeaseManager(db *DB) *LeaseManager {
|
||||
return &LeaseManager{
|
||||
tx: tx,
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,35 +64,40 @@ func (lm *LeaseManager) Create(ctx context.Context, opts ...leases.Opt) (leases.
|
||||
return leases.Lease{}, err
|
||||
}
|
||||
|
||||
topbkt, err := createBucketIfNotExists(lm.tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases)
|
||||
if err != nil {
|
||||
return leases.Lease{}, err
|
||||
}
|
||||
|
||||
txbkt, err := topbkt.CreateBucket([]byte(l.ID))
|
||||
if err != nil {
|
||||
if err == bolt.ErrBucketExists {
|
||||
err = errdefs.ErrAlreadyExists
|
||||
if err := update(ctx, lm.db, func(tx *bolt.Tx) error {
|
||||
topbkt, err := createBucketIfNotExists(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return leases.Lease{}, errors.Wrapf(err, "lease %q", l.ID)
|
||||
}
|
||||
|
||||
t := time.Now().UTC()
|
||||
createdAt, err := t.MarshalBinary()
|
||||
if err != nil {
|
||||
return leases.Lease{}, err
|
||||
}
|
||||
if err := txbkt.Put(bucketKeyCreatedAt, createdAt); err != nil {
|
||||
return leases.Lease{}, err
|
||||
}
|
||||
|
||||
if l.Labels != nil {
|
||||
if err := boltutil.WriteLabels(txbkt, l.Labels); err != nil {
|
||||
return leases.Lease{}, err
|
||||
txbkt, err := topbkt.CreateBucket([]byte(l.ID))
|
||||
if err != nil {
|
||||
if err == bolt.ErrBucketExists {
|
||||
err = errdefs.ErrAlreadyExists
|
||||
}
|
||||
return errors.Wrapf(err, "lease %q", l.ID)
|
||||
}
|
||||
}
|
||||
l.CreatedAt = t
|
||||
|
||||
t := time.Now().UTC()
|
||||
createdAt, err := t.MarshalBinary()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := txbkt.Put(bucketKeyCreatedAt, createdAt); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if l.Labels != nil {
|
||||
if err := boltutil.WriteLabels(txbkt, l.Labels); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
l.CreatedAt = t
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return leases.Lease{}, err
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
@@ -102,17 +108,22 @@ func (lm *LeaseManager) Delete(ctx context.Context, lease leases.Lease, _ ...lea
|
||||
return err
|
||||
}
|
||||
|
||||
topbkt := getBucket(lm.tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases)
|
||||
if topbkt == nil {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
|
||||
}
|
||||
if err := topbkt.DeleteBucket([]byte(lease.ID)); err != nil {
|
||||
if err == bolt.ErrBucketNotFound {
|
||||
err = errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
|
||||
return update(ctx, lm.db, func(tx *bolt.Tx) error {
|
||||
topbkt := getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases)
|
||||
if topbkt == nil {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
if err := topbkt.DeleteBucket([]byte(lease.ID)); err != nil {
|
||||
if err == bolt.ErrBucketNotFound {
|
||||
err = errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
atomic.AddUint32(&lm.db.dirty, 1)
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// List lists all active leases
|
||||
@@ -129,39 +140,41 @@ func (lm *LeaseManager) List(ctx context.Context, fs ...string) ([]leases.Lease,
|
||||
|
||||
var ll []leases.Lease
|
||||
|
||||
topbkt := getBucket(lm.tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases)
|
||||
if topbkt == nil {
|
||||
return ll, nil
|
||||
}
|
||||
|
||||
if err := topbkt.ForEach(func(k, v []byte) error {
|
||||
if v != nil {
|
||||
if err := view(ctx, lm.db, func(tx *bolt.Tx) error {
|
||||
topbkt := getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases)
|
||||
if topbkt == nil {
|
||||
return nil
|
||||
}
|
||||
txbkt := topbkt.Bucket(k)
|
||||
|
||||
l := leases.Lease{
|
||||
ID: string(k),
|
||||
}
|
||||
return topbkt.ForEach(func(k, v []byte) error {
|
||||
if v != nil {
|
||||
return nil
|
||||
}
|
||||
txbkt := topbkt.Bucket(k)
|
||||
|
||||
if v := txbkt.Get(bucketKeyCreatedAt); v != nil {
|
||||
t := &l.CreatedAt
|
||||
if err := t.UnmarshalBinary(v); err != nil {
|
||||
l := leases.Lease{
|
||||
ID: string(k),
|
||||
}
|
||||
|
||||
if v := txbkt.Get(bucketKeyCreatedAt); v != nil {
|
||||
t := &l.CreatedAt
|
||||
if err := t.UnmarshalBinary(v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
labels, err := boltutil.ReadLabels(txbkt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
l.Labels = labels
|
||||
|
||||
labels, err := boltutil.ReadLabels(txbkt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l.Labels = labels
|
||||
if filter.Match(adaptLease(l)) {
|
||||
ll = append(ll, l)
|
||||
}
|
||||
|
||||
if filter.Match(adaptLease(l)) {
|
||||
ll = append(ll, l)
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil
|
||||
})
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -176,24 +189,26 @@ func (lm *LeaseManager) AddResource(ctx context.Context, lease leases.Lease, r l
|
||||
return err
|
||||
}
|
||||
|
||||
topbkt := getBucket(lm.tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases, []byte(lease.ID))
|
||||
if topbkt == nil {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
|
||||
}
|
||||
return update(ctx, lm.db, func(tx *bolt.Tx) error {
|
||||
topbkt := getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases, []byte(lease.ID))
|
||||
if topbkt == nil {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
|
||||
}
|
||||
|
||||
keys, ref, err := parseLeaseResource(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bkt := topbkt
|
||||
for _, key := range keys {
|
||||
bkt, err = bkt.CreateBucketIfNotExists([]byte(key))
|
||||
keys, ref, err := parseLeaseResource(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return bkt.Put([]byte(ref), nil)
|
||||
|
||||
bkt := topbkt
|
||||
for _, key := range keys {
|
||||
bkt, err = bkt.CreateBucketIfNotExists([]byte(key))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return bkt.Put([]byte(ref), nil)
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteResource dereferences the resource by the provided lease.
|
||||
@@ -203,28 +218,35 @@ func (lm *LeaseManager) DeleteResource(ctx context.Context, lease leases.Lease,
|
||||
return err
|
||||
}
|
||||
|
||||
topbkt := getBucket(lm.tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases, []byte(lease.ID))
|
||||
if topbkt == nil {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
|
||||
}
|
||||
|
||||
keys, ref, err := parseLeaseResource(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bkt := topbkt
|
||||
for _, key := range keys {
|
||||
if bkt == nil {
|
||||
break
|
||||
return update(ctx, lm.db, func(tx *bolt.Tx) error {
|
||||
topbkt := getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases, []byte(lease.ID))
|
||||
if topbkt == nil {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
|
||||
}
|
||||
bkt = bkt.Bucket([]byte(key))
|
||||
}
|
||||
|
||||
if bkt == nil {
|
||||
keys, ref, err := parseLeaseResource(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bkt := topbkt
|
||||
for _, key := range keys {
|
||||
if bkt == nil {
|
||||
break
|
||||
}
|
||||
bkt = bkt.Bucket([]byte(key))
|
||||
}
|
||||
|
||||
if bkt != nil {
|
||||
if err := bkt.Delete([]byte(ref)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
atomic.AddUint32(&lm.db.dirty, 1)
|
||||
|
||||
return nil
|
||||
}
|
||||
return bkt.Delete([]byte(ref))
|
||||
})
|
||||
}
|
||||
|
||||
// ListResources lists all the resources referenced by the lease.
|
||||
@@ -234,59 +256,66 @@ func (lm *LeaseManager) ListResources(ctx context.Context, lease leases.Lease) (
|
||||
return nil, err
|
||||
}
|
||||
|
||||
topbkt := getBucket(lm.tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases, []byte(lease.ID))
|
||||
if topbkt == nil {
|
||||
return nil, errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
|
||||
}
|
||||
var rs []leases.Resource
|
||||
|
||||
rs := make([]leases.Resource, 0)
|
||||
if err := view(ctx, lm.db, func(tx *bolt.Tx) error {
|
||||
|
||||
// content resources
|
||||
if cbkt := topbkt.Bucket(bucketKeyObjectContent); cbkt != nil {
|
||||
if err := cbkt.ForEach(func(k, _ []byte) error {
|
||||
rs = append(rs, leases.Resource{
|
||||
ID: string(k),
|
||||
Type: string(bucketKeyObjectContent),
|
||||
})
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
topbkt := getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases, []byte(lease.ID))
|
||||
if topbkt == nil {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
|
||||
}
|
||||
}
|
||||
|
||||
// ingest resources
|
||||
if lbkt := topbkt.Bucket(bucketKeyObjectIngests); lbkt != nil {
|
||||
if err := lbkt.ForEach(func(k, _ []byte) error {
|
||||
rs = append(rs, leases.Resource{
|
||||
ID: string(k),
|
||||
Type: string(bucketKeyObjectIngests),
|
||||
})
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// snapshot resources
|
||||
if sbkt := topbkt.Bucket(bucketKeyObjectSnapshots); sbkt != nil {
|
||||
if err := sbkt.ForEach(func(sk, sv []byte) error {
|
||||
if sv != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
snbkt := sbkt.Bucket(sk)
|
||||
return snbkt.ForEach(func(k, _ []byte) error {
|
||||
// content resources
|
||||
if cbkt := topbkt.Bucket(bucketKeyObjectContent); cbkt != nil {
|
||||
if err := cbkt.ForEach(func(k, _ []byte) error {
|
||||
rs = append(rs, leases.Resource{
|
||||
ID: string(k),
|
||||
Type: fmt.Sprintf("%s/%s", bucketKeyObjectSnapshots, sk),
|
||||
Type: string(bucketKeyObjectContent),
|
||||
})
|
||||
|
||||
return nil
|
||||
})
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// ingest resources
|
||||
if lbkt := topbkt.Bucket(bucketKeyObjectIngests); lbkt != nil {
|
||||
if err := lbkt.ForEach(func(k, _ []byte) error {
|
||||
rs = append(rs, leases.Resource{
|
||||
ID: string(k),
|
||||
Type: string(bucketKeyObjectIngests),
|
||||
})
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// snapshot resources
|
||||
if sbkt := topbkt.Bucket(bucketKeyObjectSnapshots); sbkt != nil {
|
||||
if err := sbkt.ForEach(func(sk, sv []byte) error {
|
||||
if sv != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
snbkt := sbkt.Bucket(sk)
|
||||
return snbkt.ForEach(func(k, _ []byte) error {
|
||||
rs = append(rs, leases.Resource{
|
||||
ID: string(k),
|
||||
Type: fmt.Sprintf("%s/%s", bucketKeyObjectSnapshots, sk),
|
||||
})
|
||||
return nil
|
||||
})
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rs, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user