Remove containerTagsHash/processTags from DSM primary pathway hash - #12573
arjunguhaswe wants to merge 7 commits into
Conversation
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>
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>
🟢 Java Benchmark SLOs — All performance SLOs passed
PR vs. master results
Commit: Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion. |
…ntainertagshashprocesstags-from-dsm
Testing evidenceRan 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) |
There was a problem hiding this comment.
💡 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".
| } | ||
|
|
||
| /** | ||
| * DSM topology-identity hash: service + env + primary tag only. Unlike {@link #getBaseHash()} |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
left a comment
There was a problem hiding this comment.
Left minor comments.
| identityHash = | ||
| calcIdentity( | ||
| Config.get().getServiceName(), Config.get().getEnv(), Config.get().getPrimaryTag()); |
There was a problem hiding this comment.
Just curious: If this can mutate during app lifetime or can be calculated once?
There was a problem hiding this comment.
I believe these dimensions are completely static.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Well that was Claude ☝️, but i do think it's a good suggestion to calc once.
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
left a comment
There was a problem hiding this comment.
LGTM from LP side, but I think it make sense to get an approval from DSM/IDM too?
Summary
Fixes DSM2-335: DSM's primary pathway
hashwas seeded fromBaseHash.getBaseHash(), a global static shared with DBM that folds inserviceName + env + primaryTag + processTags + containerTagsHash.containerTagsHashis derived by the local Agent fromkube_replica_setand changes on every rolling deploy;processTagsis enabled by default. SinceDDAgentFeaturesDiscovery.processInfoResponseHeaders()recalculatesBaseHashunconditionally whenever the Agent reports a new container-tags hash, the same logical DSM edge (same service, same topic, same direction) was producing a new pathwayhashon every rolling deploy — permanently inflatingblock_on_hashescardinality 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 tagsDataStreamsTagsTest: container-tags hash / process tag changes affectaggregationHash/completeHashbut not the primaryhash(the DSM2-335 regression tests)DefaultPathwayContextTestupdated to seed via the newBaseHash.updateIdentityHash()test hookSQLCommenterTestsuite (DBM, 91 tests) passes unmodified — confirmsBaseHash.getBaseHash()behavior for DBM is untoucheddatasetNamebug is an equally plausible explanation for versions before that🤖 Generated with Claude Code