@@ -44,6 +44,7 @@ use crate::query_plan::query_planning_traversal::BestQueryPlanInfo;
44
44
use crate :: query_plan:: query_planning_traversal:: QueryPlanningParameters ;
45
45
use crate :: query_plan:: query_planning_traversal:: QueryPlanningTraversal ;
46
46
use crate :: query_plan:: query_planning_traversal:: convert_type_from_subgraph;
47
+ use crate :: query_plan:: query_planning_traversal:: non_local_selections_estimation;
47
48
use crate :: schema:: ValidFederationSchema ;
48
49
use crate :: schema:: position:: AbstractTypeDefinitionPosition ;
49
50
use crate :: schema:: position:: CompositeTypeDefinitionPosition ;
@@ -172,7 +173,7 @@ pub struct QueryPlanningStatistics {
172
173
pub evaluated_plan_paths : Cell < usize > ,
173
174
}
174
175
175
- #[ derive( Default , Clone ) ]
176
+ #[ derive( Clone ) ]
176
177
pub struct QueryPlanOptions < ' a > {
177
178
/// A set of labels which will be used _during query planning_ to
178
179
/// enable/disable edges with a matching label in their override condition.
@@ -183,6 +184,19 @@ pub struct QueryPlanOptions<'a> {
183
184
pub override_conditions : Vec < String > ,
184
185
185
186
pub check_for_cooperative_cancellation : Option < & ' a dyn Fn ( ) -> ControlFlow < ( ) > > ,
187
+ /// Impose a limit on the number of non-local selections, which can be a
188
+ /// performance hazard. On by default.
189
+ pub non_local_selections_limit_enabled : bool ,
190
+ }
191
+
192
+ impl Default for QueryPlanOptions < ' _ > {
193
+ fn default ( ) -> Self {
194
+ Self {
195
+ override_conditions : Vec :: new ( ) ,
196
+ check_for_cooperative_cancellation : None ,
197
+ non_local_selections_limit_enabled : true ,
198
+ }
199
+ }
186
200
}
187
201
188
202
impl std:: fmt:: Debug for QueryPlanOptions < ' _ > {
@@ -197,6 +211,10 @@ impl std::fmt::Debug for QueryPlanOptions<'_> {
197
211
& "None"
198
212
} ,
199
213
)
214
+ . field (
215
+ "non_local_selections_limit_enabled" ,
216
+ & self . non_local_selections_limit_enabled ,
217
+ )
200
218
. finish ( )
201
219
}
202
220
}
@@ -224,7 +242,7 @@ pub struct QueryPlanner {
224
242
/// subgraphs.
225
243
// PORT_NOTE: Named `inconsistentAbstractTypesRuntimes` in the JS codebase, which was slightly
226
244
// confusing.
227
- abstract_types_with_inconsistent_runtime_types : IndexSet < AbstractTypeDefinitionPosition > ,
245
+ abstract_types_with_inconsistent_runtime_types : IndexSet < Name > ,
228
246
}
229
247
230
248
impl QueryPlanner {
@@ -317,6 +335,7 @@ impl QueryPlanner {
317
335
. get_types ( )
318
336
. filter_map ( |position| AbstractTypeDefinitionPosition :: try_from ( position) . ok ( ) )
319
337
. filter ( |position| is_inconsistent ( position. clone ( ) ) )
338
+ . map ( |position| position. type_name ( ) . clone ( ) )
320
339
. collect :: < IndexSet < _ > > ( ) ;
321
340
322
341
Ok ( Self {
@@ -443,10 +462,23 @@ impl QueryPlanner {
443
462
fetch_id_generator : Arc :: new ( FetchIdGenerator :: new ( ) ) ,
444
463
} ;
445
464
465
+ let mut non_local_selection_state = options
466
+ . non_local_selections_limit_enabled
467
+ . then ( non_local_selections_estimation:: State :: default) ;
446
468
let root_node = if !defer_conditions. is_empty ( ) {
447
- compute_plan_for_defer_conditionals ( & mut parameters, & mut processor, defer_conditions)
469
+ compute_plan_for_defer_conditionals (
470
+ & mut parameters,
471
+ & mut processor,
472
+ defer_conditions,
473
+ & mut non_local_selection_state,
474
+ )
448
475
} else {
449
- compute_plan_internal ( & mut parameters, & mut processor, has_defers)
476
+ compute_plan_internal (
477
+ & mut parameters,
478
+ & mut processor,
479
+ has_defers,
480
+ & mut non_local_selection_state,
481
+ )
450
482
} ?;
451
483
452
484
let root_node = match root_node {
@@ -521,6 +553,7 @@ impl QueryPlanner {
521
553
fn compute_root_serial_dependency_graph (
522
554
parameters : & QueryPlanningParameters ,
523
555
has_defers : bool ,
556
+ non_local_selection_state : & mut Option < non_local_selections_estimation:: State > ,
524
557
) -> Result < Vec < FetchDependencyGraph > , FederationError > {
525
558
let QueryPlanningParameters {
526
559
supergraph_schema,
@@ -547,14 +580,24 @@ fn compute_root_serial_dependency_graph(
547
580
mut fetch_dependency_graph,
548
581
path_tree : mut prev_path,
549
582
..
550
- } = compute_root_parallel_best_plan ( parameters, selection_set, has_defers) ?;
583
+ } = compute_root_parallel_best_plan (
584
+ parameters,
585
+ selection_set,
586
+ has_defers,
587
+ non_local_selection_state,
588
+ ) ?;
551
589
let mut prev_subgraph = only_root_subgraph ( & fetch_dependency_graph) ?;
552
590
for selection_set in split_roots {
553
591
let BestQueryPlanInfo {
554
592
fetch_dependency_graph : new_dep_graph,
555
593
path_tree : new_path,
556
594
..
557
- } = compute_root_parallel_best_plan ( parameters, selection_set, has_defers) ?;
595
+ } = compute_root_parallel_best_plan (
596
+ parameters,
597
+ selection_set,
598
+ has_defers,
599
+ non_local_selection_state,
600
+ ) ?;
558
601
let new_subgraph = only_root_subgraph ( & new_dep_graph) ?;
559
602
if new_subgraph == prev_subgraph {
560
603
// The new operation (think 'mutation' operation) is on the same subgraph than the previous one, so we can concat them in a single fetch
@@ -677,10 +720,16 @@ pub(crate) fn compute_root_fetch_groups(
677
720
fn compute_root_parallel_dependency_graph (
678
721
parameters : & QueryPlanningParameters ,
679
722
has_defers : bool ,
723
+ non_local_selection_state : & mut Option < non_local_selections_estimation:: State > ,
680
724
) -> Result < FetchDependencyGraph , FederationError > {
681
725
trace ! ( "Starting process to construct a parallel fetch dependency graph" ) ;
682
726
let selection_set = parameters. operation . selection_set . clone ( ) ;
683
- let best_plan = compute_root_parallel_best_plan ( parameters, selection_set, has_defers) ?;
727
+ let best_plan = compute_root_parallel_best_plan (
728
+ parameters,
729
+ selection_set,
730
+ has_defers,
731
+ non_local_selection_state,
732
+ ) ?;
684
733
snapshot ! (
685
734
"FetchDependencyGraph" ,
686
735
best_plan. fetch_dependency_graph. to_dot( ) ,
@@ -693,13 +742,15 @@ fn compute_root_parallel_best_plan(
693
742
parameters : & QueryPlanningParameters ,
694
743
selection : SelectionSet ,
695
744
has_defers : bool ,
745
+ non_local_selection_state : & mut Option < non_local_selections_estimation:: State > ,
696
746
) -> Result < BestQueryPlanInfo , FederationError > {
697
747
let planning_traversal = QueryPlanningTraversal :: new (
698
748
parameters,
699
749
selection,
700
750
has_defers,
701
751
parameters. operation . root_kind ,
702
752
FetchDependencyGraphToCostProcessor ,
753
+ non_local_selection_state. as_mut ( ) ,
703
754
) ?;
704
755
705
756
// Getting no plan means the query is essentially unsatisfiable (it's a valid query, but we can prove it will never return a result),
@@ -713,11 +764,16 @@ fn compute_plan_internal(
713
764
parameters : & mut QueryPlanningParameters ,
714
765
processor : & mut FetchDependencyGraphToQueryPlanProcessor ,
715
766
has_defers : bool ,
767
+ non_local_selection_state : & mut Option < non_local_selections_estimation:: State > ,
716
768
) -> Result < Option < PlanNode > , FederationError > {
717
769
let root_kind = parameters. operation . root_kind ;
718
770
719
771
let ( main, deferred, primary_selection) = if root_kind == SchemaRootDefinitionKind :: Mutation {
720
- let dependency_graphs = compute_root_serial_dependency_graph ( parameters, has_defers) ?;
772
+ let dependency_graphs = compute_root_serial_dependency_graph (
773
+ parameters,
774
+ has_defers,
775
+ non_local_selection_state,
776
+ ) ?;
721
777
let mut main = None ;
722
778
let mut deferred = vec ! [ ] ;
723
779
let mut primary_selection = None :: < SelectionSet > ;
@@ -741,7 +797,11 @@ fn compute_plan_internal(
741
797
}
742
798
( main, deferred, primary_selection)
743
799
} else {
744
- let mut dependency_graph = compute_root_parallel_dependency_graph ( parameters, has_defers) ?;
800
+ let mut dependency_graph = compute_root_parallel_dependency_graph (
801
+ parameters,
802
+ has_defers,
803
+ non_local_selection_state,
804
+ ) ?;
745
805
746
806
let ( main, deferred) = dependency_graph. process ( & mut * processor, root_kind) ?;
747
807
snapshot ! (
@@ -769,13 +829,14 @@ fn compute_plan_for_defer_conditionals(
769
829
parameters : & mut QueryPlanningParameters ,
770
830
processor : & mut FetchDependencyGraphToQueryPlanProcessor ,
771
831
defer_conditions : IndexMap < Name , IndexSet < String > > ,
832
+ non_local_selection_state : & mut Option < non_local_selections_estimation:: State > ,
772
833
) -> Result < Option < PlanNode > , FederationError > {
773
834
generate_condition_nodes (
774
835
parameters. operation . clone ( ) ,
775
836
defer_conditions. iter ( ) ,
776
837
& mut |op| {
777
838
parameters. operation = op;
778
- compute_plan_internal ( parameters, processor, true )
839
+ compute_plan_internal ( parameters, processor, true , non_local_selection_state )
779
840
} ,
780
841
)
781
842
}
0 commit comments