2019-11-26 16:25:21 +00:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package pieces
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2022-12-15 17:52:05 +00:00
|
|
|
"sync"
|
2019-11-26 16:25:21 +00:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"go.uber.org/zap"
|
|
|
|
|
2022-12-15 17:52:05 +00:00
|
|
|
"storj.io/common/storj"
|
2019-12-27 11:48:47 +00:00
|
|
|
"storj.io/common/sync2"
|
2019-11-26 16:25:21 +00:00
|
|
|
"storj.io/storj/storagenode/trust"
|
|
|
|
)
|
|
|
|
|
2020-07-16 15:18:02 +01:00
|
|
|
// TrashChore is the chore that periodically empties the trash.
|
2019-11-26 16:25:21 +00:00
|
|
|
type TrashChore struct {
|
|
|
|
log *zap.Logger
|
|
|
|
trashExpiryInterval time.Duration
|
|
|
|
store *Store
|
|
|
|
trust *trust.Pool
|
2022-12-15 17:52:05 +00:00
|
|
|
|
|
|
|
Cycle *sync2.Cycle
|
|
|
|
|
2022-12-16 16:14:17 +00:00
|
|
|
started sync2.Fence
|
|
|
|
root context.Context
|
|
|
|
|
|
|
|
mu sync.Mutex
|
|
|
|
done bool
|
|
|
|
satellites map[storj.NodeID]*sync2.Workplace
|
2019-11-26 16:25:21 +00:00
|
|
|
}
|
|
|
|
|
2022-12-16 16:14:17 +00:00
|
|
|
const (
|
|
|
|
jobEmptyTrash = 1
|
|
|
|
jobRestoreTrash = 2
|
|
|
|
)
|
|
|
|
|
2019-11-26 16:25:21 +00:00
|
|
|
// NewTrashChore instantiates a new TrashChore. choreInterval is how often this
|
|
|
|
// chore runs, and trashExpiryInterval is passed into the EmptyTrash method to
|
2020-07-16 15:18:02 +01:00
|
|
|
// determine which trashed pieces should be deleted.
|
2019-11-26 16:25:21 +00:00
|
|
|
func NewTrashChore(log *zap.Logger, choreInterval, trashExpiryInterval time.Duration, trust *trust.Pool, store *Store) *TrashChore {
|
|
|
|
return &TrashChore{
|
|
|
|
log: log,
|
|
|
|
trashExpiryInterval: trashExpiryInterval,
|
|
|
|
store: store,
|
|
|
|
trust: trust,
|
2022-12-15 17:52:05 +00:00
|
|
|
|
2022-12-16 16:14:17 +00:00
|
|
|
Cycle: sync2.NewCycle(choreInterval),
|
|
|
|
satellites: map[storj.NodeID]*sync2.Workplace{},
|
2019-11-26 16:25:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-16 15:18:02 +01:00
|
|
|
// Run starts the cycle.
|
2019-11-26 16:25:21 +00:00
|
|
|
func (chore *TrashChore) Run(ctx context.Context) (err error) {
|
|
|
|
defer mon.Task()(&ctx)(&err)
|
|
|
|
|
2022-12-16 16:14:17 +00:00
|
|
|
chore.root = ctx
|
|
|
|
chore.started.Release()
|
2019-11-26 16:25:21 +00:00
|
|
|
|
2022-12-16 16:14:17 +00:00
|
|
|
err = chore.Cycle.Run(ctx, func(ctx context.Context) error {
|
|
|
|
chore.log.Debug("starting to empty trash")
|
2022-12-15 17:52:05 +00:00
|
|
|
|
2022-12-16 16:14:17 +00:00
|
|
|
var wg sync.WaitGroup
|
|
|
|
limiter := make(chan struct{}, 1)
|
|
|
|
for _, satellite := range chore.trust.GetSatellites(ctx) {
|
|
|
|
satellite := satellite
|
|
|
|
place := chore.ensurePlace(satellite)
|
|
|
|
wg.Add(1)
|
|
|
|
ok := place.Start(chore.root, jobEmptyTrash, nil, func(ctx context.Context) {
|
|
|
|
defer wg.Done()
|
|
|
|
// don't allow multiple trash jobs at the same time
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return
|
|
|
|
case limiter <- struct{}{}:
|
|
|
|
}
|
|
|
|
defer func() { <-limiter }()
|
|
|
|
|
2023-01-17 09:04:47 +00:00
|
|
|
chore.log.Info("emptying trash started", zap.Stringer("Satellite ID", satellite))
|
2022-12-16 16:14:17 +00:00
|
|
|
trashedBefore := time.Now().Add(-chore.trashExpiryInterval)
|
|
|
|
err := chore.store.EmptyTrash(ctx, satellite, trashedBefore)
|
|
|
|
if err != nil {
|
|
|
|
chore.log.Error("emptying trash failed", zap.Error(err))
|
|
|
|
}
|
|
|
|
})
|
|
|
|
if !ok {
|
|
|
|
wg.Done()
|
2019-11-26 16:25:21 +00:00
|
|
|
}
|
|
|
|
}
|
2022-12-16 16:14:17 +00:00
|
|
|
wg.Wait()
|
2019-11-26 16:25:21 +00:00
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
2022-12-15 17:52:05 +00:00
|
|
|
chore.mu.Lock()
|
2022-12-16 16:14:17 +00:00
|
|
|
chore.done = true
|
2022-12-15 17:52:05 +00:00
|
|
|
chore.mu.Unlock()
|
|
|
|
|
2022-12-16 16:14:17 +00:00
|
|
|
for _, place := range chore.satellites {
|
|
|
|
place.Cancel()
|
2022-12-15 17:52:05 +00:00
|
|
|
}
|
2022-12-16 16:14:17 +00:00
|
|
|
for _, place := range chore.satellites {
|
|
|
|
<-place.Done()
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
2019-11-26 16:25:21 +00:00
|
|
|
}
|
|
|
|
|
2022-12-16 16:14:17 +00:00
|
|
|
// Close closes the chore.
|
2019-11-26 16:25:21 +00:00
|
|
|
func (chore *TrashChore) Close() error {
|
2022-12-15 17:52:05 +00:00
|
|
|
chore.Cycle.Close()
|
2019-11-26 16:25:21 +00:00
|
|
|
return nil
|
|
|
|
}
|
2022-12-15 17:52:05 +00:00
|
|
|
|
2022-12-16 16:14:17 +00:00
|
|
|
// StartRestore starts a satellite restore, if it hasn't already started and
|
|
|
|
// the chore is not shutting down.
|
|
|
|
func (chore *TrashChore) StartRestore(ctx context.Context, satellite storj.NodeID) error {
|
|
|
|
if !chore.started.Wait(ctx) {
|
|
|
|
return ctx.Err()
|
|
|
|
}
|
2022-12-15 17:52:05 +00:00
|
|
|
|
2022-12-16 16:14:17 +00:00
|
|
|
place := chore.ensurePlace(satellite)
|
|
|
|
if place == nil {
|
|
|
|
return context.Canceled
|
|
|
|
}
|
2022-12-15 17:52:05 +00:00
|
|
|
|
2022-12-16 16:14:17 +00:00
|
|
|
place.Start(chore.root, jobRestoreTrash, func(jobID interface{}) bool {
|
|
|
|
return jobID == jobEmptyTrash
|
|
|
|
}, func(ctx context.Context) {
|
|
|
|
chore.log.Info("restore trash started", zap.Stringer("Satellite ID", satellite))
|
|
|
|
err := chore.store.RestoreTrash(ctx, satellite)
|
|
|
|
if err != nil {
|
|
|
|
chore.log.Error("restore trash failed", zap.Stringer("Satellite ID", satellite), zap.Error(err))
|
|
|
|
} else {
|
|
|
|
chore.log.Info("restore trash finished", zap.Stringer("Satellite ID", satellite))
|
|
|
|
}
|
|
|
|
})
|
2022-12-15 17:52:05 +00:00
|
|
|
|
2022-12-16 16:14:17 +00:00
|
|
|
return nil
|
2022-12-15 17:52:05 +00:00
|
|
|
}
|
|
|
|
|
2022-12-16 16:14:17 +00:00
|
|
|
// ensurePlace creates a work place for the specified satellite.
|
|
|
|
func (chore *TrashChore) ensurePlace(satellite storj.NodeID) *sync2.Workplace {
|
|
|
|
chore.mu.Lock()
|
|
|
|
defer chore.mu.Unlock()
|
|
|
|
if chore.done {
|
|
|
|
return nil
|
2022-12-15 17:52:05 +00:00
|
|
|
}
|
|
|
|
|
2022-12-16 16:14:17 +00:00
|
|
|
place, ok := chore.satellites[satellite]
|
|
|
|
if !ok {
|
|
|
|
place = sync2.NewWorkPlace()
|
|
|
|
chore.satellites[satellite] = place
|
2022-12-15 17:52:05 +00:00
|
|
|
}
|
2022-12-16 16:14:17 +00:00
|
|
|
return place
|
2022-12-15 17:52:05 +00:00
|
|
|
}
|