4daece2b98
This new component broadcasts metrics about the current size of the pinqueue, which can in turn be used to inform allocations. It has a weight_bucket_size option that serves to divide the actual size by a given factor. This allows considering peers with similar queue sizes to have the same weight. Additionally, some changes have been made to the balanced allocator so that a combination of tags, pinqueue sizes and free-spaces can be used. When allocating by [<tag>, pinqueue, freespace], the allocator will prioritize choosing peers with the smallest pin queue weight first, and of those with the same weight, it will allocate based on freespace.
111 lines
2.2 KiB
Go
111 lines
2.2 KiB
Go
// Package pinqueue implements an ipfs-cluster informer which issues the
|
|
// current size of the pinning queue.
|
|
package pinqueue
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/ipfs/ipfs-cluster/api"
|
|
|
|
rpc "github.com/libp2p/go-libp2p-gorpc"
|
|
|
|
"go.opencensus.io/trace"
|
|
)
|
|
|
|
// MetricName specifies the name of our metric
|
|
var MetricName = "pinqueue"
|
|
|
|
// Informer is a simple object to implement the ipfscluster.Informer
|
|
// and Component interfaces
|
|
type Informer struct {
|
|
config *Config
|
|
|
|
mu sync.Mutex
|
|
rpcClient *rpc.Client
|
|
}
|
|
|
|
// New returns an initialized Informer.
|
|
func New(cfg *Config) (*Informer, error) {
|
|
err := cfg.Validate()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &Informer{
|
|
config: cfg,
|
|
}, nil
|
|
}
|
|
|
|
// SetClient provides us with an rpc.Client which allows
|
|
// contacting other components in the cluster.
|
|
func (inf *Informer) SetClient(c *rpc.Client) {
|
|
inf.mu.Lock()
|
|
inf.rpcClient = c
|
|
inf.mu.Unlock()
|
|
}
|
|
|
|
// Shutdown is called on cluster shutdown. We just invalidate
|
|
// any metrics from this point.
|
|
func (inf *Informer) Shutdown(ctx context.Context) error {
|
|
_, span := trace.StartSpan(ctx, "informer/numpin/Shutdown")
|
|
defer span.End()
|
|
|
|
inf.mu.Lock()
|
|
inf.rpcClient = nil
|
|
inf.mu.Unlock()
|
|
return nil
|
|
}
|
|
|
|
// Name returns the name of this informer
|
|
func (inf *Informer) Name() string {
|
|
return MetricName
|
|
}
|
|
|
|
// GetMetrics contacts the Pintracker component and requests the number of
|
|
// queued items for pinning.
|
|
func (inf *Informer) GetMetrics(ctx context.Context) []api.Metric {
|
|
ctx, span := trace.StartSpan(ctx, "informer/pinqueue/GetMetric")
|
|
defer span.End()
|
|
|
|
inf.mu.Lock()
|
|
rpcClient := inf.rpcClient
|
|
inf.mu.Unlock()
|
|
|
|
if rpcClient == nil {
|
|
return []api.Metric{
|
|
{
|
|
Valid: false,
|
|
},
|
|
}
|
|
}
|
|
|
|
var queued int64
|
|
|
|
err := rpcClient.CallContext(
|
|
ctx,
|
|
"",
|
|
"PinTracker",
|
|
"PinQueueSize",
|
|
struct{}{},
|
|
&queued,
|
|
)
|
|
valid := err == nil
|
|
weight := -queued // smaller pin queues have more priority
|
|
if div := inf.config.WeightBucketSize; div > 0 {
|
|
weight = weight / int64(div)
|
|
}
|
|
|
|
m := api.Metric{
|
|
Name: MetricName,
|
|
Value: fmt.Sprintf("%d", queued),
|
|
Valid: valid,
|
|
Partitionable: false,
|
|
Weight: weight,
|
|
}
|
|
|
|
m.SetTTL(inf.config.MetricTTL)
|
|
return []api.Metric{m}
|
|
}
|