Skip to content

Extract TagMap's bucket mechanics into HashSupport (dense store - part 4) - #13002

Open
dougqh wants to merge 8 commits into
dougqh/eager-postprocessors-span-contextfrom
dougqh/tagmap-hash-support
Open

dougqh wants to merge 8 commits into
dougqh/eager-postprocessors-span-contextfrom
dougqh/tagmap-hash-support

Conversation

@dougqh

@dougqh dougqh commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

What Does This Do

A pure move. TagMap's loops over one bucket array become static methods of a new HashSupport class, moved verbatim:

  • find, put, remove, copy and merge;
  • the forEach variants, fillMap and fillStringMap;
  • count, isEmpty, the bucket-position check and toInternalString.

Each method reports what it did through its return value: the entry that put replaced, the entry that remove removed, and how much merge grew the map. TagMap keeps its fields and its size counter, plus the read-through and tombstone handling around those calls.

Motivation

The next PR in the stack splits a span's tags into a known-tag store and a custom-tag store. Both reuse these mechanics, so this moves them out first and reviews the move on its own, separate from the split.

Additional Notes

  • No new objects or fields, and no behavior change. Allocation per trace matches the base, and the TagMap and core span suites pass unchanged.
  • The bucket-integrity check was copied as-is. It still has a pre-existing indexing bug (it uses the outer bucket index inside the group loop). The split PR next in the stack fixes it, so this one stays a verbatim move.

Where this is going

This PR is one step in replacing the span's single TagMap with storage that knows each tag's kind. The goal is to cut what every span allocates on the application thread, without changing behavior.

The end state

Later, not in this stack: cheaper read-through to parent spans, trace-level tags in a per-trace holder (TraceSegment), and primitive tag values without boxing.

The stack. This replaces #12918, split into pieces that can each be reviewed, and measured, on their own.

PR Step Allocation per 7-span trace (flag off unless noted)
#12999 A null tag value removes the tag in TagMap. This is the stack's only behavior change, kept separate on purpose. unchanged
#12992 Bucket known tags by slot in TagMap, and add TraceShapeBenchmark −96 B vs master
#13001 TagStore for the eager post-processors unchanged
#13002 Extract TagMap's bucket mechanics into HashSupport (a pure move) unchanged
#13006 Add the id and name tag stores, not yet used unchanged
#13007 Make TagMap a facade over the two stores unchanged
#13003 Have the span own its tag stores directly +104 B (+1.3%)
#13004 Dense id store behind trace.experimental.dense.tags.enabled (off by default) flag on: −30.6%
#12926 Turn the dense store on by default, add sizing hints and bulk prototype seeding flag on: about 3% less again

Every PR after #12999 is behavior-preserving.

The pieces' allocation figures come from a deterministic per-thread probe (ThreadMXBean allocated bytes) that builds the same 7-span trace as TraceShapeBenchmark. The #12992 and #12926 figures come from TraceShapeBenchmark itself.

🤖 Generated with Claude Code

@datadog-prod-us1-5

This comment has been minimized.

@dd-octo-sts

dd-octo-sts Bot commented Oct 23, 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.76 s 14.59 s [+0.4%; +2.0%] (maybe worse)
startup:insecure-bank:tracing:Agent 13.57 s 13.69 s [-1.6%; -0.0%] (maybe better)
startup:petclinic:appsec:Agent 17.17 s 17.05 s [-0.1%; +1.5%] (no difference)
startup:petclinic:iast:Agent 17.01 s 17.01 s [-0.9%; +0.8%] (no difference)
startup:petclinic:profiling:Agent 16.64 s 16.95 s [-3.0%; -0.6%] (maybe better)
startup:petclinic:sca:Agent 17.07 s 16.97 s [-0.1%; +1.3%] (no difference)
startup:petclinic:tracing:Agent 16.19 s 16.08 s [-0.1%; +1.5%] (no difference)

Commit: a6470291 · 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.

@dougqh dougqh changed the title Extract TagMap's bucket mechanics into HashSupport Extract TagMap's bucket mechanics into HashSupport (dense store - part 4) Oct 23, 2026
@bric3
bric3 added this pull request to stack #13019 October 23, 2026 16:02
A pure move: the loops over one bucket array (find, put, remove, copy,
merge, the forEach variants, fillMap / fillStringMap, count, isEmpty,
the bucket-position check, toInternalString) become static methods of
HashSupport, moved verbatim. Each reports what it did through its
return value (the entry put replaced, the entry remove removed, how much
merge grew the map), and TagMap keeps its fields, its size counter, and
the read-through and tombstone handling around them.

No new objects or fields, and no behavior change: allocation per trace
in TraceShapeBenchmark matches the base within fork-to-fork noise, and
the TagMap and core span suites pass unchanged. This prepares the split
of known and custom tags into separate stores, which reuse these
mechanics.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dougqh
dougqh force-pushed the dougqh/tagmap-hash-support branch from 4c83a5c to d5a7f64 Compare October 23, 2026 16:57
* entry it replaced, remove the entry it removed, merge how much the map grew -- and the calling
* map keeps its own count. Read-through to a parent map and its tombstones stay with the map.
*/
final class HashSupport {

@dougqh dougqh Oct 26, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is just relocating the guts of TagMap into a static helper class.
This is being done, so that we can transition to a hash store for name and another hash store by ID - which is itself an incremental step towards hash-based store for names only and the new dense store for IDs.

@dougqh
dougqh marked this pull request as ready for review October 26, 2026 20:46
@dougqh
dougqh requested a review from a team as a code owner October 26, 2026 20:46
@dougqh
dougqh removed the request for review from a team October 26, 2026 20:46
@dougqh
dougqh requested a review from claponcet October 26, 2026 20:46
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-26T20:48:48.068480Z 76d27dc Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@datadog-prod-us1-5 datadog-prod-us1-5 Bot 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.

Bits Code Review: PASS

More details

Bucket mutations preserve replacement, removal, and merge-growth reporting to TagMap, maintaining its size accounting. Parent read-through and tombstone handling remain intact.

Was this helpful? React 👍 or 👎

Open Bits AI session

🤖 Bits Code Review · Commit 76d27dc

parentEntryVisible still masked the hash into a bucket by hand before
calling findInBucket, the one place outside HashSupport that knew the
bucket array's power-of-2 layout. It now calls HashSupport.find, and
findInBucket becomes private.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

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

Labels

comp: core Tracer core tag: ai generated Largely based on code generated by an AI or LLM tag: no release notes Changes to exclude from release notes type: refactoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant