4.x: Make TailRecursiveSink lock-free and have less allocations #499
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.
This PR changes
TailRecursiveSinkto a lock-free algorithm as well as reduces the allocations in the class by inlining variousIDisposablefields.The aim of the class is to make sure
OnCompleteorOnErrorinConcat,Catchand various other operators don't trigger an infinite recursion but stay on the level.This could have been solved with a straightforward trampoline like this
Concatimplementation, however, there is a small complication. The recursion may be not only on the termination side, but on the existence of the innerIObservables.For example, to avoid yet another level of recursion due to graphs like
Concat(Concat(a, b), Concat(c, d)), theExtractmethod can get another level ofIEnumerable<IObservable<TSource>>on the current level, and the concatenation should resume on the innerConcat.The
Stackis there to allow returning to an outer enumeration and resume it. I don't know what the length stack was supposed to do; the algorithm doesn't have to know how long eachIEnumeratoris. Was it some kind of optimization for Lists and arrays avoidingMoveNext() == falseand thusIEnumerator.Dispose()? The former should be as costly as an index comparison and the latter should be no-op anyway.