Change mode of shard components #1121

Merged
fyrchik merged 3 commits from achuprov/frostfs-node:feat/change_mode_shard_components into master 2024-06-05 05:55:27 +00:00
48 changed files with 215 additions and 114 deletions

View file

@ -14,7 +14,16 @@ Each mode is characterized by two important properties:
| `read-only` | Read-only mode, only read operations are allowed, metabase is available. |
| `degraded` | Degraded mode in which metabase and write-cache is disabled. It shouldn't be used at all, because metabase can contain important indices, such as LOCK objects info and modifying operation in this mode can lead to unexpected behaviour. The purpose of this mode is to allow PUT/DELETE operations without the metabase if really necessary. |
| `degraded-read-only` | Same as `degraded`, but with only read operations allowed. This mode is used during SSD replacement and/or when the metabase error counter exceeds threshold. |
| `disabled` | Currently used only in config file to temporarily disable a shard. |
| `disabled` | Currently used only in config file to temporarily disable a shard.
## Shard and Component Status
| Shard Mode | Metabase Mode | Blobstore Mode | Writecache Mode | Pilorama Mode | Blobovnicza Tree Mode | FSTree Mode |
|-----------------------|---------------|----------------|-----------------|---------------|-----------------------|-------------|
| `Read-Write` | READ_WRITE | READ_WRITE | READ_WRITE | READ_WRITE | READ_WRITE | READ_WRITE |
| `Read-Only` | READ_ONLY | READ_ONLY | READ_ONLY | READ_ONLY | READ_ONLY | READ_ONLY |
| `Degraded-Read-Write` | CLOSED | READ_WRITE | CLOSED | CLOSED | READ_WRITE | READ_WRITE |
| `Degraded-Read-Only` | CLOSED | READ_ONLY | CLOSED | CLOSED | READ_ONLY | READ_ONLY |
## Transition order

View file

