Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add jni Support for API CreateColumnFamilyWithImport #11646

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions java/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ set(JNI_NATIVE_SOURCES
rocksjni/env_options.cc
rocksjni/event_listener.cc
rocksjni/event_listener_jnicallback.cc
rocksjni/export_import_files_metadatajni.cc
rocksjni/filter.cc
rocksjni/import_column_family_options.cc
rocksjni/ingest_external_file_options.cc
rocksjni/iterator.cc
rocksjni/jnicallback.cc
Expand Down Expand Up @@ -157,6 +159,7 @@ set(JAVA_MAIN_CLASSES
src/main/java/org/rocksdb/EnvOptions.java
src/main/java/org/rocksdb/EventListener.java
src/main/java/org/rocksdb/Experimental.java
src/main/java/org/rocksdb/ExportImportFilesMetaData.java
src/main/java/org/rocksdb/ExternalFileIngestionInfo.java
src/main/java/org/rocksdb/Filter.java
src/main/java/org/rocksdb/FilterPolicyType.java
Expand All @@ -169,6 +172,7 @@ set(JAVA_MAIN_CLASSES
src/main/java/org/rocksdb/HistogramData.java
src/main/java/org/rocksdb/HistogramType.java
src/main/java/org/rocksdb/Holder.java
src/main/java/org/rocksdb/ImportColumnFamilyOptions.java
src/main/java/org/rocksdb/IndexShorteningMode.java
src/main/java/org/rocksdb/IndexType.java
src/main/java/org/rocksdb/InfoLogLevel.java
Expand Down
1 change: 1 addition & 0 deletions java/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ JAVA_TESTS = \
org.rocksdb.util.JNIComparatorTest\
org.rocksdb.FilterTest\
org.rocksdb.FlushTest\
org.rocksdb.ImportColumnFamilyTest\
org.rocksdb.InfoLogLevelTest\
org.rocksdb.KeyExistsTest \
org.rocksdb.KeyMayExistTest\
Expand Down
35 changes: 35 additions & 0 deletions java/rocksjni/checkpoint.cc
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,38 @@ void Java_org_rocksdb_Checkpoint_createCheckpoint(JNIEnv* env, jobject /*jobj*/,
ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
}
}

/*
* Class: org_rocksdb_Checkpoint
* Method: exportColumnFamily
* Signature: (JJLjava/lang/String;)Lorg/rocksdb/ExportImportFilesMetaData;
*/
jlong Java_org_rocksdb_Checkpoint_exportColumnFamily(
JNIEnv* env, jobject /*jobj*/, jlong jcheckpoint_handle,
jlong jcolumn_family_handle, jstring jexport_path) {
const char* export_path = env->GetStringUTFChars(jexport_path, 0);
if (export_path == nullptr) {
// exception thrown: OutOfMemoryError
return 0;
}

auto* checkpoint =
reinterpret_cast<ROCKSDB_NAMESPACE::Checkpoint*>(jcheckpoint_handle);

auto* column_family_handle =
reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>(
jcolumn_family_handle);

ROCKSDB_NAMESPACE::ExportImportFilesMetaData* metadata = nullptr;

ROCKSDB_NAMESPACE::Status s = checkpoint->ExportColumnFamily(
column_family_handle, export_path, &metadata);

env->ReleaseStringUTFChars(jexport_path, export_path);

if (!s.ok()) {
ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
}

return GET_CPLUSPLUS_POINTER(metadata);
}
22 changes: 22 additions & 0 deletions java/rocksjni/export_import_files_metadatajni.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
//
// This source code is licensed under both the GPLv2 (found in the
// COPYING file in the root directory) and Apache 2.0 License
// (found in the LICENSE.Apache file in the root directory).

#include "include/org_rocksdb_ExportImportFilesMetaData.h"
#include "include/org_rocksdb_LiveFileMetaData.h"
#include "rocksjni/portal.h"

/*
* Class: org_rocksdb_ExportImportFilesMetaData
* Method: disposeInternal
* Signature: (J)V
*/
void Java_org_rocksdb_ExportImportFilesMetaData_disposeInternal(
JNIEnv* /*env*/, jobject /*jopt*/, jlong jhandle) {
auto* metadata =
reinterpret_cast<ROCKSDB_NAMESPACE::ExportImportFilesMetaData*>(jhandle);
assert(metadata != nullptr);
delete metadata;
}
59 changes: 59 additions & 0 deletions java/rocksjni/import_column_family_options.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
//
// This source code is licensed under both the GPLv2 (found in the
// COPYING file in the root directory) and Apache 2.0 License
// (found in the LICENSE.Apache file in the root directory).

#include <jni.h>

#include "include/org_rocksdb_ImportColumnFamilyOptions.h"
#include "rocksdb/options.h"
#include "rocksjni/cplusplus_to_java_convert.h"

/*
* Class: org_rocksdb_ImportColumnFamilyOptions
* Method: newImportColumnFamilyOptions
* Signature: ()J
*/
jlong Java_org_rocksdb_ImportColumnFamilyOptions_newImportColumnFamilyOptions(
JNIEnv *, jclass) {
ROCKSDB_NAMESPACE::ImportColumnFamilyOptions *opts =
new ROCKSDB_NAMESPACE::ImportColumnFamilyOptions();
return GET_CPLUSPLUS_POINTER(opts);
}

/*
* Class: org_rocksdb_ImportColumnFamilyOptions
* Method: setMoveFiles
* Signature: (JZ)V
*/
void Java_org_rocksdb_ImportColumnFamilyOptions_setMoveFiles(
JNIEnv *, jobject, jlong jhandle, jboolean jmove_files) {
auto *options =
reinterpret_cast<ROCKSDB_NAMESPACE::ImportColumnFamilyOptions *>(jhandle);
options->move_files = static_cast<bool>(jmove_files);
}

/*
* Class: org_rocksdb_ImportColumnFamilyOptions
* Method: moveFiles
* Signature: (J)Z
*/
jboolean Java_org_rocksdb_ImportColumnFamilyOptions_moveFiles(JNIEnv *, jobject,
jlong jhandle) {
auto *options =
reinterpret_cast<ROCKSDB_NAMESPACE::ImportColumnFamilyOptions *>(jhandle);
return static_cast<jboolean>(options->move_files);
}

/*
* Class: org_rocksdb_ImportColumnFamilyOptions
* Method: disposeInternal
* Signature: (J)V
*/
void Java_org_rocksdb_ImportColumnFamilyOptions_disposeInternal(JNIEnv *,
jobject,
jlong jhandle) {
delete reinterpret_cast<ROCKSDB_NAMESPACE::ImportColumnFamilyOptions *>(
jhandle);
}
57 changes: 57 additions & 0 deletions java/rocksjni/rocksjni.cc
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,63 @@ jlongArray Java_org_rocksdb_RocksDB_createColumnFamilies__J_3J_3_3B(
return jcf_handles;
}

/*
* Class: org_rocksdb_RocksDB
* Method: createColumnFamilyWithImport
* Signature: (J[BIJJ[J)J
*/
jlong Java_org_rocksdb_RocksDB_createColumnFamilyWithImport(
JNIEnv* env, jobject, jlong jdb_handle, jbyteArray jcf_name,
jint jcf_name_len, jlong j_cf_options, jlong j_cf_import_options,
jlongArray j_metadata_handle_array) {
auto* db = reinterpret_cast<ROCKSDB_NAMESPACE::DB*>(jdb_handle);
jboolean has_exception = JNI_FALSE;
const std::string cf_name =
ROCKSDB_NAMESPACE::JniUtil::byteString<std::string>(
env, jcf_name, jcf_name_len,
[](const char* str, const size_t len) {
return std::string(str, len);
},
&has_exception);
if (has_exception == JNI_TRUE) {
// exception occurred
return 0;
}
auto* cf_options =
reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyOptions*>(j_cf_options);

auto* cf_import_options =
reinterpret_cast<ROCKSDB_NAMESPACE::ImportColumnFamilyOptions*>(
j_cf_import_options);

std::vector<const ROCKSDB_NAMESPACE::ExportImportFilesMetaData*> metadatas;
jlong* ptr_metadata_handle_array =
env->GetLongArrayElements(j_metadata_handle_array, nullptr);
if (j_metadata_handle_array == nullptr) {
// exception thrown: OutOfMemoryError
return 0;
}
const jsize array_size = env->GetArrayLength(j_metadata_handle_array);
for (jsize i = 0; i < array_size; ++i) {
const ROCKSDB_NAMESPACE::ExportImportFilesMetaData* metadata_ptr =
reinterpret_cast<ROCKSDB_NAMESPACE::ExportImportFilesMetaData*>(
ptr_metadata_handle_array[i]);
metadatas.push_back(metadata_ptr);
}
env->ReleaseLongArrayElements(j_metadata_handle_array,
ptr_metadata_handle_array, JNI_ABORT);

ROCKSDB_NAMESPACE::ColumnFamilyHandle* cf_handle = nullptr;
ROCKSDB_NAMESPACE::Status s = db->CreateColumnFamilyWithImport(
*cf_options, cf_name, *cf_import_options, metadatas, &cf_handle);
if (!s.ok()) {
// error occurred
ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
return 0;
}
return GET_CPLUSPLUS_POINTER(cf_handle);
}

/*
* Class: org_rocksdb_RocksDB
* Method: dropColumnFamily
Expand Down
11 changes: 11 additions & 0 deletions java/src/main/java/org/rocksdb/Checkpoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

package org.rocksdb;

import java.util.*;
cbi42 marked this conversation as resolved.
Show resolved Hide resolved

/**
* Provides Checkpoint functionality. Checkpoints
* provide persistent snapshots of RocksDB databases.
Expand Down Expand Up @@ -50,6 +52,12 @@ public void createCheckpoint(final String checkpointPath)
createCheckpoint(nativeHandle_, checkpointPath);
}

public ExportImportFilesMetaData exportColumnFamily(final ColumnFamilyHandle columnFamilyHandle,
final String exportPath) throws RocksDBException {
return new ExportImportFilesMetaData(
exportColumnFamily(nativeHandle_, columnFamilyHandle.nativeHandle_, exportPath));
}

private Checkpoint(final RocksDB db) {
super(newCheckpoint(db.nativeHandle_));
}
Expand All @@ -59,4 +67,7 @@ private Checkpoint(final RocksDB db) {

private native void createCheckpoint(long handle, String checkpointPath)
throws RocksDBException;

private native long exportColumnFamily(long handle, long columnFamilyHandle, String exportPath)
throws RocksDBException;
}
18 changes: 18 additions & 0 deletions java/src/main/java/org/rocksdb/ExportImportFilesMetaData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
//
// This source code is licensed under both the GPLv2 (found in the
// COPYING file in the root directory) and Apache 2.0 License
// (found in the LICENSE.Apache file in the root directory).

package org.rocksdb;

/**
* The metadata that describes a column family.
*/
public class ExportImportFilesMetaData extends RocksObject {
ExportImportFilesMetaData(final long nativeHandle) {
super(nativeHandle);
}

@Override protected native void disposeInternal(final long handle);
}
44 changes: 44 additions & 0 deletions java/src/main/java/org/rocksdb/ImportColumnFamilyOptions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
//
// This source code is licensed under both the GPLv2 (found in the
// COPYING file in the root directory) and Apache 2.0 License
// (found in the LICENSE.Apache file in the root directory).

package org.rocksdb;

/**
* ImportColumnFamilyOptions is used by
* {@link RocksDB#createColumnFamilyWithImport(ColumnFamilyDescriptor, ImportColumnFamilyOptions,
* ExportImportFilesMetaData)}.
*/
public class ImportColumnFamilyOptions extends RocksObject {
public ImportColumnFamilyOptions() {
super(newImportColumnFamilyOptions());
}

/**
* Can be set to true to move the files instead of copying them.
*
* @return true if files will be moved
*/
public boolean moveFiles() {
return moveFiles(nativeHandle_);
}

/**
* Can be set to true to move the files instead of copying them.
*
* @param moveFiles true if files should be moved instead of copied
*
* @return the reference to the current IngestExternalFileOptions.
*/
public ImportColumnFamilyOptions setMoveFiles(final boolean moveFiles) {
setMoveFiles(nativeHandle_, moveFiles);
return this;
}

private static native long newImportColumnFamilyOptions();
private native boolean moveFiles(final long handle);
private native void setMoveFiles(final long handle, final boolean move_files);
@Override protected final native void disposeInternal(final long handle);
}
14 changes: 14 additions & 0 deletions java/src/main/java/org/rocksdb/LiveFileMetaData.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,18 @@ public byte[] columnFamilyName() {
public int level() {
return level;
}

public long newLiveFileMetaDataHandle() {
return newLiveFileMetaDataHandle(columnFamilyName(), columnFamilyName().length, level(),
fileName(), path(), size(), smallestSeqno(), largestSeqno(), smallestKey(),
smallestKey().length, largestKey(), largestKey().length, numReadsSampled(),
beingCompacted(), numEntries(), numDeletions());
}

private native long newLiveFileMetaDataHandle(final byte[] columnFamilyName,
final int columnFamilyNameLength, final int level, final String fileName, final String path,
final long size, final long smallestSeqno, final long largestSeqno, final byte[] smallestKey,
final int smallestKeyLength, final byte[] largestKey, final int largestKeyLength,
final long numReadsSampled, final boolean beingCompacted, final long numEntries,
final long numDeletions);
}
44 changes: 44 additions & 0 deletions java/src/main/java/org/rocksdb/RocksDB.java
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,46 @@ public List<ColumnFamilyHandle> createColumnFamilies(
return columnFamilyHandles;
}

/**
* Creates a new column family with the name columnFamilyName and
* import external SST files specified in `metadata` allocates a
* ColumnFamilyHandle within an internal structure.
* The ColumnFamilyHandle is automatically disposed with DB disposal.
*
* @param columnFamilyDescriptor column family to be created.
* @return {@link org.rocksdb.ColumnFamilyHandle} instance.
*
* @throws RocksDBException thrown if error happens in underlying
* native library.
*/
public ColumnFamilyHandle createColumnFamilyWithImport(
final ColumnFamilyDescriptor columnFamilyDescriptor,
final ImportColumnFamilyOptions importColumnFamilyOptions,
final ExportImportFilesMetaData metadata) throws RocksDBException {
List<ExportImportFilesMetaData> metadatas = new ArrayList<>();
metadatas.add(metadata);
return createColumnFamilyWithImport(
columnFamilyDescriptor, importColumnFamilyOptions, metadatas);
}

public ColumnFamilyHandle createColumnFamilyWithImport(
final ColumnFamilyDescriptor columnFamilyDescriptor,
final ImportColumnFamilyOptions importColumnFamilyOptions,
final List<ExportImportFilesMetaData> metadatas) throws RocksDBException {
final int metadataNum = metadatas.size();
final long[] metadataHandleList = new long[metadataNum];
for (int i = 0; i < metadataNum; i++) {
Copy link
Collaborator

@adamretter adamretter Jul 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am a bit confused between the relationship you have chosen between the Java class org.rocksdb.ExportImportFilesMetaData and the C++ class ROCKSDB_NAMESPACE::ExportImportFilesMetaData.

Normally where there is a Java class that may need to have ownership of a C++ object, we typically follow the pattern of inheriting from RocksObject where possible, or if you need references to C++ objects which should not be owned by the Java Object then you may extend AbstractImmutableNativeReference.

I am wondering if there is a reason why you have chosen not to follow that pattern? It is important in RocksJava that we understand the ownership model so that we don't leak memory by not deleting C++ objects that we own, and/or causing crashes by deleting C++ objects that we don't own.

Copy link
Contributor Author

@mayuehappy mayuehappy Jul 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adamretter

Thank you very much for Review code, it is my honor to contribute code.

I‘v read your comment. Before I modify the code I would like to ask a question, PTAL

ExportImportFilesMetaData may be used in two places. One situation is that we can create ExportImportFilesMetaData through Checkpoint.exportColumnFamily, from here it seems that org.rocksdb.ExportImportFilesMetaData and org.rocksdb.LiveFileMetaData are similar, Called from JNI C++, so i did not to follow that pattern.
But in another case, ExportImportFilesMetaData needs to be passed in when calling createColumnFamilyWithImport. In this case we need to follow the pattern of inheriting from RocksObject.
So if this is the case, do LiveFileMetaData and SstFileMetaData also need to follow this pattern?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. So in C++ when you call Checkpoint::ExportColumnFamily the caller will be the owner of the new ExportImportFilesMetaData object that is created and returned. So if you are calling this from Java, then the Java caller is now the owner of this, and is responsible for freeing it - for this something like RocksObject in Java is perfect.

  2. In C++ when you call DB::CreateColumnFamilyWithImport as the caller you have to provide an ExportImportFilesMetaData object. As you are in C++ you may choose to create this object either on the stack or on the heap. From Java though if you want to have a Java object which represents this C++ object, then you will need to call JNI and create the object on the heap, at which point you are the owner of that object, and so therefore again RocksObject in Java again becomes the correct choice.

@mayuehappy Is that helpful?

metadataHandleList[i] = metadatas.get(i).getNativeHandle();
}
final ColumnFamilyHandle columnFamilyHandle = new ColumnFamilyHandle(this,
createColumnFamilyWithImport(nativeHandle_, columnFamilyDescriptor.getName(),
columnFamilyDescriptor.getName().length,
columnFamilyDescriptor.getOptions().nativeHandle_,
importColumnFamilyOptions.nativeHandle_, metadataHandleList));
ownedColumnFamilyHandles.add(columnFamilyHandle);
return columnFamilyHandle;
}

/**
* Drops the column family specified by {@code columnFamilyHandle}. This call
* only records a drop record in the manifest and prevents the column
Expand Down Expand Up @@ -4713,6 +4753,10 @@ private native long[] createColumnFamilies(final long handle,
private native long[] createColumnFamilies(
final long handle, final long[] columnFamilyOptionsHandles, final byte[][] columnFamilyNames)
throws RocksDBException;
private native long createColumnFamilyWithImport(final long handle, final byte[] columnFamilyName,
final int columnFamilyNamelen, final long columnFamilyOptions,
final long importColumnFamilyOptions, final long[] metadataHandleList)
throws RocksDBException;
private native void dropColumnFamily(
final long handle, final long cfHandle) throws RocksDBException;
private native void dropColumnFamilies(final long handle,
Expand Down
Loading
Loading