b6a46cd8a4
The new "metrics" allocator is about to partition metrics and distribe allocations among the partitions. For example: given a region, an availability zone and free space on disk, the allocator would be able to choose allocations by distributing among regions and availability zones as much as possible, and for those peers in the same region/az, selecting those with most free space first. This requires a major overhaul of the allocator component.
152 lines
3.3 KiB
Go
152 lines
3.3 KiB
Go
// Package disk implements an ipfs-cluster informer which can provide different
|
|
// disk-related metrics from the IPFS daemon as an api.Metric.
|
|
package disk
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/ipfs/ipfs-cluster/allocator/metrics"
|
|
"github.com/ipfs/ipfs-cluster/allocator/sorter"
|
|
"github.com/ipfs/ipfs-cluster/api"
|
|
|
|
logging "github.com/ipfs/go-log/v2"
|
|
rpc "github.com/libp2p/go-libp2p-gorpc"
|
|
|
|
"go.opencensus.io/trace"
|
|
)
|
|
|
|
// MetricType identifies the type of metric to fetch from the IPFS daemon.
|
|
type MetricType int
|
|
|
|
const (
|
|
// MetricFreeSpace provides the available space reported by IPFS
|
|
MetricFreeSpace MetricType = iota
|
|
// MetricRepoSize provides the used space reported by IPFS
|
|
MetricRepoSize
|
|
)
|
|
|
|
// String returns a string representation for MetricType.
|
|
func (t MetricType) String() string {
|
|
switch t {
|
|
case MetricFreeSpace:
|
|
return "freespace"
|
|
case MetricRepoSize:
|
|
return "reposize"
|
|
}
|
|
return ""
|
|
}
|
|
|
|
var logger = logging.Logger("diskinfo")
|
|
|
|
func init() {
|
|
metrics.RegisterInformer(MetricFreeSpace.String(), sorter.SortNumericReverse, false)
|
|
metrics.RegisterInformer(MetricRepoSize.String(), sorter.SortNumeric, false)
|
|
}
|
|
|
|
// Informer is a simple object to implement the ipfscluster.Informer
|
|
// and Component interfaces.
|
|
type Informer struct {
|
|
config *Config // set when created, readonly
|
|
|
|
mu sync.Mutex // guards access to following fields
|
|
rpcClient *rpc.Client
|
|
}
|
|
|
|
// NewInformer returns an initialized informer using the given InformerConfig.
|
|
func NewInformer(cfg *Config) (*Informer, error) {
|
|
err := cfg.Validate()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &Informer{
|
|
config: cfg,
|
|
}, nil
|
|
}
|
|
|
|
// Name returns the name of the metric issued by this informer.
|
|
func (disk *Informer) Name() string {
|
|
return disk.config.MetricType.String()
|
|
}
|
|
|
|
// SetClient provides us with an rpc.Client which allows
|
|
// contacting other components in the cluster.
|
|
func (disk *Informer) SetClient(c *rpc.Client) {
|
|
disk.mu.Lock()
|
|
defer disk.mu.Unlock()
|
|
disk.rpcClient = c
|
|
}
|
|
|
|
// Shutdown is called on cluster shutdown. We just invalidate
|
|
// any metrics from this point.
|
|
func (disk *Informer) Shutdown(ctx context.Context) error {
|
|
_, span := trace.StartSpan(ctx, "informer/disk/Shutdown")
|
|
defer span.End()
|
|
|
|
disk.mu.Lock()
|
|
defer disk.mu.Unlock()
|
|
|
|
disk.rpcClient = nil
|
|
return nil
|
|
}
|
|
|
|
// GetMetric returns the metric obtained by this
|
|
// Informer.
|
|
func (disk *Informer) GetMetric(ctx context.Context) *api.Metric {
|
|
ctx, span := trace.StartSpan(ctx, "informer/disk/GetMetric")
|
|
defer span.End()
|
|
|
|
disk.mu.Lock()
|
|
rpcClient := disk.rpcClient
|
|
disk.mu.Unlock()
|
|
|
|
if rpcClient == nil {
|
|
return &api.Metric{
|
|
Name: disk.Name(),
|
|
Valid: false,
|
|
}
|
|
}
|
|
|
|
var repoStat api.IPFSRepoStat
|
|
var metric uint64
|
|
|
|
valid := true
|
|
|
|
err := rpcClient.CallContext(
|
|
ctx,
|
|
"",
|
|
"IPFSConnector",
|
|
"RepoStat",
|
|
struct{}{},
|
|
&repoStat,
|
|
)
|
|
if err != nil {
|
|
logger.Error(err)
|
|
valid = false
|
|
} else {
|
|
switch disk.config.MetricType {
|
|
case MetricFreeSpace:
|
|
size := repoStat.RepoSize
|
|
total := repoStat.StorageMax
|
|
if size < total {
|
|
metric = total - size
|
|
} else { // Make sure we don't underflow
|
|
metric = 0
|
|
}
|
|
case MetricRepoSize:
|
|
metric = repoStat.RepoSize
|
|
}
|
|
}
|
|
|
|
m := &api.Metric{
|
|
Name: disk.Name(),
|
|
Value: fmt.Sprintf("%d", metric),
|
|
Valid: valid,
|
|
}
|
|
|
|
m.SetTTL(disk.config.MetricTTL)
|
|
return m
|
|
}
|