statemachine: Better naming
This commit is contained in:
parent
2fea9433d8
commit
2ef8c1ae0c
@ -10,7 +10,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/actors"
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
"github.com/filecoin-project/lotus/chain/blocksync"
|
"github.com/filecoin-project/lotus/chain/blocksync"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/lib/evtsm"
|
"github.com/filecoin-project/lotus/lib/statemachine"
|
||||||
"github.com/filecoin-project/lotus/paych"
|
"github.com/filecoin-project/lotus/paych"
|
||||||
"github.com/filecoin-project/lotus/storage"
|
"github.com/filecoin-project/lotus/storage"
|
||||||
)
|
)
|
||||||
@ -133,9 +133,9 @@ func main() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = gen.WriteMapEncodersToFile("./lib/evtsm/cbor_gen.go", "evtsm",
|
err = gen.WriteMapEncodersToFile("./lib/statemachine/cbor_gen.go", "statemachine",
|
||||||
evtsm.TestState{},
|
statemachine.TestState{},
|
||||||
evtsm.TestEvent{},
|
statemachine.TestEvent{},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("%+v\n", err)
|
fmt.Printf("%+v\n", err)
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
package evtsm
|
|
||||||
|
|
||||||
type Event struct {
|
|
||||||
User interface{}
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
package evtsm
|
package statemachine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
@ -1,4 +1,4 @@
|
|||||||
package evtsm
|
package statemachine
|
||||||
|
|
||||||
import "context"
|
import "context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package evtsm
|
package statemachine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -15,43 +15,49 @@ type StateHandler interface {
|
|||||||
Plan(events []Event, user interface{}) (interface{}, error)
|
Plan(events []Event, user interface{}) (interface{}, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Sched struct {
|
// StateGroup manages a group of state machines sharing the same logic
|
||||||
|
type StateGroup struct {
|
||||||
sts *statestore.StateStore
|
sts *statestore.StateStore
|
||||||
hnd StateHandler
|
hnd StateHandler
|
||||||
stateType reflect.Type
|
stateType reflect.Type
|
||||||
|
|
||||||
lk sync.Mutex
|
lk sync.Mutex
|
||||||
sms map[datastore.Key]*ESm
|
sms map[datastore.Key]*StateMachine
|
||||||
}
|
}
|
||||||
|
|
||||||
// stateType: T - (reflect.TypeOf(MyStateStruct{}))
|
// stateType: T - (reflect.TypeOf(MyStateStruct{}))
|
||||||
func New(ds datastore.Datastore, hnd StateHandler, stateType reflect.Type) *Sched {
|
func New(ds datastore.Datastore, hnd StateHandler, stateType reflect.Type) *StateGroup {
|
||||||
return &Sched{
|
return &StateGroup{
|
||||||
sts: statestore.New(ds),
|
sts: statestore.New(ds),
|
||||||
hnd: hnd,
|
hnd: hnd,
|
||||||
stateType: stateType,
|
stateType: stateType,
|
||||||
|
|
||||||
sms: map[datastore.Key]*ESm{},
|
sms: map[datastore.Key]*StateMachine{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Sched) Send(to interface{}, evt interface{}) (err error) {
|
// Send sends an event to machine identified by `id`.
|
||||||
|
// `evt` is going to be passed into StateHandler.Planner, in the events[].User param
|
||||||
|
//
|
||||||
|
// If a state machine with the specified id doesn't exits, it's created, and it's
|
||||||
|
// state is set to zero-value of stateType provided in group constructor
|
||||||
|
func (s *StateGroup) Send(id interface{}, evt interface{}) (err error) {
|
||||||
s.lk.Lock()
|
s.lk.Lock()
|
||||||
defer s.lk.Unlock()
|
defer s.lk.Unlock()
|
||||||
|
|
||||||
sm, exist := s.sms[statestore.ToKey(to)]
|
sm, exist := s.sms[statestore.ToKey(id)]
|
||||||
if !exist {
|
if !exist {
|
||||||
sm, err = s.loadOrCreate(to)
|
sm, err = s.loadOrCreate(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("loadOrCreate state: %w", err)
|
return xerrors.Errorf("loadOrCreate state: %w", err)
|
||||||
}
|
}
|
||||||
s.sms[statestore.ToKey(to)] = sm
|
s.sms[statestore.ToKey(id)] = sm
|
||||||
}
|
}
|
||||||
|
|
||||||
return sm.send(Event{User: evt})
|
return sm.send(Event{User: evt})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Sched) loadOrCreate(name interface{}) (*ESm, error) {
|
func (s *StateGroup) loadOrCreate(name interface{}) (*StateMachine, error) {
|
||||||
exists, err := s.sts.Has(name)
|
exists, err := s.sts.Has(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to check if state for %v exists: %w", name, err)
|
return nil, xerrors.Errorf("failed to check if state for %v exists: %w", name, err)
|
||||||
@ -66,7 +72,7 @@ func (s *Sched) loadOrCreate(name interface{}) (*ESm, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res := &ESm{
|
res := &StateMachine{
|
||||||
planner: s.hnd.Plan,
|
planner: s.hnd.Plan,
|
||||||
eventsIn: make(chan Event),
|
eventsIn: make(chan Event),
|
||||||
|
|
||||||
@ -84,7 +90,8 @@ func (s *Sched) loadOrCreate(name interface{}) (*ESm, error) {
|
|||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Sched) Stop(ctx context.Context) error {
|
// Stop stops all state machines in this group
|
||||||
|
func (s *StateGroup) Stop(ctx context.Context) error {
|
||||||
s.lk.Lock()
|
s.lk.Lock()
|
||||||
defer s.lk.Unlock()
|
defer s.lk.Unlock()
|
||||||
|
|
||||||
@ -97,10 +104,13 @@ func (s *Sched) Stop(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Sched) List(out interface{}) error {
|
// List outputs states of all state machines in this group
|
||||||
|
// out: *[]StateT
|
||||||
|
func (s *StateGroup) List(out interface{}) error {
|
||||||
return s.sts.List(out)
|
return s.sts.List(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Sched) Get(i interface{}) *statestore.StoredState {
|
// Get gets state for a single state machine
|
||||||
return s.sts.Get(i)
|
func (s *StateGroup) Get(id interface{}) *statestore.StoredState {
|
||||||
|
return s.sts.Get(id)
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package evtsm
|
package statemachine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -12,10 +12,14 @@ import (
|
|||||||
|
|
||||||
var log = logging.Logger("evtsm")
|
var log = logging.Logger("evtsm")
|
||||||
|
|
||||||
|
type Event struct {
|
||||||
|
User interface{}
|
||||||
|
}
|
||||||
|
|
||||||
// returns func(ctx Context, st <T>) (func(*<T>), error), where <T> is the typeOf(User) param
|
// returns func(ctx Context, st <T>) (func(*<T>), error), where <T> is the typeOf(User) param
|
||||||
type Planner func(events []Event, user interface{}) (interface{}, error)
|
type Planner func(events []Event, user interface{}) (interface{}, error)
|
||||||
|
|
||||||
type ESm struct {
|
type StateMachine struct {
|
||||||
planner Planner
|
planner Planner
|
||||||
eventsIn chan Event
|
eventsIn chan Event
|
||||||
|
|
||||||
@ -30,7 +34,7 @@ type ESm struct {
|
|||||||
busy int32
|
busy int32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fsm *ESm) run() {
|
func (fsm *StateMachine) run() {
|
||||||
defer close(fsm.closed)
|
defer close(fsm.closed)
|
||||||
|
|
||||||
var pendingEvents []Event
|
var pendingEvents []Event
|
||||||
@ -93,7 +97,7 @@ func (fsm *ESm) run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fsm *ESm) mutateUser(cb func(user interface{}) error) error {
|
func (fsm *StateMachine) mutateUser(cb func(user interface{}) error) error {
|
||||||
mutt := reflect.FuncOf([]reflect.Type{reflect.PtrTo(fsm.stateType)}, []reflect.Type{reflect.TypeOf(new(error)).Elem()}, false)
|
mutt := reflect.FuncOf([]reflect.Type{reflect.PtrTo(fsm.stateType)}, []reflect.Type{reflect.TypeOf(new(error)).Elem()}, false)
|
||||||
|
|
||||||
mutf := reflect.MakeFunc(mutt, func(args []reflect.Value) (results []reflect.Value) {
|
mutf := reflect.MakeFunc(mutt, func(args []reflect.Value) (results []reflect.Value) {
|
||||||
@ -104,12 +108,12 @@ func (fsm *ESm) mutateUser(cb func(user interface{}) error) error {
|
|||||||
return fsm.st.Mutate(mutf.Interface())
|
return fsm.st.Mutate(mutf.Interface())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fsm *ESm) send(evt Event) error {
|
func (fsm *StateMachine) send(evt Event) error {
|
||||||
fsm.eventsIn <- evt // TODO: ctx, at least
|
fsm.eventsIn <- evt // TODO: ctx, at least
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fsm *ESm) stop(ctx context.Context) error {
|
func (fsm *StateMachine) stop(ctx context.Context) error {
|
||||||
close(fsm.closing)
|
close(fsm.closing)
|
||||||
|
|
||||||
select {
|
select {
|
@ -1,4 +1,4 @@
|
|||||||
package evtsm
|
package statemachine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
@ -1,4 +1,4 @@
|
|||||||
package evtsm
|
package statemachine
|
||||||
|
|
||||||
type TestState struct {
|
type TestState struct {
|
||||||
A uint64
|
A uint64
|
@ -22,7 +22,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/gen"
|
"github.com/filecoin-project/lotus/chain/gen"
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/lib/evtsm"
|
"github.com/filecoin-project/lotus/lib/statemachine"
|
||||||
)
|
)
|
||||||
|
|
||||||
var log = logging.Logger("storageminer")
|
var log = logging.Logger("storageminer")
|
||||||
@ -39,7 +39,7 @@ type Miner struct {
|
|||||||
|
|
||||||
// Sealing
|
// Sealing
|
||||||
sb SectorBuilder
|
sb SectorBuilder
|
||||||
sectors *evtsm.Sched
|
sectors *statemachine.StateGroup
|
||||||
tktFn TicketFn
|
tktFn TicketFn
|
||||||
|
|
||||||
sectorIncoming chan *SectorInfo
|
sectorIncoming chan *SectorInfo
|
||||||
@ -104,7 +104,7 @@ func NewMiner(api storageMinerApi, addr address.Address, h host.Host, ds datasto
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: separate sector stuff from miner struct
|
// TODO: separate sector stuff from miner struct
|
||||||
m.sectors = evtsm.New(namespace.Wrap(ds, datastore.NewKey(SectorStorePrefix)), m, reflect.TypeOf(SectorInfo{}))
|
m.sectors = statemachine.New(namespace.Wrap(ds, datastore.NewKey(SectorStorePrefix)), m, reflect.TypeOf(SectorInfo{}))
|
||||||
|
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/lib/evtsm"
|
"github.com/filecoin-project/lotus/lib/statemachine"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SectorStart struct {
|
type SectorStart struct {
|
||||||
@ -53,13 +53,13 @@ type SectorForceState struct {
|
|||||||
state api.SectorState
|
state api.SectorState
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Miner) Plan(events []evtsm.Event, user interface{}) (interface{}, error) {
|
func (m *Miner) Plan(events []statemachine.Event, user interface{}) (interface{}, error) {
|
||||||
next, err := m.plan(events, user.(*SectorInfo))
|
next, err := m.plan(events, user.(*SectorInfo))
|
||||||
if err != nil || next == nil {
|
if err != nil || next == nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return func(ctx evtsm.Context, si SectorInfo) error {
|
return func(ctx statemachine.Context, si SectorInfo) error {
|
||||||
err := next(ctx, si)
|
err := next(ctx, si)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err := ctx.Send(SectorFatalError{error: err}); err != nil {
|
if err := ctx.Send(SectorFatalError{error: err}); err != nil {
|
||||||
@ -71,7 +71,7 @@ func (m *Miner) Plan(events []evtsm.Event, user interface{}) (interface{}, error
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Miner) plan(events []evtsm.Event, state *SectorInfo) (func(evtsm.Context, SectorInfo) error, error) {
|
func (m *Miner) plan(events []statemachine.Event, state *SectorInfo) (func(statemachine.Context, SectorInfo) error, error) {
|
||||||
/////
|
/////
|
||||||
// First process all events
|
// First process all events
|
||||||
|
|
||||||
|
@ -9,10 +9,10 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/actors"
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/lib/evtsm"
|
"github.com/filecoin-project/lotus/lib/statemachine"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (m *Miner) handlePacking(ctx evtsm.Context, sector SectorInfo) error {
|
func (m *Miner) handlePacking(ctx statemachine.Context, sector SectorInfo) error {
|
||||||
log.Infow("performing filling up rest of the sector...", "sector", sector.SectorID)
|
log.Infow("performing filling up rest of the sector...", "sector", sector.SectorID)
|
||||||
|
|
||||||
var allocated uint64
|
var allocated uint64
|
||||||
@ -43,7 +43,7 @@ func (m *Miner) handlePacking(ctx evtsm.Context, sector SectorInfo) error {
|
|||||||
return ctx.Send(SectorPacked{pieces: pieces})
|
return ctx.Send(SectorPacked{pieces: pieces})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Miner) handleUnsealed(ctx evtsm.Context, sector SectorInfo) error {
|
func (m *Miner) handleUnsealed(ctx statemachine.Context, sector SectorInfo) error {
|
||||||
log.Infow("performing sector replication...", "sector", sector.SectorID)
|
log.Infow("performing sector replication...", "sector", sector.SectorID)
|
||||||
ticket, err := m.tktFn(ctx.Context())
|
ticket, err := m.tktFn(ctx.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -65,7 +65,7 @@ func (m *Miner) handleUnsealed(ctx evtsm.Context, sector SectorInfo) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Miner) handlePreCommitting(ctx evtsm.Context, sector SectorInfo) error {
|
func (m *Miner) handlePreCommitting(ctx statemachine.Context, sector SectorInfo) error {
|
||||||
params := &actors.SectorPreCommitInfo{
|
params := &actors.SectorPreCommitInfo{
|
||||||
SectorNumber: sector.SectorID,
|
SectorNumber: sector.SectorID,
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ func (m *Miner) handlePreCommitting(ctx evtsm.Context, sector SectorInfo) error
|
|||||||
return ctx.Send(SectorPreCommitted{message: smsg.Cid()})
|
return ctx.Send(SectorPreCommitted{message: smsg.Cid()})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Miner) handlePreCommitted(ctx evtsm.Context, sector SectorInfo) error {
|
func (m *Miner) handlePreCommitted(ctx statemachine.Context, sector SectorInfo) error {
|
||||||
// would be ideal to just use the events.Called handler, but it wouldnt be able to handle individual message timeouts
|
// would be ideal to just use the events.Called handler, but it wouldnt be able to handle individual message timeouts
|
||||||
log.Info("Sector precommitted: ", sector.SectorID)
|
log.Info("Sector precommitted: ", sector.SectorID)
|
||||||
mw, err := m.api.StateWaitMsg(ctx.Context(), *sector.PreCommitMessage)
|
mw, err := m.api.StateWaitMsg(ctx.Context(), *sector.PreCommitMessage)
|
||||||
@ -142,7 +142,7 @@ func (m *Miner) handlePreCommitted(ctx evtsm.Context, sector SectorInfo) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Miner) handleCommitting(ctx evtsm.Context, sector SectorInfo) error {
|
func (m *Miner) handleCommitting(ctx statemachine.Context, sector SectorInfo) error {
|
||||||
log.Info("scheduling seal proof computation...")
|
log.Info("scheduling seal proof computation...")
|
||||||
|
|
||||||
proof, err := m.sb.SealCommit(ctx.Context(), sector.SectorID, sector.Ticket.SB(), sector.Seed.SB(), sector.pieceInfos(), sector.rspco())
|
proof, err := m.sb.SealCommit(ctx.Context(), sector.SectorID, sector.Ticket.SB(), sector.Seed.SB(), sector.pieceInfos(), sector.rspco())
|
||||||
@ -184,7 +184,7 @@ func (m *Miner) handleCommitting(ctx evtsm.Context, sector SectorInfo) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Miner) handleCommitWait(ctx evtsm.Context, sector SectorInfo) error {
|
func (m *Miner) handleCommitWait(ctx statemachine.Context, sector SectorInfo) error {
|
||||||
if sector.CommitMessage == nil {
|
if sector.CommitMessage == nil {
|
||||||
log.Errorf("sector %d entered commit wait state without a message cid", sector.SectorID)
|
log.Errorf("sector %d entered commit wait state without a message cid", sector.SectorID)
|
||||||
return ctx.Send(SectorCommitFailed{xerrors.Errorf("entered commit wait with no commit cid")})
|
return ctx.Send(SectorCommitFailed{xerrors.Errorf("entered commit wait with no commit cid")})
|
||||||
@ -203,7 +203,7 @@ func (m *Miner) handleCommitWait(ctx evtsm.Context, sector SectorInfo) error {
|
|||||||
return ctx.Send(SectorProving{})
|
return ctx.Send(SectorProving{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Miner) handleFaulty(ctx evtsm.Context, sector SectorInfo) error {
|
func (m *Miner) handleFaulty(ctx statemachine.Context, sector SectorInfo) error {
|
||||||
// TODO: check if the fault has already been reported, and that this sector is even valid
|
// TODO: check if the fault has already been reported, and that this sector is even valid
|
||||||
|
|
||||||
// TODO: coalesce faulty sector reporting
|
// TODO: coalesce faulty sector reporting
|
||||||
@ -235,7 +235,7 @@ func (m *Miner) handleFaulty(ctx evtsm.Context, sector SectorInfo) error {
|
|||||||
return ctx.Send(SectorFaultReported{reportMsg: smsg.Cid()})
|
return ctx.Send(SectorFaultReported{reportMsg: smsg.Cid()})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Miner) handleFaultReported(ctx evtsm.Context, sector SectorInfo) error {
|
func (m *Miner) handleFaultReported(ctx statemachine.Context, sector SectorInfo) error {
|
||||||
if sector.FaultReportMsg == nil {
|
if sector.FaultReportMsg == nil {
|
||||||
return xerrors.Errorf("entered fault reported state without a FaultReportMsg cid")
|
return xerrors.Errorf("entered fault reported state without a FaultReportMsg cid")
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user