diff options
Diffstat (limited to 'storage/bdb/libdb_java/java_info.c')
-rw-r--r-- | storage/bdb/libdb_java/java_info.c | 1125 |
1 files changed, 1125 insertions, 0 deletions
diff --git a/storage/bdb/libdb_java/java_info.c b/storage/bdb/libdb_java/java_info.c new file mode 100644 index 00000000000..22fcbd23d46 --- /dev/null +++ b/storage/bdb/libdb_java/java_info.c @@ -0,0 +1,1125 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2002 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: java_info.c,v 11.46 2002/08/29 14:22:23 margo Exp $"; +#endif /* not lint */ + +#include <jni.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include "db_int.h" +#include "java_util.h" + +/**************************************************************** + * + * Callback functions + */ + +static int Db_assoc_callback(DB *db, + const DBT *key, + const DBT *data, + DBT *retval) +{ + DB_JAVAINFO *dbinfo; + + DB_ASSERT(db != NULL); + dbinfo = (DB_JAVAINFO *)db->api_internal; + return (dbji_call_assoc(dbinfo, db, dbinfo->jdbref, + key, data, retval)); +} + +static void Db_feedback_callback(DB *db, int opcode, int percent) +{ + DB_JAVAINFO *dbinfo; + + DB_ASSERT(db != NULL); + dbinfo = (DB_JAVAINFO *)db->api_internal; + dbji_call_feedback(dbinfo, db, dbinfo->jdbref, opcode, percent); +} + +static int Db_append_recno_callback(DB *db, DBT *dbt, db_recno_t recno) +{ + DB_JAVAINFO *dbinfo; + + dbinfo = (DB_JAVAINFO *)db->api_internal; + return (dbji_call_append_recno(dbinfo, db, dbinfo->jdbref, dbt, recno)); +} + +static int Db_bt_compare_callback(DB *db, const DBT *dbt1, const DBT *dbt2) +{ + DB_JAVAINFO *dbinfo; + + dbinfo = (DB_JAVAINFO *)db->api_internal; + return (dbji_call_bt_compare(dbinfo, db, dbinfo->jdbref, dbt1, dbt2)); +} + +static size_t Db_bt_prefix_callback(DB *db, const DBT *dbt1, const DBT *dbt2) +{ + DB_JAVAINFO *dbinfo; + + dbinfo = (DB_JAVAINFO *)db->api_internal; + return (dbji_call_bt_prefix(dbinfo, db, dbinfo->jdbref, dbt1, dbt2)); +} + +static int Db_dup_compare_callback(DB *db, const DBT *dbt1, const DBT *dbt2) +{ + DB_JAVAINFO *dbinfo; + + dbinfo = (DB_JAVAINFO *)db->api_internal; + return (dbji_call_dup_compare(dbinfo, db, dbinfo->jdbref, dbt1, dbt2)); +} + +static u_int32_t Db_h_hash_callback(DB *db, const void *data, u_int32_t len) +{ + DB_JAVAINFO *dbinfo; + + dbinfo = (DB_JAVAINFO *)db->api_internal; + return (dbji_call_h_hash(dbinfo, db, dbinfo->jdbref, data, len)); +} + +static void DbEnv_feedback_callback(DB_ENV *dbenv, int opcode, int percent) +{ + DB_ENV_JAVAINFO *dbinfo; + + DB_ASSERT(dbenv != NULL); + dbinfo = (DB_ENV_JAVAINFO *)dbenv->api2_internal; + dbjie_call_feedback(dbinfo, dbenv, dbinfo->jenvref, opcode, percent); +} + +static int DbEnv_rep_transport_callback(DB_ENV *dbenv, + const DBT *control, const DBT *rec, + int envid, u_int32_t flags) +{ + DB_ENV_JAVAINFO *dbinfo; + + dbinfo = (DB_ENV_JAVAINFO *)dbenv->api2_internal; + return (dbjie_call_rep_transport(dbinfo, dbenv, + dbinfo->jenvref, control, rec, envid, (int)flags)); +} + +static int DbEnv_app_dispatch_callback(DB_ENV *dbenv, DBT *dbt, + DB_LSN *lsn, db_recops recops) +{ + DB_ENV_JAVAINFO *dbinfo; + + DB_ASSERT(dbenv != NULL); + dbinfo = (DB_ENV_JAVAINFO *)dbenv->api2_internal; + return (dbjie_call_app_dispatch(dbinfo, dbenv, dbinfo->jenvref, dbt, + lsn, recops)); +} + +/**************************************************************** + * + * Implementation of class DBT_javainfo + */ +DBT_JAVAINFO * +dbjit_construct() +{ + DBT_JAVAINFO *dbjit; + int err; + + /*XXX should return err*/ + if ((err = __os_malloc(NULL, sizeof(DBT_JAVAINFO), &dbjit)) != 0) + return (NULL); + + memset(dbjit, 0, sizeof(DBT_JAVAINFO)); + return (dbjit); +} + +void dbjit_destroy(DBT_JAVAINFO *dbjit) +{ + DB_ASSERT(!F_ISSET(dbjit, DBT_JAVAINFO_LOCKED)); + /* Extra paranoia */ + memset(dbjit, 0, sizeof(DBT_JAVAINFO)); + (void)__os_free(NULL, dbjit); +} + +/**************************************************************** + * + * Implementation of class DB_ENV_JAVAINFO + */ + +/* create/initialize an object */ +DB_ENV_JAVAINFO * +dbjie_construct(JNIEnv *jnienv, + jobject jenv, + jobject default_errcall, + int is_dbopen) +{ + DB_ENV_JAVAINFO *dbjie; + int err; + + /*XXX should return err*/ + if ((err = __os_malloc(NULL, sizeof(DB_ENV_JAVAINFO), &dbjie)) != 0) + return (NULL); + memset(dbjie, 0, sizeof(DB_ENV_JAVAINFO)); + dbjie->is_dbopen = is_dbopen; + + if ((*jnienv)->GetJavaVM(jnienv, &dbjie->javavm) != 0) { + __os_free(NULL, dbjie); + report_exception(jnienv, "cannot get Java VM", 0, 0); + return (NULL); + } + + /* + * The default error call just prints to the 'System.err' + * stream. If the user does set_errcall to null, we'll + * want to have a reference to set it back to. + * + * Why do we have always set db_errcall to our own callback? + * Because it makes the interaction between setting the + * error prefix, error stream, and user's error callback + * that much easier. + */ + dbjie->default_errcall = NEW_GLOBAL_REF(jnienv, default_errcall); + dbjie->errcall = NEW_GLOBAL_REF(jnienv, default_errcall); + dbjie->jenvref = NEW_GLOBAL_REF(jnienv, jenv); + return (dbjie); +} + +/* release all objects held by this this one */ +void dbjie_dealloc(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv) +{ + if (dbjie->feedback != NULL) { + DELETE_GLOBAL_REF(jnienv, dbjie->feedback); + dbjie->feedback = NULL; + } + if (dbjie->app_dispatch != NULL) { + DELETE_GLOBAL_REF(jnienv, dbjie->app_dispatch); + dbjie->app_dispatch = NULL; + } + if (dbjie->errcall != NULL) { + DELETE_GLOBAL_REF(jnienv, dbjie->errcall); + dbjie->errcall = NULL; + } + if (dbjie->default_errcall != NULL) { + DELETE_GLOBAL_REF(jnienv, dbjie->default_errcall); + dbjie->default_errcall = NULL; + } + if (dbjie->jenvref != NULL) { + DELETE_GLOBAL_REF(jnienv, dbjie->jenvref); + dbjie->jenvref = NULL; + } + + if (dbjie->conflict != NULL) { + __os_free(NULL, dbjie->conflict); + dbjie->conflict = NULL; + dbjie->conflict_size = 0; + } + if (dbjie->errpfx != NULL) { + __os_free(NULL, dbjie->errpfx); + dbjie->errpfx = NULL; + } +} + +/* free this object, releasing anything allocated on its behalf */ +void dbjie_destroy(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv) +{ + dbjie_dealloc(dbjie, jnienv); + + /* Extra paranoia */ + memset(dbjie, 0, sizeof(DB_ENV_JAVAINFO)); + (void)__os_free(NULL, dbjie); +} + +/* + * Attach to the current thread that is running and + * return that. We use the java virtual machine + * that we saved in the constructor. + */ +JNIEnv * +dbjie_get_jnienv(DB_ENV_JAVAINFO *dbjie) +{ + /* + * Note: + * Different versions of the JNI disagree on the signature + * for AttachCurrentThread. The most recent documentation + * seems to say that (JNIEnv **) is correct, but newer + * JNIs seem to use (void **), oddly enough. + */ +#ifdef JNI_VERSION_1_2 + void *attachret = 0; +#else + JNIEnv *attachret = 0; +#endif + + /* + * This should always succeed, as we are called via + * some Java activity. I think therefore I am (a thread). + */ + if ((*dbjie->javavm)->AttachCurrentThread(dbjie->javavm, &attachret, 0) + != 0) + return (0); + + return ((JNIEnv *)attachret); +} + +jstring +dbjie_get_errpfx(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv) +{ + return (get_java_string(jnienv, dbjie->errpfx)); +} + +void +dbjie_set_errcall(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv, jobject new_errcall) +{ + /* + * If the new_errcall is null, we'll set the error call + * to the default one. + */ + if (new_errcall == NULL) + new_errcall = dbjie->default_errcall; + + DELETE_GLOBAL_REF(jnienv, dbjie->errcall); + dbjie->errcall = NEW_GLOBAL_REF(jnienv, new_errcall); +} + +void +dbjie_set_errpfx(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv, jstring errpfx) +{ + if (dbjie->errpfx != NULL) + __os_free(NULL, dbjie->errpfx); + + if (errpfx) + dbjie->errpfx = get_c_string(jnienv, errpfx); + else + dbjie->errpfx = NULL; +} + +void +dbjie_set_conflict(DB_ENV_JAVAINFO *dbjie, u_char *newarr, size_t size) +{ + if (dbjie->conflict != NULL) + (void)__os_free(NULL, dbjie->conflict); + dbjie->conflict = newarr; + dbjie->conflict_size = size; +} + +void dbjie_set_feedback_object(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv, + DB_ENV *dbenv, jobject jfeedback) +{ + int err; + + if (dbjie->feedback != NULL) { + DELETE_GLOBAL_REF(jnienv, dbjie->feedback); + } + if (jfeedback == NULL) { + if ((err = dbenv->set_feedback(dbenv, NULL)) != 0) + report_exception(jnienv, "set_feedback failed", + err, 0); + } + else { + if ((err = dbenv->set_feedback(dbenv, + DbEnv_feedback_callback)) != 0) + report_exception(jnienv, "set_feedback failed", + err, 0); + } + + dbjie->feedback = NEW_GLOBAL_REF(jnienv, jfeedback); +} + +void dbjie_call_feedback(DB_ENV_JAVAINFO *dbjie, DB_ENV *dbenv, jobject jenv, + int opcode, int percent) +{ + JNIEnv *jnienv; + jclass feedback_class; + jmethodID id; + + COMPQUIET(dbenv, NULL); + jnienv = dbjie_get_jnienv(dbjie); + if (jnienv == NULL) { + fprintf(stderr, "Cannot attach to current thread!\n"); + return; + } + + if ((feedback_class = + get_class(jnienv, name_DbEnvFeedback)) == NULL) { + fprintf(stderr, "Cannot find callback class %s\n", + name_DbEnvFeedback); + return; /* An exception has been posted. */ + } + id = (*jnienv)->GetMethodID(jnienv, feedback_class, + "feedback", + "(Lcom/sleepycat/db/DbEnv;II)V"); + if (!id) { + fprintf(stderr, "Cannot find callback method feedback\n"); + return; + } + + (*jnienv)->CallVoidMethod(jnienv, dbjie->feedback, id, + jenv, (jint)opcode, (jint)percent); +} + +void dbjie_set_rep_transport_object(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv, + DB_ENV *dbenv, int id, jobject jtransport) +{ + int err; + + if (dbjie->rep_transport != NULL) + DELETE_GLOBAL_REF(jnienv, dbjie->rep_transport); + + err = dbenv->set_rep_transport(dbenv, id, + DbEnv_rep_transport_callback); + verify_return(jnienv, err, 0); + + dbjie->rep_transport = NEW_GLOBAL_REF(jnienv, jtransport); +} + +int dbjie_call_rep_transport(DB_ENV_JAVAINFO *dbjie, DB_ENV *dbenv, + jobject jenv, const DBT *control, + const DBT *rec, int flags, int envid) +{ + JNIEnv *jnienv; + jclass rep_transport_class; + jmethodID jid; + jobject jcdbt, jrdbt; + + COMPQUIET(dbenv, NULL); + jnienv = dbjie_get_jnienv(dbjie); + if (jnienv == NULL) { + fprintf(stderr, "Cannot attach to current thread!\n"); + return (0); + } + + if ((rep_transport_class = + get_class(jnienv, name_DbRepTransport)) == NULL) { + fprintf(stderr, "Cannot find callback class %s\n", + name_DbRepTransport); + return (0); /* An exception has been posted. */ + } + jid = (*jnienv)->GetMethodID(jnienv, rep_transport_class, + "send", + "(Lcom/sleepycat/db/DbEnv;" + "Lcom/sleepycat/db/Dbt;" + "Lcom/sleepycat/db/Dbt;II)I"); + + if (!jid) { + fprintf(stderr, "Cannot find callback method send\n"); + return (0); + } + + jcdbt = get_const_Dbt(jnienv, control, NULL); + jrdbt = get_const_Dbt(jnienv, rec, NULL); + + return (*jnienv)->CallIntMethod(jnienv, dbjie->rep_transport, jid, jenv, + jcdbt, jrdbt, flags, envid); +} + +void dbjie_set_app_dispatch_object(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv, + DB_ENV *dbenv, jobject japp_dispatch) +{ + int err; + + if (dbjie->app_dispatch != NULL) { + DELETE_GLOBAL_REF(jnienv, dbjie->app_dispatch); + } + if (japp_dispatch == NULL) { + if ((err = dbenv->set_app_dispatch(dbenv, NULL)) != 0) + report_exception(jnienv, "set_app_dispatch failed", + err, 0); + } + else { + if ((err = dbenv->set_app_dispatch(dbenv, + DbEnv_app_dispatch_callback)) != 0) + report_exception(jnienv, "set_app_dispatch failed", + err, 0); + } + + dbjie->app_dispatch = NEW_GLOBAL_REF(jnienv, japp_dispatch); +} + +int dbjie_call_app_dispatch(DB_ENV_JAVAINFO *dbjie, DB_ENV *dbenv, jobject jenv, + DBT *dbt, DB_LSN *lsn, int recops) +{ + JNIEnv *jnienv; + jclass app_dispatch_class; + jmethodID id; + jobject jdbt; + jobject jlsn; + + COMPQUIET(dbenv, NULL); + jnienv = dbjie_get_jnienv(dbjie); + if (jnienv == NULL) { + fprintf(stderr, "Cannot attach to current thread!\n"); + return (0); + } + + if ((app_dispatch_class = + get_class(jnienv, name_DbTxnRecover)) == NULL) { + fprintf(stderr, "Cannot find callback class %s\n", + name_DbTxnRecover); + return (0); /* An exception has been posted. */ + } + id = (*jnienv)->GetMethodID(jnienv, app_dispatch_class, + "app_dispatch", + "(Lcom/sleepycat/db/DbEnv;" + "Lcom/sleepycat/db/Dbt;" + "Lcom/sleepycat/db/DbLsn;" + "I)I"); + if (!id) { + fprintf(stderr, "Cannot find callback method app_dispatch\n"); + return (0); + } + + jdbt = get_Dbt(jnienv, dbt, NULL); + + if (lsn == NULL) + jlsn = NULL; + else + jlsn = get_DbLsn(jnienv, *lsn); + + return (*jnienv)->CallIntMethod(jnienv, dbjie->app_dispatch, id, jenv, + jdbt, jlsn, recops); +} + +jobject dbjie_get_errcall(DB_ENV_JAVAINFO *dbjie) +{ + return (dbjie->errcall); +} + +jint dbjie_is_dbopen(DB_ENV_JAVAINFO *dbjie) +{ + return (dbjie->is_dbopen); +} + +/**************************************************************** + * + * Implementation of class DB_JAVAINFO + */ + +DB_JAVAINFO *dbji_construct(JNIEnv *jnienv, jobject jdb, jint flags) +{ + DB_JAVAINFO *dbji; + int err; + + /*XXX should return err*/ + if ((err = __os_malloc(NULL, sizeof(DB_JAVAINFO), &dbji)) != 0) + return (NULL); + + memset(dbji, 0, sizeof(DB_JAVAINFO)); + + if ((*jnienv)->GetJavaVM(jnienv, &dbji->javavm) != 0) { + report_exception(jnienv, "cannot get Java VM", 0, 0); + (void)__os_free(NULL, dbji); + return (NULL); + } + dbji->jdbref = NEW_GLOBAL_REF(jnienv, jdb); + dbji->construct_flags = flags; + return (dbji); +} + +void +dbji_dealloc(DB_JAVAINFO *dbji, JNIEnv *jnienv) +{ + if (dbji->append_recno != NULL) { + DELETE_GLOBAL_REF(jnienv, dbji->append_recno); + dbji->append_recno = NULL; + } + if (dbji->assoc != NULL) { + DELETE_GLOBAL_REF(jnienv, dbji->assoc); + dbji->assoc = NULL; + } + if (dbji->bt_compare != NULL) { + DELETE_GLOBAL_REF(jnienv, dbji->bt_compare); + dbji->bt_compare = NULL; + } + if (dbji->bt_prefix != NULL) { + DELETE_GLOBAL_REF(jnienv, dbji->bt_prefix); + dbji->bt_prefix = NULL; + } + if (dbji->dup_compare != NULL) { + DELETE_GLOBAL_REF(jnienv, dbji->dup_compare); + dbji->dup_compare = NULL; + } + if (dbji->feedback != NULL) { + DELETE_GLOBAL_REF(jnienv, dbji->feedback); + dbji->feedback = NULL; + } + if (dbji->h_hash != NULL) { + DELETE_GLOBAL_REF(jnienv, dbji->h_hash); + dbji->h_hash = NULL; + } + if (dbji->jdbref != NULL) { + DELETE_GLOBAL_REF(jnienv, dbji->jdbref); + dbji->jdbref = NULL; + } +} + +void +dbji_destroy(DB_JAVAINFO *dbji, JNIEnv *jnienv) +{ + dbji_dealloc(dbji, jnienv); + __os_free(NULL, dbji); +} + +JNIEnv *dbji_get_jnienv(DB_JAVAINFO *dbji) +{ + /* + * Note: + * Different versions of the JNI disagree on the signature + * for AttachCurrentThread. The most recent documentation + * seems to say that (JNIEnv **) is correct, but newer + * JNIs seem to use (void **), oddly enough. + */ +#ifdef JNI_VERSION_1_2 + void *attachret = 0; +#else + JNIEnv *attachret = 0; +#endif + + /* + * This should always succeed, as we are called via + * some Java activity. I think therefore I am (a thread). + */ + if ((*dbji->javavm)->AttachCurrentThread(dbji->javavm, &attachret, 0) + != 0) + return (0); + + return ((JNIEnv *)attachret); +} + +jint dbji_get_flags(DB_JAVAINFO *dbji) +{ + return (dbji->construct_flags); +} + +void dbji_set_feedback_object(DB_JAVAINFO *dbji, JNIEnv *jnienv, + DB *db, jobject jfeedback) +{ + jclass feedback_class; + + if (dbji->feedback_method_id == NULL) { + if ((feedback_class = + get_class(jnienv, name_DbFeedback)) == NULL) + return; /* An exception has been posted. */ + dbji->feedback_method_id = + (*jnienv)->GetMethodID(jnienv, feedback_class, + "feedback", + "(Lcom/sleepycat/db/Db;II)V"); + if (dbji->feedback_method_id == NULL) { + /* + * XXX + * We should really have a better way + * to translate this to a Java exception class. + * In theory, it shouldn't happen. + */ + report_exception(jnienv, "Cannot find callback method", + EFAULT, 0); + return; + } + } + + if (dbji->feedback != NULL) { + DELETE_GLOBAL_REF(jnienv, dbji->feedback); + } + if (jfeedback == NULL) { + db->set_feedback(db, NULL); + } + else { + db->set_feedback(db, Db_feedback_callback); + } + + dbji->feedback = NEW_GLOBAL_REF(jnienv, jfeedback); + +} + +void dbji_call_feedback(DB_JAVAINFO *dbji, DB *db, jobject jdb, + int opcode, int percent) +{ + JNIEnv *jnienv; + + COMPQUIET(db, NULL); + jnienv = dbji_get_jnienv(dbji); + if (jnienv == NULL) { + fprintf(stderr, "Cannot attach to current thread!\n"); + return; + } + + DB_ASSERT(dbji->feedback_method_id != NULL); + (*jnienv)->CallVoidMethod(jnienv, dbji->feedback, + dbji->feedback_method_id, + jdb, (jint)opcode, (jint)percent); +} + +void dbji_set_append_recno_object(DB_JAVAINFO *dbji, JNIEnv *jnienv, + DB *db, jobject jcallback) +{ + jclass append_recno_class; + + if (dbji->append_recno_method_id == NULL) { + if ((append_recno_class = + get_class(jnienv, name_DbAppendRecno)) == NULL) + return; /* An exception has been posted. */ + dbji->append_recno_method_id = + (*jnienv)->GetMethodID(jnienv, append_recno_class, + "db_append_recno", + "(Lcom/sleepycat/db/Db;" + "Lcom/sleepycat/db/Dbt;I)V"); + if (dbji->append_recno_method_id == NULL) { + /* + * XXX + * We should really have a better way + * to translate this to a Java exception class. + * In theory, it shouldn't happen. + */ + report_exception(jnienv, "Cannot find callback method", + EFAULT, 0); + return; + } + } + + if (dbji->append_recno != NULL) { + DELETE_GLOBAL_REF(jnienv, dbji->append_recno); + } + if (jcallback == NULL) { + db->set_append_recno(db, NULL); + } + else { + db->set_append_recno(db, Db_append_recno_callback); + } + + dbji->append_recno = NEW_GLOBAL_REF(jnienv, jcallback); +} + +extern int dbji_call_append_recno(DB_JAVAINFO *dbji, DB *db, jobject jdb, + DBT *dbt, jint recno) +{ + JNIEnv *jnienv; + jobject jresult; + DBT_JAVAINFO *dbtji; + LOCKED_DBT lresult; + DB_ENV *dbenv; + u_char *bytearray; + int err; + + jnienv = dbji_get_jnienv(dbji); + dbenv = db->dbenv; + if (jnienv == NULL) { + fprintf(stderr, "Cannot attach to current thread!\n"); + return (0); + } + + jresult = get_Dbt(jnienv, dbt, &dbtji); + + DB_ASSERT(dbji->append_recno_method_id != NULL); + (*jnienv)->CallVoidMethod(jnienv, dbji->append_recno, + dbji->append_recno_method_id, + jdb, jresult, recno); + + /* + * The underlying C API requires that an errno be returned + * on error. Java users know nothing of errnos, so we + * allow them to throw exceptions instead. We leave the + * exception in place and return DB_JAVA_CALLBACK to the C API + * that called us. Eventually the DB->get will fail and + * when java prepares to throw an exception in + * report_exception(), this will be spotted as a special case, + * and the original exception will be preserved. + * + * Note: we have sometimes noticed strange behavior with + * exceptions under Linux 1.1.7 JVM. (i.e. multiple calls + * to ExceptionOccurred() may report different results). + * Currently we don't know of any problems related to this + * in our code, but if it pops up in the future, users are + * encouranged to get a more recent JVM. + */ + if ((*jnienv)->ExceptionOccurred(jnienv) != NULL) + return (DB_JAVA_CALLBACK); + + /* + * Now get the DBT back from java, because the user probably + * changed it. We'll have to copy back the array too and let + * our caller free it. + * + * We expect that the user *has* changed the DBT (why else would + * they set up an append_recno callback?) so we don't + * worry about optimizing the unchanged case. + */ + if ((err = locked_dbt_get(&lresult, jnienv, dbenv, jresult, inOp)) != 0) + return (err); + + memcpy(dbt, &lresult.javainfo->dbt, sizeof(DBT)); + if ((err = __os_malloc(dbenv, dbt->size, &bytearray)) != 0) + goto out; + + memcpy(bytearray, dbt->data, dbt->size); + dbt->data = bytearray; + dbt->flags |= DB_DBT_APPMALLOC; + + out: + locked_dbt_put(&lresult, jnienv, dbenv); + return (err); +} + +void dbji_set_assoc_object(DB_JAVAINFO *dbji, JNIEnv *jnienv, + DB *db, DB_TXN *txn, DB *second, + jobject jcallback, int flags) +{ + jclass assoc_class; + int err; + + if (dbji->assoc_method_id == NULL) { + if ((assoc_class = + get_class(jnienv, name_DbSecondaryKeyCreate)) == NULL) + return; /* An exception has been posted. */ + dbji->assoc_method_id = + (*jnienv)->GetMethodID(jnienv, assoc_class, + "secondary_key_create", + "(Lcom/sleepycat/db/Db;" + "Lcom/sleepycat/db/Dbt;" + "Lcom/sleepycat/db/Dbt;" + "Lcom/sleepycat/db/Dbt;)I"); + if (dbji->assoc_method_id == NULL) { + /* + * XXX + * We should really have a better way + * to translate this to a Java exception class. + * In theory, it shouldn't happen. + */ + report_exception(jnienv, "Cannot find callback method", + EFAULT, 0); + return; + } + } + + if (dbji->assoc != NULL) { + DELETE_GLOBAL_REF(jnienv, dbji->assoc); + dbji->assoc = NULL; + } + + if (jcallback == NULL) + err = db->associate(db, txn, second, NULL, flags); + else + err = db->associate(db, txn, second, Db_assoc_callback, flags); + + if (verify_return(jnienv, err, 0)) + dbji->assoc = NEW_GLOBAL_REF(jnienv, jcallback); +} + +extern int dbji_call_assoc(DB_JAVAINFO *dbji, DB *db, jobject jdb, + const DBT *key, const DBT *value, DBT *result) +{ + JNIEnv *jnienv; + jobject jresult; + LOCKED_DBT lresult; + DB_ENV *dbenv; + int err; + int sz; + u_char *bytearray; + jint retval; + + jnienv = dbji_get_jnienv(dbji); + if (jnienv == NULL) { + fprintf(stderr, "Cannot attach to current thread!\n"); + return (0); + } + + DB_ASSERT(dbji->assoc_method_id != NULL); + + dbenv = db->dbenv; + jresult = create_default_object(jnienv, name_DBT); + + retval = (*jnienv)->CallIntMethod(jnienv, dbji->assoc, + dbji->assoc_method_id, jdb, + get_const_Dbt(jnienv, key, NULL), + get_const_Dbt(jnienv, value, NULL), + jresult); + if (retval != 0) + return (retval); + + if ((*jnienv)->ExceptionOccurred(jnienv) != NULL) + return (DB_JAVA_CALLBACK); + + if ((err = locked_dbt_get(&lresult, jnienv, dbenv, jresult, inOp)) != 0) + return (err); + + sz = lresult.javainfo->dbt.size; + if (sz > 0) { + bytearray = (u_char *)lresult.javainfo->dbt.data; + + /* + * If the byte array is in the range of one of the + * arrays passed to us we can use it directly. + * If not, we must create our own array and + * fill it in with the java array. Since + * the java array may disappear and we don't + * want to keep its memory locked indefinitely, + * we cannot just pin the array. + * + * XXX consider pinning the array, and having + * some way for the C layer to notify the java + * layer when it can be unpinned. + */ + if ((bytearray < (u_char *)key->data || + bytearray + sz > (u_char *)key->data + key->size) && + (bytearray < (u_char *)value->data || + bytearray + sz > (u_char *)value->data + value->size)) { + + result->flags |= DB_DBT_APPMALLOC; + if ((err = __os_malloc(dbenv, sz, &bytearray)) != 0) + goto out; + memcpy(bytearray, lresult.javainfo->dbt.data, sz); + } + result->data = bytearray; + result->size = sz; + } + out: + locked_dbt_put(&lresult, jnienv, dbenv); + return (err); +} + +void dbji_set_bt_compare_object(DB_JAVAINFO *dbji, JNIEnv *jnienv, + DB *db, jobject jcompare) +{ + jclass bt_compare_class; + + if (dbji->bt_compare_method_id == NULL) { + if ((bt_compare_class = + get_class(jnienv, name_DbBtreeCompare)) == NULL) + return; /* An exception has been posted. */ + dbji->bt_compare_method_id = + (*jnienv)->GetMethodID(jnienv, bt_compare_class, + "bt_compare", + "(Lcom/sleepycat/db/Db;" + "Lcom/sleepycat/db/Dbt;" + "Lcom/sleepycat/db/Dbt;)I"); + if (dbji->bt_compare_method_id == NULL) { + /* + * XXX + * We should really have a better way + * to translate this to a Java exception class. + * In theory, it shouldn't happen. + */ + report_exception(jnienv, "Cannot find callback method", + EFAULT, 0); + return; + } + } + + if (dbji->bt_compare != NULL) { + DELETE_GLOBAL_REF(jnienv, dbji->bt_compare); + } + if (jcompare == NULL) { + db->set_bt_compare(db, NULL); + } + else { + db->set_bt_compare(db, Db_bt_compare_callback); + } + + dbji->bt_compare = NEW_GLOBAL_REF(jnienv, jcompare); +} + +int dbji_call_bt_compare(DB_JAVAINFO *dbji, DB *db, jobject jdb, + const DBT *dbt1, const DBT *dbt2) +{ + JNIEnv *jnienv; + jobject jdbt1, jdbt2; + + COMPQUIET(db, NULL); + jnienv = dbji_get_jnienv(dbji); + if (jnienv == NULL) { + fprintf(stderr, "Cannot attach to current thread!\n"); + return (0); + } + + jdbt1 = get_const_Dbt(jnienv, dbt1, NULL); + jdbt2 = get_const_Dbt(jnienv, dbt2, NULL); + + DB_ASSERT(dbji->bt_compare_method_id != NULL); + return (*jnienv)->CallIntMethod(jnienv, dbji->bt_compare, + dbji->bt_compare_method_id, + jdb, jdbt1, jdbt2); +} + +void dbji_set_bt_prefix_object(DB_JAVAINFO *dbji, JNIEnv *jnienv, + DB *db, jobject jprefix) +{ + jclass bt_prefix_class; + + if (dbji->bt_prefix_method_id == NULL) { + if ((bt_prefix_class = + get_class(jnienv, name_DbBtreePrefix)) == NULL) + return; /* An exception has been posted. */ + dbji->bt_prefix_method_id = + (*jnienv)->GetMethodID(jnienv, bt_prefix_class, + "bt_prefix", + "(Lcom/sleepycat/db/Db;" + "Lcom/sleepycat/db/Dbt;" + "Lcom/sleepycat/db/Dbt;)I"); + if (dbji->bt_prefix_method_id == NULL) { + /* + * XXX + * We should really have a better way + * to translate this to a Java exception class. + * In theory, it shouldn't happen. + */ + report_exception(jnienv, "Cannot find callback method", + EFAULT, 0); + return; + } + } + + if (dbji->bt_prefix != NULL) { + DELETE_GLOBAL_REF(jnienv, dbji->bt_prefix); + } + if (jprefix == NULL) { + db->set_bt_prefix(db, NULL); + } + else { + db->set_bt_prefix(db, Db_bt_prefix_callback); + } + + dbji->bt_prefix = NEW_GLOBAL_REF(jnienv, jprefix); +} + +size_t dbji_call_bt_prefix(DB_JAVAINFO *dbji, DB *db, jobject jdb, + const DBT *dbt1, const DBT *dbt2) +{ + JNIEnv *jnienv; + jobject jdbt1, jdbt2; + + COMPQUIET(db, NULL); + jnienv = dbji_get_jnienv(dbji); + if (jnienv == NULL) { + fprintf(stderr, "Cannot attach to current thread!\n"); + return (0); + } + + jdbt1 = get_const_Dbt(jnienv, dbt1, NULL); + jdbt2 = get_const_Dbt(jnienv, dbt2, NULL); + + DB_ASSERT(dbji->bt_prefix_method_id != NULL); + return (size_t)(*jnienv)->CallIntMethod(jnienv, dbji->bt_prefix, + dbji->bt_prefix_method_id, + jdb, jdbt1, jdbt2); +} + +void dbji_set_dup_compare_object(DB_JAVAINFO *dbji, JNIEnv *jnienv, + DB *db, jobject jcompare) +{ + jclass dup_compare_class; + + if (dbji->dup_compare_method_id == NULL) { + if ((dup_compare_class = + get_class(jnienv, name_DbDupCompare)) == NULL) + return; /* An exception has been posted. */ + dbji->dup_compare_method_id = + (*jnienv)->GetMethodID(jnienv, dup_compare_class, + "dup_compare", + "(Lcom/sleepycat/db/Db;" + "Lcom/sleepycat/db/Dbt;" + "Lcom/sleepycat/db/Dbt;)I"); + if (dbji->dup_compare_method_id == NULL) { + /* + * XXX + * We should really have a better way + * to translate this to a Java exception class. + * In theory, it shouldn't happen. + */ + report_exception(jnienv, "Cannot find callback method", + EFAULT, 0); + return; + } + } + + if (dbji->dup_compare != NULL) + DELETE_GLOBAL_REF(jnienv, dbji->dup_compare); + + if (jcompare == NULL) + db->set_dup_compare(db, NULL); + else + db->set_dup_compare(db, Db_dup_compare_callback); + + dbji->dup_compare = NEW_GLOBAL_REF(jnienv, jcompare); +} + +int dbji_call_dup_compare(DB_JAVAINFO *dbji, DB *db, jobject jdb, + const DBT *dbt1, const DBT *dbt2) +{ + JNIEnv *jnienv; + jobject jdbt1, jdbt2; + + COMPQUIET(db, NULL); + jnienv = dbji_get_jnienv(dbji); + if (jnienv == NULL) { + fprintf(stderr, "Cannot attach to current thread!\n"); + return (0); + } + + jdbt1 = get_const_Dbt(jnienv, dbt1, NULL); + jdbt2 = get_const_Dbt(jnienv, dbt2, NULL); + + DB_ASSERT(dbji->dup_compare_method_id != NULL); + return (*jnienv)->CallIntMethod(jnienv, dbji->dup_compare, + dbji->dup_compare_method_id, + jdb, jdbt1, jdbt2); +} + +void dbji_set_h_hash_object(DB_JAVAINFO *dbji, JNIEnv *jnienv, + DB *db, jobject jhash) +{ + jclass h_hash_class; + + if (dbji->h_hash_method_id == NULL) { + if ((h_hash_class = + get_class(jnienv, name_DbHash)) == NULL) + return; /* An exception has been posted. */ + dbji->h_hash_method_id = + (*jnienv)->GetMethodID(jnienv, h_hash_class, + "hash", + "(Lcom/sleepycat/db/Db;" + "[BI)I"); + if (dbji->h_hash_method_id == NULL) { + /* + * XXX + * We should really have a better way + * to translate this to a Java exception class. + * In theory, it shouldn't happen. + */ + report_exception(jnienv, "Cannot find callback method", + EFAULT, 0); + return; + } + } + + if (dbji->h_hash != NULL) + DELETE_GLOBAL_REF(jnienv, dbji->h_hash); + + if (jhash == NULL) + db->set_h_hash(db, NULL); + else + db->set_h_hash(db, Db_h_hash_callback); + + dbji->h_hash = NEW_GLOBAL_REF(jnienv, jhash); +} + +int dbji_call_h_hash(DB_JAVAINFO *dbji, DB *db, jobject jdb, + const void *data, int len) +{ + JNIEnv *jnienv; + jbyteArray jdata; + + COMPQUIET(db, NULL); + jnienv = dbji_get_jnienv(dbji); + if (jnienv == NULL) { + fprintf(stderr, "Cannot attach to current thread!\n"); + return (0); + } + + DB_ASSERT(dbji->h_hash_method_id != NULL); + + if ((jdata = (*jnienv)->NewByteArray(jnienv, len)) == NULL) + return (0); /* An exception has been posted by the JVM */ + (*jnienv)->SetByteArrayRegion(jnienv, jdata, 0, len, (void *)data); + return (*jnienv)->CallIntMethod(jnienv, dbji->h_hash, + dbji->h_hash_method_id, + jdb, jdata, len); +} |