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

Feat/add meta indexes inspection to lens #2882

Merged
merged 5 commits into from
Jul 3, 2024
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 @@ -4,6 +4,7 @@ Changelog for NeoFS Node
## [Unreleased]

### Added
- Indexes inspection command to neofs-lens (#2882)

### Fixed
- Control service's Drop call does not clean metabase (#2822)
Expand Down
1 change: 1 addition & 0 deletions cmd/neofs-lens/internal/meta/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
listGarbageCMD,
writeObjectCMD,
getCMD,
statCMD,

Check warning on line 38 in cmd/neofs-lens/internal/meta/root.go

View check run for this annotation

Codecov / codecov/patch

cmd/neofs-lens/internal/meta/root.go#L38

Added line #L38 was not covered by tests
)
}

Expand Down
55 changes: 55 additions & 0 deletions cmd/neofs-lens/internal/meta/status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package meta

import (
"fmt"

common "github.com/nspcc-dev/neofs-node/cmd/neofs-lens/internal"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/spf13/cobra"
)

var statCMD = &cobra.Command{
Use: "status",
Short: "Object status information",
Long: `Get metabase's indexes related to an object.`,
Args: cobra.NoArgs,
Run: statusFunc,
}

func init() {
common.AddAddressFlag(statCMD, &vAddress)
common.AddComponentPathFlag(statCMD, &vPath)

Check warning on line 21 in cmd/neofs-lens/internal/meta/status.go

View check run for this annotation

Codecov / codecov/patch

cmd/neofs-lens/internal/meta/status.go#L19-L21

Added lines #L19 - L21 were not covered by tests
}

func statusFunc(cmd *cobra.Command, _ []string) {
var addr oid.Address

Check warning on line 25 in cmd/neofs-lens/internal/meta/status.go

View check run for this annotation

Codecov / codecov/patch

cmd/neofs-lens/internal/meta/status.go#L24-L25

Added lines #L24 - L25 were not covered by tests

err := addr.DecodeString(vAddress)
common.ExitOnErr(cmd, common.Errf("invalid address argument: %w", err))

Check warning on line 28 in cmd/neofs-lens/internal/meta/status.go

View check run for this annotation

Codecov / codecov/patch

cmd/neofs-lens/internal/meta/status.go#L27-L28

Added lines #L27 - L28 were not covered by tests

db := openMeta(cmd, true)
defer db.Close()

Check warning on line 31 in cmd/neofs-lens/internal/meta/status.go

View check run for this annotation

Codecov / codecov/patch

cmd/neofs-lens/internal/meta/status.go#L30-L31

Added lines #L30 - L31 were not covered by tests

res, err := db.ObjectStatus(addr)
common.ExitOnErr(cmd, common.Errf("reading object status: %w", err))

Check warning on line 34 in cmd/neofs-lens/internal/meta/status.go

View check run for this annotation

Codecov / codecov/patch

cmd/neofs-lens/internal/meta/status.go#L33-L34

Added lines #L33 - L34 were not covered by tests

const emptyValPlaceholder = "<empty>"
storageID := res.StorageID
if storageID == "" {
storageID = emptyValPlaceholder

Check warning on line 39 in cmd/neofs-lens/internal/meta/status.go

View check run for this annotation

Codecov / codecov/patch

cmd/neofs-lens/internal/meta/status.go#L36-L39

Added lines #L36 - L39 were not covered by tests
}

cmd.Printf("Metabase version: %d\n", res.Version)
cmd.Printf("Object state: %s\n", res.State)
cmd.Printf("Storage's ID: %s\n", storageID)
cmd.Println("Indexes:")
for _, bucket := range res.Buckets {
valStr := emptyValPlaceholder
if bucket.Value != nil {
valStr = fmt.Sprintf("%x", bucket.Value)

Check warning on line 49 in cmd/neofs-lens/internal/meta/status.go

View check run for this annotation

Codecov / codecov/patch

cmd/neofs-lens/internal/meta/status.go#L42-L49

Added lines #L42 - L49 were not covered by tests
}

cmd.Printf("\tBucket: %d\n"+
"\tValue (HEX): %s\n", bucket.BucketIndex, valStr)

Check warning on line 53 in cmd/neofs-lens/internal/meta/status.go

View check run for this annotation

Codecov / codecov/patch

cmd/neofs-lens/internal/meta/status.go#L52-L53

Added lines #L52 - L53 were not covered by tests
cthulhu-rider marked this conversation as resolved.
Show resolved Hide resolved
}
}
24 changes: 12 additions & 12 deletions pkg/local_object_storage/metabase/VERSION.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,55 +47,55 @@ The lowest not used bucket index: 20.
- Key: object ID
- Value: marshalled object
- Bucket containing objects of LOCK type
- Name: container ID + `7`
- Name: `7` + container ID
- Key: object ID
- Value: marshalled object
- Bucket containing objects of STORAGEGROUP type
- Name: container ID + 8
- Name: `8` + container ID
- Key: object ID
- Value: marshaled object
- Bucket containing objects of TOMBSTONE type
- Name: container ID + `9`
- Name: `9` + container ID
- Key: object ID
- Value: marshaled object
- Bucket containing object or LINK type
- Name: container ID + `18`
- Name: `18` + container ID
- Key: object ID
- Value: marshaled object
- Bucket mapping objects to the storage ID they are stored in
- Name: container ID + `10`
- Name: `10` + container ID
- Key: object ID
- Value: storage ID
- Bucket for mapping parent object to the split info
- Name: container ID + `11`
- Name: `11` + container ID
- Key: object ID
- Value: split info

