Skip to content

Remove containerTagsHash/processTags from DSM primary pathway hash - #12573

Open
arjunguhaswe wants to merge 7 commits into
masterfrom
arjunguha/dsm2-335-dd-trace-java-remove-containertagshashprocesstags-from-dsm
Open

arjunguhaswe wants to merge 7 commits into
masterfrom
arjunguha/dsm2-335-dd-trace-java-remove-containertagshashprocesstags-from-dsm

Conversation

@arjunguhaswe

@arjunguhaswe arjunguhaswe commented Sep 18, 2026

Copy link
Copy Markdown

Summary

Fixes DSM2-335: DSM's primary pathway hash was seeded from BaseHash.getBaseHash(), a global static shared with DBM that folds in serviceName + env + primaryTag + processTags + containerTagsHash. containerTagsHash is derived by the local Agent from kube_replica_set and changes on every rolling deploy; processTags is enabled by default. Since DDAgentFeaturesDiscovery.processInfoResponseHeaders() recalculates BaseHash unconditionally whenever the Agent reports a new container-tags hash, the same logical DSM edge (same service, same topic, same direction) was producing a new pathway hash on every rolling deploy — permanently inflating block_on_hashes cardinality with no real fan-out.

Testing evidence

Ran the repro against the Data Streams Sandbox account (metrics collection happens in the Datadog HQ / org2 account).

Before (unpatched — primary hash fragments on rolling deploy)
Testing Run (Data Streams Prod)
Dropped Payload Metrics (Org2)

After (with this fix — primary hash stable across rolling deploy)
Testing Run (Data Streams Prod)
Dropped Payload Metrics (Org2)

Test plan

  • BaseHashTest: identity hash tracks service/env/primaryTag but is unaffected by container-tags hash or process tags
  • DataStreamsTagsTest: container-tags hash / process tag changes affect aggregationHash/completeHash but not the primary hash (the DSM2-335 regression tests)
  • DefaultPathwayContextTest updated to seed via the new BaseHash.updateIdentityHash() test hook
  • Existing SQLCommenterTest suite (DBM, 91 tests) passes unmodified — confirms BaseHash.getBaseHash() behavior for DBM is untouched
  • Manual verification against org 1300002025 (Huuuge Games) once available — recommend first confirming they're on dd-trace-java >= 1.58.0, since the already-fixed datasetName bug is an equally plausible explanation for versions before that

🤖 Generated with Claude Code

DataStreamsTags seeded its primary pathway hash from BaseHash.getBaseHash(),
a global static shared with DBM that folds in serviceName+env+primaryTag
plus process tags and the Agent-reported containerTagsHash. The latter two
are DBM-oriented (per-container SQL attribution) and change on every rolling
deploy, so the same logical DSM edge was producing a new pathway hash on
every deploy, inflating block_on_hashes cardinality with no real fan-out.

BaseHash now also exposes an identity-only hash (service+env+primaryTag),
which DSM's primary hash is seeded from; getBaseHash() is untouched so
DBM's SQL-comment injection keeps its existing per-container behavior.
containerTagsHash and process tags are instead folded into
DataStreamsTags.aggregationHash/completeHash, independently of each other,
mirroring the datasetName fix in bd3f6f5.

DSM2-335

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@arjunguhaswe arjunguhaswe added type: bug fix Bug fix comp: data streams Data Streams Monitoring tag: ai generated Largely based on code generated by an AI or LLM labels Sep 18, 2026
@linear-code

linear-code Bot commented Sep 18, 2026

Copy link
Copy Markdown

DSM2-335

@datadog-prod-us1-6

datadog-prod-us1-6 Bot commented Sep 18, 2026

Copy link
Copy Markdown

🎯 Code Coverage (details)
Patch Coverage: 100.00%
Overall Coverage: 59.12% (-0.00%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 8527d0d | Docs | Give us feedback!

arjunguhaswe and others added 2 commits September 18, 2026 17:15
They were never decoded into discrete tags by the backend, so folding
them into aggregationHash only added opaque cardinality with no
user-visible benefit. Leaves a TODO to tag a DSM backend owner before
this ships, since raphaelgavache flagged a related concern in PR #9282
that was never answered.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@dd-octo-sts

dd-octo-sts Bot commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

🟢 Java Benchmark SLOs — All performance SLOs passed

Suite Status
Startup 🟢 pass

SLO thresholds are defined here based on automatically generated metrics. A warning is raised when results are within 5% of the threshold.

PR vs. master results
Scenario Candidate master Δ (95% CI of mean)
startup:insecure-bank:iast:Agent 14.82 s 14.64 s [+0.1%; +2.3%] (maybe worse)
startup:insecure-bank:tracing:Agent 13.65 s 13.66 s [-0.8%; +0.6%] (no difference)
startup:petclinic:appsec:Agent 17.06 s 16.86 s [+0.2%; +2.1%] (maybe worse)
startup:petclinic:iast:Agent 16.94 s 17.01 s [-1.2%; +0.4%] (no difference)
startup:petclinic:profiling:Agent 16.80 s 16.72 s [-0.7%; +1.6%] (no difference)
startup:petclinic:sca:Agent 16.93 s 16.71 s [+0.4%; +2.3%] (maybe worse)
startup:petclinic:tracing:Agent 16.15 s 16.09 s [-0.8%; +1.5%] (no difference)

Commit: 8527d0d4 · CI Pipeline · Benchmarking Platform UI


Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion.

@arjunguhaswe

Copy link
Copy Markdown
Author

Testing evidence

Ran the repro against the Data Streams Sandbox account (metrics collection happens in the Datadog HQ / org2 account).

Before (unpatched — primary hash fragments on rolling deploy)

After (with this fix — primary hash stable across rolling deploy)

@arjunguhaswe
arjunguhaswe marked this pull request as ready for review September 21, 2026 19:36
@arjunguhaswe
arjunguhaswe requested review from a team as code owners September 21, 2026 19:36
@arjunguhaswe
arjunguhaswe requested review from AlexeyKuznetsov-DD and removed request for a team September 21, 2026 19:36

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1ac2f088e8

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread internal-api/src/test/groovy/datadog/trace/api/BaseHashTest.groovy Outdated

@datadog-prod-us1-6 datadog-prod-us1-6 Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bits Code Review: PASS

More details

The identity hash follows the existing base-hash update path. DBM keeps its current hash behavior.

Was this helpful? React 👍 or 👎

Open Bits AI session

🤖 Bits Code Review · Commit 1ac2f08 · @DataDog review to ask questions

}

