1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under both the GPLv2 (found in the
3 // COPYING file in the root directory) and Apache 2.0 License
4 // (found in the LICENSE.Apache file in the root directory).
6 // This file implements the "bridge" between Java and C++
7 // for ROCKSDB_NAMESPACE::TransactionDB.
14 #include "include/org_rocksdb_TransactionDB.h"
16 #include "rocksdb/options.h"
17 #include "rocksdb/utilities/transaction.h"
18 #include "rocksdb/utilities/transaction_db.h"
20 #include "rocksjni/portal.h"
23 * Class: org_rocksdb_TransactionDB
25 * Signature: (JJLjava/lang/String;)J
27 jlong
Java_org_rocksdb_TransactionDB_open__JJLjava_lang_String_2(
28 JNIEnv
* env
, jclass
, jlong joptions_handle
,
29 jlong jtxn_db_options_handle
, jstring jdb_path
) {
31 reinterpret_cast<ROCKSDB_NAMESPACE::Options
*>(joptions_handle
);
32 auto* txn_db_options
=
33 reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDBOptions
*>(
34 jtxn_db_options_handle
);
35 ROCKSDB_NAMESPACE::TransactionDB
* tdb
= nullptr;
36 const char* db_path
= env
->GetStringUTFChars(jdb_path
, nullptr);
37 if (db_path
== nullptr) {
38 // exception thrown: OutOfMemoryError
41 ROCKSDB_NAMESPACE::Status s
= ROCKSDB_NAMESPACE::TransactionDB::Open(
42 *options
, *txn_db_options
, db_path
, &tdb
);
43 env
->ReleaseStringUTFChars(jdb_path
, db_path
);
46 return reinterpret_cast<jlong
>(tdb
);
48 ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env
, s
);
54 * Class: org_rocksdb_TransactionDB
56 * Signature: (JJLjava/lang/String;[[B[J)[J
58 jlongArray
Java_org_rocksdb_TransactionDB_open__JJLjava_lang_String_2_3_3B_3J(
59 JNIEnv
* env
, jclass
, jlong jdb_options_handle
,
60 jlong jtxn_db_options_handle
, jstring jdb_path
, jobjectArray jcolumn_names
,
61 jlongArray jcolumn_options_handles
) {
62 const char* db_path
= env
->GetStringUTFChars(jdb_path
, nullptr);
63 if (db_path
== nullptr) {
64 // exception thrown: OutOfMemoryError
68 const jsize len_cols
= env
->GetArrayLength(jcolumn_names
);
69 if (env
->EnsureLocalCapacity(len_cols
) != 0) {
71 env
->ReleaseStringUTFChars(jdb_path
, db_path
);
75 jlong
* jco
= env
->GetLongArrayElements(jcolumn_options_handles
, nullptr);
77 // exception thrown: OutOfMemoryError
78 env
->ReleaseStringUTFChars(jdb_path
, db_path
);
81 std::vector
<ROCKSDB_NAMESPACE::ColumnFamilyDescriptor
> column_families
;
82 for (int i
= 0; i
< len_cols
; i
++) {
83 const jobject jcn
= env
->GetObjectArrayElement(jcolumn_names
, i
);
84 if (env
->ExceptionCheck()) {
85 // exception thrown: ArrayIndexOutOfBoundsException
86 env
->ReleaseLongArrayElements(jcolumn_options_handles
, jco
, JNI_ABORT
);
87 env
->ReleaseStringUTFChars(jdb_path
, db_path
);
90 const jbyteArray jcn_ba
= reinterpret_cast<jbyteArray
>(jcn
);
91 jbyte
* jcf_name
= env
->GetByteArrayElements(jcn_ba
, nullptr);
92 if (jcf_name
== nullptr) {
93 // exception thrown: OutOfMemoryError
94 env
->DeleteLocalRef(jcn
);
95 env
->ReleaseLongArrayElements(jcolumn_options_handles
, jco
, JNI_ABORT
);
96 env
->ReleaseStringUTFChars(jdb_path
, db_path
);
100 const int jcf_name_len
= env
->GetArrayLength(jcn_ba
);
101 if (env
->EnsureLocalCapacity(jcf_name_len
) != 0) {
103 env
->ReleaseByteArrayElements(jcn_ba
, jcf_name
, JNI_ABORT
);
104 env
->DeleteLocalRef(jcn
);
105 env
->ReleaseLongArrayElements(jcolumn_options_handles
, jco
, JNI_ABORT
);
106 env
->ReleaseStringUTFChars(jdb_path
, db_path
);
109 const std::string
cf_name(reinterpret_cast<char*>(jcf_name
), jcf_name_len
);
110 const ROCKSDB_NAMESPACE::ColumnFamilyOptions
* cf_options
=
111 reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyOptions
*>(jco
[i
]);
112 column_families
.push_back(
113 ROCKSDB_NAMESPACE::ColumnFamilyDescriptor(cf_name
, *cf_options
));
115 env
->ReleaseByteArrayElements(jcn_ba
, jcf_name
, JNI_ABORT
);
116 env
->DeleteLocalRef(jcn
);
118 env
->ReleaseLongArrayElements(jcolumn_options_handles
, jco
, JNI_ABORT
);
121 reinterpret_cast<ROCKSDB_NAMESPACE::DBOptions
*>(jdb_options_handle
);
122 auto* txn_db_options
=
123 reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDBOptions
*>(
124 jtxn_db_options_handle
);
125 std::vector
<ROCKSDB_NAMESPACE::ColumnFamilyHandle
*> handles
;
126 ROCKSDB_NAMESPACE::TransactionDB
* tdb
= nullptr;
127 const ROCKSDB_NAMESPACE::Status s
= ROCKSDB_NAMESPACE::TransactionDB::Open(
128 *db_options
, *txn_db_options
, db_path
, column_families
, &handles
, &tdb
);
130 // check if open operation was successful
132 const jsize resultsLen
= 1 + len_cols
; // db handle + column family handles
133 std::unique_ptr
<jlong
[]> results
=
134 std::unique_ptr
<jlong
[]>(new jlong
[resultsLen
]);
135 results
[0] = reinterpret_cast<jlong
>(tdb
);
136 for (int i
= 1; i
<= len_cols
; i
++) {
137 results
[i
] = reinterpret_cast<jlong
>(handles
[i
- 1]);
140 jlongArray jresults
= env
->NewLongArray(resultsLen
);
141 if (jresults
== nullptr) {
142 // exception thrown: OutOfMemoryError
145 env
->SetLongArrayRegion(jresults
, 0, resultsLen
, results
.get());
146 if (env
->ExceptionCheck()) {
147 // exception thrown: ArrayIndexOutOfBoundsException
148 env
->DeleteLocalRef(jresults
);
153 ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env
, s
);
159 * Class: org_rocksdb_TransactionDB
160 * Method: disposeInternal
163 void Java_org_rocksdb_TransactionDB_disposeInternal(
164 JNIEnv
*, jobject
, jlong jhandle
) {
165 auto* txn_db
= reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDB
*>(jhandle
);
166 assert(txn_db
!= nullptr);
171 * Class: org_rocksdb_TransactionDB
172 * Method: closeDatabase
175 void Java_org_rocksdb_TransactionDB_closeDatabase(
176 JNIEnv
* env
, jclass
, jlong jhandle
) {
177 auto* txn_db
= reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDB
*>(jhandle
);
178 assert(txn_db
!= nullptr);
179 ROCKSDB_NAMESPACE::Status s
= txn_db
->Close();
180 ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env
, s
);
184 * Class: org_rocksdb_TransactionDB
185 * Method: beginTransaction
188 jlong
Java_org_rocksdb_TransactionDB_beginTransaction__JJ(
189 JNIEnv
*, jobject
, jlong jhandle
, jlong jwrite_options_handle
) {
190 auto* txn_db
= reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDB
*>(jhandle
);
191 auto* write_options
=
192 reinterpret_cast<ROCKSDB_NAMESPACE::WriteOptions
*>(jwrite_options_handle
);
193 ROCKSDB_NAMESPACE::Transaction
* txn
=
194 txn_db
->BeginTransaction(*write_options
);
195 return reinterpret_cast<jlong
>(txn
);
199 * Class: org_rocksdb_TransactionDB
200 * Method: beginTransaction
203 jlong
Java_org_rocksdb_TransactionDB_beginTransaction__JJJ(
204 JNIEnv
*, jobject
, jlong jhandle
, jlong jwrite_options_handle
,
205 jlong jtxn_options_handle
) {
206 auto* txn_db
= reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDB
*>(jhandle
);
207 auto* write_options
=
208 reinterpret_cast<ROCKSDB_NAMESPACE::WriteOptions
*>(jwrite_options_handle
);
209 auto* txn_options
= reinterpret_cast<ROCKSDB_NAMESPACE::TransactionOptions
*>(
210 jtxn_options_handle
);
211 ROCKSDB_NAMESPACE::Transaction
* txn
=
212 txn_db
->BeginTransaction(*write_options
, *txn_options
);
213 return reinterpret_cast<jlong
>(txn
);
217 * Class: org_rocksdb_TransactionDB
218 * Method: beginTransaction_withOld
221 jlong
Java_org_rocksdb_TransactionDB_beginTransaction_1withOld__JJJ(
222 JNIEnv
*, jobject
, jlong jhandle
, jlong jwrite_options_handle
,
223 jlong jold_txn_handle
) {
224 auto* txn_db
= reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDB
*>(jhandle
);
225 auto* write_options
=
226 reinterpret_cast<ROCKSDB_NAMESPACE::WriteOptions
*>(jwrite_options_handle
);
228 reinterpret_cast<ROCKSDB_NAMESPACE::Transaction
*>(jold_txn_handle
);
229 ROCKSDB_NAMESPACE::TransactionOptions txn_options
;
230 ROCKSDB_NAMESPACE::Transaction
* txn
=
231 txn_db
->BeginTransaction(*write_options
, txn_options
, old_txn
);
233 // RocksJava relies on the assumption that
234 // we do not allocate a new Transaction object
235 // when providing an old_txn
236 assert(txn
== old_txn
);
238 return reinterpret_cast<jlong
>(txn
);
242 * Class: org_rocksdb_TransactionDB
243 * Method: beginTransaction_withOld
246 jlong
Java_org_rocksdb_TransactionDB_beginTransaction_1withOld__JJJJ(
247 JNIEnv
*, jobject
, jlong jhandle
, jlong jwrite_options_handle
,
248 jlong jtxn_options_handle
, jlong jold_txn_handle
) {
249 auto* txn_db
= reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDB
*>(jhandle
);
250 auto* write_options
=
251 reinterpret_cast<ROCKSDB_NAMESPACE::WriteOptions
*>(jwrite_options_handle
);
252 auto* txn_options
= reinterpret_cast<ROCKSDB_NAMESPACE::TransactionOptions
*>(
253 jtxn_options_handle
);
255 reinterpret_cast<ROCKSDB_NAMESPACE::Transaction
*>(jold_txn_handle
);
256 ROCKSDB_NAMESPACE::Transaction
* txn
=
257 txn_db
->BeginTransaction(*write_options
, *txn_options
, old_txn
);
259 // RocksJava relies on the assumption that
260 // we do not allocate a new Transaction object
261 // when providing an old_txn
262 assert(txn
== old_txn
);
264 return reinterpret_cast<jlong
>(txn
);
268 * Class: org_rocksdb_TransactionDB
269 * Method: getTransactionByName
270 * Signature: (JLjava/lang/String;)J
272 jlong
Java_org_rocksdb_TransactionDB_getTransactionByName(
273 JNIEnv
* env
, jobject
, jlong jhandle
, jstring jname
) {
274 auto* txn_db
= reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDB
*>(jhandle
);
275 const char* name
= env
->GetStringUTFChars(jname
, nullptr);
276 if (name
== nullptr) {
277 // exception thrown: OutOfMemoryError
280 ROCKSDB_NAMESPACE::Transaction
* txn
= txn_db
->GetTransactionByName(name
);
281 env
->ReleaseStringUTFChars(jname
, name
);
282 return reinterpret_cast<jlong
>(txn
);
286 * Class: org_rocksdb_TransactionDB
287 * Method: getAllPreparedTransactions
290 jlongArray
Java_org_rocksdb_TransactionDB_getAllPreparedTransactions(
291 JNIEnv
* env
, jobject
, jlong jhandle
) {
292 auto* txn_db
= reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDB
*>(jhandle
);
293 std::vector
<ROCKSDB_NAMESPACE::Transaction
*> txns
;
294 txn_db
->GetAllPreparedTransactions(&txns
);
296 const size_t size
= txns
.size();
297 assert(size
< UINT32_MAX
); // does it fit in a jint?
299 const jsize len
= static_cast<jsize
>(size
);
300 std::vector
<jlong
> tmp(len
);
301 for (jsize i
= 0; i
< len
; ++i
) {
302 tmp
[i
] = reinterpret_cast<jlong
>(txns
[i
]);
305 jlongArray jtxns
= env
->NewLongArray(len
);
306 if (jtxns
== nullptr) {
307 // exception thrown: OutOfMemoryError
310 env
->SetLongArrayRegion(jtxns
, 0, len
, tmp
.data());
311 if (env
->ExceptionCheck()) {
312 // exception thrown: ArrayIndexOutOfBoundsException
313 env
->DeleteLocalRef(jtxns
);
321 * Class: org_rocksdb_TransactionDB
322 * Method: getLockStatusData
323 * Signature: (J)Ljava/util/Map;
325 jobject
Java_org_rocksdb_TransactionDB_getLockStatusData(
326 JNIEnv
* env
, jobject
, jlong jhandle
) {
327 auto* txn_db
= reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDB
*>(jhandle
);
328 const std::unordered_multimap
<uint32_t, ROCKSDB_NAMESPACE::KeyLockInfo
>
329 lock_status_data
= txn_db
->GetLockStatusData();
330 const jobject jlock_status_data
= ROCKSDB_NAMESPACE::HashMapJni::construct(
331 env
, static_cast<uint32_t>(lock_status_data
.size()));
332 if (jlock_status_data
== nullptr) {
333 // exception occurred
337 const ROCKSDB_NAMESPACE::HashMapJni::FnMapKV
<
338 const int32_t, const ROCKSDB_NAMESPACE::KeyLockInfo
, jobject
, jobject
>
340 [env
](const std::pair
<const int32_t,
341 const ROCKSDB_NAMESPACE::KeyLockInfo
>& pair
) {
342 const jobject jlong_column_family_id
=
343 ROCKSDB_NAMESPACE::LongJni::valueOf(env
, pair
.first
);
344 if (jlong_column_family_id
== nullptr) {
346 return std::unique_ptr
<std::pair
<jobject
, jobject
>>(nullptr);
348 const jobject jkey_lock_info
=
349 ROCKSDB_NAMESPACE::KeyLockInfoJni::construct(env
, pair
.second
);
350 if (jkey_lock_info
== nullptr) {
352 return std::unique_ptr
<std::pair
<jobject
, jobject
>>(nullptr);
354 return std::unique_ptr
<std::pair
<jobject
, jobject
>>(
355 new std::pair
<jobject
, jobject
>(jlong_column_family_id
,
359 if (!ROCKSDB_NAMESPACE::HashMapJni::putAll(
360 env
, jlock_status_data
, lock_status_data
.begin(),
361 lock_status_data
.end(), fn_map_kv
)) {
362 // exception occcurred
366 return jlock_status_data
;
370 * Class: org_rocksdb_TransactionDB
371 * Method: getDeadlockInfoBuffer
372 * Signature: (J)[Lorg/rocksdb/TransactionDB/DeadlockPath;
374 jobjectArray
Java_org_rocksdb_TransactionDB_getDeadlockInfoBuffer(
375 JNIEnv
* env
, jobject jobj
, jlong jhandle
) {
376 auto* txn_db
= reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDB
*>(jhandle
);
377 const std::vector
<ROCKSDB_NAMESPACE::DeadlockPath
> deadlock_info_buffer
=
378 txn_db
->GetDeadlockInfoBuffer();
380 const jsize deadlock_info_buffer_len
=
381 static_cast<jsize
>(deadlock_info_buffer
.size());
382 jobjectArray jdeadlock_info_buffer
= env
->NewObjectArray(
383 deadlock_info_buffer_len
,
384 ROCKSDB_NAMESPACE::DeadlockPathJni::getJClass(env
), nullptr);
385 if (jdeadlock_info_buffer
== nullptr) {
386 // exception thrown: OutOfMemoryError
389 jsize jdeadlock_info_buffer_offset
= 0;
391 auto buf_end
= deadlock_info_buffer
.end();
392 for (auto buf_it
= deadlock_info_buffer
.begin(); buf_it
!= buf_end
;
394 const ROCKSDB_NAMESPACE::DeadlockPath deadlock_path
= *buf_it
;
395 const std::vector
<ROCKSDB_NAMESPACE::DeadlockInfo
> deadlock_infos
=
397 const jsize deadlock_infos_len
=
398 static_cast<jsize
>(deadlock_info_buffer
.size());
399 jobjectArray jdeadlock_infos
= env
->NewObjectArray(
400 deadlock_infos_len
, ROCKSDB_NAMESPACE::DeadlockInfoJni::getJClass(env
),
402 if (jdeadlock_infos
== nullptr) {
403 // exception thrown: OutOfMemoryError
404 env
->DeleteLocalRef(jdeadlock_info_buffer
);
407 jsize jdeadlock_infos_offset
= 0;
409 auto infos_end
= deadlock_infos
.end();
410 for (auto infos_it
= deadlock_infos
.begin(); infos_it
!= infos_end
;
412 const ROCKSDB_NAMESPACE::DeadlockInfo deadlock_info
= *infos_it
;
413 const jobject jdeadlock_info
=
414 ROCKSDB_NAMESPACE::TransactionDBJni::newDeadlockInfo(
415 env
, jobj
, deadlock_info
.m_txn_id
, deadlock_info
.m_cf_id
,
416 deadlock_info
.m_waiting_key
, deadlock_info
.m_exclusive
);
417 if (jdeadlock_info
== nullptr) {
418 // exception occcurred
419 env
->DeleteLocalRef(jdeadlock_info_buffer
);
422 env
->SetObjectArrayElement(jdeadlock_infos
, jdeadlock_infos_offset
++,
424 if (env
->ExceptionCheck()) {
425 // exception thrown: ArrayIndexOutOfBoundsException or
426 // ArrayStoreException
427 env
->DeleteLocalRef(jdeadlock_info
);
428 env
->DeleteLocalRef(jdeadlock_info_buffer
);
433 const jobject jdeadlock_path
=
434 ROCKSDB_NAMESPACE::DeadlockPathJni::construct(
435 env
, jdeadlock_infos
, deadlock_path
.limit_exceeded
);
436 if (jdeadlock_path
== nullptr) {
437 // exception occcurred
438 env
->DeleteLocalRef(jdeadlock_info_buffer
);
441 env
->SetObjectArrayElement(jdeadlock_info_buffer
,
442 jdeadlock_info_buffer_offset
++, jdeadlock_path
);
443 if (env
->ExceptionCheck()) {
444 // exception thrown: ArrayIndexOutOfBoundsException or ArrayStoreException
445 env
->DeleteLocalRef(jdeadlock_path
);
446 env
->DeleteLocalRef(jdeadlock_info_buffer
);
451 return jdeadlock_info_buffer
;
455 * Class: org_rocksdb_TransactionDB
456 * Method: setDeadlockInfoBufferSize
459 void Java_org_rocksdb_TransactionDB_setDeadlockInfoBufferSize(
460 JNIEnv
*, jobject
, jlong jhandle
, jint jdeadlock_info_buffer_size
) {
461 auto* txn_db
= reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDB
*>(jhandle
);
462 txn_db
->SetDeadlockInfoBufferSize(jdeadlock_info_buffer_size
);