Hello! A gentle ping: please review https://bugs.openjdk.java.net/browse/JDK-8244288 http://cr.openjdk.java.net/~tvaleev/webrev/8244288/r1/ The details are listed below.
With best regards, Tagir Valeev. On Sun, May 3, 2020 at 4:36 PM Tagir Valeev <amae...@gmail.com> wrote: > > Hello! > > Please review the following change: > https://bugs.openjdk.java.net/browse/JDK-8244288 > http://cr.openjdk.java.net/~tvaleev/webrev/8244288/r1/ > > We already implemented putIfAbsent, merge, computeIfAbsent, > computeIfPresent, and compute for TreeMap class (see JDK-8176894). > However, default implementations of these methods are still used for > TreeMap derived maps, such as descendingMap(), tailMap(), headMap() > and subMap(). The implementation is pretty straightforward, just a > range-check+delegation for each of these methods inside the > TreeMap.NavigableSubMap (+32 lines in TreeMap.java). Care should be > taken to avoid throwing IAE from compute* methods if the key is > outside of the range but we don't actually add the entry. This mimics > the previous behavior and also consistent with other modification > methods like Map.remove (we don't throw from remove if the key is out > of range, simply do nothing). > > To cover these changes with tests, I added new > TreeMap().descendingMap() to > InPlaceOpsCollisions.nullValueFriendlyMaps and > MapWithCollisionsProviders.makeMapsMoreTypes. This map should behave > like a normal Map modulo iteration order but implementation goes > through NavigableSubMap. Also, I added more adders to > LockStep::randomAdder (lines 572+) to cover new methods, as well as > some more throws IAE asserts around line 806. At the same time, I took > the liberty to modernize this test: > - Convert all the raw-types to properly parameterized (using 'var' for > local vars where resulting type is long) > - Convert MapFrobber and SetFrobber to interfaces, and convert all the > implementations to lambdas (automatic conversion via IntelliJ IDEA + > rename of conflicting parameter names) > - Use for-each loop instead of indexed for loop where possible > - 'elts' array was created in two places but unused afterward. I added > size assert to these arrays to use it at least somehow (though > probably content should be checked as well). > - Use Comparator.naturalOrder() instead of manually written one in > comparator() methods (should not affect the testing in any way as it's > only used directly, not passed e.g. to TreeMap constructor). > - Use Objects.equals inside LockStep#equal > - Inverted 'if' at line 299 to avoid empty block. > If the cleanup really complicates the review I can post the cleanup as > a separate changeset. Though it should not be very problematic as the > actual changes are quite compact (as said above, near lines 572 and > 806) > > I also improved the previously added benchmark TreeMapUpdate to check > descendingMap and tailMap cases to confirm the hypothesis that the > change improves the performance of derived maps. This is indeed the > case. E.g. merge test yields (comparator = false, size = 1000) for > unpatched JDK: > > (benchmark) (mode) (prefill) Score Error Units > TreeMapUpdate.merge TreeMap true 63589,075 ± 1028,065 ns/op > TreeMapUpdate.merge TreeMap false 65414,367 ± 1011,442 ns/op > TreeMapUpdate.merge descendingMap true 121501,618 ± 1849,108 ns/op > TreeMapUpdate.merge descendingMap false 95913,212 ± 2854,063 ns/op > TreeMapUpdate.merge tailMap true 126657,309 ± 4467,733 ns/op > TreeMapUpdate.merge tailMap false 93448,840 ± 1359,392 ns/op > > As you can see, the merge on derived maps is significantly slower. > After the patch is applied the results are much better: > > (benchmark) (mode) (prefill) Score Error Units > TreeMapUpdate.merge TreeMap true 64059,189 ± 808,230 ns/op > TreeMapUpdate.merge TreeMap false 65156,912 ± 1229,965 ns/op > TreeMapUpdate.merge descendingMap true 69938,131 ± 1697,357 ns/op > TreeMapUpdate.merge descendingMap false 67783,829 ± 263,061 ns/op > TreeMapUpdate.merge tailMap true 71079,529 ± 841,738 ns/op > TreeMapUpdate.merge tailMap false 68577,169 ± 1196,758 ns/op > > I don't think this requires a CSR, as the changed class is > package-private, so it cannot be extended by clients. > > With best regards, > Tagir Valeev.