Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make metabase.ContainerSize actually read-only #1975

Merged
merged 3 commits into from
Oct 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Changelog for NeoFS Node
- Inability to provide session to NeoFS CLI in a NeoFS-binary format (#1933)
- `neofs-adm` now works correctly with a committee of more than 4 nodes (#1949, #1959)
- Closing a shard now waits until GC background workers stop (#1964)
- Make it possible to use `shard.ContainerSize` in read-only mode (#1975)

### Removed
### Updated
Expand Down
8 changes: 6 additions & 2 deletions pkg/local_object_storage/engine/container.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package engine

import (
"errors"

"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/shard"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
"go.uber.org/zap"
Expand Down Expand Up @@ -75,7 +77,7 @@ func (e *StorageEngine) containerSize(prm ContainerSizePrm) (res ContainerSizeRe
csPrm.SetContainerID(prm.cnr)

csRes, err := sh.Shard.ContainerSize(csPrm)
if err != nil {
if err != nil && !errors.Is(err, shard.ErrDegradedMode) {
e.reportShardError(sh, "can't get container size", err,
zap.Stringer("container_id", prm.cnr),
)
Expand Down Expand Up @@ -124,7 +126,9 @@ func (e *StorageEngine) listContainers() (ListContainersRes, error) {
e.iterateOverUnsortedShards(func(sh hashedShard) (stop bool) {
res, err := sh.Shard.ListContainers(shard.ListContainersPrm{})
if err != nil {
e.reportShardError(sh, "can't get list of containers", err)
if !errors.Is(err, shard.ErrDegradedMode) {
e.reportShardError(sh, "can't get list of containers", err)
}
return false
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/local_object_storage/engine/evacuate.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ mainLoop:
// because ListWithCursor works only with the metabase.
listRes, err := sh.ListWithCursor(listPrm)
if err != nil {
if errors.Is(err, meta.ErrEndOfListing) {
if errors.Is(err, meta.ErrEndOfListing) || errors.Is(err, shard.ErrDegradedMode) {
continue mainLoop
}
return res, err
Expand Down
6 changes: 5 additions & 1 deletion pkg/local_object_storage/engine/select.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package engine

import (
"errors"

"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/shard"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
"github.com/nspcc-dev/neofs-sdk-go/object"
Expand Down Expand Up @@ -109,7 +111,9 @@ func (e *StorageEngine) list(limit uint64) (SelectRes, error) {
e.iterateOverUnsortedShards(func(sh hashedShard) (stop bool) {
res, err := sh.List() // consider limit result of shard iterator
if err != nil {
e.reportShardError(sh, "could not select objects from shard", err)
if !errors.Is(err, shard.ErrDegradedMode) {
e.reportShardError(sh, "could not select objects from shard", err)
}
} else {
for _, addr := range res.AddressList() { // save only unique values
if _, ok := uniqueMap[addr.EncodeToString()]; !ok {
Expand Down
18 changes: 7 additions & 11 deletions pkg/local_object_storage/metabase/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ func (db *DB) Containers() (list []cid.ID, err error) {
db.modeMtx.RLock()
defer db.modeMtx.RUnlock()

if db.mode.NoMetabase() {
return nil, ErrDegradedMode
}

err = db.boltDB.View(func(tx *bbolt.Tx) error {
list, err = db.containers(tx)

Expand Down Expand Up @@ -38,7 +42,7 @@ func (db *DB) containers(tx *bbolt.Tx) ([]cid.ID, error) {
}

func (db *DB) ContainerSize(id cid.ID) (size uint64, err error) {
err = db.boltDB.Update(func(tx *bbolt.Tx) error {
err = db.boltDB.View(func(tx *bbolt.Tx) error {
size, err = db.containerSize(tx, id)

return err
Expand All @@ -48,11 +52,7 @@ func (db *DB) ContainerSize(id cid.ID) (size uint64, err error) {
}

func (db *DB) containerSize(tx *bbolt.Tx, id cid.ID) (uint64, error) {
containerVolume, err := tx.CreateBucketIfNotExists(containerVolumeBucketName)
if err != nil {
return 0, err
}

containerVolume := tx.Bucket(containerVolumeBucketName)
key := make([]byte, cidSize)
id.Encode(key)

Expand All @@ -78,11 +78,7 @@ func parseContainerSize(v []byte) uint64 {
}

func changeContainerSize(tx *bbolt.Tx, id cid.ID, delta uint64, increase bool) error {
containerVolume, err := tx.CreateBucketIfNotExists(containerVolumeBucketName)
if err != nil {
return err
}

containerVolume := tx.Bucket(containerVolumeBucketName)
key := make([]byte, cidSize)
id.Encode(key)

Expand Down
17 changes: 10 additions & 7 deletions pkg/local_object_storage/metabase/control.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ func (db *DB) init(reset bool) error {
string(toMoveItBucketName): {},
string(garbageBucketName): {},
string(shardInfoBucket): {},
string(bucketNameLocked): {},
}

return db.boltDB.Update(func(tx *bbolt.Tx) error {
Expand All @@ -106,16 +107,18 @@ func (db *DB) init(reset bool) error {
}
}
for k := range mStaticBuckets {
b, err := tx.CreateBucketIfNotExists([]byte(k))
if err != nil {
return fmt.Errorf("could not create static bucket %s: %w", k, err)
}

name := []byte(k)
if reset {
if err = resetBucket(b); err != nil {
return fmt.Errorf("could not reset static bucket %s: %w", k, err)
err := tx.DeleteBucket(name)
if err != nil && !errors.Is(err, bbolt.ErrBucketNotFound) {
return fmt.Errorf("could not delete static bucket %s: %w", k, err)
}
}

_, err := tx.CreateBucketIfNotExists(name)
if err != nil {
return fmt.Errorf("could not create static bucket %s: %w", k, err)
}
}

if !reset {
Expand Down
4 changes: 0 additions & 4 deletions pkg/local_object_storage/metabase/graveyard.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,6 @@ func (db *DB) iterateDeletedObj(tx *bbolt.Tx, h kvHandler, offset *oid.Address)
panic(fmt.Sprintf("metabase: unknown iteration object hadler: %T", t))
}

if bkt == nil {
return nil
}

c := bkt.Cursor()
var k, v []byte

Expand Down
4 changes: 4 additions & 0 deletions pkg/local_object_storage/metabase/inhume.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ func (db *DB) Inhume(prm InhumePrm) (res InhumeRes, err error) {
db.modeMtx.RLock()
defer db.modeMtx.RUnlock()

if db.mode.NoMetabase() {
return InhumeRes{}, ErrDegradedMode
}

currEpoch := db.epochState.CurrentEpoch()
var inhumed uint64

Expand Down
3 changes: 0 additions & 3 deletions pkg/local_object_storage/metabase/iterators.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,6 @@ func (db *DB) IterateCoveredByTombstones(tss map[string]oid.Address, h func(oid.

func (db *DB) iterateCoveredByTombstones(tx *bbolt.Tx, tss map[string]oid.Address, h func(oid.Address) error) error {
bktGraveyard := tx.Bucket(graveyardBucketName)
if bktGraveyard == nil {
return nil
}

err := bktGraveyard.ForEach(func(k, v []byte) error {
var addr oid.Address
Expand Down
5 changes: 1 addition & 4 deletions pkg/local_object_storage/metabase/lock.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,7 @@ func (db *DB) Lock(cnr cid.ID, locker oid.ID, locked []oid.ID) error {
return apistatus.LockNonRegularObject{}
}

bucketLocked, err := tx.CreateBucketIfNotExists(bucketNameLocked)
if err != nil {
return fmt.Errorf("create global bucket for locked objects: %w", err)
}
bucketLocked := tx.Bucket(bucketNameLocked)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe throw clear panic in this case instead of NPE?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is like this in many places and is not expected to happen.


cnr.Encode(key)
bucketLockedContainer, err := bucketLocked.CreateBucketIfNotExists(key)
Expand Down
14 changes: 1 addition & 13 deletions pkg/local_object_storage/metabase/movable.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,7 @@ func (db *DB) ToMoveIt(prm ToMoveItPrm) (res ToMoveItRes, err error) {
key = addressKey(prm.addr, key)

err = db.boltDB.Update(func(tx *bbolt.Tx) error {
toMoveIt, err := tx.CreateBucketIfNotExists(toMoveItBucketName)
if err != nil {
return err
}

toMoveIt := tx.Bucket(toMoveItBucketName)
return toMoveIt.Put(key, zeroValue)
})

Expand All @@ -77,10 +73,6 @@ func (db *DB) DoNotMove(prm DoNotMovePrm) (res DoNotMoveRes, err error) {

err = db.boltDB.Update(func(tx *bbolt.Tx) error {
toMoveIt := tx.Bucket(toMoveItBucketName)
if toMoveIt == nil {
return nil
}

return toMoveIt.Delete(key)
})

Expand All @@ -96,10 +88,6 @@ func (db *DB) Movable(_ MovablePrm) (MovableRes, error) {

err := db.boltDB.View(func(tx *bbolt.Tx) error {
toMoveIt := tx.Bucket(toMoveItBucketName)
if toMoveIt == nil {
return nil
}

return toMoveIt.ForEach(func(k, v []byte) error {
strAddrs = append(strAddrs, string(k))

Expand Down
11 changes: 0 additions & 11 deletions pkg/local_object_storage/metabase/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,17 +223,6 @@ func objectKey(obj oid.ID, key []byte) []byte {
return key[:objectKeySize]
}

// removes all bucket elements.
func resetBucket(b *bbolt.Bucket) error {
return b.ForEach(func(k, v []byte) error {
if v != nil {
return b.Delete(k)
}

return b.DeleteBucket(k)
})
}

// if meets irregular object container in objs - returns its type, otherwise returns object.TypeRegular.
//
// firstIrregularObjectType(tx, cnr, obj) usage allows getting object type.
Expand Down
7 changes: 7 additions & 0 deletions pkg/local_object_storage/shard/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ func (r ContainerSizeRes) Size() uint64 {
}

func (s *Shard) ContainerSize(prm ContainerSizePrm) (ContainerSizeRes, error) {
s.m.RLock()
defer s.m.RUnlock()

if s.info.Mode.NoMetabase() {
return ContainerSizeRes{}, ErrDegradedMode
}

size, err := s.metaBase.ContainerSize(prm.cnr)
if err != nil {
return ContainerSizeRes{}, fmt.Errorf("could not get container size: %w", err)
Expand Down
21 changes: 21 additions & 0 deletions pkg/local_object_storage/shard/gc.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,11 @@ func (s *Shard) collectExpiredTombstones(ctx context.Context, e Event) {
for {
log.Debug("iterating tombstones")

if s.GetMode().NoMetabase() {
s.log.Debug("shard is in a degraded mode, skip collecting expired tombstones")
return
}

err := s.metaBase.IterateOverGraveyard(iterPrm)
if err != nil {
log.Error("iterator over graveyard failed", zap.Error(err))
Expand Down Expand Up @@ -327,6 +332,10 @@ func (s *Shard) collectExpiredLocks(ctx context.Context, e Event) {
}

func (s *Shard) getExpiredObjects(ctx context.Context, epoch uint64, typeCond func(object.Type) bool) ([]oid.Address, error) {
if s.GetMode().NoMetabase() {
return nil, ErrDegradedMode
}

var expired []oid.Address

err := s.metaBase.IterateExpired(epoch, func(expiredObject *meta.ExpiredObject) error {
Expand All @@ -351,6 +360,10 @@ func (s *Shard) getExpiredObjects(ctx context.Context, epoch uint64, typeCond fu
//
// Does not modify tss.
func (s *Shard) HandleExpiredTombstones(tss []meta.TombstonedObject) {
if s.GetMode().NoMetabase() {
return
}

// Mark tombstones as garbage.
var pInhume meta.InhumePrm

Expand Down Expand Up @@ -385,6 +398,10 @@ func (s *Shard) HandleExpiredTombstones(tss []meta.TombstonedObject) {
// HandleExpiredLocks unlocks all objects which were locked by lockers.
// If successful, marks lockers themselves as garbage.
func (s *Shard) HandleExpiredLocks(lockers []oid.Address) {
if s.GetMode().NoMetabase() {
return
}

err := s.metaBase.FreeLockedBy(lockers)
if err != nil {
s.log.Warn("failure to unlock objects",
Expand Down Expand Up @@ -412,6 +429,10 @@ func (s *Shard) HandleExpiredLocks(lockers []oid.Address) {

// HandleDeletedLocks unlocks all objects which were locked by lockers.
func (s *Shard) HandleDeletedLocks(lockers []oid.Address) {
if s.GetMode().NoMetabase() {
return
}

err := s.metaBase.FreeLockedBy(lockers)
if err != nil {
s.log.Warn("failure to unlock objects",
Expand Down
8 changes: 8 additions & 0 deletions pkg/local_object_storage/shard/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ func (r ListWithCursorRes) Cursor() *Cursor {

// List returns all objects physically stored in the Shard.
func (s *Shard) List() (res SelectRes, err error) {
if s.GetMode().NoMetabase() {
return SelectRes{}, ErrDegradedMode
}

lst, err := s.metaBase.Containers()
if err != nil {
return res, fmt.Errorf("can't list stored containers: %w", err)
Expand Down Expand Up @@ -93,6 +97,10 @@ func (s *Shard) List() (res SelectRes, err error) {
}

func (s *Shard) ListContainers(_ ListContainersPrm) (ListContainersRes, error) {
if s.GetMode().NoMetabase() {
return ListContainersRes{}, ErrDegradedMode
}

containers, err := s.metaBase.Containers()
if err != nil {
return ListContainersRes{}, fmt.Errorf("could not get list of containers: %w", err)
Expand Down