2018-10-02 00:25:41 +01:00
|
|
|
// Copyright (C) 2018 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package queue
|
|
|
|
|
|
|
|
import (
|
2018-12-27 09:56:25 +00:00
|
|
|
"context"
|
|
|
|
|
2018-11-20 18:29:07 +00:00
|
|
|
"github.com/gogo/protobuf/proto"
|
2018-11-20 15:54:22 +00:00
|
|
|
"go.uber.org/zap"
|
2018-11-27 15:57:51 +00:00
|
|
|
|
2018-10-02 00:25:41 +01:00
|
|
|
"storj.io/storj/pkg/pb"
|
|
|
|
"storj.io/storj/storage"
|
|
|
|
)
|
|
|
|
|
|
|
|
// RepairQueue is the interface for the data repair queue
|
|
|
|
type RepairQueue interface {
|
2018-12-27 09:56:25 +00:00
|
|
|
Enqueue(ctx context.Context, qi *pb.InjuredSegment) error
|
|
|
|
Dequeue(ctx context.Context) (pb.InjuredSegment, error)
|
|
|
|
Peekqueue(ctx context.Context, limit int) ([]pb.InjuredSegment, error)
|
2018-10-02 00:25:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Queue implements the RepairQueue interface
|
|
|
|
type Queue struct {
|
2018-11-08 13:53:27 +00:00
|
|
|
db storage.Queue
|
2018-10-02 00:25:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewQueue returns a pointer to a new Queue instance with an initialized connection to Redis
|
2018-11-08 13:53:27 +00:00
|
|
|
func NewQueue(client storage.Queue) *Queue {
|
2018-11-20 15:54:22 +00:00
|
|
|
zap.L().Info("Initializing new data repair queue")
|
2018-11-08 13:53:27 +00:00
|
|
|
return &Queue{db: client}
|
2018-10-02 00:25:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Enqueue adds a repair segment to the queue
|
2018-12-27 09:56:25 +00:00
|
|
|
func (q *Queue) Enqueue(ctx context.Context, qi *pb.InjuredSegment) error {
|
2018-10-02 00:25:41 +01:00
|
|
|
val, err := proto.Marshal(qi)
|
|
|
|
if err != nil {
|
2018-10-09 17:09:33 +01:00
|
|
|
return Error.New("error marshalling injured seg %s", err)
|
2018-10-02 00:25:41 +01:00
|
|
|
}
|
2018-11-08 13:53:27 +00:00
|
|
|
|
|
|
|
err = q.db.Enqueue(val)
|
2018-10-02 00:25:41 +01:00
|
|
|
if err != nil {
|
2018-10-09 17:09:33 +01:00
|
|
|
return Error.New("error adding injured seg to queue %s", err)
|
2018-10-02 00:25:41 +01:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dequeue returns the next repair segement and removes it from the queue
|
2018-12-27 09:56:25 +00:00
|
|
|
func (q *Queue) Dequeue(ctx context.Context) (pb.InjuredSegment, error) {
|
2018-11-08 13:53:27 +00:00
|
|
|
val, err := q.db.Dequeue()
|
2018-10-02 00:25:41 +01:00
|
|
|
if err != nil {
|
2018-11-27 15:57:51 +00:00
|
|
|
if err == storage.ErrEmptyQueue {
|
|
|
|
return pb.InjuredSegment{}, err
|
|
|
|
}
|
2018-11-08 13:53:27 +00:00
|
|
|
return pb.InjuredSegment{}, Error.New("error obtaining item from repair queue %s", err)
|
2018-10-02 00:25:41 +01:00
|
|
|
}
|
|
|
|
seg := &pb.InjuredSegment{}
|
|
|
|
err = proto.Unmarshal(val, seg)
|
|
|
|
if err != nil {
|
2018-10-09 17:09:33 +01:00
|
|
|
return pb.InjuredSegment{}, Error.New("error unmarshalling segment %s", err)
|
2018-10-02 00:25:41 +01:00
|
|
|
}
|
|
|
|
return *seg, nil
|
|
|
|
}
|
2018-11-16 13:31:33 +00:00
|
|
|
|
|
|
|
// Peekqueue returns upto 'limit' of the entries from the repair queue
|
2018-12-27 09:56:25 +00:00
|
|
|
func (q *Queue) Peekqueue(ctx context.Context, limit int) ([]pb.InjuredSegment, error) {
|
2018-11-16 13:31:33 +00:00
|
|
|
if limit < 0 || limit > storage.LookupLimit {
|
|
|
|
limit = storage.LookupLimit
|
|
|
|
}
|
|
|
|
result, err := q.db.Peekqueue(limit)
|
|
|
|
if err != nil {
|
|
|
|
return []pb.InjuredSegment{}, Error.New("error peeking into repair queue %s", err)
|
|
|
|
}
|
|
|
|
segs := make([]pb.InjuredSegment, 0)
|
|
|
|
for _, v := range result {
|
|
|
|
seg := &pb.InjuredSegment{}
|
|
|
|
if err = proto.Unmarshal(v, seg); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
segs = append(segs, *seg)
|
|
|
|
}
|
|
|
|
return segs, nil
|
|
|
|
}
|