Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
jni-util.cc
Go to the documentation of this file.
1 // Copyright 2012 Cloudera Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "util/jni-util.h"
16 
17 #include <hdfs.h>
18 #include <sstream>
19 
20 #include "common/status.h"
21 #include "rpc/jni-thrift-util.h"
22 
23 #include "common/names.h"
24 
25 namespace impala {
26 
27 jclass JniUtil::jni_util_cl_ = NULL;
28 jclass JniUtil::internal_exc_cl_ = NULL;
29 jmethodID JniUtil::get_jvm_metrics_id_ = NULL;
30 jmethodID JniUtil::throwable_to_string_id_ = NULL;
32 vector<jobject> JniUtil::global_refs_;
33 
34 Status JniLocalFrame::push(JNIEnv* env, int max_local_ref) {
35  DCHECK(env_ == NULL);
36  DCHECK_GT(max_local_ref, 0);
37  if (env->PushLocalFrame(max_local_ref) < 0) {
38  env->ExceptionClear();
39  return Status("failed to push frame");
40  }
41  env_ = env;
42  return Status::OK;
43 }
44 
45 bool JniUtil::ClassExists(JNIEnv* env, const char* class_str) {
46  jclass local_cl = env->FindClass(class_str);
47  jthrowable exc = env->ExceptionOccurred();
48  if (exc != NULL) {
49  env->ExceptionClear();
50  return false;
51  }
52  env->DeleteLocalRef(local_cl);
53  return true;
54 }
55 
56 Status JniUtil::GetGlobalClassRef(JNIEnv* env, const char* class_str, jclass* class_ref) {
57  *class_ref = NULL;
58  jclass local_cl = env->FindClass(class_str);
60  RETURN_IF_ERROR(LocalToGlobalRef(env, reinterpret_cast<jobject>(local_cl),
61  reinterpret_cast<jobject*>(class_ref)));
62  env->DeleteLocalRef(local_cl);
64  return Status::OK;
65 }
66 
67 Status JniUtil::LocalToGlobalRef(JNIEnv* env, jobject local_ref, jobject* global_ref) {
68  *global_ref = env->NewGlobalRef(local_ref);
70  global_refs_.push_back(*global_ref);
71  return Status::OK;
72 }
73 
75  // Get the JNIEnv* corresponding to current thread.
76  JNIEnv* env = getJNIEnv();
77  if (env == NULL) return Status("Failed to get/create JVM");
78  // Find JniUtil class and create a global ref.
79  jclass local_jni_util_cl = env->FindClass("com/cloudera/impala/common/JniUtil");
80  if (local_jni_util_cl == NULL) {
81  if (env->ExceptionOccurred()) env->ExceptionDescribe();
82  return Status("Failed to find JniUtil class.");
83  }
84  jni_util_cl_ = reinterpret_cast<jclass>(env->NewGlobalRef(local_jni_util_cl));
85  if (jni_util_cl_ == NULL) {
86  if (env->ExceptionOccurred()) env->ExceptionDescribe();
87  return Status("Failed to create global reference to JniUtil class.");
88  }
89  env->DeleteLocalRef(local_jni_util_cl);
90  if (env->ExceptionOccurred()) {
91  return Status("Failed to delete local reference to JniUtil class.");
92  }
93 
94  // Find InternalException class and create a global ref.
95  jclass local_internal_exc_cl =
96  env->FindClass("com/cloudera/impala/common/InternalException");
97  if (local_internal_exc_cl == NULL) {
98  if (env->ExceptionOccurred()) env->ExceptionDescribe();
99  return Status("Failed to find JniUtil class.");
100  }
101  internal_exc_cl_ = reinterpret_cast<jclass>(env->NewGlobalRef(local_internal_exc_cl));
102  if (internal_exc_cl_ == NULL) {
103  if (env->ExceptionOccurred()) env->ExceptionDescribe();
104  return Status("Failed to create global reference to JniUtil class.");
105  }
106  env->DeleteLocalRef(local_internal_exc_cl);
107  if (env->ExceptionOccurred()) {
108  return Status("Failed to delete local reference to JniUtil class.");
109  }
110 
111  // Throwable toString()
113  env->GetStaticMethodID(jni_util_cl_, "throwableToString",
114  "(Ljava/lang/Throwable;)Ljava/lang/String;");
115  if (throwable_to_string_id_ == NULL) {
116  if (env->ExceptionOccurred()) env->ExceptionDescribe();
117  return Status("Failed to find JniUtil.throwableToString method.");
118  }
119 
120  // throwableToStackTrace()
122  env->GetStaticMethodID(jni_util_cl_, "throwableToStackTrace",
123  "(Ljava/lang/Throwable;)Ljava/lang/String;");
124  if (throwable_to_stack_trace_id_ == NULL) {
125  if (env->ExceptionOccurred()) env->ExceptionDescribe();
126  return Status("Failed to find JniUtil.throwableToFullStackTrace method.");
127  }
128 
130  env->GetStaticMethodID(jni_util_cl_, "getJvmMetrics", "([B)[B");
131  if (get_jvm_metrics_id_ == NULL) {
132  if (env->ExceptionOccurred()) env->ExceptionDescribe();
133  return Status("Failed to find JniUtil.getJvmMetrics method.");
134  }
135 
136 
137  return Status::OK;
138 }
139 
141  // make random libhdfs calls to make sure that the context class loader isn't
142  // null; see xxx for an explanation
143  hdfsFS fs = hdfsConnect("default", 0);
144  hdfsDisconnect(fs);
145 }
146 
148  // Get the JNIEnv* corresponding to current thread.
149  JNIEnv* env = getJNIEnv();
150  if (env == NULL) {
151  return Status("Failed to get/create JVM");
152  }
153  vector<jobject>::iterator it;
154  for (it = global_refs_.begin(); it != global_refs_.end(); ++it) {
155  env->DeleteGlobalRef(*it);
156  }
157  global_refs_.clear();
158  return Status::OK;
159 }
160 
161 Status JniUtil::GetJniExceptionMsg(JNIEnv* env, bool log_stack, const string& prefix) {
162  jthrowable exc = (env)->ExceptionOccurred();
163  if (exc == NULL) return Status::OK;
164  env->ExceptionClear();
165  DCHECK(throwable_to_string_id() != NULL);
166  jstring msg = (jstring) env->CallStaticObjectMethod(jni_util_class(),
167  throwable_to_string_id(), exc);
168  jboolean is_copy;
169  string error_msg =
170  (reinterpret_cast<const char*>(env->GetStringUTFChars(msg, &is_copy)));
171 
172  if (log_stack) {
173  jstring stack = (jstring) env->CallStaticObjectMethod(jni_util_class(),
175  const char* c_stack =
176  reinterpret_cast<const char*>(env->GetStringUTFChars(stack, &is_copy));
177  VLOG(1) << string(c_stack);
178  }
179 
180  env->ExceptionClear();
181  env->DeleteLocalRef(exc);
182 
183  stringstream ss;
184  ss << prefix << error_msg;
185  return Status(ss.str());
186 }
187 
188 Status JniUtil::GetJvmMetrics(const TGetJvmMetricsRequest& request,
189  TGetJvmMetricsResponse* result) {
190  return JniUtil::CallJniMethod(jni_util_class(), get_jvm_metrics_id_, request, result);
191 }
192 
193 Status JniUtil::LoadJniMethod(JNIEnv* env, const jclass& jni_class,
194  JniMethodDescriptor* descriptor) {
195  (*descriptor->method_id) = env->GetMethodID(jni_class,
196  descriptor->name.c_str(), descriptor->signature.c_str());
197  RETURN_ERROR_IF_EXC(env);
198  return Status::OK;
199 }
200 
201 }
static jclass jni_util_cl_
Definition: jni-util.h:290
static std::vector< jobject > global_refs_
Definition: jni-util.h:297
const std::string signature
JNI-style method signature.
Definition: jni-util.h:154
#define RETURN_IF_ERROR(stmt)
some generally useful macros
Definition: status.h:242
static Status LoadJniMethod(JNIEnv *jni_env, const jclass &jni_class, JniMethodDescriptor *descriptor)
Definition: jni-util.cc:193
static jmethodID throwable_to_stack_trace_id()
Definition: jni-util.h:200
static Status Init()
Find JniUtil class, and get JniUtil.throwableToString method id.
Definition: jni-util.cc:74
static Status Cleanup()
Delete all global references: class members, and those stored in global_refs_.
Definition: jni-util.cc:147
static jmethodID throwable_to_stack_trace_id_
Definition: jni-util.h:293
static Status LocalToGlobalRef(JNIEnv *env, jobject local_ref, jobject *global_ref)
Definition: jni-util.cc:67
static void InitLibhdfs()
Call this prior to any libhdfs calls.
Definition: jni-util.cc:140
static jmethodID get_jvm_metrics_id_
Definition: jni-util.h:294
static Status GetJniExceptionMsg(JNIEnv *env, bool log_stack=true, const std::string &prefix="")
Definition: jni-util.cc:161
Status push(JNIEnv *env, int max_local_ref=10)
Definition: jni-util.cc:34
Describes one method to look up in a Java object.
Definition: jni-util.h:149
const std::string name
Name of the method, case must match.
Definition: jni-util.h:151
#define RETURN_ERROR_IF_EXC(env)
Definition: jni-util.h:99
static jclass jni_util_class()
Global reference to java JniUtil class.
Definition: jni-util.h:203
static bool ClassExists(JNIEnv *env, const char *class_str)
Definition: jni-util.cc:45
static const Status OK
Definition: status.h:87
jmethodID * method_id
Handle to the method.
Definition: jni-util.h:157
static Status GetGlobalClassRef(JNIEnv *env, const char *class_str, jclass *class_ref)
Definition: jni-util.cc:56
static jclass internal_exc_cl_
Definition: jni-util.h:291
static jmethodID throwable_to_string_id()
Definition: jni-util.h:199
static Status GetJvmMetrics(const TGetJvmMetricsRequest &request, TGetJvmMetricsResponse *result)
Definition: jni-util.cc:188
static Status CallJniMethod(const jobject &obj, const jmethodID &method, const T &arg)
Definition: jni-util.h:231
static jmethodID throwable_to_string_id_
Definition: jni-util.h:292
JNIEnv * getJNIEnv(void)
C linkage for helper functions in hdfsJniHelper.h.