8195614: FilteredList throws ArrayIndexOutOfBoundsException if created with 1 element#2163
Conversation
|
👋 Welcome back mhanl! A progress list of the required criteria for merging this PR into |
|
❗ This change is not yet ready to be integrated. |
|
@Maran23 |
|
The total number of required reviews for this PR has been set to 2 based on the presence of this label: |
andy-goryachev-oracle
left a comment
There was a problem hiding this comment.
minor optimization might be possible.
|
|
||
| @Override | ||
| protected void sourceChanged(Change<? extends E> c) { | ||
| ensureSize(getSource().size()); |
There was a problem hiding this comment.
are you sure this is needed?
the tests in the two JBS tickets pass without it, addRemove() invokes this method in ~L239 (then calls it again with size+1 in L273). update() calls it in ~L286, and permutate() does not need it.
perhaps addRemove() can be further optimized so as not to call ensureSize() twice?
There was a problem hiding this comment.
update() and permutate() do not call it anymore. I relocated them into one single location: Here.
So functionality wise, it did not change.
We could probably remove it, as we will catch any grow on size in addRemove(). But it might hurt performance.
If we have a FilteredList with a size 1 and add 10_000 elements, we will call ensureSize a lot of times, which will lead to a degraded performance.
But since we call it once here, we will immediately grow to the worst case size - if nothing need to be filtered and MAY only grow it in addRemove() when we temporarily have more elements due to processing the changes one by one.
There was a problem hiding this comment.
I might be misunderstanding something.
- Is
ensureSize()L138 needed forpermutate()? addRemove()callsensureSize()twice (L138 and L237). can it call it only once?update()does not change the filtered size, right? why is it callingensureSize()in L138?
There was a problem hiding this comment.
- No - but when we are only sorting (permutation) the list, the
ensureSizeshould be a noop, since the size had to be increased at some point in the past to what we currently have and ensured the size - No - because a sub change temporarily adds an element which is later removed on another sub change. We unfortunately can not predict that/count that in beforehand in this
ensureSizecall. With that said, the second call inaddRemoveshould happen very rarely - probably only with small sizes - It can. When we change an item, lets say A -> B and A is filtered out but B is not, we grow in size by 1 (or the other way around). But same as in the
permutation,- theensureSizeshould be a noop, since the size had to be increased at some point in the past to what we currently have and ensured the size
There was a problem hiding this comment.
So, while I agree that it's likely to be a no-op, my original comment did pointed out a possible optimization (not that it will give us megabytes or free space or 10% less CPU consumption).
So in cases 1) and 2) we could call ensureSize() only when needed. It's up to you whether you want to pursue this further or leave as is.
There was a problem hiding this comment.
Yeah I thought about it as well - but this is very hard to balance.
We reserve quite much space here. If we have 1000 elements, we reserve space for 1501 elements. That's huge. And we are in FilteredList - so the normal usecase is probably with quite a few elements filtered out.
But on the other hand growing in size just a few times is much better performance-wise vs. growing in size many more times. As I found out here already: #758
…angeEvent with multiple change NB: this fix is an alternative to openjdk#2163 It has been heavily tested in our application during 6 months with success. it fixes also JDK-8195614
This PR fixes the (rare) issue that an
ArrayIndexOutOfBoundsExceptionis thrown inFilteredList.Some details of the problem:
int[] filtered) to compensate a temporary element increase. With a small size like 1, we can reproduce it easily by making two change events (In the reproducer and test, a 'move element to first index' change operation)Details for the fix:
ensureSize(getSource().size());is normally correct as ourFilteredListwill always be <= source list.But we can have the situation where we have temporarily more elements than the source list as we are processing all change events (e.g. add 1, remove 1).
ensureSizeagain when we could run into the situation where we have more elements than we reserved forfilteredarray, I did not use the proposed change in the ticket but this one instead. We will really only (may) increase the size when we really need itfilteredthan we may need, this does not happen often, especially not with more elementsensureSize(size + 1);is very likely a noop, but in cases like this e will correctly reserve more capacity/issue add JDK-8195750
Progress
Issues
Reviewers
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/jfx.git pull/2163/head:pull/2163$ git checkout pull/2163Update a local copy of the PR:
$ git checkout pull/2163$ git pull https://git.openjdk.org/jfx.git pull/2163/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 2163View PR using the GUI difftool:
$ git pr show -t 2163Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jfx/pull/2163.diff
Using Webrev
Link to Webrev Comment