[#1445] shard/gc: Collect objects of all types
Signed-off-by: Aleksey Savchuk <a.savchuk@yadro.com>
This commit is contained in:
parent
8d6d829348
commit
6bc49eb741
3 changed files with 80 additions and 75 deletions
|
@ -254,6 +254,7 @@ const (
|
||||||
ShardFailureToMarkLockersAsGarbage = "failure to mark lockers as garbage"
|
ShardFailureToMarkLockersAsGarbage = "failure to mark lockers as garbage"
|
||||||
ShardFailureToGetExpiredUnlockedObjects = "failure to get expired unlocked objects"
|
ShardFailureToGetExpiredUnlockedObjects = "failure to get expired unlocked objects"
|
||||||
ShardCouldNotMarkObjectToDeleteInMetabase = "could not mark object to delete in metabase"
|
ShardCouldNotMarkObjectToDeleteInMetabase = "could not mark object to delete in metabase"
|
||||||
|
ShardUnknownObjectTypeWhileIteratingExpiredObjects = "encountered unknown object type while iterating expired objects"
|
||||||
WritecacheWaitingForChannelsToFlush = "waiting for channels to flush"
|
WritecacheWaitingForChannelsToFlush = "waiting for channels to flush"
|
||||||
WritecacheCantRemoveObjectFromWritecache = "can't remove object from write-cache"
|
WritecacheCantRemoveObjectFromWritecache = "can't remove object from write-cache"
|
||||||
BlobovniczatreeCouldNotGetObjectFromLevel = "could not get object from level"
|
BlobovniczatreeCouldNotGetObjectFromLevel = "could not get object from level"
|
||||||
|
|
|
@ -116,7 +116,6 @@ func (s *Shard) Init(ctx context.Context) error {
|
||||||
eventNewEpoch: {
|
eventNewEpoch: {
|
||||||
cancelFunc: func() {},
|
cancelFunc: func() {},
|
||||||
handlers: []eventHandler{
|
handlers: []eventHandler{
|
||||||
s.collectExpiredLockObjects,
|
|
||||||
s.collectExpiredObjects,
|
s.collectExpiredObjects,
|
||||||
s.collectExpiredGraves,
|
s.collectExpiredGraves,
|
||||||
s.collectExpiredMetrics,
|
s.collectExpiredMetrics,
|
||||||
|
|
|
@ -2,6 +2,7 @@ package shard
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"slices"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -14,6 +15,7 @@ import (
|
||||||
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
"golang.org/x/exp/maps"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -356,40 +358,61 @@ func (s *Shard) collectExpiredObjects(ctx context.Context, e Event) {
|
||||||
s.gc.metrics.AddExpiredObjectCollectionDuration(time.Since(startedAt), err == nil)
|
s.gc.metrics.AddExpiredObjectCollectionDuration(time.Since(startedAt), err == nil)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
s.log.Debug(ctx, logs.ShardGCCollectingExpiredObjectsStarted, zap.Uint64("epoch", e.(newEpoch).epoch))
|
epoch := e.(newEpoch).epoch
|
||||||
defer s.log.Debug(ctx, logs.ShardGCCollectingExpiredObjectsCompleted, zap.Uint64("epoch", e.(newEpoch).epoch))
|
|
||||||
|
s.log.Debug(ctx, logs.ShardGCCollectingExpiredObjectsStarted, zap.Uint64("epoch", epoch))
|
||||||
|
defer s.log.Debug(ctx, logs.ShardGCCollectingExpiredObjectsCompleted, zap.Uint64("epoch", epoch))
|
||||||
|
|
||||||
workersCount, batchSize := s.getExpiredObjectsParameters()
|
workersCount, batchSize := s.getExpiredObjectsParameters()
|
||||||
|
|
||||||
errGroup, egCtx := errgroup.WithContext(ctx)
|
errGroup, egCtx := errgroup.WithContext(ctx)
|
||||||
errGroup.SetLimit(workersCount)
|
errGroup.SetLimit(workersCount)
|
||||||
|
|
||||||
errGroup.Go(func() error {
|
handlers := map[objectSDK.Type]func(context.Context, []oid.Address){
|
||||||
batch := make([]oid.Address, 0, batchSize)
|
objectSDK.TypeRegular: s.handleExpiredObjects,
|
||||||
expErr := s.getExpiredObjects(egCtx, e.(newEpoch).epoch, func(o *meta.ExpiredObject) {
|
objectSDK.TypeTombstone: s.handleExpiredTombstones,
|
||||||
if o.Type() != objectSDK.TypeTombstone && o.Type() != objectSDK.TypeLock {
|
objectSDK.TypeLock: func(ctx context.Context, batch []oid.Address) {
|
||||||
batch = append(batch, o.Address())
|
s.expiredLockObjectsCallback(ctx, epoch, batch)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
knownTypes := maps.Keys(handlers)
|
||||||
|
|
||||||
if len(batch) == batchSize {
|
batches := make(map[objectSDK.Type][]oid.Address)
|
||||||
expired := batch
|
for _, typ := range knownTypes {
|
||||||
errGroup.Go(func() error {
|
batches[typ] = make([]oid.Address, 0, batchSize)
|
||||||
s.handleExpiredObjects(egCtx, expired)
|
}
|
||||||
return egCtx.Err()
|
|
||||||
})
|
errGroup.Go(func() error {
|
||||||
batch = make([]oid.Address, 0, batchSize)
|
expErr := s.getExpiredObjects(egCtx, epoch, func(o *meta.ExpiredObject) {
|
||||||
}
|
typ := o.Type()
|
||||||
|
|
||||||
|
if !slices.Contains(knownTypes, typ) {
|
||||||
|
s.log.Warn(ctx, logs.ShardUnknownObjectTypeWhileIteratingExpiredObjects, zap.Stringer("type", typ))
|
||||||
|
}
|
||||||
|
|
||||||
|
batches[typ] = append(batches[typ], o.Address())
|
||||||
|
|
||||||
|
if len(batches[typ]) == batchSize {
|
||||||
|
expired := batches[typ]
|
||||||
|
errGroup.Go(func() error {
|
||||||
|
handlers[typ](egCtx, expired)
|
||||||
|
return egCtx.Err()
|
||||||
|
})
|
||||||
|
batches[typ] = make([]oid.Address, 0, batchSize)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if expErr != nil {
|
if expErr != nil {
|
||||||
return expErr
|
return expErr
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(batch) > 0 {
|
for typ, batch := range batches {
|
||||||
expired := batch
|
if len(batch) > 0 {
|
||||||
errGroup.Go(func() error {
|
expired := batch
|
||||||
s.handleExpiredObjects(egCtx, expired)
|
errGroup.Go(func() error {
|
||||||
return egCtx.Err()
|
handlers[typ](egCtx, expired)
|
||||||
})
|
return egCtx.Err()
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -400,6 +423,41 @@ func (s *Shard) collectExpiredObjects(ctx context.Context, e Event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Shard) handleExpiredTombstones(ctx context.Context, expired []oid.Address) {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
s.m.RLock()
|
||||||
|
defer s.m.RUnlock()
|
||||||
|
|
||||||
|
if s.info.Mode.NoMetabase() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var inhumePrm meta.InhumePrm
|
||||||
|
inhumePrm.SetAddresses(expired...)
|
||||||
|
inhumePrm.SetGCMark()
|
||||||
|
|
||||||
|
res, err := s.metaBase.Inhume(ctx, inhumePrm)
|
||||||
|
if err != nil {
|
||||||
|
s.log.Warn(ctx, logs.ShardCouldNotInhumeTheObjects, zap.Error(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s.gc.metrics.AddInhumedObjectCount(res.LogicInhumed(), objectTypeTombstone)
|
||||||
|
s.decObjectCounterBy(logical, res.LogicInhumed())
|
||||||
|
s.decObjectCounterBy(user, res.UserInhumed())
|
||||||
|
s.decContainerObjectCounter(res.InhumedByCnrID())
|
||||||
|
|
||||||
|
for i := range res.GetDeletionInfoLength() {
|
||||||
|
delInfo := res.GetDeletionInfoByIndex(i)
|
||||||
|
s.addToContainerSize(delInfo.CID.EncodeToString(), -int64(delInfo.Size))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Shard) handleExpiredObjects(ctx context.Context, expired []oid.Address) {
|
func (s *Shard) handleExpiredObjects(ctx context.Context, expired []oid.Address) {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
|
@ -535,59 +593,6 @@ func (s *Shard) collectExpiredGraves(ctx context.Context, e Event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Shard) collectExpiredLockObjects(ctx context.Context, e Event) {
|
|
||||||
var err error
|
|
||||||
startedAt := time.Now()
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
s.gc.metrics.AddExpiredObjectCollectionDuration(time.Since(startedAt), err == nil)
|
|
||||||
}()
|
|
||||||
|
|
||||||
s.log.Debug(ctx, logs.ShardGCCollectingExpiredLocksStarted, zap.Uint64("epoch", e.(newEpoch).epoch))
|
|
||||||
defer s.log.Debug(ctx, logs.ShardGCCollectingExpiredLocksCompleted, zap.Uint64("epoch", e.(newEpoch).epoch))
|
|
||||||
|
|
||||||
workersCount, batchSize := s.getExpiredObjectsParameters()
|
|
||||||
|
|
||||||
errGroup, egCtx := errgroup.WithContext(ctx)
|
|
||||||
errGroup.SetLimit(workersCount)
|
|
||||||
|
|
||||||
errGroup.Go(func() error {
|
|
||||||
batch := make([]oid.Address, 0, batchSize)
|
|
||||||
|
|
||||||
expErr := s.getExpiredObjects(egCtx, e.(newEpoch).epoch, func(o *meta.ExpiredObject) {
|
|
||||||
if o.Type() == objectSDK.TypeLock {
|
|
||||||
batch = append(batch, o.Address())
|
|
||||||
|
|
||||||
if len(batch) == batchSize {
|
|
||||||
expired := batch
|
|
||||||
errGroup.Go(func() error {
|
|
||||||
s.expiredLockObjectsCallback(egCtx, e.(newEpoch).epoch, expired)
|
|
||||||
return egCtx.Err()
|
|
||||||
})
|
|
||||||
batch = make([]oid.Address, 0, batchSize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if expErr != nil {
|
|
||||||
return expErr
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(batch) > 0 {
|
|
||||||
expired := batch
|
|
||||||
errGroup.Go(func() error {
|
|
||||||
s.expiredLockObjectsCallback(egCtx, e.(newEpoch).epoch, expired)
|
|
||||||
return egCtx.Err()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if err = errGroup.Wait(); err != nil {
|
|
||||||
s.log.Warn(ctx, logs.ShardIteratorOverExpiredLocksFailed, zap.Error(err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Shard) getExpiredObjects(ctx context.Context, epoch uint64, onExpiredFound func(*meta.ExpiredObject)) error {
|
func (s *Shard) getExpiredObjects(ctx context.Context, epoch uint64, onExpiredFound func(*meta.ExpiredObject)) error {
|
||||||
s.m.RLock()
|
s.m.RLock()
|
||||||
defer s.m.RUnlock()
|
defer s.m.RUnlock()
|
||||||
|
|
Loading…
Reference in a new issue