ARTEMIS-6144 Improve getPagedResult - #6563
Conversation
|
Ready for review. |
| Map<Object, Object> fieldCache = new IdentityHashMap<>(array.length); | ||
| for (T item : array) { | ||
| if (item != null) { | ||
| fieldCache.put(item, getField(item, sortField)); |
There was a problem hiding this comment.
In the old code, getField() was called inside the comparator's try/catch, so an exception during field extraction was swallowed and treated as equal. However, the new code computes fields in a pre-loop with no exception handling.
This could be a problem for views like QueueView where getField() does server.locateQueue(...) and dereferences the result. Here if a queue is deleted mid-listing you get an NPE. Previously one bad element sorted as "equal" and the listing succeeded; now a single bad element throws out of getPagedResult, failing the entire management query.
There was a problem hiding this comment.
Thanks - added a try/catch in the loop.
| this.sortOrder = json.getString(SORT_ORDER); | ||
| } else if (json.containsKey(SORT_COLUMN)) { | ||
| this.sortField = json.getString(SORT_COLUMN); | ||
| this.sortOrder = json.getString(SORT_ORDER); |
There was a problem hiding this comment.
A payload with SORT_COLUMN but no SORT_ORDER now throws where the old code didn't.
There was a problem hiding this comment.
Fixed by adding a check if json contains SORT_ORDER.
| Arrays.sort(array, cachedComparator); | ||
|
|
||
| if (page == -1 || pageSize == -1) { | ||
| return Arrays.asList(array); |
There was a problem hiding this comment.
This now returns a mutable Arrays.asList(...) instead of Collections.unmodifiableList(...). This might not make any difference, but it's a contract change.
There was a problem hiding this comment.
Code now returns Collections.unmodifiableList(collectionList) or Collections.unmodifiableList(collectionList.subList(start, end)).
| if (sortOrderDescending) { | ||
| if (rightValue instanceof Comparable r) { | ||
| return r.compareTo(leftValue); | ||
| } | ||
| } else { | ||
| if (leftValue instanceof Comparable l) { | ||
| return l.compareTo(rightValue); | ||
| } |
There was a problem hiding this comment.
getField returns null for absent/optional fields, so a sort field with some null values is realistic.
Consider the scenario with ascending order, leftValue = abc, and rightValue = null:
- Old code:
rightValue instanceof Comparableisfalseso return0. Clean, no exception. - New code: only
leftValueis checked; it isComparable, so it calls"abc".compareTo(null)throwing aNullPointerExceptionwhich is caught so return 0.
The result (i.e., 0) is the same, but the new path throws and catches an exception on roughly every comparison that involves a null, inside the hottest loop of the sort. This is orders of magnitude more expensive than the avoided instanceof. So sorting any data containing a null will be slower, not faster.
There was a problem hiding this comment.
The new code now also checks for null values before executing the compareTo method:
if (leftValue == rightValue) {
return 0;
}
// push nulls to bottom of the list
if (leftValue == null) {
return 1;
}
if (rightValue == null) {
return -1;
}
Benchmarks below: