node: Set mode to shard's components when open it #967
25 changed files with 219 additions and 74 deletions
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
common "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-lens/internal"
|
||||
meta "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/metabase"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
|
||||
"github.com/spf13/cobra"
|
||||
"go.etcd.io/bbolt"
|
||||
)
|
||||
|
@ -43,7 +44,7 @@ func openMeta(cmd *cobra.Command) *meta.DB {
|
|||
}),
|
||||
meta.WithEpochState(epochState{}),
|
||||
)
|
||||
common.ExitOnErr(cmd, common.Errf("could not open metabase: %w", db.Open(cmd.Context(), true)))
|
||||
common.ExitOnErr(cmd, common.Errf("could not open metabase: %w", db.Open(cmd.Context(), mode.ReadOnly)))
|
||||
|
||||
return db
|
||||
}
|
||||
|
|
|
@ -11,6 +11,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"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/teststore"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
|
||||
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -51,7 +52,7 @@ func TestCompression(t *testing.T) {
|
|||
bs := New(
|
||||
WithCompressObjects(compress),
|
||||
WithStorages(defaultStorages(dir, smallSizeLimit)))
|
||||
require.NoError(t, bs.Open(context.Background(), false))
|
||||
require.NoError(t, bs.Open(context.Background(), mode.ReadWrite))
|
||||
require.NoError(t, bs.Init())
|
||||
return bs
|
||||
}
|
||||
|
@ -126,7 +127,7 @@ func TestBlobstor_needsCompression(t *testing.T) {
|
|||
Storage: fstree.New(fstree.WithPath(dir)),
|
||||
},
|
||||
}))
|
||||
require.NoError(t, bs.Open(context.Background(), false))
|
||||
require.NoError(t, bs.Open(context.Background(), mode.ReadWrite))
|
||||
require.NoError(t, bs.Init())
|
||||
return bs
|
||||
}
|
||||
|
@ -188,7 +189,7 @@ func TestConcurrentPut(t *testing.T) {
|
|||
|
||||
blobStor := New(
|
||||
WithStorages(defaultStorages(dir, smallSizeLimit)))
|
||||
require.NoError(t, blobStor.Open(context.Background(), false))
|
||||
require.NoError(t, blobStor.Open(context.Background(), mode.ReadWrite))
|
||||
require.NoError(t, blobStor.Init())
|
||||
|
||||
testGet := func(t *testing.T, b *BlobStor, obj *objectSDK.Object) {
|
||||
|
@ -268,7 +269,7 @@ func TestConcurrentDelete(t *testing.T) {
|
|||
|
||||
blobStor := New(
|
||||
WithStorages(defaultStorages(dir, smallSizeLimit)))
|
||||
require.NoError(t, blobStor.Open(context.Background(), false))
|
||||
require.NoError(t, blobStor.Open(context.Background(), mode.ReadWrite))
|
||||
require.NoError(t, blobStor.Init())
|
||||
|
||||
|
||||
testPut := func(t *testing.T, b *BlobStor, obj *objectSDK.Object) {
|
||||
|
|
|
@ -6,13 +6,29 @@ import (
|
|||
"fmt"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// Open opens BlobStor.
|
||||
func (b *BlobStor) Open(ctx context.Context, readOnly bool) error {
|
||||
func (b *BlobStor) Open(ctx context.Context, mode mode.Mode) error {
|
||||
b.log.Debug(logs.BlobstorOpening)
|
||||
|
||||
b.modeMtx.Lock()
|
||||
defer b.modeMtx.Unlock()
|
||||
b.mode = mode
|
||||
|
||||
err := b.openBlobStor(ctx, mode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.metrics.SetMode(mode.ReadOnly())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BlobStor) openBlobStor(ctx context.Context, mode mode.Mode) error {
|
||||
readOnly := mode.ReadOnly()
|
||||
for i := range b.storage {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
|
@ -24,7 +40,6 @@ func (b *BlobStor) Open(ctx context.Context, readOnly bool) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
b.metrics.SetMode(readOnly)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -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/blobstor/teststore"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
|
||||
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
|
||||
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
|
||||
|
@ -20,7 +21,7 @@ func TestExists(t *testing.T) {
|
|||
|
||||
b := New(WithStorages(storages))
|
||||
|
||||
require.NoError(t, b.Open(context.Background(), false))
|
||||
require.NoError(t, b.Open(context.Background(), mode.ReadWrite))
|
||||
require.NoError(t, b.Init())
|
||||
|
||||
objects := []*objectSDK.Object{
|
||||
|
|
|
@ -7,6 +7,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"
|
||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -26,7 +27,7 @@ func TestIterateObjects(t *testing.T) {
|
|||
defer os.RemoveAll(p)
|
||||
|
||||
// open Blobstor
|
||||
require.NoError(t, blobStor.Open(context.Background(), false))
|
||||
require.NoError(t, blobStor.Open(context.Background(), mode.ReadWrite))
|
||||
|
||||
// initialize Blobstor
|
||||
require.NoError(t, blobStor.Init())
|
||||
|
|
|
@ -22,7 +22,7 @@ func (b *BlobStor) SetMode(m mode.Mode) error {
|
|||
|
||||
err := b.Close()
|
||||
if err == nil {
|
||||
if err = b.Open(context.TODO(), m.ReadOnly()); err == nil {
|
||||
if err = b.openBlobStor(context.TODO(), m); err == nil {
|
||||
err = b.Init()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
|
||||
// Component represents single storage component.
|
||||
type Component interface {
|
||||
Open(context.Context, bool) error
|
||||
Open(context.Context, mode.Mode) error
|
||||
SetMode(mode.Mode) error
|
||||
Init() error
|
||||
Close() error
|
||||
|
@ -58,18 +58,18 @@ func TestCloseAfterOpen(t *testing.T, cons Constructor) {
|
|||
t.Run("RW", func(t *testing.T) {
|
||||
// Use-case: irrecoverable error on some components, close everything.
|
||||
s := cons(t)
|
||||
require.NoError(t, s.Open(context.Background(), false))
|
||||
require.NoError(t, s.Open(context.Background(), mode.ReadWrite))
|
||||
require.NoError(t, s.Close())
|
||||
})
|
||||
t.Run("RO", func(t *testing.T) {
|
||||
// Use-case: irrecoverable error on some components, close everything.
|
||||
// Open in read-only must be done after the db is here.
|
||||
s := cons(t)
|
||||
require.NoError(t, s.Open(context.Background(), false))
|
||||
require.NoError(t, s.Open(context.Background(), mode.ReadWrite))
|
||||
require.NoError(t, s.Init())
|
||||
require.NoError(t, s.Close())
|
||||
|
||||
require.NoError(t, s.Open(context.Background(), true))
|
||||
require.NoError(t, s.Open(context.Background(), mode.ReadOnly))
|
||||
require.NoError(t, s.Close())
|
||||
})
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ func TestCloseAfterOpen(t *testing.T, cons Constructor) {
|
|||
func TestCloseTwice(t *testing.T, cons Constructor) {
|
||||
// Use-case: move to maintenance mode twice, first time failed.
|
||||
s := cons(t)
|
||||
require.NoError(t, s.Open(context.Background(), false))
|
||||
require.NoError(t, s.Open(context.Background(), mode.ReadWrite))
|
||||
require.NoError(t, s.Init())
|
||||
require.NoError(t, s.Close())
|
||||
require.NoError(t, s.Close()) // already closed, no-op
|
||||
|
@ -90,12 +90,12 @@ func TestSetMode(t *testing.T, cons Constructor, m mode.Mode) {
|
|||
// Use-case: metabase `Init` failed,
|
||||
// call `SetMode` on all not-yet-initialized components.
|
||||
s := cons(t)
|
||||
require.NoError(t, s.Open(context.Background(), false))
|
||||
require.NoError(t, s.Open(context.Background(), mode.ReadWrite))
|
||||
require.NoError(t, s.SetMode(m))
|
||||
|
||||
t.Run("after open in RO", func(t *testing.T) {
|
||||
require.NoError(t, s.Close())
|
||||
require.NoError(t, s.Open(context.Background(), true))
|
||||
require.NoError(t, s.Open(context.Background(), mode.ReadOnly))
|
||||
require.NoError(t, s.SetMode(m))
|
||||
})
|
||||
|
||||
|
@ -104,7 +104,7 @@ func TestSetMode(t *testing.T, cons Constructor, m mode.Mode) {
|
|||
t.Run("after init", func(t *testing.T) {
|
||||
s := cons(t)
|
||||
// Use-case: notmal node operation.
|
||||
require.NoError(t, s.Open(context.Background(), false))
|
||||
require.NoError(t, s.Open(context.Background(), mode.ReadWrite))
|
||||
require.NoError(t, s.Init())
|
||||
require.NoError(t, s.SetMode(m))
|
||||
require.NoError(t, s.Close())
|
||||
|
@ -114,7 +114,7 @@ func TestSetMode(t *testing.T, cons Constructor, m mode.Mode) {
|
|||
func TestModeTransition(t *testing.T, cons Constructor, from, to mode.Mode) {
|
||||
// Use-case: normal node operation.
|
||||
s := cons(t)
|
||||
require.NoError(t, s.Open(context.Background(), false))
|
||||
require.NoError(t, s.Open(context.Background(), mode.ReadWrite))
|
||||
require.NoError(t, s.Init())
|
||||
require.NoError(t, s.SetMode(from))
|
||||
require.NoError(t, s.SetMode(to))
|
||||
|
|
|
@ -22,7 +22,18 @@ var ErrDegradedMode = logicerr.New("metabase is in a degraded mode")
|
|||
var ErrReadOnlyMode = logicerr.New("metabase is in a read-only mode")
|
||||
|
||||
// Open boltDB instance for metabase.
|
||||
func (db *DB) Open(_ context.Context, readOnly bool) error {
|
||||
func (db *DB) Open(_ context.Context, mode mode.Mode) error {
|
||||
db.modeMtx.Lock()
|
||||
defer db.modeMtx.Unlock()
|
||||
db.mode = mode
|
||||
|
||||
if mode.NoMetabase() {
|
||||
return nil
|
||||
}
|
||||
return db.openDB(mode)
|
||||
}
|
||||
|
||||
func (db *DB) openDB(mode mode.Mode) error {
|
||||
err := util.MkdirAllX(filepath.Dir(db.info.Path), db.info.Permission)
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't create dir %s for metabase: %w", db.info.Path, err)
|
||||
|
@ -34,7 +45,7 @@ func (db *DB) Open(_ context.Context, readOnly bool) error {
|
|||
opts := *bbolt.DefaultOptions
|
||||
db.boltOptions = &opts
|
||||
}
|
||||
db.boltOptions.ReadOnly = readOnly
|
||||
db.boltOptions.ReadOnly = mode.ReadOnly()
|
||||
|
||||
return metaerr.Wrap(db.openBolt())
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/internal/testutil"
|
||||
meta "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/metabase"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||
|
@ -49,7 +50,7 @@ func newDB(t testing.TB, opts ...meta.Option) *meta.DB {
|
|||
}, opts...)...,
|
||||
)
|
||||
|
||||
require.NoError(t, bdb.Open(context.Background(), false))
|
||||
require.NoError(t, bdb.Open(context.Background(), mode.ReadWrite))
|
||||
require.NoError(t, bdb.Init())
|
||||
|
||||
return bdb
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package meta
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
|
||||
|
@ -23,22 +22,17 @@ func (db *DB) SetMode(m mode.Mode) error {
|
|||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
switch {
|
||||
case m.NoMetabase():
|
||||
if m.NoMetabase() {
|
||||
db.boltDB = nil
|
||||
case m.ReadOnly():
|
||||
err = db.Open(context.TODO(), true)
|
||||
default:
|
||||
err = db.Open(context.TODO(), false)
|
||||
}
|
||||
if err == nil && !m.NoMetabase() && !m.ReadOnly() {
|
||||
} else {
|
||||
err := db.openDB(m)
|
||||
if err == nil && !m.ReadOnly() {
|
||||
err = db.Init()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't set metabase mode (old=%s, new=%s): %w", db.mode, m, err)
|
||||
}
|
||||
}
|
||||
|
||||
db.mode = m
|
||||
db.metrics.SetMode(m)
|
||||
|
|
37
pkg/local_object_storage/metabase/mode_test.go
Normal file
37
pkg/local_object_storage/metabase/mode_test.go
Normal file
|
@ -0,0 +1,37 @@
|
|||
package meta
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type epochStateTest struct{}
|
||||
|
||||
func (s epochStateTest) CurrentEpoch() uint64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func Test_Mode(t *testing.T) {
|
||||
t.Parallel()
|
||||
bdb := New([]Option{
|
||||
WithPath(filepath.Join(t.TempDir(), "metabase")),
|
||||
WithPermissions(0o600),
|
||||
WithEpochState(epochStateTest{}),
|
||||
}...)
|
||||
|
||||
require.NoError(t, bdb.Open(context.Background(), mode.DegradedReadOnly))
|
||||
require.Nil(t, bdb.boltDB)
|
||||
require.NoError(t, bdb.Init())
|
||||
require.Nil(t, bdb.boltDB)
|
||||
require.NoError(t, bdb.Close())
|
||||
|
||||
require.NoError(t, bdb.Open(context.Background(), mode.Degraded))
|
||||
require.Nil(t, bdb.boltDB)
|
||||
require.NoError(t, bdb.Init())
|
||||
require.Nil(t, bdb.boltDB)
|
||||
require.NoError(t, bdb.Close())
|
||||
}
|
|
@ -8,6 +8,7 @@ import (
|
|||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.etcd.io/bbolt"
|
||||
)
|
||||
|
@ -43,13 +44,13 @@ func TestVersion(t *testing.T) {
|
|||
}
|
||||
t.Run("simple", func(t *testing.T) {
|
||||
db := newDB(t)
|
||||
require.NoError(t, db.Open(context.Background(), false))
|
||||
require.NoError(t, db.Open(context.Background(), mode.ReadWrite))
|
||||
require.NoError(t, db.Init())
|
||||
check(t, db)
|
||||
require.NoError(t, db.Close())
|
||||
|
||||
t.Run("reopen", func(t *testing.T) {
|
||||
require.NoError(t, db.Open(context.Background(), false))
|
||||
require.NoError(t, db.Open(context.Background(), mode.ReadWrite))
|
||||
require.NoError(t, db.Init())
|
||||
check(t, db)
|
||||
require.NoError(t, db.Close())
|
||||
|
@ -57,29 +58,29 @@ func TestVersion(t *testing.T) {
|
|||
})
|
||||
t.Run("old data", func(t *testing.T) {
|
||||
db := newDB(t)
|
||||
require.NoError(t, db.Open(context.Background(), false))
|
||||
require.NoError(t, db.Open(context.Background(), mode.ReadWrite))
|
||||
require.NoError(t, db.WriteShardID([]byte{1, 2, 3, 4}))
|
||||
require.NoError(t, db.Close())
|
||||
|
||||
require.NoError(t, db.Open(context.Background(), false))
|
||||
require.NoError(t, db.Open(context.Background(), mode.ReadWrite))
|
||||
require.NoError(t, db.Init())
|
||||
check(t, db)
|
||||
require.NoError(t, db.Close())
|
||||
})
|
||||
t.Run("invalid version", func(t *testing.T) {
|
||||
db := newDB(t)
|
||||
require.NoError(t, db.Open(context.Background(), false))
|
||||
require.NoError(t, db.Open(context.Background(), mode.ReadWrite))
|
||||
require.NoError(t, db.boltDB.Update(func(tx *bbolt.Tx) error {
|
||||
return updateVersion(tx, version+1)
|
||||
}))
|
||||
require.NoError(t, db.Close())
|
||||
|
||||
require.NoError(t, db.Open(context.Background(), false))
|
||||
require.NoError(t, db.Open(context.Background(), mode.ReadWrite))
|
||||
require.Error(t, db.Init())
|
||||
require.NoError(t, db.Close())
|
||||
|
||||
t.Run("reset", func(t *testing.T) {
|
||||
require.NoError(t, db.Open(context.Background(), false))
|
||||
require.NoError(t, db.Open(context.Background(), mode.ReadWrite))
|
||||
require.NoError(t, db.Reset())
|
||||
check(t, db)
|
||||
require.NoError(t, db.Close())
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"sync/atomic"
|
||||
"testing"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
|
||||
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -26,7 +27,7 @@ func BenchmarkCreate(b *testing.B) {
|
|||
f := NewBoltForest(
|
||||
WithPath(filepath.Join(tmpDir, "test.db")),
|
||||
WithMaxBatchSize(runtime.GOMAXPROCS(0)))
|
||||
require.NoError(b, f.Open(context.Background(), false))
|
||||
require.NoError(b, f.Open(context.Background(), mode.ReadWrite))
|
||||
require.NoError(b, f.Init())
|
||||
defer func() { require.NoError(b, f.Close()) }()
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ func (t *boltForest) SetMode(m mode.Mode) error {
|
|||
|
||||
err := t.Close()
|
||||
if err == nil && !m.NoMetabase() {
|
||||
if err = t.Open(context.TODO(), m.ReadOnly()); err == nil {
|
||||
if err = t.openBolt(m); err == nil {
|
||||
err = t.Init()
|
||||
}
|
||||
}
|
||||
|
@ -112,7 +112,18 @@ func (t *boltForest) SetMode(m mode.Mode) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (t *boltForest) Open(_ context.Context, readOnly bool) error {
|
||||
func (t *boltForest) Open(_ context.Context, mode mode.Mode) error {
|
||||
t.modeMtx.Lock()
|
||||
defer t.modeMtx.Unlock()
|
||||
t.mode = mode
|
||||
if mode.NoMetabase() {
|
||||
return nil
|
||||
}
|
||||
return t.openBolt(mode)
|
||||
}
|
||||
|
||||
func (t *boltForest) openBolt(mode mode.Mode) error {
|
||||
readOnly := mode.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))
|
||||
|
@ -131,11 +142,7 @@ func (t *boltForest) Open(_ context.Context, readOnly bool) error {
|
|||
|
||||
t.db.MaxBatchSize = t.maxBatchSize
|
||||
t.db.MaxBatchDelay = t.maxBatchDelay
|
||||
m := mode.ReadWrite
|
||||
if readOnly {
|
||||
m = mode.ReadOnly
|
||||
}
|
||||
t.metrics.SetMode(m)
|
||||
t.metrics.SetMode(mode)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ func (f *memoryForest) Init() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (f *memoryForest) Open(context.Context, bool) error {
|
||||
func (f *memoryForest) Open(context.Context, mode.Mode) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
|
||||
cidSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
|
||||
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||
|
@ -24,7 +25,7 @@ var providers = []struct {
|
|||
}{
|
||||
{"inmemory", func(t testing.TB, _ ...Option) ForestStorage {
|
||||
f := NewMemoryForest()
|
||||
require.NoError(t, f.Open(context.Background(), false))
|
||||
require.NoError(t, f.Open(context.Background(), mode.ReadWrite))
|
||||
require.NoError(t, f.Init())
|
||||
return f
|
||||
}},
|
||||
|
@ -34,7 +35,7 @@ var providers = []struct {
|
|||
WithPath(filepath.Join(t.TempDir(), "test.db")),
|
||||
WithMaxBatchSize(1),
|
||||
}, opts...)...)
|
||||
require.NoError(t, f.Open(context.Background(), false))
|
||||
require.NoError(t, f.Open(context.Background(), mode.ReadWrite))
|
||||
require.NoError(t, f.Init())
|
||||
return f
|
||||
}},
|
||||
|
|
|
@ -58,7 +58,7 @@ type ForestStorage interface {
|
|||
// DumpInfo returns information about the pilorama.
|
||||
DumpInfo() Info
|
||||
Init() error
|
||||
Open(context.Context, bool) error
|
||||
Open(context.Context, mode.Mode) error
|
||||
Close() error
|
||||
SetMode(m mode.Mode) error
|
||||
SetParentID(id string)
|
||||
|
|
31
pkg/local_object_storage/pilorama/mode_test.go
Normal file
31
pkg/local_object_storage/pilorama/mode_test.go
Normal file
|
@ -0,0 +1,31 @@
|
|||
package pilorama
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_Mode(t *testing.T) {
|
||||
t.Parallel()
|
||||
f := NewBoltForest(
|
||||
[]Option{
|
||||
WithPath(filepath.Join(t.TempDir(), "test.db")),
|
||||
WithMaxBatchSize(1),
|
||||
}...)
|
||||
|
||||
require.NoError(t, f.Open(context.Background(), mode.DegradedReadOnly))
|
||||
require.Nil(t, f.(*boltForest).db)
|
||||
require.NoError(t, f.Init())
|
||||
require.Nil(t, f.(*boltForest).db)
|
||||
require.NoError(t, f.Close())
|
||||
|
||||
require.NoError(t, f.Open(context.Background(), mode.Degraded))
|
||||
require.Nil(t, f.(*boltForest).db)
|
||||
require.NoError(t, f.Init())
|
||||
require.Nil(t, f.(*boltForest).db)
|
||||
require.NoError(t, f.Close())
|
||||
}
|
|
@ -43,12 +43,17 @@ func (s *Shard) handleMetabaseFailure(stage string, err error) error {
|
|||
// Open opens all Shard's components.
|
||||
func (s *Shard) Open(ctx context.Context) error {
|
||||
components := []interface {
|
||||
Open(context.Context, bool) error
|
||||
Open(context.Context, mode.Mode) error
|
||||
}{
|
||||
s.blobStor, s.metaBase,
|
||||
s.blobStor,
|
||||
}
|
||||
m := s.GetMode()
|
||||
|
||||
if !m.NoMetabase() {
|
||||
components = append(components, s.metaBase)
|
||||
}
|
||||
|
||||
if s.hasWriteCache() {
|
||||
if s.hasWriteCache() && !m.NoMetabase() {
|
||||
components = append(components, s.writeCache)
|
||||
}
|
||||
|
||||
|
@ -57,12 +62,12 @@ func (s *Shard) Open(ctx context.Context) error {
|
|||
}
|
||||
|
||||
for i, component := range components {
|
||||
if err := component.Open(ctx, false); err != nil {
|
||||
if err := component.Open(ctx, m); err != nil {
|
||||
if component == s.metaBase {
|
||||
// We must first open all other components to avoid
|
||||
// opening non-existent DB in read-only mode.
|
||||
for j := i + 1; j < len(components); j++ {
|
||||
if err := components[j].Open(ctx, false); err != nil {
|
||||
if err := components[j].Open(ctx, m); err != nil {
|
||||
// Other components must be opened, fail.
|
||||
return fmt.Errorf("could not open %T: %w", components[j], err)
|
||||
}
|
||||
|
@ -97,8 +102,9 @@ func (s *Shard) Init(ctx context.Context) error {
|
|||
}
|
||||
|
||||
var components []initializer
|
||||
m := s.GetMode()
|
||||
|
||||
if !s.GetMode().NoMetabase() {
|
||||
if !m.NoMetabase() {
|
||||
var initMetabase initializer
|
||||
|
||||
if s.NeedRefillMetabase() {
|
||||
|
@ -114,7 +120,7 @@ func (s *Shard) Init(ctx context.Context) error {
|
|||
components = []initializer{s.blobStor}
|
||||
}
|
||||
|
||||
if s.hasWriteCache() {
|
||||
if s.hasWriteCache() && !m.NoMetabase() {
|
||||
components = append(components, s.writeCache)
|
||||
}
|
||||
|
||||
|
|
|
@ -31,12 +31,11 @@ func (s *Shard) ID() *ID {
|
|||
|
||||
// UpdateID reads shard ID saved in the metabase and updates it if it is missing.
|
||||
func (s *Shard) UpdateID(ctx context.Context) (err error) {
|
||||
var metabaseOpened bool
|
||||
var idFromMetabase []byte
|
||||
if err = s.metaBase.Open(ctx, false); err != nil {
|
||||
metabaseOpened := !s.GetMode().NoMetabase()
|
||||
if err = s.metaBase.Open(ctx, s.GetMode()); err != nil {
|
||||
err = fmt.Errorf("failed to open metabase: %w", err)
|
||||
fyrchik
commented
No when the mode is provided to Open(), do we still need this if? It seems metabase knows to do nothing in Degraded mode. No when the mode is provided to Open(), do we still need this if? It seems metabase knows to do nothing in Degraded mode.
acid-ant
commented
Thanks, simplified this part. Thanks, simplified this part.
|
||||
} else {
|
||||
metabaseOpened = true
|
||||
metabaseOpened = false
|
||||
}
|
||||
if metabaseOpened {
|
||||
defer func() {
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/teststore"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/internal/testutil"
|
||||
meta "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/metabase"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/writecache"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -75,7 +76,7 @@ func benchmarkPutPar(b *testing.B, cache writecache.Cache, size uint64) {
|
|||
}
|
||||
|
||||
func benchmarkPutPrepare(b *testing.B, cache writecache.Cache) {
|
||||
require.NoError(b, cache.Open(context.Background(), false), "opening")
|
||||
require.NoError(b, cache.Open(context.Background(), mode.ReadWrite), "opening")
|
||||
require.NoError(b, cache.Init(), "initializing")
|
||||
}
|
||||
|
||||
|
|
|
@ -95,8 +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, readOnly bool) error {
|
||||
err := c.openStore(readOnly)
|
||||
func (c *cache) Open(_ context.Context, mode mode.Mode) error {
|
||||
c.modeMtx.Lock()
|
||||
defer c.modeMtx.Unlock()
|
||||
c.mode = mode
|
||||
if mode.NoMetabase() {
|
||||
return nil
|
||||
}
|
||||
err := c.openStore(mode.ReadOnly())
|
||||
if err != nil {
|
||||
return metaerr.Wrap(err)
|
||||
}
|
||||
|
|
|
@ -202,7 +202,7 @@ func newCache[Option any](
|
|||
mb := meta.New(
|
||||
meta.WithPath(filepath.Join(dir, "meta")),
|
||||
meta.WithEpochState(dummyEpoch{}))
|
||||
require.NoError(t, mb.Open(context.Background(), false))
|
||||
require.NoError(t, mb.Open(context.Background(), mode.ReadWrite))
|
||||
require.NoError(t, mb.Init())
|
||||
|
||||
bs := blobstor.New(blobstor.WithStorages([]blobstor.SubStorage{
|
||||
|
@ -213,11 +213,11 @@ func newCache[Option any](
|
|||
fstree.WithDirNameLen(1)),
|
||||
},
|
||||
}))
|
||||
require.NoError(t, bs.Open(context.Background(), false))
|
||||
require.NoError(t, bs.Open(context.Background(), mode.ReadWrite))
|
||||
require.NoError(t, bs.Init())
|
||||
|
||||
wc := createCacheFn(t, smallSize, mb, bs, opts...)
|
||||
require.NoError(t, wc.Open(context.Background(), false))
|
||||
require.NoError(t, wc.Open(context.Background(), mode.ReadWrite))
|
||||
require.NoError(t, wc.Init())
|
||||
|
||||
// First set mode for metabase and blobstor to prevent background flushes.
|
||||
|
|
30
pkg/local_object_storage/writecache/mode_test.go
Normal file
30
pkg/local_object_storage/writecache/mode_test.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
package writecache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
func TestMode(t *testing.T) {
|
||||
t.Parallel()
|
||||
wc := New(
|
||||
WithLogger(test.NewLogger(t)),
|
||||
WithFlushWorkersCount(2),
|
||||
WithPath(t.TempDir()))
|
||||
|
||||
require.NoError(t, wc.Open(context.Background(), mode.DegradedReadOnly))
|
||||
require.Nil(t, wc.(*cache).db)
|
||||
require.NoError(t, wc.Init())
|
||||
require.Nil(t, wc.(*cache).db)
|
||||
require.NoError(t, wc.Close())
|
||||
|
||||
require.NoError(t, wc.Open(context.Background(), mode.Degraded))
|
||||
require.Nil(t, wc.(*cache).db)
|
||||
require.NoError(t, wc.Init())
|
||||
require.Nil(t, wc.(*cache).db)
|
||||
require.NoError(t, wc.Close())
|
||||
}
|
|
@ -39,7 +39,7 @@ type Cache interface {
|
|||
Seal(context.Context, bool) error
|
||||
|
||||
Init() error
|
||||
Open(ctx context.Context, readOnly bool) error
|
||||
Open(ctx context.Context, mode mode.Mode) error
|
||||
Close() error
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue
It is necessary to put this in
New()
? It doesn't accepts such things by design, becausethey are provided in
Open
(wherero bool
parameter can be replaced withm mode.Mode
I guess)No, it is not necessary. But in this case, we need to store
mode
insideOpen
, except whenOpen
executed fromSetMode
.Updated, now
mode
propagated viaOpen
.