Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DRAFT] improve generate fragment compression #6651

Draft
wants to merge 2 commits into
base: dev
Choose a base branch
from
Draft

Conversation

dariuszkuc
Copy link
Member

Description here

Fixes #issue_number


Checklist

Complete the checklist (and note appropriate exceptions) before the PR is marked ready-for-review.

  • Changes are compatible1
  • Documentation2 completed
  • Performance impact assessed and acceptable
  • Tests added and passing3
    • Unit Tests
    • Integration Tests
    • Manual Tests

Exceptions

Note any exceptions here

Notes

Footnotes

  1. It may be appropriate to bring upcoming changes to the attention of other (impacted) groups. Please endeavour to do this before seeking PR approval. The mechanism for doing this will vary considerably, so use your judgement as to how and when to do this.

  2. Configuration is an important part of many changes. Where applicable please try to document configuration examples.

  3. Tick whichever testing boxes are applicable. If you are adding Manual Tests, please document the manual testing (extensively) in the Exceptions.

@dariuszkuc dariuszkuc changed the title improve generate fragment compression [DRAFT] improve generate fragment compression Jan 27, 2025
Copy link
Contributor

@dariuszkuc, please consider creating a changeset entry in /.changesets/. These instructions describe the process and tooling.

@svc-apollo-docs
Copy link
Collaborator

svc-apollo-docs commented Jan 27, 2025

✅ Docs preview has no changes

The preview was not built because there were no changes.

Build ID: f60ea5662e69c48eea3227a1

Copy link

@briannafugate408 briannafugate408 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just had one question out of curiosity 🗒️

@@ -373,6 +373,7 @@ impl Configuration {
QueryPlannerConfig {
subgraph_graphql_validation: false,
generate_query_fragments: self.supergraph.generate_query_fragments,
generate_query_fragments_v2: false,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out of curiosity: what is this false represent? is it a way to feature flag which generate query fragments function to use?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was just there so it compiles -> router initializes QP with user config (so this will be dropped actually)

apollo-federation/src/operation/optimize.rs Outdated Show resolved Hide resolved
Comment on lines +384 to +382
let hash = self.hash_key(parent_type, selection_set);
*self.selection_counts.entry(hash).or_insert(0) += 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if there is a hash collision here? We potentially generate fragments for things that might not need them? Is that all?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After thinking about this some more, a hash collision here wouldn't cause too many problems, but mapping a hash to a named fragment would. Perhaps the inner type that you declare in the hash_key function should be used as the keys.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use this hash value as a key for minimized_fragments so if we have a collision we would end up with potentially generating invalid operation as our named fragments would be incorrect.

apollo-federation/src/operation/optimize.rs Outdated Show resolved Hide resolved
Comment on lines +201 to +209
impl Hash for SelectionMap {
fn hash<H: Hasher>(&self, state: &mut H) {
// NOTE: this is order dependent so { a b c } != { c b a }
for selection in &self.selections {
selection.hash(state);
}
}
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While this wouldn't trigger this lint, it does violate the stated problem. The PartialEq impl is order independent while the Hash impl is order dependent. This means you can trivially violate the key implication of hashes and eq (if two objects are equal, then their hashes must be equal). I don't think we're using this in a way that can cause problems, but I don't think we should make it possible to have this problem in the future.

I think a good alternative is to provide a wrapper type, say struct HashableSelectionMap<'a>(&'a SelectionMap);, that impls Hash but not PartialEq and remove the impl of Hash for SelectionMap.

Copy link
Member Author

@dariuszkuc dariuszkuc Jan 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SelectionMap stores selections on SelectionSet so I don't think adding new wrapper will do any good. Sounds like maybe we should be using IndexMap instead (which sounds like a potentially large refactor)?

@@ -60,6 +61,7 @@ pub struct QueryPlannerConfig {
///
/// Defaults to false.
pub generate_query_fragments: bool,
pub generate_query_fragments_v2: bool,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this should be removed and generate_query_fragments should be something like Option<FragmentGenerationAlgo> (and have true map to Some(NewAlgo) and false map to None`). As is, I would read this config file as a switch + an algorithm, but it is implemented as two switches.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just a temp flag so I can easily run both algorithms from performance harness BUT it does raise a question -> do we want to provide multiple fragment generation algorithms? Personally I'd say no we probably shouldn't but it is definitely a possibility

apollo-federation/src/operation/optimize.rs Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants