Documentation ¶
Overview ¶
Incr is a library that enables building incremental computation graphs.
These graphs are useful for partially recomputing a small subset of a very large number of computations if only a subset of the inputs change.
Index ¶
- Constants
- Variables
- func DetectCycleIfLinked(child, parent INode) error
- func Dot(wr io.Writer, g *Graph) (err error)
- func FormatStabilizationNumber(ctx context.Context) (output string)
- func GetStabilizationNumber(ctx context.Context) (stabilizationNumber uint64, ok bool)
- func OptGraphMaxHeight(maxHeight int) func(*GraphOptions)
- func OptGraphParallelism(parallelism int) func(*GraphOptions)
- func OptGraphPreallocateNodesSize(size int) func(*GraphOptions)
- func OptGraphPreallocateObserversSize(size int) func(*GraphOptions)
- func OptGraphPreallocateSentinelsSize(size int) func(*GraphOptions)
- func SetIdentifierProvider(ip func() Identifier)
- func TraceErrorf(ctx context.Context, format string, args ...any)
- func TraceErrorln(ctx context.Context, args ...any)
- func TracePrintf(ctx context.Context, format string, args ...any)
- func TracePrintln(ctx context.Context, args ...any)
- func WithStabilizationNumber(ctx context.Context, stabilizationNumber uint64) context.Context
- func WithTracer(ctx context.Context, tracer Tracer) context.Context
- func WithTracing(ctx context.Context) context.Context
- func WithTracingOutputs(ctx context.Context, output, errOutput io.Writer) context.Context
- func WithinScope[A INode](scope Scope, node A) A
- type BindContextFunc
- type BindFunc
- type BindIncr
- func Bind[A, B any](scope Scope, input Incr[A], fn BindFunc[A, B]) BindIncr[B]
- func Bind2[A, B, C any](scope Scope, a Incr[A], b Incr[B], fn func(Scope, A, B) Incr[C]) BindIncr[C]
- func Bind2Context[A, B, C any](scope Scope, a Incr[A], b Incr[B], ...) BindIncr[C]
- func Bind3[A, B, C, D any](scope Scope, a Incr[A], b Incr[B], c Incr[C], fn func(Scope, A, B, C) Incr[D]) BindIncr[D]
- func Bind3Context[A, B, C, D any](scope Scope, a Incr[A], b Incr[B], c Incr[C], ...) BindIncr[D]
- func Bind4[A, B, C, D, E any](scope Scope, a Incr[A], b Incr[B], c Incr[C], d Incr[D], ...) BindIncr[E]
- func Bind4Context[A, B, C, D, E any](scope Scope, a Incr[A], b Incr[B], c Incr[C], d Incr[D], ...) BindIncr[E]
- func BindContext[A, B any](scope Scope, input Incr[A], fn BindContextFunc[A, B]) BindIncr[B]
- func BindIf[A any](scope Scope, p Incr[bool], ...) BindIncr[A]
- type Cutoff2ContextFunc
- type Cutoff2Func
- type CutoffContextFunc
- type CutoffFunc
- type Graph
- func (graph *Graph) Has(gn INode) (ok bool)
- func (graph *Graph) HasObserver(on IObserver) (ok bool)
- func (graph *Graph) HasSentinel(sn ISentinel) (ok bool)
- func (graph *Graph) ID() Identifier
- func (graph *Graph) IsStabilizing() bool
- func (graph *Graph) Label() string
- func (graph *Graph) Metadata() any
- func (graph *Graph) OnStabilizationEnd(handler func(context.Context, time.Time, error))
- func (graph *Graph) OnStabilizationStart(handler func(context.Context))
- func (graph *Graph) ParallelStabilize(ctx context.Context) (err error)
- func (graph *Graph) SetLabel(label string)
- func (graph *Graph) SetMetadata(metadata any)
- func (graph *Graph) SetStale(gn INode)
- func (graph *Graph) Stabilize(ctx context.Context) (err error)
- func (graph *Graph) String() string
- type GraphOption
- type GraphOptions
- type IAlways
- type IBindChange
- type IBindMain
- type ICutoff
- type IExpertGraph
- type IExpertNode
- type IExpertVar
- type INode
- type IObserver
- type IParents
- type ISentinel
- type IShouldBeInvalidated
- type IStabilize
- type IStale
- type Identifier
- type Incr
- func Always[A any](scope Scope, input Incr[A]) Incr[A]
- func Cutoff[A any](bs Scope, i Incr[A], fn CutoffFunc[A]) Incr[A]
- func Cutoff2[A, B any](bs Scope, epsilon Incr[A], input Incr[B], fn Cutoff2Func[A, B]) Incr[B]
- func Cutoff2Context[A, B any](bs Scope, epsilon Incr[A], input Incr[B], fn Cutoff2ContextFunc[A, B]) Incr[B]
- func CutoffContext[A any](bs Scope, i Incr[A], fn CutoffContextFunc[A]) Incr[A]
- func Freeze[A any](scope Scope, i Incr[A]) Incr[A]
- func Func[T any](scope Scope, fn func(context.Context) (T, error)) Incr[T]
- func Map[A, B any](scope Scope, a Incr[A], fn func(A) B) Incr[B]
- func Map2[A, B, C any](scope Scope, a Incr[A], b Incr[B], fn func(A, B) C) Incr[C]
- func Map2Context[A, B, C any](scope Scope, a Incr[A], b Incr[B], fn func(context.Context, A, B) (C, error)) Incr[C]
- func Map3[A, B, C, D any](scope Scope, a Incr[A], b Incr[B], c Incr[C], fn func(A, B, C) D) Incr[D]
- func Map3Context[A, B, C, D any](scope Scope, a Incr[A], b Incr[B], c Incr[C], ...) Incr[D]
- func Map4[A, B, C, D, E any](scope Scope, a Incr[A], b Incr[B], c Incr[C], d Incr[D], fn func(A, B, C, D) E) Incr[E]
- func Map4Context[A, B, C, D, E any](scope Scope, a Incr[A], b Incr[B], c Incr[C], d Incr[D], ...) Incr[E]
- func MapContext[A, B any](scope Scope, a Incr[A], fn func(context.Context, A) (B, error)) Incr[B]
- func MapIf[A any](scope Scope, a, b Incr[A], p Incr[bool]) Incr[A]
- func Return[A any](scope Scope, v A) Incr[A]
- func Timer[A any](scope Scope, input Incr[A], every time.Duration) Incr[A]
- type MapNContextFunc
- type MapNFunc
- type MapNIncr
- type Node
- func (n *Node) ID() Identifier
- func (n *Node) Kind() string
- func (n *Node) Label() string
- func (n *Node) Metadata() any
- func (n *Node) OnError(fn func(context.Context, error))
- func (n *Node) OnUpdate(fn func(context.Context))
- func (n *Node) SetKind(kind string)
- func (n *Node) SetLabel(label string)
- func (n *Node) SetMetadata(md any)
- func (n *Node) String() string
- type ObserveIncr
- type Scope
- type SentinelIncr
- type Tracer
- type VarIncr
- type WatchIncr
Constants ¶
const ( StatusNotStabilizing int32 = iota StatusStabilizing StatusRunningUpdateHandlers )
Status constants for graph stabilization status.
const ( // DefaultMaxHeight is the default maximum height that can // be tracked in the recompute heap. DefaultMaxHeight = 256 )
const HeightUnset = -1
HeightUnset is a constant that denotes that a height isn't strictly set (because heights can be 0, we have to use something other than the integer zero value).
Variables ¶
var ( // ErrAlreadyStabilizing is returned if you're already stabilizing a graph. ErrAlreadyStabilizing = errors.New("stabilize; already stabilizing, cannot continue") )
Functions ¶
func DetectCycleIfLinked ¶
DetectCycleIfLinked determines if adding a given input to a given child would cause a graph cycle.
It is a low-level utility function that should be used in special cases; the vast majority of situations outside very esoteric Bind use cases cannot create cycles.
func Dot ¶
Dot formats a graph from a given node in the dot format so that you can export the graph as an image.
To do so, you'll want to make sure you have `graphviz` installed locally, and then you'll want to run:
> go run ??? | dot -Tpng > /home/foo/graph.png
As an for an example of a program that renders a graph with `Dot`, look at `examples/benchmark/main.go`.
func FormatStabilizationNumber ¶
FormatStabilizationNumber formats the stabilization number from a context for tracing output.
func GetStabilizationNumber ¶
GetStabilizationNumber gets the stabilization number from a context.
func OptGraphMaxHeight ¶
func OptGraphMaxHeight(maxHeight int) func(*GraphOptions)
OptGraphMaxHeight sets the graph max recompute height.
func OptGraphParallelism ¶ added in v1.1.8
func OptGraphParallelism(parallelism int) func(*GraphOptions)
OptGraphParallelism sets the parallelism factor, or said another way the number of goroutines, to use when stabilizing using Graph.ParallelStabilize.
This will default to runtime.NumCPU if unset.
func OptGraphPreallocateNodesSize ¶ added in v1.1.8
func OptGraphPreallocateNodesSize(size int) func(*GraphOptions)
OptGraphPreallocateNodesSize preallocates the node tracking map within the graph with a given size number of elements for items.
If not provided, no size for elements will be preallocated.
func OptGraphPreallocateObserversSize ¶ added in v1.1.8
func OptGraphPreallocateObserversSize(size int) func(*GraphOptions)
OptGraphPreallocateObserversSize preallocates the observer tracking map within the graph with a given size number of elements for items.
If not provided, no size for elements will be preallocated.
func OptGraphPreallocateSentinelsSize ¶ added in v1.1.8
func OptGraphPreallocateSentinelsSize(size int) func(*GraphOptions)
OptGraphPreallocateSentinelsSize preallocates the sentinel tracking map within the graph with a given size number of elements for items.
If not provided, no size for elements will be preallocated.
func SetIdentifierProvider ¶ added in v1.1.8
func SetIdentifierProvider(ip func() Identifier)
SetIdentifierProvider sets the identifier provider to a custom provider separate from the default.
This is especially useful in performance critical use cases where the identifier doesn't need to be securely random, that is there are looser constraints on the randomness of the identifier because there will be few nodes over the lifetime of the program or graph.
func TraceErrorf ¶
TraceErrorf prints a line to the error output of a tracer on a given context with a given format and args.
func TraceErrorln ¶
TraceErrorln prints a line to the error output of a tracer on a given context.
func TracePrintf ¶
TracePrintf prints a line to the tracer on a given context with a given format and args.
func TracePrintln ¶
TracePrintln prints a line to the tracer on a given context.
func WithStabilizationNumber ¶
WithStabilizationNumber adds a stabilization number to a context.
func WithTracer ¶
WithTracer adds a tracer to a given context.
func WithTracing ¶
WithTracing adds a default tracer to a given context.
Tracing writes text logs to a standard out and standard error around the stabilization process, though for performance reasons this is typically just the start and stop of stabilization, and the elapsed time.
func WithTracingOutputs ¶
WithTracingOutputs adds a tracer to a given context with given outputs.
func WithinScope ¶
WithinScope updates a node's createdIn scope to reflect a new inner-most bind scope applied by a bind.
The scope itself is created by a bind at its construction, and will hold a reference to both the bind node itself and the bind's left-hand-side or input node. All nodes created within the bind's function will be associated with its scope unless they were created outside that scope and are simply referenced by nodes created by the bind.
You shouldn't need to call WithinScope in practice typically, as it is sufficient to pass the Bind function's provided scope to node constructors to associate the scopes correctly. This method is exported for advanced use cases where you want to manage scopes manually.
Types ¶
type BindContextFunc ¶
BindContextFunc is the type of bind function.
type BindIncr ¶
type BindIncr[A any] interface { Incr[A] IStabilize IShouldBeInvalidated IBindMain fmt.Stringer }
BindIncr is a node that implements Bind, which can dynamically swap out subgraphs based on input incrementals changing.
BindIncr gives the graph dynamism, but as a result is somewhat expensive to compute and should be used tactically.
func Bind ¶
Bind lets you swap out an entire subgraph of a computation based on a given function and a single input.
A way to think about this, as a sequence:
A given node `a` can be bound to `c` or `d` or more subnodes with the value of `a` as the input:
a -> b.bind() -> c
We might want to, at some point in the future, swap out `c` for `d` based on some logic:
a -> b.bind() -> d
As a result, (a) is a child of (b), and (c) or (d) are children of (b). When the bind changes from (c) to (d), (c) is unlinked, and is removed as a "child" of (b), preventing it from being considered part of the overall computation unless it's referenced by another node in the graph.
More information is available at in the [Janestreet docs].
func Bind2 ¶
func Bind2[A, B, C any](scope Scope, a Incr[A], b Incr[B], fn func(Scope, A, B) Incr[C]) BindIncr[C]
Bind2 lets you swap out an entire subgraph of a computation based on a given set of 2 input incrementals.
func Bind2Context ¶
func Bind2Context[A, B, C any](scope Scope, a Incr[A], b Incr[B], fn func(context.Context, Scope, A, B) (Incr[C], error)) BindIncr[C]
Bind2Context lets you swap out an entire subgraph of a computation based on a given set of 2 input incrementals, taking a context and as well returning an error.
func Bind3 ¶
func Bind3[A, B, C, D any](scope Scope, a Incr[A], b Incr[B], c Incr[C], fn func(Scope, A, B, C) Incr[D]) BindIncr[D]
Bind3 lets you swap out an entire subgraph of a computation based on a given set of 3 input incrementals.
func Bind3Context ¶
func Bind3Context[A, B, C, D any](scope Scope, a Incr[A], b Incr[B], c Incr[C], fn func(context.Context, Scope, A, B, C) (Incr[D], error)) BindIncr[D]
Bind3Context lets you swap out an entire subgraph of a computation based on a given set of 3 input incrementals, taking a context and as well returning an error.
func Bind4 ¶
func Bind4[A, B, C, D, E any](scope Scope, a Incr[A], b Incr[B], c Incr[C], d Incr[D], fn func(Scope, A, B, C, D) Incr[E]) BindIncr[E]
Bind4 lets you swap out an entire subgraph of a computation based on a given set of 4 input incrementals.
func Bind4Context ¶
func Bind4Context[A, B, C, D, E any](scope Scope, a Incr[A], b Incr[B], c Incr[C], d Incr[D], fn func(context.Context, Scope, A, B, C, D) (Incr[E], error)) BindIncr[E]
Bind4Context lets you swap out an entire subgraph of a computation based on a given set of 4 input incrementals, taking a context and as well returning an error.
func BindContext ¶
func BindContext[A, B any](scope Scope, input Incr[A], fn BindContextFunc[A, B]) BindIncr[B]
BindContext is like Bind but allows the bind delegate to take a context and return an error.
If an error returned, the bind is aborted, the error listener(s) will fire for the node, and the computation will stop.
func BindIf ¶
func BindIf[A any](scope Scope, p Incr[bool], fn func(context.Context, Scope, bool) (Incr[A], error)) BindIncr[A]
BindIf lets you swap out an entire subgraph of a computation based on a given boolean incremental predicate.
It is largely "macro" for a Bind that takes an input bool incremental.
type Cutoff2ContextFunc ¶
Cutoff2ContextFunc is a function that implements cutoff checking and takes a context.
type Cutoff2Func ¶
Cutoff2Func is a function that implements cutoff checking.
type CutoffContextFunc ¶
CutoffContextFunc is a function that implements cutoff checking and takes a context.
type CutoffFunc ¶
CutoffFunc is a function that implements cutoff checking.
type Graph ¶
type Graph struct {
// contains filtered or unexported fields
}
Graph is the state that is shared across nodes in a computation graph.
You should instantiate this type with the New function.
The graph holds information such as, how many stabilizations have happened, what node are currently observed, and what nodes need to be recomputed.
func GraphForNode ¶
GraphForNode returns the graph for a given node as derrived through the scope it was created in, which must return a graph reference.
func GraphForScope ¶ added in v1.1.0
GraphForScope returns the graph for a given scope.
It is used for advanced situations where you need to refer back to the underlying graph of a scope but may not have a reference available (e.g. in generalized bind functions).
func New ¶
func New(opts ...GraphOption) *Graph
New returns a new Graph, which is the type that represents the shared state of a computation graph.
You can pass configuration options as GraphOption to customize settings within the graph, such as what the maximum "height" a node can be.
This is the entrypoint for all stabilization and computation operations, and generally the Graph will be passed to node constructors.
Nodes you initialize the graph with will need to be be observed by an [Observer] before you can stabilize them.
func (*Graph) HasObserver ¶
HasObserver returns if a graph has a given observer.
func (*Graph) HasSentinel ¶ added in v1.1.0
HasSentinel returns if a graph has a given sentinel.
func (*Graph) IsStabilizing ¶
IsStabilizing returns if the graph is currently stabilizing.
func (*Graph) OnStabilizationEnd ¶
OnStabilizationEnd adds a stabilization end handler.
func (*Graph) OnStabilizationStart ¶
OnStabilizationStart adds a stabilization start handler.
func (*Graph) ParallelStabilize ¶
ParallelStabilize stabilizes a graph in parallel.
This is done similarly to Graph.Stabilize, in that nodes are stabilized starting with the minimum height in the recompute heap working upwards, but unlike the serial processing that Graph.Stabilize does, Graph.ParallelStabilize will process a height "block" all at once concurrently.
Because of the concurrent nature of the block processing, Graph.ParallelStabilize is considerably slower to process nodes, specifically because locks have to be acquired and shared state managed carefully.
You should only reach for Graph.ParallelStabilize if you have very long running node recomputations that would benefit from processing in parallel, e.g. if you have nodes that are I/O bound or CPU intensive.
func (*Graph) SetMetadata ¶
SetMetadata sets the metadata for the graph instance.
func (*Graph) Stabilize ¶
Stabilize kicks off the stabilization for nodes that have been observed by the graph's scope.
The general process of stabilization is to scan the recompute heap up from the minimum height block, processing each node in the block until there are no more nodes.
Stabilizing a node can add more nodes to the recompute heap, creating more work as the stabilization progresses, until finally no more nodes are left to process.
The [Stabailize] stabilization process is serial, that is each node is recomputed in sequence one after the other.
This can be extremely fast in practice because it lets us makes some assumptions about what can change in during each node's stabilization, specifically we can assume that Bind nodes evaluate serially and we can adjust recompute heights accordingly, and as a result we don't need to worry about shared resource contention and can skip acquiring locks.
If during the stabilization pass a node's stabilize function returns an error, the recomputation pass is stopped and the error is returned.
type GraphOptions ¶
type GraphOptions struct { MaxHeight int Parallelism int PreallocateNodesSize int PreallocateObserversSize int PreallocateSentinelsSize int }
GraphOptions are options for graphs.
type IAlways ¶
type IAlways interface {
Always()
}
IAlways is a type that is opted into for recomputation each pass of stabilization.
type IBindChange ¶
type IBindChange interface {
RightScopeNodes() []INode
}
IBindChange holds the methods specific to the bind-lhs-change node.
type IBindMain ¶
type IBindMain interface { IParents Invalidate() }
IBindMain holds the methods specific to the bind main node.
type ICutoff ¶
ICutoff is a type that determines if changes should continue to propagate past this node or not.
type IExpertGraph ¶
type IExpertGraph interface { // SetID sets the identifier for the [Graph]. SetID(Identifier) // NumNodes returns the number of nodes the [Graph] is tracking. NumNodes() uint64 // NumNodesRecomputed returns the number of nodes the [Graph] has // recomputed in its lifetime. NumNodesRecomputed() uint64 // NumNodesChanged returns the number of nodes the [Graph] has // updated the value of in its lifetime. NumNodesChanged() uint64 // NumObservers returns the current count of observers the [Graph] is tracking. NumObservers() uint64 // StabilizationNum returns the current stabilization number of the [Graph]. StabilizationNum() uint64 // SetStabilizationNumber sets the current stabilization number, specifically // in situations where you're restoring graph state. SetStabilizationNum(uint64) // RecomputeHeapAdd directly adds a varadic array of nodes to the recompute heap. RecomputeHeapAdd(...INode) // RecomputeHeapLen returns the current length of the recompute heap. RecomputeHeapLen() int // RecomputeHeapIDs returns the node identifiers that are held in the recompute heap. // // This is useful when saving the state of a [Graph] to an external store. RecomputeHeapIDs() []Identifier // AddChild associates a child node to a parent. AddChild(child INode, parent INode) error // RemoveParent removes the association between a child and a parent. RemoveParent(child INode, parent INode) // ObserveNode implements the observe steps usually handled by [Observe] for custom nodes. ObserveNode(IObserver, INode) error // UnobserveNode implements the unobserve steps usually handled by observers. UnobserveNode(IObserver, INode) }
IExpertGraph is an interface to allow you to manage internal fields of a graph (this is useful if you're deserializing the graph from a durable store).
Note there are no compatibility guarantees on this interface and you should use this interface at your own risk.
func ExpertGraph ¶
func ExpertGraph(g *Graph) IExpertGraph
ExpertGraph returns an "expert" interface to modify internal fields of the graph type.
Note there are no compatibility guarantees on this interface and you should use this interface at your own risk.
type IExpertNode ¶
type IExpertNode interface { CreatedIn() Scope SetCreatedIn(Scope) SetID(Identifier) Valid() bool SetValid(bool) Height() int SetHeight(int) HeightInRecomputeHeap() int SetHeightInRecomputeHeap(int) HeightInAdjustHeightsHeap() int SetHeightInAdjustHeightsHeap(int) ChangedAt() uint64 SetChangedAt(uint64) SetAt() uint64 SetSetAt(uint64) RecomputedAt() uint64 SetRecomputedAt(uint64) NumRecomputes() uint64 SetNumRecomputes(uint64) NumChanges() uint64 SetNumChanges(uint64) IsNecessary() bool IsStale() bool IsInRecomputeHeap() bool Always() bool SetAlways(bool) Observer() bool SetObserver(bool) Children() []INode AddChildren(...INode) Parents() []INode AddParents(...INode) Observers() []IObserver AddObservers(...IObserver) RemoveChild(Identifier) RemoveParent(Identifier) RemoveObserver(Identifier) // ComputePseudoHeight walks the node graph up from a given node // computing the height of the node in-respect to its full graph. // // This is in contrast to how the node's height is calculated during // computation, which is only when it is linked or bound, and only // in respect to its immediate parents. // // This method is useful in advanced scenarios where you may be // rebuilding a graph from scratch dynamically. ComputePseudoHeight() int // Value returns the underlying value of the node // as an untyped `interface{}` for use in debugging. Value() any }
IExpertNode is an expert interface for nodes.
Note there are no compatibility guarantees on this interface and you should use this interface at your own risk.
func ExpertNode ¶
func ExpertNode(in INode) IExpertNode
ExpertNode returns an "expert" interface to interact with nodes.
Note there are no compatibility guarantees on this interface and you should use this interface at your own risk.
type IExpertVar ¶
type IExpertVar[A any] interface { // SetInternalValue allows you to set the underlying value of a var // without marking it as stale. // // This can be useful when deserializing graphs from some other state. SetInternalValue(A) }
IExpertVar are methods implemented by ExpertVar.
Note there are no compatibility guarantees on this interface and you should use this interface at your own risk.
func ExpertVar ¶
func ExpertVar[A any](v VarIncr[A]) IExpertVar[A]
ExpertVar returns an "expert" version of a var node.
Note there are no compatibility guarantees on this interface and you should use this interface at your own risk.
type INode ¶
type INode interface { // INode returns the underlying node metadata // for a given incremental node. Node() *Node }
INode is a node in the incremental graph.
type IObserver ¶
type IObserver interface { INode // Unobserve effectively removes a given node from the observed ref count for a graph. // // As well, it unlinks the observer from its parent nodes, and as a result // you should _not_ re-use the node. // // To observe parts of a graph again, use the `MustObserve(...)` helper. Unobserve(context.Context) }
IObserver is an INode that can be unobserved.
type IParents ¶
type IParents interface { // Parents provides a list of nodes that this node takes as inputs // for propagation of changes and dependency tracking. Parents() []INode }
IParents is a type that has parents or inputs.
This list is used to link the node into the graph but also to reconstruct the links if the node becomes unnecessary, and then necessary again after construction.
type ISentinel ¶ added in v1.1.0
ISentinel is a node that manages the staleness of a target node based on a predicate and can mark that target node for recomputation.
type IShouldBeInvalidated ¶
type IShouldBeInvalidated interface {
ShouldBeInvalidated() bool
}
IShouldBeInvalidateds a type that determines if a node should be invalidated or not.
type IStabilize ¶
IStabilize is a type that can be stabilized.
type IStale ¶
type IStale interface {
Stale() bool
}
IStale is a type that determines if it is stale or not.
type Identifier ¶
type Identifier [16]byte
Identifier is a unique id.
Create a new identifier with NewIdentifier.
func MustParseIdentifier ¶
func MustParseIdentifier(raw string) (output Identifier)
MustParseIdentifier is the reverse of `.String()` that will panic if an error is returned by `ParseIdentifier`.
func NewIdentifier ¶
func NewIdentifier() (output Identifier)
NewIdentifier returns a new identifier.
Currently the underlying data looks like a uuidv4 but that shouldn't be relied upon.
By default NewIdentifier uses crypto/rand to generate the random data for the identifier in a rotating buffer, which yields decent performance and uniqueness guarantees.
If performance is still bottlenecked on creating identifiers for nodes you can swap out the algorithm for generating ids with SetIdentifierProvider.
func ParseIdentifier ¶
func ParseIdentifier(raw string) (output Identifier, err error)
ParseIdentifier is the reverse of `.String()`.
func (Identifier) IsZero ¶
func (id Identifier) IsZero() bool
IsZero returns if the identifier is unset.
func (Identifier) MarshalJSON ¶
func (id Identifier) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler.
func (Identifier) Short ¶
func (id Identifier) Short() string
Short returns the short hex representation of the id.
In practice this is the last ~8 bytes of the identifier.
func (Identifier) String ¶
func (id Identifier) String() string
String returns the full hex representation of the id.
func (*Identifier) UnmarshalJSON ¶
func (id *Identifier) UnmarshalJSON(data []byte) error
UnmarshalJSON implements json.Unmarshaler.
type Incr ¶
type Incr[T any] interface { INode // Value returns the stabilized value of the node. // // In practice you do not want to access this value // directly, you almost always want to associate this // value with a node as an input, and use the value // as resolved through a map or bind function. Value() T }
Incr is a type that can be an incremental node in a computation graph.
func Always ¶
Always returns an incremental that is always stale and whose children will always be marked for recomputation.
The Always node will pass through the input incremental value to the nodes that take the Always node as an input.
An example use case for Always might be something like:
g := incr.New() v := incr.Var(g, "hello") mv := incr.Map(g, v, func(vv string) string { return "not-" + v }) a := incr.Always(g, mv) var counter int mva := incr.Map(g, a, func(vv string) string { counter++; return vv }) _ = g.Stabilize(context.TODO())
In the above example, each time we call Graph.Stabilize we'll increment the counter.
func Cutoff ¶
func Cutoff[A any](bs Scope, i Incr[A], fn CutoffFunc[A]) Incr[A]
Cutoff returns a new wrapping cutoff incremental.
The goal of the cutoff incremental is to stop recomputation at a given node if the difference between the previous and latest values are not significant enough to warrant a full recomputation of the children of this node.
func Cutoff2Context ¶
func Cutoff2Context[A, B any](bs Scope, epsilon Incr[A], input Incr[B], fn Cutoff2ContextFunc[A, B]) Incr[B]
Cutoff2Context returns a new cutoff incremental that takes an epsilon input.
The goal of the cutoff incremental is to stop recomputation at a given node if the difference between the previous and latest values are not significant enough to warrant a full recomputation of the children of this node.
func CutoffContext ¶
func CutoffContext[A any](bs Scope, i Incr[A], fn CutoffContextFunc[A]) Incr[A]
CutoffContext returns a new wrapping cutoff incremental.
The goal of the cutoff incremental is to stop recomputation at a given node if the difference between the previous and latest values are not significant enough to warrant a full recomputation of the children of this node.
func Freeze ¶
Freeze yields an incremental that takes the value of an input incremental on the first stabilization and doesn't change thereafter.
Stabilization propagates through this node even after the first stabilization.
func Func ¶
Func wraps a given function as an incremental.
The result of the function after the first stabilization will be re-used between stabilizations unless you mark the node stale with the `SetStale` function on the `Graph` type.
Because there is no tracking of input changes, this node type is generally discouraged in favor of `Map` or `Bind` incrementals but is included for "expert" use cases, typically as an input to other nodes.
func Map ¶
Map applies a function to a given input incremental and returns a new incremental of the output type of that function.
func Map2 ¶
Map2 applies a function to a given input incremental and returns a new incremental of the output type of that function.
func Map2Context ¶
func Map2Context[A, B, C any](scope Scope, a Incr[A], b Incr[B], fn func(context.Context, A, B) (C, error)) Incr[C]
Map2Context applies a function that accepts a context and returns an error, to a given input incremental and returns a new incremental of the output type of that function.
func Map3 ¶
Map3 applies a function to given input incrementals and returns a new incremental of the output type of that function.
func Map3Context ¶
func Map3Context[A, B, C, D any](scope Scope, a Incr[A], b Incr[B], c Incr[C], fn func(context.Context, A, B, C) (D, error)) Incr[D]
Map3Context applies a function that accepts a context and returns an error, to given input incrementals and returns a new incremental of the output type of that function.
func Map4 ¶
func Map4[A, B, C, D, E any](scope Scope, a Incr[A], b Incr[B], c Incr[C], d Incr[D], fn func(A, B, C, D) E) Incr[E]
Map4 applies a function to given input incrementals and returns a new incremental of the output type of that function.
func Map4Context ¶
func Map4Context[A, B, C, D, E any](scope Scope, a Incr[A], b Incr[B], c Incr[C], d Incr[D], fn func(context.Context, A, B, C, D) (E, error)) Incr[E]
Map4Context applies a function that accepts a context and returns an error, to given input incrementals and returns a new incremental of the output type of that function.
func MapContext ¶
MapContext applies a function to a given input incremental and returns a new incremental of the output type of that function but is context aware and can also return an error, aborting stabilization.
func MapIf ¶
MapIf returns an incremental that yields one of two values based on the boolean condition returned from a third.
Specifically, we term this _Apply_If because the nodes are all linked in the graph, but the value changes during stabilization.
func Return ¶
Return yields a constant incremental for a given value.
Note that it does not implement IStabilize and is effectively always the same value, and never causes recomputations.
func Timer ¶
Timer returns a special node type that fires if a given duration has elapsed since it last stabilized.
When it stabilizes, it assumes the value of the input node, and causes any children (i.e. nodes that take the timer as input) to recompute if this is the first stabilization or if the timer has elapsed.
type MapNContextFunc ¶
MapNContextFunc is the function that the MapNContext incremental applies.
type MapNFunc ¶
type MapNFunc[A, B any] func(...A) B
MapNFunc is the function that the MapN incremental applies.
type MapNIncr ¶
MapNIncr is a type of incremental that can add inputs over time.
func MapN ¶
MapN applies a function to given list of input incrementals and returns a new incremental of the output type of that function.
func MapNContext ¶
func MapNContext[A, B any](scope Scope, fn MapNContextFunc[A, B], inputs ...Incr[A]) MapNIncr[A, B]
MapNContext applies a function to given list of input incrementals and returns a new incremental of the output type of that function.
type Node ¶
type Node struct {
// contains filtered or unexported fields
}
Node is the common metadata for any node in the computation graph.
func (*Node) Label ¶
Label returns a descriptive label for the node or an empty string if one hasn't been provided.
func (*Node) OnError ¶
OnError registers an error handler.
An error handler is called when the stabilize or cutoff function for this node returns an error.
func (*Node) OnUpdate ¶
OnUpdate registers an update handler.
An update handler is called when this node is recomputed.
func (*Node) SetMetadata ¶
SetMetadata sets the metadata on the node.
type ObserveIncr ¶
type ObserveIncr[A any] interface { IObserver // OnUpdate lets you register an update handler for the observer node. // // This handler is called when the observed node is recomputed. It is // passed the value of the observed node post-stabilization. // // If the stabilization is "serial" all update handlers that are registered // will also be called serially, conversely if the stabilization is "paralllel" // all update handlers will be called in parallel using the graph worker pool. OnUpdate(func(context.Context, A)) // Value returns the observed node value. Value() A }
ObserveIncr is an incremental that observes a graph of incrementals starting a given input.
func MustObserve ¶
func MustObserve[A any](g *Graph, observed Incr[A]) ObserveIncr[A]
MustObserve observes a node, specifically including it for computation as well as all of its parents.
If this detects a cycle or any other issue a panic will be raised.
type Scope ¶
Scope is a type that's used to track which nodes are created by which "areas" of the graph.
When in doubt, if you see a scope argument you should pass the Graph itself.
If you're within a bind, you should pass the scope that is passed to your bind function.
type SentinelIncr ¶ added in v1.1.0
SentinelIncr is a node that is recomputed always, but can cutoff the computation based on the result of a provided deligate.
func Sentinel ¶ added in v1.1.0
func Sentinel(scope Scope, fn func() bool, watched INode) SentinelIncr
Sentinel returns a node that evaluates a staleness function for each stabilization.
The provided predicate should return true if we should recompute the watched node. Returning false will stop recomputation from propagating past this node, specifically skipping the watched node and its children. Conversely, if the predicate returns true the watched node will be recomputed.
You can attach sentinels to parts of a graph to automatically recompute nodes on the result of a function withouth having to mark those nodes explicitly stale. Sentinels are somewhat expensive as a result, and should only be used sparingly, and even then only in situations where the stalness function will return true infequently.
func SentinelContext ¶ added in v1.1.0
func SentinelContext(scope Scope, fn func(context.Context) (bool, error), watched INode) SentinelIncr
SentinelContext returns a node that evaluates a staleness function for each stabilization, similar to Sentinel, except that the predicate is passed the stabilization context and can return an error.
type VarIncr ¶
type VarIncr[T any] interface { Incr[T] // Set sets the var value. // // Calling [Set] will invalidate any nodes that reference this variable. Set(T) }
VarIncr is a graph node type that implements an incremental variable.
func Var ¶
Var returns a new var node.
Var nodes are special nodes in incremental as they let you input data into a computation, and specifically change data between stabilization passes.
Var nodes include a method [Var.Set] that let you update the value after the initial construction. Calling [Var.Set] will mark the Var node stale, as well any of the nodes that take the Var node as an input (i.e. the Var node's children).
type WatchIncr ¶
type WatchIncr[A any] interface { Incr[A] // Reset empties the tracked values. Reset() // Values returns the input incremental values the [Watch] node // has seen through stabilization passes. This array of values will // continue to grow until you call [Reset] on the node. Values() []A }
WatchIncr is a type that implements the watch interface.
Source Files ¶
- adjust_heights_heap.go
- always.go
- bind.go
- bind2.go
- bind3.go
- bind4.go
- bind_if.go
- cutoff.go
- cutoff2.go
- detect_cycle_if_linked.go
- doc.go
- dot.go
- errors.go
- expert_graph.go
- expert_node.go
- expert_var.go
- freeze.go
- func.go
- graph.go
- identifier.go
- incr.go
- list_util.go
- map.go
- map2.go
- map3.go
- map4.go
- map_if.go
- map_n.go
- node.go
- node_sorter.go
- observe.go
- parallel_batch.go
- parallel_stabilize.go
- queue.go
- recompute_heap.go
- recompute_heap_list.go
- return.go
- scope.go
- sentinel.go
- stabilize.go
- status.go
- timer.go
- trace.go
- var.go
- watch.go
Directories ¶
Path | Synopsis |
---|---|
examples
|
|
Package incrutil provides helper types above what is already provided in incr.
|
Package incrutil provides helper types above what is already provided in incr. |
mapi
package mapi provides helper incrementals for working with maps.
|
package mapi provides helper incrementals for working with maps. |
naive
package naive provides basic implementations of incremental primitives to test what a "baseline" implementation of a DAG would perform like _before_ you add incremental.
|
package naive provides basic implementations of incremental primitives to test what a "baseline" implementation of a DAG would perform like _before_ you add incremental. |