2019-07-24 18:26:43 +01:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package gc
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"time"
|
|
|
|
|
2021-04-01 11:56:39 +01:00
|
|
|
"github.com/zeebo/errs"
|
2019-07-24 18:26:43 +01:00
|
|
|
"go.uber.org/zap"
|
|
|
|
|
2019-12-27 11:48:47 +00:00
|
|
|
"storj.io/common/bloomfilter"
|
|
|
|
"storj.io/common/memory"
|
|
|
|
"storj.io/common/storj"
|
2021-05-28 11:10:01 +01:00
|
|
|
"storj.io/storj/satellite/metabase/segmentloop"
|
2019-07-24 18:26:43 +01:00
|
|
|
)
|
|
|
|
|
2022-08-10 14:24:47 +01:00
|
|
|
var remoteSegmentFunc = mon.Task()
|
2022-05-18 10:58:45 +01:00
|
|
|
|
2021-05-28 11:10:01 +01:00
|
|
|
var _ segmentloop.Observer = (*PieceTracker)(nil)
|
2019-09-10 14:24:16 +01:00
|
|
|
|
2020-12-05 16:01:42 +00:00
|
|
|
// PieceTracker implements the metainfo loop observer interface for garbage collection.
|
2019-09-10 14:24:16 +01:00
|
|
|
//
|
|
|
|
// architecture: Observer
|
2019-07-24 18:26:43 +01:00
|
|
|
type PieceTracker struct {
|
|
|
|
log *zap.Logger
|
|
|
|
config Config
|
|
|
|
creationDate time.Time
|
2019-08-27 13:37:42 +01:00
|
|
|
// TODO: should we use int or int64 consistently for piece count (db type is int64)?
|
|
|
|
pieceCounts map[storj.NodeID]int
|
2019-07-24 18:26:43 +01:00
|
|
|
|
2020-12-21 14:59:11 +00:00
|
|
|
RetainInfos map[storj.NodeID]*RetainInfo
|
2019-07-24 18:26:43 +01:00
|
|
|
}
|
|
|
|
|
2020-07-16 15:18:02 +01:00
|
|
|
// NewPieceTracker instantiates a new gc piece tracker to be subscribed to the metainfo loop.
|
2019-07-24 18:26:43 +01:00
|
|
|
func NewPieceTracker(log *zap.Logger, config Config, pieceCounts map[storj.NodeID]int) *PieceTracker {
|
|
|
|
return &PieceTracker{
|
|
|
|
log: log,
|
|
|
|
config: config,
|
|
|
|
creationDate: time.Now().UTC(),
|
|
|
|
pieceCounts: pieceCounts,
|
|
|
|
|
2020-12-21 14:59:11 +00:00
|
|
|
RetainInfos: make(map[storj.NodeID]*RetainInfo, len(pieceCounts)),
|
2019-07-24 18:26:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-28 11:10:01 +01:00
|
|
|
// LoopStarted is called at each start of a loop.
|
|
|
|
func (pieceTracker *PieceTracker) LoopStarted(ctx context.Context, info segmentloop.LoopInfo) (err error) {
|
|
|
|
if pieceTracker.creationDate.After(info.Started) {
|
|
|
|
return errs.New("Creation date after loop starting time.")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// RemoteSegment takes a remote segment found in metabase and adds pieces to bloom filters.
|
2022-05-18 10:58:45 +01:00
|
|
|
func (pieceTracker *PieceTracker) RemoteSegment(ctx context.Context, segment *segmentloop.Segment) error {
|
2022-08-10 14:24:47 +01:00
|
|
|
defer remoteSegmentFunc(&ctx)(nil) // method always returns nil
|
2019-07-24 18:26:43 +01:00
|
|
|
|
2022-05-18 10:32:38 +01:00
|
|
|
deriver := segment.RootPieceID.Deriver()
|
2020-10-27 06:59:14 +00:00
|
|
|
for _, piece := range segment.Pieces {
|
2022-05-18 10:32:38 +01:00
|
|
|
pieceID := deriver.Derive(piece.StorageNode, int32(piece.Number))
|
2020-10-27 06:59:14 +00:00
|
|
|
pieceTracker.add(piece.StorageNode, pieceID)
|
2019-07-24 18:26:43 +01:00
|
|
|
}
|
2020-10-27 06:59:14 +00:00
|
|
|
|
2019-07-24 18:26:43 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-07-16 15:18:02 +01:00
|
|
|
// InlineSegment returns nil because we're only doing gc for storage nodes for now.
|
2021-05-28 11:10:01 +01:00
|
|
|
func (pieceTracker *PieceTracker) InlineSegment(ctx context.Context, segment *segmentloop.Segment) (err error) {
|
2019-07-24 18:26:43 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-07-16 15:18:02 +01:00
|
|
|
// adds a pieceID to the relevant node's RetainInfo.
|
2019-07-24 18:26:43 +01:00
|
|
|
func (pieceTracker *PieceTracker) add(nodeID storj.NodeID, pieceID storj.PieceID) {
|
2022-05-18 10:32:38 +01:00
|
|
|
info, ok := pieceTracker.RetainInfos[nodeID]
|
|
|
|
if !ok {
|
2019-07-24 18:26:43 +01:00
|
|
|
// If we know how many pieces a node should be storing, use that number. Otherwise use default.
|
|
|
|
numPieces := pieceTracker.config.InitialPieces
|
|
|
|
if pieceTracker.pieceCounts[nodeID] > 0 {
|
|
|
|
numPieces = pieceTracker.pieceCounts[nodeID]
|
|
|
|
}
|
2020-05-11 06:26:32 +01:00
|
|
|
// limit size of bloom filter to ensure we are under the limit for RPC
|
2019-07-24 18:26:43 +01:00
|
|
|
filter := bloomfilter.NewOptimalMaxSize(numPieces, pieceTracker.config.FalsePositiveRate, 2*memory.MiB)
|
2022-05-18 10:32:38 +01:00
|
|
|
info = &RetainInfo{
|
2019-07-24 18:26:43 +01:00
|
|
|
Filter: filter,
|
|
|
|
CreationDate: pieceTracker.creationDate,
|
|
|
|
}
|
2022-05-18 10:32:38 +01:00
|
|
|
pieceTracker.RetainInfos[nodeID] = info
|
2019-07-24 18:26:43 +01:00
|
|
|
}
|
|
|
|
|
2022-05-18 10:32:38 +01:00
|
|
|
info.Filter.Add(pieceID)
|
|
|
|
info.Count++
|
2019-07-24 18:26:43 +01:00
|
|
|
}
|