mirror of
https://github.com/MariaDB/server.git
synced 2025-01-18 04:53:01 +01:00
1001 lines
26 KiB
C
1001 lines
26 KiB
C
/*-
|
|
* See the file LICENSE for redistribution information.
|
|
*
|
|
* Copyright (c) 1997, 1998, 1999, 2000
|
|
* Sleepycat Software. All rights reserved.
|
|
*/
|
|
#include "db_config.h"
|
|
|
|
#ifndef lint
|
|
static const char revid[] = "$Id: java_info.c,v 11.18 2000/10/28 13:09:39 dda 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"
|
|
|
|
/****************************************************************
|
|
*
|
|
* Callback functions
|
|
*
|
|
*/
|
|
|
|
static void Db_feedback_callback(DB *db, int opcode, int percent)
|
|
{
|
|
DB_JAVAINFO *dbinfo;
|
|
|
|
DB_ASSERT(db != NULL);
|
|
dbinfo = (DB_JAVAINFO *)db->cj_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->cj_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->cj_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->cj_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->cj_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->cj_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->cj_internal;
|
|
dbjie_call_feedback(dbinfo, dbenv, dbinfo->jenvref_, opcode, percent);
|
|
}
|
|
|
|
static int DbEnv_recovery_init_callback(DB_ENV *dbenv)
|
|
{
|
|
DB_ENV_JAVAINFO *dbinfo;
|
|
|
|
dbinfo = (DB_ENV_JAVAINFO *)dbenv->cj_internal;
|
|
return (dbjie_call_recovery_init(dbinfo, dbenv, dbinfo->jenvref_));
|
|
}
|
|
|
|
static int DbEnv_tx_recover_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->cj_internal;
|
|
return dbjie_call_tx_recover(dbinfo, dbenv, dbinfo->jenvref_, dbt,
|
|
lsn, recops);
|
|
}
|
|
|
|
/****************************************************************
|
|
*
|
|
* Implementation of class DBT_javainfo
|
|
*
|
|
*/
|
|
DBT_JAVAINFO *
|
|
dbjit_construct()
|
|
{
|
|
DBT_JAVAINFO *dbjit;
|
|
|
|
dbjit = (DBT_JAVAINFO *)malloc(sizeof(DBT_JAVAINFO));
|
|
memset(dbjit, 0, sizeof(DBT_JAVAINFO));
|
|
return (dbjit);
|
|
}
|
|
|
|
void dbjit_destroy(DBT_JAVAINFO *dbjit)
|
|
{
|
|
/* Sanity check:
|
|
* We cannot delete the global ref because we don't have a JNIEnv.
|
|
*/
|
|
if (dbjit->array_ != NULL) {
|
|
fprintf(stderr, "object is not freed\n");
|
|
}
|
|
|
|
/* Extra paranoia */
|
|
memset(dbjit, 0, sizeof(DB_JAVAINFO));
|
|
free(dbjit);
|
|
}
|
|
|
|
void dbjit_release(DBT_JAVAINFO *dbjit, JNIEnv *jnienv)
|
|
{
|
|
if (dbjit->array_ != NULL) {
|
|
DELETE_GLOBAL_REF(jnienv, dbjit->array_);
|
|
dbjit->array_ = NULL;
|
|
}
|
|
}
|
|
|
|
/****************************************************************
|
|
*
|
|
* Implementation of class DB_ENV_JAVAINFO
|
|
*
|
|
*/
|
|
|
|
/* create/initialize an object */
|
|
DB_ENV_JAVAINFO *
|
|
dbjie_construct(JNIEnv *jnienv,
|
|
jobject default_errcall,
|
|
int is_dbopen)
|
|
{
|
|
DB_ENV_JAVAINFO *dbjie;
|
|
|
|
dbjie = (DB_ENV_JAVAINFO *)malloc(sizeof(DB_ENV_JAVAINFO));
|
|
memset(dbjie, 0, sizeof(DB_ENV_JAVAINFO));
|
|
dbjie->is_dbopen_ = is_dbopen;
|
|
|
|
if ((*jnienv)->GetJavaVM(jnienv, &dbjie->javavm_) != 0) {
|
|
free(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);
|
|
return (dbjie);
|
|
}
|
|
|
|
/* release all objects held by this this one */
|
|
void dbjie_dealloc(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv)
|
|
{
|
|
if (dbjie->recovery_init_ != NULL) {
|
|
DELETE_GLOBAL_REF(jnienv, dbjie->recovery_init_);
|
|
dbjie->recovery_init_ = NULL;
|
|
}
|
|
if (dbjie->feedback_ != NULL) {
|
|
DELETE_GLOBAL_REF(jnienv, dbjie->feedback_);
|
|
dbjie->feedback_ = NULL;
|
|
}
|
|
if (dbjie->tx_recover_ != NULL) {
|
|
DELETE_GLOBAL_REF(jnienv, dbjie->tx_recover_);
|
|
dbjie->tx_recover_ = 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->conflict_ != NULL) {
|
|
free(dbjie->conflict_);
|
|
dbjie->conflict_ = NULL;
|
|
}
|
|
if (dbjie->errpfx_ != NULL) {
|
|
free(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));
|
|
free(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)
|
|
free(dbjie->errpfx_);
|
|
|
|
if (errpfx)
|
|
dbjie->errpfx_ = get_c_string(jnienv, errpfx);
|
|
else
|
|
dbjie->errpfx_ = NULL;
|
|
}
|
|
|
|
void
|
|
dbjie_set_conflict(DB_ENV_JAVAINFO *dbjie, unsigned char *newarr)
|
|
{
|
|
if (dbjie->conflict_)
|
|
free(dbjie->conflict_);
|
|
dbjie->conflict_ = newarr;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
feedback_class = get_class(jnienv, name_DbEnvFeedback);
|
|
id = (*jnienv)->GetMethodID(jnienv, feedback_class,
|
|
"feedback",
|
|
"(Lcom/sleepycat/db/DbEnv;II)V");
|
|
if (!id) {
|
|
fprintf(stderr, "Cannot find callback class\n");
|
|
return;
|
|
}
|
|
|
|
(*jnienv)->CallVoidMethod(jnienv, dbjie->feedback_, id,
|
|
jenv, (jint)opcode, (jint)percent);
|
|
}
|
|
|
|
void dbjie_set_recovery_init_object(DB_ENV_JAVAINFO *dbjie,
|
|
JNIEnv *jnienv, DB_ENV *dbenv,
|
|
jobject jrecovery_init)
|
|
{
|
|
int err;
|
|
|
|
if (dbjie->recovery_init_ != NULL) {
|
|
DELETE_GLOBAL_REF(jnienv, dbjie->recovery_init_);
|
|
}
|
|
if (jrecovery_init == NULL) {
|
|
if ((err = dbenv->set_recovery_init(dbenv, NULL)) != 0)
|
|
report_exception(jnienv, "set_recovery_init failed",
|
|
err, 0);
|
|
}
|
|
else {
|
|
if ((err = dbenv->set_recovery_init(dbenv,
|
|
DbEnv_recovery_init_callback)) != 0)
|
|
report_exception(jnienv, "set_recovery_init failed",
|
|
err, 0);
|
|
}
|
|
|
|
dbjie->recovery_init_ = NEW_GLOBAL_REF(jnienv, jrecovery_init);
|
|
}
|
|
|
|
int dbjie_call_recovery_init(DB_ENV_JAVAINFO *dbjie, DB_ENV *dbenv,
|
|
jobject jenv)
|
|
{
|
|
JNIEnv *jnienv;
|
|
jclass recovery_init_class;
|
|
jmethodID id;
|
|
|
|
COMPQUIET(dbenv, NULL);
|
|
jnienv = dbjie_get_jnienv(dbjie);
|
|
if (jnienv == NULL) {
|
|
fprintf(stderr, "Cannot attach to current thread!\n");
|
|
return (EINVAL);
|
|
}
|
|
|
|
recovery_init_class = get_class(jnienv, name_DbRecoveryInit);
|
|
id = (*jnienv)->GetMethodID(jnienv, recovery_init_class,
|
|
"recovery_init",
|
|
"(Lcom/sleepycat/db/DbEnv;)V");
|
|
if (!id) {
|
|
fprintf(stderr, "Cannot find callback class\n");
|
|
return (EINVAL);
|
|
}
|
|
return (*jnienv)->CallIntMethod(jnienv, dbjie->recovery_init_,
|
|
id, jenv);
|
|
}
|
|
|
|
void dbjie_set_tx_recover_object(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv,
|
|
DB_ENV *dbenv, jobject jtx_recover)
|
|
{
|
|
int err;
|
|
|
|
if (dbjie->tx_recover_ != NULL) {
|
|
DELETE_GLOBAL_REF(jnienv, dbjie->tx_recover_);
|
|
}
|
|
if (jtx_recover == NULL) {
|
|
if ((err = dbenv->set_tx_recover(dbenv, NULL)) != 0)
|
|
report_exception(jnienv, "set_tx_recover failed",
|
|
err, 0);
|
|
}
|
|
else {
|
|
if ((err = dbenv->set_tx_recover(dbenv,
|
|
DbEnv_tx_recover_callback)) != 0)
|
|
report_exception(jnienv, "set_tx_recover failed",
|
|
err, 0);
|
|
}
|
|
|
|
dbjie->tx_recover_ = NEW_GLOBAL_REF(jnienv, jtx_recover);
|
|
}
|
|
|
|
int dbjie_call_tx_recover(DB_ENV_JAVAINFO *dbjie, DB_ENV *dbenv, jobject jenv,
|
|
DBT *dbt, DB_LSN *lsn, int recops)
|
|
{
|
|
JNIEnv *jnienv;
|
|
jclass tx_recover_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);
|
|
}
|
|
|
|
tx_recover_class = get_class(jnienv, name_DbTxnRecover);
|
|
id = (*jnienv)->GetMethodID(jnienv, tx_recover_class,
|
|
"tx_recover",
|
|
"(Lcom/sleepycat/db/DbEnv;"
|
|
"Lcom/sleepycat/db/Dbt;"
|
|
"Lcom/sleepycat/db/DbLsn;"
|
|
"I)I");
|
|
if (!id) {
|
|
fprintf(stderr, "Cannot find callback class\n");
|
|
return (0);
|
|
}
|
|
|
|
if (dbt == NULL)
|
|
jdbt = NULL;
|
|
else
|
|
jdbt = get_Dbt(jnienv, dbt);
|
|
|
|
if (lsn == NULL)
|
|
jlsn = NULL;
|
|
else
|
|
jlsn = get_DbLsn(jnienv, *lsn);
|
|
|
|
return (*jnienv)->CallIntMethod(jnienv, dbjie->tx_recover_, id, jenv,
|
|
jdbt, jlsn, recops);
|
|
}
|
|
|
|
jobject dbjie_get_errcall(DB_ENV_JAVAINFO *dbjie)
|
|
{
|
|
return (dbjie->errcall_);
|
|
}
|
|
|
|
int dbjie_is_dbopen(DB_ENV_JAVAINFO *dbjie)
|
|
{
|
|
return (dbjie->is_dbopen_);
|
|
}
|
|
|
|
/****************************************************************
|
|
*
|
|
* Implementation of class DB_JAVAINFO
|
|
*
|
|
*/
|
|
|
|
DB_JAVAINFO *dbji_construct(JNIEnv *jnienv, jint flags)
|
|
{
|
|
DB_JAVAINFO *dbji;
|
|
|
|
dbji = (DB_JAVAINFO *)malloc(sizeof(DB_JAVAINFO));
|
|
memset(dbji, 0, sizeof(DB_JAVAINFO));
|
|
|
|
if ((*jnienv)->GetJavaVM(jnienv, &dbji->javavm_) != 0) {
|
|
report_exception(jnienv, "cannot get Java VM", 0, 0);
|
|
free(dbji);
|
|
return (NULL);
|
|
}
|
|
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->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;
|
|
}
|
|
}
|
|
|
|
void
|
|
dbji_destroy(DB_JAVAINFO *dbji, JNIEnv *jnienv)
|
|
{
|
|
dbji_dealloc(dbji, jnienv);
|
|
free(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) {
|
|
feedback_class = get_class(jnienv, name_DbFeedback);
|
|
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) {
|
|
append_recno_class = get_class(jnienv, name_DbAppendRecno);
|
|
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 jdbt;
|
|
DBT_JAVAINFO *dbtji;
|
|
jbyteArray arr;
|
|
unsigned int arraylen;
|
|
unsigned char *data;
|
|
|
|
COMPQUIET(db, NULL);
|
|
jnienv = dbji_get_jnienv(dbji);
|
|
if (jnienv == NULL) {
|
|
fprintf(stderr, "Cannot attach to current thread!\n");
|
|
return (0);
|
|
}
|
|
|
|
/* XXX
|
|
* We should have a pool of Dbt objects used for this purpose
|
|
* instead of creating new ones each time. Because of
|
|
* multithreading, we may need an arbitrary number (more than two).
|
|
* We might also have a byte arrays that grow as needed,
|
|
* so we don't need to allocate those either.
|
|
*
|
|
* Note, we do not set the 'create_array_' flag as on other
|
|
* callbacks as we are creating the array here.
|
|
*/
|
|
jdbt = create_default_object(jnienv, name_DBT);
|
|
dbtji = get_DBT_JAVAINFO(jnienv, jdbt);
|
|
memcpy(&dbtji->dbt, dbt, sizeof(DBT));
|
|
dbtji->dbt.data = NULL;
|
|
arr = (*jnienv)->NewByteArray(jnienv, dbt->size);
|
|
(*jnienv)->SetByteArrayRegion(jnienv, arr, 0, dbt->size,
|
|
(jbyte *)dbt->data);
|
|
dbtji->array_ = (jbyteArray)NEW_GLOBAL_REF(jnienv, arr);
|
|
|
|
DB_ASSERT(dbji->append_recno_method_id_ != NULL);
|
|
(*jnienv)->CallVoidMethod(jnienv, dbji->append_recno_,
|
|
dbji->append_recno_method_id_,
|
|
jdb, jdbt, 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);
|
|
|
|
if (dbtji->array_ == NULL) {
|
|
report_exception(jnienv, "Dbt.data is null", 0, 0);
|
|
return (EFAULT);
|
|
}
|
|
|
|
arraylen = (*jnienv)->GetArrayLength(jnienv, dbtji->array_);
|
|
if (dbtji->offset_ < 0 ) {
|
|
report_exception(jnienv, "Dbt.offset illegal", 0, 0);
|
|
return (EFAULT);
|
|
}
|
|
if (dbt->ulen + dbtji->offset_ > arraylen) {
|
|
report_exception(jnienv,
|
|
"Dbt.ulen + Dbt.offset greater than array length", 0, 0);
|
|
return (EFAULT);
|
|
}
|
|
|
|
data = (*jnienv)->GetByteArrayElements(jnienv, dbtji->array_,
|
|
(jboolean *)0);
|
|
dbt->data = data + dbtji->offset_;
|
|
return (0);
|
|
}
|
|
|
|
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) {
|
|
bt_compare_class = get_class(jnienv, name_DbBtreeCompare);
|
|
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;
|
|
DBT_JAVAINFO *dbtji1, *dbtji2;
|
|
|
|
COMPQUIET(db, NULL);
|
|
jnienv = dbji_get_jnienv(dbji);
|
|
if (jnienv == NULL) {
|
|
fprintf(stderr, "Cannot attach to current thread!\n");
|
|
return (0);
|
|
}
|
|
|
|
/* XXX
|
|
* We should have a pool of Dbt objects used for this purpose
|
|
* instead of creating new ones each time. Because of
|
|
* multithreading, we may need an arbitrary number (more than two).
|
|
* We might also have a byte arrays that grow as needed,
|
|
* so we don't need to allocate those either.
|
|
*/
|
|
jdbt1 = create_default_object(jnienv, name_DBT);
|
|
jdbt2 = create_default_object(jnienv, name_DBT);
|
|
dbtji1 = get_DBT_JAVAINFO(jnienv, jdbt1);
|
|
memcpy(&dbtji1->dbt, dbt1, sizeof(DBT));
|
|
dbtji1->create_array_ = 1;
|
|
dbtji2 = get_DBT_JAVAINFO(jnienv, jdbt2);
|
|
memcpy(&dbtji2->dbt, dbt2, sizeof(DBT));
|
|
dbtji2->create_array_ = 1;
|
|
|
|
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) {
|
|
bt_prefix_class = get_class(jnienv, name_DbBtreePrefix);
|
|
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;
|
|
DBT_JAVAINFO *dbtji1, *dbtji2;
|
|
|
|
COMPQUIET(db, NULL);
|
|
jnienv = dbji_get_jnienv(dbji);
|
|
if (jnienv == NULL) {
|
|
fprintf(stderr, "Cannot attach to current thread!\n");
|
|
return (0);
|
|
}
|
|
|
|
/* XXX
|
|
* We should have a pool of Dbt objects used for this purpose
|
|
* instead of creating new ones each time. Because of
|
|
* multithreading, we may need an arbitrary number (more than two).
|
|
* We might also have a byte arrays that grow as needed,
|
|
* so we don't need to allocate those either.
|
|
*/
|
|
jdbt1 = create_default_object(jnienv, name_DBT);
|
|
jdbt2 = create_default_object(jnienv, name_DBT);
|
|
dbtji1 = get_DBT_JAVAINFO(jnienv, jdbt1);
|
|
memcpy(&dbtji1->dbt, dbt1, sizeof(DBT));
|
|
dbtji1->create_array_ = 1;
|
|
dbtji2 = get_DBT_JAVAINFO(jnienv, jdbt2);
|
|
memcpy(&dbtji2->dbt, dbt2, sizeof(DBT));
|
|
dbtji2->create_array_ = 1;
|
|
|
|
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) {
|
|
dup_compare_class = get_class(jnienv, name_DbDupCompare);
|
|
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;
|
|
DBT_JAVAINFO *dbtji1, *dbtji2;
|
|
|
|
COMPQUIET(db, NULL);
|
|
jnienv = dbji_get_jnienv(dbji);
|
|
if (jnienv == NULL) {
|
|
fprintf(stderr, "Cannot attach to current thread!\n");
|
|
return (0);
|
|
}
|
|
|
|
/* XXX
|
|
* We should have a pool of Dbt objects used for this purpose
|
|
* instead of creating new ones each time. Because of
|
|
* multithreading, we may need an arbitrary number (more than two).
|
|
* We might also have a byte arrays that grow as needed,
|
|
* so we don't need to allocate those either.
|
|
*/
|
|
jdbt1 = create_default_object(jnienv, name_DBT);
|
|
jdbt2 = create_default_object(jnienv, name_DBT);
|
|
dbtji1 = get_DBT_JAVAINFO(jnienv, jdbt1);
|
|
memcpy(&dbtji1->dbt, dbt1, sizeof(DBT));
|
|
dbtji1->create_array_ = 1;
|
|
dbtji2 = get_DBT_JAVAINFO(jnienv, jdbt2);
|
|
memcpy(&dbtji2->dbt, dbt2, sizeof(DBT));
|
|
dbtji2->create_array_ = 1;
|
|
|
|
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) {
|
|
h_hash_class = get_class(jnienv, name_DbHash);
|
|
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 jarray;
|
|
|
|
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);
|
|
|
|
jarray = (*jnienv)->NewByteArray(jnienv, len);
|
|
(*jnienv)->SetByteArrayRegion(jnienv, jarray, 0, len, (void *)data);
|
|
return (*jnienv)->CallIntMethod(jnienv, dbji->h_hash_,
|
|
dbji->h_hash_method_id_,
|
|
jdb, jarray, len);
|
|
}
|