/*- * 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_util.c,v 1.1.1.1 2003/02/15 04:56:08 zarzycki Exp $"; #endif /* not lint */ #include #include #include "db_int.h" #include "java_util.h" #ifdef DB_WIN32 #define sys_errlist _sys_errlist #define sys_nerr _sys_nerr #endif const char * const name_DB = "Db"; const char * const name_DB_BTREE_STAT = "DbBtreeStat"; const char * const name_DBC = "Dbc"; const char * const name_DB_DEADLOCK_EX = "DbDeadlockException"; const char * const name_DB_ENV = "DbEnv"; const char * const name_DB_EXCEPTION = "DbException"; const char * const name_DB_HASH_STAT = "DbHashStat"; const char * const name_DB_LOCK = "DbLock"; const char * const name_DB_LOCK_STAT = "DbLockStat"; const char * const name_DB_LOCKNOTGRANTED_EX = "DbLockNotGrantedException"; const char * const name_DB_LOGC = "DbLogc"; const char * const name_DB_LOG_STAT = "DbLogStat"; const char * const name_DB_LSN = "DbLsn"; const char * const name_DB_MEMORY_EX = "DbMemoryException"; const char * const name_DB_MPOOL_FSTAT = "DbMpoolFStat"; const char * const name_DB_MPOOL_STAT = "DbMpoolStat"; const char * const name_DB_PREPLIST = "DbPreplist"; const char * const name_DB_QUEUE_STAT = "DbQueueStat"; const char * const name_DB_REP_STAT = "DbRepStat"; const char * const name_DB_RUNRECOVERY_EX = "DbRunRecoveryException"; const char * const name_DBT = "Dbt"; const char * const name_DB_TXN = "DbTxn"; const char * const name_DB_TXN_STAT = "DbTxnStat"; const char * const name_DB_TXN_STAT_ACTIVE = "DbTxnStat$Active"; const char * const name_DB_UTIL = "DbUtil"; const char * const name_DbAppendRecno = "DbAppendRecno"; const char * const name_DbBtreeCompare = "DbBtreeCompare"; const char * const name_DbBtreePrefix = "DbBtreePrefix"; const char * const name_DbDupCompare = "DbDupCompare"; const char * const name_DbEnvFeedback = "DbEnvFeedback"; const char * const name_DbErrcall = "DbErrcall"; const char * const name_DbHash = "DbHash"; const char * const name_DbLockRequest = "DbLockRequest"; const char * const name_DbFeedback = "DbFeedback"; const char * const name_DbRecoveryInit = "DbRecoveryInit"; const char * const name_DbRepTransport = "DbRepTransport"; const char * const name_DbSecondaryKeyCreate = "DbSecondaryKeyCreate"; const char * const name_DbTxnRecover = "DbTxnRecover"; const char * const name_RepElectResult = "DbEnv$RepElectResult"; const char * const name_RepProcessMessage = "DbEnv$RepProcessMessage"; const char * const string_signature = "Ljava/lang/String;"; jfieldID fid_Dbt_data; jfieldID fid_Dbt_offset; jfieldID fid_Dbt_size; jfieldID fid_Dbt_ulen; jfieldID fid_Dbt_dlen; jfieldID fid_Dbt_doff; jfieldID fid_Dbt_flags; jfieldID fid_Dbt_private_dbobj_; jfieldID fid_Dbt_must_create_data; jfieldID fid_DbLockRequest_op; jfieldID fid_DbLockRequest_mode; jfieldID fid_DbLockRequest_timeout; jfieldID fid_DbLockRequest_obj; jfieldID fid_DbLockRequest_lock; jfieldID fid_RepProcessMessage_envid; /**************************************************************** * * Utility functions used by "glue" functions. */ /* * Do any one time initialization, especially initializing any * unchanging methodIds, fieldIds, etc. */ void one_time_init(JNIEnv *jnienv) { jclass cl; if ((cl = get_class(jnienv, name_DBT)) == NULL) return; /* An exception has been posted. */ fid_Dbt_data = (*jnienv)->GetFieldID(jnienv, cl, "data", "[B"); fid_Dbt_offset = (*jnienv)->GetFieldID(jnienv, cl, "offset", "I"); fid_Dbt_size = (*jnienv)->GetFieldID(jnienv, cl, "size", "I"); fid_Dbt_ulen = (*jnienv)->GetFieldID(jnienv, cl, "ulen", "I"); fid_Dbt_dlen = (*jnienv)->GetFieldID(jnienv, cl, "dlen", "I"); fid_Dbt_doff = (*jnienv)->GetFieldID(jnienv, cl, "doff", "I"); fid_Dbt_flags = (*jnienv)->GetFieldID(jnienv, cl, "flags", "I"); fid_Dbt_must_create_data = (*jnienv)->GetFieldID(jnienv, cl, "must_create_data", "Z"); fid_Dbt_private_dbobj_ = (*jnienv)->GetFieldID(jnienv, cl, "private_dbobj_", "J"); if ((cl = get_class(jnienv, name_DbLockRequest)) == NULL) return; /* An exception has been posted. */ fid_DbLockRequest_op = (*jnienv)->GetFieldID(jnienv, cl, "op", "I"); fid_DbLockRequest_mode = (*jnienv)->GetFieldID(jnienv, cl, "mode", "I"); fid_DbLockRequest_timeout = (*jnienv)->GetFieldID(jnienv, cl, "timeout", "I"); fid_DbLockRequest_obj = (*jnienv)->GetFieldID(jnienv, cl, "obj", "Lcom/sleepycat/db/Dbt;"); fid_DbLockRequest_lock = (*jnienv)->GetFieldID(jnienv, cl, "lock", "Lcom/sleepycat/db/DbLock;"); if ((cl = get_class(jnienv, name_RepProcessMessage)) == NULL) return; /* An exception has been posted. */ fid_RepProcessMessage_envid = (*jnienv)->GetFieldID(jnienv, cl, "envid", "I"); } /* * Get the private data from a Db* object that points back to a C DB_* object. * The private data is stored in the object as a Java long (64 bits), * which is long enough to store a pointer on current architectures. */ void *get_private_dbobj(JNIEnv *jnienv, const char *classname, jobject obj) { jclass dbClass; jfieldID id; long_to_ptr lp; if (!obj) return (0); if ((dbClass = get_class(jnienv, classname)) == NULL) return (NULL); /* An exception has been posted. */ id = (*jnienv)->GetFieldID(jnienv, dbClass, "private_dbobj_", "J"); lp.java_long = (*jnienv)->GetLongField(jnienv, obj, id); return (lp.ptr); } /* * Set the private data in a Db* object that points back to a C DB_* object. * The private data is stored in the object as a Java long (64 bits), * which is long enough to store a pointer on current architectures. */ void set_private_dbobj(JNIEnv *jnienv, const char *classname, jobject obj, void *value) { long_to_ptr lp; jclass dbClass; jfieldID id; lp.java_long = 0; /* no junk in case sizes mismatch */ lp.ptr = value; if ((dbClass = get_class(jnienv, classname)) == NULL) return; /* An exception has been posted. */ id = (*jnienv)->GetFieldID(jnienv, dbClass, "private_dbobj_", "J"); (*jnienv)->SetLongField(jnienv, obj, id, lp.java_long); } /* * Get the private data in a Db/DbEnv object that holds additional 'side data'. * The private data is stored in the object as a Java long (64 bits), * which is long enough to store a pointer on current architectures. */ void *get_private_info(JNIEnv *jnienv, const char *classname, jobject obj) { jclass dbClass; jfieldID id; long_to_ptr lp; if (!obj) return (NULL); if ((dbClass = get_class(jnienv, classname)) == NULL) return (NULL); /* An exception has been posted. */ id = (*jnienv)->GetFieldID(jnienv, dbClass, "private_info_", "J"); lp.java_long = (*jnienv)->GetLongField(jnienv, obj, id); return (lp.ptr); } /* * Set the private data in a Db/DbEnv object that holds additional 'side data'. * The private data is stored in the object as a Java long (64 bits), * which is long enough to store a pointer on current architectures. */ void set_private_info(JNIEnv *jnienv, const char *classname, jobject obj, void *value) { long_to_ptr lp; jclass dbClass; jfieldID id; lp.java_long = 0; /* no junk in case sizes mismatch */ lp.ptr = value; if ((dbClass = get_class(jnienv, classname)) == NULL) return; /* An exception has been posted. */ id = (*jnienv)->GetFieldID(jnienv, dbClass, "private_info_", "J"); (*jnienv)->SetLongField(jnienv, obj, id, lp.java_long); } /* * Given a non-qualified name (e.g. "foo"), get the class handle * for the fully qualified name (e.g. "com.sleepycat.db.foo") */ jclass get_class(JNIEnv *jnienv, const char *classname) { /* * Note: PERFORMANCE: It should be possible to cache jclass's. * If we do a NewGlobalRef on each one, we can keep them * around in a table. A jclass is a jobject, and * since NewGlobalRef returns a jobject, it isn't * technically right, but it would likely work with * most implementations. Possibly make it configurable. */ char fullname[128]; (void)snprintf(fullname, sizeof(fullname), "%s%s", DB_PACKAGE_NAME, classname); return ((*jnienv)->FindClass(jnienv, fullname)); } /* * Given a fully qualified name (e.g. "java.util.Hashtable") * return the jclass object. If it can't be found, an * exception is raised and NULL is return. * This is appropriate to be used for classes that may * not be present. */ jclass get_fully_qualified_class(JNIEnv *jnienv, const char *classname) { jclass result; result = ((*jnienv)->FindClass(jnienv, classname)); if (result == NULL) { jclass cnfe; char message[1024]; cnfe = (*jnienv)->FindClass(jnienv, "java/lang/ClassNotFoundException"); strncpy(message, classname, sizeof(message)); strncat(message, ": class not found", sizeof(message)); (*jnienv)->ThrowNew(jnienv, cnfe, message); } return (result); } /* * Set an individual field in a Db* object. * The field must be a DB object type. */ void set_object_field(JNIEnv *jnienv, jclass class_of_this, jobject jthis, const char *object_classname, const char *name_of_field, jobject obj) { char signature[512]; jfieldID id; (void)snprintf(signature, sizeof(signature), "L%s%s;", DB_PACKAGE_NAME, object_classname); id = (*jnienv)->GetFieldID( jnienv, class_of_this, name_of_field, signature); (*jnienv)->SetObjectField(jnienv, jthis, id, obj); } /* * Set an individual field in a Db* object. * The field must be an integer type. */ void set_int_field(JNIEnv *jnienv, jclass class_of_this, jobject jthis, const char *name_of_field, jint value) { jfieldID id = (*jnienv)->GetFieldID(jnienv, class_of_this, name_of_field, "I"); (*jnienv)->SetIntField(jnienv, jthis, id, value); } /* * Set an individual field in a Db* object. * The field must be an integer type. */ void set_long_field(JNIEnv *jnienv, jclass class_of_this, jobject jthis, const char *name_of_field, jlong value) { jfieldID id = (*jnienv)->GetFieldID(jnienv, class_of_this, name_of_field, "J"); (*jnienv)->SetLongField(jnienv, jthis, id, value); } /* * Set an individual field in a Db* object. * The field must be an integer type. */ void set_lsn_field(JNIEnv *jnienv, jclass class_of_this, jobject jthis, const char *name_of_field, DB_LSN value) { set_object_field(jnienv, class_of_this, jthis, name_DB_LSN, name_of_field, get_DbLsn(jnienv, value)); } /* * Report an exception back to the java side. */ void report_exception(JNIEnv *jnienv, const char *text, int err, unsigned long expect_mask) { jstring textString; jclass dbexcept; jclass javaexcept; jthrowable obj; textString = NULL; dbexcept = NULL; javaexcept = NULL; switch (err) { /* * DB_JAVA_CALLBACK is returned by * dbji_call_append_recno() (the append_recno callback) * when the Java version of the callback has thrown * an exception, and we want to pass the exception on. * The exception has already been thrown, we * don't want to throw a new one. */ case DB_JAVA_CALLBACK: break; case ENOENT: /* * In this case there is a corresponding * standard java exception type that we'll use. * First we make sure that the calling function * expected this kind of error, if not we give * an 'internal error' DbException, since * we must not throw an exception type that isn't * declared in the signature. * * We'll make this a little more general if/when * we add more java standard exceptions. */ if ((expect_mask & EXCEPTION_FILE_NOT_FOUND) != 0) { javaexcept = (*jnienv)->FindClass(jnienv, "java/io/FileNotFoundException"); } else { char errstr[1024]; snprintf(errstr, sizeof(errstr), "internal error: unexpected errno: %s", text); textString = get_java_string(jnienv, errstr); dbexcept = get_class(jnienv, name_DB_EXCEPTION); } break; case DB_RUNRECOVERY: dbexcept = get_class(jnienv, name_DB_RUNRECOVERY_EX); break; case DB_LOCK_DEADLOCK: dbexcept = get_class(jnienv, name_DB_DEADLOCK_EX); break; default: dbexcept = get_class(jnienv, name_DB_EXCEPTION); break; } if (dbexcept != NULL) { if (textString == NULL) textString = get_java_string(jnienv, text); if ((obj = create_exception(jnienv, textString, err, dbexcept)) != NULL) (*jnienv)->Throw(jnienv, obj); /* Otherwise, an exception has been posted. */ } else if (javaexcept != NULL) (*jnienv)->ThrowNew(jnienv, javaexcept, text); else fprintf(stderr, "report_exception: failed to create an exception\n"); } /* * Report an exception back to the java side, for the specific * case of DB_LOCK_NOTGRANTED, as more things are added to the * constructor of this type of exception. */ void report_notgranted_exception(JNIEnv *jnienv, const char *text, db_lockop_t op, db_lockmode_t mode, jobject jdbt, jobject jlock, int index) { jstring textString; jclass dbexcept; jthrowable obj; jmethodID mid; if ((dbexcept = get_class(jnienv, name_DB_LOCKNOTGRANTED_EX)) == NULL) return; /* An exception has been posted. */ textString = get_java_string(jnienv, text); mid = (*jnienv)->GetMethodID(jnienv, dbexcept, "", "(Ljava/lang/String;II" "Lcom/sleepycat/db/Dbt;" "Lcom/sleepycat/db/DbLock;I)V"); if ((obj = (jthrowable)(*jnienv)->NewObject(jnienv, dbexcept, mid, textString, op, mode, jdbt, jlock, index)) != NULL) (*jnienv)->Throw(jnienv, obj); else fprintf(stderr, "report_notgranted_exception: failed to create an exception\n"); } /* * Create an exception object and return it. * The given class must have a constructor that has a * constructor with args (java.lang.String text, int errno); * DbException and its subclasses fit this bill. */ jobject create_exception(JNIEnv *jnienv, jstring text, int err, jclass dbexcept) { jthrowable obj; jmethodID mid; mid = (*jnienv)->GetMethodID(jnienv, dbexcept, "", "(Ljava/lang/String;I)V"); if (mid != NULL) obj = (jthrowable)(*jnienv)->NewObject(jnienv, dbexcept, mid, text, err); else { fprintf(stderr, "Cannot get exception init method ID!\n"); obj = NULL; } return (obj); } /* * Report an error via the errcall mechanism. */ void report_errcall(JNIEnv *jnienv, jobject errcall, jstring prefix, const char *message) { jmethodID id; jclass errcall_class; jstring msg; if ((errcall_class = get_class(jnienv, name_DbErrcall)) == NULL) return; /* An exception has been posted. */ msg = get_java_string(jnienv, message); id = (*jnienv)->GetMethodID(jnienv, errcall_class, "errcall", "(Ljava/lang/String;Ljava/lang/String;)V"); if (id == NULL) { fprintf(stderr, "Cannot get errcall methodID!\n"); fprintf(stderr, "error: %s\n", message); return; } (*jnienv)->CallVoidMethod(jnienv, errcall, id, prefix, msg); } /* * If the object is null, report an exception and return false (0), * otherwise return true (1). */ int verify_non_null(JNIEnv *jnienv, void *obj) { if (obj == NULL) { report_exception(jnienv, "null object", EINVAL, 0); return (0); } return (1); } /* * If the error code is non-zero, report an exception and return false (0), * otherwise return true (1). */ int verify_return(JNIEnv *jnienv, int err, unsigned long expect_mask) { if (err == 0) return (1); report_exception(jnienv, db_strerror(err), err, expect_mask); return (0); } /* * Verify that there was no memory error due to undersized Dbt. * If there is report a DbMemoryException, with the Dbt attached * and return false (0), otherwise return true (1). */ int verify_dbt(JNIEnv *jnienv, int err, LOCKED_DBT *ldbt) { DBT *dbt; jobject exception; jstring text; jclass dbexcept; jmethodID mid; if (err != ENOMEM) return (1); dbt = &ldbt->javainfo->dbt; if (!F_ISSET(dbt, DB_DBT_USERMEM) || dbt->size <= dbt->ulen) return (1); /* Create/throw an exception of type DbMemoryException */ if ((dbexcept = get_class(jnienv, name_DB_MEMORY_EX)) == NULL) return (1); /* An exception has been posted. */ text = get_java_string(jnienv, "Dbt not large enough for available data"); exception = create_exception(jnienv, text, ENOMEM, dbexcept); /* Attach the dbt to the exception */ mid = (*jnienv)->GetMethodID(jnienv, dbexcept, "set_dbt", "(L" DB_PACKAGE_NAME "Dbt;)V"); (*jnienv)->CallVoidMethod(jnienv, exception, mid, ldbt->jdbt); (*jnienv)->Throw(jnienv, exception); return (0); } /* * Create an object of the given class, calling its default constructor. */ jobject create_default_object(JNIEnv *jnienv, const char *class_name) { jmethodID id; jclass dbclass; if ((dbclass = get_class(jnienv, class_name)) == NULL) return (NULL); /* An exception has been posted. */ id = (*jnienv)->GetMethodID(jnienv, dbclass, "", "()V"); return ((*jnienv)->NewObject(jnienv, dbclass, id)); } /* * Convert an DB object to a Java encapsulation of that object. * Note: This implementation creates a new Java object on each call, * so it is generally useful when a new DB object has just been created. */ jobject convert_object(JNIEnv *jnienv, const char *class_name, void *dbobj) { jobject jo; if (!dbobj) return (0); jo = create_default_object(jnienv, class_name); set_private_dbobj(jnienv, class_name, jo, dbobj); return (jo); } /* * Create a copy of the string */ char *dup_string(const char *str) { int len; char *retval; int err; len = strlen(str) + 1; if ((err = __os_malloc(NULL, sizeof(char)*len, &retval)) != 0) return (NULL); strncpy(retval, str, len); return (retval); } /* * Create a java string from the given string */ jstring get_java_string(JNIEnv *jnienv, const char* string) { if (string == 0) return (0); return ((*jnienv)->NewStringUTF(jnienv, string)); } /* * Create a copy of the java string using __os_malloc. * Caller must free it. */ char *get_c_string(JNIEnv *jnienv, jstring jstr) { const char *utf; char *retval; utf = (*jnienv)->GetStringUTFChars(jnienv, jstr, NULL); retval = dup_string(utf); (*jnienv)->ReleaseStringUTFChars(jnienv, jstr, utf); return (retval); } /* * Convert a java object to the various C pointers they represent. */ DB *get_DB(JNIEnv *jnienv, jobject obj) { return ((DB *)get_private_dbobj(jnienv, name_DB, obj)); } DB_BTREE_STAT *get_DB_BTREE_STAT(JNIEnv *jnienv, jobject obj) { return ((DB_BTREE_STAT *) get_private_dbobj(jnienv, name_DB_BTREE_STAT, obj)); } DBC *get_DBC(JNIEnv *jnienv, jobject obj) { return ((DBC *)get_private_dbobj(jnienv, name_DBC, obj)); } DB_ENV *get_DB_ENV(JNIEnv *jnienv, jobject obj) { return ((DB_ENV *)get_private_dbobj(jnienv, name_DB_ENV, obj)); } DB_ENV_JAVAINFO *get_DB_ENV_JAVAINFO(JNIEnv *jnienv, jobject obj) { return ((DB_ENV_JAVAINFO *)get_private_info(jnienv, name_DB_ENV, obj)); } DB_HASH_STAT *get_DB_HASH_STAT(JNIEnv *jnienv, jobject obj) { return ((DB_HASH_STAT *) get_private_dbobj(jnienv, name_DB_HASH_STAT, obj)); } DB_JAVAINFO *get_DB_JAVAINFO(JNIEnv *jnienv, jobject obj) { return ((DB_JAVAINFO *)get_private_info(jnienv, name_DB, obj)); } DB_LOCK *get_DB_LOCK(JNIEnv *jnienv, jobject obj) { return ((DB_LOCK *)get_private_dbobj(jnienv, name_DB_LOCK, obj)); } DB_LOGC *get_DB_LOGC(JNIEnv *jnienv, jobject obj) { return ((DB_LOGC *)get_private_dbobj(jnienv, name_DB_LOGC, obj)); } DB_LOG_STAT *get_DB_LOG_STAT(JNIEnv *jnienv, jobject obj) { return ((DB_LOG_STAT *) get_private_dbobj(jnienv, name_DB_LOG_STAT, obj)); } DB_LSN *get_DB_LSN(JNIEnv *jnienv, /* DbLsn */ jobject obj) { /* * DbLsns that are created from within java (new DbLsn()) rather * than from within C (get_DbLsn()) may not have a "private" DB_LSN * structure allocated for them yet. We can't do this in the * actual constructor (init_lsn()), because there's no way to pass * in an initializing value in, and because the get_DbLsn()/ * convert_object() code path needs a copy of the pointer before * the constructor gets called. Thus, get_DbLsn() allocates and * fills a DB_LSN for the object it's about to create. * * Since "new DbLsn()" may reasonably be passed as an argument to * functions such as DbEnv.log_put(), though, we need to make sure * that DB_LSN's get allocated when the object was created from * Java, too. Here, we lazily allocate a new private DB_LSN if * and only if it turns out that we don't already have one. * * The only exception is if the DbLsn object is a Java null * (in which case the jobject will also be NULL). Then a NULL * DB_LSN is legitimate. */ DB_LSN *lsnp; int err; if (obj == NULL) return (NULL); lsnp = (DB_LSN *)get_private_dbobj(jnienv, name_DB_LSN, obj); if (lsnp == NULL) { if ((err = __os_malloc(NULL, sizeof(DB_LSN), &lsnp)) != 0) return (NULL); memset(lsnp, 0, sizeof(DB_LSN)); set_private_dbobj(jnienv, name_DB_LSN, obj, lsnp); } return (lsnp); } DB_MPOOL_FSTAT *get_DB_MPOOL_FSTAT(JNIEnv *jnienv, jobject obj) { return ((DB_MPOOL_FSTAT *) get_private_dbobj(jnienv, name_DB_MPOOL_FSTAT, obj)); } DB_MPOOL_STAT *get_DB_MPOOL_STAT(JNIEnv *jnienv, jobject obj) { return ((DB_MPOOL_STAT *) get_private_dbobj(jnienv, name_DB_MPOOL_STAT, obj)); } DB_QUEUE_STAT *get_DB_QUEUE_STAT(JNIEnv *jnienv, jobject obj) { return ((DB_QUEUE_STAT *) get_private_dbobj(jnienv, name_DB_QUEUE_STAT, obj)); } DB_TXN *get_DB_TXN(JNIEnv *jnienv, jobject obj) { return ((DB_TXN *)get_private_dbobj(jnienv, name_DB_TXN, obj)); } DB_TXN_STAT *get_DB_TXN_STAT(JNIEnv *jnienv, jobject obj) { return ((DB_TXN_STAT *) get_private_dbobj(jnienv, name_DB_TXN_STAT, obj)); } DBT *get_DBT(JNIEnv *jnienv, jobject obj) { DBT_JAVAINFO *ji; ji = (DBT_JAVAINFO *)get_private_dbobj(jnienv, name_DBT, obj); if (ji == NULL) return (NULL); else return (&ji->dbt); } DBT_JAVAINFO *get_DBT_JAVAINFO(JNIEnv *jnienv, jobject obj) { return ((DBT_JAVAINFO *)get_private_dbobj(jnienv, name_DBT, obj)); } /* * Convert a C pointer to the various Java objects they represent. */ jobject get_DbBtreeStat(JNIEnv *jnienv, DB_BTREE_STAT *dbobj) { return (convert_object(jnienv, name_DB_BTREE_STAT, dbobj)); } jobject get_Dbc(JNIEnv *jnienv, DBC *dbobj) { return (convert_object(jnienv, name_DBC, dbobj)); } jobject get_DbHashStat(JNIEnv *jnienv, DB_HASH_STAT *dbobj) { return (convert_object(jnienv, name_DB_HASH_STAT, dbobj)); } jobject get_DbLogc(JNIEnv *jnienv, DB_LOGC *dbobj) { return (convert_object(jnienv, name_DB_LOGC, dbobj)); } jobject get_DbLogStat(JNIEnv *jnienv, DB_LOG_STAT *dbobj) { return (convert_object(jnienv, name_DB_LOG_STAT, dbobj)); } /* * LSNs are different since they are really normally * treated as by-value objects. We actually create * a pointer to the LSN and store that, deleting it * when the LSN is GC'd. */ jobject get_DbLsn(JNIEnv *jnienv, DB_LSN dbobj) { DB_LSN *lsnp; int err; if ((err = __os_malloc(NULL, sizeof(DB_LSN), &lsnp)) != 0) return (NULL); memset(lsnp, 0, sizeof(DB_LSN)); *lsnp = dbobj; return (convert_object(jnienv, name_DB_LSN, lsnp)); } /* * Shared code for get_Dbt and get_const_Dbt. * * XXX * Currently we make no distinction in implementation of these * two kinds of Dbts, although in the future we may want to. * (It's probably easier to make the optimizations listed below * with readonly Dbts). * * Dbt's created via this function are only used for a short lifetime, * during callback functions. In the future, we should consider taking * advantage of this by having a pool of Dbt objects instead of creating * new ones each time. Because of multithreading, we may need an * arbitrary number. We might also have sharing of the byte arrays * used by the Dbts. */ static jobject get_Dbt_shared(JNIEnv *jnienv, const DBT *dbt, int readonly, DBT_JAVAINFO **ret_info) { jobject jdbt; DBT_JAVAINFO *dbtji; COMPQUIET(readonly, 0); /* A NULL DBT should become a null Dbt. */ if (dbt == NULL) return (NULL); /* * Note that a side effect of creating a Dbt object * is the creation of the attached DBT_JAVAINFO object * (see the native implementation of Dbt.init()) * A DBT_JAVAINFO object contains its own DBT. */ jdbt = create_default_object(jnienv, name_DBT); dbtji = get_DBT_JAVAINFO(jnienv, jdbt); memcpy(&dbtji->dbt, dbt, sizeof(DBT)); /* * Set the boolean indicator so that the Java side knows to * call back when it wants to look at the array. This avoids * needlessly creating/copying arrays that may never be looked at. */ (*jnienv)->SetBooleanField(jnienv, jdbt, fid_Dbt_must_create_data, 1); (*jnienv)->SetIntField(jnienv, jdbt, fid_Dbt_size, dbt->size); if (ret_info != NULL) *ret_info = dbtji; return (jdbt); } /* * Get a writeable Dbt. * * Currently we're sharing code with get_const_Dbt. * It really shouldn't be this way, we have a DBT that we can * change, and have some mechanism for copying back * any changes to the original DBT. */ jobject get_Dbt(JNIEnv *jnienv, DBT *dbt, DBT_JAVAINFO **ret_info) { return (get_Dbt_shared(jnienv, dbt, 0, ret_info)); } /* * Get a Dbt that we promise not to change, or at least * if there are changes, they don't matter and won't get * seen by anyone. */ jobject get_const_Dbt(JNIEnv *jnienv, const DBT *dbt, DBT_JAVAINFO **ret_info) { return (get_Dbt_shared(jnienv, dbt, 1, ret_info)); } jobject get_DbMpoolFStat(JNIEnv *jnienv, DB_MPOOL_FSTAT *dbobj) { return (convert_object(jnienv, name_DB_MPOOL_FSTAT, dbobj)); } jobject get_DbMpoolStat(JNIEnv *jnienv, DB_MPOOL_STAT *dbobj) { return (convert_object(jnienv, name_DB_MPOOL_STAT, dbobj)); } jobject get_DbQueueStat(JNIEnv *jnienv, DB_QUEUE_STAT *dbobj) { return (convert_object(jnienv, name_DB_QUEUE_STAT, dbobj)); } jobject get_DbTxn(JNIEnv *jnienv, DB_TXN *dbobj) { return (convert_object(jnienv, name_DB_TXN, dbobj)); } jobject get_DbTxnStat(JNIEnv *jnienv, DB_TXN_STAT *dbobj) { return (convert_object(jnienv, name_DB_TXN_STAT, dbobj)); }