358
}
359
}
360
>
def, ok := n.registry.Machine(key.Type)
tree.go
361
>
if !ok {
362
return nil, fmt.Errorf("%w: state machine for type: %v", ErrNotRegistered, key.Type)
363
}
364
>
serialized, err := def.Serialize(data)
tree.go
365
>
if err != nil {
366
return nil, err
367
}
368
369
>
nextVersionedTransition := &persistencespb.VersionedTransition{
tree.go
370
>
NamespaceFailoverVersion: n.backend.GetCurrentVersion(),
371
>
// The transition count for the backend is only incremented when closing the current transaction,
372
>
// but any change to state machine node is a state transtion,
373
>
// so we can safely using next transition count here is safe.
374
>
TransitionCount: n.backend.NextTransitionCount(),
375
>
}
376
>
node := &Node{
377
>
Key: key,
378
>
Parent: n,
379
>
definition: def,
380
>
registry: n.registry,
381
>
persistence: &persistencespb.StateMachineNode{
382
>
Children: make(map[string]*persistencespb.StateMachineMap),
383
>
Data: serialized,
384
>
InitialVersionedTransition: nextVersionedTransition,
385
>
LastUpdateVersionedTransition: nextVersionedTransition,
386
>
TransitionCount: 0,
387
>
},
388
>
cache: &cachedMachine{
389
>
dataLoaded: true,
390
>
data: data,
391
>
dirty: true,
392
>
children: make(map[Key]*Node),
393
>
},
394
>
backend: n.backend,
395
>
}
396
>
n.cache.children[key] = node
397
>
children, ok := n.persistence.Children[key.Type]
398
>
if !ok {
399
>
children = &persistencespb.StateMachineMap{MachinesById: make(map[string]*persistencespb.StateMachineNode)}
tree.go
400
>
// Children may be nil if the map was empty and the proto message we serialized and deserialized.
401
>
if n.persistence.Children == nil {
402
n.persistence.Children = make(map[string]*persistencespb.StateMachineMap, 1)
403
}
404
>
n.persistence.Children[key.Type] = children
tree.go
405
}
406
>
children.MachinesById[key.ID] = node.persistence
tree.go
407
>
return node, nil
408
}
409
410
// DeleteChild marks a child node and all its descendants as deleted, removing them from the cache. No transitions will
411
// be allowed after deleting a child.
412
>
func (n *Node) DeleteChild(key Key) error {
tree.go
413
>
if n.cache.deleted {
414
return fmt.Errorf("%w: cannot delete from deleted node: %v", ErrStateMachineInvalidState, n.Key)
415
}
416
417
>
child, err := n.Child([]Key{key})
tree.go
418
>
if err != nil {
419
return err
420
}
421
422
// Mark entire subtree as deleted
423
>
if err := child.Walk(func(n *Node) error {
tree.go
424
>
n.cache.deleted = true
425
>
return nil
426
>
}); err != nil {
427
return err
428
}
429
431
>
root.opLog = append(root.opLog, DeleteOperation{
432
>
path: child.Path(),
433
>
})
434
>
435
>
// Remove from persistence and cache
436
>
machinesMap := n.persistence.Children[key.Type]
437
>
if machinesMap != nil {
438
>
delete(machinesMap.MachinesById, key.ID)
439
>
if len(machinesMap.MachinesById) == 0 {
440
>
delete(n.persistence.Children, key.Type)
tree.go
441
>
}
442
}
443
>
delete(n.cache.children, key)
tree.go
444
>
return nil
445
}
446
447
// AddHistoryEvent adds a history event to be committed at the end of the current transaction.
448
// Must be called within an [Environment.Access] function block with write access.
449
>
func (n *Node) AddHistoryEvent(t enumspb.EventType, setAttributes func(*historypb.HistoryEvent)) *historypb.HistoryEvent {
tree.go
450
>
return n.backend.AddHistoryEvent(t, setAttributes)
451
>
}
452
453
// GenerateEventLoadToken generates a token for loading the given history event via [LoadHistoryEvent].
454
// Must be called within an [Environment.Access] function block for an event that was just added or is currently
455
// being applied in the active transaction.
456
>
func (n *Node) GenerateEventLoadToken(event *historypb.HistoryEvent) ([]byte, error) {
tree.go
457
>
return n.backend.GenerateEventLoadToken(event)
458
>
}
459
460
// Load a history event by token generated via [GenerateEventLoadToken].
461
// Must be called within an [Environment.Access] function block with either read or write access.
462
>
func (n *Node) LoadHistoryEvent(ctx context.Context, token []byte) (*historypb.HistoryEvent, error) {
tree.go
463
>
return n.backend.LoadHistoryEvent(ctx, token)
464
>
}
465
466
// MachineData deserializes the persistent state machine's data, casts it to type T, and returns it.
467
// Returns an error when deserialization or casting fails.
468
>
func MachineData[T any](n *Node) (T, error) {
tree.go
469
>
var t T
470
>
if n.cache.dataLoaded {
471
>
if t, ok := n.cache.data.(T); ok {
tree.go
472
>
return t, nil
473
>
}
474
return t, ErrIncompatibleType
475
}