summaryrefslogtreecommitdiff
path: root/bdb/libdb_java/java_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'bdb/libdb_java/java_util.c')
-rw-r--r--bdb/libdb_java/java_util.c584
1 files changed, 459 insertions, 125 deletions
diff --git a/bdb/libdb_java/java_util.c b/bdb/libdb_java/java_util.c
index f42ceafbee8..5a538ee0785 100644
--- a/bdb/libdb_java/java_util.c
+++ b/bdb/libdb_java/java_util.c
@@ -1,21 +1,19 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 1997, 1998, 1999, 2000
+ * Copyright (c) 1997-2002
* Sleepycat Software. All rights reserved.
*/
#include "db_config.h"
#ifndef lint
-static const char revid[] = "$Id: java_util.c,v 11.17 2000/10/28 13:09:39 dda Exp $";
+static const char revid[] = "$Id: java_util.c,v 11.49 2002/09/13 03:09:30 mjc Exp $";
#endif /* not lint */
#include <jni.h>
#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include "db.h"
+#include "db_int.h"
#include "java_util.h"
#ifdef DB_WIN32
@@ -32,17 +30,22 @@ 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";
@@ -50,24 +53,84 @@ 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.
- *
*/
-/* Get the private data from a Db* object that points back to a C DB_* object.
+/*
+ * 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)
+ jobject obj)
{
jclass dbClass;
jfieldID id;
@@ -76,18 +139,20 @@ void *get_private_dbobj(JNIEnv *jnienv, const char *classname,
if (!obj)
return (0);
- dbClass = get_class(jnienv, classname);
+ 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.
+/*
+ * 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)
+ jobject obj, void *value)
{
long_to_ptr lp;
jclass dbClass;
@@ -95,12 +160,14 @@ void set_private_dbobj(JNIEnv *jnienv, const char *classname,
lp.java_long = 0; /* no junk in case sizes mismatch */
lp.ptr = value;
- dbClass = get_class(jnienv, classname);
+ 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'.
+/*
+ * 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.
*/
@@ -112,15 +179,17 @@ void *get_private_info(JNIEnv *jnienv, const char *classname,
long_to_ptr lp;
if (!obj)
- return (0);
+ return (NULL);
- dbClass = get_class(jnienv, classname);
+ 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'.
+/*
+ * 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.
*/
@@ -133,7 +202,8 @@ void set_private_info(JNIEnv *jnienv, const char *classname,
lp.java_long = 0; /* no junk in case sizes mismatch */
lp.ptr = value;
- dbClass = get_class(jnienv, classname);
+ 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);
}
@@ -144,19 +214,48 @@ void set_private_info(JNIEnv *jnienv, const char *classname,
*/
jclass get_class(JNIEnv *jnienv, const char *classname)
{
- /* Note: PERFORMANCE: It should be possible to cache jclass's.
+ /*
+ * 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] = DB_PACKAGE_NAME;
- strncat(fullname, classname, sizeof(fullname));
+ char fullname[128];
+
+ (void)snprintf(fullname, sizeof(fullname),
+ "%s%s", DB_PACKAGE_NAME, classname);
return ((*jnienv)->FindClass(jnienv, fullname));
}
-/* Set an individual field in a Db* object.
+/*
+ * 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,
@@ -166,36 +265,39 @@ void set_object_field(JNIEnv *jnienv, jclass class_of_this,
char signature[512];
jfieldID id;
- strncpy(signature, "L", sizeof(signature));
- strncat(signature, DB_PACKAGE_NAME, sizeof(signature));
- strncat(signature, object_classname, sizeof(signature));
- strncat(signature, ";", sizeof(signature));
-
- id = (*jnienv)->GetFieldID(jnienv, class_of_this, name_of_field, signature);
+ (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.
+/*
+ * 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");
+ 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.
+/*
+ * 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");
+ 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.
+/*
+ * 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,
@@ -205,89 +307,144 @@ void set_lsn_field(JNIEnv *jnienv, jclass class_of_this,
name_of_field, get_DbLsn(jnienv, value));
}
-/* Report an exception back to the java side.
+/*
+ * Report an exception back to the java side.
*/
-void report_exception(JNIEnv *jnienv, const char *text, int err,
- unsigned long expect_mask)
+void report_exception(JNIEnv *jnienv, const char *text,
+ int err, unsigned long expect_mask)
{
jstring textString;
jclass dbexcept;
jclass javaexcept;
- jmethodID constructId;
jthrowable obj;
textString = NULL;
dbexcept = NULL;
javaexcept = NULL;
- constructId = NULL;
- obj = 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
+ /*
+ * 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 ENOMEM:
- dbexcept = get_class(jnienv, name_DB_MEMORY_EX);
- 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) {
- char errstr[1024];
-
- strncpy(errstr, "internal error: unexpected errno: ",
- sizeof(errstr));
- strncat(errstr, text, sizeof(errstr));
- textString = get_java_string(jnienv, errstr);
+ 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);
- }
- else {
- javaexcept =
- (*jnienv)->FindClass(jnienv, "java/io/FileNotFoundException");
- }
- 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;
+ break;
}
if (dbexcept != NULL) {
if (textString == NULL)
textString = get_java_string(jnienv, text);
- constructId = (*jnienv)->GetMethodID(jnienv, dbexcept,
- "<init>",
- "(Ljava/lang/String;I)V");
- obj = (jthrowable)(*jnienv)->NewObject(jnienv, dbexcept,
- constructId, textString,
- err);
- (*jnienv)->Throw(jnienv, obj);
+ if ((obj = create_exception(jnienv, textString, err, dbexcept))
+ != NULL)
+ (*jnienv)->Throw(jnienv, obj);
+ /* Otherwise, an exception has been posted. */
}
- else if (javaexcept != NULL) {
- javaexcept =
- (*jnienv)->FindClass(jnienv, "java/io/FileNotFoundException");
+ 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, "<init>",
+ "(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, "<init>",
+ "(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.
+/*
+ * Report an error via the errcall mechanism.
*/
void report_errcall(JNIEnv *jnienv, jobject errcall,
jstring prefix, const char *message)
@@ -296,7 +453,8 @@ void report_errcall(JNIEnv *jnienv, jobject errcall,
jclass errcall_class;
jstring msg;
- errcall_class = get_class(jnienv, name_DbErrcall);
+ 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,
@@ -311,7 +469,8 @@ void report_errcall(JNIEnv *jnienv, jobject errcall,
(*jnienv)->CallVoidMethod(jnienv, errcall, id, prefix, msg);
}
-/* If the object is null, report an exception and return false (0),
+/*
+ * If the object is null, report an exception and return false (0),
* otherwise return true (1).
*/
int verify_non_null(JNIEnv *jnienv, void *obj)
@@ -323,29 +482,70 @@ int verify_non_null(JNIEnv *jnienv, void *obj)
return (1);
}
-/* If the error code is non-zero, report an exception and return false (0),
+/*
+ * 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;
+ return (1);
report_exception(jnienv, db_strerror(err), err, expect_mask);
- return 0;
+ return (0);
}
-/* Create an object of the given class, calling its default constructor.
+/*
+ * 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)
{
- jclass dbclass = get_class(jnienv, class_name);
- jmethodID id = (*jnienv)->GetMethodID(jnienv, dbclass, "<init>", "()V");
- jobject object = (*jnienv)->NewObject(jnienv, dbclass, id);
- return (object);
+ jmethodID id;
+ jclass dbclass;
+
+ if ((dbclass = get_class(jnienv, class_name)) == NULL)
+ return (NULL); /* An exception has been posted. */
+ id = (*jnienv)->GetMethodID(jnienv, dbclass, "<init>", "()V");
+ return ((*jnienv)->NewObject(jnienv, dbclass, id));
}
-/* Convert an DB object to a Java encapsulation of that object.
+/*
+ * 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.
*/
@@ -361,20 +561,24 @@ jobject convert_object(JNIEnv *jnienv, const char *class_name, void *dbobj)
return (jo);
}
-/* Create a copy of the string
+/*
+ * Create a copy of the string
*/
char *dup_string(const char *str)
{
int len;
char *retval;
+ int err;
len = strlen(str) + 1;
- retval = (char *)malloc(sizeof(char)*len);
+ 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
+/*
+ * Create a java string from the given string
*/
jstring get_java_string(JNIEnv *jnienv, const char* string)
{
@@ -383,21 +587,23 @@ jstring get_java_string(JNIEnv *jnienv, const char* string)
return ((*jnienv)->NewStringUTF(jnienv, string));
}
-/* Create a malloc'ed copy of the java string.
+/*
+ * Create a copy of the java string using __os_malloc.
* Caller must free it.
*/
char *get_c_string(JNIEnv *jnienv, jstring jstr)
{
- const jbyte *utf;
+ const char *utf;
char *retval;
utf = (*jnienv)->GetStringUTFChars(jnienv, jstr, NULL);
- retval = dup_string((const char *)utf);
+ retval = dup_string(utf);
(*jnienv)->ReleaseStringUTFChars(jnienv, jstr, utf);
- return retval;
+ return (retval);
}
-/* Convert a java object to the various C pointers they represent.
+/*
+ * Convert a java object to the various C pointers they represent.
*/
DB *get_DB(JNIEnv *jnienv, jobject obj)
{
@@ -406,7 +612,8 @@ DB *get_DB(JNIEnv *jnienv, jobject 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));
+ return ((DB_BTREE_STAT *)
+ get_private_dbobj(jnienv, name_DB_BTREE_STAT, obj));
}
DBC *get_DBC(JNIEnv *jnienv, jobject obj)
@@ -426,7 +633,8 @@ DB_ENV_JAVAINFO *get_DB_ENV_JAVAINFO(JNIEnv *jnienv, jobject 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));
+ return ((DB_HASH_STAT *)
+ get_private_dbobj(jnienv, name_DB_HASH_STAT, obj));
}
DB_JAVAINFO *get_DB_JAVAINFO(JNIEnv *jnienv, jobject obj)
@@ -439,29 +647,71 @@ DB_LOCK *get_DB_LOCK(JNIEnv *jnienv, jobject obj)
return ((DB_LOCK *)get_private_dbobj(jnienv, name_DB_LOCK, obj));
}
-DB_LOG_STAT *get_DB_LOG_STAT(JNIEnv *jnienv, jobject obj)
+DB_LOGC *get_DB_LOGC(JNIEnv *jnienv, jobject obj)
{
- return ((DB_LOG_STAT *)get_private_dbobj(jnienv, name_DB_LOG_STAT, obj));
+ return ((DB_LOGC *)get_private_dbobj(jnienv, name_DB_LOGC, obj));
}
-DB_LSN *get_DB_LSN(JNIEnv *jnienv, jobject obj)
+DB_LOG_STAT *get_DB_LOG_STAT(JNIEnv *jnienv, jobject obj)
{
- return ((DB_LSN *)get_private_dbobj(jnienv, name_DB_LSN, 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));
+ 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));
+ 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));
+ return ((DB_QUEUE_STAT *)
+ get_private_dbobj(jnienv, name_DB_QUEUE_STAT, obj));
}
DB_TXN *get_DB_TXN(JNIEnv *jnienv, jobject obj)
@@ -471,7 +721,8 @@ DB_TXN *get_DB_TXN(JNIEnv *jnienv, jobject 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));
+ return ((DB_TXN_STAT *)
+ get_private_dbobj(jnienv, name_DB_TXN_STAT, obj));
}
DBT *get_DBT(JNIEnv *jnienv, jobject obj)
@@ -490,7 +741,8 @@ 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.
+/*
+ * Convert a C pointer to the various Java objects they represent.
*/
jobject get_DbBtreeStat(JNIEnv *jnienv, DB_BTREE_STAT *dbobj)
{
@@ -507,27 +759,109 @@ 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
+/*
+ * 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 = (DB_LSN *)malloc(sizeof(DB_LSN));
+ 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));
}
-jobject get_Dbt(JNIEnv *jnienv, DBT *dbt)
+/*
+ * 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 (convert_object(jnienv, name_DBT, dbt));
+ return (get_Dbt_shared(jnienv, dbt, 1, ret_info));
}
jobject get_DbMpoolFStat(JNIEnv *jnienv, DB_MPOOL_FSTAT *dbobj)