/**
* DSM topology-identity hash: service + env + primary tag only. Unlike {@link #getBaseHash()}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

so DBM added per container hash tags and such to differentiate containers, but i'm wondering if DSM shouldn't have an equivalent? (not for this PR necessarily, but generally). like our equivalent of container tags are like
{ kafkaClusterId, awsAccount, awsRegion, queueKind }? because if i happen to have an sqs queue and a kafka topic with the same name, shouldn't they be different? and the same topic on 2 kafka clusters or if i have a queue thats replicated across a couple of aws regions?

@arjunguhaswe arjunguhaswe Sep 21, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

It's an interesting thought. I do believe DataStreamsTags accomplishes this by incorporating such data into the node specific hash for some dimensions. Extending it seems like the correct approach:

  public String tagByIndex(int index) {
    switch (index) {
      case 0:
        return this.bus;
      case 1:
        return this.direction;
      case 2:
        return this.exchange;
      case 3:
        return this.topic;
      case 4:
        return this.type;
      case 5:
        return this.subscription;
      case 6:
        return this.kafkaClusterId;
      case 7:
        return this.datasetName;
      case 8:
        return this.datasetNamespace;
      case 9:
        return this.isManual;
      case 10:
        return this.group;
      case 11:
        return this.consumerGroup;
      case 12:
        return this.partition;
      case 13:
        return this.hasRoutingKey;
      default:
        return null;
    }
  } 

There are some categories that seem better as a primary_tag though, but that's highly dependent on the client's architecture.

@AlexeyKuznetsov-DD AlexeyKuznetsov-DD left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Left minor comments.

Comment thread internal-api/src/main/java/datadog/trace/api/BaseHash.java Outdated
Comment on lines +24 to +26
identityHash =
calcIdentity(
Config.get().getServiceName(), Config.get().getEnv(), Config.get().getPrimaryTag());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just curious: If this can mutate during app lifetime or can be calculated once?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I believe these dimensions are completely static.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

In production it can't mutate — Config.INSTANCE is private static final (set once at class-load), so serviceName/env/primaryTag are fixed for the JVM's lifetime once Config is built. The only thing that makes it look mutable is the test harness (WithConfigExtension/DDSpecification), which uses a load-time bytecode agent to strip final off Config.INSTANCE so tests can rebuild it between cases.

So this could in principle be computed once and cached rather than recomputed inside recalc() every time. I left it recomputed alongside baseHash for two reasons: it's cheap (2-3 FNV64 continuations over short strings, and recalc() only fires a handful of times per process — on the agent reporting a new container-tags hash, or on a process tag being added), and it keeps the existing BaseHashTest case ("Identity hash tracks service/env/primaryTag like base hash") able to exercise this by mutating Config and calling recalcBaseHash again, without extra plumbing to force a recompute. Happy to switch to a lazily-cached value if you'd rather avoid the redundant work — let me know.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Well that was Claude ☝️, but i do think it's a good suggestion to calc once.

arjunguhaswe and others added 3 commits September 21, 2026 16:37
internal-api unit tests should be JUnit 5 per AGENTS.md; the Spock
suites in BaseHashTest.groovy/DataStreamsTagsTest.groovy predate that
convention, so leave them as-is and add the new coverage in new JUnit 5
files instead of extending them further.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
service/env/primaryTag are fixed for the JVM's lifetime once Config is
built, so recomputing identityHash inside recalc() on every
containerTagsHash/processTags change was redundant. Compute it once at
class-load instead; calcIdentity is now package-private so it can be
exercised directly in tests without forcing a Config-driven recompute.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

@AlexeyKuznetsov-DD AlexeyKuznetsov-DD left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM from LP side, but I think it make sense to get an approval from DSM/IDM too?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp: data streams Data Streams Monitoring tag: ai generated Largely based on code generated by an AI or LLM type: bug fix Bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants