-
Notifications
You must be signed in to change notification settings - Fork 3.8k
/
scheduled_event_executor.go
125 lines (113 loc) · 4.01 KB
/
scheduled_event_executor.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// Copyright 2023 The Cockroach Authors.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
package scheduled
import (
"context"
"fmt"
"sort"
"time"
"github.com/cockroachdb/cockroach/pkg/kv/kvserver/asim/event"
"github.com/cockroachdb/cockroach/pkg/kv/kvserver/asim/history"
"github.com/cockroachdb/cockroach/pkg/kv/kvserver/asim/state"
"github.com/cockroachdb/cockroach/pkg/util/log"
)
// EventExecutor is the exported interface for eventExecutor, responsible for
// managing scheduled events, allowing event registration, tick-based
// triggering. Please use NewExecutorWithNoEvents for proper initialization.
type EventExecutor interface {
// RegisterScheduledEvent registers an event to be executed as part of
// eventExecutor.
RegisterScheduledEvent(ScheduledEvent)
// Start sorts the scheduled list chronologically, ready to execute events for
// simulation.
Start()
// TickEvents retrieves and invokes the underlying event function from the
// scheduled events at the given tick. It returns a boolean indicating if any
// assertion event failed during the tick, allowing for early exit.
TickEvents(context.Context, time.Time, state.State, history.History) bool
// PrintEventSummary returns a string summarizing the executed mutation and
// assertion events.
PrintEventSummary() string
// PrintEventsExecuted returns a detailed string representation of executed
// events including details of mutation events, assertion checks, and assertion
// results.
PrintEventsExecuted() string
}
// eventExecutor is the private implementation of the EventExecutor interface,
// maintaining a list of scheduled events and an index for the next event to be
// executed.
type eventExecutor struct {
scheduledEvents ScheduledEventList
nextEventIndex int
}
// NewExecutorWithNoEvents returns the exported interface.
func NewExecutorWithNoEvents() EventExecutor {
return newExecutorWithNoEvents()
}
// newExecutorWithNoEvents returns the actual implementation of the
// EventExecutor interface.
func newExecutorWithNoEvents() *eventExecutor {
return &eventExecutor{
scheduledEvents: ScheduledEventList{},
}
}
func (e *eventExecutor) Start() {
sort.Sort(e.scheduledEvents)
}
func (e *eventExecutor) PrintEventSummary() string {
mutationEvents, assertionEvents := 0, 0
for _, e := range e.scheduledEvents {
if e.IsMutationEvent() {
mutationEvents++
} else {
assertionEvents++
}
}
return fmt.Sprintf(
"number of mutation events=%d, number of assertion events=%d", mutationEvents, assertionEvents)
}
func (e *eventExecutor) PrintEventsExecuted() string {
return ""
}
func (e *eventExecutor) TickEvents(
ctx context.Context, tick time.Time, state state.State, history history.History,
) (failureExists bool) {
// Assume the events are in sorted order and the event list is never added
// to.
for e.nextEventIndex < len(e.scheduledEvents) {
if !tick.Before(e.scheduledEvents[e.nextEventIndex].At) {
log.Infof(ctx, "applying event (scheduled=%s tick=%s)", e.scheduledEvents[e.nextEventIndex].At, tick)
scheduledEvent := e.scheduledEvents[e.nextEventIndex]
fn := scheduledEvent.TargetEvent.Func()
if scheduledEvent.IsMutationEvent() {
mutationFn, ok := fn.(event.MutationFunc)
if ok {
mutationFn(ctx, state)
} else {
panic("expected mutation type to hold mutationFunc but found something else")
}
} else {
assertionFn, ok := fn.(event.AssertionFunc)
if ok {
assertionFn(ctx, tick, history)
} else {
panic("expected assertion type to hold assertionFunc but found something else")
}
}
e.nextEventIndex++
} else {
break
}
}
return failureExists
}
func (e *eventExecutor) RegisterScheduledEvent(scheduledEvent ScheduledEvent) {
e.scheduledEvents = append(e.scheduledEvents, scheduledEvent)
}