ConditionalWeakTable - don't link Containers when no entries are transferred #108941
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.
ConditionalWeakTable uses internal Container objects for the underlying table. Container entries are write-once because the read path is lock-free. When a Container is full, a new Container is allocated, entries are copied, and compaction can occur (if there aren't any currently live enumerators relying on specific indices).
A two-pass finalization scheme is used to free the entries (dependent handles) and then the Containers themselves. Finalization provides a guarantee that the Container is no longer in use, and the second pass accounts for finalization resurrection. Because entries can be duplicated across Containers, each Container contains a link to the one that replaces it.
This can greatly extend the lifetime of Containers. (See #50683 and #108447.)
However, if the Container is empty and not being enumerated, there is no need to link it to the next Container. This PR handles that case, which includes microbenchmarks where single entries are added and removed from ConditionalWeakTable and equivalent tests where TransactionScope is functioning as a wrapper around a ConditionalWeakTable entry. Of course, this is only a partial solution because a single live entry or enumerator leaves the old behavior. Another caveat is that the finalization queue can be filled faster than it can be emptied, though this is more likely in microbenchmarks where other work isn't being done.