2019-03-18 10:55:06 +00:00
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
2019-05-08 12:11:59 +01:00
// Package collector implements expired piece deletion from storage node.
2019-03-18 10:55:06 +00:00
package collector
import (
2019-05-08 12:11:59 +01:00
"context"
2020-07-21 14:10:46 +01:00
"os"
2019-03-18 10:55:06 +00:00
"time"
2019-11-08 20:40:39 +00:00
"github.com/spacemonkeygo/monkit/v3"
2022-09-02 10:37:07 +01:00
"github.com/zeebo/errs"
2019-03-18 10:55:06 +00:00
"go.uber.org/zap"
2019-12-27 11:48:47 +00:00
"storj.io/common/sync2"
2019-03-18 10:55:06 +00:00
"storj.io/storj/storagenode/pieces"
2020-05-27 22:07:24 +01:00
"storj.io/storj/storagenode/piecestore/usedserials"
2019-03-18 10:55:06 +00:00
)
2019-05-08 12:11:59 +01:00
var mon = monkit . Package ( )
2019-03-18 10:55:06 +00:00
// Config defines parameters for storage node Collector.
type Config struct {
2019-05-08 12:11:59 +01:00
Interval time . Duration ` help:"how frequently expired pieces are collected" default:"1h0m0s" `
2019-03-18 10:55:06 +00:00
}
// Service implements collecting expired pieces on the storage node.
2019-09-10 14:24:16 +01:00
//
// architecture: Chore
2019-03-18 10:55:06 +00:00
type Service struct {
2019-06-06 20:06:31 +01:00
log * zap . Logger
pieces * pieces . Store
2020-05-27 22:07:24 +01:00
usedSerials * usedserials . Table
2019-05-08 12:11:59 +01:00
2020-01-29 15:37:50 +00:00
Loop * sync2 . Cycle
2019-03-18 10:55:06 +00:00
}
// NewService creates a new collector service.
2020-05-27 22:07:24 +01:00
func NewService ( log * zap . Logger , pieces * pieces . Store , usedSerials * usedserials . Table , config Config ) * Service {
2019-03-18 10:55:06 +00:00
return & Service {
2019-06-06 20:06:31 +01:00
log : log ,
pieces : pieces ,
usedSerials : usedSerials ,
2020-01-29 15:37:50 +00:00
Loop : sync2 . NewCycle ( config . Interval ) ,
2019-03-18 10:55:06 +00:00
}
}
2019-05-08 12:11:59 +01:00
2020-06-19 12:35:21 +01:00
// Run runs collector service.
2019-05-08 12:11:59 +01:00
func ( service * Service ) Run ( ctx context . Context ) ( err error ) {
defer mon . Task ( ) ( & ctx ) ( & err )
return service . Loop . Run ( ctx , func ( ctx context . Context ) error {
2019-11-20 15:02:57 +00:00
// V3-3143 Pieces should be collected at least 24 hours after expiration
// to avoid premature deletion due to timezone issues, which may lead to
// storage node disqualification.
err := service . Collect ( ctx , time . Now ( ) . Add ( - 24 * time . Hour ) )
2019-05-08 12:11:59 +01:00
if err != nil {
service . log . Error ( "error during collecting pieces: " , zap . Error ( err ) )
}
return nil
} )
}
// Close stops the collector service.
func ( service * Service ) Close ( ) ( err error ) {
service . Loop . Close ( )
return nil
}
// Collect collects pieces that have expired by now.
func ( service * Service ) Collect ( ctx context . Context , now time . Time ) ( err error ) {
defer mon . Task ( ) ( & ctx ) ( & err )
2020-05-27 22:07:24 +01:00
service . usedSerials . DeleteExpired ( now )
2019-06-06 20:06:31 +01:00
2019-05-08 12:11:59 +01:00
const maxBatches = 100
const batchSize = 1000
var count int64
defer func ( ) {
if count > 0 {
2019-08-08 02:47:30 +01:00
service . log . Info ( "collect" , zap . Int64 ( "count" , count ) )
2019-05-08 12:11:59 +01:00
}
} ( )
for k := 0 ; k < maxBatches ; k ++ {
2019-08-08 02:47:30 +01:00
infos , err := service . pieces . GetExpired ( ctx , now , batchSize )
2019-05-08 12:11:59 +01:00
if err != nil {
return err
}
if len ( infos ) == 0 {
return nil
}
for _ , expired := range infos {
err := service . pieces . Delete ( ctx , expired . SatelliteID , expired . PieceID )
if err != nil {
2022-09-02 10:37:07 +01:00
if errs . Is ( err , os . ErrNotExist ) {
2022-09-08 12:08:49 +01:00
service . log . Warn ( "file does not exist" , zap . Stringer ( "Satellite ID" , expired . SatelliteID ) , zap . Stringer ( "Piece ID" , expired . PieceID ) )
err := service . pieces . DeleteExpired ( ctx , expired . SatelliteID , expired . PieceID )
if err != nil {
service . log . Error ( "unable to delete expired piece info from DB" , zap . Stringer ( "Satellite ID" , expired . SatelliteID ) , zap . Stringer ( "Piece ID" , expired . PieceID ) , zap . Error ( err ) )
continue
}
service . log . Info ( "deleted expired piece info from DB" , zap . Stringer ( "Satellite ID" , expired . SatelliteID ) , zap . Stringer ( "Piece ID" , expired . PieceID ) )
2020-07-21 14:10:46 +01:00
continue
}
2019-08-08 02:47:30 +01:00
errfailed := service . pieces . DeleteFailed ( ctx , expired , now )
2019-05-08 12:11:59 +01:00
if errfailed != nil {
2019-11-05 21:04:07 +00:00
service . log . Error ( "unable to update piece info" , zap . Stringer ( "Satellite ID" , expired . SatelliteID ) , zap . Stringer ( "Piece ID" , expired . PieceID ) , zap . Error ( errfailed ) )
2019-05-08 12:11:59 +01:00
}
2019-11-05 21:04:07 +00:00
service . log . Error ( "unable to delete piece" , zap . Stringer ( "Satellite ID" , expired . SatelliteID ) , zap . Stringer ( "Piece ID" , expired . PieceID ) , zap . Error ( err ) )
2019-05-08 12:11:59 +01:00
continue
}
2022-09-08 12:08:49 +01:00
service . log . Info ( "deleted expired piece" , zap . Stringer ( "Satellite ID" , expired . SatelliteID ) , zap . Stringer ( "Piece ID" , expired . PieceID ) )
2019-05-08 12:11:59 +01:00
count ++
}
}
return nil
}