[COLLECTIONS-885] PatriciaTrie. Prevent silent mutations, prevents CMEs when iterating.#672
Conversation
…iews with subMap, headMap, tailMap, and prefixMap. Fixes shared usage where even simple read access among multiple iterating threads results in ConcurrentModificationExceptions.
| * A null-safe utility method for calling {@link KeyAnalyzer#compare(Object, Object)} | ||
| */ | ||
| final boolean compareKeys(final K key, final K other) { | ||
| final boolean keysAreEqual(final K key, final K other) { |
There was a problem hiding this comment.
Renamed as this method name is a little misleading, it's actually checking that the keys are equal, in a null-safe manner, returning a boolean, not an int as you would expect.
| assertTrue(trie.prefixMap(prefixString).containsKey(longerString)); | ||
| } | ||
|
|
||
| @Test |
There was a problem hiding this comment.
Added these simple tests to verify continued correctness of the modified methods.
I could also add a threaded test which verifies there is no CME when one thread is iterating and another is creating a new sub/tail/head/prefix map view, but it's not guaranteed to result in a CME depending on timing. From my own local testing using a constantly iterating thread and a second thread which constantly creates new map views it fixes the issue, no CMEs on the new branch.
There was a problem hiding this comment.
Hello @griffinjm
This class is not advertised as thread-safe so we don't need to further complicate the code with multi-threaded testing.
garydgregory
left a comment
There was a problem hiding this comment.
Hello Hello @griffinjm
If I only apply the test side of the patch, all the tests still pass, the new tests should fail. This means a regression could undo whatever the main changes claim to make.
Some methods in AbstractPatriciaTrie use a pattern where they silently mutate the trie when searching for a key which is not an exact match for an existing key in the Trie. Said methods are invoked by subMap/tailMap/headMap/prefixMap under the hood. This results in CMEs for even simple shared read access.
The referenced modCount is used as a fail-fast mechanism in the iterators.
This fix prevents the issue by instead:
See https://issues.apache.org/jira/browse/COLLECTIONS-885 for all details.