Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix broken implementation of ParTaskImpl::tasksFromIterable #347

Merged
merged 1 commit into from
Mar 12, 2024

Conversation

zackthehuman
Copy link
Contributor

@zackthehuman zackthehuman commented Mar 7, 2024

The tasksFromIterable method in ParTaskImpl needs to read the contents of an iterator and then create an array of the read tasks. This is an unfortunate performance/memory tradeoff of using these two things: iterators don't have a length and arrays need one. The implementation reads the iterator's contents into a collection and then turns that collection into an array. The problem is, it then tries to cast that array of Object into a more narrow type, which is not allowed. This always results in a ClassCastException if the value is non null. The exists tests did not cover this case.

The code has been fixed to take a less performant path and delegate the array creation to tasksFromCollection. A test has been written for the Iterable code path and verified through coverage analysis.

This should fix #209 .

Before this change, if you use a class that implements Iterable but does not also implement Collection with Task.par then you'll be met with an exception:

java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Lcom.linkedin.parseq.Task;
	at com.linkedin.parseq.ParTaskImpl.tasksFromIterable(ParTaskImpl.java:77)
	at com.linkedin.parseq.ParTaskImpl.<init>(ParTaskImpl.java:61)
	at com.linkedin.parseq.Tasks.par(Tasks.java:361)
	at com.linkedin.parseq.TestParTask.testIterableSeqWithMultipleElements(TestParTask.java:105)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:85)
	at org.testng.internal.Invoker.invokeMethod(Invoker.java:639)
	at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:816)
	at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1124)
	at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:125)
	at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:108)
	at org.testng.TestRunner.privateRun(TestRunner.java:774)
	at org.testng.TestRunner.run(TestRunner.java:624)
	at org.testng.SuiteRunner.runTest(SuiteRunner.java:359)
	at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:354)
	at org.testng.SuiteRunner.privateRun(SuiteRunner.java:312)
	at org.testng.SuiteRunner.run(SuiteRunner.java:261)

This is because the Iterable code path does some illegal casting of Object[] to Task[], which is not allowed.

The `tasksFromIterable` method in `ParTaskImpl` needs to read the contents of
an iterator and then create an array of the read tasks. This is an unfortunate
performance/memory tradeoff of using these two things: iterators don't have a
length and arrays need one. The implementation reads the iterator's contents
into a collection and then turns that collection into an array. The problem is,
it then tries to cast that array of `Object` into a more narrow type, which is
not allowed. This _always_ results in a ClassCastException if the value is non
null. The exists tests did not cover this case.

The code has been fixed to take a less performant path and delegate the array
creation to `tasksFromCollection`. A test has been written for the `Iterable`
code path and verified through coverage analysis.
@zackthehuman zackthehuman force-pushed the zmulgrew/fix-iterable-casting branch from 895b268 to 1c5ee57 Compare March 8, 2024 00:01
@zackthehuman zackthehuman merged commit f6ab57d into master Mar 12, 2024
1 check passed
@zackthehuman zackthehuman deleted the zmulgrew/fix-iterable-casting branch March 12, 2024 20:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Task.par() doesn't work with Vavr List, throw ClassCastException
3 participants