Add storage bucket service
The storage bucket service wraps another bucket service, and invokes actions on a storage engine based upon the actions taken upon buckets. Currently, the storage bucket service will delete bucket data from the storage engine when the bucket is deleted via the bucket service.pull/10616/head
parent
5a12a3a72e
commit
e3ae256782
|
@ -0,0 +1,90 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/influxdata/platform"
|
||||
)
|
||||
|
||||
// BucketDeleter defines the behaviour of deleting a bucket.
|
||||
type BucketDeleter interface {
|
||||
DeleteBucket(platform.ID, platform.ID) error
|
||||
}
|
||||
|
||||
// BucketService wraps an existing platform.BucketService implementation.
|
||||
//
|
||||
// BucketService ensures that when a bucket is deleted, all stored data
|
||||
// associated with the bucket is either removed, or marked to be removed via a
|
||||
// future compaction.
|
||||
type BucketService struct {
|
||||
inner platform.BucketService
|
||||
engine BucketDeleter
|
||||
}
|
||||
|
||||
// NewBucketService returns a new BucketService for the provided BucketDeleter,
|
||||
// which typically will be an Engine.
|
||||
func NewBucketService(s platform.BucketService, engine BucketDeleter) *BucketService {
|
||||
return &BucketService{
|
||||
inner: s,
|
||||
engine: engine,
|
||||
}
|
||||
}
|
||||
|
||||
// FindBucketByID returns a single bucket by ID.
|
||||
func (s *BucketService) FindBucketByID(ctx context.Context, id platform.ID) (*platform.Bucket, error) {
|
||||
if s.inner == nil || s.engine == nil {
|
||||
return nil, errors.New("nil inner BucketService or Engine")
|
||||
}
|
||||
return s.inner.FindBucketByID(ctx, id)
|
||||
}
|
||||
|
||||
// FindBucket returns the first bucket that matches filter.
|
||||
func (s *BucketService) FindBucket(ctx context.Context, filter platform.BucketFilter) (*platform.Bucket, error) {
|
||||
if s.inner == nil || s.engine == nil {
|
||||
return nil, errors.New("nil inner BucketService or Engine")
|
||||
}
|
||||
return s.inner.FindBucket(ctx, filter)
|
||||
}
|
||||
|
||||
// FindBuckets returns a list of buckets that match filter and the total count of matching buckets.
|
||||
// Additional options provide pagination & sorting.
|
||||
func (s *BucketService) FindBuckets(ctx context.Context, filter platform.BucketFilter, opt ...platform.FindOptions) ([]*platform.Bucket, int, error) {
|
||||
if s.inner == nil || s.engine == nil {
|
||||
return nil, 0, errors.New("nil inner BucketService or Engine")
|
||||
}
|
||||
return s.inner.FindBuckets(ctx, filter, opt...)
|
||||
}
|
||||
|
||||
// CreateBucket creates a new bucket and sets b.ID with the new identifier.
|
||||
func (s *BucketService) CreateBucket(ctx context.Context, b *platform.Bucket) error {
|
||||
if s.inner == nil || s.engine == nil {
|
||||
return errors.New("nil inner BucketService or Engine")
|
||||
}
|
||||
return s.inner.CreateBucket(ctx, b)
|
||||
}
|
||||
|
||||
// UpdateBucket updates a single bucket with changeset.
|
||||
// Returns the new bucket state after update.
|
||||
func (s *BucketService) UpdateBucket(ctx context.Context, id platform.ID, upd platform.BucketUpdate) (*platform.Bucket, error) {
|
||||
if s.inner == nil || s.engine == nil {
|
||||
return nil, errors.New("nil inner BucketService or Engine")
|
||||
}
|
||||
return s.inner.UpdateBucket(ctx, id, upd)
|
||||
}
|
||||
|
||||
// DeleteBucket removes a bucket by ID.
|
||||
func (s *BucketService) DeleteBucket(ctx context.Context, bucketID platform.ID) error {
|
||||
bucket, err := s.FindBucketByID(ctx, bucketID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// The data is dropped first from the storage engine. If this fails for any
|
||||
// reason, then the bucket will still be available in the future to retrieve
|
||||
// the orgID, which is needed for the engine.
|
||||
if err := s.engine.DeleteBucket(bucket.OrganizationID, bucketID); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.inner.DeleteBucket(ctx, bucketID)
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package storage_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/influxdata/platform"
|
||||
"github.com/influxdata/platform/inmem"
|
||||
"github.com/influxdata/platform/storage"
|
||||
)
|
||||
|
||||
func TestBucketService(t *testing.T) {
|
||||
service := storage.NewBucketService(nil, nil)
|
||||
|
||||
i, err := platform.IDFromString("2222222222222222")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := service.DeleteBucket(context.TODO(), *i); err == nil {
|
||||
t.Fatal("expected error, got nil")
|
||||
}
|
||||
|
||||
inmemService := inmem.NewService()
|
||||
service = storage.NewBucketService(inmemService, nil)
|
||||
|
||||
if err := service.DeleteBucket(context.TODO(), *i); err == nil {
|
||||
t.Fatal("expected error, got nil")
|
||||
}
|
||||
|
||||
org := &platform.Organization{}
|
||||
if err := inmemService.CreateOrganization(context.TODO(), org); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
bucket := &platform.Bucket{OrganizationID: org.ID}
|
||||
if err := inmemService.CreateBucket(context.TODO(), bucket); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Test deleting a bucket calls into the deleter.
|
||||
deleter := &MockDeleter{}
|
||||
service = storage.NewBucketService(inmemService, deleter)
|
||||
|
||||
if err := service.DeleteBucket(context.TODO(), bucket.ID); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if deleter.orgID != org.ID {
|
||||
t.Errorf("got org ID: %s, expected %s", deleter.orgID, org.ID)
|
||||
} else if deleter.bucketID != bucket.ID {
|
||||
t.Errorf("got bucket ID: %s, expected %s", deleter.bucketID, bucket.ID)
|
||||
}
|
||||
}
|
||||
|
||||
type MockDeleter struct {
|
||||
orgID, bucketID platform.ID
|
||||
}
|
||||
|
||||
func (m *MockDeleter) DeleteBucket(orgID, bucketID platform.ID) error {
|
||||
m.orgID, m.bucketID = orgID, bucketID
|
||||
return nil
|
||||
}
|
|
@ -192,15 +192,6 @@ func (s *retentionEnforcer) PrometheusCollectors() []prometheus.Collector {
|
|||
return s.metrics.PrometheusCollectors()
|
||||
}
|
||||
|
||||
// A BucketService is an platform.BucketService that the retentionEnforcer can open,
|
||||
// close and log.
|
||||
type BucketService interface {
|
||||
platform.BucketService
|
||||
Open() error
|
||||
Close() error
|
||||
WithLogger(l *zap.Logger)
|
||||
}
|
||||
|
||||
type seriesIteratorAdapter struct {
|
||||
itr SeriesCursor
|
||||
ea seriesElemAdapter
|
||||
|
|
Loading…
Reference in New Issue