go.temporal.io/server/chasm/ref.go

187 LOC · 82 covered · 105 uncovered · 20 ranges · 308 concepts · 14 introducers · 128 tests

File neighbourhood

The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.

1 package chasm
2
3 import (
4 "reflect"
5
6 "go.temporal.io/api/serviceerror"
7 persistencespb "go.temporal.io/server/api/persistence/v1"
8 )
9
10 // ErrMalformedComponentRef is returned when component ref bytes cannot be deserialized.
11 var ErrMalformedComponentRef = serviceerror.NewInvalidArgument("malformed component ref")
12
13 // ErrInvalidComponentRef is returned when component ref bytes deserialize to an invalid component ref.
14 var ErrInvalidComponentRef = serviceerror.NewInvalidArgument("invalid component ref")
15
16 // ExecutionKey uniquely identifies a CHASM execution in the system.
17 type ExecutionKey struct {
18 NamespaceID string
19 BusinessID string
20 RunID string
21 }
22
23 type ComponentRef struct {
24 ExecutionKey
25
26 // archetypeID is CHASM framework's internal ID for the type of the root component of the CHASM execution.
27 //
28 // It is used to find and validate the loaded execution has the right archetype, especially when runID
29 // is not specified in the ExecutionKey.
30 archetypeID ArchetypeID
31 // executionGoType is used for determining the ComponetRef's archetype.
32 // When CHASM deverloper needs to create a ComponentRef, they will only provide the component type,
33 // and leave the work of determining archetypeID to the CHASM framework.
34 executionGoType reflect.Type
35
36 // executionLastUpdateVT is the consistency token for the entire execution.
37 executionLastUpdateVT *persistencespb.VersionedTransition
38
39 // componentType is the fully qualified component type name.
40 // It is for performing partial loading more efficiently in future versions of CHASM.
41 //
42 // From the componentType, we can find the registered component struct definition,
43 // then use reflection to find sub-components and understand if those sub-components
44 // need to be loaded or not.
45 // We only need to do this for sub-components, path for parent/ancenstor components
46 // can be inferred from the current component path and they always needs to be loaded.
47 //
48 // componentType string
49
50 // componentPath and componentInitialVT are used to identify a component.
51 componentPath []string
52 componentInitialVT *persistencespb.VersionedTransition
53
54 validationFn func(NodeBackend, Context, Component, *Registry) error
55 }
56
57 // NewComponentRef creates a new ComponentRef with a registered root component go type.
58 //
59 // In V1, if you don't have a ref,
60 // then you can only interact with the (top level) execution.
61 func NewComponentRef[C Component](
62 executionKey ExecutionKey,
63 > ) ComponentRef { ref.go ×1
64 > return ComponentRef{
65 > ExecutionKey: executionKey,
66 > executionGoType: reflect.TypeFor[C](),
67 > }
68 > }
69
70 // NewComponentRefByArchetypeID creates a new ComponentRef with a known archetype ID.
71 // This should only be used by CHASM framework internals.
72 // CHASM library developers should use [NewComponentRef] instead.
73 func NewComponentRefByArchetypeID(
74 executionKey ExecutionKey,
75 archetypeID ArchetypeID,
76 > ) ComponentRef { ref.go ×1
77 > return ComponentRef{
78 > ExecutionKey: executionKey,
79 > archetypeID: archetypeID,
80 > }
81 > }
82
83 // forConsistencyLevel returns a copy of the ref adjusted for the requested [RefConsistencyLevel] by
84 // dropping the consistency tokens (and, at the weakest level, the run ID) that the level does not enforce.
85 // See [RefConsistencyLevel] for the ladder.
86 > func (r *ComponentRef) forConsistencyLevel(level RefConsistencyLevel) (ComponentRef, error) { ref.go ×1
87 > ref := *r
88 > switch level {
89 > case RefConsistencyLevelExecutionLastUpdate: ref.go ×1
90 > // Strongest (default): enforce the execution-level token; nothing relaxed.
91 > return ref, nil
92 > case RefConsistencyLevelComponentCreation: ref.go ×1
93 > // Tolerate a stale execution transition without losing the staleness guarantee: run the
94 > // execution staleness check ([Node.IsStale]) against the component's creation transition
95 > // instead of the execution's last update. This still reloads a mutable state that predates
96 > // the component (so the handler never operates on a state that doesn't yet know about the
97 > // component), while no longer requiring the ref to match the latest execution transition.
98 > // The creation transition is also matched in [Node.Component]; identity is otherwise the
99 > // caller's responsibility (e.g. request ID).
100 > ref.executionLastUpdateVT = ref.componentInitialVT
101 > return ref, nil
102 > case RefConsistencyLevelCurrentRun: ref.go ×1
103 > // Weakest: resolve by component path on the current run. Drop the run ID and every versioned
104 > // transition; identity must be re-established by caller logic (e.g. request ID).
105 > ref.executionLastUpdateVT = nil
106 > ref.componentInitialVT = nil
107 > ref.RunID = ""
108 > return ref, nil
109 default:
110 return ref, serviceerror.NewInternalf("unknown ref consistency level: %d", level)
111 }
112 }
113
114 func (r *ComponentRef) ArchetypeID(
115 registry *Registry,
116 > ) (ArchetypeID, error) { ref.go ×1
117 > if r.archetypeID != UnspecifiedArchetypeID {
118 > return r.archetypeID, nil ref.go ×1
119 > }
120
121 > rc, ok := registry.componentOf(r.executionGoType) ref.go ×2
122 > if !ok {
123 return 0, serviceerror.NewInternal("unknown chasm component type: " + r.executionGoType.String())
124 }
125 > r.archetypeID = rc.componentID ref.go ×2
126 >
127 > return r.archetypeID, nil
128 }
129
130 func (r *ComponentRef) Serialize(
131 registry *Registry,
132 > ) ([]byte, error) { ref.go ×3
133 > if r == nil {
134 return nil, nil
135 }
136
137 > archetypeID, err := r.ArchetypeID(registry) ref.go ×3
138 > if err != nil {
139 return nil, err
140 }
141
142 > pRef := persistencespb.ChasmComponentRef{ ref.go ×3
143 > NamespaceId: r.NamespaceID,
144 > BusinessId: r.BusinessID,
145 > RunId: r.RunID,
146 > ArchetypeId: archetypeID,
147 > ExecutionVersionedTransition: r.executionLastUpdateVT,
148 > ComponentPath: r.componentPath,
149 > ComponentInitialVersionedTransition: r.componentInitialVT,
150 > }
151 > return pRef.Marshal()
152 }
153
154 // DeserializeComponentRef deserializes a byte slice into a ComponentRef.
155 // Provides caller the access to information including ExecutionKey, Archetype, and ShardingKey.
156 > func DeserializeComponentRef(data []byte) (ComponentRef, error) { ref.go ×2
157 > if len(data) == 0 {
158 > return ComponentRef{}, ErrInvalidComponentRef ref.go ×1
159 > }
160 > var pRef persistencespb.ChasmComponentRef ref.go ×2
161 > if err := pRef.Unmarshal(data); err != nil {
162 > return ComponentRef{}, ErrMalformedComponentRef validator.go ×1
163 > }
164
165 > ref := ProtoRefToComponentRef(&pRef) ref.go ×3
166 > if ref.BusinessID == "" || ref.NamespaceID == "" {
167 return ComponentRef{}, ErrInvalidComponentRef
168 }
169 > return ref, nil ref.go ×3
170 }
171
172 // ProtoRefToComponentRef converts a persistence ChasmComponentRef reference to a
173 // ComponentRef. This is useful for situations where the protobuf ComponentRef has
174 // already been deserialized as part of an enclosing message.
175 > func ProtoRefToComponentRef(pRef *persistencespb.ChasmComponentRef) ComponentRef { ref.go ×3
176 > return ComponentRef{
177 > ExecutionKey: ExecutionKey{
178 > NamespaceID: pRef.NamespaceId,
179 > BusinessID: pRef.BusinessId,
180 > RunID: pRef.RunId,
181 > },
182 > archetypeID: pRef.ArchetypeId,
183 > executionLastUpdateVT: pRef.ExecutionVersionedTransition,
184 > componentPath: pRef.ComponentPath,
185 > componentInitialVT: pRef.ComponentInitialVersionedTransition,
186 > }
187 > }