Skip to content

HollowSparseIntegerSet: skip the clone and CAS when set()/clear() would not change the bit - #872

Merged
Sunjeet merged 1 commit into
Netflix:masterfrom
arpitmalhotra:fix/sparseintegerset-skip-clone-when-unchanged
Oct 14, 2026
Merged

Sunjeet merged 1 commit into
Netflix:masterfrom
arpitmalhotra:fix/sparseintegerset-skip-clone-when-unchanged

Conversation

@arpitmalhotra

Copy link
Copy Markdown

Summary

SparseBitSet.set() and clear() cloned the bucket's long[] before checking whether the bit actually needed to change, and then always CASed a new Bucket into place. Re-setting a bit that is already set, or clearing one that is already clear, allocated a copy of the bucket and swapped in an identical one.

This is the same pattern as the ThreadSafeBitSet.set()/clear() fix, kept as a separate PR.

  • Check the bit against the published long[] first and return early when it is already in the target state, skipping both the clone and the CAS.
  • Published arrays are never mutated, so the clone is now done only on the paths that update an existing long in place. The grow/shrink paths already build a new array.

Testing

  • New testSetAndClearAreIdempotent: repeated set/clear of bits that share a long and a bucket, including clearing unset bits in an initialized long.
  • New testRepeatedSetAndClearMultipleThread: threads concurrently re-set every value, then concurrently re-clear the odd values, and the test checks the final contents.
  • SparseBitSetTest (10) and HollowSparseIntegerSetTest (2) pass.

🤖 Generated with Claude Code

…ld not change the bit

SparseBitSet.set() and clear() cloned the bucket's long[] on every call, before
checking whether the bit actually needed to change, and then always CASed a new
Bucket into place. Setting a bit that is already set, or clearing one that is
already clear (for a long that is initialized), therefore allocated a copy of
the bucket and replaced it with an identical one.

Check the bit against the published long[] first and return early when it is
already in the target state. Published arrays are never mutated, so the clone
now happens only on the paths that update an existing long in place; the paths
that grow or shrink the array already build a new one.

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

Copy link
Copy Markdown
Author

@jasonk000 this is the separate PR related to the comment from #871 (comment)

@Sunjeet
Sunjeet merged commit 547c2ac into Netflix:master Oct 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants