Documentation
¶
Index ¶
- func CheckEvents(model Model, history []Event) bool
- func CheckEventsVerbose(model Model, history []Event, timeout time.Duration) (CheckResult, LinearizationInfo)
- func CheckOperations(model Model, history []Operation) bool
- func CheckOperationsVerbose(model Model, history []Operation, timeout time.Duration) (CheckResult, LinearizationInfo)
- func Visualize(model Model, info LinearizationInfo, output io.Writer) error
- func VisualizePath(model Model, info LinearizationInfo, path string) error
- type Annotation
- type CheckResult
- type Event
- type EventKind
- type LinearizationInfo
- type Model
- type NondeterministicModel
- type Operation
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CheckEvents ¶
CheckEvents checks whether a history is linearizable.
func CheckEventsVerbose ¶
func CheckEventsVerbose(model Model, history []Event, timeout time.Duration) (CheckResult, LinearizationInfo)
CheckEventsVerbose checks whether a history is linearizable while computing data that can be used to visualize the history and linearization.
The returned LinearizationInfo can be used with Visualize.
func CheckOperations ¶
CheckOperations checks whether a history is linearizable.
func CheckOperationsVerbose ¶
func CheckOperationsVerbose(model Model, history []Operation, timeout time.Duration) (CheckResult, LinearizationInfo)
CheckOperationsVerbose checks whether a history is linearizable while computing data that can be used to visualize the history and linearization.
The returned LinearizationInfo can be used with Visualize.
func Visualize ¶
func Visualize(model Model, info LinearizationInfo, output io.Writer) error
Visualize produces a visualization of a history and (partial) linearization as an HTML file that can be viewed in a web browser.
If the history is linearizable, the visualization shows the linearization of the history. If the history is not linearizable, the visualization shows partial linearizations and illegal linearization points.
To get the LinearizationInfo that this function requires, you can use CheckOperationsVerbose / CheckEventsVerbose.
This function writes the visualization, an HTML file with embedded JavaScript and data, to the given output.
func VisualizePath ¶
func VisualizePath(model Model, info LinearizationInfo, path string) error
VisualizePath is a wrapper around Visualize to write the visualization to a file path.
Types ¶
type Annotation ¶ added in v0.2.0
type Annotation struct {
ClientId int
Tag string
Start int64
End int64
Description string
Details string
TextColor string
BackgroundColor string
// contains filtered or unexported fields
}
Annotations to add to histories.
Either a ClientId or Tag must be supplied. The End is optional, for "point in time" annotations. If the end is left unspecified, the framework interprets it as Start. The text given in Description is shown in the main visualization, and the text given in Details (optional) is shown in the tooltip for the annotation. TextColor and BackgroundColor are both optional; if specified, they should be valid CSS colors, e.g., "#efaefc".
To attach annotations to a visualization, use LinearizationInfo.AddAnnotations.
type CheckResult ¶
type CheckResult string
A CheckResult is the result of a linearizability check.
Checking for linearizability is decidable, but it is an NP-hard problem, so the checker might take a long time. If a timeout is not given, functions in this package will always return Ok or Illegal, but if a timeout is supplied, then some functions may return Unknown. Depending on the use case, you can interpret an Unknown result as Ok (i.e., the tool didn't find a linearizability violation within the given timeout).
const ( Unknown CheckResult = "Unknown" // timed out Ok CheckResult = "Ok" Illegal CheckResult = "Illegal" )
func CheckEventsTimeout ¶
func CheckEventsTimeout(model Model, history []Event, timeout time.Duration) CheckResult
CheckEventsTimeout checks whether a history is linearizable, with a timeout.
A timeout of 0 is interpreted as an unlimited timeout.
func CheckOperationsTimeout ¶
func CheckOperationsTimeout(model Model, history []Operation, timeout time.Duration) CheckResult
CheckOperationsTimeout checks whether a history is linearizable, with a timeout.
A timeout of 0 is interpreted as an unlimited timeout.
type Event ¶
type Event struct {
ClientId int // optional, unless you want a visualization; zero-indexed
Kind EventKind
Value interface{}
Id int
// Metadata contains arbitrary metadata associated with the operation.
// It is not used for linearizability checking but can be used for visualization.
// Can be set on CallEvent or ReturnEvent. If both have metadata, ReturnEvent metadata takes precedence.
Metadata interface{}
// contains filtered or unexported fields
}
An Event is an element of a history, a function call event or a return event.
This package supports two different representations of histories, as a sequence of Event or Operation. In the Event representation, function calls and returns are only relatively ordered and do not have absolute timestamps.
The Id field is used to match a function call event with its corresponding return event.
type EventKind ¶
type EventKind bool
An EventKind tags an Event as either a function call or a return.
type LinearizationInfo ¶ added in v0.1.6
type LinearizationInfo struct {
// contains filtered or unexported fields
}
func (*LinearizationInfo) AddAnnotations ¶ added in v0.2.0
func (li *LinearizationInfo) AddAnnotations(annotations []Annotation)
AddAnnotations adds extra annotations to a visualization.
This can be used to add extra client operations or it can be used to add standalone annotations with arbitrary tags, e.g., associated with "servers" rather than clients, or even a "test framework".
See documentation on Annotation for what kind of annotations you can add.
func (*LinearizationInfo) PartialLinearizations ¶ added in v0.2.0
func (li *LinearizationInfo) PartialLinearizations() [][][]int
PartialLinearizations returns partial linearizations found during the linearizability check, as sets of operation IDs.
For each partition, it returns a set of possible linearization histories, where each history is represented as a sequence of operation IDs. If the history is linearizable, this will contain a complete linearization. If not linearizable, it contains the maximal partial linearizations found.
func (*LinearizationInfo) PartialLinearizationsOperations ¶ added in v0.2.0
func (li *LinearizationInfo) PartialLinearizationsOperations() [][][]Operation
PartialLinearizationsOperations returns partial linearizations found during the linearizability check, as sets of sequences of Operation.
For each partition, it returns a set of possible linearization histories, where each history is represented as a sequence of Operation. If the history is linearizable, this will contain a complete linearization. If not linearizable, it contains the maximal partial linearizations found.
type Model ¶
type Model struct {
// Partition functions, such that a history is linearizable if and only
// if each partition is linearizable. If left nil, this package will
// skip partitioning.
Partition func(history []Operation) [][]Operation
PartitionEvent func(history []Event) [][]Event
// Initial state of the system.
Init func() interface{}
// Step function for the system. Returns whether or not the system
// could take this step with the given inputs and outputs and also
// returns the new state. This function must be a pure function: it
// cannot mutate the given state.
Step func(state interface{}, input interface{}, output interface{}) (bool, interface{})
// StepContext is an optional context-aware Step function. If set, the
// checker and visualization replay call StepContext instead of Step,
// allowing the model to stop work promptly when a timeout expires.
StepContext func(ctx context.Context, state interface{}, input interface{}, output interface{}) (bool, interface{})
// Equality on states. If left nil, this package will use == as a
// fallback ([ShallowEqual]).
Equal func(state1, state2 interface{}) bool
// Hash returns a hash of the given state. If non-nil, the checker uses
// it to reduce the number of [Equal] comparisons. Must satisfy the
// invariant that [Equal] states have equal hashes.
Hash func(state interface{}) uint64
// For visualization, describe an operation as a string. For example,
// "Get('x') -> 'y'". Can be omitted if you're not producing
// visualizations.
DescribeOperation func(input interface{}, output interface{}) string
// For visualization purposes, describe a state as a string. For
// example, "{'x' -> 'y', 'z' -> 'w'}". Can be omitted if you're not
// producing visualizations.
DescribeState func(state interface{}) string
// For visualization purposes, describe metadata as a string. Can be
// omitted if you're not producing visualizations.
DescribeOperationMetadata func(info interface{}) string
// contains filtered or unexported fields
}
A Model is a sequential specification of a system.
Note: models in this package are expected to be purely functional. That is, the model Step function should not modify the given state (or input or output), but return a new state.
Only the Init, Step (or StepContext), and Equal functions are necessary to specify if you just want to test histories for linearizability.
Implementing the partition functions can greatly improve performance. If you're implementing the partition function, the model Init and Step functions can be per-partition. For example, if your specification is for a key-value store and you partition by key, then the per-partition state representation can just be a single value rather than a map.
Implementing DescribeOperation and DescribeState will produce nicer visualizations.
It may be helpful to look at this package's test code for examples of how to write models, including models that include partition functions.
type NondeterministicModel ¶ added in v1.0.0
type NondeterministicModel struct {
// Partition functions, such that a history is linearizable if and only
// if each partition is linearizable. If left nil, this package will
// skip partitioning.
Partition func(history []Operation) [][]Operation
PartitionEvent func(history []Event) [][]Event
// Initial states of the system.
Init func() []interface{}
// Step function for the system. Returns all possible next states for
// the given state, input, and output. If the system cannot step with
// the given state/input to produce the given output, this function
// should return an empty slice.
Step func(state interface{}, input interface{}, output interface{}) []interface{}
// StepContext is an optional context-aware Step function. If set, the
// checker calls StepContext instead of Step, allowing the model to stop
// work promptly when a timeout expires.
StepContext func(ctx context.Context, state interface{}, input interface{}, output interface{}) []interface{}
// Equality on states. If left nil, this package will use == as a
// fallback ([ShallowEqual]).
Equal func(state1, state2 interface{}) bool
// Hash returns a hash of the given state. If non-nil, the checker uses
// it to reduce the number of [Equal] comparisons. Must satisfy the
// invariant that [Equal] states have equal hashes.
Hash func(state interface{}) uint64
// For visualization, describe an operation as a string. For example,
// "Get('x') -> 'y'". Can be omitted if you're not producing
// visualizations.
DescribeOperation func(input interface{}, output interface{}) string
// For visualization purposes, describe a state as a string. For
// example, "{'x' -> 'y', 'z' -> 'w'}". Can be omitted if you're not
// producing visualizations.
DescribeState func(state interface{}) string
// For visualization purposes, describe metadata as a string. Can be
// omitted if you're not producing visualizations.
DescribeOperationMetadata func(info interface{}) string
// contains filtered or unexported fields
}
A NondeterministicModel is a nondeterministic sequential specification of a system.
For basics on models, see the documentation for Model. In contrast to Model, NondeterministicModel has a step function that returns a set of states, indicating all possible next states. It can be converted to a Model using the NondeterministicModel.ToModel function.
It may be helpful to look at this package's test code for examples of how to write and use nondeterministic models.
func (*NondeterministicModel) ToModel ¶ added in v1.0.0
func (nm *NondeterministicModel) ToModel() Model
ToModel converts a NondeterministicModel to a Model using a power set construction.
This makes it suitable for use in linearizability checking operations like CheckOperations. This is a general construction that can be used for any nondeterministic model. It relies on the NondeterministicModel's Equal function to merge states. You may be able to achieve better performance by implementing a Model directly.
type Operation ¶
type Operation struct {
ClientId int // optional, unless you want a visualization; zero-indexed
Input interface{}
Call int64 // invocation timestamp
Output interface{}
Return int64 // response timestamp
// Metadata contains arbitrary metadata associated with the operation.
// It is not used for linearizability checking but can be used for visualization.
Metadata interface{}
// contains filtered or unexported fields
}
An Operation is an element of a history.
This package supports two different representations of histories, as a sequence of Operation or Event. In the Operation representation, function call/returns are packaged together, along with timestamps of when the function call was made and when the function call returned.
The interval [Call, Return] is interpreted as a closed interval, so an operation with interval [10, 20] is concurrent with another operation with interval [20, 30].