Skip to content

Commit

Permalink
support concurrent state machine reads
Browse files Browse the repository at this point in the history
  • Loading branch information
qmuntal committed Jul 24, 2023
1 parent fc6e1a7 commit 143dfc7
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 13 deletions.
30 changes: 17 additions & 13 deletions statemachine.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ type StateMachine struct {
eventQueue list.List
firingMode FiringMode
firingMutex sync.Mutex
stateMutex sync.RWMutex
}

func newStateMachine() *StateMachine {
Expand Down Expand Up @@ -295,22 +296,25 @@ func (sm *StateMachine) setState(ctx context.Context, state State) error {
return sm.stateMutator(ctx, state)
}

func (sm *StateMachine) currentState(ctx context.Context) (sr *stateRepresentation, err error) {
var state State
state, err = sm.State(ctx)
if err == nil {
sr = sm.stateRepresentation(state)
func (sm *StateMachine) currentState(ctx context.Context) (*stateRepresentation, error) {
state, err := sm.State(ctx)
if err != nil {
return nil, err
}
return
return sm.stateRepresentation(state), nil
}

func (sm *StateMachine) stateRepresentation(state State) (sr *stateRepresentation) {
var ok bool
if sr, ok = sm.stateConfig[state]; !ok {
func (sm *StateMachine) stateRepresentation(state State) *stateRepresentation {
sm.stateMutex.RLock()
sr, ok := sm.stateConfig[state]
sm.stateMutex.RUnlock()
if !ok {
sr = newstateRepresentation(state)
sm.stateMutex.Lock()
sm.stateConfig[state] = sr
sm.stateMutex.Unlock()
}
return
return sr
}

func (sm *StateMachine) internalFire(ctx context.Context, trigger Trigger, args ...any) error {
Expand Down Expand Up @@ -354,7 +358,7 @@ func (sm *StateMachine) internalFireQueued(ctx context.Context, trigger Trigger,
return nil
}

func (sm *StateMachine) internalFireOne(ctx context.Context, trigger Trigger, args ...any) (err error) {
func (sm *StateMachine) internalFireOne(ctx context.Context, trigger Trigger, args ...any) error {
sm.ops.Add(1)
defer sm.ops.Add(^uint64(0))
var (
Expand All @@ -366,7 +370,7 @@ func (sm *StateMachine) internalFireOne(ctx context.Context, trigger Trigger, ar
}
source, err := sm.State(ctx)
if err != nil {
return
return err
}
representativeState := sm.stateRepresentation(source)
var result triggerBehaviourResult
Expand Down Expand Up @@ -397,7 +401,7 @@ func (sm *StateMachine) internalFireOne(ctx context.Context, trigger Trigger, ar
err = sr.InternalAction(ctx, transition, args...)
}
}
return
return err
}

func (sm *StateMachine) handleReentryTrigger(ctx context.Context, sr *stateRepresentation, transition Transition, args ...any) error {
Expand Down
15 changes: 15 additions & 0 deletions statemachine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1513,6 +1513,21 @@ func TestStateMachine_String(t *testing.T) {
}
}

func TestStateMachine_String_Concurrent(t *testing.T) {
// Test that race mode doesn't complain about concurrent access to the state machine.
sm := NewStateMachine(stateA)
const n = 10
var wg sync.WaitGroup
wg.Add(n)
for i := 0; i < n; i++ {
go func() {
defer wg.Done()
_ = sm.String()
}()
}
wg.Wait()
}

func TestStateMachine_Firing_Queued(t *testing.T) {
sm := NewStateMachine(stateA)

Expand Down

0 comments on commit 143dfc7

Please sign in to comment.