statemachine: Better naming

This commit is contained in:
Łukasz Magiera 2020-01-13 18:44:59 +01:00
parent 2fea9433d8
commit 2ef8c1ae0c
11 changed files with 60 additions and 51 deletions

View File

@ -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)

View File

@ -1,5 +0,0 @@
package evtsm
type Event struct {
User interface{}
}

View File

@ -1,4 +1,4 @@
package evtsm package statemachine
import ( import (
"fmt" "fmt"

View File

@ -1,4 +1,4 @@
package evtsm package statemachine
import "context" import "context"

View File

@ -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)
} }

View File

@ -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 {

View File

@ -1,4 +1,4 @@
package evtsm package statemachine
import ( import (
"context" "context"

View File

@ -1,4 +1,4 @@
package evtsm package statemachine
type TestState struct { type TestState struct {
A uint64 A uint64

View File

@ -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
} }

View File

@ -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

View File

@ -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")
} }