### FKBT index buckets
- Bucket mapping owner to object IDs
- Name: containerID + `12`
- Name: `12` + container ID
- Key: owner ID as base58 string
- Value: bucket containing object IDs as keys
- Bucket containing objects attributes indexes
- Name: containerID + `13` + attribute key
- Name: `13` + container ID + attribute key
- Key: attribute value
- Value: bucket containing object IDs as keys

### List index buckets
- Bucket mapping payload hash to a list of object IDs
- Name: container ID + `14`
- Name: `14` + container ID
- Key: payload hash
- Value: list of object IDs
- Bucket mapping parent ID to a list of children IDs
- Name: container ID + `15`
- Name: `15` + container ID
- Key: parent ID
- Value: list of children object IDs
- Bucket mapping split ID to a list of object IDs
- Name: container ID + `16`
- Name: `16` + container ID
- Key: split ID
- Value: list of object IDs
- Bucket mapping first object ID to a list of objects IDs
- Name: container ID + `19`
- Name: `19` + container ID
- Key: first object ID
- Value: objects for corresponding split chain

Expand Down
89 changes: 85 additions & 4 deletions pkg/local_object_storage/metabase/status.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
package meta

import (
"errors"
"bytes"
"fmt"

cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"go.etcd.io/bbolt"
)

// BucketValue pairs a bucket index and a value that relates
// an object.
type BucketValue struct {
BucketIndex int
cthulhu-rider marked this conversation as resolved.
Show resolved Hide resolved
Value []byte
}

// ObjectStatus represents the status of the object in the Metabase.
type ObjectStatus struct {
Version uint64
Buckets []BucketValue
State []string
Path string
StorageID string
Error error
}

