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/blocksync"
"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/storage"
)
@ -133,9 +133,9 @@ func main() {
os.Exit(1)
}
err = gen.WriteMapEncodersToFile("./lib/evtsm/cbor_gen.go", "evtsm",
evtsm.TestState{},
evtsm.TestEvent{},
err = gen.WriteMapEncodersToFile("./lib/statemachine/cbor_gen.go", "statemachine",
statemachine.TestState{},
statemachine.TestEvent{},
)
if err != nil {
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 (
"fmt"

View File

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

View File

@ -1,4 +1,4 @@
package evtsm
package statemachine
import (
"context"
@ -15,43 +15,49 @@ type StateHandler interface {
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
hnd StateHandler
stateType reflect.Type
lk sync.Mutex
sms map[datastore.Key]*ESm
sms map[datastore.Key]*StateMachine
}
// stateType: T - (reflect.TypeOf(MyStateStruct{}))
func New(ds datastore.Datastore, hnd StateHandler, stateType reflect.Type) *Sched {
return &Sched{
func New(ds datastore.Datastore, hnd StateHandler, stateType reflect.Type) *StateGroup {
return &StateGroup{
sts: statestore.New(ds),
hnd: hnd,
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()
defer s.lk.Unlock()
sm, exist := s.sms[statestore.ToKey(to)]
sm, exist := s.sms[statestore.ToKey(id)]
if !exist {
sm, err = s.loadOrCreate(to)
sm, err = s.loadOrCreate(id)
if err != nil {
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})
}
func (s *Sched) loadOrCreate(name interface{}) (*ESm, error) {
func (s *StateGroup) loadOrCreate(name interface{}) (*StateMachine, error) {
exists, err := s.sts.Has(name)
if err != nil {
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,
eventsIn: make(chan Event),
@ -84,7 +90,8 @@ func (s *Sched) loadOrCreate(name interface{}) (*ESm, error) {
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()
defer s.lk.Unlock()
@ -97,10 +104,13 @@ func (s *Sched) Stop(ctx context.Context) error {
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)
}
func (s *Sched) Get(i interface{}) *statestore.StoredState {
return s.sts.Get(i)
// Get gets state for a single state machine
func (s *StateGroup) Get(id interface{}) *statestore.StoredState {
return s.sts.Get(id)
}

View File

@ -1,4 +1,4 @@
package evtsm
package statemachine
import (
"context"
@ -12,10 +12,14 @@ import (
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
type Planner func(events []Event, user interface{}) (interface{}, error)
type ESm struct {
type StateMachine struct {
planner Planner
eventsIn chan Event
@ -30,7 +34,7 @@ type ESm struct {
busy int32
}
func (fsm *ESm) run() {
func (fsm *StateMachine) run() {
defer close(fsm.closed)
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)
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())
}
func (fsm *ESm) send(evt Event) error {
func (fsm *StateMachine) send(evt Event) error {
fsm.eventsIn <- evt // TODO: ctx, at least
return nil
}
func (fsm *ESm) stop(ctx context.Context) error {
func (fsm *StateMachine) stop(ctx context.Context) error {
close(fsm.closing)
select {

View File

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

View File

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

View File

@ -22,7 +22,7 @@ import (
"github.com/filecoin-project/lotus/chain/gen"
"github.com/filecoin-project/lotus/chain/store"
"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")
@ -39,7 +39,7 @@ type Miner struct {
// Sealing
sb SectorBuilder
sectors *evtsm.Sched
sectors *statemachine.StateGroup
tktFn TicketFn
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
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
}

View File

@ -8,7 +8,7 @@ import (
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/lib/evtsm"
"github.com/filecoin-project/lotus/lib/statemachine"
)
type SectorStart struct {
@ -53,13 +53,13 @@ type SectorForceState struct {
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))
if err != nil || next == nil {
return nil, err
}
return func(ctx evtsm.Context, si SectorInfo) error {
return func(ctx statemachine.Context, si SectorInfo) error {
err := next(ctx, si)
if 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
}
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

View File

@ -9,10 +9,10 @@ import (
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"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)
var allocated uint64
@ -43,7 +43,7 @@ func (m *Miner) handlePacking(ctx evtsm.Context, sector SectorInfo) error {
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)
ticket, err := m.tktFn(ctx.Context())
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{
SectorNumber: sector.SectorID,
@ -97,7 +97,7 @@ func (m *Miner) handlePreCommitting(ctx evtsm.Context, sector SectorInfo) error
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
log.Info("Sector precommitted: ", sector.SectorID)
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
}
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...")
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 {
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")})
@ -203,7 +203,7 @@ func (m *Miner) handleCommitWait(ctx evtsm.Context, sector SectorInfo) error {
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: 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()})
}
func (m *Miner) handleFaultReported(ctx evtsm.Context, sector SectorInfo) error {
func (m *Miner) handleFaultReported(ctx statemachine.Context, sector SectorInfo) error {
if sector.FaultReportMsg == nil {
return xerrors.Errorf("entered fault reported state without a FaultReportMsg cid")
}