Repository navigation
Conversation
SpanData is what a TagContributor or TagExtractor may read and set on a span: the setTag overloads (by name and by id) and getTag, with the span's tag semantics (a null value removes the tag, the interceptor runs), plus setResourceName, setError and setMeasured. AgentSpan extends it with covariant returns, and the contributor and extractor now take a SpanData. DDSpanContext is a SpanData too: its setTag family returns this. Its setTagsFrom takes the tag lock once and hands the contributor a HeldSpanData that lives only for that call: it forwards to new package-private *HoldingLock variants of setTag, removeTag and getTag (the same bodies without the synchronized), and asserts the lock is still held. Contributor call sites are monomorphic by design, so the wrapper should be scalar-replaced. The public setters are unchanged. SetTagsFromBenchmark compares a jdbc span's nine tags one by one, through a contributor and through an extractor, on a reused and a fresh span. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What Does This Do
setTagsFromnow takes the span's tag lock once for a whole batch of tags, instead of once persetTag, while keeping the span's tag semantics.SpanDatais a new interface: what aTagContributororTagExtractormay read and set on a span.setTagoverloads by name and by id, plussetTag(EntryReader). A null value removes the tag, and the tag interceptor runs.getTag.setResourceName,setErrorandsetMeasured.AgentSpan extends SpanData, with covariantAgentSpanreturns.TagContributor.addToandTagExtractor.extracttake aSpanDatainstead of anAgentSpan. Nothing in production implements either yet.DDSpanContextis aSpanData. ItssetTagfamily returnsthisinstead ofvoid, and it gainssetResourceName(CharSequence)andsetError(boolean)at default priority.DDSpan.setTagsFromdelegates toDDSpanContext.setTagsFrom. That takes the tag lock once and hands the contributor or extractor aHeldSpanData, whichDDSpanContextprovides.HeldSpanDataforwards to new package-private*HoldingLockvariants ofsetTag,removeTagandgetTag: the same bodies without thesynchronized.setTagsFromcall, and asserts that the lock is still held.@NoEscape. Contributor call sites are monomorphic by design (@Strategy), so it should be scalar-replaced.setTagcalls.Motivation
One lock per batch. A decorator's run of
setTagcalls takes and releases the span's tag lock once per call. JDK 17 can't coarsen those locks across the interceptor's calls. A held outer lock doesn't help either, because a recursive monitor enter still does an atomic update.The vocabulary keeps the contracts apart.
setTagandgetTag, means intercepted and locking.SpanStorage(Introduce SpanStorage for eager tag post-processors (dense store - part 3) #13001), withloadandstore, means raw.HeldSpanDataadds a third behavior, intercepted with the lock already held. It's a separate short-lived object, so no existing method changes what it means.No adapter on hot shared paths. The post-processor chain is megamorphic, so an adapter handed down it would always escape. That's why
SpanStoragepassesDDSpanContextitself. Contributor sites are monomorphic, which is what makes a short-lived wrapper viable here.Additional Notes
setAllTagsalready intercepts while holding it, and interceptor callbacks re-enter the span's locking setters, since the lock is reentrant.SetTagsFromBenchmarkis new, but its numbers are still to come. It compares 9 jdbc tags (8 known by id, including an int and the interceptedspan.kind, plus 1 custom) one by one, through a contributor, and through an extractor, on a reused span and on a fresh span.-prof gcchecks thatHeldSpanDatais scalar-replaced.DDSpanSetTagsFromTestchecks that:setTagcalls set;resource.nameandspan.kind), and reads see the batch's own writes;SpanDataused after the call trips the assertion.TagMapimplementsMapbut doesn't overrideequals, so two maps with the same contents aren't equal. It's pre-existing and not fixed here; the test compares plain map copies.🤖 Generated with Claude Code