Loki: Fix bug where items are returned to a sync.Pool incorrectly #4518
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.
#4160 correctly fixed an issue to make sure all iterators are properly closed when nonOverlappingSampleIterator's Close() method is called.
However, there was an unexpected side effect with this change.
It introduced occurences of the iterators close method being called more than once.
Loki has a mix of iterators that will error if closed more than once and others that need to be idempotent, there are some situations where an iterator wrapping another iterator can't always know if the underlying iterator(s) have been closed already so it does result in Close() being called twice.
We discovered a case where the SampleIteratorWithClose was not properly idempotent resulting in a somewhat obscure and difficult to find problem as Cyril described in #4512
The memchunk.go and unordered.go's use of the close function both return elements to a sync.Pool
Our understanding here is that the first call would return the items to the pool correctly, however when any subsequent calls to the iterators close were made, the iterator still holds references to the same items already returned to the pool. These same items could possibly have been lended out by the pool again between calls to the close funtion. This results in items actively in use being put back into the pool where they could be lended out again. Making it possible for multiple separate iterators to all have references to the same items and memory from the pool.
a sync.Once{} has been added to the iterator to make sure the close function is idempotent.
Fixes #4512