diff --git a/NOTICE b/NOTICE index 3473ef1dfa..4cb006827f 100644 --- a/NOTICE +++ b/NOTICE @@ -34,6 +34,10 @@ Licensed under the Apache License, Version 2.0. Copyright (C) 2014 Stephen Macke (smacke@cs.stanford.edu) * DirectIoLib in pixels-common is partially derived from Jaydio. +7. RocksDB-Cloud +Licensed under the Apache License, Version 2.0. +* RocksetJni in pixels-index-rockset is partially modified from RocksDB-Cloud Jni. + According to the requirement of Apache License Version 2.0 (Apache 2.0), we include a copy of Apache 2.0 here: diff --git a/cpp/pixels-index/pixels-index-rockset/CMakeLists.txt b/cpp/pixels-index/pixels-index-rockset/CMakeLists.txt index 23f96a0dcc..9b50ca9767 100644 --- a/cpp/pixels-index/pixels-index-rockset/CMakeLists.txt +++ b/cpp/pixels-index/pixels-index-rockset/CMakeLists.txt @@ -79,16 +79,25 @@ add_dependencies(RocksDB::rocksdb rocksdb_cloud) include_directories( ${JNI_INCLUDE_DIRS} # JNI headers (jni.h, jni_md.h) ${ROCKSDB_CLOUD_INCLUDE_DIR} # RocksDB-Cloud headers - ${CMAKE_SOURCE_DIR}/include + ${CMAKE_SOURCE_DIR}/include/jni ) -# 8. Build pixels-index-rockset shared library -set(SOURCES - lib/RocksetJni.cpp +# 8. Collect all JNI cpp files +file(GLOB ROCKSET_JNI_SOURCES + ${CMAKE_SOURCE_DIR}/lib/jni/*.cpp ) -add_library(pixels-index-rockset SHARED ${SOURCES}) -# 9. Link RocksDB and its dependencies +message(STATUS "Rockset JNI sources: ${ROCKSET_JNI_SOURCES}") + + +# 9. Build pixels-index-rockset shared library +add_library(pixels-index-rockset SHARED + ${ROCKSET_JNI_SOURCES} +) + +add_dependencies(pixels-index-rockset rocksdb_cloud) + +# 10. ink RocksDB and its dependencies target_link_libraries(pixels-index-rockset RocksDB::rocksdb z @@ -97,6 +106,6 @@ target_link_libraries(pixels-index-rockset dl ) -# 10. install pixels-index-rockset to ${PIXELS_HOME}/lib +# 11. Install pixels-index-rockset to ${PIXELS_HOME}/lib install(TARGETS pixels-index-rockset LIBRARY DESTINATION ${PIXELS_HOME}/lib) \ No newline at end of file diff --git a/cpp/pixels-index/pixels-index-rockset/include/RocksetJni.h b/cpp/pixels-index/pixels-index-rockset/include/RocksetJni.h deleted file mode 100644 index 82cfd6db98..0000000000 --- a/cpp/pixels-index/pixels-index-rockset/include/RocksetJni.h +++ /dev/null @@ -1,165 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class io_pixelsdb_pixels_index_rockset_RocksetIndexStub */ - -#ifndef _Included_io_pixelsdb_pixels_index_rockset_RocksetIndexStub -#define _Included_io_pixelsdb_pixels_index_rockset_RocksetIndexStub -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: CreateCloudFileSystem0 - * Signature: (Ljava/lang/String;Ljava/lang/String;)J - */ -JNIEXPORT jlong JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_CreateCloudFileSystem0 - (JNIEnv *, jobject, jstring, jstring); - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: OpenDBCloud0 - * Signature: (JLjava/lang/String;Ljava/lang/String;JZ)J - */ -JNIEXPORT jlong JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_OpenDBCloud0 - (JNIEnv *, jobject, jlong, jstring, jstring, jlong, jboolean); - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: DBput0 - * Signature: (J[B[B)V - */ -JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_DBput0 - (JNIEnv *, jobject, jlong, jbyteArray, jbyteArray); - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: DBget0 - * Signature: (J[B)[B - */ -JNIEXPORT jbyteArray JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_DBget0 - (JNIEnv *, jobject, jlong, jbyteArray); - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: DBdelete0 - * Signature: (J[B)V - */ -JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_DBdelete0 - (JNIEnv *, jobject, jlong, jbyteArray); - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: CloseDB0 - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_CloseDB0 - (JNIEnv *, jobject, jlong); - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: DBNewIterator0 - * Signature: (J)J - */ -JNIEXPORT jlong JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_DBNewIterator0 - (JNIEnv *, jobject, jlong); - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: IteratorSeekForPrev0 - * Signature: (J[B)V - */ -JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_IteratorSeekForPrev0 - (JNIEnv *, jobject, jlong, jbyteArray); - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: IteratorIsValid0 - * Signature: (J)Z - */ -JNIEXPORT jboolean JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_IteratorIsValid0 - (JNIEnv *, jobject, jlong); - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: IteratorKey0 - * Signature: (J)[B - */ -JNIEXPORT jbyteArray JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_IteratorKey0 - (JNIEnv *, jobject, jlong); - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: IteratorValue0 - * Signature: (J)[B - */ -JNIEXPORT jbyteArray JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_IteratorValue0 - (JNIEnv *, jobject, jlong); - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: IteratorPrev0 - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_IteratorPrev0 - (JNIEnv *, jobject, jlong); - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: IteratorClose0 - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_IteratorClose0 - (JNIEnv *, jobject, jlong); - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: WriteBatchCreate0 - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_WriteBatchCreate0 - (JNIEnv *, jobject); - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: WriteBatchPut0 - * Signature: (J[B[B)V - */ -JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_WriteBatchPut0 - (JNIEnv *, jobject, jlong, jbyteArray, jbyteArray); - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: WriteBatchDelete0 - * Signature: (J[B)V - */ -JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_WriteBatchDelete0 - (JNIEnv *, jobject, jlong, jbyteArray); - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: DBWrite0 - * Signature: (JJ)Z - */ -JNIEXPORT jboolean JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_DBWrite0 - (JNIEnv *, jobject, jlong, jlong); - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: WriteBatchClear0 - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_WriteBatchClear0 - (JNIEnv *, jobject, jlong); - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: WriteBatchDestroy0 - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_WriteBatchDestroy0 - (JNIEnv *, jobject, jlong); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/cpp/pixels-index/pixels-index-rockset/include/jni/cplusplus_to_java_convert.h b/cpp/pixels-index/pixels-index-rockset/include/jni/cplusplus_to_java_convert.h new file mode 100644 index 0000000000..c14a611bfe --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/include/jni/cplusplus_to_java_convert.h @@ -0,0 +1,32 @@ +#pragma once + +/* + * This macro is used for 32 bit OS. In 32 bit OS, the result number is a + negative number if we use reinterpret_cast(pointer). + * For example, jlong ptr = reinterpret_cast(pointer), ptr is a negative + number in 32 bit OS. + * If we check ptr using ptr > 0, it fails. For example, the following code is + not correct. + * if (jblock_cache_handle > 0) { + std::shared_ptr *pCache = + reinterpret_cast *>( + jblock_cache_handle); + options.block_cache = *pCache; + } + * But the result number is positive number if we do + reinterpret_cast(pointer) first and then cast it to jlong. size_t is 4 + bytes long in 32 bit OS and 8 bytes long in 64 bit OS. + static_cast(reinterpret_cast(_pointer)) is also working in 64 + bit OS. + * + * We don't need an opposite cast because it works from jlong to c++ pointer in + both 32 bit and 64 bit OS. + * For example, the following code is working in both 32 bit and 64 bit OS. + jblock_cache_handle is jlong. + * std::shared_ptr *pCache = + reinterpret_cast *>( + jblock_cache_handle); +*/ + +#define GET_CPLUSPLUS_POINTER(_pointer) \ + static_cast(reinterpret_cast(_pointer)) diff --git a/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_Filter.h b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_Filter.h new file mode 100644 index 0000000000..2c279d45c0 --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_Filter.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class io_pixelsdb_pixels_index_rockset_jni_Filter */ + +#ifndef _Included_io_pixelsdb_pixels_index_rockset_jni_Filter +#define _Included_io_pixelsdb_pixels_index_rockset_jni_Filter +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_Filter + * Method: disposeInternalJni + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_Filter_disposeInternalJni + (JNIEnv *, jclass, jlong); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetBlockBasedTableConfig.h b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetBlockBasedTableConfig.h new file mode 100644 index 0000000000..0f76bd3310 --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetBlockBasedTableConfig.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class io_pixelsdb_pixels_index_rockset_jni_RocksetBlockBasedTableConfig */ + +#ifndef _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetBlockBasedTableConfig +#define _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetBlockBasedTableConfig +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetBlockBasedTableConfig + * Method: newTableFactoryHandle + * Signature: (JJJZ)J + */ +JNIEXPORT jlong JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetBlockBasedTableConfig_newTableFactoryHandle + (JNIEnv *, jclass, jlong, jlong, jlong, jboolean); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetBloomFilter.h b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetBloomFilter.h new file mode 100644 index 0000000000..9028b36fe1 --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetBloomFilter.h @@ -0,0 +1,23 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class io_pixelsdb_pixels_index_rockset_jni_RocksetBloomFilter */ + +#ifndef _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetBloomFilter +#define _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetBloomFilter +#ifdef __cplusplus +extern "C" { +#endif +#undef io_pixelsdb_pixels_index_rockset_jni_RocksetBloomFilter_DEFAULT_BITS_PER_KEY +#define io_pixelsdb_pixels_index_rockset_jni_RocksetBloomFilter_DEFAULT_BITS_PER_KEY 10.0 +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetBloomFilter + * Method: createNewBloomFilter + * Signature: (D)J + */ +JNIEXPORT jlong JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetBloomFilter_createNewBloomFilter + (JNIEnv *, jclass, jdouble); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyHandle.h b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyHandle.h new file mode 100644 index 0000000000..9aaa00b2b0 --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyHandle.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyHandle */ + +#ifndef _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyHandle +#define _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyHandle +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyHandle + * Method: disposeInternalJni + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyHandle_disposeInternalJni + (JNIEnv *, jclass, jlong); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions.h b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions.h new file mode 100644 index 0000000000..84ae928f5f --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions.h @@ -0,0 +1,133 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions */ + +#ifndef _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions +#define _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions + * Method: newColumnFamilyOptions + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_newColumnFamilyOptions + (JNIEnv *, jclass); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions + * Method: nativeSetWriteBufferSize + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetWriteBufferSize + (JNIEnv *, jclass, jlong, jlong); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions + * Method: nativeSetMaxWriteBufferNumber + * Signature: (JI)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetMaxWriteBufferNumber + (JNIEnv *, jclass, jlong, jint); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions + * Method: nativeSetMinWriteBufferNumberToMerge + * Signature: (JI)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetMinWriteBufferNumberToMerge + (JNIEnv *, jclass, jlong, jint); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions + * Method: nativeSetMemtablePrefixBloomSizeRatio + * Signature: (JD)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetMemtablePrefixBloomSizeRatio + (JNIEnv *, jclass, jlong, jdouble); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions + * Method: nativeSetTableFactory + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetTableFactory + (JNIEnv *, jclass, jlong, jlong); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions + * Method: nativeSetLevel0FileNumCompactionTrigger + * Signature: (JI)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetLevel0FileNumCompactionTrigger + (JNIEnv *, jclass, jlong, jint); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions + * Method: nativeSetMaxBytesForLevelBase + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetMaxBytesForLevelBase + (JNIEnv *, jclass, jlong, jlong); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions + * Method: nativeSetMaxBytesForLevelMultiplier + * Signature: (JD)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetMaxBytesForLevelMultiplier + (JNIEnv *, jclass, jlong, jdouble); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions + * Method: nativeSetTargetFileSizeBase + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetTargetFileSizeBase + (JNIEnv *, jclass, jlong, jlong); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions + * Method: nativeSetTargetFileSizeMultiplier + * Signature: (JI)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetTargetFileSizeMultiplier + (JNIEnv *, jclass, jlong, jint); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions + * Method: nativeSetCompressionType + * Signature: (JB)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetCompressionType + (JNIEnv *, jclass, jlong, jbyte); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions + * Method: nativeSetBottommostCompressionType + * Signature: (JB)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetBottommostCompressionType + (JNIEnv *, jclass, jlong, jbyte); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions + * Method: nativeSetCompactionStyle + * Signature: (JB)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetCompactionStyle + (JNIEnv *, jclass, jlong, jbyte); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions + * Method: disposeInternalJni + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_disposeInternalJni + (JNIEnv *, jclass, jlong); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetDB.h b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetDB.h new file mode 100644 index 0000000000..8c8707b748 --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetDB.h @@ -0,0 +1,77 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class io_pixelsdb_pixels_index_rockset_jni_RocksetDB */ + +#ifndef _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetDB +#define _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetDB +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetDB + * Method: closeDatabase + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDB_closeDatabase + (JNIEnv *, jclass, jlong); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetDB + * Method: open + * Signature: (JJLjava/lang/String;[[B[J)[J + */ +JNIEXPORT jlongArray JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDB_open + (JNIEnv *, jclass, jlong, jlong, jstring, jobjectArray, jlongArray); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetDB + * Method: listColumnFamilies0 + * Signature: (Ljava/lang/String;)Ljava/util/List; + */ +JNIEXPORT jobject JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDB_listColumnFamilies0 + (JNIEnv *, jclass, jstring); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetDB + * Method: createColumnFamily0 + * Signature: (J[B)J + */ +JNIEXPORT jlong JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDB_createColumnFamily0 + (JNIEnv *, jobject, jlong, jbyteArray); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetDB + * Method: putDirect + * Signature: (JJLjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;IIJ)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDB_putDirect + (JNIEnv *, jclass, jlong, jlong, jobject, jint, jint, jobject, jint, jint, jlong); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetDB + * Method: put + * Signature: (JJ[BII[BIIJ)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDB_put + (JNIEnv *, jclass, jlong, jlong, jbyteArray, jint, jint, jbyteArray, jint, jint, jlong); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetDB + * Method: write0 + * Signature: (JJJ)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDB_write0 + (JNIEnv *, jclass, jlong, jlong, jlong); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetDB + * Method: iterator + * Signature: (JJJ)J + */ +JNIEXPORT jlong JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDB_iterator + (JNIEnv *, jclass, jlong, jlong, jlong); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions.h b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions.h new file mode 100644 index 0000000000..d4d6c5210a --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions.h @@ -0,0 +1,101 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions */ + +#ifndef _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions +#define _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions + * Method: newDBOptions + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions_newDBOptions + (JNIEnv *, jclass); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions + * Method: disposeInternalJni + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions_disposeInternalJni + (JNIEnv *, jclass, jlong); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions + * Method: nativeSetCreateIfMissing + * Signature: (JZ)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions_nativeSetCreateIfMissing + (JNIEnv *, jclass, jlong, jboolean); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions + * Method: nativeSetCreateMissingColumnFamilies + * Signature: (JZ)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions_nativeSetCreateMissingColumnFamilies + (JNIEnv *, jclass, jlong, jboolean); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions + * Method: nativeSetMaxBackgroundFlushes + * Signature: (JI)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions_nativeSetMaxBackgroundFlushes + (JNIEnv *, jclass, jlong, jint); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions + * Method: nativeSetMaxBackgroundCompactions + * Signature: (JI)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions_nativeSetMaxBackgroundCompactions + (JNIEnv *, jclass, jlong, jint); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions + * Method: nativeSetMaxSubcompactions + * Signature: (JI)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions_nativeSetMaxSubcompactions + (JNIEnv *, jclass, jlong, jint); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions + * Method: nativeSetMaxOpenFiles + * Signature: (JI)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions_nativeSetMaxOpenFiles + (JNIEnv *, jclass, jlong, jint); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions + * Method: nativeSetStatistics + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions_nativeSetStatistics + (JNIEnv *, jclass, jlong, jlong); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions + * Method: nativeSetStatsDumpPeriodSec + * Signature: (JI)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions_nativeSetStatsDumpPeriodSec + (JNIEnv *, jclass, jlong, jint); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions + * Method: nativeSetDbLogDir + * Signature: (JLjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions_nativeSetDbLogDir + (JNIEnv *, jclass, jlong, jstring); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetEnv.h b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetEnv.h new file mode 100644 index 0000000000..1330020622 --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetEnv.h @@ -0,0 +1,29 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class io_pixelsdb_pixels_index_rockset_jni_RocksetEnv */ + +#ifndef _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetEnv +#define _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetEnv +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetEnv + * Method: disposeInternalJni + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetEnv_disposeInternalJni + (JNIEnv *, jclass, jlong); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetEnv + * Method: createCloudFileSystem0 + * Signature: (Ljava/lang/String;Ljava/lang/String;)J + */ +JNIEXPORT jlong JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetEnv_createCloudFileSystem0 + (JNIEnv *, jclass, jstring, jstring); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetIterator.h b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetIterator.h new file mode 100644 index 0000000000..90274e675d --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetIterator.h @@ -0,0 +1,69 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class io_pixelsdb_pixels_index_rockset_jni_RocksetIterator */ + +#ifndef _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetIterator +#define _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetIterator +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetIterator + * Method: seekDirect0Jni + * Signature: (JLjava/nio/ByteBuffer;II)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetIterator_seekDirect0Jni + (JNIEnv *, jclass, jlong, jobject, jint, jint); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetIterator + * Method: seekByteArray0Jni + * Signature: (J[BII)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetIterator_seekByteArray0Jni + (JNIEnv *, jclass, jlong, jbyteArray, jint, jint); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetIterator + * Method: next0 + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetIterator_next0 + (JNIEnv *, jclass, jlong); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetIterator + * Method: isValid0 + * Signature: (J)Z + */ +JNIEXPORT jboolean JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetIterator_isValid0 + (JNIEnv *, jclass, jlong); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetIterator + * Method: key0 + * Signature: (J)[B + */ +JNIEXPORT jbyteArray JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetIterator_key0 + (JNIEnv *, jclass, jlong); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetIterator + * Method: value0 + * Signature: (J)[B + */ +JNIEXPORT jbyteArray JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetIterator_value0 + (JNIEnv *, jclass, jlong); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetIterator + * Method: disposeInternalJni + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetIterator_disposeInternalJni + (JNIEnv *, jclass, jlong); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetLRUCache.h b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetLRUCache.h new file mode 100644 index 0000000000..305ac10cf6 --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetLRUCache.h @@ -0,0 +1,29 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class io_pixelsdb_pixels_index_rockset_jni_RocksetLRUCache */ + +#ifndef _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetLRUCache +#define _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetLRUCache +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetLRUCache + * Method: newLRUCache + * Signature: (JIZDD)J + */ +JNIEXPORT jlong JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetLRUCache_newLRUCache + (JNIEnv *, jclass, jlong, jint, jboolean, jdouble, jdouble); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetLRUCache + * Method: disposeInternalJni + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetLRUCache_disposeInternalJni + (JNIEnv *, jclass, jlong); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetReadOptions.h b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetReadOptions.h new file mode 100644 index 0000000000..ea1832d9b1 --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetReadOptions.h @@ -0,0 +1,37 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class io_pixelsdb_pixels_index_rockset_jni_RocksetReadOptions */ + +#ifndef _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetReadOptions +#define _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetReadOptions +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetReadOptions + * Method: newReadOptions + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetReadOptions_newReadOptions + (JNIEnv *, jclass); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetReadOptions + * Method: disposeInternalJni + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetReadOptions_disposeInternalJni + (JNIEnv *, jclass, jlong); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetReadOptions + * Method: setPrefixSameAsStart + * Signature: (JZ)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetReadOptions_setPrefixSameAsStart + (JNIEnv *, jobject, jlong, jboolean); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetStatistics.h b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetStatistics.h new file mode 100644 index 0000000000..14ab8aefdd --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetStatistics.h @@ -0,0 +1,29 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class io_pixelsdb_pixels_index_rockset_jni_RocksetStatistics */ + +#ifndef _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetStatistics +#define _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetStatistics +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetStatistics + * Method: newStatisticsInstance + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetStatistics_newStatisticsInstance + (JNIEnv *, jclass); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetStatistics + * Method: disposeInternalJni + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetStatistics_disposeInternalJni + (JNIEnv *, jclass, jlong); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetWriteBatch.h b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetWriteBatch.h new file mode 100644 index 0000000000..a6457e6e62 --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetWriteBatch.h @@ -0,0 +1,45 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class io_pixelsdb_pixels_index_rockset_jni_RocksetWriteBatch */ + +#ifndef _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetWriteBatch +#define _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetWriteBatch +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetWriteBatch + * Method: newWriteBatch0 + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetWriteBatch_newWriteBatch0 + (JNIEnv *, jclass); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetWriteBatch + * Method: disposeInternalJni + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetWriteBatch_disposeInternalJni + (JNIEnv *, jclass, jlong); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetWriteBatch + * Method: putDirectJni + * Signature: (JLjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;IIJ)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetWriteBatch_putDirectJni + (JNIEnv *, jclass, jlong, jobject, jint, jint, jobject, jint, jint, jlong); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetWriteBatch + * Method: deleteJni + * Signature: (J[BIJ)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetWriteBatch_deleteJni + (JNIEnv *, jclass, jlong, jbyteArray, jint, jlong); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetWriteOptions.h b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetWriteOptions.h new file mode 100644 index 0000000000..0868fe25b7 --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/include/jni/io_pixelsdb_pixels_index_rockset_jni_RocksetWriteOptions.h @@ -0,0 +1,29 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class io_pixelsdb_pixels_index_rockset_jni_RocksetWriteOptions */ + +#ifndef _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetWriteOptions +#define _Included_io_pixelsdb_pixels_index_rockset_jni_RocksetWriteOptions +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetWriteOptions + * Method: newWriteOptions + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetWriteOptions_newWriteOptions + (JNIEnv *, jclass); + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetWriteOptions + * Method: disposeInternalJni + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_jni_RocksetWriteOptions_disposeInternalJni + (JNIEnv *, jclass, jlong); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/cpp/pixels-index/pixels-index-rockset/include/jni/portal.h b/cpp/pixels-index/pixels-index-rockset/include/jni/portal.h new file mode 100644 index 0000000000..34e382df3b --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/include/jni/portal.h @@ -0,0 +1,164 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rocksdb/convenience.h" +#include "rocksdb/db.h" +#include "rocksdb/filter_policy.h" +#include "rocksdb/perf_level.h" +#include "rocksdb/rate_limiter.h" +#include "rocksdb/status.h" +#include "rocksdb/table.h" +#include "rocksdb/utilities/backup_engine.h" +#include "rocksdb/utilities/memory_util.h" +#include "rocksdb/utilities/transaction_db.h" +#include "rocksdb/utilities/write_batch_with_index.h" + +namespace ROCKSDB_NAMESPACE { +class JniUtil { + public: + /** + * Detect if jlong overflows size_t + * + * @param jvalue the jlong value + * + * @return + */ + inline static Status check_if_jlong_fits_size_t(const jlong& jvalue) { + Status s = Status::OK(); + if (static_cast(jvalue) > std::numeric_limits::max()) { + s = Status::InvalidArgument(Slice("jlong overflows 32 bit value.")); + } + return s; + } + + /* + * Helper for operations on a key and value + * for example WriteBatch->Delete + * + * TODO(AR) could be extended to cover returning ROCKSDB_NAMESPACE::Status + * from `op` and used for RocksDB->Delete etc. + */ + static void k_op_direct(std::function op, + JNIEnv* env, jobject jkey, jint jkey_off, + jint jkey_len) { + char* key = reinterpret_cast(env->GetDirectBufferAddress(jkey)); + if (key == nullptr || + env->GetDirectBufferCapacity(jkey) < (jkey_off + jkey_len)) { + jclass ex = env->FindClass("java/lang/RuntimeException"); + env->ThrowNew(ex, "Invalid key argument"); + return; + } + + key += jkey_off; + + ROCKSDB_NAMESPACE::Slice key_slice(key, jkey_len); + + return op(key_slice); + } + + /* + * Helper for operations on a key which is a region of an array + * Used to extract the common code from seek/seekForPrev. + * Possible that it can be generalised from that. + * + * We use GetByteArrayRegion to copy the key region of the whole array into + * a char[] We suspect this is not much slower than GetByteArrayElements, + * which probably copies anyway. + */ + static void k_op_region(std::function op, + JNIEnv* env, jbyteArray jkey, jint jkey_off, + jint jkey_len) { + const std::unique_ptr key(new char[jkey_len]); + if (key == nullptr) { + jclass oom_class = env->FindClass("/lang/java/OutOfMemoryError"); + env->ThrowNew(oom_class, + "Memory allocation failed in RocksDB JNI function"); + return; + } + env->GetByteArrayRegion(jkey, jkey_off, jkey_len, + reinterpret_cast(key.get())); + if (env->ExceptionCheck()) { + // exception thrown: OutOfMemoryError + return; + } + + ROCKSDB_NAMESPACE::Slice key_slice(reinterpret_cast(key.get()), + jkey_len); + op(key_slice); + } + /* + * Helper for operations on a key and value + * for example WriteBatch->Put + * + * TODO(AR) could be extended to cover returning ROCKSDB_NAMESPACE::Status + * from `op` and used for RocksDB->Put etc. + */ + static void kv_op_direct( + std::function + op, + JNIEnv* env, jobject jkey, jint jkey_off, jint jkey_len, jobject jval, + jint jval_off, jint jval_len) { + char* key = reinterpret_cast(env->GetDirectBufferAddress(jkey)); + if (key == nullptr || + env->GetDirectBufferCapacity(jkey) < (jkey_off + jkey_len)) { + jclass ex = env->FindClass("java/lang/RuntimeException"); + env->ThrowNew(ex, "Invalid key argument"); + return; + } + + char* value = reinterpret_cast(env->GetDirectBufferAddress(jval)); + if (value == nullptr || + env->GetDirectBufferCapacity(jval) < (jval_off + jval_len)) { + jclass ex = env->FindClass("java/lang/RuntimeException"); + env->ThrowNew(ex, "Invalid value argument"); + return; + } + + key += jkey_off; + value += jval_off; + + ROCKSDB_NAMESPACE::Slice key_slice(key, jkey_len); + ROCKSDB_NAMESPACE::Slice value_slice(value, jval_len); + + op(key_slice, value_slice); + } + + /* + * Helper for operations on a key + * for example WriteBatch->Delete + * + * TODO(AR) could be used for RocksDB->Delete etc. + */ + static std::unique_ptr k_op( + std::function op, + JNIEnv* env, jbyteArray jkey, jint jkey_len) { + jbyte* key = env->GetByteArrayElements(jkey, nullptr); + if (env->ExceptionCheck()) { + // exception thrown: OutOfMemoryError + return nullptr; + } + + ROCKSDB_NAMESPACE::Slice key_slice(reinterpret_cast(key), jkey_len); + + auto status = op(key_slice); + + if (key != nullptr) { + env->ReleaseByteArrayElements(jkey, key, JNI_ABORT); + } + + return std::unique_ptr( + new ROCKSDB_NAMESPACE::Status(status)); + } + }; +} \ No newline at end of file diff --git a/cpp/pixels-index/pixels-index-rockset/lib/RocksetJni.cpp b/cpp/pixels-index/pixels-index-rockset/lib/RocksetJni.cpp deleted file mode 100644 index 49537bc189..0000000000 --- a/cpp/pixels-index/pixels-index-rockset/lib/RocksetJni.cpp +++ /dev/null @@ -1,523 +0,0 @@ -/* - * Copyright 2025 PixelsDB. - * - * This file is part of Pixels. - * - * Pixels is free software: you can redistribute it and/or modify - * it under the terms of the Affero GNU General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * Pixels is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Affero GNU General Public License for more details. - * - * You should have received a copy of the Affero GNU General Public - * License along with Pixels. If not, see - * . - */ -#include "RocksetJni.h" -#include "rocksdb/cloud/db_cloud.h" -#include "rocksdb/options.h" -#include "rocksdb/status.h" -#include "rocksdb/cloud/cloud_file_system.h" -#include "rocksdb/convenience.h" -#include -#include -#include - -using ROCKSDB_NAMESPACE::CloudFileSystem; -using ROCKSDB_NAMESPACE::CloudFileSystemEnv; -using ROCKSDB_NAMESPACE::CloudFileSystemOptions; -using ROCKSDB_NAMESPACE::DBCloud; -using ROCKSDB_NAMESPACE::Env; -using ROCKSDB_NAMESPACE::FileSystem; -using ROCKSDB_NAMESPACE::Options; -using ROCKSDB_NAMESPACE::ReadOptions; -using ROCKSDB_NAMESPACE::Slice; -using ROCKSDB_NAMESPACE::Iterator; -using ROCKSDB_NAMESPACE::Status; -using ROCKSDB_NAMESPACE::WriteOptions; -using ROCKSDB_NAMESPACE::FlushOptions; -using ROCKSDB_NAMESPACE::WriteBatch; - -/** - * @author hank, Rolland1944 - * @create 2025-05-01 - */ -// Helper function to convert jstring to std::string -std::string jstring_to_string(JNIEnv* env, jstring jstr) -{ - const char* cstr = env->GetStringUTFChars(jstr, nullptr); - std::string str(cstr); - env->ReleaseStringUTFChars(jstr, cstr); - return str; -} - -// Test if set the environment -bool check_env_vars(JNIEnv* env) -{ - if (!getenv("AWS_ACCESS_KEY_ID") || !getenv("AWS_SECRET_ACCESS_KEY") || !getenv("AWS_DEFAULT_REGION")) - { - env->ThrowNew(env->FindClass("java/lang/IllegalStateException"), - "Missing required environment variables: " - "AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION"); - return false; - } - return true; -} - -/* - * Class: io_pixelsdb_pixels_index_rocksdb_RocksetInde - * Method: CreateCloudFileSystem0 - * Signature: (Ljava/lang/String;Ljava/lang/String;[J)J - */ -JNIEXPORT jlong JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_CreateCloudFileSystem0( - JNIEnv* env, jobject obj, - jstring bucket_name, jstring s3_prefix) -{ - if (!check_env_vars(env)) - { - return 0; - } - - Aws::SDKOptions options; - Aws::InitAPI(options); - - // Initialize CloudFileSystem Configuration - CloudFileSystemOptions cloud_fs_options; - cloud_fs_options.credentials.InitializeSimple( - getenv("AWS_ACCESS_KEY_ID"), - getenv("AWS_SECRET_ACCESS_KEY")); - - if (!cloud_fs_options.credentials.HasValid().ok()) - { - env->ThrowNew(env->FindClass("java/lang/SecurityException"), - "Invalid AWS credentials in environment variables"); - return 0; - } - - // Set S3 Bucket and Prefix - std::string bucket = jstring_to_string(env, bucket_name); - std::string prefix = jstring_to_string(env, s3_prefix); - cloud_fs_options.src_bucket.SetBucketName(bucket); - cloud_fs_options.src_bucket.SetObjectPath(prefix); - cloud_fs_options.src_bucket.SetRegion("cn-north-1"); - - // Create Base_env - Env* base_env = Env::Default(); - - // Create CloudFileSystem - std::shared_ptr base_fs = base_env->GetFileSystem(); - CloudFileSystem* cfs; - std::cout << "Start to Create CloudFileSystem"<< std::endl; - Status s = CloudFileSystemEnv::NewAwsFileSystem(base_fs, cloud_fs_options, nullptr, &cfs); - if (!s.ok()) - { - env->ThrowNew(env->FindClass("java/io/IOException"), - "Failed to create CloudFileSystem. Check S3 permissions and bucket name."); - return 0; - } - - // return CompositeEnv and base_env - std::shared_ptr fs(cfs); - std::unique_ptr cloud_env = CloudFileSystemEnv::NewCompositeEnv(base_env, std::move(fs)); - Env* raw_env_ptr = cloud_env.release(); - - // return reinterpret_cast(cloud_env.get()); - std::cout << "Complete Create CloudFileSystem"<< std::endl; - return reinterpret_cast(raw_env_ptr); -} - -/* - * Class: io_pixelsdb_pixels_index_rocksdb_RocksetIndex - * Method: OpenDBCloud0 - * Signature: (JLjava/lang/String;Ljava/lang/String;JZ)J - */ -JNIEXPORT jlong JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_OpenDBCloud0( - JNIEnv* env, jobject obj, - jlong cloud_env_ptr, jstring local_db_path, - jstring persistent_cache_path, jlong persistent_cache_size_gb, - jboolean read_only) -{ - // Convert Java strings - std::string db_path = jstring_to_string(env, local_db_path); - std::string cache_path = jstring_to_string(env, persistent_cache_path); - - // Configure options - Options options; - options.env = reinterpret_cast(cloud_env_ptr); - options.create_if_missing = true; - options.best_efforts_recovery = true; - options.paranoid_checks = false; - - // Open DBCloud - DBCloud* dbcloud = nullptr; - Status s = DBCloud::Open( - options, - db_path, - cache_path, - static_cast(persistent_cache_size_gb), - &dbcloud, - static_cast(read_only) - ); - - if (!s.ok()) - { - std::cout << "Failed to open DBCloud: " << s.ToString() << std::endl; - env->ThrowNew(env->FindClass("java/lang/RuntimeException"), "Failed to open DBCloud"); - return 0; - } - - return reinterpret_cast(dbcloud); -} - -/* - * Class: io_pixelsdb_pixels_index_rocksdb_RocksetIndex - * Method: DBput0 - * Signature: (J[B[B)V - */ -JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_DBput0( - JNIEnv* env, jobject obj, - jlong db_ptr, jbyteArray key, jbyteArray value) -{ - DBCloud* db = reinterpret_cast(db_ptr); - jbyte* key_data = env->GetByteArrayElements(key, nullptr); - jsize key_len = env->GetArrayLength(key); - jbyte* value_data = env->GetByteArrayElements(value, nullptr); - jsize value_len = env->GetArrayLength(value); - - Slice key_slice(reinterpret_cast(key_data), key_len); - Slice value_slice(reinterpret_cast(value_data), value_len); - - Status s = db->Put(WriteOptions(), key_slice, value_slice); - - env->ReleaseByteArrayElements(key, key_data, JNI_ABORT); - env->ReleaseByteArrayElements(value, value_data, JNI_ABORT); - - if (!s.ok()) - { - env->ThrowNew(env->FindClass("java/lang/RuntimeException"), "Put operation failed"); - } -} - -/* - * Class: io_pixelsdb_pixels_index_rocksdb_RocksetIndex - * Method: DBget0 - * Signature: (J[B)[B - */ -JNIEXPORT jbyteArray JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_DBget0( - JNIEnv* env, jobject obj, - jlong db_ptr, jbyteArray key) -{ - DBCloud* db = reinterpret_cast(db_ptr); - jbyte* key_data = env->GetByteArrayElements(key, nullptr); - jsize key_len = env->GetArrayLength(key); - Slice key_slice(reinterpret_cast(key_data), key_len); - - std::string value; - Status s = db->Get(ReadOptions(), key_slice, &value); - - env->ReleaseByteArrayElements(key, key_data, JNI_ABORT); - - if (s.ok()) - { - jbyteArray result = env->NewByteArray(value.size()); - env->SetByteArrayRegion(result, 0, value.size(), reinterpret_cast(value.data())); - return result; - } - else if (s.IsNotFound()) - { - return nullptr; - } - else - { - env->ThrowNew(env->FindClass("java/lang/RuntimeException"), "Get operation failed"); - return nullptr; - } -} - -/* - * Class: io_pixelsdb_pixels_index_rocksdb_RocksetIndex - * Method: DBdelete0 - * Signature: (J[B)V - */ -JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_DBdelete0( - JNIEnv* env, jobject obj, - jlong db_ptr, jbyteArray key) -{ - DBCloud* db = reinterpret_cast(db_ptr); - jbyte* key_data = env->GetByteArrayElements(key, nullptr); - jsize key_len = env->GetArrayLength(key); - Slice key_slice(reinterpret_cast(key_data), key_len); - - Status s = db->Delete(WriteOptions(), key_slice); - - env->ReleaseByteArrayElements(key, key_data, JNI_ABORT); - - if (!s.ok()) - { - env->ThrowNew(env->FindClass("java/lang/RuntimeException"), "Delete operation failed"); - } -} - -/* - * Class: io_pixelsdb_pixels_index_rocksdb_RocksetIndex - * Method: CloseDB0 - * Signature: (JJ)V - */ -JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_CloseDB0( - JNIEnv* env, jobject obj, - jlong db_ptr) -{ - DBCloud* db = reinterpret_cast(db_ptr); - if(db) - { - db->Flush(FlushOptions()); // convert pending writes to sst files - delete db; - db = nullptr; - } -} - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: DBNewIterator0 - * Signature: (J)J - */ -JNIEXPORT jlong JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_DBNewIterator0( - JNIEnv* env, jobject obj, jlong db_ptr) -{ - DBCloud* db = reinterpret_cast(db_ptr); - if (!db) { - env->ThrowNew(env->FindClass("java/lang/RuntimeException"), "DB handle is null"); - return 0; - } - - Iterator* it = db->NewIterator(ReadOptions()); - - return reinterpret_cast(it); -} - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: IteratorSeekForPrev0 - * Signature: (J[B)V - */ -JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_IteratorSeekForPrev0( - JNIEnv* env, jobject obj, jlong it_ptr, jbyteArray targetKey) -{ - Iterator* it = reinterpret_cast(it_ptr); - if (!it) { - env->ThrowNew(env->FindClass("java/lang/RuntimeException"), "Iterator handle is null in SeekForPrev"); - return; - } - - jbyte* key_data = env->GetByteArrayElements(targetKey, nullptr); - jsize key_len = env->GetArrayLength(targetKey); - - Slice target(reinterpret_cast(key_data), key_len); - - it->SeekForPrev(target); - - env->ReleaseByteArrayElements(targetKey, key_data, JNI_ABORT); -} - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: IteratorKey0 - * Signature: (J)[B - */ - JNIEXPORT jbyteArray JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_IteratorKey0( - JNIEnv* env, jobject obj, jlong it_ptr) -{ - Iterator* it = reinterpret_cast(it_ptr); - if (it == nullptr || !it->Valid()) - { - env->ThrowNew(env->FindClass("java/lang/RuntimeException"), "Iterator handle is null in IteratorKey"); - return nullptr; - } - - Slice key = it->key(); - jbyteArray jkey = env->NewByteArray(static_cast(key.size())); - env->SetByteArrayRegion(jkey, 0, static_cast(key.size()), - reinterpret_cast(key.data())); - return jkey; -} - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: IteratorValue0 - * Signature: (J)[B - */ -JNIEXPORT jbyteArray JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_IteratorValue0( - JNIEnv * env, jobject obj, jlong it_ptr) -{ - Iterator* it = reinterpret_cast(it_ptr); - if (it == nullptr || !it->Valid()) - { - env->ThrowNew(env->FindClass("java/lang/RuntimeException"), "Iterator handle is null in IteratorValue"); - return nullptr; - } - - Slice value = it->value(); - jbyteArray jvalue = env->NewByteArray(static_cast(value.size())); - env->SetByteArrayRegion(jvalue, 0, static_cast(value.size()), - reinterpret_cast(value.data())); - return jvalue; -} - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: IteratorIsValid0 - * Signature: (J)Z - */ -JNIEXPORT jboolean JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_IteratorIsValid0( - JNIEnv* env, jobject obj, jlong it_ptr) -{ - Iterator* it = reinterpret_cast(it_ptr); - if (!it) { - return JNI_FALSE; - } - return it->Valid() ? JNI_TRUE : JNI_FALSE; -} - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: IteratorPrev0 - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_IteratorPrev0 - (JNIEnv* env, jobject obj, jlong it_ptr) -{ - Iterator* it = reinterpret_cast(it_ptr); - if (it == nullptr) { - env->ThrowNew(env->FindClass("java/lang/NullPointerException"), - "Iterator handle is null in IteratorPrev"); - return; - } - it->Prev(); -} - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: IteratorClose0 - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_IteratorClose0 - (JNIEnv* env, jobject obj, jlong it_ptr) -{ - Iterator* it = reinterpret_cast(it_ptr); - if (it == nullptr) { - return; - } - delete it; - it = nullptr; -} - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: WriteBatchCreate0 - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_WriteBatchCreate0 - (JNIEnv * env, jobject obj) -{ - auto* wb = new WriteBatch(); - return reinterpret_cast(wb); -} - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: WriteBatchPut0 - * Signature: (J[B[B)V - */ -JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_WriteBatchPut0 - (JNIEnv* env, jobject obj, jlong wb_handle, jbyteArray jkey, jbyteArray jvalue) -{ - auto* wb = reinterpret_cast(wb_handle); - if (wb == nullptr) return; - - // Convert Java byte[] key to Slice - jsize key_len = env->GetArrayLength(jkey); - jbyte* key_bytes = env->GetByteArrayElements(jkey, nullptr); - Slice key(reinterpret_cast(key_bytes), key_len); - - // Convert Java byte[] value to Slice - jsize val_len = env->GetArrayLength(jvalue); - jbyte* val_bytes = env->GetByteArrayElements(jvalue, nullptr); - Slice value(reinterpret_cast(val_bytes), val_len); - - wb->Put(key, value); - - // Release resources - env->ReleaseByteArrayElements(jkey, key_bytes, JNI_ABORT); - env->ReleaseByteArrayElements(jvalue, val_bytes, JNI_ABORT); -} - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: WriteBatchDelete0 - * Signature: (J[B)V - */ -JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_WriteBatchDelete0 - (JNIEnv* env, jobject obj, jlong wb_handle, jbyteArray jkey) -{ - auto* wb = reinterpret_cast(wb_handle); - if (wb == nullptr) return; - - // Convert Java byte[] key to Slice - jsize key_len = env->GetArrayLength(jkey); - jbyte* key_bytes = env->GetByteArrayElements(jkey, nullptr); - Slice key(reinterpret_cast(key_bytes), key_len); - - wb->Delete(key); - - // Release resources - env->ReleaseByteArrayElements(jkey, key_bytes, JNI_ABORT); -} - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: DBWrite0 - * Signature: (JJ)Z - */ -JNIEXPORT jboolean JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_DBWrite0 - (JNIEnv * env, jobject obj, jlong db_handle, jlong wb_handle) -{ - auto* db = reinterpret_cast(db_handle); - auto* wb = reinterpret_cast(wb_handle); - if (db == nullptr || wb == nullptr) return JNI_FALSE; - - WriteOptions write_options; - Status s = db->Write(write_options, wb); - return s.ok() ? JNI_TRUE : JNI_FALSE; -} - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: WriteBatchClear0 - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_WriteBatchClear0 - (JNIEnv * env, jobject obj, jlong wb_handle) -{ - auto* wb = reinterpret_cast(wb_handle); - if (wb != nullptr) { - wb->Clear(); - } -} - -/* - * Class: io_pixelsdb_pixels_index_rockset_RocksetIndexStub - * Method: WriteBatchDestroy0 - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_io_pixelsdb_pixels_index_rockset_RocksetIndexStub_WriteBatchDestroy0 - (JNIEnv * env, jobject obj, jlong wb_handle) -{ - auto* wb = reinterpret_cast(wb_handle); - if (wb != nullptr) { - delete wb; - } -} \ No newline at end of file diff --git a/cpp/pixels-index/pixels-index-rockset/lib/jni/BlockBasedTableConfig.cpp b/cpp/pixels-index/pixels-index-rockset/lib/jni/BlockBasedTableConfig.cpp new file mode 100644 index 0000000000..b8ecbeba91 --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/lib/jni/BlockBasedTableConfig.cpp @@ -0,0 +1,56 @@ +#include "io_pixelsdb_pixels_index_rockset_jni_RocksetBlockBasedTableConfig.h" + +#include +#include +#include "cplusplus_to_java_convert.h" + +#include +using ROCKSDB_NAMESPACE::BlockBasedTableOptions; +using ROCKSDB_NAMESPACE::NewBlockBasedTableFactory; +using ROCKSDB_NAMESPACE::FilterPolicy; +using ROCKSDB_NAMESPACE::Cache; + +/** + * This file is modified from RocksDB's own JNI bindings. + * @author Rolland1944 + * @create 2025-12-22 + */ + +JNIEXPORT jlong JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetBlockBasedTableConfig_newTableFactoryHandle( + JNIEnv*, + jclass, + jlong jblock_cache_handle, + jlong jfilter_policy_handle, + jlong jblock_size, + jboolean jwhole_key_filtering, + jboolean jcache_index_and_filter_blocks) +{ + BlockBasedTableOptions options; + // 1. block cache + if (jblock_cache_handle > 0) + { + auto* cache_ptr = + reinterpret_cast*>( + jblock_cache_handle); + options.block_cache = *cache_ptr; + } + // 2. filter policy + if (jfilter_policy_handle > 0) + { + auto* filter_ptr = + reinterpret_cast*>( + jfilter_policy_handle); + options.filter_policy = *filter_ptr; + } + // 3. block size + if (jblock_size > 0) + { + options.block_size = static_cast(jblock_size); + } + // 4. whole key filtering + options.whole_key_filtering = static_cast(jwhole_key_filtering); + // 5. create factory + return GET_CPLUSPLUS_POINTER( + ROCKSDB_NAMESPACE::NewBlockBasedTableFactory(options)); +} diff --git a/cpp/pixels-index/pixels-index-rockset/lib/jni/BloomFilter.cpp b/cpp/pixels-index/pixels-index-rockset/lib/jni/BloomFilter.cpp new file mode 100644 index 0000000000..5bd32332b4 --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/lib/jni/BloomFilter.cpp @@ -0,0 +1,22 @@ +#include "io_pixelsdb_pixels_index_rockset_jni_RocksetBloomFilter.h" +#include +#include + +/** + * This file is modified from RocksDB's own JNI bindings. + * @author Rolland1944 + * @create 2025-12-22 + */ + +JNIEXPORT jlong JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetBloomFilter_createNewBloomFilter( + JNIEnv*, + jclass, + jdouble bits_per_key) +{ + auto* sptr_filter = + new std::shared_ptr( + ROCKSDB_NAMESPACE::NewBloomFilterPolicy(bits_per_key)); + + return reinterpret_cast(sptr_filter); +} diff --git a/cpp/pixels-index/pixels-index-rockset/lib/jni/ColumnFamilyHandle.cpp b/cpp/pixels-index/pixels-index-rockset/lib/jni/ColumnFamilyHandle.cpp new file mode 100644 index 0000000000..8c423595eb --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/lib/jni/ColumnFamilyHandle.cpp @@ -0,0 +1,22 @@ +#include "io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyHandle.h" +#include +#include + +/** + * This file is modified from RocksDB's own JNI bindings. + * @author Rolland1944 + * @create 2025-12-22 + */ + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyHandle_disposeInternalJni( + JNIEnv*, + jclass, + jlong jhandle) +{ + auto* cfh = + reinterpret_cast(jhandle); + + assert(cfh != nullptr); + delete cfh; +} \ No newline at end of file diff --git a/cpp/pixels-index/pixels-index-rockset/lib/jni/ColumnFamilyOptions.cpp b/cpp/pixels-index/pixels-index-rockset/lib/jni/ColumnFamilyOptions.cpp new file mode 100644 index 0000000000..125bf8e3a5 --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/lib/jni/ColumnFamilyOptions.cpp @@ -0,0 +1,144 @@ +#include "io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions.h" +#include +#include + +using ROCKSDB_NAMESPACE::ColumnFamilyOptions; +using ROCKSDB_NAMESPACE::CompressionType; +using ROCKSDB_NAMESPACE::CompactionStyle; + +/** + * This file is modified from RocksDB's own JNI bindings. + * @author Rolland1944 + * @create 2025-12-22 + */ + + +JNIEXPORT jlong JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_newColumnFamilyOptions( + JNIEnv* /*env*/, + jclass /*jcls*/) +{ + auto* op = new ROCKSDB_NAMESPACE::ColumnFamilyOptions(); + return reinterpret_cast(op); +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetWriteBufferSize( + JNIEnv* env, jclass, jlong jhandle, jlong jwrite_buffer_size) +{ + if (jwrite_buffer_size < 0 || jwrite_buffer_size > static_cast(SIZE_MAX)) { + jclass exc = env->FindClass("java/lang/IllegalArgumentException"); + env->ThrowNew(exc, "write_buffer_size out of range"); + return; + } + auto* options = reinterpret_cast(jhandle); + options->write_buffer_size = static_cast(jwrite_buffer_size); +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetMaxWriteBufferNumber( + JNIEnv*, jclass, jlong jhandle, jint jmax_write_buffer_number) +{ + auto* options = reinterpret_cast(jhandle); + options->max_write_buffer_number = static_cast(jmax_write_buffer_number); +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetMinWriteBufferNumberToMerge( + JNIEnv*, jclass, jlong jhandle, jint jmin_write_buffer_number_to_merge) +{ + auto* options = reinterpret_cast(jhandle); + options->min_write_buffer_number_to_merge = static_cast(jmin_write_buffer_number_to_merge); +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetMemtablePrefixBloomSizeRatio( + JNIEnv*, jclass, jlong jhandle, jdouble jmemtable_prefix_bloom_size_ratio) +{ + auto* options = reinterpret_cast(jhandle); + options->memtable_prefix_bloom_size_ratio = static_cast(jmemtable_prefix_bloom_size_ratio); +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetTableFactory( + JNIEnv*, jclass, jlong jhandle, jlong jtable_factory_handle) +{ + auto* options = reinterpret_cast(jhandle); + auto* table_factory = reinterpret_cast(jtable_factory_handle); + options->table_factory.reset(table_factory); +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetLevel0FileNumCompactionTrigger( + JNIEnv*, jclass, jlong jhandle, jint jlevel0_file_num_compaction_trigger) +{ + auto* options = reinterpret_cast(jhandle); + options->level0_file_num_compaction_trigger = static_cast(jlevel0_file_num_compaction_trigger); +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetMaxBytesForLevelBase( + JNIEnv*, jclass, jlong jhandle, jlong jmax_bytes_for_level_base) +{ + auto* options = reinterpret_cast(jhandle); + options->max_bytes_for_level_base = static_cast(jmax_bytes_for_level_base); +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetMaxBytesForLevelMultiplier( + JNIEnv*, jclass, jlong jhandle, jdouble jmultiplier) +{ + auto* options = reinterpret_cast(jhandle); + options->max_bytes_for_level_multiplier = static_cast(jmultiplier); +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetTargetFileSizeBase( + JNIEnv*, jclass, jlong jhandle, jlong jtarget_file_size_base) +{ + auto* options = reinterpret_cast(jhandle); + options->target_file_size_base = static_cast(jtarget_file_size_base); +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetTargetFileSizeMultiplier( + JNIEnv*, jclass, jlong jhandle, jint jtarget_file_size_multiplier) +{ + auto* options = reinterpret_cast(jhandle); + options->target_file_size_multiplier = static_cast(jtarget_file_size_multiplier); +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetCompressionType( + JNIEnv*, jclass, jlong jhandle, jbyte jcompression_type) +{ + auto* options = reinterpret_cast(jhandle); + options->compression = static_cast(jcompression_type); +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetBottommostCompressionType( + JNIEnv*, jclass, jlong jhandle, jbyte jcompression_type) +{ + auto* options = reinterpret_cast(jhandle); + options->bottommost_compression = static_cast(jcompression_type); +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_nativeSetCompactionStyle( + JNIEnv*, jclass, jlong jhandle, jbyte jcompaction_style) +{ + auto* options = reinterpret_cast(jhandle); + options->compaction_style = static_cast(jcompaction_style); +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetColumnFamilyOptions_disposeInternalJni(JNIEnv*, jclass, + jlong handle) { + auto* cfo = reinterpret_cast(handle); + assert(cfo != nullptr); + delete cfo; +} + + + diff --git a/cpp/pixels-index/pixels-index-rockset/lib/jni/DBOptions.cpp b/cpp/pixels-index/pixels-index-rockset/lib/jni/DBOptions.cpp new file mode 100644 index 0000000000..cf1dac89bf --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/lib/jni/DBOptions.cpp @@ -0,0 +1,100 @@ +#include "io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions.h" +#include "rocksdb/options.h" +#include "rocksdb/statistics.h" +#include +#include + +using ROCKSDB_NAMESPACE::DBOptions; +using ROCKSDB_NAMESPACE::Statistics; + +/** + * This file is modified from RocksDB's own JNI bindings. + * @author Rolland1944 + * @create 2025-12-22 + */ + + +JNIEXPORT jlong JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions_newDBOptions( + JNIEnv*, jclass) +{ + auto* dbop = new DBOptions(); + return reinterpret_cast(dbop); +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions_disposeInternalJni( + JNIEnv*, jclass, jlong jhandle) +{ + auto* dbo = reinterpret_cast(jhandle); + assert(dbo != nullptr); + delete dbo; +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions_nativeSetCreateIfMissing( + JNIEnv*, jclass, jlong jhandle, jboolean flag) +{ + reinterpret_cast(jhandle)->create_if_missing = flag; +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions_nativeSetCreateMissingColumnFamilies( + JNIEnv*, jclass, jlong jhandle, jboolean flag) +{ + reinterpret_cast(jhandle)->create_missing_column_families = flag; +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions_nativeSetMaxBackgroundFlushes( + JNIEnv*, jclass, jlong jhandle, jint num) +{ + reinterpret_cast(jhandle)->max_background_flushes = static_cast(num); +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions_nativeSetMaxBackgroundCompactions( + JNIEnv*, jclass, jlong jhandle, jint num) +{ + reinterpret_cast(jhandle)->max_background_compactions = static_cast(num); +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions_nativeSetMaxSubcompactions( + JNIEnv*, jclass, jlong jhandle, jint num) +{ + reinterpret_cast(jhandle)->max_subcompactions = static_cast(num); +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions_nativeSetMaxOpenFiles( + JNIEnv*, jclass, jlong jhandle, jint num) +{ + reinterpret_cast(jhandle)->max_open_files = static_cast(num); +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions_nativeSetStatistics( + JNIEnv*, jclass, jlong jhandle, jlong stats_handle) +{ + auto* options = reinterpret_cast(jhandle); + auto* stats = reinterpret_cast*>(stats_handle); + options->statistics = *stats; +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions_nativeSetStatsDumpPeriodSec( + JNIEnv*, jclass, jlong jhandle, jint interval) +{ + reinterpret_cast(jhandle)->stats_dump_period_sec = static_cast(interval); +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDBOptions_nativeSetDbLogDir( + JNIEnv* env, jclass, jlong jhandle, jstring jpath) +{ + auto* options = reinterpret_cast(jhandle); + const char* cpath = env->GetStringUTFChars(jpath, nullptr); + options->db_log_dir = std::string(cpath); + env->ReleaseStringUTFChars(jpath, cpath); +} diff --git a/cpp/pixels-index/pixels-index-rockset/lib/jni/Filter.cpp b/cpp/pixels-index/pixels-index-rockset/lib/jni/Filter.cpp new file mode 100644 index 0000000000..89b5ae2a0e --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/lib/jni/Filter.cpp @@ -0,0 +1,25 @@ +#include "io_pixelsdb_pixels_index_rockset_jni_Filter.h" + +#include "rocksdb/filter_policy.h" +#include + +using ROCKSDB_NAMESPACE::FilterPolicy; + +/** + * This file is modified from RocksDB's own JNI bindings. + * @author Rolland1944 + * @create 2025-12-22 + */ + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_Filter_disposeInternalJni( + JNIEnv* /*env*/, + jclass /*jcls*/, + jlong jhandle) +{ + // jhandle is a pointer to std::shared_ptr + auto* handle = + reinterpret_cast*>(jhandle); + + delete handle; // decrement refcount and free wrapper +} \ No newline at end of file diff --git a/cpp/pixels-index/pixels-index-rockset/lib/jni/Iterator.cpp b/cpp/pixels-index/pixels-index-rockset/lib/jni/Iterator.cpp new file mode 100644 index 0000000000..04f5f2df50 --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/lib/jni/Iterator.cpp @@ -0,0 +1,178 @@ +#include "io_pixelsdb_pixels_index_rockset_jni_RocksetIterator.h" +#include + +#include "rocksdb/iterator.h" +#include "rocksdb/slice.h" + +#include "portal.h" + +using ROCKSDB_NAMESPACE::Iterator; +using ROCKSDB_NAMESPACE::Slice; + +/** + * This file is modified from RocksDB's own JNI bindings. + * @author Rolland1944 + * @create 2025-12-22 + */ + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetIterator + * Method: seekDirect0Jni + * Signature: (JLjava/nio/ByteBuffer;II)V + */ +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetIterator_seekDirect0Jni( + JNIEnv* env, + jclass /* cls */, + jlong handle, + jobject jtarget, + jint jtarget_off, + jint jtarget_len) +{ + auto* it = reinterpret_cast(handle); + assert(it != nullptr); + + auto seek = [&it](Slice& target_slice) + { + it->Seek(target_slice); + }; + + ROCKSDB_NAMESPACE::JniUtil::k_op_direct( + seek, env, jtarget, jtarget_off, jtarget_len); +} + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetIterator + * Method: seekByteArray0Jni + * Signature: (J[BII)V + */ +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetIterator_seekByteArray0Jni( + JNIEnv* env, + jclass /* cls */, + jlong handle, + jbyteArray jtarget, + jint jtarget_off, + jint jtarget_len) +{ + auto* it = reinterpret_cast(handle); + assert(it != nullptr); + + auto seek = [&it](Slice& target_slice) + { + it->Seek(target_slice); + }; + + ROCKSDB_NAMESPACE::JniUtil::k_op_region( + seek, env, jtarget, jtarget_off, jtarget_len); +} + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetIterator + * Method: next0 + * Signature: (J)V + */ +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetIterator_next0( + JNIEnv* /* env */, + jclass /* cls */, + jlong handle) +{ + reinterpret_cast(handle)->Next(); +} + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetIterator + * Method: isValid0 + * Signature: (J)Z + */ +JNIEXPORT jboolean JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetIterator_isValid0( + JNIEnv* /* env */, + jclass /* cls */, + jlong handle) +{ + return reinterpret_cast(handle)->Valid(); +} + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetIterator + * Method: key0 + * Signature: (J)[B + */ +JNIEXPORT jbyteArray JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetIterator_key0( + JNIEnv* env, + jclass /* cls */, + jlong handle) +{ + auto* it = reinterpret_cast(handle); + assert(it != nullptr); + + Slice key_slice = it->key(); + + jbyteArray jkey = + env->NewByteArray(static_cast(key_slice.size())); + if (jkey == nullptr) + { + // OutOfMemoryError already thrown + return nullptr; + } + + env->SetByteArrayRegion( + jkey, + 0, + static_cast(key_slice.size()), + reinterpret_cast(key_slice.data())); + + return jkey; +} + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetIterator + * Method: value0 + * Signature: (J)[B + */ +JNIEXPORT jbyteArray JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetIterator_value0( + JNIEnv* env, + jclass /* cls */, + jlong handle) +{ + auto* it = reinterpret_cast(handle); + assert(it != nullptr); + + Slice value_slice = it->value(); + + jbyteArray jvalue = + env->NewByteArray(static_cast(value_slice.size())); + if (jvalue == nullptr) + { + // OutOfMemoryError already thrown + return nullptr; + } + + env->SetByteArrayRegion( + jvalue, + 0, + static_cast(value_slice.size()), + reinterpret_cast(value_slice.data())); + + return jvalue; +} + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetIterator + * Method: disposeInternalJni + * Signature: (J)V + */ +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetIterator_disposeInternalJni( + JNIEnv* /* env */, + jclass /* cls */, + jlong handle) +{ + auto* it = reinterpret_cast(handle); + assert(it != nullptr); + delete it; +} diff --git a/cpp/pixels-index/pixels-index-rockset/lib/jni/LRUCache.cpp b/cpp/pixels-index/pixels-index-rockset/lib/jni/LRUCache.cpp new file mode 100644 index 0000000000..baef4d6c2f --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/lib/jni/LRUCache.cpp @@ -0,0 +1,49 @@ +#include "io_pixelsdb_pixels_index_rockset_jni_RocksetLRUCache.h" +#include + +#include "rocksdb/cache.h" + +using ROCKSDB_NAMESPACE::Cache; +using ROCKSDB_NAMESPACE::NewLRUCache; + +/** + * This file is modified from RocksDB's own JNI bindings. + * @author Rolland1944 + * @create 2025-12-22 + */ + +JNIEXPORT jlong JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetLRUCache_newLRUCache( + JNIEnv* /*env*/, + jclass /*jcls*/, + jlong jcapacity, + jint jnum_shard_bits, + jboolean jstrict_capacity_limit, + jdouble jhigh_pri_pool_ratio, + jdouble jlow_pri_pool_ratio) +{ + auto* sptr_lru_cache = + new std::shared_ptr( + NewLRUCache( + static_cast(jcapacity), + static_cast(jnum_shard_bits), + static_cast(jstrict_capacity_limit), + static_cast(jhigh_pri_pool_ratio), + nullptr /* memory_allocator */, + ROCKSDB_NAMESPACE::kDefaultToAdaptiveMutex, + ROCKSDB_NAMESPACE::kDefaultCacheMetadataChargePolicy, + static_cast(jlow_pri_pool_ratio))); + + return reinterpret_cast(sptr_lru_cache); +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetLRUCache_disposeInternalJni( + JNIEnv* /*env*/, + jclass /*jcls*/, + jlong jhandle) +{ + auto* sptr_lru_cache = + reinterpret_cast*>(jhandle); + delete sptr_lru_cache; +} diff --git a/cpp/pixels-index/pixels-index-rockset/lib/jni/ReadOptions.cpp b/cpp/pixels-index/pixels-index-rockset/lib/jni/ReadOptions.cpp new file mode 100644 index 0000000000..da0a1d323e --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/lib/jni/ReadOptions.cpp @@ -0,0 +1,51 @@ +#include "io_pixelsdb_pixels_index_rockset_jni_RocksetReadOptions.h" +#include +#include "rocksdb/options.h" + +using ROCKSDB_NAMESPACE::ReadOptions; + +/** + * This file is modified from RocksDB's own JNI bindings. + * @author Rolland1944 + * @create 2025-12-22 + */ + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetReadOptions + * Method: newReadOptions + * Signature: ()J + */ +JNIEXPORT jlong JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetReadOptions_newReadOptions( + JNIEnv*, jclass) +{ + auto* opts = new ReadOptions(); + return reinterpret_cast(opts); +} + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetReadOptions + * Method: disposeInternalJni + * Signature: (J)V + */ +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetReadOptions_disposeInternalJni( + JNIEnv*, jclass, jlong handle) +{ + auto* opts = reinterpret_cast(handle); + assert(opts != nullptr); + delete opts; +} + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetReadOptions + * Method: setPrefixSameAsStart + * Signature: (JZ)V + */ +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetReadOptions_setPrefixSameAsStart( + JNIEnv*, jclass, jlong handle, jboolean flag) +{ + reinterpret_cast(handle)->prefix_same_as_start = + static_cast(flag); +} \ No newline at end of file diff --git a/cpp/pixels-index/pixels-index-rockset/lib/jni/Rockset.cpp b/cpp/pixels-index/pixels-index-rockset/lib/jni/Rockset.cpp new file mode 100644 index 0000000000..78d659f523 --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/lib/jni/Rockset.cpp @@ -0,0 +1,353 @@ +#include "io_pixelsdb_pixels_index_rockset_jni_RocksetDB.h" +#include +#include + +#include "rocksdb/cloud/db_cloud.h" +#include "rocksdb/options.h" +#include "rocksdb/db.h" +#include "portal.h" +#include "cplusplus_to_java_convert.h" + +/** + * This file is modified from RocksDB's own JNI bindings. + * @author Rolland1944 + * @create 2025-12-22 + */ + +JNIEXPORT jlongArray JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDB_open( + JNIEnv* env, + jclass, + jlong cloud_env_ptr, + jlong joptions, + jstring jdb_path, + jobjectArray jcf_names, + jlongArray jcf_options_handles) +{ + // 1. Options* + auto* options = + reinterpret_cast(joptions); + assert(options != nullptr); + options->env = reinterpret_cast(cloud_env_ptr); + + // 2. db path + const char* db_path_chars = + env->GetStringUTFChars(jdb_path, nullptr); + std::string db_path(db_path_chars); + env->ReleaseStringUTFChars(jdb_path, db_path_chars); + + // 3. column families + jsize cf_count = env->GetArrayLength(jcf_names); + jsize opt_count = env->GetArrayLength(jcf_options_handles); + assert(cf_count == opt_count); + + std::vector cf_descs; + cf_descs.reserve(cf_count); + + jlong* cf_opts = + env->GetLongArrayElements(jcf_options_handles, nullptr); + + for (jsize i = 0; i < cf_count; ++i) { + auto jname = + (jbyteArray)env->GetObjectArrayElement(jcf_names, i); + + jsize len = env->GetArrayLength(jname); + std::string cf_name(len, '\0'); + env->GetByteArrayRegion( + jname, 0, len, + reinterpret_cast(&cf_name[0])); + + auto* cf_options = + reinterpret_cast( + cf_opts[i]); + + cf_descs.emplace_back(cf_name, *cf_options); + + env->DeleteLocalRef(jname); + } + + env->ReleaseLongArrayElements( + jcf_options_handles, cf_opts, JNI_ABORT); + + // 4. open DBCloud + std::vector handles; + ROCKSDB_NAMESPACE::DBCloud* db = nullptr; + + auto status = ROCKSDB_NAMESPACE::DBCloud::Open( + *options, + db_path, + cf_descs, + "" /* persistent_cache_path */, + 0 /* persistent_cache_size_gb */, + &handles, + &db, + false /* read_only */ + ); + + if (!status.ok()) { + return nullptr; + } + + // 5. prepare return value + jlongArray result = + env->NewLongArray(handles.size() + 1); + + std::vector values; + values.reserve(handles.size() + 1); + + values.push_back(reinterpret_cast(db)); + for (auto* h : handles) { + values.push_back(reinterpret_cast(h)); + } + + env->SetLongArrayRegion( + result, 0, values.size(), values.data()); + + return result; +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDB_closeDatabase( + JNIEnv*, jclass, jlong jdb) +{ + auto* db = + reinterpret_cast(jdb); + if (db == nullptr) { + return; + } + + delete db; +} + +JNIEXPORT jobject JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDB_listColumnFamilies0( + JNIEnv* env, jclass, jstring jdb_path) +{ + const char* path_chars = env->GetStringUTFChars(jdb_path, nullptr); + if (path_chars == nullptr) { + return nullptr; // OOM + } + std::string db_path(path_chars); + env->ReleaseStringUTFChars(jdb_path, path_chars); + ROCKSDB_NAMESPACE::Options options; + std::vector column_families; + ROCKSDB_NAMESPACE::Status st = + ROCKSDB_NAMESPACE::DBCloud::ListColumnFamilies( + options, db_path, &column_families); + + if (!st.ok()) { + jclass ex = env->FindClass("java/lang/RuntimeException"); + env->ThrowNew(ex, st.ToString().c_str()); + return nullptr; + } + + jclass array_list_clz = env->FindClass("java/util/ArrayList"); + jmethodID array_list_ctor = + env->GetMethodID(array_list_clz, "", "(I)V"); + jmethodID array_list_add = + env->GetMethodID(array_list_clz, "add", "(Ljava/lang/Object;)Z"); + + jobject jlist = + env->NewObject(array_list_clz, array_list_ctor, + static_cast(column_families.size())); + + for (const auto& cf : column_families) { + jbyteArray jbytes = env->NewByteArray(cf.size()); + env->SetByteArrayRegion( + jbytes, 0, cf.size(), + reinterpret_cast(cf.data())); + env->CallBooleanMethod(jlist, array_list_add, jbytes); + env->DeleteLocalRef(jbytes); + } + + return jlist; +} + +JNIEXPORT jlong JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDB_createColumnFamily0( + JNIEnv* env, jobject jdb, jlong jhandle, jbyteArray jcf_name) +{ + auto* db = reinterpret_cast(jhandle); + if (db == nullptr) { + jclass ex = env->FindClass("java/lang/RuntimeException"); + env->ThrowNew(ex, "DB is closed"); + return reinterpret_cast(nullptr); + } + + jsize len = env->GetArrayLength(jcf_name); + std::string cf_name; + cf_name.resize(len); + env->GetByteArrayRegion( + jcf_name, 0, len, + reinterpret_cast(&cf_name[0])); + + ROCKSDB_NAMESPACE::ColumnFamilyOptions cf_options; + + ROCKSDB_NAMESPACE::ColumnFamilyHandle* cf_handle = nullptr; + ROCKSDB_NAMESPACE::Status st = + db->CreateColumnFamily(cf_options, cf_name, &cf_handle); + + if (!st.ok()) { + jclass ex = env->FindClass("java/lang/RuntimeException"); + env->ThrowNew(ex, st.ToString().c_str()); + return reinterpret_cast(nullptr); + } + + auto* sptr = + new std::shared_ptr(cf_handle); + + jclass cf_handle_clz = + env->FindClass( + "io/pixelsdb/pixels/index/rockset/jni/RocksetColumnFamilyHandle"); + + jmethodID ctor = + env->GetMethodID(cf_handle_clz, "", "(J)V"); + + return GET_CPLUSPLUS_POINTER(cf_handle); +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDB_put( + JNIEnv* env, + jclass, + jlong db_handle, + jlong cf_handle, + jbyteArray jkey, + jint koff, + jint klen, + jbyteArray jval, + jint voff, + jint vlen, + jlong write_opt_handle) +{ + auto* db = + reinterpret_cast(db_handle); + auto* cf = + reinterpret_cast(cf_handle); + auto* wo = + reinterpret_cast(write_opt_handle); + + jbyte* k = env->GetByteArrayElements(jkey, nullptr); + jbyte* v = env->GetByteArrayElements(jval, nullptr); + + ROCKSDB_NAMESPACE::Slice key( + reinterpret_cast(k + koff), klen); + ROCKSDB_NAMESPACE::Slice val( + reinterpret_cast(v + voff), vlen); + + auto status = db->Put(*wo, cf, key, val); + + env->ReleaseByteArrayElements(jkey, k, JNI_ABORT); + env->ReleaseByteArrayElements(jval, v, JNI_ABORT); + + if (!status.ok()) { + env->ThrowNew(env->FindClass("java/lang/RuntimeException"), + status.ToString().c_str()); + } +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDB_putDirect( + JNIEnv* env, + jclass, + jlong jdb_handle, + jlong jcf_handle, + jobject jkey, + jint jkey_off, + jint jkey_len, + jobject jval, + jint jval_off, + jint jval_len, + jlong jwrite_options_handle) +{ + auto* db = + reinterpret_cast(jdb_handle); + auto* cf_handle = + reinterpret_cast(jcf_handle); + auto* write_options = + reinterpret_cast( + jwrite_options_handle); + + if (db == nullptr || write_options == nullptr) { + env->ThrowNew(env->FindClass("java/lang/IllegalStateException"), + "DB or WriteOptions is null"); + return; + } + + auto put = + [&env, &db, &cf_handle, &write_options]( + ROCKSDB_NAMESPACE::Slice& key, + ROCKSDB_NAMESPACE::Slice& value) { + + ROCKSDB_NAMESPACE::Status s; + if (cf_handle == nullptr) { + s = db->Put(*write_options, key, value); + } else { + s = db->Put(*write_options, cf_handle, key, value); + } + + if (!s.ok()) { + env->ThrowNew(env->FindClass("java/lang/RuntimeException"), + s.ToString().c_str()); + } + }; + + ROCKSDB_NAMESPACE::JniUtil::kv_op_direct( + put, + env, + jkey, + jkey_off, + jkey_len, + jval, + jval_off, + jval_len); +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDB_write0( + JNIEnv* env, + jclass, + jlong db_handle, + jlong write_opt_handle, + jlong batch_handle) +{ + auto* db = + reinterpret_cast(db_handle); + auto* wo = + reinterpret_cast(write_opt_handle); + auto* batch = + reinterpret_cast(batch_handle); + + auto status = db->Write(*wo, batch); + + if (!status.ok()) { + env->ThrowNew(env->FindClass("java/lang/RuntimeException"), + status.ToString().c_str()); + } +} + +JNIEXPORT jlong JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetDB_iterator( + JNIEnv* env, + jclass, + jlong db_handle, + jlong cf_handle, + jlong read_opt_handle) +{ + auto* db = + reinterpret_cast(db_handle); + auto* cf = + reinterpret_cast(cf_handle); + auto* ro = + reinterpret_cast(read_opt_handle); + + if (!db || !cf || !ro) { + env->ThrowNew(env->FindClass("java/lang/IllegalStateException"), + "Null handle in iterator()"); + return 0; + } + + auto* it = db->NewIterator(*ro, cf); + return reinterpret_cast(it); +} + diff --git a/cpp/pixels-index/pixels-index-rockset/lib/jni/RocksetEnv.cpp b/cpp/pixels-index/pixels-index-rockset/lib/jni/RocksetEnv.cpp new file mode 100644 index 0000000000..0a897ca0f1 --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/lib/jni/RocksetEnv.cpp @@ -0,0 +1,105 @@ +#include "io_pixelsdb_pixels_index_rockset_jni_RocksetEnv.h" +#include "rocksdb/cloud/db_cloud.h" +#include "rocksdb/cloud/cloud_file_system.h" +#include + +/** + * This file is modified from RocksDB's own JNI bindings. + * @author Rolland1944 + * @create 2025-12-22 + */ + +JNIEXPORT jlong JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetEnv_createCloudFileSystem0( + JNIEnv* env, + jclass, + jstring jbucket_name, + jstring js3_prefix) +{ + // 1. Check AWS env vars + if (!getenv("AWS_ACCESS_KEY_ID") || + !getenv("AWS_SECRET_ACCESS_KEY") || + !getenv("AWS_DEFAULT_REGION")) { + env->ThrowNew( + env->FindClass("java/lang/IllegalStateException"), + "Missing AWS env vars: AWS_ACCESS_KEY_ID, " + "AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION"); + return 0; + } + + // 2. AWS SDK + Aws::SDKOptions aws_options; + Aws::InitAPI(aws_options); + + // 3. CloudFileSystemOptions + ROCKSDB_NAMESPACE::CloudFileSystemOptions cfs_options; + cfs_options.credentials.InitializeSimple( + getenv("AWS_ACCESS_KEY_ID"), + getenv("AWS_SECRET_ACCESS_KEY")); + + if (!cfs_options.credentials.HasValid().ok()) { + env->ThrowNew( + env->FindClass("java/lang/SecurityException"), + "Invalid AWS credentials"); + return 0; + } + + // 4. bucket / prefix + const char* bucket_chars = + env->GetStringUTFChars(jbucket_name, nullptr); + const char* prefix_chars = + env->GetStringUTFChars(js3_prefix, nullptr); + + cfs_options.src_bucket.SetBucketName(bucket_chars); + cfs_options.src_bucket.SetObjectPath(prefix_chars); + cfs_options.src_bucket.SetRegion( + getenv("AWS_DEFAULT_REGION")); + + env->ReleaseStringUTFChars(jbucket_name, bucket_chars); + env->ReleaseStringUTFChars(js3_prefix, prefix_chars); + + // 5. base Env + ROCKSDB_NAMESPACE::Env* base_env = + ROCKSDB_NAMESPACE::Env::Default(); + + // 6. Create CloudFileSystem + std::shared_ptr base_fs = + base_env->GetFileSystem(); + + ROCKSDB_NAMESPACE::CloudFileSystem* cloud_fs = nullptr; + auto status = + ROCKSDB_NAMESPACE::CloudFileSystemEnv::NewAwsFileSystem( + base_fs, cfs_options, nullptr, &cloud_fs); + + if (!status.ok()) { + env->ThrowNew( + env->FindClass("java/io/IOException"), + status.ToString().c_str()); + return 0; + } + + // 7. Composite Env + std::shared_ptr fs(cloud_fs); + std::unique_ptr cloud_env = + ROCKSDB_NAMESPACE::CloudFileSystemEnv::NewCompositeEnv( + base_env, std::move(fs)); + + return reinterpret_cast(cloud_env.release()); +} + +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetEnv_disposeInternalJni( + JNIEnv*, + jclass, + jlong jenv_handle) +{ + if (jenv_handle == 0) { + return; + } + + auto* env = + reinterpret_cast(jenv_handle); + + delete env; +} + diff --git a/cpp/pixels-index/pixels-index-rockset/lib/jni/Statistics.cpp b/cpp/pixels-index/pixels-index-rockset/lib/jni/Statistics.cpp new file mode 100644 index 0000000000..5fd2021fe9 --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/lib/jni/Statistics.cpp @@ -0,0 +1,44 @@ +#include "io_pixelsdb_pixels_index_rockset_jni_RocksetStatistics.h" +#include +#include + +#include "rocksdb/statistics.h" + +using ROCKSDB_NAMESPACE::Statistics; +using ROCKSDB_NAMESPACE::CreateDBStatistics; + +/** + * This file is modified from RocksDB's own JNI bindings. + * @author Rolland1944 + * @create 2025-12-22 + */ + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetStatistics + * Method: newStatisticsInstance + * Signature: ()J + */ +JNIEXPORT jlong JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetStatistics_newStatisticsInstance( + JNIEnv*, jclass) +{ + auto* sptr_statistics = + new std::shared_ptr(CreateDBStatistics()); + return reinterpret_cast(sptr_statistics); +} + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetStatistics + * Method: disposeInternalJni + * Signature: (J)V + */ +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetStatistics_disposeInternalJni( + JNIEnv*, jclass, jlong handle) +{ + if (handle > 0) { + auto* sptr_statistics = + reinterpret_cast*>(handle); + delete sptr_statistics; // delete shared_ptr + } +} \ No newline at end of file diff --git a/cpp/pixels-index/pixels-index-rockset/lib/jni/WriteBatch.cpp b/cpp/pixels-index/pixels-index-rockset/lib/jni/WriteBatch.cpp new file mode 100644 index 0000000000..37fe3a16dd --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/lib/jni/WriteBatch.cpp @@ -0,0 +1,128 @@ +#include "io_pixelsdb_pixels_index_rockset_jni_RocksetWriteBatch.h" +#include + +#include "rocksdb/write_batch.h" +#include "cplusplus_to_java_convert.h" + +#include "portal.h" + +using ROCKSDB_NAMESPACE::WriteBatch; +using ROCKSDB_NAMESPACE::ColumnFamilyHandle; +using ROCKSDB_NAMESPACE::Slice; + +/** + * This file is modified from RocksDB's own JNI bindings. + * @author Rolland1944 + * @create 2025-12-22 + */ + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetWriteBatch + * Method: newWriteBatch0 + * Signature: ()J + */ +JNIEXPORT jlong JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetWriteBatch_newWriteBatch0( + JNIEnv* /* env */, jclass /* cls */) +{ + auto* wb = new WriteBatch(); + return GET_CPLUSPLUS_POINTER(wb); +} + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetWriteBatch + * Method: disposeInternalJni + * Signature: (J)V + */ +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetWriteBatch_disposeInternalJni( + JNIEnv* /* env */, jclass /* cls */, jlong handle) +{ + auto* wb = reinterpret_cast(handle); + assert(wb != nullptr); + delete wb; +} + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetWriteBatch + * Method: putDirectJni + * Signature: (JLjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;IIJ)V + */ +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetWriteBatch_putDirectJni( + JNIEnv* env, + jclass /* cls */, + jlong jwb_handle, + jobject jkey, + jint jkey_offset, + jint jkey_len, + jobject jval, + jint jval_offset, + jint jval_len, + jlong jcf_handle) +{ + auto* wb = reinterpret_cast(jwb_handle); + assert(wb != nullptr); + + auto* cf_handle = + reinterpret_cast(jcf_handle); + + auto put = [&wb, &cf_handle](Slice& key, Slice& value) + { + if (cf_handle == nullptr) + { + wb->Put(key, value); + } + else + { + wb->Put(cf_handle, key, value); + } + }; + + ROCKSDB_NAMESPACE::JniUtil::kv_op_direct( + put, + env, + jkey, + jkey_offset, + jkey_len, + jval, + jval_offset, + jval_len); +} + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetWriteBatch + * Method: deleteJni + * Signature: (J[BIJ)V + */ +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetWriteBatch_deleteJni( + JNIEnv* env, + jclass /* cls */, + jlong jwb_handle, + jbyteArray jkey, + jint jkey_len, + jlong jcf_handle) +{ + auto* wb = reinterpret_cast(jwb_handle); + assert(wb != nullptr); + + auto* cf_handle = + reinterpret_cast(jcf_handle); + assert(cf_handle != nullptr); + + auto remove = [&wb, &cf_handle](Slice key) + { + return wb->Delete(cf_handle, key); + }; + + std::unique_ptr status = + ROCKSDB_NAMESPACE::JniUtil::k_op( + remove, env, jkey, jkey_len); + + if (status != nullptr && !status->ok()) + { + jclass ex = env->FindClass("java/lang/RuntimeException"); + env->ThrowNew(ex, status->ToString().c_str()); + } +} \ No newline at end of file diff --git a/cpp/pixels-index/pixels-index-rockset/lib/jni/WriteOptions.cpp b/cpp/pixels-index/pixels-index-rockset/lib/jni/WriteOptions.cpp new file mode 100644 index 0000000000..fd131e2a9e --- /dev/null +++ b/cpp/pixels-index/pixels-index-rockset/lib/jni/WriteOptions.cpp @@ -0,0 +1,38 @@ +#include "io_pixelsdb_pixels_index_rockset_jni_RocksetWriteOptions.h" +#include +#include "rocksdb/options.h" +#include "cplusplus_to_java_convert.h" + +/** + * This file is modified from RocksDB's own JNI bindings. + * @author Rolland1944 + * @create 2025-12-22 + */ + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetWriteOptions + * Method: newWriteOptions + * Signature: ()J + */ +JNIEXPORT jlong JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetWriteOptions_newWriteOptions( + JNIEnv*, jclass) +{ + auto* write_options = new ROCKSDB_NAMESPACE::WriteOptions(); + return GET_CPLUSPLUS_POINTER(write_options); +} + +/* + * Class: io_pixelsdb_pixels_index_rockset_jni_RocksetWriteOptions + * Method: disposeInternalJni + * Signature: (J)V + */ +JNIEXPORT void JNICALL +Java_io_pixelsdb_pixels_index_rockset_jni_RocksetWriteOptions_disposeInternalJni( + JNIEnv*, jclass, jlong jhandle) +{ + auto* write_options = + reinterpret_cast(jhandle); + assert(write_options != nullptr); + delete write_options; +} diff --git a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/RocksetFactory.java b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/RocksetFactory.java new file mode 100644 index 0000000000..d61b28a347 --- /dev/null +++ b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/RocksetFactory.java @@ -0,0 +1,234 @@ +/* + * Copyright 2025 PixelsDB. + * + * This file is part of Pixels. + * + * Pixels is free software: you can redistribute it and/or modify + * it under the terms of the Affero GNU General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * Pixels is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Affero GNU General Public License for more details. + * + * You should have received a copy of the Affero GNU General Public + * License along with Pixels. If not, see + * . + */ +package io.pixelsdb.pixels.index.rockset; + +import io.pixelsdb.pixels.common.utils.ConfigFactory; +import io.pixelsdb.pixels.index.rockset.jni.*; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +public class RocksetFactory +{ + private static final String dbPath = ConfigFactory.Instance().getProperty("index.rockset.data.path"); + private static final boolean multiCF = Boolean.parseBoolean(ConfigFactory.Instance().getProperty("index.rocksdb.multicf")); + private static RocksetDB rocksetDB; + private static RocksetCache blockCache; + private static final long blockCacheCapacity = Long.parseLong(ConfigFactory.Instance().getProperty("index.rocksdb.block.cache.capacity")); + private static final int blockCacheShardBits = Integer.parseInt(ConfigFactory.Instance().getProperty("index.rocksdb.block.cache.shard.bits")); + private static final String bucketName = ConfigFactory.Instance().getProperty("index.rockset.s3.bucket"); + private static final String s3Prefix = ConfigFactory.Instance().getProperty("index.rockset.s3.prefix"); + private static final String localDbPath = ConfigFactory.Instance().getProperty("index.rockset.local.data.path"); + private static final String persistentCachePath = ConfigFactory.Instance().getProperty("index.rockset.persistent.cache.path"); + private static final long persistentCacheSizeGB = Long.parseLong(ConfigFactory.Instance().getProperty("index.rockset.persistent.cache.size.gb")); + private static final boolean readOnly = Boolean.parseBoolean(ConfigFactory.Instance().getProperty("index.rockset.read.only")); + /** + * The reference counter. + */ + private static final AtomicInteger reference = new AtomicInteger(0); + private static final Map cfHandles = new ConcurrentHashMap<>(); + private static final String defaultColumnFamily = "default"; // Change for Rockset if needed + + private RocksetFactory() { } + + private static RocksetEnv createRocksetEnv() + { + CloudDBOptions dbOptions = new CloudDBOptions().setBucketName(bucketName).setS3Prefix(s3Prefix) + .setLocalDbPath(localDbPath).setPersistentCachePath(persistentCachePath) + .setPersistentCacheSizeGB(persistentCacheSizeGB).setReadOnly(readOnly); + return RocksetEnv.create(dbOptions.getBucketName(),dbOptions.getS3Prefix()); + } + private static RocksetDB createRocksetDB() + { + // 1. Get existing column families (returns empty list for new database) + List existingColumnFamilies; + try + { + existingColumnFamilies = RocksetDB.listColumnFamilies0(dbPath); + } catch (Exception e) + { + // For new database, return list containing only default column family + existingColumnFamilies = Collections.singletonList(RocksetDB.DEFAULT_COLUMN_FAMILY); + } + // 2. Ensure default column family is included + if (!existingColumnFamilies.contains(RocksetDB.DEFAULT_COLUMN_FAMILY)) + { + existingColumnFamilies = new ArrayList<>(existingColumnFamilies); + existingColumnFamilies.add(RocksetDB.DEFAULT_COLUMN_FAMILY); + } + + if (blockCache == null) + { + blockCache = new RocksetLRUCache(blockCacheCapacity, blockCacheShardBits); + } + + // 3. Prepare column family descriptors + List descriptors = existingColumnFamilies.stream() + .map(RocksetFactory::createCFDescriptor) + .collect(Collectors.toList()); + // 4. Open DB + List handles = new ArrayList<>(); + int maxBackgroundFlushes = Integer.parseInt(ConfigFactory.Instance() + .getProperty("index.rockset.max.background.flushes")); + + int maxBackgroundCompactions = Integer.parseInt(ConfigFactory.Instance() + .getProperty("index.rockset.max.background.compactions")); + + int maxSubcompactions = Integer.parseInt(ConfigFactory.Instance() + .getProperty("index.rockset.max.subcompactions")); + + int maxOpenFiles = Integer.parseInt(ConfigFactory.Instance() + .getProperty("index.rockset.max.open.files")); + + boolean enableStats = Boolean.parseBoolean(ConfigFactory.Instance() + .getProperty("index.rockset.stats.enabled")); + + RocksetDBOptions options = RocksetDBOptions.create() + .setCreateIfMissing(true) + .setCreateMissingColumnFamilies(true) + .setMaxBackgroundFlushes(maxBackgroundFlushes) + .setMaxBackgroundCompactions(maxBackgroundCompactions) + .setMaxSubcompactions(maxSubcompactions) + .setMaxOpenFiles(maxOpenFiles); + + if (enableStats) + { + String statsPath = ConfigFactory.Instance().getProperty("index.rockset.stats.path"); + int statsInterval = Integer.parseInt(ConfigFactory.Instance() + .getProperty("index.rockset.stats.interval")); + RocksetStatistics statistics = new RocksetStatistics(); + options.setStatistics(statistics) + .setStatsDumpPeriodSec(statsInterval) + .setDbLogDir(statsPath); + } + RocksetEnv rocksetEnv = createRocksetEnv(); + RocksetDB db = RocksetDB.open(rocksetEnv, options, dbPath, descriptors, handles); + + // 5. Save handles for reuse + for (int i = 0; i < descriptors.size(); i++) + { + String cfName = new String(descriptors.get(i).getName(), StandardCharsets.UTF_8); + cfHandles.putIfAbsent(cfName, handles.get(i)); + } + return db; + } + + private static RocksetColumnFamilyDescriptor createCFDescriptor(byte[] name) + { + ConfigFactory config = ConfigFactory.Instance(); + + long blockSize = Long.parseLong(config.getProperty("index.rocksdb.block.size")); + RocksetBlockBasedTableConfig tableConfig = new RocksetBlockBasedTableConfig() + .setFilterPolicy(new RocksetBloomFilter(10, false)) + .setWholeKeyFiltering(false) + .setBlockSize(blockSize) + .setBlockCache(blockCache); + + // ColumnFamily Options + long writeBufferSize = Long.parseLong(config.getProperty("index.rocksdb.write.buffer.size")); + int maxWriteBufferNumber = Integer.parseInt(config.getProperty("index.rocksdb.max.write.buffer.number")); + int minWriteBufferNumberToMerge = Integer.parseInt(config.getProperty("index.rocksdb.min.write.buffer.number.to.merge")); + + // Compaction Options + int level0FileNumCompactionTrigger = Integer.parseInt(config.getProperty("index.rocksdb.level0.file.num.compaction.trigger")); + long maxBytesForLevelBase = Long.parseLong(config.getProperty("index.rocksdb.max.bytes.for.level.base")); + int maxBytesForLevelMultiplier = Integer.parseInt(config.getProperty("index.rocksdb.max.bytes.for.level.multiplier")); + long targetFileSizeBase = Long.parseLong(config.getProperty("index.rocksdb.target.file.size.base")); + int targetFileSizeMultiplier = Integer.parseInt(config.getProperty("index.rocksdb.target.file.size.multiplier")); + RocksetCompactionStyle compactionStyle = RocksetCompactionStyle.valueOf(config.getProperty("index.rocksdb.compaction.style")); + + // Compression Options + RocksetCompressionType compressionType = RocksetCompressionType.valueOf(config.getProperty("index.rocksdb.compression.type")); + RocksetCompressionType bottommostCompressionType = RocksetCompressionType.valueOf(config.getProperty("index.rocksdb.bottommost.compression.type")); + + RocksetColumnFamilyOptions cfOptions = new RocksetColumnFamilyOptions() + .setWriteBufferSize(writeBufferSize) + .setMaxWriteBufferNumber(maxWriteBufferNumber) + .setMinWriteBufferNumberToMerge(minWriteBufferNumberToMerge) + .setMemtablePrefixBloomSizeRatio(0.1) + .setTableFormatConfig(tableConfig) + .setLevel0FileNumCompactionTrigger(level0FileNumCompactionTrigger) + .setMaxBytesForLevelBase(maxBytesForLevelBase) + .setMaxBytesForLevelMultiplier(maxBytesForLevelMultiplier) + .setTargetFileSizeBase(targetFileSizeBase) + .setTargetFileSizeMultiplier(targetFileSizeMultiplier) + .setCompressionType(compressionType) + .setBottommostCompressionType(bottommostCompressionType) + .setCompactionStyle(compactionStyle); + + return new RocksetColumnFamilyDescriptor(name, cfOptions); + } + + public static synchronized RocksetColumnFamilyHandle getOrCreateColumnFamily(long tableId, long indexId) throws Exception { + String cfName = getCFName(tableId, indexId); + + // Return cached handle if exists + if (cfHandles.containsKey(cfName)) { + return cfHandles.get(cfName); + } + + RocksetDB db = getRocksetDB(); + RocksetColumnFamilyHandle handle = db.createColumnFamily(cfName.getBytes(StandardCharsets.UTF_8)); + cfHandles.put(cfName, handle); + return handle; + } + + private static String getCFName(long tableId, long indexId) { + if(multiCF) + { + return "t" + tableId + "_i" + indexId; + } + else + { + return defaultColumnFamily; + } + } + + public static synchronized RocksetDB getRocksetDB() throws Exception { + if (rocksetDB == null || rocksetDB.isClosed()) { + rocksetDB = createRocksetDB(); + } + reference.incrementAndGet(); + return rocksetDB; + } + + public static synchronized void close() { + if (rocksetDB != null && reference.decrementAndGet() == 0) { + for (RocksetColumnFamilyHandle handle : cfHandles.values()) { + handle.close(); // Ensure that native handles are properly closed + } + cfHandles.clear(); + // Add closing logic for your native database + rocksetDB.close(); + rocksetDB = null; + } + } + + public static synchronized String getDbPath() { + return dbPath; + } +} + diff --git a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/RocksetIndex.java b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/RocksetIndex.java index b9b54d107b..a8ce93d108 100644 --- a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/RocksetIndex.java +++ b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/RocksetIndex.java @@ -20,154 +20,79 @@ package io.pixelsdb.pixels.index.rockset; import com.google.common.collect.ImmutableList; +import com.google.protobuf.ByteString; import io.pixelsdb.pixels.common.exception.SinglePointIndexException; import io.pixelsdb.pixels.common.index.CachingSinglePointIndex; import io.pixelsdb.pixels.index.IndexProto; +import io.pixelsdb.pixels.index.rockset.jni.*; +import org.apache.commons.io.FileUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import javax.annotation.Nonnull; +import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import java.io.File; +import java.nio.file.Paths; + +import static io.pixelsdb.pixels.index.rockset.RocksetThreadResources.EMPTY_VALUE_BUFFER; + +/** + * @author Rolland1944 + * @create 2025-12-29 + */ public class RocksetIndex extends CachingSinglePointIndex { - private final RocksetIndexStub stub = new RocksetIndexStub(); - - // --------- Small Java wrappers (null-safety & lifecycle) ---------- - protected long CreateDBCloud(@Nonnull CloudDBOptions dbOptions) + // load pixels-index-rockset + static { - long cloudEnvPtr = stub.CreateCloudFileSystem0(dbOptions.getBucketName(), dbOptions.getS3Prefix()); - if (cloudEnvPtr == 0) + String pixelsHome = System.getenv("PIXELS_HOME"); + if (pixelsHome == null || pixelsHome.isEmpty()) { - throw new RuntimeException("Failed to create CloudFileSystem"); + throw new IllegalStateException("Environment variable PIXELS_HOME is not set"); } - long dbHandle = stub.OpenDBCloud0(cloudEnvPtr, dbOptions.getLocalDbPath(), dbOptions.getPersistentCachePath(), - dbOptions.getPersistentCacheSizeGB(), dbOptions.isReadOnly()); - if (dbHandle == 0) + String libPath = Paths.get(pixelsHome, "lib/libpixels-index-rockset.so").toString(); + File libFile = new File(libPath); + if (!libFile.exists()) { - stub.CloseDB0(0); - throw new RuntimeException("Failed to open DBCloud"); + throw new IllegalStateException("libpixels-index-rockset.so not found at " + libPath); } - - return dbHandle; - } - - protected void DBput(long dbHandle, byte[] key, byte[] value) - { - stub.DBput0(dbHandle, key, value); - } - - protected byte[] DBget(long dbHandle, byte[] key) - { - return stub.DBget0(dbHandle, key); - } - - protected void DBdelete(long dbHandle, byte[] key) - { - stub.DBdelete0(dbHandle, key); - } - - protected void CloseDB(long dbHandle) - { - if (dbHandle != 0) + if (!libFile.canRead()) { - stub.CloseDB0(dbHandle); + throw new IllegalStateException("libpixels-index-rockset.so is not readable at " + libPath); } + System.load(libPath); + System.out.println("JNI loaded OK"); } - - // ---------------- Iterator wrapper methods ---------------- - protected long DBNewIterator(long dbHandle) - { - return stub.DBNewIterator0(dbHandle); - } - - protected void IteratorSeekForPrev(long itHandle, byte[] targetKey) - { - stub.IteratorSeekForPrev0(itHandle, targetKey); - } - - protected boolean IteratorIsValid(long itHandle) - { - return stub.IteratorIsValid0(itHandle); - } - - protected byte[] IteratorKey(long itHandle) - { - return stub.IteratorKey0(itHandle); - } - - protected byte[] IteratorValue(long itHandle) - { - return stub.IteratorValue0(itHandle); - } - - protected void IteratorPrev(long itHandle) - { - stub.IteratorPrev0(itHandle); - } - - protected void IteratorClose(long itHandle) - { - stub.IteratorClose0(itHandle); - } - - // ---------------- WriteBatch wrapper methods ---------------- - protected long WriteBatchCreate() - { - return stub.WriteBatchCreate0(); - } - - protected void WriteBatchPut(long wbHandle, byte[] key, byte[] value) - { - stub.WriteBatchPut0(wbHandle, key, value); - } - - protected void WriteBatchDelete(long wbHandle, byte[] key) - { - stub.WriteBatchDelete0(wbHandle, key); - } - - protected boolean DBWrite(long dbHandle, long wbHandle) - { - return stub.DBWrite0(dbHandle, wbHandle); - } - - protected void WriteBatchClear(long wbHandle) - { - stub.WriteBatchClear0(wbHandle); - } - - protected void WriteBatchDestroy(long wbHandle) - { - stub.WriteBatchDestroy0(wbHandle); - } - private static final Logger LOGGER = LogManager.getLogger(RocksetIndex.class); - - private long dbHandle; + private static final long TOMBSTONE_ROW_ID = Long.MAX_VALUE; + private final RocksetDB rocksetDB; + private final String rocksDBPath; + private final RocksetWriteOptions writeOptions; + private final RocksetColumnFamilyHandle columnFamilyHandle; private final long tableId; private final long indexId; private final boolean unique; - private volatile boolean closed = false; - private volatile boolean removed = false; + private final AtomicBoolean closed = new AtomicBoolean(false); + private final AtomicBoolean removed = new AtomicBoolean(false); - public RocksetIndex(long tableId, long indexId, CloudDBOptions options, boolean unique) - { + public RocksetIndex(long tableId, long indexId, boolean unique) throws Exception { this.tableId = tableId; this.indexId = indexId; + this.rocksDBPath = RocksetFactory.getDbPath(); + this.rocksetDB = RocksetFactory.getRocksetDB(); this.unique = unique; - this.dbHandle = CreateDBCloud(options); + this.writeOptions = RocksetWriteOptions.create(); + this.columnFamilyHandle = RocksetFactory.getOrCreateColumnFamily(tableId, indexId); } // ---------------- SinglePointIndex interface ---------------- - protected long getDbHandle() - { - return dbHandle; - } - @Override public long getTableId() { @@ -187,71 +112,73 @@ public boolean isUnique() } @Override - public long getUniqueRowIdInternal(IndexProto.IndexKey key) - { - byte[] prefix = toByteArray(key); // indexId + key (NO timestamp) - long ts = key.getTimestamp(); - byte[] upperKey = concat(prefix, writeLongBE(ts + 1)); - long it = 0; - try + public long getUniqueRowIdInternal(IndexProto.IndexKey key) throws SinglePointIndexException { + if (!unique) { - it = DBNewIterator(this.dbHandle); - IteratorSeekForPrev(it, upperKey); - if (!IteratorIsValid(it)) - return -1L; - byte[] k = IteratorKey(it); - if (!startsWith(k, prefix)) - return -1L; - byte[] v = IteratorValue(it); - if (v == null || v.length < Long.BYTES) return -1L; - return ByteBuffer.wrap(v).getLong(); + throw new SinglePointIndexException("getUniqueRowId should only be called on unique index"); } - catch (Throwable t) + RocksetReadOptions readOptions = RocksetThreadResources.getReadOptions(); + readOptions.setPrefixSameAsStart(true); + ByteBuffer keyBuffer = toKeyBuffer(key); + long rowId = -1L; + try (RocksetIterator iterator = rocksetDB.newIterator(columnFamilyHandle,readOptions)) { - LOGGER.error("getUniqueRowId failed", t); - return -1L; - } - finally + iterator.seek(keyBuffer); + if (iterator.isValid()) + { + ByteBuffer keyFound = ByteBuffer.wrap(iterator.key()); + if (startsWith(keyFound, keyBuffer)) + { + ByteBuffer valueBuffer = RocksetThreadResources.getValueBuffer(); + valueBuffer = ByteBuffer.wrap(iterator.value()); + rowId = valueBuffer.getLong(); + rowId = rowId == TOMBSTONE_ROW_ID ? -1L : rowId; + } + } + } catch (Exception e) { - if (it != 0) - IteratorClose(it); + throw new SinglePointIndexException("Error reading from Rockset CF for tableId=" + + tableId + ", indexId=" + indexId, e); } + return rowId; } @Override - public List getRowIds(IndexProto.IndexKey key) - { - ImmutableList.Builder out = ImmutableList.builder(); - byte[] prefix = toByteArray(key); - long ts = key.getTimestamp(); - byte[] upperKey = concat(prefix, writeLongBE(ts + 1)); - long it = 0; - try + public List getRowIds(IndexProto.IndexKey key) throws SinglePointIndexException { + if (unique) { - it = DBNewIterator(this.dbHandle); - IteratorSeekForPrev(it, upperKey); - while (IteratorIsValid(it)) + return ImmutableList.of(getUniqueRowId(key)); + } + Set rowIds = new HashSet<>(); + RocksetReadOptions readOptions = RocksetThreadResources.getReadOptions(); + readOptions.setPrefixSameAsStart(true); + ByteBuffer keyBuffer = toKeyBuffer(key); + try (RocksetIterator iterator = rocksetDB.newIterator(columnFamilyHandle,readOptions)) + { + iterator.seek(keyBuffer); + while (iterator.isValid()) { - byte[] k = IteratorKey(it); - if (!startsWith(k, prefix)) + ByteBuffer keyFound = ByteBuffer.wrap(iterator.key()); + if (startsWith(keyFound, keyBuffer)) + { + long rowId = extractRowIdFromKey(keyFound); + if (rowId == TOMBSTONE_ROW_ID) + { + break; + } + rowIds.add(rowId); + iterator.next(); + } + else + { break; - long rowId = extractRowIdFromKey(k); - if (rowId < 0) break; - out.add(rowId); - IteratorPrev(it); + } } + } catch (Exception e) { + throw new SinglePointIndexException("Error reading from Rockset CF for tableId=" + + tableId + ", indexId=" + indexId, e); } - catch (Throwable t) - { - LOGGER.error("getRowIds failed", t); - return ImmutableList.of(); - } - finally - { - if (it != 0) - IteratorClose(it); - } - return out.build(); + return ImmutableList.copyOf(rowIds); } @Override @@ -261,14 +188,15 @@ public boolean putEntryInternal(IndexProto.IndexKey key, long rowId) throws Sing { if (unique) { - byte[] fullKey = concat(toByteArray(key), writeLongBE(key.getTimestamp())); - byte[] val = writeLongBE(rowId); - DBput(this.dbHandle, fullKey, val); + ByteBuffer keyBuffer = toKeyBuffer(key); + ByteBuffer valueBuffer = RocksetThreadResources.getValueBuffer(); + valueBuffer.putLong(rowId).position(0); + rocksetDB.put(columnFamilyHandle, writeOptions, keyBuffer, valueBuffer); } else { - byte[] nonUniqueKey = toNonUniqueKey(key, rowId); - DBput(this.dbHandle, nonUniqueKey, new byte[0]); + ByteBuffer nonUniqueKeyBuffer = toNonUniqueKeyBuffer(key, rowId); + rocksetDB.put(columnFamilyHandle, writeOptions, nonUniqueKeyBuffer, EMPTY_VALUE_BUFFER); } return true; } @@ -282,85 +210,76 @@ public boolean putEntryInternal(IndexProto.IndexKey key, long rowId) throws Sing public boolean putPrimaryEntriesInternal(List entries) throws SinglePointIndexException { - long wb = 0; - try + if (!unique) + { + throw new SinglePointIndexException("putPrimaryEntries can only be called on unique indexes"); + } + try(RocksetWriteBatch writeBatch = RocksetWriteBatch.create()) { - wb = WriteBatchCreate(); for (IndexProto.PrimaryIndexEntry entry : entries) { IndexProto.IndexKey key = entry.getIndexKey(); long rowId = entry.getRowId(); - byte[] fullKey = concat(toByteArray(key), writeLongBE(key.getTimestamp())); - byte[] val = writeLongBE(rowId); - WriteBatchPut(wb, fullKey, val); + ByteBuffer keyBuffer = toKeyBuffer(key); + ByteBuffer valueBuffer = RocksetThreadResources.getValueBuffer(); + valueBuffer.putLong(rowId).position(0); + writeBatch.put(columnFamilyHandle, keyBuffer, valueBuffer); } - DBWrite(this.dbHandle, wb); + rocksetDB.write(writeOptions,writeBatch); return true; } catch (Exception e) { throw new SinglePointIndexException("Failed to put rockset primary index entries", e); } - finally - { - if (wb != 0) - { - WriteBatchClear(wb); - WriteBatchDestroy(wb); - } - } } @Override public boolean putSecondaryEntriesInternal(List entries) throws SinglePointIndexException { - long wb = 0; - try + try (RocksetWriteBatch writeBatch = RocksetWriteBatch.create()) { - wb = WriteBatchCreate(); for (IndexProto.SecondaryIndexEntry entry : entries) { IndexProto.IndexKey key = entry.getIndexKey(); long rowId = entry.getRowId(); if (unique) { - byte[] fullKey = concat(toByteArray(key), writeLongBE(key.getTimestamp())); - byte[] val = writeLongBE(rowId); - WriteBatchPut(wb, fullKey, val); + ByteBuffer keyBuffer = toKeyBuffer(key); + ByteBuffer valueBuffer = RocksetThreadResources.getValueBuffer(); + valueBuffer.putLong(rowId).position(0); + writeBatch.put(columnFamilyHandle, keyBuffer, valueBuffer); } else { - byte[] nonUniqueKey = toNonUniqueKey(key, rowId); - WriteBatchPut(wb, nonUniqueKey, new byte[0]); + ByteBuffer nonUniqueKeyBuffer = toNonUniqueKeyBuffer(key, rowId); + writeBatch.put(columnFamilyHandle, nonUniqueKeyBuffer, EMPTY_VALUE_BUFFER); } } - DBWrite(this.dbHandle, wb); + rocksetDB.write(writeOptions,writeBatch); return true; } catch (Exception e) { throw new SinglePointIndexException("Failed to put rockset secondary index entries", e); } - finally - { - if (wb != 0) - { - WriteBatchClear(wb); - WriteBatchDestroy(wb); - } - } } @Override public long updatePrimaryEntryInternal(IndexProto.IndexKey key, long rowId) throws SinglePointIndexException { + if (!unique) + { + throw new SinglePointIndexException("updatePrimaryEntry can only be called on unique indexes"); + } try { - long prev = getUniqueRowId(key); - byte[] fullKey = concat(toByteArray(key), writeLongBE(key.getTimestamp())); - byte[] val = writeLongBE(rowId); - DBput(this.dbHandle, fullKey, val); - return prev; + long prevRowId = getUniqueRowId(key); + ByteBuffer keyBuffer = toKeyBuffer(key); + ByteBuffer valueBuffer = RocksetThreadResources.getValueBuffer(); + valueBuffer.putLong(rowId).position(0); + rocksetDB.put(columnFamilyHandle, writeOptions, keyBuffer, valueBuffer); + return prevRowId; } catch (Exception e) { @@ -376,16 +295,21 @@ public List updateSecondaryEntryInternal(IndexProto.IndexKey key, long row ImmutableList.Builder prev = ImmutableList.builder(); if (unique) { - prev.add(getUniqueRowId(key)); - byte[] fullKey = concat(toByteArray(key), writeLongBE(key.getTimestamp())); - DBput(this.dbHandle, fullKey, writeLongBE(rowId)); + long prevRowId = getUniqueRowId(key); + if (prevRowId >= 0) + { + prev.add(prevRowId); + } + ByteBuffer keyBuffer = toKeyBuffer(key); + ByteBuffer valueBuffer = RocksetThreadResources.getValueBuffer(); + valueBuffer.putLong(rowId).position(0); + rocksetDB.put(columnFamilyHandle, writeOptions, keyBuffer, valueBuffer); } else { - List rowIds = getRowIds(key); - prev.addAll(rowIds); - byte[] nonUniqueKey = toNonUniqueKey(key, rowId); - DBput(this.dbHandle, nonUniqueKey, new byte[0]); + prev.addAll(this.getRowIds(key)); + ByteBuffer nonUniqueKeyBuffer = toNonUniqueKeyBuffer(key, rowId); + rocksetDB.put(columnFamilyHandle, writeOptions, nonUniqueKeyBuffer, EMPTY_VALUE_BUFFER); } return prev.build(); } @@ -398,47 +322,41 @@ public List updateSecondaryEntryInternal(IndexProto.IndexKey key, long row @Override public List updatePrimaryEntriesInternal(List entries) throws SinglePointIndexException { - long wb = 0; - try + if (!unique) + { + throw new SinglePointIndexException("updatePrimaryEntries can only be called on unique indexes"); + } + try (RocksetWriteBatch writeBatch = RocksetWriteBatch.create()) { - wb = WriteBatchCreate(); ImmutableList.Builder prevRowIds = ImmutableList.builder(); for (IndexProto.PrimaryIndexEntry entry : entries) { IndexProto.IndexKey key = entry.getIndexKey(); + long rowId = entry.getRowId(); long prevRowId = getUniqueRowId(key); - if (prevRowId < 0) + if (prevRowId >= 0) { - return ImmutableList.of(); + prevRowIds.add(prevRowId); } - prevRowIds.add(prevRowId); - byte[] fullKey = concat(toByteArray(key), writeLongBE(key.getTimestamp())); - WriteBatchPut(wb, fullKey, writeLongBE(entry.getRowId())); + ByteBuffer keyBuffer = toKeyBuffer(key); + ByteBuffer valueBuffer = RocksetThreadResources.getValueBuffer(); + valueBuffer.putLong(rowId).position(0); + writeBatch.put(columnFamilyHandle, keyBuffer, valueBuffer); } - DBWrite(this.dbHandle, wb); + rocksetDB.write(writeOptions,writeBatch); return prevRowIds.build(); } catch (Exception e) { throw new SinglePointIndexException("Failed to update primary index entries", e); } - finally - { - if (wb != 0) - { - WriteBatchClear(wb); - WriteBatchDestroy(wb); - } - } } @Override public List updateSecondaryEntriesInternal(List entries) throws SinglePointIndexException { - long wb = 0; - try + try (RocksetWriteBatch writeBatch = RocksetWriteBatch.create()) { - wb = WriteBatchCreate(); ImmutableList.Builder prevRowIds = ImmutableList.builder(); for (IndexProto.SecondaryIndexEntry entry : entries) { @@ -447,54 +365,50 @@ public List updateSecondaryEntriesInternal(List= 0) { - return ImmutableList.of(); + prevRowIds.add(prevRowId); } - prevRowIds.add(prevRowId); - byte[] fullKey = concat(toByteArray(key), writeLongBE(key.getTimestamp())); - WriteBatchPut(wb, fullKey, writeLongBE(rowId)); + ByteBuffer keyBuffer = toKeyBuffer(key); + ByteBuffer valueBuffer = RocksetThreadResources.getValueBuffer(); + valueBuffer.putLong(rowId).position(0); + writeBatch.put(columnFamilyHandle, keyBuffer, valueBuffer); } else { - List rowIds = getRowIds(key); - if (rowIds.isEmpty()) - { - return ImmutableList.of(); - } - prevRowIds.addAll(rowIds); - byte[] nonUniqueKey = toNonUniqueKey(key, rowId); - WriteBatchPut(wb, nonUniqueKey, new byte[0]); + prevRowIds.addAll(this.getRowIds(key)); + ByteBuffer nonUniqueKeyBuffer = toNonUniqueKeyBuffer(key, rowId); + writeBatch.put(columnFamilyHandle, nonUniqueKeyBuffer, EMPTY_VALUE_BUFFER); } } - DBWrite(this.dbHandle, wb); + rocksetDB.write(writeOptions,writeBatch); return prevRowIds.build(); } catch (Exception e) { throw new SinglePointIndexException("Failed to update secondary index entries", e); } - finally - { - if (wb != 0) - { - WriteBatchClear(wb); - WriteBatchDestroy(wb); - } - } } @Override public long deleteUniqueEntryInternal(IndexProto.IndexKey key) throws SinglePointIndexException { + if (!unique) + { + throw new SinglePointIndexException("deleteUniqueEntry can only be called on unique indexes"); + } try { - long prev = getUniqueRowId(key); - byte[] tomb = writeLongBE(-1L); // tombstone marker - byte[] fullKey = concat(toByteArray(key), writeLongBE(key.getTimestamp())); - DBput(this.dbHandle, fullKey, tomb); - - return prev; + long rowId = getUniqueRowId(key); + if (rowId < 0) + { + return rowId; + } + ByteBuffer keyBuffer = toKeyBuffer(key); + ByteBuffer valueBuffer = RocksetThreadResources.getValueBuffer(); + valueBuffer.putLong(TOMBSTONE_ROW_ID).position(0); + rocksetDB.put(columnFamilyHandle, writeOptions, keyBuffer, valueBuffer); + return rowId; } catch (Exception e) { @@ -505,11 +419,9 @@ public long deleteUniqueEntryInternal(IndexProto.IndexKey key) throws SinglePoin @Override public List deleteEntryInternal(IndexProto.IndexKey key) throws SinglePointIndexException { - long wb = 0; - try + try (RocksetWriteBatch writeBatch = RocksetWriteBatch.create()) { ImmutableList.Builder prev = ImmutableList.builder(); - wb = WriteBatchCreate(); if (unique) { long rowId = getUniqueRowId(key); @@ -518,8 +430,10 @@ public List deleteEntryInternal(IndexProto.IndexKey key) throws SinglePoin return ImmutableList.of(); } prev.add(rowId); - byte[] fullKey = concat(toByteArray(key), writeLongBE(key.getTimestamp())); - WriteBatchPut(wb, fullKey, writeLongBE(-1L)); + ByteBuffer keyBuffer = toKeyBuffer(key); + ByteBuffer valueBuffer = RocksetThreadResources.getValueBuffer(); + valueBuffer.putLong(TOMBSTONE_ROW_ID).position(0); + writeBatch.put(columnFamilyHandle, keyBuffer, valueBuffer); } else { @@ -529,108 +443,105 @@ public List deleteEntryInternal(IndexProto.IndexKey key) throws SinglePoin return ImmutableList.of(); } prev.addAll(rowIds); - // mark tombstone entry for this (key, -1L) - byte[] nonUniqueKeyTomb = toNonUniqueKey(key, -1L); - WriteBatchPut(wb, nonUniqueKeyTomb, new byte[0]); + ByteBuffer nonUniqueKeyBuffer = toNonUniqueKeyBuffer(key, TOMBSTONE_ROW_ID); + writeBatch.put(columnFamilyHandle, nonUniqueKeyBuffer, EMPTY_VALUE_BUFFER); } - DBWrite(this.dbHandle, wb); + rocksetDB.write(writeOptions,writeBatch); return prev.build(); } catch (Exception e) { throw new SinglePointIndexException("Failed to delete entry", e); } - finally - { - if (wb != 0) - { - WriteBatchClear(wb); - WriteBatchDestroy(wb); - } - } } @Override public List deleteEntriesInternal(List keys) throws SinglePointIndexException { - long wb = 0; - try + try (RocksetWriteBatch writeBatch = RocksetWriteBatch.create()) { - wb = WriteBatchCreate(); ImmutableList.Builder prev = ImmutableList.builder(); for (IndexProto.IndexKey key : keys) { if (unique) { long rowId = getUniqueRowId(key); - if (rowId < 0) + if(rowId >= 0) { - return ImmutableList.of(); + prev.add(rowId); + ByteBuffer keyBuffer = toKeyBuffer(key); + ByteBuffer valueBuffer = RocksetThreadResources.getValueBuffer(); + valueBuffer.putLong(TOMBSTONE_ROW_ID).position(0); + writeBatch.put(columnFamilyHandle, keyBuffer, valueBuffer); } - prev.add(rowId); - byte[] fullKey = concat(toByteArray(key), writeLongBE(key.getTimestamp())); - WriteBatchPut(wb, fullKey, writeLongBE(-1L)); } else { List rowIds = getRowIds(key); - if (rowIds.isEmpty()) + if(!rowIds.isEmpty()) { - return ImmutableList.of(); + prev.addAll(rowIds); + ByteBuffer nonUniqueKeyBuffer = toNonUniqueKeyBuffer(key, TOMBSTONE_ROW_ID); + writeBatch.put(columnFamilyHandle, nonUniqueKeyBuffer, EMPTY_VALUE_BUFFER); } - prev.addAll(rowIds); - byte[] nonUniqueKeyTomb = toNonUniqueKey(key, -1L); - WriteBatchPut(wb, nonUniqueKeyTomb, new byte[0]); } } - DBWrite(this.dbHandle, wb); + rocksetDB.write(writeOptions,writeBatch); return prev.build(); } catch (Exception e) { throw new SinglePointIndexException("Failed to delete entries", e); } - finally - { - if (wb != 0) - { - WriteBatchClear(wb); - WriteBatchDestroy(wb); - } - } } @Override public List purgeEntriesInternal(List indexKeys) throws SinglePointIndexException { ImmutableList.Builder builder = ImmutableList.builder(); - long wb = 0; - try + try (RocksetWriteBatch writeBatch = RocksetWriteBatch.create()) { - wb = WriteBatchCreate(); for (IndexProto.IndexKey key : indexKeys) { - byte[] prefix = toByteArray(key); // indexId + key (NO timestamp) - long ts = key.getTimestamp(); - byte[] upperKey = concat(prefix, writeLongBE(ts + 1)); - long it = 0; - try + RocksetReadOptions readOptions = RocksetThreadResources.getReadOptions(); + readOptions.setPrefixSameAsStart(true); + ByteBuffer keyBuffer = toKeyBuffer(key); + try (RocksetIterator iterator = rocksetDB.newIterator(columnFamilyHandle,readOptions)) { - it = DBNewIterator(this.dbHandle); - IteratorSeekForPrev(it, upperKey); - while (IteratorIsValid(it)) + + iterator.seek(keyBuffer); + boolean foundTombstone = false; + while (iterator.isValid()) { - byte[] k = IteratorKey(it); - if (startsWith(k, prefix)) + ByteBuffer keyFound = ByteBuffer.wrap(iterator.key()); + if (startsWith(keyFound, keyBuffer)) { + long rowId; if(unique) { - long rowId = ByteBuffer.wrap(IteratorValue(it)).getLong(); - if(rowId > 0) - builder.add(rowId); + ByteBuffer valueBuffer = RocksetThreadResources.getValueBuffer(); + valueBuffer = ByteBuffer.wrap(iterator.value()); + rowId = valueBuffer.getLong(); + } + else + { + rowId = extractRowIdFromKey(keyFound); + } + iterator.next(); + if (rowId == TOMBSTONE_ROW_ID) + { + foundTombstone = true; + } + else if(foundTombstone) + { + builder.add(rowId); } - WriteBatchDelete(wb, k); - IteratorPrev(it); + else + { + continue; + } + // keyFound is not direct, must use its backing array + writeBatch.delete(columnFamilyHandle, keyFound.array()); } else { @@ -643,96 +554,131 @@ public List purgeEntriesInternal(List indexKeys) thro LOGGER.error("purgeEntries failed", t); return ImmutableList.of(); } - finally - { - if (it != 0) - IteratorClose(it); - } } - DBWrite(this.dbHandle, wb); + rocksetDB.write(writeOptions,writeBatch); return builder.build(); } catch (Exception e) { throw new SinglePointIndexException("Failed to purge entries by prefix", e); } - finally - { - if (wb != 0) - { - WriteBatchClear(wb); - WriteBatchDestroy(wb); - } - } } @Override public void close() throws IOException { - if (dbHandle != 0) + if (closed.compareAndSet(false, true)) { - closed = true; - this.dbHandle = 0; + // Issue #1158: do not directly close the rocksDB instance as it is shared by other indexes + RocksetFactory.close(); + writeOptions.close(); } } @Override public boolean closeAndRemove() throws SinglePointIndexException { - try + if (closed.compareAndSet(false, true) && removed.compareAndSet(false, true)) { - close(); - removed = true; // no local RocksDB folder to delete for cloud; mark removed + try + { + // Issue #1158: do not directly close the rocksDB instance as it is shared by other indexes + RocksetFactory.close(); + writeOptions.close(); + FileUtils.deleteDirectory(new File(rocksDBPath)); + } + catch (IOException e) + { + throw new SinglePointIndexException("Failed to close and cleanup the RocksDB index", e); + } return true; } - catch (IOException e) - { - throw new SinglePointIndexException("Failed to close rockset index", e); - } + return false; } // ----------------- Encoding helpers ----------------- - private byte[] toByteArray(IndexProto.IndexKey key) + protected static ByteBuffer toBuffer(long indexId, ByteString key, int bufferNum, long... postValues) + throws SinglePointIndexException { - // prefix = indexId(8 bytes, BE) + raw key bytes - byte[] indexIdBytes = writeLongBE(this.indexId); - byte[] rawKey = key.getKey().toByteArray(); - return concat(indexIdBytes, rawKey); + int keySize = key.size(); + int totalLength = Long.BYTES + keySize + Long.BYTES * postValues.length; + ByteBuffer compositeKey; + if (bufferNum == 1) + { + compositeKey = RocksetThreadResources.getKeyBuffer(totalLength); + } + else if (bufferNum == 2) + { + compositeKey = RocksetThreadResources.getKeyBuffer2(totalLength); + } + else if (bufferNum == 3) + { + compositeKey = RocksetThreadResources.getKeyBuffer3(totalLength); + } + else + { + throw new SinglePointIndexException("Invalid buffer number"); + } + // Write indexId (8 bytes, big endian) + compositeKey.putLong(indexId); + // Write key bytes (variable length) + key.copyTo(compositeKey); + // Write post values (8 bytes each, big endian) + for (long postValue : postValues) + { + compositeKey.putLong(postValue); + } + compositeKey.position(0); + return compositeKey; } - private byte[] toNonUniqueKey(IndexProto.IndexKey key, long rowId) + protected static ByteBuffer toKeyBuffer(IndexProto.IndexKey key) throws SinglePointIndexException { - // prefix + timestamp + rowId - return concat(concat(toByteArray(key), writeLongBE(key.getTimestamp())), writeLongBE(rowId)); + return toBuffer(key.getIndexId(), key.getKey(), 1, Long.MAX_VALUE - key.getTimestamp()); } - private static byte[] concat(byte[] a, byte[] b) + protected static ByteBuffer toNonUniqueKeyBuffer(IndexProto.IndexKey key, long rowId) throws SinglePointIndexException { - byte[] out = new byte[a.length + b.length]; - System.arraycopy(a, 0, out, 0, a.length); - System.arraycopy(b, 0, out, a.length, b.length); - return out; + return toBuffer(key.getIndexId(), key.getKey(), 1, + Long.MAX_VALUE - key.getTimestamp(), Long.MAX_VALUE - rowId); } - private static boolean startsWith(byte[] key, byte[] prefix) + // check if byte array starts with specified prefix + protected static boolean startsWith(ByteBuffer keyFound, ByteBuffer keyCurrent) { - if (key.length < prefix.length) return false; - for (int i = 0; i < prefix.length; i++) + // prefix is indexId + key, without timestamp + int prefixLength = keyCurrent.limit() - Long.BYTES; + if (keyFound.limit() < prefixLength) { - if (key[i] != prefix[i]) return false; + return false; } - return true; + keyFound.position(0); + keyCurrent.position(0); + ByteBuffer keyFound1 = keyFound.slice(); + keyFound1.limit(prefixLength); + ByteBuffer keyCurrent1 = keyCurrent.slice(); + keyCurrent1.limit(prefixLength); + return keyFound1.compareTo(keyCurrent1) == 0; } - private static long extractRowIdFromKey(byte[] fullKey) + // extract rowId from non-unique key + protected static long extractRowIdFromKey(ByteBuffer keyBuffer) { - if (fullKey.length < Long.BYTES) return -1L; - int off = fullKey.length - Long.BYTES; - return ByteBuffer.wrap(fullKey, off, Long.BYTES).getLong(); + // extract rowId portion (last 8 bytes of key) + return Long.MAX_VALUE - keyBuffer.getLong(keyBuffer.limit() - Long.BYTES); } private static byte[] writeLongBE(long v) { return ByteBuffer.allocate(Long.BYTES).putLong(v).array(); } + + public static byte[] byteBufferToByteArray(ByteBuffer byteBuffer) { + if (byteBuffer == null) { + return null; + } + byte[] byteArray = new byte[byteBuffer.remaining()]; + byteBuffer.get(byteArray); + return byteArray; + } } diff --git a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/RocksetIndexProvider.java b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/RocksetIndexProvider.java index ca9682d6b2..2fe3ac9661 100644 --- a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/RocksetIndexProvider.java +++ b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/RocksetIndexProvider.java @@ -50,7 +50,7 @@ public SinglePointIndex createInstance(long tableId, long indexId, @Nonnull Sing CloudDBOptions dbOptions = new CloudDBOptions().setBucketName(bucketName).setS3Prefix(s3Prefix) .setLocalDbPath(localDbPath).setPersistentCachePath(persistentCachePath) .setPersistentCacheSizeGB(persistentCacheSizeGB).setReadOnly(readOnly); - return new RocksetIndex(tableId, indexId, dbOptions, unique); + return new RocksetIndex(tableId, indexId, unique); } catch (Exception e) { diff --git a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/RocksetIndexStub.java b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/RocksetIndexStub.java deleted file mode 100644 index f853b8765f..0000000000 --- a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/RocksetIndexStub.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2025 PixelsDB. - * - * This file is part of Pixels. - * - * Pixels is free software: you can redistribute it and/or modify - * it under the terms of the Affero GNU General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * Pixels is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Affero GNU General Public License for more details. - * - * You should have received a copy of the Affero GNU General Public - * License along with Pixels. If not, see - * . - */ -package io.pixelsdb.pixels.index.rockset; - -import java.io.File; -import java.nio.file.Paths; - -public class RocksetIndexStub -{ - // load pixels-index-rockset - static - { - String pixelsHome = System.getenv("PIXELS_HOME"); - if (pixelsHome == null || pixelsHome.isEmpty()) - { - throw new IllegalStateException("Environment variable PIXELS_HOME is not set"); - } - - String libPath = Paths.get(pixelsHome, "lib/libpixels-index-rockset.so").toString(); - File libFile = new File(libPath); - if (!libFile.exists()) - { - throw new IllegalStateException("libpixels-index-rockset.so not found at " + libPath); - } - if (!libFile.canRead()) - { - throw new IllegalStateException("libpixels-index-rockset.so is not readable at " + libPath); - } - System.load(libPath); - } - // ---------- JNI native bindings ---------- - public native long CreateCloudFileSystem0( - String bucketName, - String s3Prefix); - public native long OpenDBCloud0( - long cloudEnvPtr, - String localDbPath, - String persistentCachePath, - long persistentCacheSizeGB, - boolean readOnly); - public native void DBput0(long dbHandle, byte[] key, byte[] valueOrNull); - public native byte[] DBget0(long dbHandle, byte[] key); - public native void DBdelete0(long dbHandle, byte[] key); - public native void CloseDB0(long dbHandle); - - // iterator - public native long DBNewIterator0(long dbHandle); - public native void IteratorSeekForPrev0(long itHandle, byte[] targetKey); - public native boolean IteratorIsValid0(long itHandle); - public native byte[] IteratorKey0(long itHandle); - public native byte[] IteratorValue0(long itHandle); - public native void IteratorPrev0(long itHandle); - public native void IteratorClose0(long itHandle); - - // write batch - public native long WriteBatchCreate0(); - public native void WriteBatchPut0(long wbHandle, byte[] key, byte[] value); - public native void WriteBatchDelete0(long wbHandle, byte[] key); - public native boolean DBWrite0(long dbHandle, long wbHandle); - public native void WriteBatchClear0(long wbHandle); - public native void WriteBatchDestroy0(long wbHandle); -} \ No newline at end of file diff --git a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/RocksetThreadResources.java b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/RocksetThreadResources.java new file mode 100644 index 0000000000..b8b2e8ac56 --- /dev/null +++ b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/RocksetThreadResources.java @@ -0,0 +1,142 @@ + +/* + * Copyright 2025 PixelsDB. + * + * This file is part of Pixels. + * + * Pixels is free software: you can redistribute it and/or modify + * it under the terms of the Affero GNU General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * Pixels is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Affero GNU General Public License for more details. + * + * You should have received a copy of the Affero GNU General Public + * License along with Pixels. If not, see + * . + */ +package io.pixelsdb.pixels.index.rockset; + +import io.pixelsdb.pixels.common.index.ThreadId; +import io.pixelsdb.pixels.common.utils.ShutdownHookManager; +import io.pixelsdb.pixels.index.rockset.jni.RocksetReadOptions; + +import java.nio.ByteBuffer; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +final class RocksetThreadResources { + private static final ThreadLocal threadIds = ThreadLocal.withInitial(ThreadId::new); + /** + * Thread-local ReadOptions for each thread. + */ + private static final Map threadReadOptions = new ConcurrentHashMap<>(); + private static final Map threadKeyBuffers = new ConcurrentHashMap<>(); + private static final Map threadKeyBuffers2 = new ConcurrentHashMap<>(); + private static final Map threadKeyBuffers3 = new ConcurrentHashMap<>(); + private static final Map threadKeyBuffers4 = new ConcurrentHashMap<>(); + private static final Map threadValueBuffers = new ConcurrentHashMap<>(); + + private static final int DEFAULT_KEY_LENGTH = 32; + private static final int VALUE_LENGTH = 8; + + static final ByteBuffer EMPTY_VALUE_BUFFER = ByteBuffer.allocateDirect(0); + + static { + // Release resources when the process is shutting down. + ShutdownHookManager.Instance().registerShutdownHook( + RocksetThreadResources.class, false, RocksetThreadResources::release); + } + + private RocksetThreadResources() { } + + /** + * Get the current thread's ReadOptions. + */ + static RocksetReadOptions getReadOptions() { + ThreadId threadId = threadIds.get(); + RocksetReadOptions readOptions = threadReadOptions.get(threadId); + if (readOptions == null) { + readOptions = RocksetReadOptions.create(); + threadReadOptions.put(threadId, readOptions); + } + return readOptions; + } + + /** + * Get the current thread's key buffer. + */ + static ByteBuffer getKeyBuffer(int length) { + return internalGetKeyBuffer(threadKeyBuffers, length); + } + + /** + * Get the current thread's second key buffer. + */ + static ByteBuffer getKeyBuffer2(int length) { + return internalGetKeyBuffer(threadKeyBuffers2, length); + } + + /** + * Get the current thread's third key buffer. + */ + static ByteBuffer getKeyBuffer3(int length) { + return internalGetKeyBuffer(threadKeyBuffers3, length); + } + + /** + * Get the current thread's fourth key buffer. + */ + static ByteBuffer getKeyBuffer4(int length) { + return internalGetKeyBuffer(threadKeyBuffers4, length); + } + + static ByteBuffer internalGetKeyBuffer(Map keyBuffers, int length) + { + ThreadId threadId = threadIds.get(); + ByteBuffer keyBuffer = keyBuffers.get(threadId); + // no need to add a lock as concurrent threads have unique thread ids + if (keyBuffer == null) + { + keyBuffer = ByteBuffer.allocateDirect(Math.max(length, DEFAULT_KEY_LENGTH)); + keyBuffers.put(threadId, keyBuffer); + } + else if (keyBuffer.capacity() < length) + { + keyBuffer = ByteBuffer.allocateDirect(length); + keyBuffers.put(threadId, keyBuffer); + } + keyBuffer.position(0); + keyBuffer.limit(length); + return keyBuffer; + } + + /** + * Get the current thread's value buffer. + */ + static ByteBuffer getValueBuffer() + { + ThreadId threadId = threadIds.get(); + // no need to add a lock as concurrent threads have unique thread ids + ByteBuffer valueBuffer = threadValueBuffers.computeIfAbsent(threadId, + k -> ByteBuffer.allocateDirect(VALUE_LENGTH)); + valueBuffer.position(0); + valueBuffer.limit(VALUE_LENGTH); + return valueBuffer; + } + + private static void release() { + threadReadOptions.forEach((threadId, ctx) -> ctx.close()); + threadReadOptions.clear(); + threadValueBuffers.clear(); + threadKeyBuffers.clear(); + threadKeyBuffers2.clear(); + threadKeyBuffers3.clear(); + threadKeyBuffers4.clear(); + } +} + + diff --git a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/Filter.java b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/Filter.java new file mode 100644 index 0000000000..5149b83489 --- /dev/null +++ b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/Filter.java @@ -0,0 +1,21 @@ +package io.pixelsdb.pixels.index.rockset.jni; + +public abstract class Filter extends RocksetHandle +{ + protected Filter(long var1) + { + super(var1); + } + + protected void disposeInternal() + { + this.disposeInternal(this.nativeHandle); + } + + protected final void disposeInternal(long var1) + { + disposeInternalJni(var1); + } + + private static native void disposeInternalJni(long var0); +} diff --git a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetBlockBasedTableConfig.java b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetBlockBasedTableConfig.java new file mode 100644 index 0000000000..660d6093a5 --- /dev/null +++ b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetBlockBasedTableConfig.java @@ -0,0 +1,66 @@ +package io.pixelsdb.pixels.index.rockset.jni; + +public class RocksetBlockBasedTableConfig extends RocksetTableFormatConfig +{ + private Filter filterPolicy; + private boolean wholeKeyFiltering; + private long blockSize; + private RocksetCache blockCache; + + public RocksetBlockBasedTableConfig() + { + this.blockCache = null; + this.blockSize = 4096L; + this.filterPolicy = null; + this.wholeKeyFiltering = true; + } + + @Override + protected long newTableFactoryHandle() + { + long var1; + if (this.filterPolicy != null) + { + var1 = this.filterPolicy.nativeHandle; + } else + { + var1 = 0L; + } + + long var3; + if (this.blockCache != null) + { + var3 = this.blockCache.nativeHandle; + } else + { + var3 = 0L; + } + + return newTableFactoryHandle(var3, this.blockSize, var1, this.wholeKeyFiltering); + } + + public RocksetBlockBasedTableConfig setFilterPolicy(Filter var1) + { + this.filterPolicy = var1; + return this; + } + public RocksetBlockBasedTableConfig setWholeKeyFiltering(boolean var1) + { + this.wholeKeyFiltering = var1; + return this; + } + + public RocksetBlockBasedTableConfig setBlockSize(long var1) + { + this.blockSize = var1; + return this; + } + + public RocksetBlockBasedTableConfig setBlockCache(RocksetCache var1) + { + this.blockCache = var1; + return this; + } + + private static native long newTableFactoryHandle(long var1, long var2, long var3, boolean var4); +} diff --git a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetBloomFilter.java b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetBloomFilter.java new file mode 100644 index 0000000000..02c2a822ae --- /dev/null +++ b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetBloomFilter.java @@ -0,0 +1,54 @@ +package io.pixelsdb.pixels.index.rockset.jni; + +import java.util.Objects; + +public class RocksetBloomFilter extends Filter +{ + private static final double DEFAULT_BITS_PER_KEY = (double)10.0F; + private final double bitsPerKey; + + public RocksetBloomFilter() + { + this((double)10.0F); + } + + public RocksetBloomFilter(double var1) + { + this(createNewBloomFilter(var1), var1); + } + + RocksetBloomFilter(long var1, double var3) + { + super(var1); + this.bitsPerKey = var3; + } + + public RocksetBloomFilter(double var1, boolean var3) + { + this(var1); + } + + public boolean equals(Object var1) + { + if (this == var1) + { + return true; + } else if (var1 != null && this.getClass() == var1.getClass()) + { + return this.bitsPerKey == ((RocksetBloomFilter)var1).bitsPerKey; + } else + { + return false; + } + } + + public int hashCode() + { + return Objects.hash(new Object[]{this.bitsPerKey}); + } + + private static native long createNewBloomFilter(double var0); + + @Override + public void close() {} +} diff --git a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetCache.java b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetCache.java new file mode 100644 index 0000000000..09c741df6a --- /dev/null +++ b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetCache.java @@ -0,0 +1,19 @@ +package io.pixelsdb.pixels.index.rockset.jni; + + +public abstract class RocksetCache +{ + protected final long nativeHandle; + + protected RocksetCache(long nativeHandle) + { + this.nativeHandle = nativeHandle; + } + + long handle() + { + return nativeHandle; + } + + public abstract void close(long var1); +} \ No newline at end of file diff --git a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetColumnFamilyDescriptor.java b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetColumnFamilyDescriptor.java new file mode 100644 index 0000000000..442946cb65 --- /dev/null +++ b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetColumnFamilyDescriptor.java @@ -0,0 +1,32 @@ +package io.pixelsdb.pixels.index.rockset.jni; + +public final class RocksetColumnFamilyDescriptor +{ + private final byte[] name; + private final RocksetColumnFamilyOptions options; + + public RocksetColumnFamilyDescriptor(byte[] name, + RocksetColumnFamilyOptions options) + { + if (name == null || name.length == 0) + { + throw new IllegalArgumentException("ColumnFamily name must not be empty"); + } + if (options == null) + { + throw new IllegalArgumentException("ColumnFamilyOptions must not be null"); + } + this.name = name; + this.options = options; + } + + public byte[] getName() + { + return name; + } + + public RocksetColumnFamilyOptions getOptions() + { + return options; + } +} diff --git a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetColumnFamilyHandle.java b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetColumnFamilyHandle.java new file mode 100644 index 0000000000..d3c02c624b --- /dev/null +++ b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetColumnFamilyHandle.java @@ -0,0 +1,33 @@ +package io.pixelsdb.pixels.index.rockset.jni; + +import java.util.Arrays; +import java.util.Objects; + +public class RocksetColumnFamilyHandle extends RocksetHandle +{ + private final RocksetDB rocksetDB; + RocksetColumnFamilyHandle(long handle) + { + super(handle); + this.rocksetDB = null; + } + + RocksetColumnFamilyHandle(RocksetDB rocksetDB, long handle) + { + super(handle); + assert rocksetDB != null; + this.rocksetDB = rocksetDB; + } + + protected final void disposeInternal(long var1) { + disposeInternalJni(var1); + } + + private static native void disposeInternalJni(long var0); + + @Override + public void close() + { + this.disposeInternal(this.nativeHandle); + } +} diff --git a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetColumnFamilyOptions.java b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetColumnFamilyOptions.java new file mode 100644 index 0000000000..920e0459f6 --- /dev/null +++ b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetColumnFamilyOptions.java @@ -0,0 +1,116 @@ +package io.pixelsdb.pixels.index.rockset.jni; + + +public final class RocksetColumnFamilyOptions implements AutoCloseable +{ + private final long nativeHandle; + + public RocksetColumnFamilyOptions() + { + this.nativeHandle = newColumnFamilyOptions(); + } + + long handle() + { + return nativeHandle; + } + + public RocksetColumnFamilyOptions setWriteBufferSize(long var1) + { + nativeSetWriteBufferSize(this.nativeHandle, var1); + return this; + } + + public RocksetColumnFamilyOptions setMaxWriteBufferNumber(int var1) + { + nativeSetMaxWriteBufferNumber(this.nativeHandle, var1); + return this; + } + + public RocksetColumnFamilyOptions setMinWriteBufferNumberToMerge(int var1) + { + nativeSetMinWriteBufferNumberToMerge(this.nativeHandle, var1); + return this; + } + + public RocksetColumnFamilyOptions setMemtablePrefixBloomSizeRatio(double var1) + { + nativeSetMemtablePrefixBloomSizeRatio(this.nativeHandle, var1); + return this; + } + + public RocksetColumnFamilyOptions setTableFormatConfig(RocksetTableFormatConfig var1) + { + nativeSetTableFactory(this.nativeHandle, var1.newTableFactoryHandle()); + return this; + } + + public RocksetColumnFamilyOptions setLevel0FileNumCompactionTrigger(int var1) + { + nativeSetLevel0FileNumCompactionTrigger(this.nativeHandle, var1); + return this; + } + + public RocksetColumnFamilyOptions setMaxBytesForLevelBase(long var1) + { + nativeSetMaxBytesForLevelBase(this.nativeHandle, var1); + return this; + } + + public RocksetColumnFamilyOptions setMaxBytesForLevelMultiplier(double var1) + { + nativeSetMaxBytesForLevelMultiplier(this.nativeHandle, var1); + return this; + } + + public RocksetColumnFamilyOptions setTargetFileSizeBase(long var1) + { + nativeSetTargetFileSizeBase(this.nativeHandle, var1); + return this; + } + + public RocksetColumnFamilyOptions setTargetFileSizeMultiplier(int var1) + { + nativeSetTargetFileSizeMultiplier(this.nativeHandle, var1); + return this; + } + + public RocksetColumnFamilyOptions setCompressionType(RocksetCompressionType var1) + { + nativeSetCompressionType(this.nativeHandle, var1.getValue()); + return this; + } + + public RocksetColumnFamilyOptions setBottommostCompressionType(RocksetCompressionType var1) + { + nativeSetBottommostCompressionType(this.nativeHandle, var1.getValue()); + return this; + } + + public RocksetColumnFamilyOptions setCompactionStyle(RocksetCompactionStyle var1) + { + nativeSetCompactionStyle(this.nativeHandle, var1.getValue()); + return this; + } + @Override + public void close() + { + disposeInternalJni(this.nativeHandle); + } + + private static native long newColumnFamilyOptions(); + private static native void nativeSetWriteBufferSize(long var0, long var2) throws IllegalArgumentException; + private static native void nativeSetMaxWriteBufferNumber(long var0, int var2); + private static native void nativeSetMinWriteBufferNumberToMerge(long var0, int var2); + private static native void nativeSetMemtablePrefixBloomSizeRatio(long var0, double var2); + private static native void nativeSetTableFactory(long var0, long var2); + private static native void nativeSetLevel0FileNumCompactionTrigger(long var0, int var2); + private static native void nativeSetMaxBytesForLevelBase(long var0, long var2); + private static native void nativeSetMaxBytesForLevelMultiplier(long var0, double var2); + private static native void nativeSetTargetFileSizeBase(long var0, long var2); + private static native void nativeSetTargetFileSizeMultiplier(long var0, int var2); + private static native void nativeSetCompressionType(long var0, byte var2); + private static native void nativeSetBottommostCompressionType(long var0, byte var2); + private static native void nativeSetCompactionStyle(long var0, byte var2); + private static native void disposeInternalJni(long var0); +} diff --git a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetCompactionStyle.java b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetCompactionStyle.java new file mode 100644 index 0000000000..f7691f83a0 --- /dev/null +++ b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetCompactionStyle.java @@ -0,0 +1,34 @@ +package io.pixelsdb.pixels.index.rockset.jni; + +public enum RocksetCompactionStyle +{ + LEVEL((byte) 0), + UNIVERSAL((byte) 1), + FIFO((byte) 2), + NONE((byte) 3); + + private final byte value; + + RocksetCompactionStyle(byte value) + { + this.value = value; + } + + public byte getValue() + { + return value; + } + + static RocksetCompactionStyle fromValue(byte value) + { + for (RocksetCompactionStyle s : values()) + { + if (s.value == value) + { + return s; + } + } + throw new IllegalArgumentException( + "Unknown value for RocksetCompactionStyle: " + value); + } +} diff --git a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetCompressionType.java b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetCompressionType.java new file mode 100644 index 0000000000..d5713efcd8 --- /dev/null +++ b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetCompressionType.java @@ -0,0 +1,77 @@ +package io.pixelsdb.pixels.index.rockset.jni; + + +public enum RocksetCompressionType +{ + NO_COMPRESSION((byte)0, (String)null, "kNoCompression"), + SNAPPY_COMPRESSION((byte)1, "snappy", "kSnappyCompression"), + ZLIB_COMPRESSION((byte)2, "z", "kZlibCompression"), + BZLIB2_COMPRESSION((byte)3, "bzip2", "kBZip2Compression"), + LZ4_COMPRESSION((byte)4, "lz4", "kLZ4Compression"), + LZ4HC_COMPRESSION((byte)5, "lz4hc", "kLZ4HCCompression"), + XPRESS_COMPRESSION((byte)6, "xpress", "kXpressCompression"), + ZSTD_COMPRESSION((byte)7, "zstd", "kZSTD"), + DISABLE_COMPRESSION_OPTION((byte)127, (String)null, "kDisableCompressionOption"); + + private final byte value_; + private final String libraryName_; + private final String internalName_; + + public static RocksetCompressionType getCompressionType(String var0) + { + if (var0 != null) + { + for(RocksetCompressionType var4 : values()) + { + if (var4.getLibraryName() != null && var4.getLibraryName().equals(var0)) + { + return var4; + } + } + } + + return NO_COMPRESSION; + } + + public static RocksetCompressionType getCompressionType(byte var0) + { + for(RocksetCompressionType var4 : values()) + { + if (var4.getValue() == var0) + { + return var4; + } + } + throw new IllegalArgumentException("Illegal value provided for CompressionType."); + } + + static RocksetCompressionType getFromInternal(String var0) + { + for(RocksetCompressionType var4 : values()) + { + if (var4.internalName_.equals(var0)) + { + return var4; + } + } + + throw new IllegalArgumentException("Illegal internalName '" + var0 + " ' provided for CompressionType."); + } + + public byte getValue() + { + return this.value_; + } + + public String getLibraryName() + { + return this.libraryName_; + } + + private RocksetCompressionType(byte var3, String var4, String var5) + { + this.value_ = var3; + this.libraryName_ = var4; + this.internalName_ = var5; + } +} diff --git a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetDB.java b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetDB.java new file mode 100644 index 0000000000..1571863d4d --- /dev/null +++ b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetDB.java @@ -0,0 +1,174 @@ +/* + * Copyright 2025 PixelsDB. + * + * This file is part of Pixels. + * + * Pixels is free software: you can redistribute it and/or modify + * it under the terms of the Affero GNU General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * Pixels is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Affero GNU General Public License for more details. + * + * You should have received a copy of the Affero GNU General Public + * License along with Pixels. If not, see + * . + */ +package io.pixelsdb.pixels.index.rockset.jni; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public final class RocksetDB +{ + private final long nativeHandle; + protected RocksetDBOptions options; + private RocksetColumnFamilyHandle defaultColumnFamilyHandle; + public static final byte[] DEFAULT_COLUMN_FAMILY; + final List ownedColumnFamilyHandles = new ArrayList<>(); + + static + { + DEFAULT_COLUMN_FAMILY = "default".getBytes(StandardCharsets.UTF_8); + } + + public RocksetDB(long nativeHandle) + { + this.nativeHandle = nativeHandle; + } + + public long handle() + { + return nativeHandle; + } + + public static RocksetDB open(RocksetEnv env, RocksetDBOptions var0, String var1, List var2, List var3) + { + byte[][] var4 = new byte[var2.size()][]; + long[] var5 = new long[var2.size()]; + int var6 = -1; + + for(int var7 = 0; var7 < var2.size(); ++var7) + { + RocksetColumnFamilyDescriptor var8 = (RocksetColumnFamilyDescriptor)var2.get(var7); + var4[var7] = var8.getName(); + var5[var7] = var8.getOptions().handle(); + if (Arrays.equals(var8.getName(), DEFAULT_COLUMN_FAMILY)) + { + var6 = var7; + } + } + + if (var6 < 0) + { + throw new IllegalArgumentException("You must provide the default column family in your columnFamilyDescriptors"); + } else + { + long[] var11 = open(env.nativeHandle(), var0.nativeHandle, var1, var4, var5); + RocksetDB var12 = new RocksetDB(var11[0]); + var12.storeOptionsInstance(var0); + + for(int var9 = 1; var9 < var11.length; ++var9) + { + RocksetColumnFamilyHandle var10 = new RocksetColumnFamilyHandle(var12, var11[var9]); + var3.add(var10); + } + + var12.ownedColumnFamilyHandles.addAll(var3); + var12.storeDefaultColumnFamilyHandle((RocksetColumnFamilyHandle)var3.get(var6)); + return var12; + } + } + + public void put(RocksetColumnFamilyHandle var1, RocksetWriteOptions var2, ByteBuffer var3, ByteBuffer var4) throws RuntimeException { + if (var3.isDirect() && var4.isDirect()) + { + putDirect(this.nativeHandle, var2.nativeHandle, var3, var3.position(), var3.remaining(), var4, var4.position(), var4.remaining(), var1.nativeHandle); + } + else + { + if (var3.isDirect() || var4.isDirect()) + { + throw new RuntimeException("ByteBuffer parameters must all be direct, or must all be indirect"); + } + + assert var3.hasArray(); + + assert var4.hasArray(); + + put(this.nativeHandle, var2.nativeHandle, var3.array(), var3.arrayOffset() + var3.position(), var3.remaining(), var4.array(), var4.arrayOffset() + var4.position(), var4.remaining(), var1.nativeHandle); + } + + var3.position(var3.limit()); + var4.position(var4.limit()); + } + + public void write(RocksetWriteOptions var1, RocksetWriteBatch var2) throws RuntimeException + { + write0(this.nativeHandle, var1.nativeHandle, var2.nativeHandle); + } + + private void storeOptionsInstance(RocksetDBOptions var0) + { + this.options = var0; + } + + private void storeDefaultColumnFamilyHandle(RocksetColumnFamilyHandle var1) + { + this.defaultColumnFamilyHandle = var1; + } + + public RocksetIterator newIterator(RocksetColumnFamilyHandle cfHandle, RocksetReadOptions readOptions) + { + long iteratorHandle = iterator( + this.nativeHandle, + cfHandle.nativeHandle, + readOptions.nativeHandle + ); + return new RocksetIterator(this, iteratorHandle); + } + + public void close() + { + for(RocksetColumnFamilyHandle var2 : this.ownedColumnFamilyHandles) + { + var2.close(); + } + this.ownedColumnFamilyHandles.clear(); + closeDatabase(nativeHandle); + } + + public boolean isClosed() + { + return this.nativeHandle == 0; + } + + public RocksetColumnFamilyHandle createColumnFamily(byte[] name) + { + try + { + long handle = createColumnFamily0(this.nativeHandle, name); + return new RocksetColumnFamilyHandle(handle); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } + + private static native void closeDatabase(long var0); + private static native long[] open(long env_handle, long options_handle, String db_path, byte[][] descriptors, long[] cf_handles); + public static native List listColumnFamilies0(String dbPath); + private native long createColumnFamily0(long dbHandle, byte[] columnFamilyName) throws Exception; + private static native void putDirect(long var0, long var2, ByteBuffer var4, int var5, int var6, ByteBuffer var7, int var8, int var9, long var10) throws RuntimeException; + private static native void put(long var0, long var2, byte[] var4, int var5, int var6, byte[] var7, int var8, int var9, long var10) throws RuntimeException; + private static native void write0(long var0, long var2, long var4) throws RuntimeException; + private static native long iterator(long var0, long var2, long var4); +} + diff --git a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetDBOptions.java b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetDBOptions.java new file mode 100644 index 0000000000..10d9eb455b --- /dev/null +++ b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetDBOptions.java @@ -0,0 +1,85 @@ +package io.pixelsdb.pixels.index.rockset.jni; + +public final class RocksetDBOptions extends RocksetHandle +{ + private RocksetDBOptions(long handle) + { + super(handle); + } + + public static RocksetDBOptions create() + { + return new RocksetDBOptions(newDBOptions()); + } + + public RocksetDBOptions setCreateIfMissing(boolean value) + { + nativeSetCreateIfMissing(nativeHandle, value); + return this; + } + + public RocksetDBOptions setCreateMissingColumnFamilies(boolean value) + { + nativeSetCreateMissingColumnFamilies(nativeHandle, value); + return this; + } + + public RocksetDBOptions setMaxBackgroundFlushes(int value) + { + nativeSetMaxBackgroundFlushes(nativeHandle, value); + return this; + } + + public RocksetDBOptions setMaxBackgroundCompactions(int value) + { + nativeSetMaxBackgroundCompactions(nativeHandle, value); + return this; + } + + public RocksetDBOptions setMaxSubcompactions(int value) + { + nativeSetMaxSubcompactions(nativeHandle, value); + return this; + } + + public RocksetDBOptions setMaxOpenFiles(int value) + { + nativeSetMaxOpenFiles(nativeHandle, value); + return this; + } + + public RocksetDBOptions setStatistics(RocksetStatistics stats) + { + nativeSetStatistics(nativeHandle, stats.handle()); + return this; + } + + public RocksetDBOptions setStatsDumpPeriodSec(int var1) + { + nativeSetStatsDumpPeriodSec(nativeHandle, var1); + return this; + } + + public RocksetDBOptions setDbLogDir(String var1) + { + nativeSetDbLogDir(nativeHandle, var1); + return this; + } + + public void close() + { + disposeInternalJni(nativeHandle); + } + + private static native long newDBOptions(); + private static native void disposeInternalJni(long handle); + private static native void nativeSetCreateIfMissing(long handle, boolean value); + private static native void nativeSetCreateMissingColumnFamilies(long handle, boolean value); + private static native void nativeSetMaxBackgroundFlushes(long handle, int value); + private static native void nativeSetMaxBackgroundCompactions(long handle, int value); + private static native void nativeSetMaxSubcompactions(long handle, int value); + private static native void nativeSetMaxOpenFiles(long handle, int value); + private static native void nativeSetStatistics(long optionsHandle, long statisticsHandle); + private static native void nativeSetStatsDumpPeriodSec(long optionsHandle, int var); + private static native void nativeSetDbLogDir(long optionsHandle, String var); +} diff --git a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetEnv.java b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetEnv.java new file mode 100644 index 0000000000..a9cc80664f --- /dev/null +++ b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetEnv.java @@ -0,0 +1,33 @@ +package io.pixelsdb.pixels.index.rockset.jni; + +public final class RocksetEnv implements AutoCloseable +{ + private long nativeHandle; + + private RocksetEnv(long handle) + { + this.nativeHandle = handle; + } + + public static RocksetEnv create(String bucket, String prefix) + { + long h = createCloudFileSystem0(bucket, prefix); + return new RocksetEnv(h); + } + + long nativeHandle() + { + return nativeHandle; + } + + @Override + public void close() + { + disposeInternalJni(nativeHandle); + nativeHandle = 0; + } + + private static native void disposeInternalJni(long handle); + private static native long createCloudFileSystem0(String bucket, String prefix); +} + diff --git a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetHandle.java b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetHandle.java new file mode 100644 index 0000000000..f10c841f0f --- /dev/null +++ b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetHandle.java @@ -0,0 +1,19 @@ +package io.pixelsdb.pixels.index.rockset.jni; + + +abstract class RocksetHandle +{ + protected final long nativeHandle; + + protected RocksetHandle(long nativeHandle) + { + this.nativeHandle = nativeHandle; + } + + public long handle() + { + return nativeHandle; + } + + public abstract void close(); +} diff --git a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetIterator.java b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetIterator.java new file mode 100644 index 0000000000..e8e75d5b75 --- /dev/null +++ b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetIterator.java @@ -0,0 +1,104 @@ +package io.pixelsdb.pixels.index.rockset.jni; + +import java.nio.ByteBuffer; + +public final class RocksetIterator implements AutoCloseable +{ + + /** + * Native handle to rocksdb::Iterator + */ + private long nativeHandle; + + /** + * Owning DB instance (to keep DB alive) + */ + private final RocksetDB db; + + RocksetIterator(RocksetDB db, long nativeHandle) + { + this.db = db; + this.nativeHandle = nativeHandle; + } + + /* ================= cursor ================= */ + public void seek(ByteBuffer var1) + { + ensureValid(); + if (var1.isDirect()) + { + this.seekDirect0(this.nativeHandle, var1, var1.position(), var1.remaining()); + } + else + { + this.seekByteArray0(this.nativeHandle, var1.array(), var1.arrayOffset() + var1.position(), var1.remaining()); + } + var1.position(var1.limit()); + } + + public void next() + { + ensureValid(); + next0(nativeHandle); + } + + public boolean isValid() + { + ensureValid(); + return isValid0(nativeHandle); + } + + /* ================= data ================= */ + + public byte[] key() + { + ensureValid(); + return key0(nativeHandle); + } + + public byte[] value() + { + ensureValid(); + return value0(nativeHandle); + } + + /* ================= lifecycle ================= */ + + @Override + public void close() + { + if (nativeHandle != 0) + { + disposeInternalJni(nativeHandle); + nativeHandle = 0; + } + } + + private void ensureValid() + { + if (nativeHandle == 0) + { + throw new IllegalStateException("RocksetIterator already closed"); + } + } + + final void seekDirect0(long var1, ByteBuffer var3, int var4, int var5) + { + seekDirect0Jni(var1, var3, var4, var5); + } + + final void seekByteArray0(long var1, byte[] var3, int var4, int var5) + { + seekByteArray0Jni(var1, var3, var4, var5); + } + + /* ================= native ================= */ + + private static native void seekDirect0Jni(long var0, ByteBuffer var2, int var3, int var4); + private static native void seekByteArray0Jni(long var0, byte[] var2, int var3, int var4); + private static native void next0(long itHandle); + private static native boolean isValid0(long itHandle); + private static native byte[] key0(long itHandle); + private static native byte[] value0(long itHandle); + private static native void disposeInternalJni(long itHandle); +} diff --git a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetLRUCache.java b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetLRUCache.java new file mode 100644 index 0000000000..258f460644 --- /dev/null +++ b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetLRUCache.java @@ -0,0 +1,18 @@ +package io.pixelsdb.pixels.index.rockset.jni; + +public final class RocksetLRUCache extends RocksetCache +{ + public RocksetLRUCache(long capacity, int shardBits) + { + super(newLRUCache(capacity, shardBits, false, (double)0.0F, (double) 0.0F)); + } + + private static native long newLRUCache(long var0, int var2, boolean var3, double var4, double var6); + private static native void disposeInternalJni(long var0); + + @Override + public void close(long var1) + { + disposeInternalJni(var1); + } +} diff --git a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetReadOptions.java b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetReadOptions.java new file mode 100644 index 0000000000..fac36a7210 --- /dev/null +++ b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetReadOptions.java @@ -0,0 +1,29 @@ +package io.pixelsdb.pixels.index.rockset.jni; + +public class RocksetReadOptions extends RocksetHandle +{ + private RocksetReadOptions(long handle) + { + super(handle); + } + + public static RocksetReadOptions create() + { + return new RocksetReadOptions(newReadOptions()); + } + + public RocksetReadOptions setPrefixSameAsStart(boolean var1) + { + setPrefixSameAsStart(this.nativeHandle, var1); + return this; + } + @Override + public void close() + { + disposeInternalJni(nativeHandle); + } + + private static native long newReadOptions(); + private static native void disposeInternalJni(long var0); + private native void setPrefixSameAsStart(long var0, boolean isTrue); +} diff --git a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetStatistics.java b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetStatistics.java new file mode 100644 index 0000000000..4928868177 --- /dev/null +++ b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetStatistics.java @@ -0,0 +1,26 @@ +package io.pixelsdb.pixels.index.rockset.jni; + + +public final class RocksetStatistics implements AutoCloseable +{ + private final long nativeHandle; + + public RocksetStatistics() + { + this.nativeHandle = newStatisticsInstance(); + } + + private static native long newStatisticsInstance(); + private static native void disposeInternalJni(long var0); + + long handle() + { + return nativeHandle; + } + + @Override + public void close() + { + disposeInternalJni(nativeHandle); + } +} diff --git a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetTableFormatConfig.java b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetTableFormatConfig.java new file mode 100644 index 0000000000..2012d2d379 --- /dev/null +++ b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetTableFormatConfig.java @@ -0,0 +1,6 @@ +package io.pixelsdb.pixels.index.rockset.jni; + +public abstract class RocksetTableFormatConfig +{ + protected abstract long newTableFactoryHandle(); +} diff --git a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetWriteBatch.java b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetWriteBatch.java new file mode 100644 index 0000000000..50e0bc98b9 --- /dev/null +++ b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetWriteBatch.java @@ -0,0 +1,72 @@ +package io.pixelsdb.pixels.index.rockset.jni; + +import java.nio.ByteBuffer; + +public final class RocksetWriteBatch implements AutoCloseable +{ + + /** + * Native handle to rocksdb::WriteBatch + */ + public long nativeHandle; + + public RocksetWriteBatch(long nativeHandle) + { + this.nativeHandle = nativeHandle; + } + + /** + * Create a new empty WriteBatch. + */ + public static RocksetWriteBatch create() + { + long handle = newWriteBatch0(); + if (handle == 0) + { + throw new RuntimeException("Failed to create RocksetWriteBatch"); + } + return new RocksetWriteBatch(handle); + } + + public void put(RocksetColumnFamilyHandle var1, ByteBuffer var2, ByteBuffer var3) + { + assert var2.isDirect() && var3.isDirect(); + + this.putDirect(this.nativeHandle, var2, var2.position(), var2.remaining(), var3, var3.position(), var3.remaining(), var1.nativeHandle); + var2.position(var2.limit()); + var3.position(var3.limit()); + } + + public void delete(RocksetColumnFamilyHandle var1, byte[] var2) + { + this.delete(this.nativeHandle, var2, var2.length, var1.nativeHandle); + } + + @Override + public void close() + { + if (nativeHandle != 0) + { + disposeInternalJni(nativeHandle); + nativeHandle = 0; + } + } + + final void putDirect(long var1, ByteBuffer var3, int var4, int var5, ByteBuffer var6, int var7, int var8, long var9) + { + putDirectJni(var1, var3, var4, var5, var6, var7, var8, var9); + } + + final void delete(long var1, byte[] var3, int var4, long var5) + { + deleteJni(var1, var3, var4, var5); + } + + /* ================= native ================= */ + + private static native long newWriteBatch0(); + private static native void disposeInternalJni(long handle); + private static native void putDirectJni(long var0, ByteBuffer var2, int var3, int var4, ByteBuffer var5, int var6, int var7, long var8); + private static native void deleteJni(long var0, byte[] var2, int var3, long var4); +} + diff --git a/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetWriteOptions.java b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetWriteOptions.java new file mode 100644 index 0000000000..a54990e745 --- /dev/null +++ b/pixels-index/pixels-index-rockset/src/main/java/io/pixelsdb/pixels/index/rockset/jni/RocksetWriteOptions.java @@ -0,0 +1,23 @@ +package io.pixelsdb.pixels.index.rockset.jni; + +public class RocksetWriteOptions extends RocksetHandle +{ + private RocksetWriteOptions(long handle) + { + super(handle); + } + + public static RocksetWriteOptions create() + { + return new RocksetWriteOptions(newWriteOptions()); + } + + @Override + public void close() + { + disposeInternalJni(nativeHandle); + } + + private static native long newWriteOptions(); + private static native void disposeInternalJni(long handle); +} diff --git a/pixels-index/pixels-index-rockset/src/test/java/io/pixelsdb/pixels/index/rockset/JniSmokeTest.java b/pixels-index/pixels-index-rockset/src/test/java/io/pixelsdb/pixels/index/rockset/JniSmokeTest.java new file mode 100644 index 0000000000..46350bcd29 --- /dev/null +++ b/pixels-index/pixels-index-rockset/src/test/java/io/pixelsdb/pixels/index/rockset/JniSmokeTest.java @@ -0,0 +1,51 @@ +/* +* Copyright 2025 PixelsDB. +* +* This file is part of Pixels. +* +* Pixels is free software: you can redistribute it and/or modify +* it under the terms of the Affero GNU General Public License as +* published by the Free Software Foundation, either version 3 of +* the License, or (at your option) any later version. +* +* Pixels is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* Affero GNU General Public License for more details. +* +* You should have received a copy of the Affero GNU General Public +* License along with Pixels. If not, see +* . +*/ +package io.pixelsdb.pixels.index.rockset; +import java.io.File; +import java.nio.file.Paths; + +public class JniSmokeTest +{ + // load pixels-index-rockset + static + { + String pixelsHome = System.getenv("PIXELS_HOME"); + if (pixelsHome == null || pixelsHome.isEmpty()) + { + throw new IllegalStateException("Environment variable PIXELS_HOME is not set"); + } + + String libPath = Paths.get(pixelsHome, "lib/libpixels-index-rockset.so").toString(); + File libFile = new File(libPath); + if (!libFile.exists()) + { + throw new IllegalStateException("libpixels-index-rockset.so not found at " + libPath); + } + if (!libFile.canRead()) + { + throw new IllegalStateException("libpixels-index-rockset.so is not readable at " + libPath); + } + System.load(libPath); + } + + public static void main(String[] args) { + System.out.println("JNI loaded OK"); + } +} \ No newline at end of file diff --git a/pixels-index/pixels-index-rockset/src/test/java/io/pixelsdb/pixels/index/rockset/TestRocksetIndex.java b/pixels-index/pixels-index-rockset/src/test/java/io/pixelsdb/pixels/index/rockset/TestRocksetIndex.java index b07de105b4..d9a5a737a2 100644 --- a/pixels-index/pixels-index-rockset/src/test/java/io/pixelsdb/pixels/index/rockset/TestRocksetIndex.java +++ b/pixels-index/pixels-index-rockset/src/test/java/io/pixelsdb/pixels/index/rockset/TestRocksetIndex.java @@ -19,99 +19,375 @@ */ package io.pixelsdb.pixels.index.rockset; +import com.google.common.collect.ImmutableList; +import com.google.protobuf.ByteString; +import io.pixelsdb.pixels.common.exception.MainIndexException; import io.pixelsdb.pixels.common.exception.SinglePointIndexException; import io.pixelsdb.pixels.common.index.SinglePointIndex; -import io.pixelsdb.pixels.common.index.SinglePointIndexFactory; -import org.junit.Test; +import io.pixelsdb.pixels.index.IndexProto; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import io.pixelsdb.pixels.index.rockset.jni.*; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import static io.pixelsdb.pixels.index.rockset.RocksetIndex.toKeyBuffer; +import static org.junit.jupiter.api.Assertions.*; public class TestRocksetIndex { + private RocksetDB rocksetDB; + private static final long TABLE_ID = 100L; + private static final long INDEX_ID = 100L; + private SinglePointIndex uniqueIndex; + private SinglePointIndex nonUniqueIndex; + + @BeforeEach + public void setUp() throws Exception + { + uniqueIndex = new RocksetIndex(TABLE_ID, INDEX_ID, true); + nonUniqueIndex = new RocksetIndex(TABLE_ID, INDEX_ID + 1, false); + rocksetDB = RocksetFactory.getRocksetDB(); + } + + @AfterEach + public void tearDown() throws SinglePointIndexException + { + if (uniqueIndex != null) + { + uniqueIndex.closeAndRemove(); + } + if (nonUniqueIndex != null) + { + nonUniqueIndex.closeAndRemove(); + } + } + + @Test + public void testPutEntry() throws SinglePointIndexException + { + // Create Entry + byte[] key = "testPutEntry".getBytes(); + long timestamp = 1000L; + long rowId = 100L; + + IndexProto.IndexKey keyProto = IndexProto.IndexKey.newBuilder() + .setIndexId(INDEX_ID).setKey(ByteString.copyFrom(key)).setTimestamp(timestamp).build(); + + boolean success = uniqueIndex.putEntry(keyProto, rowId); + assertTrue(success, "putEntry should return true"); + + ByteBuffer keyBuffer = toKeyBuffer(keyProto); + ByteBuffer valueBuffer = RocksetThreadResources.getValueBuffer(); + RocksetReadOptions RocksetreadOptions = RocksetThreadResources.getReadOptions(); + // Assert index has been written to rockset + // int ret = rocksetDB.get(RocksetreadOptions, keyBuffer, valueBuffer); + // assertTrue(ret != 0); + + long storedRowId = valueBuffer.getLong(); + assertEquals(rowId, storedRowId); + } + + @Test + public void testPutEntries() throws SinglePointIndexException, MainIndexException + { + long timestamp = 1000L; + long fileId = 1L; + int rgId = 2; + + List entries = new ArrayList<>(); + + // Create two entries + for (int i = 0; i < 2; i++) + { + byte[] key = ("testPutEntries" + i).getBytes(); // use different keys + + long rowId = i * 1000L; + + IndexProto.IndexKey keyProto = IndexProto.IndexKey.newBuilder() + .setIndexId(INDEX_ID).setKey(ByteString.copyFrom(key)).setTimestamp(timestamp).build(); + + IndexProto.RowLocation rowLocation = IndexProto.RowLocation.newBuilder() + .setFileId(fileId).setRgId(rgId).setRgRowOffset(i).build(); + + IndexProto.PrimaryIndexEntry entry = IndexProto.PrimaryIndexEntry.newBuilder() + .setIndexKey(keyProto).setRowId(rowId).setRowLocation(rowLocation).build(); + entries.add(entry); + } + + boolean success = uniqueIndex.putPrimaryEntries(entries); + assertTrue(success, "putEntries should return true"); + + // Assert every index has been written to rockset + for (int i = 0; i < entries.size(); i++) + { + IndexProto.PrimaryIndexEntry entry = entries.get(i); + ByteBuffer keyBuffer = toKeyBuffer(entry.getIndexKey()); + ByteBuffer valueBuffer = RocksetThreadResources.getValueBuffer(); + RocksetReadOptions rocksetReadOptions = RocksetThreadResources.getReadOptions(); + // int ret = rocksetDB.get(rocksetReadOptions, keyBuffer, valueBuffer); + // assertTrue(ret != 0); + long storedRowId = valueBuffer.getLong(); + assertEquals(i* 1000L, storedRowId); + } + } + @Test - public void test() throws SinglePointIndexException + public void testGetUniqueRowId() throws SinglePointIndexException { - RocksetIndex rocksetIndex = (RocksetIndex) SinglePointIndexFactory.Instance(). - getSinglePointIndex(new SinglePointIndexFactory.TableIndex( - 1L, 1L, SinglePointIndex.Scheme.rockset, true)); + byte[] key = "testGetUniqueRowId".getBytes(); + long timestamp1 = 1000L; + long timestamp2 = timestamp1 + 1000; // newer - long dbHandle = 0; + long rowId1 = 111L; + long rowId2 = 222L; // expected - try + IndexProto.IndexKey key1 = IndexProto.IndexKey.newBuilder() + .setIndexId(INDEX_ID) + .setKey(ByteString.copyFrom(key)) + .setTimestamp(timestamp1) + .build(); + + uniqueIndex.putEntry(key1, rowId1); + + IndexProto.IndexKey key2 = IndexProto.IndexKey.newBuilder() + .setIndexId(INDEX_ID) + .setKey(ByteString.copyFrom(key)) + .setTimestamp(timestamp2) + .build(); + + uniqueIndex.putEntry(key2, rowId2); + + long result = uniqueIndex.getUniqueRowId(key2); + assertEquals(rowId2, result, "getUniqueRowId should return the rowId of the latest timestamp entry"); + } + + @Test + public void testGetRowIds() throws SinglePointIndexException + { + byte[] key = "testGetRowIds".getBytes(); + long timestamp1 = System.currentTimeMillis(); + long timestamp2 = timestamp1 + 1000; // newer + + long rowId1 = 111L; + long rowId2 = 222L; // expected + List rowIds = new ArrayList<>(); + rowIds.add(rowId2); + rowIds.add(rowId1); + + IndexProto.IndexKey key1 = IndexProto.IndexKey.newBuilder() + .setIndexId(INDEX_ID) + .setKey(ByteString.copyFrom(key)) + .setTimestamp(timestamp1) + .build(); + + nonUniqueIndex.putEntry(key1, rowId1); + + IndexProto.IndexKey key2 = IndexProto.IndexKey.newBuilder() + .setIndexId(INDEX_ID) + .setKey(ByteString.copyFrom(key)) + .setTimestamp(timestamp2) + .build(); + + nonUniqueIndex.putEntry(key2,rowId2); + + List result = nonUniqueIndex.getRowIds(key2); + System.out.println(result.size()); + System.out.println(result.toString()); + assertTrue(rowIds.containsAll(result) && result.containsAll(rowIds), "getRowIds should return the rowId of all entries"); + } + + @Test + public void testDeleteEntry() throws SinglePointIndexException + { + byte[] key = "testDeleteEntry".getBytes(); + long timestamp = System.currentTimeMillis(); + + IndexProto.IndexKey keyProto = IndexProto.IndexKey.newBuilder().setIndexId(INDEX_ID) + .setKey(ByteString.copyFrom(key)).setTimestamp(timestamp).build(); + + uniqueIndex.putEntry(keyProto, 0L); + // Delete index + List rets = uniqueIndex.deleteEntry(keyProto); + // Assert return value + for(long ret : rets) { - // 1. get dbHandle - dbHandle = rocksetIndex.getDbHandle(); - System.out.println("DB handle: " + dbHandle); - - // Prepare test keys/values - byte[] key1 = "key1".getBytes(); - byte[] val1 = "val1".getBytes(); - byte[] key2 = "key2".getBytes(); - byte[] val2 = "val2".getBytes(); - - // 2. DB basic ops - System.out.println("=== Basic DB ops ==="); - rocksetIndex.DBput(dbHandle, key1, val1); - rocksetIndex.DBput(dbHandle, key2, val2); - - byte[] got1 = rocksetIndex.DBget(dbHandle, key1); - System.out.println("Retrieved key1: " + (got1 == null ? "null" : new String(got1))); - - rocksetIndex.DBdelete(dbHandle, key1); - byte[] deleted = rocksetIndex.DBget(dbHandle, key1); - System.out.println("After delete, key1: " + (deleted == null ? "null" : new String(deleted))); - - // 3. Iterator test - System.out.println("=== Iterator ops ==="); - long it = rocksetIndex.DBNewIterator(dbHandle); - byte[] seekKey = "zzzz".getBytes(); // seek for last key <= "zzzz" - rocksetIndex.IteratorSeekForPrev(it, seekKey); - - while (rocksetIndex.IteratorIsValid(it)) - { - byte[] ikey = rocksetIndex.IteratorKey(it); - byte[] ival = rocksetIndex.IteratorValue(it); - System.out.println("Iter kv: " + new String(ikey) + " -> " + new String(ival)); - rocksetIndex.IteratorPrev(it); - } - rocksetIndex.IteratorClose(it); - - // 4. WriteBatch test - System.out.println("=== WriteBatch ops ==="); - long wb = rocksetIndex.WriteBatchCreate(); - - byte[] key3 = "key3".getBytes(); - byte[] val3 = "val3".getBytes(); - byte[] key4 = "key4".getBytes(); - byte[] val4 = "val4".getBytes(); - - rocksetIndex.WriteBatchPut(wb, key3, val3); - rocksetIndex.WriteBatchPut(wb, key4, val4); - - rocksetIndex.DBWrite(dbHandle, wb); - - byte[] got3 = rocksetIndex.DBget(dbHandle, key3); - byte[] got4 = rocksetIndex.DBget(dbHandle, key4); - System.out.println("Retrieved key3: " + new String(got3)); - System.out.println("Retrieved key4: " + new String(got4)); - - // Delete via batch - rocksetIndex.WriteBatchClear(wb); - rocksetIndex.WriteBatchDelete(wb, key3); - rocksetIndex.DBWrite(dbHandle, wb); - - byte[] deleted3 = rocksetIndex.DBget(dbHandle, key3); - System.out.println("After batch delete, key3: " + (deleted3 == null ? "null" : new String(deleted3))); - - // cleanup batch - rocksetIndex.WriteBatchDestroy(wb); + assertTrue(ret >= 0, "deleteEntry should return true"); } - finally + } + + @Test + public void testDeleteEntries() throws SinglePointIndexException, MainIndexException + { + long timestamp = System.currentTimeMillis(); + long fileId = 1L; + int rgId = 2; + + List entries = new ArrayList<>(); + List keyList = new ArrayList<>(); + + for (int i = 0; i < 2; i++) + { + byte[] key = ("testDeleteEntries" + i).getBytes(); + + IndexProto.IndexKey keyProto = IndexProto.IndexKey.newBuilder().setIndexId(INDEX_ID) + .setKey(ByteString.copyFrom(key)).setTimestamp(timestamp).build(); + + keyList.add(keyProto); + + IndexProto.RowLocation rowLocation = IndexProto.RowLocation.newBuilder() + .setFileId(fileId).setRgId(rgId).setRgRowOffset(i).build(); + + IndexProto.PrimaryIndexEntry entry = IndexProto.PrimaryIndexEntry.newBuilder() + .setIndexKey(keyProto).setRowId(i).setRowLocation(rowLocation).build(); + entries.add(entry); + } + + uniqueIndex.putPrimaryEntries(entries); + + // delete Indexes + List ret = uniqueIndex.deleteEntries(keyList); + assertNotNull(ret, "deleteEntries should return true"); + } + + @Test + public void testUpdatePrimaryEntry() throws Exception + { + byte[] key = "testUpdatePrimaryEntry".getBytes(); + long timestamp = System.currentTimeMillis(); + IndexProto.IndexKey indexKey = IndexProto.IndexKey.newBuilder().setIndexId(INDEX_ID) + .setKey(ByteString.copyFrom(key)).setTimestamp(timestamp).build(); + long initialRowId = 100L; + long updatedRowId = 200L; + + // Put initial entry + uniqueIndex.putEntry(indexKey, initialRowId); + + // Update entry + long prevRowId = uniqueIndex.updatePrimaryEntry(indexKey, updatedRowId); + assertEquals(initialRowId, prevRowId, "Previous rowId should match the one inserted before"); + + // Verify the updated value + long actualRowId = uniqueIndex.getUniqueRowId(indexKey); + assertEquals(updatedRowId, actualRowId, "RowId should be updated correctly"); + } + + @Test + public void testUpdateSecondaryEntry() throws Exception + { + byte[] key = "testUpdateSecondaryEntry".getBytes(); + long timestamp = System.currentTimeMillis(); + IndexProto.IndexKey indexKey = IndexProto.IndexKey.newBuilder().setIndexId(INDEX_ID) + .setKey(ByteString.copyFrom(key)).setTimestamp(timestamp).build(); + long initialRowId = 500L; + long updatedRowId = 600L; + + // Put initial entry + uniqueIndex.putEntry(indexKey, initialRowId); + + // Update entry + List prevRowIds = uniqueIndex.updateSecondaryEntry(indexKey, updatedRowId); + assertEquals(1, prevRowIds.size()); + assertEquals(initialRowId, prevRowIds.get(0)); + + // Verify the new value + long actualRowId = uniqueIndex.getUniqueRowId(indexKey); + assertEquals(updatedRowId, actualRowId); + } + + @Disabled("Performance test, run manually") + @Test + public void benchmarkGetUniqueRowId() throws SinglePointIndexException + { + int count = 1_000_000; + byte[] key = "benchmarkGetUniqueRowId".getBytes(); + ImmutableList.Builder builder = ImmutableList.builder(); + + // prepare data + for (int i = 0; i < count; i++) + { + long timestamp = System.currentTimeMillis(); + + IndexProto.IndexKey keyProto = IndexProto.IndexKey.newBuilder() + .setIndexId(INDEX_ID) + .setKey(ByteString.copyFrom(key)) + .setTimestamp(timestamp) + .build(); + + uniqueIndex.putEntry(keyProto, i); + builder.add(keyProto); + } + // get rowId + long start = System.nanoTime(); + for (IndexProto.IndexKey keyProto : builder.build()) + { + uniqueIndex.getUniqueRowId(keyProto); + } + long end = System.nanoTime(); + double durationMs = (end - start) / 1_000_000.0; + System.out.printf("Get %,d unique rowIds in %.2f ms (%.2f ops/sec)%n", count, durationMs, count * 1000.0 / durationMs); + } + + @Disabled("Performance test, run manually") + @Test + public void benchmarkPutEntry() throws SinglePointIndexException + { + int count = 1_000_000; + byte[] key = "benchmarkPutEntry".getBytes(); + + long start = System.nanoTime(); + for (int i = 0; i < count; i++) + { + long timestamp = System.currentTimeMillis(); + IndexProto.IndexKey keyProto = IndexProto.IndexKey.newBuilder() + .setIndexId(INDEX_ID) + .setKey(ByteString.copyFrom(key)) + .setTimestamp(timestamp) + .build(); + + uniqueIndex.putEntry(keyProto, i); + } + long end = System.nanoTime(); + double durationMs = (end - start) / 1_000_000.0; + System.out.printf("Put %,d entries in %.2f ms (%.2f ops/sec)%n", count, durationMs, count * 1000.0 / durationMs); + } + + @Disabled("Performance test, run manually") + @Test + public void benchmarkDeleteEntry() throws SinglePointIndexException + { + int count = 1_000_000; + byte[] key = "benchmarkDeleteEntry".getBytes(); + + ImmutableList.Builder builder = ImmutableList.builder(); + + // prepare data + for (int i = 0; i < count; i++) + { + long timestamp = System.currentTimeMillis(); + + IndexProto.IndexKey keyProto = IndexProto.IndexKey.newBuilder() + .setIndexId(INDEX_ID) + .setKey(ByteString.copyFrom(key)) + .setTimestamp(timestamp) + .build(); + + uniqueIndex.putEntry(keyProto, i); + builder.add(keyProto); + } + + // delete data + long start = System.nanoTime(); + for (IndexProto.IndexKey keyProto : builder.build()) { - // 5. confirm close - if (dbHandle != 0) - { - System.out.println("Closing DB..."); - rocksetIndex.CloseDB(dbHandle); - } + uniqueIndex.deleteEntry(keyProto); } + long end = System.nanoTime(); + double durationMs = (end - start) / 1_000_000.0; + System.out.printf("Deleted %,d entries in %.2f ms (%.2f ops/sec)%n", count, durationMs, count * 1000.0 / durationMs); } } \ No newline at end of file