95a5cfe647
In some rare cases when two entities are trying to create the same bucket at the same time it's possible that we will return internal error instead of `bucket already exists`. It's because we are not handling correctly DB error about constraint error. This change checks if while inserting bucket into DB we got constraint error and propagate correct error to metainfo API. Change-Id: Ie6fd2c943b864b4ea7d71e4a162e74dc3510e386
118 lines
4.1 KiB
Go
118 lines
4.1 KiB
Go
// Copyright (C) 2018 Storj Labs, Inc.
|
|
// See LICENSE for copying information.
|
|
|
|
package buckets
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/zeebo/errs"
|
|
|
|
"storj.io/common/macaroon"
|
|
"storj.io/common/pb"
|
|
"storj.io/common/storj"
|
|
"storj.io/common/uuid"
|
|
"storj.io/storj/satellite/metabase"
|
|
)
|
|
|
|
var (
|
|
// ErrBucket is an error class for general bucket errors.
|
|
ErrBucket = errs.Class("bucket")
|
|
|
|
// ErrNoBucket is an error class for using empty bucket name.
|
|
ErrNoBucket = errs.Class("no bucket specified")
|
|
|
|
// ErrBucketNotFound is an error class for non-existing bucket.
|
|
ErrBucketNotFound = errs.Class("bucket not found")
|
|
|
|
// ErrBucketAlreadyExists is used to indicate that bucket already exists.
|
|
ErrBucketAlreadyExists = errs.Class("bucket already exists")
|
|
)
|
|
|
|
// Bucket contains information about a specific bucket.
|
|
type Bucket struct {
|
|
ID uuid.UUID
|
|
Name string
|
|
ProjectID uuid.UUID
|
|
UserAgent []byte
|
|
Created time.Time
|
|
PathCipher storj.CipherSuite
|
|
DefaultSegmentsSize int64
|
|
DefaultRedundancyScheme storj.RedundancyScheme
|
|
DefaultEncryptionParameters storj.EncryptionParameters
|
|
Placement storj.PlacementConstraint
|
|
}
|
|
|
|
// ListDirection specifies listing direction.
|
|
type ListDirection = pb.ListDirection
|
|
|
|
const (
|
|
// DirectionForward lists forwards from cursor, including cursor.
|
|
DirectionForward = pb.ListDirection_FORWARD
|
|
// DirectionAfter lists forwards from cursor, without cursor.
|
|
DirectionAfter = pb.ListDirection_AFTER
|
|
)
|
|
|
|
// MinimalBucket contains minimal bucket fields for metainfo protocol.
|
|
type MinimalBucket struct {
|
|
Name []byte
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
// ListOptions lists objects.
|
|
type ListOptions struct {
|
|
Cursor string
|
|
Direction ListDirection
|
|
Limit int
|
|
}
|
|
|
|
// NextPage returns options for listing the next page.
|
|
func (opts ListOptions) NextPage(list List) ListOptions {
|
|
if !list.More || len(list.Items) == 0 {
|
|
return ListOptions{}
|
|
}
|
|
|
|
return ListOptions{
|
|
Cursor: list.Items[len(list.Items)-1].Name,
|
|
Direction: DirectionAfter,
|
|
Limit: opts.Limit,
|
|
}
|
|
}
|
|
|
|
// List is a list of buckets.
|
|
type List struct {
|
|
More bool
|
|
Items []Bucket
|
|
}
|
|
|
|
// DB is the interface for the database to interact with buckets.
|
|
//
|
|
// architecture: Database
|
|
type DB interface {
|
|
// CreateBucket creates a new bucket
|
|
CreateBucket(ctx context.Context, bucket Bucket) (_ Bucket, err error)
|
|
// GetBucket returns an existing bucket
|
|
GetBucket(ctx context.Context, bucketName []byte, projectID uuid.UUID) (bucket Bucket, err error)
|
|
// GetBucketPlacement returns with the placement constraint identifier.
|
|
GetBucketPlacement(ctx context.Context, bucketName []byte, projectID uuid.UUID) (placement storj.PlacementConstraint, err error)
|
|
// GetMinimalBucket returns existing bucket with minimal number of fields.
|
|
GetMinimalBucket(ctx context.Context, bucketName []byte, projectID uuid.UUID) (bucket MinimalBucket, err error)
|
|
// HasBucket returns if a bucket exists.
|
|
HasBucket(ctx context.Context, bucketName []byte, projectID uuid.UUID) (exists bool, err error)
|
|
// GetBucketID returns an existing bucket id.
|
|
GetBucketID(ctx context.Context, bucket metabase.BucketLocation) (id uuid.UUID, err error)
|
|
// UpdateBucket updates an existing bucket
|
|
UpdateBucket(ctx context.Context, bucket Bucket) (_ Bucket, err error)
|
|
// UpdateUserAgent updates buckets user agent.
|
|
UpdateUserAgent(ctx context.Context, projectID uuid.UUID, bucketName string, userAgent []byte) error
|
|
// DeleteBucket deletes a bucket
|
|
DeleteBucket(ctx context.Context, bucketName []byte, projectID uuid.UUID) (err error)
|
|
// ListBuckets returns all buckets for a project
|
|
ListBuckets(ctx context.Context, projectID uuid.UUID, listOpts ListOptions, allowedBuckets macaroon.AllowedBuckets) (bucketList List, err error)
|
|
// CountBuckets returns the number of buckets a project currently has
|
|
CountBuckets(ctx context.Context, projectID uuid.UUID) (int, error)
|
|
// IterateBucketLocations iterates through all buckets from some point with limit.
|
|
IterateBucketLocations(ctx context.Context, projectID uuid.UUID, bucketName string, limit int, fn func([]metabase.BucketLocation) error) (more bool, err error)
|
|
}
|