@ -8,6 +8,7 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/internal/testutil"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger/test"
"github.com/stretchr/testify/require"
)
@ -23,7 +24,7 @@ func TestBlobovniczaTree_Concurrency(t *testing.T) {
WithBlobovniczaShallowWidth(10),
WithBlobovniczaShallowDepth(1),
WithRootPath(t.TempDir()))
require.NoError(t, st.Open(false))
require.NoError(t, st.Open(mode.ComponentReadWrite))
require.NoError(t, st.Init())
defer func() {
require.NoError(t, st.Close())

View file

@ -8,6 +8,7 @@ import (
"strings"
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util"
"go.uber.org/zap"
"golang.org/x/sync/errgroup"
@ -16,9 +17,9 @@ import (
var errFailedToChangeExtensionReadOnly = errors.New("failed to change blobovnicza extension: read only mode")
// Open opens blobovnicza tree.
func (b *Blobovniczas) Open(readOnly bool) error {
b.readOnly = readOnly
b.metrics.SetMode(readOnly)
func (b *Blobovniczas) Open(mode mode.ComponentMode) error {
b.readOnly = mode.ReadOnly()
b.metrics.SetMode(mode)
b.metrics.SetRebuildStatus(rebuildStatusNotStarted)
b.openManagers()
return nil

View file

@ -11,6 +11,7 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobovnicza"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/internal/blobstortest"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
"github.com/stretchr/testify/require"
)
@ -54,7 +55,7 @@ func openAndCloseTestTree(t *testing.T, depth, width uint64, path string) {
WithBlobovniczaShallowWidth(width),
WithRootPath(path),
)
require.NoError(t, blz.Open(false))
require.NoError(t, blz.Open(mode.ComponentReadWrite))
require.NoError(t, blz.Init())
require.NoError(t, blz.Close())
}
@ -85,7 +86,7 @@ func TestObjectsAvailableAfterDepthAndWidthEdit(t *testing.T) {
WithRootPath(rootDir),
)
require.NoError(t, blz.Open(false))
require.NoError(t, blz.Open(mode.ComponentReadWrite))
require.NoError(t, blz.Init())
obj35 := blobstortest.NewObject(10 * 1024)
@ -123,7 +124,7 @@ func TestObjectsAvailableAfterDepthAndWidthEdit(t *testing.T) {
WithRootPath(rootDir),
)
require.NoError(t, blz.Open(false))
require.NoError(t, blz.Open(mode.ComponentReadWrite))
require.NoError(t, blz.Init())
gRes, err = blz.Get(context.Background(), common.GetPrm{
@ -160,7 +161,7 @@ func TestObjectsAvailableAfterDepthAndWidthEdit(t *testing.T) {
WithBlobovniczaShallowWidth(5),
WithRootPath(rootDir),
)
require.NoError(t, blz.Open(false))
require.NoError(t, blz.Open(mode.ComponentReadWrite))
require.NoError(t, blz.Init())
gRes, err = blz.Get(context.Background(), common.GetPrm{

View file

@ -10,6 +10,7 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/internal/blobstortest"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger/test"
"github.com/stretchr/testify/require"
)
@ -24,7 +25,7 @@ func TestExistsInvalidStorageID(t *testing.T) {
WithBlobovniczaShallowDepth(2),
WithRootPath(dir),
WithBlobovniczaSize(1<<20))
require.NoError(t, b.Open(false))
require.NoError(t, b.Open(mode.ComponentReadWrite))
require.NoError(t, b.Init())
defer func() { require.NoError(t, b.Close()) }()

View file

@ -4,6 +4,7 @@ import (
"context"
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
"github.com/stretchr/testify/require"
)
@ -18,7 +19,7 @@ func TestIterateSortedLeavesAndDBPathsAreSame(t *testing.T) {
WithRootPath(t.TempDir()),
)
blz.createDBInAdvance = true
require.NoError(t, blz.Open(false))
require.NoError(t, blz.Open(mode.ComponentReadWrite))
require.NoError(t, blz.Init())
defer func() {
require.NoError(t, blz.Close())

View file

@ -4,6 +4,7 @@ import (
"time"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobovnicza"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
)
const (
@ -18,7 +19,7 @@ type Metrics interface {
SetParentID(parentID string)
SetMode(readOnly bool)
SetMode(mode.ComponentMode)
Close()
SetRebuildStatus(status string)
@ -37,7 +38,7 @@ type Metrics interface {
type noopMetrics struct{}
func (m *noopMetrics) SetParentID(string) {}
func (m *noopMetrics) SetMode(bool) {}
func (m *noopMetrics) SetMode(mode.ComponentMode) {}
func (m *noopMetrics) Close() {}
func (m *noopMetrics) SetRebuildStatus(string) {}
func (m *noopMetrics) SetRebuildPercent(uint32) {}

View file

@ -11,6 +11,7 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobovnicza"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/internal/blobstortest"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger/test"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
@ -138,7 +139,7 @@ func testRebuildFailoverValidate(t *testing.T, dir string, obj *objectSDK.Object
WithBlobovniczaSize(100*1024*1024),
WithWaitBeforeDropDB(0),
WithOpenedCacheSize(1000))
require.NoError(t, b.Open(false))
require.NoError(t, b.Open(mode.ComponentReadWrite))
require.NoError(t, b.Init())
var dPrm common.DeletePrm

View file

@ -8,6 +8,7 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/internal/blobstortest"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger/test"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"github.com/stretchr/testify/require"
@ -53,7 +54,7 @@ func TestBlobovniczaTreeRebuildLargeObject(t *testing.T) {
WithWaitBeforeDropDB(0),
WithOpenedCacheSize(1000),
WithMoveBatchSize(3))
require.NoError(t, b.Open(false))
require.NoError(t, b.Open(mode.ComponentReadWrite))
require.NoError(t, b.Init())
obj := blobstortest.NewObject(64 * 1024) // 64KB object
@ -81,7 +82,7 @@ func TestBlobovniczaTreeRebuildLargeObject(t *testing.T) {
WithWaitBeforeDropDB(0),
WithOpenedCacheSize(1000),
WithMoveBatchSize(3))
require.NoError(t, b.Open(false))
require.NoError(t, b.Open(mode.ComponentReadWrite))
require.NoError(t, b.Init())
metaStub := &storageIDUpdateStub{
@ -120,7 +121,7 @@ func testBlobovniczaTreeRebuildHelper(t *testing.T, sourceDepth, sourceWidth, ta
WithWaitBeforeDropDB(0),
WithOpenedCacheSize(1000),
WithMoveBatchSize(3))
require.NoError(t, b.Open(false))
require.NoError(t, b.Open(mode.ComponentReadWrite))
require.NoError(t, b.Init())
eg, egCtx := errgroup.WithContext(context.Background())
@ -161,7 +162,7 @@ func testBlobovniczaTreeRebuildHelper(t *testing.T, sourceDepth, sourceWidth, ta
WithWaitBeforeDropDB(0),
WithOpenedCacheSize(1000),
WithMoveBatchSize(50))
require.NoError(t, b.Open(false))
require.NoError(t, b.Open(mode.ComponentReadWrite))
require.NoError(t, b.Init())
for addr, storageID := range storageIDs {

View file

@ -4,12 +4,13 @@ import (
"context"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/compression"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
)
// Storage represents key-value object storage.
// It is used as a building block for a blobstor of a shard.
type Storage interface {
Open(readOnly bool) error
Open(mode mode.ComponentMode) error
Init() error
Close() error

View file

@ -27,15 +27,14 @@ func (b *BlobStor) Open(ctx context.Context, mode mode.Mode) error {
return nil
}
func (b *BlobStor) openBlobStor(ctx context.Context, mode mode.Mode) error {
readOnly := mode.ReadOnly()
func (b *BlobStor) openBlobStor(ctx context.Context, mod mode.Mode) error {
for i := range b.storage {
select {
case <-ctx.Done():
return ctx.Err()
default:
}
err := b.storage[i].Storage.Open(readOnly)
err := b.storage[i].Storage.Open(mode.ConvertToComponentMode(mod))
if err != nil {
return err
}

View file

@ -1,13 +1,14 @@
package fstree
import (
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util"
)
// Open implements common.Storage.
func (t *FSTree) Open(ro bool) error {
t.readOnly = ro
t.metrics.SetMode(ro)
func (t *FSTree) Open(mode mode.ComponentMode) error {
t.readOnly = mode.ReadOnly()
t.metrics.SetMode(mode)
return nil
}

View file

@ -6,6 +6,7 @@ import (
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util/logicerr"
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
@ -43,7 +44,7 @@ func TestObjectCounter(t *testing.T) {
WithDepth(2),
WithDirNameLen(2),
WithFileCounter(counter))
require.NoError(t, fst.Open(false))
require.NoError(t, fst.Open(mode.ComponentReadWrite))
require.NoError(t, fst.Init())
counterValue := counter.Value()

View file

@ -1,11 +1,15 @@
package fstree
import "time"
import (
"time"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
)
type Metrics interface {
SetParentID(parentID string)
SetMode(readOnly bool)
SetMode(mode mode.ComponentMode)
Close()
Iterate(d time.Duration, success bool)
@ -20,7 +24,7 @@ type Metrics interface {
type noopMetrics struct{}
func (m *noopMetrics) SetParentID(string) {}
func (m *noopMetrics) SetMode(bool) {}
func (m *noopMetrics) SetMode(mode.ComponentMode) {}
func (m *noopMetrics) Close() {}
func (m *noopMetrics) Iterate(time.Duration, bool) {}
func (m *noopMetrics) Delete(time.Duration, bool) {}

View file

@ -7,6 +7,7 @@ import (
objectCore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
"github.com/stretchr/testify/require"
)
@ -14,13 +15,13 @@ import (
// cons must return a storage which is NOT opened.
func TestControl(t *testing.T, cons Constructor, min, max uint64) {
s := cons(t)
require.NoError(t, s.Open(false))
require.NoError(t, s.Open(mode.ComponentReadWrite))
require.NoError(t, s.Init())
objects := prepare(t, 10, s, min, max)
require.NoError(t, s.Close())
require.NoError(t, s.Open(true))
require.NoError(t, s.Open(mode.ComponentReadOnly))
for i := range objects {
var prm common.GetPrm
prm.Address = objects[i].addr

View file

@ -5,6 +5,7 @@ import (
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
"github.com/stretchr/testify/require"
@ -12,7 +13,7 @@ import (
func TestDelete(t *testing.T, cons Constructor, min, max uint64) {
s := cons(t)
require.NoError(t, s.Open(false))
require.NoError(t, s.Open(mode.ComponentReadWrite))
require.NoError(t, s.Init())
defer func() { require.NoError(t, s.Close()) }()

View file

@ -5,13 +5,14 @@ import (
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
"github.com/stretchr/testify/require"
)
func TestExists(t *testing.T, cons Constructor, min, max uint64) {
s := cons(t)
require.NoError(t, s.Open(false))
require.NoError(t, s.Open(mode.ComponentReadWrite))
require.NoError(t, s.Init())
defer func() { require.NoError(t, s.Close()) }()

View file

@ -5,6 +5,7 @@ import (
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
"github.com/stretchr/testify/require"
@ -12,7 +13,7 @@ import (
func TestGet(t *testing.T, cons Constructor, min, max uint64) {
s := cons(t)
require.NoError(t, s.Open(false))
require.NoError(t, s.Open(mode.ComponentReadWrite))
require.NoError(t, s.Init())
defer func() { require.NoError(t, s.Close()) }()

View file

@ -6,6 +6,7 @@ import (
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
@ -14,7 +15,7 @@ import (
func TestGetRange(t *testing.T, cons Constructor, min, max uint64) {
s := cons(t)
require.NoError(t, s.Open(false))
require.NoError(t, s.Open(mode.ComponentReadWrite))
require.NoError(t, s.Init())
defer func() { require.NoError(t, s.Close()) }()

View file

@ -6,12 +6,13 @@ import (
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
"github.com/stretchr/testify/require"
)
func TestIterate(t *testing.T, cons Constructor, min, max uint64) {
s := cons(t)
require.NoError(t, s.Open(false))
require.NoError(t, s.Open(mode.ComponentReadWrite))
require.NoError(t, s.Init())
defer func() { require.NoError(t, s.Close()) }()

View file

@ -1,9 +1,12 @@
package memstore
import "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/compression"
import (
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/compression"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
)
func (s *memstoreImpl) Open(readOnly bool) error {
s.readOnly = readOnly
func (s *memstoreImpl) Open(mod mode.ComponentMode) error {
s.readOnly = mod.ReadOnly()
return nil
}

View file

@ -7,6 +7,7 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/internal/blobstortest"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger/test"
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
"github.com/stretchr/testify/require"
@ -18,7 +19,7 @@ func TestSimpleLifecycle(t *testing.T) {
WithLogger(test.NewLogger(t)),
)
defer func() { require.NoError(t, s.Close()) }()
require.NoError(t, s.Open(false))
require.NoError(t, s.Open(mode.ComponentReadWrite))
require.NoError(t, s.Init())
obj := blobstortest.NewObject(1024)

View file

@ -10,6 +10,7 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/fstree"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/memstore"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/internal/testutil"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
"github.com/stretchr/testify/require"
"golang.org/x/sync/errgroup"
)
@ -22,7 +23,7 @@ type storage struct {
func (s storage) open(b *testing.B) common.Storage {
st := s.create(b.TempDir())
require.NoError(b, st.Open(false))
require.NoError(b, st.Open(mode.ComponentReadWrite))
require.NoError(b, st.Init())
return st

View file

@ -3,12 +3,13 @@ package teststore
import (
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/compression"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
)
type cfg struct {
st common.Storage
overrides struct {
Open func(readOnly bool) error
Open func(mode mode.ComponentMode) error
Init func() error
Close func() error
@ -35,7 +36,7 @@ func WithSubstorage(st common.Storage) Option {
}
}
func WithOpen(f func(bool) error) Option { return func(c *cfg) { c.overrides.Open = f } }
func WithOpen(f func(mode.ComponentMode) error) Option { return func(c *cfg) { c.overrides.Open = f } }
func WithInit(f func() error) Option { return func(c *cfg) { c.overrides.Init = f } }
func WithClose(f func() error) Option { return func(c *cfg) { c.overrides.Close = f } }

View file

@ -20,6 +20,7 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/compression"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
)
// TestStore is a common.Storage implementation for testing/mocking purposes.
@ -50,16 +51,16 @@ func (s *TestStore) SetOption(opt Option) {
opt(s.cfg)
}
func (s *TestStore) Open(readOnly bool) error {
func (s *TestStore) Open(mod mode.ComponentMode) error {
s.mu.RLock()
defer s.mu.RUnlock()
switch {
case s.overrides.Open != nil:
return s.overrides.Open(readOnly)
return s.overrides.Open(mod)
case s.st != nil:
return s.st.Open(readOnly)
return s.st.Open(mod)
default:
panic(fmt.Sprintf("unexpected storage call: Open(%v)", readOnly))
panic(fmt.Sprintf("unexpected storage call: Open(%v)", mod.String()))
}
}

View file

@ -74,7 +74,7 @@ func TestInitializationFailure(t *testing.T) {
openFileMetabase: os.OpenFile,
openFilePilorama: os.OpenFile,
})
largeFileStorage.SetOption(teststore.WithOpen(func(ro bool) error {
largeFileStorage.SetOption(teststore.WithOpen(func(primitiveMode mode.ComponentMode) error {
return teststore.ErrDiskExploded
}))
beforeReload := func() {

View file

@ -171,8 +171,8 @@ func (m *writeCacheMetrics) SetEstimateSize(db, fstree uint64) {
m.metrics.SetEstimateSize(m.shardID, m.path, writecache.StorageTypeFSTree.String(), fstree)
}
func (m *writeCacheMetrics) SetMode(mode mode.Mode) {
m.metrics.SetMode(m.shardID, mode.String())
func (m *writeCacheMetrics) SetMode(mod mode.ComponentMode) {
m.metrics.SetMode(m.shardID, mod.String())
}
func (m *writeCacheMetrics) SetActualCounters(db, fstree uint64) {

View file

@ -38,16 +38,16 @@ var (
)
// Open boltDB instance for metabase.
func (db *DB) Open(_ context.Context, mode mode.Mode) error {
func (db *DB) Open(_ context.Context, m mode.Mode) error {
db.modeMtx.Lock()
defer db.modeMtx.Unlock()
db.mode = mode
db.metrics.SetMode(mode)
db.mode = m
db.metrics.SetMode(mode.ConvertToComponentModeDegraded(m))
if mode.NoMetabase() {
if m.NoMetabase() {
return nil
}
return db.openDB(mode)
return db.openDB(m)
}
func (db *DB) openDB(mode mode.Mode) error {
@ -239,15 +239,15 @@ func (db *DB) Reload(opts ...Option) (bool, error) {
return false, err
}
db.mode = mode.Degraded
db.metrics.SetMode(mode.Degraded)
db.mode = mode.Disabled
db.metrics.SetMode(mode.ComponentDisabled)
db.info.Path = c.info.Path
if err := db.openBolt(); err != nil {
return false, metaerr.Wrap(fmt.Errorf("%w: %v", ErrDegradedMode, err))
}
db.mode = mode.ReadWrite
db.metrics.SetMode(mode.ReadWrite)
db.metrics.SetMode(mode.ComponentReadWrite)
return true, nil
}

View file

@ -9,7 +9,7 @@ import (
type Metrics interface {
SetParentID(parentID string)
SetMode(m mode.Mode)
SetMode(m mode.ComponentMode)
Close()
AddMethodDuration(method string, d time.Duration, success bool)
@ -18,6 +18,6 @@ type Metrics interface {
type noopMetrics struct{}
func (m *noopMetrics) SetParentID(string) {}
func (m *noopMetrics) SetMode(mode.Mode) {}
func (m *noopMetrics) SetMode(mode.ComponentMode) {}
func (m *noopMetrics) Close() {}
func (m *noopMetrics) AddMethodDuration(string, time.Duration, bool) {}

View file

@ -35,6 +35,6 @@ func (db *DB) SetMode(m mode.Mode) error {
}
db.mode = m
db.metrics.SetMode(m)
db.metrics.SetMode(mode.ConvertToComponentModeDegraded(m))
return nil
}

View file

@ -69,7 +69,7 @@ func (db *DB) SetShardID(id []byte, mode metamode.Mode) error {
err := db.writeShardID(id)
if err == nil {
db.metrics.SetMode(mode)
db.metrics.SetMode(metamode.ConvertToComponentModeDegraded(mode))
}
if cErr := db.close(); cErr != nil {

View file

@ -5,6 +5,7 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobovnicza"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/blobovniczatree"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
metrics_impl "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/metrics"
)
@ -34,8 +35,8 @@ func (m *blobovniczaTreeMetrics) SetParentID(parentID string) {
m.shardID = parentID
}
func (m *blobovniczaTreeMetrics) SetMode(readOnly bool) {
m.m.SetBlobobvnizcaTreeMode(m.shardID, m.path, readOnly)
func (m *blobovniczaTreeMetrics) SetMode(mod mode.ComponentMode) {
m.m.SetBlobobvnizcaTreeMode(m.shardID, m.path, mod)
}
func (m *blobovniczaTreeMetrics) Close() {

View file

@ -4,6 +4,7 @@ import (
"time"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/fstree"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
metrics_impl "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/metrics"
)
@ -25,8 +26,8 @@ func (m *fstreeMetrics) SetParentID(parentID string) {
m.shardID = parentID
}
func (m *fstreeMetrics) SetMode(readOnly bool) {
m.m.SetMode(m.shardID, m.path, readOnly)
func (m *fstreeMetrics) SetMode(mod mode.ComponentMode) {
m.m.SetMode(m.shardID, m.path, mod)
}
func (m *fstreeMetrics) Close() {

View file

@ -26,7 +26,7 @@ func (m *metabaseMetrics) SetParentID(parentID string) {
m.shardID = parentID
}
func (m *metabaseMetrics) SetMode(mode mode.Mode) {
func (m *metabaseMetrics) SetMode(mode mode.ComponentMode) {
m.m.SetMode(m.shardID, m.path, mode.String())
}

View file

@ -24,8 +24,8 @@ func (m *piloramaMetrics) SetParentID(id string) {
m.shardID = id
}
func (m *piloramaMetrics) SetMode(mode mode.Mode) {
m.m.SetMode(m.shardID, mode)
func (m *piloramaMetrics) SetMode(mod mode.ComponentMode) {
m.m.SetMode(m.shardID, mod)
}
func (m *piloramaMetrics) Close() {

View file

@ -109,7 +109,7 @@ func (t *boltForest) SetMode(m mode.Mode) error {
}
t.mode = m
t.metrics.SetMode(m)
t.metrics.SetMode(mode.ConvertToComponentModeDegraded(m))
return nil
}
@ -123,8 +123,8 @@ func (t *boltForest) Open(_ context.Context, mode mode.Mode) error {
return t.openBolt(mode)
}
func (t *boltForest) openBolt(mode mode.Mode) error {
readOnly := mode.ReadOnly()
func (t *boltForest) openBolt(m mode.Mode) error {
readOnly := m.ReadOnly()
err := util.MkdirAllX(filepath.Dir(t.path), t.perm)
if err != nil {
return metaerr.Wrap(fmt.Errorf("can't create dir %s for the pilorama: %w", t.path, err))
@ -143,7 +143,7 @@ func (t *boltForest) openBolt(mode mode.Mode) error {
t.db.MaxBatchSize = t.maxBatchSize
t.db.MaxBatchDelay = t.maxBatchDelay
t.metrics.SetMode(mode)
t.metrics.SetMode(mode.ConvertToComponentModeDegraded(m))
return nil
}

View file

@ -9,7 +9,7 @@ import (
type Metrics interface {
SetParentID(id string)
SetMode(m mode.Mode)
SetMode(m mode.ComponentMode)
Close()
AddMethodDuration(method string, d time.Duration, success bool)
@ -18,6 +18,6 @@ type Metrics interface {
type noopMetrics struct{}
func (m *noopMetrics) SetParentID(string) {}
func (m *noopMetrics) SetMode(mode.Mode) {}
func (m *noopMetrics) SetMode(mode.ComponentMode) {}
func (m *noopMetrics) Close() {}
func (m *noopMetrics) AddMethodDuration(string, time.Duration, bool) {}

View file

@ -37,7 +37,7 @@ func (s *Shard) handleMetabaseFailure(stage string, err error) error {
err = s.SetMode(mode.DegradedReadOnly)
if err != nil {
return fmt.Errorf("could not switch to mode %s", mode.DegradedReadOnly)
return fmt.Errorf("could not switch to mode %s", mode.Mode(mode.DegradedReadOnly))
}
return nil
}

View file

@ -8,27 +8,41 @@ type Mode uint32
const (
// ReadWrite is a Mode value for shard that is available
// for read and write operations. Default shard mode.
ReadWrite Mode = 0
ReadWrite Mode = 0b000
// DegradedReadOnly is a Mode value for shard that is set automatically
// after a certain number of errors is encountered. It is the same as
// `mode.Degraded` but also is read-only.
DegradedReadOnly = Degraded | ReadOnly
// ReadOnly is a Mode value for shard that does not
// accept write operation but is readable.
ReadOnly Mode = 0b001
// Degraded is a Mode value for shard when the metabase is unavailable.
// It is hard to perform some modifying operations in this mode, thus it can only be set by an administrator.
Degraded Mode = 0b010
// Disabled mode is a mode where a shard is disabled.
// An existing shard can't have this mode, but it can be used in
// the configuration or control service commands.
Disabled = math.MaxUint32
Disabled Mode = math.MaxUint32
// DegradedReadOnly is a Mode value for shard that is set automatically
// after a certain number of errors is encountered. It is the same as
// `mode.Degraded` but also is read-only.
DegradedReadOnly Mode = Degraded | ReadOnly
)
const (
// ReadOnly is a Mode value for shard that does not
// accept write operation but is readable.
ReadOnly Mode = 1 << iota
// ComponentMode represents basic operation modes for shared components, including READ, READ_WRITE, and DISABLED.
type ComponentMode uint32
// Degraded is a Mode value for shard when the metabase is unavailable.
// It is hard to perform some modifying operations in this mode, thus it can only be set by an administrator.
Degraded
const (
// ComponentReadWrite is a Mode value for component that is available
// for read and write operations. Default component mode.
ComponentReadWrite ComponentMode = 0
// ComponentReadOnly is a Mode value for component that does not
// accept write operation but is readable.
ComponentReadOnly ComponentMode = 0b001
// ComponentDisabled mode is a mode where a component is disabled.
ComponentDisabled ComponentMode = math.MaxUint32
)
func (m Mode) String() string {
@ -48,6 +62,19 @@ func (m Mode) String() string {
}
}
func (m ComponentMode) String() string {
switch m {
default:
return "UNDEFINED"
case ComponentReadWrite:
return "READ_WRITE"
case ComponentReadOnly:
return "READ_ONLY"
case ComponentDisabled:
return "CLOSED"
}
}
// NoMetabase returns true iff m is operating without the metabase.
func (m Mode) NoMetabase() bool {
return m&Degraded != 0
@ -58,6 +85,39 @@ func (m Mode) ReadOnly() bool {
return m&ReadOnly != 0
}
// ReadOnly returns true iff m prohibits modifying operations with shard.
func (m ComponentMode) ReadOnly() bool {
return m&ComponentReadOnly != 0
}
func (m Mode) Disabled() bool {
return m == Disabled
}
func (m ComponentMode) Disabled() bool {
return m == ComponentDisabled
}
// ConvertToComponentModeDegraded converts a ShardMode to a corresponding ComponentMode.
// Disables the component if the node is in degraded mode. Used in Metabase, Writecache, Pilorama.
func ConvertToComponentModeDegraded(m Mode) ComponentMode {
if m.NoMetabase() || m.Disabled() {
return ComponentDisabled
}
if m.ReadOnly() {
return ComponentReadOnly
}
return ComponentReadWrite
}
// ConvertToComponentMode converts a ShardMode to a corresponding ComponentMode.
// Ignores the degraded mode of the node. Used in Blobstore.
func ConvertToComponentMode(m Mode) ComponentMode {
if m.Disabled() {
return ComponentDisabled
}
if m.ReadOnly() {
return ComponentReadOnly
}
return ComponentReadWrite
}

View file

@ -95,14 +95,14 @@ func (c *cache) DumpInfo() Info {
}
// Open opens and initializes database. Reads object counters from the ObjectCounters instance.
func (c *cache) Open(_ context.Context, mode mode.Mode) error {
func (c *cache) Open(_ context.Context, mod mode.Mode) error {
c.modeMtx.Lock()
defer c.modeMtx.Unlock()
c.mode = mode
if mode.NoMetabase() {
c.mode = mod
if mod.NoMetabase() {
return nil
}
err := c.openStore(mode.ReadOnly())
err := c.openStore(mode.ConvertToComponentModeDegraded(mod))
if err != nil {
return metaerr.Wrap(err)
}
@ -112,7 +112,7 @@ func (c *cache) Open(_ context.Context, mode mode.Mode) error {
// Init runs necessary services.
func (c *cache) Init() error {
c.metrics.SetMode(c.mode)
c.metrics.SetMode(mode.ConvertToComponentModeDegraded(c.mode))
ctx, cancel := context.WithCancel(context.Background())
c.cancel = cancel
c.runFlushLoop(ctx)

View file

@ -294,7 +294,7 @@ func (c *cache) Flush(ctx context.Context, ignoreErrors, seal bool) error {
if err := c.setMode(ctx, m, ignoreErrors); err != nil {
return err
}
c.metrics.SetMode(m)
c.metrics.SetMode(mode.ConvertToComponentModeDegraded(m))
}
return nil
}

View file

@ -27,7 +27,7 @@ type Metrics interface {
Evict(st StorageType)
SetEstimateSize(db, fstree uint64)
SetMode(m mode.Mode)
SetMode(m mode.ComponentMode)
SetActualCounters(db, fstree uint64)
SetPath(path string)
Close()
@ -49,7 +49,7 @@ func (metricsStub) Put(time.Duration, bool, StorageType) {}
func (metricsStub) SetEstimateSize(uint64, uint64) {}
func (metricsStub) SetMode(mode.Mode) {}
func (metricsStub) SetMode(mode.ComponentMode) {}
func (metricsStub) SetActualCounters(uint64, uint64) {}

View file

@ -27,7 +27,7 @@ func (c *cache) SetMode(m mode.Mode) error {
err := c.setMode(ctx, m, true)
if err == nil {
c.metrics.SetMode(m)
c.metrics.SetMode(mode.ConvertToComponentModeDegraded(m))
}
return err
}
@ -63,7 +63,7 @@ func (c *cache) setMode(ctx context.Context, m mode.Mode, ignoreErrors bool) err
return nil
}
if err = c.openStore(m.ReadOnly()); err != nil {
if err = c.openStore(mode.ConvertToComponentModeDegraded(m)); err != nil {
return err
}

View file

@ -22,7 +22,7 @@ func (c *cache) Seal(ctx context.Context, ignoreErrors bool) error {
// flush will be done by setMode
err := c.setMode(ctx, mode.DegradedReadOnly, ignoreErrors)
if err == nil {
c.metrics.SetMode(mode.DegradedReadOnly)
c.metrics.SetMode(mode.ComponentDisabled)
}
return err
}

View file

@ -10,6 +10,7 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/fstree"
storagelog "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/internal/log"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
@ -25,13 +26,13 @@ type store struct {
const dbName = "small.bolt"
func (c *cache) openStore(readOnly bool) error {
func (c *cache) openStore(mod mode.ComponentMode) error {
err := util.MkdirAllX(c.path, os.ModePerm)
if err != nil {
return err
}
c.db, err = OpenDB(c.path, readOnly, c.openFile)
c.db, err = OpenDB(c.path, mod.ReadOnly(), c.openFile)
if err != nil {
return fmt.Errorf("could not open database: %w", err)
}
@ -39,7 +40,7 @@ func (c *cache) openStore(readOnly bool) error {
c.db.MaxBatchSize = c.maxBatchSize
c.db.MaxBatchDelay = c.maxBatchDelay
if !readOnly {
if !mod.ReadOnly() {
err = c.db.Update(func(tx *bbolt.Tx) error {
_, err := tx.CreateBucketIfNotExists(defaultBucket)
return err
@ -57,7 +58,7 @@ func (c *cache) openStore(readOnly bool) error {
fstree.WithNoSync(c.noSync),
fstree.WithFileCounter(&c.objCounters),
)
if err := c.fsTree.Open(readOnly); err != nil {
if err := c.fsTree.Open(mod); err != nil {
return fmt.Errorf("could not open FSTree: %w", err)
}
if err := c.fsTree.Init(); err != nil {

View file

@ -4,12 +4,13 @@ import (
"strconv"
"time"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
"git.frostfs.info/TrueCloudLab/frostfs-observability/metrics"
"github.com/prometheus/client_golang/prometheus"
)
type BlobobvnizcaMetrics interface {
SetBlobobvnizcaTreeMode(shardID, path string, readOnly bool)
SetBlobobvnizcaTreeMode(shardID, path string, mode mode.ComponentMode)
CloseBlobobvnizcaTree(shardID, path string)
BlobobvnizcaTreeMethodDuration(shardID, path string, method string, d time.Duration, success bool, withStorageID NullBool)
AddBlobobvnizcaTreePut(shardID, path string, size int)
@ -98,8 +99,8 @@ func newBlobovnicza() *blobovnicza {
}
}
func (b *blobovnicza) SetBlobobvnizcaTreeMode(shardID, path string, readOnly bool) {
b.treeMode.SetMode(shardID, path, modeFromBool(readOnly))
func (b *blobovnicza) SetBlobobvnizcaTreeMode(shardID, path string, mod mode.ComponentMode) {
b.treeMode.SetMode(shardID, path, mod.String())
}
func (b *blobovnicza) CloseBlobobvnizcaTree(shardID, path string) {

View file

@ -4,12 +4,13 @@ import (
"strconv"
"time"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
"git.frostfs.info/TrueCloudLab/frostfs-observability/metrics"
"github.com/prometheus/client_golang/prometheus"
)
type FSTreeMetrics interface {
SetMode(shardID, path string, readOnly bool)
SetMode(shardID, path string, mode mode.ComponentMode)
Close(shardID, path string)
MethodDuration(shardID, path string, method string, d time.Duration, success bool)
@ -48,8 +49,8 @@ func newFSTreeMetrics() *fstreeMetrics {
}
}
func (m *fstreeMetrics) SetMode(shardID, path string, readOnly bool) {
m.mode.SetMode(shardID, path, modeFromBool(readOnly))
func (m *fstreeMetrics) SetMode(shardID, path string, mod mode.ComponentMode) {
m.mode.SetMode(shardID, path, mod.String())
}
func (m *fstreeMetrics) Close(shardID, path string) {

View file

@ -10,7 +10,7 @@ import (
)
type PiloramaMetrics interface {
SetMode(shardID string, m mode.Mode)
SetMode(shardID string, m mode.ComponentMode)
Close(shardID string)
AddMethodDuration(shardID string, method string, d time.Duration, success bool)
@ -33,7 +33,7 @@ type piloramaMetrics struct {
reqDuration *prometheus.HistogramVec
}
func (m *piloramaMetrics) SetMode(shardID string, mode mode.Mode) {
func (m *piloramaMetrics) SetMode(shardID string, mode mode.ComponentMode) {
m.mode.SetMode(shardID, mode.String())
}