Conversation
The automatic main class discovery in renaissance-core has been very unreliable lately, so we set it explicitly to avoid producing a bundle without Main-Class attribute in the manifest.
This communicates the need for efficient indexing into a SeqView in the functions computing feed stats.
The underlying buffer can be modified during stats computation and trigger ConcurrentModificationException. This uses a Range iterator (which will not change) and accesses the buffer elements using an explicit index. While still racy by design (they are just stats), any races should be benign.
farquet
approved these changes
Apr 4, 2022
Collaborator
farquet
left a comment
There was a problem hiding this comment.
Very nice analysis!
I agree that it makes sense not to add locking for a stats feature. Your fix is probably how one would want to solve this in an actual production workload.
I've tested your branch locally and numbers are comparable with renaissance 0.14 as expected.
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.
The switch to Scala 2.13 apparently unearthed an issue that has been present in
finagle-chirperall the time. The code changes infinagle-chirperbetween Renaissance 0.13 and Renaissance 0.14 were only meant to "port" it to Scala 2.13 and required changing the signature of various methods that compute feed stats to accept aSeqViewinstead ofSeq(because in Scala 2.13, a non-strictSeqViewis no longer a subtype of a strictSeq), but even in Scala 2.12, theviewmethod of anArrayBufferreturned aSeqView.The main cause appears to be the fact that the
analyze()method accesses anArrayBuffer(representing a per-user feed) without a lock. The feed is appended to under a lock in theMaster, but no lock is held when calculating stats on individual feeds (in aFuture). When processing a request for feed stats, the lock is held while creating a read only snapshot of the trie that holds all user feeds and a view is created for each feed (which essentially snapshots the number of items in the feed), but the view is processed later.The
analyze()function running as part of the future evaluation uses an iterator to go over chirps in a feed, but the underlying ArrayBuffer can be modified (appended to) in the meantime. In Scala 2.13 this results in theConcurrentModificationException. I tested the same code in Scala 2.12 (with the same libraries) and I was not able to reproduce the problem.Now, I believe that the race is intentional and should be benign (similar to updating profiling counters in hotspot), so to keep it the way it was, I just changed the
analyze()method to avoid using an iterator and instead iterate over aRangeand then access theArrayBufferelements by index. This should be "safe" even if theArrayBufferis expanded (and the backing array changed) because theArrayBufferis only appended to. Using a direct index should either fetch the element from an old array or the new array, but the returned item should be the same — assuming the implementation updates the reference to the backing array after it has copied the contents of the old array to the new array.Fixes #354 (as long as keeping the race can be considered a fix)