diff --git a/java/Makefile b/java/Makefile new file mode 100644 index 000000000..0c952fa2f --- /dev/null +++ b/java/Makefile @@ -0,0 +1,38 @@ +# Copyright 2018-2021 VMware, Inc. +# SPDX-License-Identifier: Apache-2.0 + +.suffixes: +.PHONY: clean + +JAVA_HOME ?= $(shell readlink -e "$$(dirname "$$(readlink -e "$$(which javac)")")"/..) +JAVAC = javac + +CFLAGS += -Iinclude -I"$(JAVA_HOME)/include" -I"$(JAVA_HOME)/include/linux" \ + -fPIC +LDFLAGS += -shared -lsplinterdb -DSPLINTERDB_PLATFORM_DIR=platform_linux + +OBJS = $(patsubst src/%.c,build/%.o,$(wildcard src/*.c)) + +all: build SplinterDBJNI.h libsplinterdbjni.so splinterdb.jar run-test + +build: + mkdir -p include + mkdir -p build + +splinterdb.jar: + $(JAVAC) -d build src/SplinterDBJNI.java + jar cf build/splinterdbjni.jar -C build/ org/splinterdb/SplinterDBJNI.class + +SplinterDBJNI.h: + $(JAVAC) -h include/ src/SplinterDBJNI.java + +libsplinterdbjni.so: + gcc $(CFLAGS) -o build/libsplinterdbjni.so src/SplinterDBJNI.c $(LDFLAGS) + +run-test: + mvn test + +clean: + -rm -rf include + -rm -rf build + -mvn clean diff --git a/java/pom.xml b/java/pom.xml new file mode 100644 index 000000000..877084fb5 --- /dev/null +++ b/java/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + org.splinterdb + splinterdb + 1.0-SNAPSHOT + + + 1.8 + 1.8 + + + + + junit + junit + 4.11 + test + + + + org.junit.jupiter + junit-jupiter-engine + 5.3.1 + test + + + org.splinterdb + splinterdbjni + 1.0 + system + ${project.basedir}/build/splinterdbjni.jar + + + + test + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.0 + + + java.library.path + build + + -Djava.library.path=build + + + + + diff --git a/java/src/SplinterDBJNI.c b/java/src/SplinterDBJNI.c new file mode 100644 index 000000000..3f3ea68df --- /dev/null +++ b/java/src/SplinterDBJNI.c @@ -0,0 +1,148 @@ +#include +#include +#include +#include +#include "org_splinterdb_SplinterDBJNI.h" +#include "splinterdb/data.h" +#include "splinterdb/default_data_config.h" +#include "splinterdb/public_platform.h" +#include "splinterdb/splinterdb.h" +#include "splinterdb/public_util.h" + +#define Mega (1024UL * 1024UL) + +splinterdb *splinter; +splinterdb_config cfg; +data_config default_data_config; + + +JNIEXPORT jint JNICALL +Java_org_splinterdb_SplinterDBJNI_createOrOpen + (JNIEnv *env, jobject obj, jstring filename, jlong cache_size, jlong disk_size, jint max_key_size, jint max_value_size, jint open_existing) { + + + const char *dbname = (*env)->GetStringUTFChars(env, filename, NULL); + + + default_data_config_init(max_key_size, &default_data_config); + + + cfg = + (splinterdb_config) { + .filename = dbname, + .cache_size = cache_size * Mega, + .disk_size = disk_size * Mega, + .data_cfg = &default_data_config, + }; + + int rc; + + if (open_existing) { + rc = splinterdb_open(&cfg, &splinter); + } else { + rc = splinterdb_create(&cfg, &splinter); + } + + assert(splinter != NULL); + + return rc; +} + +JNIEXPORT jint JNICALL +Java_org_splinterdb_SplinterDBJNI_insert + (JNIEnv *env, jobject obj, jint id, jbyteArray key, jbyteArray value) { + + + jboolean isCopy; + + char * key_array = (char*)((*env)->GetByteArrayElements(env, key, &isCopy)); + slice slice_key = slice_create((*env)->GetArrayLength( env, key ), key_array); + + + char * value_array = (char*)((*env)->GetByteArrayElements(env, value, &isCopy)); + slice slice_value = slice_create((*env)->GetArrayLength( env, value ), value_array); + + int rc = splinterdb_insert(splinter, slice_key, slice_value); + + return rc; + +} + +JNIEXPORT jbyteArray JNICALL +Java_org_splinterdb_SplinterDBJNI_lookup + (JNIEnv *env, jobject obj, jint id, jbyteArray key) { + + jboolean isCopy; + + char * key_array = (char*)((*env)->GetByteArrayElements(env, key, &isCopy)); + slice slice_key = slice_create((*env)->GetArrayLength( env, key ), key_array); + + + splinterdb_lookup_result result; + + splinterdb_lookup_result_init(splinter, &result, 0, NULL); + + splinterdb_lookup(splinter, slice_key, &result); + + slice value; + + splinterdb_lookup_result_value(splinter, &result, &value); + + char *value_chr = (char *)slice_data(value); + + + int length = sizeof(slice_data(value)); + + + jbyteArray value_array = (*env)->NewByteArray(env, length); + (*env)->SetByteArrayRegion(env, value_array, 0, length, (char *)slice_data(value)); + + splinterdb_lookup_result_deinit(&result); + + return value_array; +} + +JNIEXPORT jint +Java_org_splinterdb_SplinterDBJNI_delete + (JNIEnv *env, jobject obj, jint id, jbyteArray key) { + + jboolean isCopy; + + char * key_array = (char*)((*env)->GetByteArrayElements(env, key, &isCopy)); + slice slice_key = slice_create((*env)->GetArrayLength( env, key ), key_array); + + + int rc = splinterdb_delete(splinter, slice_key); + + return rc; + +} + + +JNIEXPORT jint JNICALL +Java_org_splinterdb_SplinterDBJNI_close + (JNIEnv *env, jobject obj, jint id) { + + splinterdb_close(&splinter); + + return 0; + +} + +JNIEXPORT jstring JNICALL +Java_org_splinterdb_SplinterDBJNI_version + (JNIEnv *env, jobject object) +{ + const char *versionChar = splinterdb_get_version(); + + jstring version; + version = (*env)->NewStringUTF(env,versionChar); + + return version; +} + + +int main (void **args) +{ + return 0; +} diff --git a/java/src/SplinterDBJNI.java b/java/src/SplinterDBJNI.java new file mode 100644 index 000000000..aa1fe393e --- /dev/null +++ b/java/src/SplinterDBJNI.java @@ -0,0 +1,62 @@ +package org.splinterdb; + +import java.util.concurrent.TimeUnit; + +public class SplinterDBJNI { + + + static { + System.loadLibrary("splinterdbjni"); + } + + + public native synchronized int createOrOpen(String filename, long cacheSize, long diskSize, + int maxKeySize, int valueSize, int open_existing); + + public native synchronized int insert(int dbid, byte[] key, byte[] value); + + public native synchronized byte[] lookup(int dbid, byte[] key); + + public native synchronized int delete(int dbid, byte[] key); + + public native synchronized int close(int dbid); + + public native synchronized String version(); + + public void myString() { + System.out.println("hello"); + } + + public static void main (String args[]) + { + try { + + SplinterDBJNI splinter = new SplinterDBJNI(); + + System.out.println(splinter.version()); + + int id = splinter.createOrOpen("mydb", 64, 1024, 100, 5, 0); + + String keyStr = "key1"; + byte[] keyBytes = keyStr.getBytes(); + + String valueStr = "value1"; + byte[] valueBytes = valueStr.getBytes(); + + splinter.insert(id, keyBytes, valueBytes); + + byte[] value = splinter.lookup(id, keyBytes); + + String outputValueStr = new String(value); + + System.out.println("My value is:" + outputValueStr); + + splinter.delete(id, keyBytes); + + splinter.close(id); + + } catch (Exception ex) { + System.out.println(ex.toString()); + } + } +} diff --git a/java/test/org/splinterdb/JavaJNITest.java b/java/test/org/splinterdb/JavaJNITest.java new file mode 100644 index 000000000..049680e35 --- /dev/null +++ b/java/test/org/splinterdb/JavaJNITest.java @@ -0,0 +1,45 @@ +package org.splinterdb; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.splinterdb.SplinterDBJNI; + +public class JavaJNITest { + + @Test + public void testSplinterDB() { + try { + + SplinterDBJNI splinter = new SplinterDBJNI(); + + System.out.println(splinter.version()); + + int id = splinter.createOrOpen("mydb", 64, 1024, 100, 5, 0); + + String keyStr = "key1"; + byte[] keyBytes = keyStr.getBytes(); + + String valueStr = "value1"; + byte[] valueBytes = valueStr.getBytes(); + + splinter.insert(id, keyBytes, valueBytes); + + byte[] value = splinter.lookup(id, keyBytes); + + String outputValueStr = new String(value); + + System.out.println("My value is:" + outputValueStr); + + splinter.delete(id, keyBytes); + + splinter.close(id); + + } catch (Exception ex) { + System.out.println(ex.toString()); + + assertTrue(false); + } + assertTrue(true); + + } +}