2512ecb701
New PeerManager, Allocator, Informer components have been added along with a new "replication_factor" configuration option. First, cluster peers collect and push metrics (Informer) to the Cluster leader regularly. The Informer is an interface that can be implemented in custom wayts to support custom metrics. Second, on a pin operation, using the information from the collected metrics, an Allocator can provide a list of preferences as to where the new pin should be assigned. The Allocator is an interface allowing to provide different allocation strategies. Both Allocator and Informer are Cluster Componenets, and have access to the RPC API. The allocations are kept in the shared state. Cluster peer failure detection is still missing and re-allocation is still missing, although re-pinning something when a node is down/metrics missing does re-allocate the pin somewhere else. License: MIT Signed-off-by: Hector Sanjuan <hector@protocol.ai>
110 lines
2.5 KiB
Go
110 lines
2.5 KiB
Go
package ipfscluster
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"github.com/ipfs/ipfs-cluster/api"
|
|
|
|
rpc "github.com/hsanjuan/go-libp2p-gorpc"
|
|
consensus "github.com/libp2p/go-libp2p-consensus"
|
|
peer "github.com/libp2p/go-libp2p-peer"
|
|
ma "github.com/multiformats/go-multiaddr"
|
|
)
|
|
|
|
// Type of consensus operation
|
|
const (
|
|
LogOpPin = iota + 1
|
|
LogOpUnpin
|
|
LogOpAddPeer
|
|
LogOpRmPeer
|
|
)
|
|
|
|
// LogOpType expresses the type of a consensus Operation
|
|
type LogOpType int
|
|
|
|
// LogOp represents an operation for the OpLogConsensus system.
|
|
// It implements the consensus.Op interface and it is used by the
|
|
// Consensus component.
|
|
type LogOp struct {
|
|
Cid api.CidArgSerial
|
|
Peer api.MultiaddrSerial
|
|
Type LogOpType
|
|
ctx context.Context
|
|
rpcClient *rpc.Client
|
|
}
|
|
|
|
// ApplyTo applies the operation to the State
|
|
func (op *LogOp) ApplyTo(cstate consensus.State) (consensus.State, error) {
|
|
state, ok := cstate.(State)
|
|
var err error
|
|
if !ok {
|
|
// Should never be here
|
|
panic("received unexpected state type")
|
|
}
|
|
|
|
switch op.Type {
|
|
case LogOpPin:
|
|
arg := op.Cid.ToCidArg()
|
|
err = state.Add(arg)
|
|
if err != nil {
|
|
goto ROLLBACK
|
|
}
|
|
// Async, we let the PinTracker take care of any problems
|
|
op.rpcClient.Go("",
|
|
"Cluster",
|
|
"Track",
|
|
arg.ToSerial(),
|
|
&struct{}{},
|
|
nil)
|
|
case LogOpUnpin:
|
|
arg := op.Cid.ToCidArg()
|
|
err = state.Rm(arg.Cid)
|
|
if err != nil {
|
|
goto ROLLBACK
|
|
}
|
|
// Async, we let the PinTracker take care of any problems
|
|
op.rpcClient.Go("",
|
|
"Cluster",
|
|
"Untrack",
|
|
arg.ToSerial(),
|
|
&struct{}{},
|
|
nil)
|
|
case LogOpAddPeer:
|
|
addr := op.Peer.ToMultiaddr()
|
|
op.rpcClient.Call("",
|
|
"Cluster",
|
|
"PeerManagerAddPeer",
|
|
api.MultiaddrToSerial(addr),
|
|
&struct{}{})
|
|
// TODO rebalance ops
|
|
case LogOpRmPeer:
|
|
addr := op.Peer.ToMultiaddr()
|
|
pidstr, err := addr.ValueForProtocol(ma.P_IPFS)
|
|
if err != nil {
|
|
panic("peer badly encoded")
|
|
}
|
|
pid, err := peer.IDB58Decode(pidstr)
|
|
if err != nil {
|
|
panic("could not decode a PID we ourselves encoded")
|
|
}
|
|
op.rpcClient.Call("",
|
|
"Cluster",
|
|
"PeerManagerRmPeer",
|
|
pid,
|
|
&struct{}{})
|
|
// TODO rebalance ops
|
|
default:
|
|
logger.Error("unknown LogOp type. Ignoring")
|
|
}
|
|
return state, nil
|
|
|
|
ROLLBACK:
|
|
// We failed to apply the operation to the state
|
|
// and therefore we need to request a rollback to the
|
|
// cluster to the previous state. This operation can only be performed
|
|
// by the cluster leader.
|
|
logger.Error("Rollbacks are not implemented")
|
|
return nil, errors.New("a rollback may be necessary. Reason: " + err.Error())
|
|
}
|