forked from TrueCloudLab/frostfs-node
[#473] Implement EigenTrust calculations
Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
parent
0ec8bcf6b4
commit
a97e08cfd7
14 changed files with 1112 additions and 3 deletions
69
pkg/services/reputation/eigentrust/controller/calls.go
Normal file
69
pkg/services/reputation/eigentrust/controller/calls.go
Normal file
|
@ -0,0 +1,69 @@
|
|||
package eigentrustctrl
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/nspcc-dev/neofs-node/pkg/services/reputation/eigentrust"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// ContinuePrm groups the required parameters of Continue operation.
|
||||
type ContinuePrm struct {
|
||||
epoch uint64
|
||||
}
|
||||
|
||||
type iterContext struct {
|
||||
context.Context
|
||||
|
||||
eigentrust.EpochIteration
|
||||
|
||||
last bool
|
||||
}
|
||||
|
||||
func (x iterContext) Last() bool {
|
||||
return x.last
|
||||
}
|
||||
|
||||
type iterContextCancel struct {
|
||||
iterContext
|
||||
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
// Continue moves the global reputation calculator to the next iteration.
|
||||
func (c *Controller) Continue(prm ContinuePrm) {
|
||||
c.mtx.Lock()
|
||||
|
||||
{
|
||||
iterCtx, ok := c.mCtx[prm.epoch]
|
||||
if !ok {
|
||||
iterCtx := new(iterContextCancel)
|
||||
c.mCtx[prm.epoch] = iterCtx
|
||||
|
||||
iterCtx.Context, iterCtx.cancel = context.WithCancel(context.Background())
|
||||
} else {
|
||||
iterCtx.cancel()
|
||||
}
|
||||
|
||||
iterCtx.last = iterCtx.I() == c.prm.IterationNumber
|
||||
|
||||
err := c.prm.WorkerPool.Submit(func() {
|
||||
c.prm.DaughtersTrustCalculator.Calculate(iterCtx.iterContext)
|
||||
})
|
||||
if err != nil {
|
||||
c.opts.log.Debug("iteration submit failure",
|
||||
zap.String("error", err.Error()),
|
||||
)
|
||||
}
|
||||
|
||||
if iterCtx.last {
|
||||
delete(c.mCtx, prm.epoch)
|
||||
// In this case and worker pool failure we can mark epoch
|
||||
// number as already processed, but in any case it grows up
|
||||
// during normal operation of the system. Also, such information
|
||||
// will only live while the application is alive.
|
||||
}
|
||||
}
|
||||
|
||||
c.mtx.Unlock()
|
||||
}
|
85
pkg/services/reputation/eigentrust/controller/controller.go
Normal file
85
pkg/services/reputation/eigentrust/controller/controller.go
Normal file
|
@ -0,0 +1,85 @@
|
|||
package eigentrustctrl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/nspcc-dev/neofs-node/pkg/util"
|
||||
)
|
||||
|
||||
// Prm groups the required parameters of the Controller's constructor.
|
||||
//
|
||||
// All values must comply with the requirements imposed on them.
|
||||
// Passing incorrect parameter values will result in constructor
|
||||
// failure (error or panic depending on the implementation).
|
||||
type Prm struct {
|
||||
// Number of iterations
|
||||
IterationNumber uint32
|
||||
|
||||
// Component of computing iteration of EigenTrust algorithm.
|
||||
//
|
||||
// Must not be nil.
|
||||
DaughtersTrustCalculator DaughtersTrustCalculator
|
||||
|
||||
// Routine execution pool for single epoch iteration.
|
||||
WorkerPool util.WorkerPool
|
||||
}
|
||||
|
||||
// Controller represents EigenTrust algorithm transient controller.
|
||||
//
|
||||
// Controller's main goal is to separate the two main stages of
|
||||
// the calculation:
|
||||
// 1.reporting local values to manager nodes
|
||||
// 2.calculating global trusts of child nodes
|
||||
//
|
||||
// Calculation stages are controlled based on external signals
|
||||
// that come from the application through the Controller's API.
|
||||
//
|
||||
// For correct operation, the controller must be created
|
||||
// using the constructor (New) based on the required parameters
|
||||
// and optional components. After successful creation,
|
||||
// the constructor is immediately ready to work through
|
||||
// API of external control of calculations and data transfer.
|
||||
type Controller struct {
|
||||
prm Prm
|
||||
|
||||
opts *options
|
||||
|
||||
mtx sync.Mutex
|
||||
mCtx map[uint64]*iterContextCancel
|
||||
}
|
||||
|
||||
const invalidPrmValFmt = "invalid parameter %s (%T):%v"
|
||||
|
||||
func panicOnPrmValue(n string, v interface{}) {
|
||||
panic(fmt.Sprintf(invalidPrmValFmt, n, v, v))
|
||||
}
|
||||
|
||||
// New creates a new instance of the Controller.
|
||||
//
|
||||
// Panics if at least one value of the parameters is invalid.
|
||||
//
|
||||
// The created Controller does not require additional
|
||||
// initialization and is completely ready for work.
|
||||
func New(prm Prm, opts ...Option) *Controller {
|
||||
switch {
|
||||
case prm.IterationNumber == 0:
|
||||
panicOnPrmValue("IterationNumber", prm.IterationNumber)
|
||||
case prm.WorkerPool == nil:
|
||||
panicOnPrmValue("WorkerPool", prm.WorkerPool)
|
||||
case prm.DaughtersTrustCalculator == nil:
|
||||
panicOnPrmValue("DaughtersTrustCalculator", prm.DaughtersTrustCalculator)
|
||||
}
|
||||
|
||||
o := defaultOpts()
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(o)
|
||||
}
|
||||
|
||||
return &Controller{
|
||||
prm: prm,
|
||||
opts: o,
|
||||
mCtx: make(map[uint64]*iterContextCancel),
|
||||
}
|
||||
}
|
35
pkg/services/reputation/eigentrust/controller/deps.go
Normal file
35
pkg/services/reputation/eigentrust/controller/deps.go
Normal file
|
@ -0,0 +1,35 @@
|
|||
package eigentrustctrl
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// IterationContext is a context of the i-th
|
||||
// stage of iterative EigenTrust algorithm.
|
||||
type IterationContext interface {
|
||||
context.Context
|
||||
|
||||
// Must return epoch number to select the values
|
||||
// for global trust calculation.
|
||||
Epoch() uint64
|
||||
|
||||
// Must return the sequence number of the iteration.
|
||||
I() uint32
|
||||
|
||||
// Must return true if I() is the last iteration.
|
||||
Last() bool
|
||||
}
|
||||
|
||||
// DaughtersTrustCalculator is an interface of entity
|
||||
// responsible for calculating the global trust of
|
||||
// daughter nodes in terms of EigenTrust algorithm.
|
||||
type DaughtersTrustCalculator interface {
|
||||
// Must perform the iteration step of the loop
|
||||
// for computing the global trust of all daughter
|
||||
// nodes and sending intermediate values
|
||||
// according to EigenTrust description
|
||||
// http://ilpubs.stanford.edu:8090/562/1/2002-56.pdf Ch.5.1.
|
||||
//
|
||||
// Execution should be interrupted if ctx.Last().
|
||||
Calculate(ctx IterationContext)
|
||||
}
|
30
pkg/services/reputation/eigentrust/controller/opts.go
Normal file
30
pkg/services/reputation/eigentrust/controller/opts.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
package eigentrustctrl
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neofs-node/pkg/util/logger"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// Option sets an optional parameter of Controller.
|
||||
type Option func(*options)
|
||||
|
||||
type options struct {
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func defaultOpts() *options {
|
||||
return &options{
|
||||
log: zap.L(),
|
||||
}
|
||||
}
|
||||
|
||||
// WithLogger returns option to specify logging component.
|
||||
//
|
||||
// Ignores nil values.
|
||||
func WithLogger(l *logger.Logger) Option {
|
||||
return func(o *options) {
|
||||
if l != nil {
|
||||
o.log = l
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue