Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -330,3 +330,4 @@ Directory.Build.user.props
.claude/

src/Mocha/benchmarks/Mocha.Mediator.Benchmarks/Generated/
.work/
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public bool IsNodeSkipped(int nodeId)
&& (_failedOrSkippedBitset[index] & (1UL << (nodeId & 63))) != 0;
}

public void FillBacklog(OperationPlan plan)
public void FillBacklog(IOperationPlan plan)
{
_ready.Clear();
_backlogCount = 0;
Expand Down Expand Up @@ -180,7 +180,7 @@ public void CancelProcessing()
}

public void CompleteNode(
OperationPlan plan,
IOperationPlan plan,
ExecutionNode node,
ExecutionNodeResult result)
{
Expand Down Expand Up @@ -279,7 +279,7 @@ public void CompleteNode(
}
}

public void SkipNode(OperationPlan plan, ExecutionNode node)
public void SkipNode(IOperationPlan plan, ExecutionNode node)
{
_stack.Clear();
_stack.Push(node);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ namespace HotChocolate.Fusion.Execution.Nodes;
/// associated with this defer directive. This index maps to a bit position in the
/// runtime defer flags bitmask.
/// </param>
public sealed record DeferUsage(
public sealed record DeliveryGroup(
string? Label,
DeferUsage? Parent,
DeliveryGroup? Parent,
byte DeferConditionIndex)
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ public abstract class ExecutionNode : IOperationPlanNode, IEquatable<ExecutionNo
private IOperationPlanNode[] _dependents = [];
private IOperationPlanNode[] _dependencies = [];
private IOperationPlanNode[] _optionalDependencies = [];
private int[] _parentDependencies = [];
private int _dependentCount;
private int _dependencyCount;
private int _optionalDependencyCount;
private int _parentDependencyCount;

/// <summary>
/// The unique id of this execution node.
Expand Down Expand Up @@ -54,6 +56,13 @@ public abstract class ExecutionNode : IOperationPlanNode, IEquatable<ExecutionNo
/// </summary>
public ReadOnlySpan<IOperationPlanNode> OptionalDependencies => _optionalDependencies;

/// <summary>
/// Gets the identifiers of steps in the enclosing parent plan scope that
/// this node depends on. Used by deferred sub-plan nodes to reference
/// steps that live in the parent plan rather than the sub-plan itself.
/// </summary>
public ReadOnlySpan<int> ParentDependencies => _parentDependencies.AsSpan(0, _parentDependencyCount);

#pragma warning disable CA2012
public void BeginExecute(
OperationPlanContext context,
Expand Down Expand Up @@ -172,6 +181,23 @@ internal void AddDependent(IOperationPlanNode node)
_dependents[_dependentCount++] = node;
}

internal void AddParentDependency(int parentNodeId)
{
ExpectMutable();

if (_parentDependencies.Length == 0)
{
_parentDependencies = new int[4];
}

if (_parentDependencyCount == _parentDependencies.Length)
{
Array.Resize(ref _parentDependencies, _parentDependencyCount * 2);
}

_parentDependencies[_parentDependencyCount++] = parentNodeId;
}

internal void AddOptionalDependency(IOperationPlanNode node)
{
ExpectMutable();
Expand Down Expand Up @@ -215,9 +241,15 @@ protected internal void Seal()
Array.Resize(ref _optionalDependencies, _optionalDependencyCount);
}

if (_parentDependencies.Length > _parentDependencyCount)
{
Array.Resize(ref _parentDependencies, _parentDependencyCount);
}

Array.Sort(_dependencies, static (a, b) => a.Id.CompareTo(b.Id));
Array.Sort(_dependents, static (a, b) => a.Id.CompareTo(b.Id));
Array.Sort(_optionalDependencies, static (a, b) => a.Id.CompareTo(b.Id));
Array.Sort(_parentDependencies);

OnSealingNode();

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ namespace HotChocolate.Fusion.Execution.Nodes;
/// <param name="PathIncludeFlags">
/// The flags that must be all set for this selection to be included.
/// </param>
/// <param name="DeferUsage">
/// <param name="DeliveryGroup">
/// The defer usage context this field was collected under, or <c>null</c> if the field
/// is not inside a deferred fragment.
/// </param>
public sealed record FieldSelectionNode(
FieldNode Node,
ulong PathIncludeFlags,
DeferUsage? DeferUsage = null);
DeliveryGroup? DeliveryGroup = null);
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System.Collections.Immutable;

namespace HotChocolate.Fusion.Execution.Nodes;

/// <summary>
/// Represents the shared executor contract exposed by both root operation plans
/// and incremental execution subplans. Consumers in the executor pipeline (context
/// pooling, plan iteration, incremental delivery) depend only on this surface;
/// plan-specific metrics and subplan-specific state remain on the concrete types.
/// </summary>
public interface IOperationPlan
{
/// <summary>
/// Gets the unique identifier for this plan. The root plan's id is assigned by
/// the planner (for example, <c>"main"</c> or a content-addressed hash), while
/// a subplan's id is derived from its parent plan's id.
/// </summary>
string Id { get; }

/// <summary>
/// Gets the GraphQL operation associated with this plan. For the root plan this
/// is the incoming operation; for a subplan this is the compiled operation used
/// for the subplan's result mapping.
/// </summary>
Operation Operation { get; }

/// <summary>
/// Gets the root execution nodes that serve as entry points for this plan. On
/// the root plan these are the entry nodes of the full operation; on a subplan
/// these are the subplan's own entry nodes.
/// </summary>
ImmutableArray<ExecutionNode> RootNodes { get; }

/// <summary>
/// Gets all execution nodes belonging to this plan, including both root and
/// nested nodes.
/// </summary>
ImmutableArray<ExecutionNode> AllNodes { get; }

/// <summary>
/// Gets every <see cref="DeliveryGroup"/> (delivery group) this plan uses, in
/// ascending <see cref="DeliveryGroup.Id"/> order. Empty if the plan has no
/// <c>@defer</c> directives in scope.
/// </summary>
ImmutableArray<DeliveryGroup> DeliveryGroups { get; }

/// <summary>
/// Gets the incremental execution subplans emitted for this plan. Populated on the
/// root plan, empty on a subplan (subplans do not nest at the plan level; nesting
/// is modeled via <see cref="DeliveryGroup.Parent"/> on delivery groups).
/// </summary>
ImmutableArray<IncrementalPlan> IncrementalPlans { get; }

/// <summary>
/// Gets the maximum <see cref="ExecutionNode.Id"/> across all nodes in this
/// plan. Used by the executor's context pooling to size per-invocation node
/// arrays without reallocation.
/// </summary>
int MaxNodeId { get; }

/// <summary>
/// Retrieves an execution node by its unique identifier within this plan.
/// </summary>
/// <param name="id">The unique identifier of the execution node.</param>
/// <returns>The execution node with the specified identifier.</returns>
ExecutionNode GetNodeById(int id);

/// <summary>
/// Returns the <see cref="ExecutionNode"/> responsible for executing the
/// given plan node. If the plan node is already an execution node it is
/// returned directly; if it is a child operation (such as an operation
/// definition inside a batch) the containing execution node is returned.
/// </summary>
/// <param name="planNode">The plan node to resolve.</param>
/// <returns>The execution node that owns the given plan node.</returns>
ExecutionNode GetExecutionNode(IOperationPlanNode planNode);
}
Loading
Loading