2019-07-05 17:04:15 +01:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package testblobs
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"sync/atomic"
|
|
|
|
"time"
|
|
|
|
|
2021-09-10 14:05:29 +01:00
|
|
|
"github.com/zeebo/errs"
|
2019-07-05 17:04:15 +01:00
|
|
|
"go.uber.org/zap"
|
|
|
|
|
2020-07-10 20:36:39 +01:00
|
|
|
"storj.io/common/storj"
|
2019-07-05 17:04:15 +01:00
|
|
|
"storj.io/storj/storage"
|
|
|
|
"storj.io/storj/storagenode"
|
|
|
|
)
|
|
|
|
|
|
|
|
// SlowDB implements slow storage node DB.
|
|
|
|
type SlowDB struct {
|
|
|
|
storagenode.DB
|
|
|
|
blobs *SlowBlobs
|
|
|
|
log *zap.Logger
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewSlowDB creates a new slow storage node DB wrapping the provided db.
|
|
|
|
// Use SetLatency to dynamically configure the latency of all piece operations.
|
|
|
|
func NewSlowDB(log *zap.Logger, db storagenode.DB) *SlowDB {
|
|
|
|
return &SlowDB{
|
|
|
|
DB: db,
|
2019-08-08 02:47:30 +01:00
|
|
|
blobs: newSlowBlobs(log, db.Pieces()),
|
2019-07-05 17:04:15 +01:00
|
|
|
log: log,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pieces returns the blob store.
|
|
|
|
func (slow *SlowDB) Pieces() storage.Blobs {
|
|
|
|
return slow.blobs
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetLatency enables a sleep for delay duration for all piece operations.
|
|
|
|
// A zero or negative delay means no sleep.
|
|
|
|
func (slow *SlowDB) SetLatency(delay time.Duration) {
|
|
|
|
slow.blobs.SetLatency(delay)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SlowBlobs implements a slow blob store.
|
|
|
|
type SlowBlobs struct {
|
|
|
|
delay int64 // time.Duration
|
|
|
|
blobs storage.Blobs
|
|
|
|
log *zap.Logger
|
|
|
|
}
|
|
|
|
|
2019-08-08 02:47:30 +01:00
|
|
|
// newSlowBlobs creates a new slow blob store wrapping the provided blobs.
|
2019-07-05 17:04:15 +01:00
|
|
|
// Use SetLatency to dynamically configure the latency of all operations.
|
2019-08-08 02:47:30 +01:00
|
|
|
func newSlowBlobs(log *zap.Logger, blobs storage.Blobs) *SlowBlobs {
|
2019-07-05 17:04:15 +01:00
|
|
|
return &SlowBlobs{
|
|
|
|
log: log,
|
|
|
|
blobs: blobs,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create creates a new blob that can be written optionally takes a size
|
|
|
|
// argument for performance improvements, -1 is unknown size.
|
|
|
|
func (slow *SlowBlobs) Create(ctx context.Context, ref storage.BlobRef, size int64) (storage.BlobWriter, error) {
|
2021-09-10 14:05:29 +01:00
|
|
|
if err := slow.sleep(ctx); err != nil {
|
|
|
|
return nil, errs.Wrap(err)
|
|
|
|
}
|
2019-07-05 17:04:15 +01:00
|
|
|
return slow.blobs.Create(ctx, ref, size)
|
|
|
|
}
|
|
|
|
|
2019-11-13 19:15:31 +00:00
|
|
|
// Close closes the blob store and any resources associated with it.
|
|
|
|
func (slow *SlowBlobs) Close() error {
|
|
|
|
return slow.blobs.Close()
|
|
|
|
}
|
|
|
|
|
2019-07-05 17:04:15 +01:00
|
|
|
// Open opens a reader with the specified namespace and key.
|
|
|
|
func (slow *SlowBlobs) Open(ctx context.Context, ref storage.BlobRef) (storage.BlobReader, error) {
|
2021-09-10 14:05:29 +01:00
|
|
|
if err := slow.sleep(ctx); err != nil {
|
|
|
|
return nil, errs.Wrap(err)
|
|
|
|
}
|
2019-07-05 17:04:15 +01:00
|
|
|
return slow.blobs.Open(ctx, ref)
|
|
|
|
}
|
|
|
|
|
2019-08-08 02:47:30 +01:00
|
|
|
// OpenWithStorageFormat opens a reader for the already-located blob, avoiding the potential need
|
|
|
|
// to check multiple storage formats to find the blob.
|
|
|
|
func (slow *SlowBlobs) OpenWithStorageFormat(ctx context.Context, ref storage.BlobRef, formatVer storage.FormatVersion) (storage.BlobReader, error) {
|
2021-09-10 14:05:29 +01:00
|
|
|
if err := slow.sleep(ctx); err != nil {
|
|
|
|
return nil, errs.Wrap(err)
|
|
|
|
}
|
2019-08-08 02:47:30 +01:00
|
|
|
return slow.blobs.OpenWithStorageFormat(ctx, ref, formatVer)
|
|
|
|
}
|
|
|
|
|
2019-11-14 22:19:15 +00:00
|
|
|
// Trash deletes the blob with the namespace and key.
|
|
|
|
func (slow *SlowBlobs) Trash(ctx context.Context, ref storage.BlobRef) error {
|
2021-09-10 14:05:29 +01:00
|
|
|
if err := slow.sleep(ctx); err != nil {
|
|
|
|
return errs.Wrap(err)
|
|
|
|
}
|
2019-11-14 22:19:15 +00:00
|
|
|
return slow.blobs.Trash(ctx, ref)
|
|
|
|
}
|
|
|
|
|
2020-07-16 15:18:02 +01:00
|
|
|
// RestoreTrash restores all files in the trash.
|
2019-12-21 13:11:24 +00:00
|
|
|
func (slow *SlowBlobs) RestoreTrash(ctx context.Context, namespace []byte) ([][]byte, error) {
|
2021-09-10 14:05:29 +01:00
|
|
|
if err := slow.sleep(ctx); err != nil {
|
|
|
|
return nil, errs.Wrap(err)
|
|
|
|
}
|
2019-11-14 22:19:15 +00:00
|
|
|
return slow.blobs.RestoreTrash(ctx, namespace)
|
|
|
|
}
|
|
|
|
|
2020-07-16 15:18:02 +01:00
|
|
|
// EmptyTrash empties the trash.
|
2019-12-21 13:11:24 +00:00
|
|
|
func (slow *SlowBlobs) EmptyTrash(ctx context.Context, namespace []byte, trashedBefore time.Time) (int64, [][]byte, error) {
|
2021-09-10 14:05:29 +01:00
|
|
|
if err := slow.sleep(ctx); err != nil {
|
|
|
|
return 0, nil, errs.Wrap(err)
|
|
|
|
}
|
2019-11-26 16:25:21 +00:00
|
|
|
return slow.blobs.EmptyTrash(ctx, namespace, trashedBefore)
|
|
|
|
}
|
|
|
|
|
2019-07-05 17:04:15 +01:00
|
|
|
// Delete deletes the blob with the namespace and key.
|
|
|
|
func (slow *SlowBlobs) Delete(ctx context.Context, ref storage.BlobRef) error {
|
2021-09-10 14:05:29 +01:00
|
|
|
if err := slow.sleep(ctx); err != nil {
|
|
|
|
return errs.Wrap(err)
|
|
|
|
}
|
2019-07-05 17:04:15 +01:00
|
|
|
return slow.blobs.Delete(ctx, ref)
|
|
|
|
}
|
|
|
|
|
2020-07-16 15:18:02 +01:00
|
|
|
// DeleteWithStorageFormat deletes the blob with the namespace, key, and format version.
|
2019-11-04 16:59:45 +00:00
|
|
|
func (slow *SlowBlobs) DeleteWithStorageFormat(ctx context.Context, ref storage.BlobRef, formatVer storage.FormatVersion) error {
|
2021-09-10 14:05:29 +01:00
|
|
|
if err := slow.sleep(ctx); err != nil {
|
|
|
|
return errs.Wrap(err)
|
|
|
|
}
|
2019-11-04 16:59:45 +00:00
|
|
|
return slow.blobs.DeleteWithStorageFormat(ctx, ref, formatVer)
|
|
|
|
}
|
|
|
|
|
2020-07-08 11:50:40 +01:00
|
|
|
// DeleteNamespace deletes blobs of specific satellite, used after successful GE only.
|
|
|
|
func (slow *SlowBlobs) DeleteNamespace(ctx context.Context, ref []byte) (err error) {
|
2021-09-10 14:05:29 +01:00
|
|
|
if err := slow.sleep(ctx); err != nil {
|
|
|
|
return errs.Wrap(err)
|
|
|
|
}
|
2020-07-08 11:50:40 +01:00
|
|
|
return slow.blobs.DeleteNamespace(ctx, ref)
|
|
|
|
}
|
|
|
|
|
2020-07-16 15:18:02 +01:00
|
|
|
// Stat looks up disk metadata on the blob file.
|
2019-08-08 02:47:30 +01:00
|
|
|
func (slow *SlowBlobs) Stat(ctx context.Context, ref storage.BlobRef) (storage.BlobInfo, error) {
|
2021-09-10 14:05:29 +01:00
|
|
|
if err := slow.sleep(ctx); err != nil {
|
|
|
|
return nil, errs.Wrap(err)
|
|
|
|
}
|
2019-08-08 02:47:30 +01:00
|
|
|
return slow.blobs.Stat(ctx, ref)
|
|
|
|
}
|
|
|
|
|
|
|
|
// StatWithStorageFormat looks up disk metadata for the blob file with the given storage format
|
|
|
|
// version. This avoids the potential need to check multiple storage formats for the blob
|
|
|
|
// when the format is already known.
|
|
|
|
func (slow *SlowBlobs) StatWithStorageFormat(ctx context.Context, ref storage.BlobRef, formatVer storage.FormatVersion) (storage.BlobInfo, error) {
|
2021-09-10 14:05:29 +01:00
|
|
|
if err := slow.sleep(ctx); err != nil {
|
|
|
|
return nil, errs.Wrap(err)
|
|
|
|
}
|
2019-08-08 02:47:30 +01:00
|
|
|
return slow.blobs.StatWithStorageFormat(ctx, ref, formatVer)
|
|
|
|
}
|
|
|
|
|
|
|
|
// WalkNamespace executes walkFunc for each locally stored blob in the given namespace.
|
|
|
|
// If walkFunc returns a non-nil error, WalkNamespace will stop iterating and return the
|
|
|
|
// error immediately.
|
|
|
|
func (slow *SlowBlobs) WalkNamespace(ctx context.Context, namespace []byte, walkFunc func(storage.BlobInfo) error) error {
|
2021-09-10 14:05:29 +01:00
|
|
|
if err := slow.sleep(ctx); err != nil {
|
|
|
|
return errs.Wrap(err)
|
|
|
|
}
|
2019-08-08 02:47:30 +01:00
|
|
|
return slow.blobs.WalkNamespace(ctx, namespace, walkFunc)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ListNamespaces returns all namespaces that might be storing data.
|
|
|
|
func (slow *SlowBlobs) ListNamespaces(ctx context.Context) ([][]byte, error) {
|
|
|
|
return slow.blobs.ListNamespaces(ctx)
|
|
|
|
}
|
|
|
|
|
2019-07-05 17:04:15 +01:00
|
|
|
// FreeSpace return how much free space left for writing.
|
2021-09-10 14:05:29 +01:00
|
|
|
func (slow *SlowBlobs) FreeSpace(ctx context.Context) (int64, error) {
|
|
|
|
if err := slow.sleep(ctx); err != nil {
|
|
|
|
return 0, errs.Wrap(err)
|
|
|
|
}
|
|
|
|
return slow.blobs.FreeSpace(ctx)
|
2019-07-05 17:04:15 +01:00
|
|
|
}
|
|
|
|
|
2020-08-07 17:19:37 +01:00
|
|
|
// CheckWritability tests writability of the storage directory by creating and deleting a file.
|
2021-09-10 14:05:29 +01:00
|
|
|
func (slow *SlowBlobs) CheckWritability(ctx context.Context) error {
|
|
|
|
if err := slow.sleep(ctx); err != nil {
|
|
|
|
return errs.Wrap(err)
|
|
|
|
}
|
|
|
|
return slow.blobs.CheckWritability(ctx)
|
2020-08-07 17:19:37 +01:00
|
|
|
}
|
|
|
|
|
2020-07-16 15:18:02 +01:00
|
|
|
// SpaceUsedForBlobs adds up how much is used in all namespaces.
|
2019-12-21 13:11:24 +00:00
|
|
|
func (slow *SlowBlobs) SpaceUsedForBlobs(ctx context.Context) (int64, error) {
|
2021-09-10 14:05:29 +01:00
|
|
|
if err := slow.sleep(ctx); err != nil {
|
|
|
|
return 0, errs.Wrap(err)
|
|
|
|
}
|
2019-12-21 13:11:24 +00:00
|
|
|
return slow.blobs.SpaceUsedForBlobs(ctx)
|
2019-08-08 02:47:30 +01:00
|
|
|
}
|
|
|
|
|
2020-07-16 15:18:02 +01:00
|
|
|
// SpaceUsedForBlobsInNamespace adds up how much is used in the given namespace.
|
2019-12-21 13:11:24 +00:00
|
|
|
func (slow *SlowBlobs) SpaceUsedForBlobsInNamespace(ctx context.Context, namespace []byte) (int64, error) {
|
2021-09-10 14:05:29 +01:00
|
|
|
if err := slow.sleep(ctx); err != nil {
|
|
|
|
return 0, errs.Wrap(err)
|
|
|
|
}
|
2019-12-21 13:11:24 +00:00
|
|
|
return slow.blobs.SpaceUsedForBlobsInNamespace(ctx, namespace)
|
|
|
|
}
|
|
|
|
|
2020-07-16 15:18:02 +01:00
|
|
|
// SpaceUsedForTrash adds up how much is used in all namespaces.
|
2019-12-21 13:11:24 +00:00
|
|
|
func (slow *SlowBlobs) SpaceUsedForTrash(ctx context.Context) (int64, error) {
|
2021-09-10 14:05:29 +01:00
|
|
|
if err := slow.sleep(ctx); err != nil {
|
|
|
|
return 0, errs.Wrap(err)
|
|
|
|
}
|
2019-12-21 13:11:24 +00:00
|
|
|
return slow.blobs.SpaceUsedForTrash(ctx)
|
2019-08-08 02:47:30 +01:00
|
|
|
}
|
|
|
|
|
2020-07-10 20:36:39 +01:00
|
|
|
// CreateVerificationFile creates a file to be used for storage directory verification.
|
2021-09-10 14:05:29 +01:00
|
|
|
func (slow *SlowBlobs) CreateVerificationFile(ctx context.Context, id storj.NodeID) error {
|
|
|
|
if err := slow.sleep(ctx); err != nil {
|
|
|
|
return errs.Wrap(err)
|
|
|
|
}
|
|
|
|
return slow.blobs.CreateVerificationFile(ctx, id)
|
2020-07-10 20:36:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// VerifyStorageDir verifies that the storage directory is correct by checking for the existence and validity
|
|
|
|
// of the verification file.
|
2021-09-10 14:05:29 +01:00
|
|
|
func (slow *SlowBlobs) VerifyStorageDir(ctx context.Context, id storj.NodeID) error {
|
|
|
|
return slow.blobs.VerifyStorageDir(ctx, id)
|
2020-07-10 20:36:39 +01:00
|
|
|
}
|
|
|
|
|
2019-07-05 17:04:15 +01:00
|
|
|
// SetLatency configures the blob store to sleep for delay duration for all
|
|
|
|
// operations. A zero or negative delay means no sleep.
|
|
|
|
func (slow *SlowBlobs) SetLatency(delay time.Duration) {
|
|
|
|
atomic.StoreInt64(&slow.delay, int64(delay))
|
|
|
|
}
|
|
|
|
|
2020-07-16 15:18:02 +01:00
|
|
|
// sleep sleeps for the duration set to slow.delay.
|
2021-09-10 14:05:29 +01:00
|
|
|
func (slow *SlowBlobs) sleep(ctx context.Context) error {
|
2019-07-05 17:04:15 +01:00
|
|
|
delay := time.Duration(atomic.LoadInt64(&slow.delay))
|
2021-09-10 14:05:29 +01:00
|
|
|
select {
|
|
|
|
case <-time.After(delay):
|
|
|
|
return nil
|
|
|
|
case <-ctx.Done():
|
|
|
|
return ctx.Err()
|
|
|
|
}
|
2019-07-05 17:04:15 +01:00
|
|
|
}
|