depot/packages/networking/ipfs-cluster/consensus/raft/log_op.go

106 lines
2.4 KiB
Go

package raft
import (
"context"
"errors"
"go.opencensus.io/tag"
"go.opencensus.io/trace"
"github.com/ipfs-cluster/ipfs-cluster/api"
"github.com/ipfs-cluster/ipfs-cluster/state"
consensus "github.com/libp2p/go-libp2p-consensus"
)
// Type of consensus operation
const (
LogOpPin = iota + 1
LogOpUnpin
)
// 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 {
SpanCtx trace.SpanContext `codec:"s,omitempty"`
TagCtx []byte `codec:"t,omitempty"`
Cid api.Pin `codec:"c,omitempty"`
Type LogOpType `codec:"p,omitempty"`
consensus *Consensus `codec:"-"`
tracing bool `codec:"-"`
}
// ApplyTo applies the operation to the State
func (op *LogOp) ApplyTo(cstate consensus.State) (consensus.State, error) {
var err error
ctx := context.Background()
if op.tracing {
tagmap, err := tag.Decode(op.TagCtx)
if err != nil {
logger.Error(err)
}
ctx = tag.NewContext(ctx, tagmap)
var span *trace.Span
ctx, span = trace.StartSpanWithRemoteParent(ctx, "consensus/raft/logop/ApplyTo", op.SpanCtx)
defer span.End()
}
state, ok := cstate.(state.State)
if !ok {
// Should never be here
panic("received unexpected state type")
}
pin := op.Cid
switch op.Type {
case LogOpPin:
err = state.Add(ctx, pin)
if err != nil {
logger.Error(err)
goto ROLLBACK
}
// Async, we let the PinTracker take care of any problems
op.consensus.rpcClient.GoContext(
ctx,
"",
"PinTracker",
"Track",
pin,
&struct{}{},
nil,
)
case LogOpUnpin:
err = state.Rm(ctx, pin.Cid)
if err != nil {
logger.Error(err)
goto ROLLBACK
}
// Async, we let the PinTracker take care of any problems
op.consensus.rpcClient.GoContext(
ctx,
"",
"PinTracker",
"Untrack",
pin,
&struct{}{},
nil,
)
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())
}