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

View file

@ -8,6 +8,7 @@ import (
"strings" "strings"
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs" "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" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util"
"go.uber.org/zap" "go.uber.org/zap"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
@ -16,9 +17,9 @@ import (
var errFailedToChangeExtensionReadOnly = errors.New("failed to change blobovnicza extension: read only mode") var errFailedToChangeExtensionReadOnly = errors.New("failed to change blobovnicza extension: read only mode")
// Open opens blobovnicza tree. // Open opens blobovnicza tree.
func (b *Blobovniczas) Open(readOnly bool) error { func (b *Blobovniczas) Open(mode mode.ComponentMode) error {
b.readOnly = readOnly b.readOnly = mode.ReadOnly()
b.metrics.SetMode(readOnly) b.metrics.SetMode(mode)
b.metrics.SetRebuildStatus(rebuildStatusNotStarted) b.metrics.SetRebuildStatus(rebuildStatusNotStarted)
b.openManagers() b.openManagers()
return nil 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/blobovnicza"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common" "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/blobstor/internal/blobstortest"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -54,7 +55,7 @@ func openAndCloseTestTree(t *testing.T, depth, width uint64, path string) {
WithBlobovniczaShallowWidth(width), WithBlobovniczaShallowWidth(width),
WithRootPath(path), WithRootPath(path),
) )
require.NoError(t, blz.Open(false)) require.NoError(t, blz.Open(mode.ComponentReadWrite))
require.NoError(t, blz.Init()) require.NoError(t, blz.Init())
require.NoError(t, blz.Close()) require.NoError(t, blz.Close())
} }
@ -85,7 +86,7 @@ func TestObjectsAvailableAfterDepthAndWidthEdit(t *testing.T) {
WithRootPath(rootDir), WithRootPath(rootDir),
) )
require.NoError(t, blz.Open(false)) require.NoError(t, blz.Open(mode.ComponentReadWrite))
require.NoError(t, blz.Init()) require.NoError(t, blz.Init())
obj35 := blobstortest.NewObject(10 * 1024) obj35 := blobstortest.NewObject(10 * 1024)
@ -123,7 +124,7 @@ func TestObjectsAvailableAfterDepthAndWidthEdit(t *testing.T) {
WithRootPath(rootDir), WithRootPath(rootDir),
) )
require.NoError(t, blz.Open(false)) require.NoError(t, blz.Open(mode.ComponentReadWrite))
require.NoError(t, blz.Init()) require.NoError(t, blz.Init())
gRes, err = blz.Get(context.Background(), common.GetPrm{ gRes, err = blz.Get(context.Background(), common.GetPrm{
@ -160,7 +161,7 @@ func TestObjectsAvailableAfterDepthAndWidthEdit(t *testing.T) {
WithBlobovniczaShallowWidth(5), WithBlobovniczaShallowWidth(5),
WithRootPath(rootDir), WithRootPath(rootDir),
) )
require.NoError(t, blz.Open(false)) require.NoError(t, blz.Open(mode.ComponentReadWrite))
require.NoError(t, blz.Init()) require.NoError(t, blz.Init())
gRes, err = blz.Get(context.Background(), common.GetPrm{ 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/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/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/internal/blobstortest" "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-node/pkg/util/logger/test"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -24,7 +25,7 @@ func TestExistsInvalidStorageID(t *testing.T) {
WithBlobovniczaShallowDepth(2), WithBlobovniczaShallowDepth(2),
WithRootPath(dir), WithRootPath(dir),
WithBlobovniczaSize(1<<20)) WithBlobovniczaSize(1<<20))
require.NoError(t, b.Open(false)) require.NoError(t, b.Open(mode.ComponentReadWrite))
require.NoError(t, b.Init()) require.NoError(t, b.Init())
defer func() { require.NoError(t, b.Close()) }() defer func() { require.NoError(t, b.Close()) }()

View file

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

View file

@ -4,6 +4,7 @@ import (
"time" "time"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobovnicza" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobovnicza"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
) )
const ( const (
@ -18,7 +19,7 @@ type Metrics interface {
SetParentID(parentID string) SetParentID(parentID string)
SetMode(readOnly bool) SetMode(mode.ComponentMode)
Close() Close()
SetRebuildStatus(status string) SetRebuildStatus(status string)
@ -37,7 +38,7 @@ type Metrics interface {
type noopMetrics struct{} type noopMetrics struct{}
func (m *noopMetrics) SetParentID(string) {} func (m *noopMetrics) SetParentID(string) {}
func (m *noopMetrics) SetMode(bool) {} func (m *noopMetrics) SetMode(mode.ComponentMode) {}
func (m *noopMetrics) Close() {} func (m *noopMetrics) Close() {}
func (m *noopMetrics) SetRebuildStatus(string) {} func (m *noopMetrics) SetRebuildStatus(string) {}
func (m *noopMetrics) SetRebuildPercent(uint32) {} 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/blobovnicza"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common" "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/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-node/pkg/util/logger/test"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" 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), WithBlobovniczaSize(100*1024*1024),
WithWaitBeforeDropDB(0), WithWaitBeforeDropDB(0),
WithOpenedCacheSize(1000)) WithOpenedCacheSize(1000))
require.NoError(t, b.Open(false)) require.NoError(t, b.Open(mode.ComponentReadWrite))
require.NoError(t, b.Init()) require.NoError(t, b.Init())
var dPrm common.DeletePrm 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/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/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/internal/blobstortest" "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-node/pkg/util/logger/test"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -53,7 +54,7 @@ func TestBlobovniczaTreeRebuildLargeObject(t *testing.T) {
WithWaitBeforeDropDB(0), WithWaitBeforeDropDB(0),
WithOpenedCacheSize(1000), WithOpenedCacheSize(1000),
WithMoveBatchSize(3)) WithMoveBatchSize(3))
require.NoError(t, b.Open(false)) require.NoError(t, b.Open(mode.ComponentReadWrite))
require.NoError(t, b.Init()) require.NoError(t, b.Init())
obj := blobstortest.NewObject(64 * 1024) // 64KB object obj := blobstortest.NewObject(64 * 1024) // 64KB object
@ -81,7 +82,7 @@ func TestBlobovniczaTreeRebuildLargeObject(t *testing.T) {
WithWaitBeforeDropDB(0), WithWaitBeforeDropDB(0),
WithOpenedCacheSize(1000), WithOpenedCacheSize(1000),
WithMoveBatchSize(3)) WithMoveBatchSize(3))
require.NoError(t, b.Open(false)) require.NoError(t, b.Open(mode.ComponentReadWrite))
require.NoError(t, b.Init()) require.NoError(t, b.Init())
metaStub := &storageIDUpdateStub{ metaStub := &storageIDUpdateStub{
@ -120,7 +121,7 @@ func testBlobovniczaTreeRebuildHelper(t *testing.T, sourceDepth, sourceWidth, ta
WithWaitBeforeDropDB(0), WithWaitBeforeDropDB(0),
WithOpenedCacheSize(1000), WithOpenedCacheSize(1000),
WithMoveBatchSize(3)) WithMoveBatchSize(3))
require.NoError(t, b.Open(false)) require.NoError(t, b.Open(mode.ComponentReadWrite))
require.NoError(t, b.Init()) require.NoError(t, b.Init())
eg, egCtx := errgroup.WithContext(context.Background()) eg, egCtx := errgroup.WithContext(context.Background())
@ -161,7 +162,7 @@ func testBlobovniczaTreeRebuildHelper(t *testing.T, sourceDepth, sourceWidth, ta
WithWaitBeforeDropDB(0), WithWaitBeforeDropDB(0),
WithOpenedCacheSize(1000), WithOpenedCacheSize(1000),
WithMoveBatchSize(50)) WithMoveBatchSize(50))
require.NoError(t, b.Open(false)) require.NoError(t, b.Open(mode.ComponentReadWrite))
require.NoError(t, b.Init()) require.NoError(t, b.Init())
for addr, storageID := range storageIDs { for addr, storageID := range storageIDs {

View file

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

View file

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

View file

@ -1,13 +1,14 @@
package fstree package fstree
import ( import (
"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-node/pkg/util"
) )
// Open implements common.Storage. // Open implements common.Storage.
func (t *FSTree) Open(ro bool) error { func (t *FSTree) Open(mode mode.ComponentMode) error {
t.readOnly = ro t.readOnly = mode.ReadOnly()
t.metrics.SetMode(ro) t.metrics.SetMode(mode)
return nil return nil
} }

View file

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

View file

@ -1,11 +1,15 @@
package fstree package fstree
import "time" import (
"time"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
)
type Metrics interface { type Metrics interface {
SetParentID(parentID string) SetParentID(parentID string)
SetMode(readOnly bool) SetMode(mode mode.ComponentMode)
Close() Close()
Iterate(d time.Duration, success bool) Iterate(d time.Duration, success bool)
@ -20,7 +24,7 @@ type Metrics interface {
type noopMetrics struct{} type noopMetrics struct{}
func (m *noopMetrics) SetParentID(string) {} func (m *noopMetrics) SetParentID(string) {}
func (m *noopMetrics) SetMode(bool) {} func (m *noopMetrics) SetMode(mode.ComponentMode) {}
func (m *noopMetrics) Close() {} func (m *noopMetrics) Close() {}
func (m *noopMetrics) Iterate(time.Duration, bool) {} func (m *noopMetrics) Iterate(time.Duration, bool) {}
func (m *noopMetrics) Delete(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" 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/blobstor/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -14,13 +15,13 @@ import (
// cons must return a storage which is NOT opened. // cons must return a storage which is NOT opened.
func TestControl(t *testing.T, cons Constructor, min, max uint64) { func TestControl(t *testing.T, cons Constructor, min, max uint64) {
s := cons(t) s := cons(t)
require.NoError(t, s.Open(false)) require.NoError(t, s.Open(mode.ComponentReadWrite))
require.NoError(t, s.Init()) require.NoError(t, s.Init())
objects := prepare(t, 10, s, min, max) objects := prepare(t, 10, s, min, max)
require.NoError(t, s.Close()) require.NoError(t, s.Close())
require.NoError(t, s.Open(true)) require.NoError(t, s.Open(mode.ComponentReadOnly))
for i := range objects { for i := range objects {
var prm common.GetPrm var prm common.GetPrm
prm.Address = objects[i].addr prm.Address = objects[i].addr

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,9 +1,12 @@
package memstore 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 { func (s *memstoreImpl) Open(mod mode.ComponentMode) error {
s.readOnly = readOnly s.readOnly = mod.ReadOnly()
return nil 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/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/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/internal/blobstortest" "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-node/pkg/util/logger/test"
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -18,7 +19,7 @@ func TestSimpleLifecycle(t *testing.T) {
WithLogger(test.NewLogger(t)), WithLogger(test.NewLogger(t)),
) )
defer func() { require.NoError(t, s.Close()) }() 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()) require.NoError(t, s.Init())
obj := blobstortest.NewObject(1024) 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/fstree"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/memstore" "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/internal/testutil"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
) )
@ -22,7 +23,7 @@ type storage struct {
func (s storage) open(b *testing.B) common.Storage { func (s storage) open(b *testing.B) common.Storage {
st := s.create(b.TempDir()) st := s.create(b.TempDir())
require.NoError(b, st.Open(false)) require.NoError(b, st.Open(mode.ComponentReadWrite))
require.NoError(b, st.Init()) require.NoError(b, st.Init())
return st return st

View file

@ -3,12 +3,13 @@ package teststore
import ( import (
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common" "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/blobstor/compression"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
) )
type cfg struct { type cfg struct {
st common.Storage st common.Storage
overrides struct { overrides struct {
Open func(readOnly bool) error Open func(mode mode.ComponentMode) error
Init func() error Init func() error
Close 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 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 } } 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/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/compression" "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. // TestStore is a common.Storage implementation for testing/mocking purposes.
@ -50,16 +51,16 @@ func (s *TestStore) SetOption(opt Option) {
opt(s.cfg) opt(s.cfg)
} }
func (s *TestStore) Open(readOnly bool) error { func (s *TestStore) Open(mod mode.ComponentMode) error {
s.mu.RLock() s.mu.RLock()
defer s.mu.RUnlock() defer s.mu.RUnlock()
switch { switch {
case s.overrides.Open != nil: case s.overrides.Open != nil:
return s.overrides.Open(readOnly) return s.overrides.Open(mod)
case s.st != nil: case s.st != nil:
return s.st.Open(readOnly) return s.st.Open(mod)
default: 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, openFileMetabase: os.OpenFile,
openFilePilorama: 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 return teststore.ErrDiskExploded
})) }))
beforeReload := func() { 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) m.metrics.SetEstimateSize(m.shardID, m.path, writecache.StorageTypeFSTree.String(), fstree)
} }
func (m *writeCacheMetrics) SetMode(mode mode.Mode) { func (m *writeCacheMetrics) SetMode(mod mode.ComponentMode) {
m.metrics.SetMode(m.shardID, mode.String()) m.metrics.SetMode(m.shardID, mod.String())
} }
func (m *writeCacheMetrics) SetActualCounters(db, fstree uint64) { func (m *writeCacheMetrics) SetActualCounters(db, fstree uint64) {

View file

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

View file

@ -9,7 +9,7 @@ import (
type Metrics interface { type Metrics interface {
SetParentID(parentID string) SetParentID(parentID string)
SetMode(m mode.Mode) SetMode(m mode.ComponentMode)
Close() Close()
AddMethodDuration(method string, d time.Duration, success bool) AddMethodDuration(method string, d time.Duration, success bool)
@ -18,6 +18,6 @@ type Metrics interface {
type noopMetrics struct{} type noopMetrics struct{}
func (m *noopMetrics) SetParentID(string) {} func (m *noopMetrics) SetParentID(string) {}
func (m *noopMetrics) SetMode(mode.Mode) {} func (m *noopMetrics) SetMode(mode.ComponentMode) {}
func (m *noopMetrics) Close() {} func (m *noopMetrics) Close() {}
func (m *noopMetrics) AddMethodDuration(string, time.Duration, bool) {} 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.mode = m
db.metrics.SetMode(m) db.metrics.SetMode(mode.ConvertToComponentModeDegraded(m))
return nil return nil
} }

View file

@ -69,7 +69,7 @@ func (db *DB) SetShardID(id []byte, mode metamode.Mode) error {
err := db.writeShardID(id) err := db.writeShardID(id)
if err == nil { if err == nil {
db.metrics.SetMode(mode) db.metrics.SetMode(metamode.ConvertToComponentModeDegraded(mode))
} }
if cErr := db.close(); cErr != nil { 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/blobovnicza"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/blobovniczatree" "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" metrics_impl "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/metrics"
) )
@ -34,8 +35,8 @@ func (m *blobovniczaTreeMetrics) SetParentID(parentID string) {
m.shardID = parentID m.shardID = parentID
} }
func (m *blobovniczaTreeMetrics) SetMode(readOnly bool) { func (m *blobovniczaTreeMetrics) SetMode(mod mode.ComponentMode) {
m.m.SetBlobobvnizcaTreeMode(m.shardID, m.path, readOnly) m.m.SetBlobobvnizcaTreeMode(m.shardID, m.path, mod)
} }
func (m *blobovniczaTreeMetrics) Close() { func (m *blobovniczaTreeMetrics) Close() {

View file

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

View file

@ -26,7 +26,7 @@ func (m *metabaseMetrics) SetParentID(parentID string) {
m.shardID = parentID 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()) m.m.SetMode(m.shardID, m.path, mode.String())
} }

View file

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

View file

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

View file

@ -9,7 +9,7 @@ import (
type Metrics interface { type Metrics interface {
SetParentID(id string) SetParentID(id string)
SetMode(m mode.Mode) SetMode(m mode.ComponentMode)
Close() Close()
AddMethodDuration(method string, d time.Duration, success bool) AddMethodDuration(method string, d time.Duration, success bool)
@ -18,6 +18,6 @@ type Metrics interface {
type noopMetrics struct{} type noopMetrics struct{}
func (m *noopMetrics) SetParentID(string) {} func (m *noopMetrics) SetParentID(string) {}
func (m *noopMetrics) SetMode(mode.Mode) {} func (m *noopMetrics) SetMode(mode.ComponentMode) {}
func (m *noopMetrics) Close() {} func (m *noopMetrics) Close() {}
func (m *noopMetrics) AddMethodDuration(string, time.Duration, bool) {} 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) err = s.SetMode(mode.DegradedReadOnly)
if err != nil { 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 return nil
} }

View file

@ -8,27 +8,41 @@ type Mode uint32
const ( const (
// ReadWrite is a Mode value for shard that is available // ReadWrite is a Mode value for shard that is available
// for read and write operations. Default shard mode. // 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 // ReadOnly is a Mode value for shard that does not
// after a certain number of errors is encountered. It is the same as // accept write operation but is readable.
// `mode.Degraded` but also is read-only. ReadOnly Mode = 0b001
DegradedReadOnly = Degraded | ReadOnly
// 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. // Disabled mode is a mode where a shard is disabled.
// An existing shard can't have this mode, but it can be used in // An existing shard can't have this mode, but it can be used in
// the configuration or control service commands. // 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 ( // ComponentMode represents basic operation modes for shared components, including READ, READ_WRITE, and DISABLED.
// ReadOnly is a Mode value for shard that does not type ComponentMode uint32
// accept write operation but is readable.
ReadOnly Mode = 1 << iota
// Degraded is a Mode value for shard when the metabase is unavailable. const (
// It is hard to perform some modifying operations in this mode, thus it can only be set by an administrator. // ComponentReadWrite is a Mode value for component that is available
Degraded // 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 { 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. // NoMetabase returns true iff m is operating without the metabase.
func (m Mode) NoMetabase() bool { func (m Mode) NoMetabase() bool {
return m&Degraded != 0 return m&Degraded != 0
@ -58,6 +85,39 @@ func (m Mode) ReadOnly() bool {
return m&ReadOnly != 0 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 { func (m Mode) Disabled() bool {
return m == Disabled 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. // 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() c.modeMtx.Lock()
defer c.modeMtx.Unlock() defer c.modeMtx.Unlock()
c.mode = mode c.mode = mod
if mode.NoMetabase() { if mod.NoMetabase() {
return nil return nil
} }
err := c.openStore(mode.ReadOnly()) err := c.openStore(mode.ConvertToComponentModeDegraded(mod))
if err != nil { if err != nil {
return metaerr.Wrap(err) return metaerr.Wrap(err)
} }
@ -112,7 +112,7 @@ func (c *cache) Open(_ context.Context, mode mode.Mode) error {
// Init runs necessary services. // Init runs necessary services.
func (c *cache) Init() error { func (c *cache) Init() error {
c.metrics.SetMode(c.mode) c.metrics.SetMode(mode.ConvertToComponentModeDegraded(c.mode))
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
c.cancel = cancel c.cancel = cancel
c.runFlushLoop(ctx) 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 { if err := c.setMode(ctx, m, ignoreErrors); err != nil {
return err return err
} }
c.metrics.SetMode(m) c.metrics.SetMode(mode.ConvertToComponentModeDegraded(m))
} }
return nil return nil
} }

View file

@ -27,7 +27,7 @@ type Metrics interface {
Evict(st StorageType) Evict(st StorageType)
SetEstimateSize(db, fstree uint64) SetEstimateSize(db, fstree uint64)
SetMode(m mode.Mode) SetMode(m mode.ComponentMode)
SetActualCounters(db, fstree uint64) SetActualCounters(db, fstree uint64)
SetPath(path string) SetPath(path string)
Close() Close()
@ -49,7 +49,7 @@ func (metricsStub) Put(time.Duration, bool, StorageType) {}
func (metricsStub) SetEstimateSize(uint64, uint64) {} func (metricsStub) SetEstimateSize(uint64, uint64) {}
func (metricsStub) SetMode(mode.Mode) {} func (metricsStub) SetMode(mode.ComponentMode) {}
func (metricsStub) SetActualCounters(uint64, uint64) {} 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) err := c.setMode(ctx, m, true)
if err == nil { if err == nil {
c.metrics.SetMode(m) c.metrics.SetMode(mode.ConvertToComponentModeDegraded(m))
} }
return err return err
} }
@ -63,7 +63,7 @@ func (c *cache) setMode(ctx context.Context, m mode.Mode, ignoreErrors bool) err
return nil return nil
} }
if err = c.openStore(m.ReadOnly()); err != nil { if err = c.openStore(mode.ConvertToComponentModeDegraded(m)); err != nil {
return err return err
} }

View file

@ -22,7 +22,7 @@ func (c *cache) Seal(ctx context.Context, ignoreErrors bool) error {
// flush will be done by setMode // flush will be done by setMode
err := c.setMode(ctx, mode.DegradedReadOnly, ignoreErrors) err := c.setMode(ctx, mode.DegradedReadOnly, ignoreErrors)
if err == nil { if err == nil {
c.metrics.SetMode(mode.DegradedReadOnly) c.metrics.SetMode(mode.ComponentDisabled)
} }
return err 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/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/fstree" "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" 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-node/pkg/util"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
@ -25,13 +26,13 @@ type store struct {
const dbName = "small.bolt" 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) err := util.MkdirAllX(c.path, os.ModePerm)
if err != nil { if err != nil {
return err return err
} }
c.db, err = OpenDB(c.path, readOnly, c.openFile) c.db, err = OpenDB(c.path, mod.ReadOnly(), c.openFile)
if err != nil { if err != nil {
return fmt.Errorf("could not open database: %w", err) 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.MaxBatchSize = c.maxBatchSize
c.db.MaxBatchDelay = c.maxBatchDelay c.db.MaxBatchDelay = c.maxBatchDelay
if !readOnly { if !mod.ReadOnly() {
err = c.db.Update(func(tx *bbolt.Tx) error { err = c.db.Update(func(tx *bbolt.Tx) error {
_, err := tx.CreateBucketIfNotExists(defaultBucket) _, err := tx.CreateBucketIfNotExists(defaultBucket)
return err return err
@ -57,7 +58,7 @@ func (c *cache) openStore(readOnly bool) error {
fstree.WithNoSync(c.noSync), fstree.WithNoSync(c.noSync),
fstree.WithFileCounter(&c.objCounters), 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) return fmt.Errorf("could not open FSTree: %w", err)
} }
if err := c.fsTree.Init(); err != nil { if err := c.fsTree.Init(); err != nil {

View file

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

View file

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

View file

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