-
Bug
-
Resolution: Unresolved
-
P4
-
11, 16
-
generic
This is a bug spotted by my colleague Lee Raiford (lraiford@amazon.com)
* After a ForkJoinPool rejects an external submission with a reason of "Queue capacity exceeded", incoming task submissions start overwriting existing queued tasks, instead of being rejected.
Here's more details:
The exception is thrown from ForkJoinPool.WorkQueue::growArray either because the array length exceeds the capacity or OOM during allocation: https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java#L912
There are two behaviors we believe that are unreasonable:
* The RejectedExecutionException is thrown from growArray *after* the task is already pushed to array in lockedPush (ForkJoinPool.java#L864). Even the exception message "Queue capacity exceeded" is clear, but the exception name RejectedExecutionException is misleading: It makes developer feel the push was unsuccessful (and therefore may try to recommit it to the pool) and,
* When developer tries to recommit the task, the push is successful because the resizing condition (d == m, L866) is not met anymore (and the task overwrites previous task in the array).
Here are the fixes we suggest:
* (minimum) WorkQueue should reject further pushes after a resizing failure (Or, when previous sizing failed, try resizing again).
* (Optional) WorkQueue should use a different exception for resizing failure (something like QueueCapacityExceededException).
See the attached ExceedForkJoinPoolCapacity.java as a simple repro program.
* After a ForkJoinPool rejects an external submission with a reason of "Queue capacity exceeded", incoming task submissions start overwriting existing queued tasks, instead of being rejected.
Here's more details:
The exception is thrown from ForkJoinPool.WorkQueue::growArray either because the array length exceeds the capacity or OOM during allocation: https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java#L912
There are two behaviors we believe that are unreasonable:
* The RejectedExecutionException is thrown from growArray *after* the task is already pushed to array in lockedPush (ForkJoinPool.java#L864). Even the exception message "Queue capacity exceeded" is clear, but the exception name RejectedExecutionException is misleading: It makes developer feel the push was unsuccessful (and therefore may try to recommit it to the pool) and,
* When developer tries to recommit the task, the push is successful because the resizing condition (d == m, L866) is not met anymore (and the task overwrites previous task in the array).
Here are the fixes we suggest:
* (minimum) WorkQueue should reject further pushes after a resizing failure (Or, when previous sizing failed, try resizing again).
* (Optional) WorkQueue should use a different exception for resizing failure (something like QueueCapacityExceededException).
See the attached ExceedForkJoinPoolCapacity.java as a simple repro program.