// ObjectStatus returns the status of the object in the Metabase. It contains state, path and storageID.
// ObjectStatus returns the status of the object in the Metabase. It contains state, path, storageID
// and indexed information about an object.
func (db *DB) ObjectStatus(address oid.Address) (ObjectStatus, error) {
db.modeMtx.RLock()
defer db.modeMtx.RUnlock()
Expand All @@ -27,17 +39,25 @@
storageID := StorageIDPrm{}
storageID.SetAddress(address)
resStorageID, err := db.StorageID(storageID)
if id := resStorageID.StorageID(); id != nil {
res.Error = errors.New("unexpected storage id")
if err != nil {
res.Error = fmt.Errorf("reading storage ID: %w", err)

Check warning on line 43 in pkg/local_object_storage/metabase/status.go

View check run for this annotation

Codecov / codecov/patch

pkg/local_object_storage/metabase/status.go#L42-L43

Added lines #L42 - L43 were not covered by tests
cthulhu-rider marked this conversation as resolved.
Show resolved Hide resolved
return res, res.Error
}

if id := resStorageID.StorageID(); id != nil {
res.StorageID = string(id)

Check warning on line 48 in pkg/local_object_storage/metabase/status.go

View check run for this annotation

Codecov / codecov/patch

pkg/local_object_storage/metabase/status.go#L47-L48

Added lines #L47 - L48 were not covered by tests
}

err = db.boltDB.View(func(tx *bbolt.Tx) error {
res.Version = getVersion(tx)

Check warning on line 52 in pkg/local_object_storage/metabase/status.go

View check run for this annotation

Codecov / codecov/patch

pkg/local_object_storage/metabase/status.go#L52

Added line #L52 was not covered by tests

oID := address.Object()
cID := address.Container()
objKey := objectKey(address.Object(), make([]byte, objectKeySize))
key := make([]byte, bucketKeySize)

res.Buckets = readBuckets(tx, cID, objKey)

Check warning on line 59 in pkg/local_object_storage/metabase/status.go

View check run for this annotation

Codecov / codecov/patch

pkg/local_object_storage/metabase/status.go#L59

Added line #L59 was not covered by tests

if objectLocked(tx, cID, oID) {
res.State = append(res.State, "LOCKED")
}
Expand All @@ -64,3 +84,64 @@
res.Error = err
return res, err
}

func readBuckets(tx *bbolt.Tx, cID cid.ID, objKey []byte) []BucketValue {
var res []BucketValue
cIDRaw := containerKey(cID, make([]byte, cidSize))

Check warning on line 90 in pkg/local_object_storage/metabase/status.go

View check run for this annotation

Codecov / codecov/patch

pkg/local_object_storage/metabase/status.go#L88-L90

Added lines #L88 - L90 were not covered by tests

objectBuckets := [][]byte{
graveyardBucketName,
garbageObjectsBucketName,
toMoveItBucketName,
primaryBucketName(cID, make([]byte, bucketKeySize)),
bucketNameLockers(cID, make([]byte, bucketKeySize)),
storageGroupBucketName(cID, make([]byte, bucketKeySize)),
tombstoneBucketName(cID, make([]byte, bucketKeySize)),
smallBucketName(cID, make([]byte, bucketKeySize)),
rootBucketName(cID, make([]byte, bucketKeySize)),
parentBucketName(cID, make([]byte, bucketKeySize)),
linkObjectsBucketName(cID, make([]byte, bucketKeySize)),
firstObjectIDBucketName(cID, make([]byte, bucketKeySize)),

Check warning on line 104 in pkg/local_object_storage/metabase/status.go

View check run for this annotation

Codecov / codecov/patch

pkg/local_object_storage/metabase/status.go#L92-L104

Added lines #L92 - L104 were not covered by tests
}

for _, bucketKey := range objectBuckets {
b := tx.Bucket(bucketKey)
if b == nil {
continue

Check warning on line 110 in pkg/local_object_storage/metabase/status.go

View check run for this annotation

Codecov / codecov/patch

pkg/local_object_storage/metabase/status.go#L107-L110

Added lines #L107 - L110 were not covered by tests
}

res = append(res, BucketValue{
BucketIndex: int(bucketKey[0]), // the first byte is always a prefix
cthulhu-rider marked this conversation as resolved.
Show resolved Hide resolved
Value: bytes.Clone(b.Get(objKey)),
})

Check warning on line 116 in pkg/local_object_storage/metabase/status.go

View check run for this annotation

Codecov / codecov/patch

pkg/local_object_storage/metabase/status.go#L113-L116

Added lines #L113 - L116 were not covered by tests
}

containerBuckets := []byte{
containerVolumePrefix,
garbageContainersPrefix,

Check warning on line 121 in pkg/local_object_storage/metabase/status.go

View check run for this annotation

Codecov / codecov/patch

pkg/local_object_storage/metabase/status.go#L119-L121

Added lines #L119 - L121 were not covered by tests
}

for _, bucketKey := range containerBuckets {
b := tx.Bucket([]byte{bucketKey})
if b == nil {
continue

Check warning on line 127 in pkg/local_object_storage/metabase/status.go

View check run for this annotation

Codecov / codecov/patch

pkg/local_object_storage/metabase/status.go#L124-L127

Added lines #L124 - L127 were not covered by tests
}

res = append(res, BucketValue{
BucketIndex: int(bucketKey),
Value: bytes.Clone(b.Get(cIDRaw)),
})

Check warning on line 133 in pkg/local_object_storage/metabase/status.go

View check run for this annotation

Codecov / codecov/patch

pkg/local_object_storage/metabase/status.go#L130-L133

Added lines #L130 - L133 were not covered by tests
}

if b := tx.Bucket(bucketNameLocked); b != nil {
b = b.Bucket(cIDRaw)
if b != nil {
res = append(res, BucketValue{
BucketIndex: lockedPrefix,
Value: bytes.Clone(b.Get(objKey)),
})

Check warning on line 142 in pkg/local_object_storage/metabase/status.go

View check run for this annotation

Codecov / codecov/patch

pkg/local_object_storage/metabase/status.go#L136-L142

Added lines #L136 - L142 were not covered by tests
}
}

return res

Check warning on line 146 in pkg/local_object_storage/metabase/status.go

View check run for this annotation

Codecov / codecov/patch

pkg/local_object_storage/metabase/status.go#L146

Added line #L146 was not covered by tests
}
6 changes: 6 additions & 0 deletions pkg/local_object_storage/metabase/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,12 @@
return key[:objectKeySize]
}

// containerKey returns key for K-V tables when key is a container ID.
func containerKey(cID cid.ID, key []byte) []byte {
cID.Encode(key)
return key[:cidSize]

Check warning on line 257 in pkg/local_object_storage/metabase/util.go

View check run for this annotation

Codecov / codecov/patch

pkg/local_object_storage/metabase/util.go#L255-L257

Added lines #L255 - L257 were not covered by tests
}

// 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
12 changes: 12 additions & 0 deletions pkg/local_object_storage/metabase/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,15 @@
}
return b.Put(versionKey, data)
}

func getVersion(tx *bbolt.Tx) uint64 {
b := tx.Bucket(shardInfoBucket)
if b != nil {
data := b.Get(versionKey)
if len(data) == 8 {
return binary.LittleEndian.Uint64(data)

Check warning on line 68 in pkg/local_object_storage/metabase/version.go

View check run for this annotation

Codecov / codecov/patch

pkg/local_object_storage/metabase/version.go#L63-L68

Added lines #L63 - L68 were not covered by tests
}
}

return 0

Check warning on line 72 in pkg/local_object_storage/metabase/version.go

View check run for this annotation

Codecov / codecov/patch

pkg/local_object_storage/metabase/version.go#L72

Added line #L72 was not covered by tests
}
Loading