perf: pool and pre-allocate interned-string dict (#66)#68
Merged
Conversation
Closes #66. Fixes map rehashing and slice growth on repeated interned encode/decode when the Encoder/Decoder is reused. New SetInternedStringsDictCap(n) on both Encoder and Decoder sets an initial capacity hint for the dict, avoiding rehashes as entries are added. Reset paths now reuse dict storage (clear-in-place for maps, truncate for slices) instead of dropping it to the GC every session; PutEncoder/PutDecoder drop oversized dicts (> 4096 entries) so a one-off large session doesn't permanently bloat pool memory. Introduces a dictOwned flag to track whether the dict was internally allocated or supplied by the caller via ResetDict/WithDict. The Encoder/Decoder will never clear, truncate, or append into a caller-owned dict — a regression test covers both the encoder-clear and decoder-alias clobber scenarios. A new allocation-based reuse test asserts 0 encoder allocs / 1 decoder alloc on the Reset+encode/decode hot loop (would fail on the pre-fix code).
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.
Summary
Closes #66. Pools and pre-allocates the interned-string dict so repeated encode/decode under a reused
Encoder/Decoderdoesn't rehash the map or regrow the slice.SetInternedStringsDictCap(n int)on bothEncoderandDecoder— initial capacity hint for the dict, clamped to[0, maxDictLen].PutEncoder/PutDecoderdrop dicts that grew pastinternDictPoolCap = 4096so a one-off large interning session doesn't permanently bloat pool memory (mirrors the existingwbuf/bufcap-drop pattern).dictOwnedbool so caller-supplied dicts (viaResetDict/WithDict) are never cleared, truncated, or appended into — regression test covers both the encoder-clear and decoder-alias clobber scenarios that a first draft of this patch had.Test plan
go test ./...passesgo test -race ./...passesgo vet ./...cleanTestInternedStringDictStorageIsReusedusestesting.AllocsPerRunto assert 0 encoder allocs / 1 decoder alloc (only the unavoidable string copy) on the reuse hot path — load-bearing, would fail on the pre-fix codeTestResetDoesNotMutateCallerDictguards against the ownership bugsTestInternedString,TestInternedStringTag,TestResetDict,TestMapWithInternedString) still pass