-
Notifications
You must be signed in to change notification settings - Fork 3.4k
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
ARROW-16329: [Java][C++] Keep more context when marshalling errors through JNI #13246
Conversation
Thanks for opening a pull request! If this is not a minor PR. Could you open an issue for this pull request on JIRA? https://issues.apache.org/jira/browse/ARROW Opening JIRAs ahead of time contributes to the Openness of the Apache Arrow project. Then could you also rename pull request title in the following format?
or
See also: |
|
cpp/src/jni/dataset/jni_util.cc
Outdated
std::string description = JStringToCString( | ||
env, (jstring)env->CallStaticObjectMethod(describer_class, describe_method, t)); | ||
return Status::Invalid("Error during calling Java code from native code: " + | ||
description); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm... I don't know what is possible exactly, but ideally we should:
- map Java exception classes to specific C++ status codes (for example
IOException
would map toStatus::IOError
whileInvalidTypeException
would map toStatus::TypeError
) - keep the Java exception object in a Java-specific
StatusDetail
subclass, just like we do for Python exceptions
cc @lwhite1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also this helper function should be moved out of dataset-specific code to be reused generically in all JNI bindings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also this helper function should be moved out of dataset-specific code to be reused generically in all JNI bindings.
Was considering doing the similar thing but maybe after we have a common code module for JNI stuffs? Which may require some redesign for other parts of JNI codes, orc, gandiva, plasma, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If having a common module for JNI utilities is non-trivial, then can you open a JIRA for it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pitrou sure, I have opened a ticket
https://issues.apache.org/jira/browse/ARROW-16691
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@zhztheplayer Do you want to address the other parts of the initial comment in this PR?
I'm not going to have time. Since Larry is also working on reorganizing the JNI code anyways I'll leave it up to him whether/how to approach this |
1004d62
to
24bb7ab
Compare
/** | ||
* For native code to invoke to convert a java/lang/Throwable to jstring. | ||
*/ | ||
public class JniExceptionDescriber { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need to be a public class?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to use package private.
@@ -17,14 +17,14 @@ | |||
|
|||
#include <mutex> | |||
|
|||
#include "./jni_util.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#include "./jni_util.h" | |
#include "jni_util.h" |
since Kou just fixed this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
arrow::Result<bool> IsErrorInstanceOf(JNIEnv* env, jthrowable t, std::string class_name) { | ||
jclass jclass = env->FindClass(class_name.c_str()); | ||
if (jclass == nullptr) { | ||
return arrow::Status::Invalid("Class not found: " + class_name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given the way this is used below, maybe this should be a DCHECK(jclass) << ...;
or just return false
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is DCHECK
suitable for null-checking + returning? Anyway I have changed to return false
in latest commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, DCHECK will abort the program (in a debug build). Presumably it's a bug if we can't find any of these classes/we shouldn't continue execution? But returning false
is OK
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's a bug that we can't find them (i.e. they should always be loaded), I would favour returning an error, or at least emitting a warning message.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed to use DCHECK
to guard against debug build since class_name is hard coded. Would you please take a look? Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That seems ok to me, thanks.
// Reattach current thread to JVM | ||
getEnvStat = vm->AttachCurrentThread(reinterpret_cast<void**>(&env), nullptr); | ||
if (getEnvStat != JNI_OK) { | ||
std::cout << "Failed to attach current thread to JVM. " << std::endl; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ARROW_LOG instead of std::cout?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -17,6 +17,7 @@ | |||
|
|||
#include "./jni_util.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#include "./jni_util.h" | |
#include "jni_util.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -17,6 +17,7 @@ | |||
|
|||
#include "jni_util.h" | |||
|
|||
#include <iostream> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused include now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -162,11 +165,105 @@ std::shared_ptr<ReservationListener> ReservationListenableMemoryPool::get_listen | |||
|
|||
ReservationListenableMemoryPool::~ReservationListenableMemoryPool() {} | |||
|
|||
std::string Describe(JNIEnv* env, jthrowable t) { | |||
jclass describer_class = | |||
env->FindClass("org/apache/arrow/dataset/jni/JniExceptionDescriber"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're going to check the result of FindClass below, let's also check it here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
arrow::StatusCode MapJavaError(JNIEnv* env, jthrowable t) { | ||
StatusCode code; | ||
if (IsErrorInstanceOf(env, t, "org/apache/arrow/memory/OutOfMemoryException") == | ||
JNI_TRUE) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: the method returns bool
so no need for explicit == JNI_TRUE
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
std::string JavaErrorDetail::ToString() const { | ||
JNIEnv* env = GetEnvOrAttach(vm_); | ||
if (env == nullptr) { | ||
return "Java Exception, ID: " + std::to_string(reinterpret_cast<size_t>(cause_)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cause_ is a pointer, so use uintptr_t?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
java/dataset/src/main/cpp/jni_util.h
Outdated
@@ -91,6 +93,24 @@ void ReleaseNativeRef(jlong ref) { | |||
delete retrieved_ptr; | |||
} | |||
|
|||
const char kJavaErrorDetailTypeId[] = "arrow::dataset::jni::JavaErrorDetail"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be a static
member inside JavaErrorDetail
, or perhaps extern
and defined in the .cc
?
As is, it seems there will be symbol clashes if jni_util.h
is included by several .cc
files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have moved the variable into .cc
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll let a Java expert do the final approval but this looks basically ok to me (and a very marked improvement IMHO).
https://issues.apache.org/jira/browse/ARROW-16329