forked from TrueCloudLab/frostfs-node
[#1658] node: Support object counter metrics
Increment shard's object counter on successful `Put` calls and decrement on `Delete`. Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
This commit is contained in:
parent
067ab44e0b
commit
745f72fff0
7 changed files with 87 additions and 15 deletions
|
@ -16,6 +16,8 @@ type MetricRegister interface {
|
||||||
AddRangeDuration(d time.Duration)
|
AddRangeDuration(d time.Duration)
|
||||||
AddSearchDuration(d time.Duration)
|
AddSearchDuration(d time.Duration)
|
||||||
AddListObjectsDuration(d time.Duration)
|
AddListObjectsDuration(d time.Duration)
|
||||||
|
|
||||||
|
AddToObjectCounter(shardID string, delta int)
|
||||||
}
|
}
|
||||||
|
|
||||||
func elapsed(addFunc func(d time.Duration)) func() {
|
func elapsed(addFunc func(d time.Duration)) func() {
|
||||||
|
|
|
@ -17,6 +17,23 @@ var errShardNotFound = errors.New("shard not found")
|
||||||
|
|
||||||
type hashedShard shardWrapper
|
type hashedShard shardWrapper
|
||||||
|
|
||||||
|
type metricsWithID struct {
|
||||||
|
id string
|
||||||
|
mw MetricRegister
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m metricsWithID) AddToObjectCounter(delta int) {
|
||||||
|
m.mw.AddToObjectCounter(m.id, delta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m metricsWithID) IncObjectCounter() {
|
||||||
|
m.mw.AddToObjectCounter(m.id, +1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m metricsWithID) DecObjectCounter() {
|
||||||
|
m.mw.AddToObjectCounter(m.id, -1)
|
||||||
|
}
|
||||||
|
|
||||||
// AddShard adds a new shard to the storage engine.
|
// AddShard adds a new shard to the storage engine.
|
||||||
//
|
//
|
||||||
// Returns any error encountered that did not allow adding a shard.
|
// Returns any error encountered that did not allow adding a shard.
|
||||||
|
@ -35,6 +52,15 @@ func (e *StorageEngine) AddShard(opts ...shard.Option) (*shard.ID, error) {
|
||||||
return nil, fmt.Errorf("could not generate shard ID: %w", err)
|
return nil, fmt.Errorf("could not generate shard ID: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if e.metrics != nil {
|
||||||
|
opts = append(opts, shard.WithMetricsWriter(
|
||||||
|
metricsWithID{
|
||||||
|
id: id.String(),
|
||||||
|
mw: e.metrics,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
sh := shard.New(append(opts,
|
sh := shard.New(append(opts,
|
||||||
shard.WithID(id),
|
shard.WithID(id),
|
||||||
shard.WithExpiredTombstonesCallback(e.processExpiredTombstones),
|
shard.WithExpiredTombstonesCallback(e.processExpiredTombstones),
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
||||||
"go.etcd.io/bbolt"
|
"go.etcd.io/bbolt"
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// DeletePrm groups the parameters of Delete operation.
|
// DeletePrm groups the parameters of Delete operation.
|
||||||
|
@ -20,7 +19,14 @@ type DeletePrm struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteRes groups the resulting values of Delete operation.
|
// DeleteRes groups the resulting values of Delete operation.
|
||||||
type DeleteRes struct{}
|
type DeleteRes struct {
|
||||||
|
removed uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemovedObjects returns number of removed raw objects.
|
||||||
|
func (d DeleteRes) RemovedObjects() uint64 {
|
||||||
|
return d.removed
|
||||||
|
}
|
||||||
|
|
||||||
// SetAddresses is a Delete option to set the addresses of the objects to delete.
|
// SetAddresses is a Delete option to set the addresses of the objects to delete.
|
||||||
//
|
//
|
||||||
|
@ -44,8 +50,12 @@ func (db *DB) Delete(prm DeletePrm) (DeleteRes, error) {
|
||||||
db.modeMtx.RLock()
|
db.modeMtx.RLock()
|
||||||
defer db.modeMtx.RUnlock()
|
defer db.modeMtx.RUnlock()
|
||||||
|
|
||||||
err := db.boltDB.Update(func(tx *bbolt.Tx) error {
|
var rawRemoved uint64
|
||||||
return db.deleteGroup(tx, prm.addrs)
|
var err error
|
||||||
|
|
||||||
|
err = db.boltDB.Update(func(tx *bbolt.Tx) error {
|
||||||
|
rawRemoved, err = db.deleteGroup(tx, prm.addrs)
|
||||||
|
return err
|
||||||
})
|
})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for i := range prm.addrs {
|
for i := range prm.addrs {
|
||||||
|
@ -54,10 +64,10 @@ func (db *DB) Delete(prm DeletePrm) (DeleteRes, error) {
|
||||||
storagelog.OpField("metabase DELETE"))
|
storagelog.OpField("metabase DELETE"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return DeleteRes{}, err
|
return DeleteRes{removed: rawRemoved}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) deleteGroup(tx *bbolt.Tx, addrs []oid.Address) error {
|
func (db *DB) deleteGroup(tx *bbolt.Tx, addrs []oid.Address) (uint64, error) {
|
||||||
refCounter := make(referenceCounter, len(addrs))
|
refCounter := make(referenceCounter, len(addrs))
|
||||||
currEpoch := db.epochState.CurrentEpoch()
|
currEpoch := db.epochState.CurrentEpoch()
|
||||||
|
|
||||||
|
@ -65,7 +75,7 @@ func (db *DB) deleteGroup(tx *bbolt.Tx, addrs []oid.Address) error {
|
||||||
for i := range addrs {
|
for i := range addrs {
|
||||||
removed, err := db.delete(tx, addrs[i], refCounter, currEpoch)
|
removed, err := db.delete(tx, addrs[i], refCounter, currEpoch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err // maybe log and continue?
|
return 0, err // maybe log and continue?
|
||||||
}
|
}
|
||||||
|
|
||||||
if removed {
|
if removed {
|
||||||
|
@ -75,20 +85,19 @@ func (db *DB) deleteGroup(tx *bbolt.Tx, addrs []oid.Address) error {
|
||||||
|
|
||||||
err := db.updateCounter(tx, rawDeleted, false)
|
err := db.updateCounter(tx, rawDeleted, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
db.log.Error("could not decrease object counter",
|
return 0, fmt.Errorf("could not decrease object counter: %w", err)
|
||||||
zap.Error(err))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, refNum := range refCounter {
|
for _, refNum := range refCounter {
|
||||||
if refNum.cur == refNum.all {
|
if refNum.cur == refNum.all {
|
||||||
err := db.deleteObject(tx, refNum.obj, true)
|
err := db.deleteObject(tx, refNum.obj, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err // maybe log and continue?
|
return rawDeleted, err // maybe log and continue?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return rawDeleted, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) delete(tx *bbolt.Tx, addr oid.Address, refCounter referenceCounter, currEpoch uint64) (bool, error) {
|
func (db *DB) delete(tx *bbolt.Tx, addr oid.Address, refCounter referenceCounter, currEpoch uint64) (bool, error) {
|
||||||
|
|
|
@ -14,7 +14,6 @@ import (
|
||||||
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
||||||
"go.etcd.io/bbolt"
|
"go.etcd.io/bbolt"
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
@ -146,8 +145,7 @@ func (db *DB) put(
|
||||||
if !isParent {
|
if !isParent {
|
||||||
err = db.updateCounter(tx, 1, true)
|
err = db.updateCounter(tx, 1, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
db.log.Error("could not increase object counter: %w",
|
return fmt.Errorf("could not increase object counter: %w", err)
|
||||||
zap.Error(err))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,11 +65,13 @@ func (s *Shard) Delete(prm DeletePrm) (DeleteRes, error) {
|
||||||
var delPrm meta.DeletePrm
|
var delPrm meta.DeletePrm
|
||||||
delPrm.SetAddresses(prm.addr...)
|
delPrm.SetAddresses(prm.addr...)
|
||||||
|
|
||||||
_, err := s.metaBase.Delete(delPrm)
|
res, err := s.metaBase.Delete(delPrm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return DeleteRes{}, err // stop on metabase error ?
|
return DeleteRes{}, err // stop on metabase error ?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.decObjectCounterBy(res.RemovedObjects())
|
||||||
|
|
||||||
for i := range prm.addr { // delete small object
|
for i := range prm.addr { // delete small object
|
||||||
var delPrm common.DeletePrm
|
var delPrm common.DeletePrm
|
||||||
delPrm.Address = prm.addr[i]
|
delPrm.Address = prm.addr[i]
|
||||||
|
|
|
@ -73,6 +73,8 @@ func (s *Shard) Put(prm PutPrm) (PutRes, error) {
|
||||||
// since the object has been successfully written to BlobStor
|
// since the object has been successfully written to BlobStor
|
||||||
return PutRes{}, fmt.Errorf("could not put object to metabase: %w", err)
|
return PutRes{}, fmt.Errorf("could not put object to metabase: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.incObjectCounter()
|
||||||
}
|
}
|
||||||
|
|
||||||
return PutRes{}, nil
|
return PutRes{}, nil
|
||||||
|
|
|
@ -45,6 +45,17 @@ type ExpiredObjectsCallback func(context.Context, []oid.Address)
|
||||||
// DeletedLockCallback is a callback handling list of deleted LOCK objects.
|
// DeletedLockCallback is a callback handling list of deleted LOCK objects.
|
||||||
type DeletedLockCallback func(context.Context, []oid.Address)
|
type DeletedLockCallback func(context.Context, []oid.Address)
|
||||||
|
|
||||||
|
// MetricsWriter is an interface that must store shard's metrics.
|
||||||
|
type MetricsWriter interface {
|
||||||
|
// AddToObjectCounter must update object counter. Negative
|
||||||
|
// parameter must decrease the counter.
|
||||||
|
AddToObjectCounter(delta int)
|
||||||
|
// IncObjectCounter must increment shard's object counter.
|
||||||
|
IncObjectCounter()
|
||||||
|
// DecObjectCounter must decrement shard's object counter.
|
||||||
|
DecObjectCounter()
|
||||||
|
}
|
||||||
|
|
||||||
type cfg struct {
|
type cfg struct {
|
||||||
m sync.RWMutex
|
m sync.RWMutex
|
||||||
|
|
||||||
|
@ -75,6 +86,8 @@ type cfg struct {
|
||||||
deletedLockCallBack DeletedLockCallback
|
deletedLockCallBack DeletedLockCallback
|
||||||
|
|
||||||
tsSource TombstoneSource
|
tsSource TombstoneSource
|
||||||
|
|
||||||
|
metricsWriter MetricsWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultCfg() *cfg {
|
func defaultCfg() *cfg {
|
||||||
|
@ -259,6 +272,14 @@ func WithDeletedLockCallback(v DeletedLockCallback) Option {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithMetricsWriter returns option to specify storage of the
|
||||||
|
// shard's metrics.
|
||||||
|
func WithMetricsWriter(v MetricsWriter) Option {
|
||||||
|
return func(c *cfg) {
|
||||||
|
c.metricsWriter = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Shard) fillInfo() {
|
func (s *Shard) fillInfo() {
|
||||||
s.cfg.info.MetaBaseInfo = s.metaBase.DumpInfo()
|
s.cfg.info.MetaBaseInfo = s.metaBase.DumpInfo()
|
||||||
s.cfg.info.BlobStorInfo = s.blobStor.DumpInfo()
|
s.cfg.info.BlobStorInfo = s.blobStor.DumpInfo()
|
||||||
|
@ -271,3 +292,15 @@ func (s *Shard) fillInfo() {
|
||||||
s.cfg.info.PiloramaInfo = s.pilorama.DumpInfo()
|
s.cfg.info.PiloramaInfo = s.pilorama.DumpInfo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Shard) incObjectCounter() {
|
||||||
|
if s.cfg.metricsWriter != nil {
|
||||||
|
s.cfg.metricsWriter.IncObjectCounter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Shard) decObjectCounterBy(v uint64) {
|
||||||
|
if s.cfg.metricsWriter != nil {
|
||||||
|
s.cfg.metricsWriter.AddToObjectCounter(-int(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue