Modified: hadoop/common/trunk/hadoop-hdfs-project/hadoop-hdfs/src/main/native/libhdfs/hdfs.h URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-hdfs-project/hadoop-hdfs/src/main/native/libhdfs/hdfs.h?rev=1370015&r1=1370014&r2=1370015&view=diff ============================================================================== --- hadoop/common/trunk/hadoop-hdfs-project/hadoop-hdfs/src/main/native/libhdfs/hdfs.h (original) +++ hadoop/common/trunk/hadoop-hdfs-project/hadoop-hdfs/src/main/native/libhdfs/hdfs.h Mon Aug 6 21:02:30 2012 @@ -252,7 +252,9 @@ extern "C" { * hdfsDisconnect - Disconnect from the hdfs file system. * Disconnect from hdfs. * @param fs The configured filesystem handle. - * @return Returns 0 on success, -1 on error. + * @return Returns 0 on success, -1 on error. + * Even if there is an error, the resources associated with the + * hdfsFS will be freed. */ int hdfsDisconnect(hdfsFS fs); @@ -280,6 +282,10 @@ extern "C" { * @param fs The configured filesystem handle. * @param file The file handle. * @return Returns 0 on success, -1 on error. + * On error, errno will be set appropriately. + * If the hdfs file was valid, the memory associated with it will + * be freed at the end of this call, even if there was an I/O + * error. */ int hdfsCloseFile(hdfsFS fs, hdfsFile file); @@ -336,8 +342,7 @@ extern "C" { * @param position Position from which to read * @param buffer The buffer to copy read bytes into. * @param length The length of the buffer. - * @return Returns the number of bytes actually read, possibly less than - * than length;-1 on error. + * @return See hdfsRead */ tSize hdfsPread(hdfsFS fs, hdfsFile file, tOffset position, void* buffer, tSize length);
Modified: hadoop/common/trunk/hadoop-hdfs-project/hadoop-hdfs/src/main/native/libhdfs/jni_helper.c URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-hdfs-project/hadoop-hdfs/src/main/native/libhdfs/jni_helper.c?rev=1370015&r1=1370014&r2=1370015&view=diff ============================================================================== --- hadoop/common/trunk/hadoop-hdfs-project/hadoop-hdfs/src/main/native/libhdfs/jni_helper.c (original) +++ hadoop/common/trunk/hadoop-hdfs-project/hadoop-hdfs/src/main/native/libhdfs/jni_helper.c Mon Aug 6 21:02:30 2012 @@ -17,6 +17,7 @@ */ #include "config.h" +#include "exception.h" #include "jni_helper.h" #include <stdio.h> @@ -85,16 +86,57 @@ static void hdfsThreadDestructor(void *v free(tls); } +void destroyLocalReference(JNIEnv *env, jobject jObject) +{ + if (jObject) + (*env)->DeleteLocalRef(env, jObject); +} -static int validateMethodType(MethType methType) +static jthrowable validateMethodType(JNIEnv *env, MethType methType) { if (methType != STATIC && methType != INSTANCE) { - fprintf(stderr, "Unimplemented method type\n"); - return 0; + return newRuntimeError(env, "validateMethodType(methType=%d): " + "illegal method type.\n", methType); } - return 1; + return NULL; } +jthrowable newJavaStr(JNIEnv *env, const char *str, jstring *out) +{ + jstring jstr; + + if (!str) { + /* Can't pass NULL to NewStringUTF: the result would be + * implementation-defined. */ + *out = NULL; + return NULL; + } + jstr = (*env)->NewStringUTF(env, str); + if (!jstr) { + /* If NewStringUTF returns NULL, an exception has been thrown, + * which we need to handle. Probaly an OOM. */ + return getPendingExceptionAndClear(env); + } + *out = jstr; + return NULL; +} + +jthrowable newCStr(JNIEnv *env, jstring jstr, char **out) +{ + const char *tmp; + + if (!jstr) { + *out = NULL; + return NULL; + } + tmp = (*env)->GetStringUTFChars(env, jstr, NULL); + if (!tmp) { + return getPendingExceptionAndClear(env); + } + *out = strdup(tmp); + (*env)->ReleaseStringUTFChars(env, jstr, tmp); + return NULL; +} static int hashTableInit(void) { @@ -156,7 +198,7 @@ static void* searchEntryFromTable(const -int invokeMethod(JNIEnv *env, RetVal *retval, Exc *exc, MethType methType, +jthrowable invokeMethod(JNIEnv *env, jvalue *retval, MethType methType, jobject instObj, const char *className, const char *methName, const char *methSignature, ...) { @@ -167,21 +209,16 @@ int invokeMethod(JNIEnv *env, RetVal *re const char *str; char returnType; - if (! validateMethodType(methType)) { - return -1; - } - cls = globalClassReference(className, env); - if (cls == NULL) { - return -2; - } - - mid = methodIdFromClass(className, methName, methSignature, - methType, env); - if (mid == NULL) { - (*env)->ExceptionDescribe(env); - return -3; - } - + jthr = validateMethodType(env, methType); + if (jthr) + return jthr; + jthr = globalClassReference(className, env, &cls); + if (jthr) + return jthr; + jthr = methodIdFromClass(className, methName, methSignature, + methType, env, &mid); + if (jthr) + return jthr; str = methSignature; while (*str != ')') str++; str++; @@ -248,43 +285,14 @@ int invokeMethod(JNIEnv *env, RetVal *re va_end(args); jthr = (*env)->ExceptionOccurred(env); - if (jthr != NULL) { - if (exc != NULL) - *exc = jthr; - else - (*env)->ExceptionDescribe(env); - return -1; + if (jthr) { + (*env)->ExceptionClear(env); + return jthr; } - return 0; -} - -jarray constructNewArrayString(JNIEnv *env, Exc *exc, const char **elements, int size) { - const char *className = "java/lang/String"; - jobjectArray result; - int i; - jclass arrCls = (*env)->FindClass(env, className); - if (arrCls == NULL) { - fprintf(stderr, "could not find class %s\n",className); - return NULL; /* exception thrown */ - } - result = (*env)->NewObjectArray(env, size, arrCls, - NULL); - if (result == NULL) { - fprintf(stderr, "ERROR: could not construct new array\n"); - return NULL; /* out of memory error thrown */ - } - for (i = 0; i < size; i++) { - jstring jelem = (*env)->NewStringUTF(env,elements[i]); - if (jelem == NULL) { - fprintf(stderr, "ERROR: jelem == NULL\n"); - } - (*env)->SetObjectArrayElement(env, result, i, jelem); - (*env)->DeleteLocalRef(env, jelem); - } - return result; + return NULL; } -jobject constructNewObjectOfClass(JNIEnv *env, Exc *exc, const char *className, +jthrowable constructNewObjectOfClass(JNIEnv *env, jobject *out, const char *className, const char *ctorSignature, ...) { va_list args; @@ -293,50 +301,37 @@ jobject constructNewObjectOfClass(JNIEnv jobject jobj; jthrowable jthr; - cls = globalClassReference(className, env); - if (cls == NULL) { - (*env)->ExceptionDescribe(env); - return NULL; - } - - mid = methodIdFromClass(className, "<init>", ctorSignature, - INSTANCE, env); - if (mid == NULL) { - (*env)->ExceptionDescribe(env); - return NULL; - } + jthr = globalClassReference(className, env, &cls); + if (jthr) + return jthr; + jthr = methodIdFromClass(className, "<init>", ctorSignature, + INSTANCE, env, &mid); + if (jthr) + return jthr; va_start(args, ctorSignature); jobj = (*env)->NewObjectV(env, cls, mid, args); va_end(args); - jthr = (*env)->ExceptionOccurred(env); - if (jthr != NULL) { - if (exc != NULL) - *exc = jthr; - else - (*env)->ExceptionDescribe(env); - } - return jobj; + if (!jobj) + return getPendingExceptionAndClear(env); + *out = jobj; + return NULL; } - - -jmethodID methodIdFromClass(const char *className, const char *methName, +jthrowable methodIdFromClass(const char *className, const char *methName, const char *methSignature, MethType methType, - JNIEnv *env) + JNIEnv *env, jmethodID *out) { - jclass cls = globalClassReference(className, env); - if (cls == NULL) { - fprintf(stderr, "could not find class %s\n", className); - return NULL; - } + jclass cls; + jthrowable jthr; + jthr = globalClassReference(className, env, &cls); + if (jthr) + return jthr; jmethodID mid = 0; - if (!validateMethodType(methType)) { - fprintf(stderr, "invalid method type\n"); - return NULL; - } - + jthr = validateMethodType(env, methType); + if (jthr) + return jthr; if (methType == STATIC) { mid = (*env)->GetStaticMethodID(env, cls, methName, methSignature); } @@ -344,72 +339,88 @@ jmethodID methodIdFromClass(const char * mid = (*env)->GetMethodID(env, cls, methName, methSignature); } if (mid == NULL) { - fprintf(stderr, "could not find method %s from class %s with signature %s\n",methName, className, methSignature); + fprintf(stderr, "could not find method %s from class %s with " + "signature %s\n", methName, className, methSignature); + return getPendingExceptionAndClear(env); } - return mid; + *out = mid; + return NULL; } - -jclass globalClassReference(const char *className, JNIEnv *env) +jthrowable globalClassReference(const char *className, JNIEnv *env, jclass *out) { jclass clsLocalRef; jclass cls = searchEntryFromTable(className); if (cls) { - return cls; + *out = cls; + return NULL; } - clsLocalRef = (*env)->FindClass(env,className); if (clsLocalRef == NULL) { - (*env)->ExceptionDescribe(env); - return NULL; + return getPendingExceptionAndClear(env); } cls = (*env)->NewGlobalRef(env, clsLocalRef); if (cls == NULL) { - (*env)->ExceptionDescribe(env); - return NULL; + (*env)->DeleteLocalRef(env, clsLocalRef); + return getPendingExceptionAndClear(env); } (*env)->DeleteLocalRef(env, clsLocalRef); insertEntryIntoTable(className, cls); - return cls; + *out = cls; + return NULL; } - -char *classNameOfObject(jobject jobj, JNIEnv *env) { - jclass cls, clsClass; +jthrowable classNameOfObject(jobject jobj, JNIEnv *env, char **name) +{ + jthrowable jthr; + jclass cls, clsClass = NULL; jmethodID mid; - jstring str; - const char *cstr; + jstring str = NULL; + const char *cstr = NULL; char *newstr; cls = (*env)->GetObjectClass(env, jobj); if (cls == NULL) { - (*env)->ExceptionDescribe(env); - return NULL; + jthr = getPendingExceptionAndClear(env); + goto done; } clsClass = (*env)->FindClass(env, "java/lang/Class"); if (clsClass == NULL) { - (*env)->ExceptionDescribe(env); - return NULL; + jthr = getPendingExceptionAndClear(env); + goto done; } mid = (*env)->GetMethodID(env, clsClass, "getName", "()Ljava/lang/String;"); if (mid == NULL) { - (*env)->ExceptionDescribe(env); - return NULL; + jthr = getPendingExceptionAndClear(env); + goto done; } str = (*env)->CallObjectMethod(env, cls, mid); if (str == NULL) { - (*env)->ExceptionDescribe(env); - return NULL; + jthr = getPendingExceptionAndClear(env); + goto done; } - cstr = (*env)->GetStringUTFChars(env, str, NULL); + if (!cstr) { + jthr = getPendingExceptionAndClear(env); + goto done; + } newstr = strdup(cstr); - (*env)->ReleaseStringUTFChars(env, str, cstr); if (newstr == NULL) { - perror("classNameOfObject: strdup"); - return NULL; + jthr = newRuntimeError(env, "classNameOfObject: out of memory"); + goto done; + } + *name = newstr; + jthr = NULL; + +done: + destroyLocalReference(env, cls); + destroyLocalReference(env, clsClass); + if (str) { + if (cstr) + (*env)->ReleaseStringUTFChars(env, str, cstr); + (*env)->DeleteLocalRef(env, str); } - return newstr; + return jthr; } @@ -429,6 +440,7 @@ static JNIEnv* getGlobalJNIEnv(void) JNIEnv *env; jint rv = 0; jint noVMs = 0; + jthrowable jthr; rv = JNI_GetCreatedJavaVMs(&(vmBuf[0]), vmBufLength, &noVMs); if (rv != 0) { @@ -501,10 +513,11 @@ static JNIEnv* getGlobalJNIEnv(void) "with error: %d\n", rv); return NULL; } - if (invokeMethod(env, NULL, NULL, STATIC, NULL, + jthr = invokeMethod(env, NULL, STATIC, NULL, "org/apache/hadoop/fs/FileSystem", - "loadFileSystems", "()V") != 0) { - (*env)->ExceptionDescribe(env); + "loadFileSystems", "()V"); + if (jthr) { + printExceptionAndFree(env, jthr, PRINT_EXC_ALL, "loadFileSystems"); } } else { Modified: hadoop/common/trunk/hadoop-hdfs-project/hadoop-hdfs/src/main/native/libhdfs/jni_helper.h URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-hdfs-project/hadoop-hdfs/src/main/native/libhdfs/jni_helper.h?rev=1370015&r1=1370014&r2=1370015&view=diff ============================================================================== --- hadoop/common/trunk/hadoop-hdfs-project/hadoop-hdfs/src/main/native/libhdfs/jni_helper.h (original) +++ hadoop/common/trunk/hadoop-hdfs-project/hadoop-hdfs/src/main/native/libhdfs/jni_helper.h Mon Aug 6 21:02:30 2012 @@ -37,14 +37,35 @@ typedef enum { INSTANCE } MethType; +/** + * Create a new malloc'ed C string from a Java string. + * + * @param env The JNI environment + * @param jstr The Java string + * @param out (out param) the malloc'ed C string + * + * @return NULL on success; the exception otherwise + */ +jthrowable newCStr(JNIEnv *env, jstring jstr, char **out); -/** Used for returning an appropriate return value after invoking - * a method +/** + * Create a new Java string from a C string. + * + * @param env The JNI environment + * @param str The C string + * @param out (out param) the java string + * + * @return NULL on success; the exception otherwise */ -typedef jvalue RetVal; +jthrowable newJavaStr(JNIEnv *env, const char *str, jstring *out); -/** Used for returning the exception after invoking a method */ -typedef jthrowable Exc; +/** + * Helper function to destroy a local reference of java.lang.Object + * @param env: The JNIEnv pointer. + * @param jFile: The local reference of java.lang.Object object + * @return None. + */ +void destroyLocalReference(JNIEnv *env, jobject jObject); /** invokeMethod: Invoke a Static or Instance method. * className: Name of the class where the method can be found @@ -63,33 +84,27 @@ typedef jthrowable Exc; * RETURNS: -1 on error and 0 on success. If -1 is returned, exc will have a valid exception reference, and the result stored at retval is undefined. */ -int invokeMethod(JNIEnv *env, RetVal *retval, Exc *exc, MethType methType, +jthrowable invokeMethod(JNIEnv *env, jvalue *retval, MethType methType, jobject instObj, const char *className, const char *methName, const char *methSignature, ...); -/** constructNewObjectOfClass: Invoke a constructor. - * className: Name of the class - * ctorSignature: the signature of the constructor "(arg-types)V" - * env: The JNIEnv pointer - * exc: If the ctor throws any exception, this will contain the reference - * Arguments to the ctor must be passed after ctorSignature - */ -jobject constructNewObjectOfClass(JNIEnv *env, Exc *exc, const char *className, +jthrowable constructNewObjectOfClass(JNIEnv *env, jobject *out, const char *className, const char *ctorSignature, ...); -jmethodID methodIdFromClass(const char *className, const char *methName, +jthrowable methodIdFromClass(const char *className, const char *methName, const char *methSignature, MethType methType, - JNIEnv *env); + JNIEnv *env, jmethodID *out); -jclass globalClassReference(const char *className, JNIEnv *env); +jthrowable globalClassReference(const char *className, JNIEnv *env, jclass *out); /** classNameOfObject: Get an object's class name. * @param jobj: The object. * @param env: The JNIEnv pointer. - * @return Returns a pointer to a string containing the class name. This string - * must be freed by the caller. + * @param name: (out param) On success, will contain a string containing the + * class name. This string must be freed by the caller. + * @return NULL on success, or the exception */ -char *classNameOfObject(jobject jobj, JNIEnv *env); +jthrowable classNameOfObject(jobject jobj, JNIEnv *env, char **name); /** getJNIEnv: A helper function to get the JNIEnv* for the given thread. * If no JVM exists, then one will be created. JVM command line arguments @@ -99,8 +114,6 @@ char *classNameOfObject(jobject jobj, JN * */ JNIEnv* getJNIEnv(void); -jarray constructNewArrayString(JNIEnv *env, Exc *exc, const char **elements, int size) ; - #endif /*LIBHDFS_JNI_HELPER_H*/ /** Modified: hadoop/common/trunk/hadoop-hdfs-project/hadoop-hdfs/src/main/native/libhdfs/native_mini_dfs.c URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-hdfs-project/hadoop-hdfs/src/main/native/libhdfs/native_mini_dfs.c?rev=1370015&r1=1370014&r2=1370015&view=diff ============================================================================== --- hadoop/common/trunk/hadoop-hdfs-project/hadoop-hdfs/src/main/native/libhdfs/native_mini_dfs.c (original) +++ hadoop/common/trunk/hadoop-hdfs-project/hadoop-hdfs/src/main/native/libhdfs/native_mini_dfs.c Mon Aug 6 21:02:30 2012 @@ -16,6 +16,7 @@ * limitations under the License. */ +#include "exception.h" #include "jni_helper.h" #include "native_mini_dfs.h" @@ -41,6 +42,8 @@ struct NativeMiniDfsCluster* nmdCreate(s jobject bld = NULL, bld2 = NULL, cobj = NULL; jvalue val; JNIEnv *env = getJNIEnv(); + jthrowable jthr; + if (!env) { fprintf(stderr, "nmdCreate: unable to construct JNIEnv.\n"); goto error; @@ -50,35 +53,38 @@ struct NativeMiniDfsCluster* nmdCreate(s fprintf(stderr, "nmdCreate: OOM"); goto error; } - cobj = constructNewObjectOfClass(env, NULL, HADOOP_CONF, "()V"); - if (!cobj) { - fprintf(stderr, "nmdCreate: unable to construct Configuration\n"); + jthr = constructNewObjectOfClass(env, &cobj, HADOOP_CONF, "()V"); + if (jthr) { + printExceptionAndFree(env, jthr, PRINT_EXC_ALL, + "nmdCreate: new Configuration"); goto error_free_cl; } - bld = constructNewObjectOfClass(env, NULL, MINIDFS_CLUSTER_BUILDER, + jthr = constructNewObjectOfClass(env, &bld, MINIDFS_CLUSTER_BUILDER, "(L"HADOOP_CONF";)V", cobj); - if (!bld) { - fprintf(stderr, "nmdCreate: unable to construct " - "NativeMiniDfsCluster#Builder\n"); + if (jthr) { + printExceptionAndFree(env, jthr, PRINT_EXC_ALL, + "nmdCreate: NativeMiniDfsCluster#Builder#Builder"); goto error_dlr_cobj; } - if (invokeMethod(env, &val, NULL, INSTANCE, bld, - MINIDFS_CLUSTER_BUILDER, "format", - "(Z)L" MINIDFS_CLUSTER_BUILDER ";", conf->doFormat)) { - fprintf(stderr, "nmdCreate: failed to call Builder#doFormat\n"); + jthr = invokeMethod(env, &val, INSTANCE, bld, MINIDFS_CLUSTER_BUILDER, + "format", "(Z)L" MINIDFS_CLUSTER_BUILDER ";", conf->doFormat); + if (jthr) { + printExceptionAndFree(env, jthr, PRINT_EXC_ALL, "nmdCreate: " + "Builder::format"); goto error_dlr_bld; } bld2 = val.l; - if (invokeMethod(env, &val, NULL, INSTANCE, bld, - MINIDFS_CLUSTER_BUILDER, "build", - "()L" MINIDFS_CLUSTER ";")) { - fprintf(stderr, "nmdCreate: failed to call Builder#build\n"); + jthr = invokeMethod(env, &val, INSTANCE, bld, MINIDFS_CLUSTER_BUILDER, + "build", "()L" MINIDFS_CLUSTER ";"); + if (jthr) { + printExceptionAndFree(env, jthr, PRINT_EXC_ALL, + "nmdCreate: Builder#build"); goto error_dlr_bld2; } cl->obj = (*env)->NewGlobalRef(env, val.l); if (!cl->obj) { - fprintf(stderr, "nmdCreate: failed to create global reference to " - "MiniDFSCluster\n"); + printPendingExceptionAndFree(env, PRINT_EXC_ALL, + "nmdCreate: NewGlobalRef"); goto error_dlr_val; } (*env)->DeleteLocalRef(env, val.l); @@ -116,13 +122,17 @@ void nmdFree(struct NativeMiniDfsCluster int nmdShutdown(struct NativeMiniDfsCluster* cl) { JNIEnv *env = getJNIEnv(); + jthrowable jthr; + if (!env) { fprintf(stderr, "nmdShutdown: getJNIEnv failed\n"); return -EIO; } - if (invokeMethod(env, NULL, NULL, INSTANCE, cl->obj, - MINIDFS_CLUSTER, "shutdown", "()V")) { - fprintf(stderr, "nmdShutdown: MiniDFSCluster#shutdown failure\n"); + jthr = invokeMethod(env, NULL, INSTANCE, cl->obj, + MINIDFS_CLUSTER, "shutdown", "()V"); + if (jthr) { + printExceptionAndFree(env, jthr, PRINT_EXC_ALL, + "nmdShutdown: MiniDFSCluster#shutdown"); return -EIO; } return 0; @@ -130,15 +140,17 @@ int nmdShutdown(struct NativeMiniDfsClus int nmdWaitClusterUp(struct NativeMiniDfsCluster *cl) { + jthrowable jthr; JNIEnv *env = getJNIEnv(); if (!env) { fprintf(stderr, "nmdWaitClusterUp: getJNIEnv failed\n"); return -EIO; } - if (invokeMethod(env, NULL, NULL, INSTANCE, cl->obj, - MINIDFS_CLUSTER, "waitClusterUp", "()V")) { - fprintf(stderr, "nmdWaitClusterUp: MiniDFSCluster#waitClusterUp " - "failure\n"); + jthr = invokeMethod(env, NULL, INSTANCE, cl->obj, + MINIDFS_CLUSTER, "waitClusterUp", "()V"); + if (jthr) { + printExceptionAndFree(env, jthr, PRINT_EXC_ALL, + "nmdWaitClusterUp: MiniDFSCluster#waitClusterUp "); return -EIO; } return 0; @@ -148,6 +160,7 @@ int nmdGetNameNodePort(struct NativeMini { JNIEnv *env = getJNIEnv(); jvalue jVal; + jthrowable jthr; if (!env) { fprintf(stderr, "nmdHdfsConnect: getJNIEnv failed\n"); @@ -155,10 +168,11 @@ int nmdGetNameNodePort(struct NativeMini } // Note: this will have to be updated when HA nativeMiniDfs clusters are // supported - if (invokeMethod(env, &jVal, NULL, INSTANCE, cl->obj, - MINIDFS_CLUSTER, "getNameNodePort", "()I")) { - fprintf(stderr, "nmdHdfsConnect: MiniDFSCluster#getNameNodePort " - "failure\n"); + jthr = invokeMethod(env, &jVal, INSTANCE, cl->obj, + MINIDFS_CLUSTER, "getNameNodePort", "()I"); + if (jthr) { + printExceptionAndFree(env, jthr, PRINT_EXC_ALL, + "nmdHdfsConnect: MiniDFSCluster#getNameNodePort"); return -EIO; } return jVal.i;
