]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/java/rocksjni/transaction_db.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / rocksdb / java / rocksjni / transaction_db.cc
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).
5 //
6 // This file implements the "bridge" between Java and C++
7 // for ROCKSDB_NAMESPACE::TransactionDB.
8
9 #include <jni.h>
10 #include <functional>
11 #include <memory>
12 #include <utility>
13
14 #include "include/org_rocksdb_TransactionDB.h"
15
16 #include "rocksdb/options.h"
17 #include "rocksdb/utilities/transaction.h"
18 #include "rocksdb/utilities/transaction_db.h"
19
20 #include "rocksjni/portal.h"
21
22 /*
23 * Class: org_rocksdb_TransactionDB
24 * Method: open
25 * Signature: (JJLjava/lang/String;)J
26 */
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) {
30 auto* options =
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
39 return 0;
40 }
41 ROCKSDB_NAMESPACE::Status s = ROCKSDB_NAMESPACE::TransactionDB::Open(
42 *options, *txn_db_options, db_path, &tdb);
43 env->ReleaseStringUTFChars(jdb_path, db_path);
44
45 if (s.ok()) {
46 return reinterpret_cast<jlong>(tdb);
47 } else {
48 ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
49 return 0;
50 }
51 }
52
53 /*
54 * Class: org_rocksdb_TransactionDB
55 * Method: open
56 * Signature: (JJLjava/lang/String;[[B[J)[J
57 */
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
65 return nullptr;
66 }
67
68 const jsize len_cols = env->GetArrayLength(jcolumn_names);
69 if (env->EnsureLocalCapacity(len_cols) != 0) {
70 // out of memory
71 env->ReleaseStringUTFChars(jdb_path, db_path);
72 return nullptr;
73 }
74
75 jlong* jco = env->GetLongArrayElements(jcolumn_options_handles, nullptr);
76 if (jco == nullptr) {
77 // exception thrown: OutOfMemoryError
78 env->ReleaseStringUTFChars(jdb_path, db_path);
79 return nullptr;
80 }
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);
88 return nullptr;
89 }
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);
97 return nullptr;
98 }
99
100 const int jcf_name_len = env->GetArrayLength(jcn_ba);
101 if (env->EnsureLocalCapacity(jcf_name_len) != 0) {
102 // out of memory
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);
107 return nullptr;
108 }
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));
114
115 env->ReleaseByteArrayElements(jcn_ba, jcf_name, JNI_ABORT);
116 env->DeleteLocalRef(jcn);
117 }
118 env->ReleaseLongArrayElements(jcolumn_options_handles, jco, JNI_ABORT);
119
120 auto* db_options =
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);
129
130 // check if open operation was successful
131 if (s.ok()) {
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]);
138 }
139
140 jlongArray jresults = env->NewLongArray(resultsLen);
141 if (jresults == nullptr) {
142 // exception thrown: OutOfMemoryError
143 return nullptr;
144 }
145 env->SetLongArrayRegion(jresults, 0, resultsLen, results.get());
146 if (env->ExceptionCheck()) {
147 // exception thrown: ArrayIndexOutOfBoundsException
148 env->DeleteLocalRef(jresults);
149 return nullptr;
150 }
151 return jresults;
152 } else {
153 ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
154 return nullptr;
155 }
156 }
157
158 /*
159 * Class: org_rocksdb_TransactionDB
160 * Method: disposeInternal
161 * Signature: (J)V
162 */
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);
167 delete txn_db;
168 }
169
170 /*
171 * Class: org_rocksdb_TransactionDB
172 * Method: closeDatabase
173 * Signature: (J)V
174 */
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);
181 }
182
183 /*
184 * Class: org_rocksdb_TransactionDB
185 * Method: beginTransaction
186 * Signature: (JJ)J
187 */
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);
196 }
197
198 /*
199 * Class: org_rocksdb_TransactionDB
200 * Method: beginTransaction
201 * Signature: (JJJ)J
202 */
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);
214 }
215
216 /*
217 * Class: org_rocksdb_TransactionDB
218 * Method: beginTransaction_withOld
219 * Signature: (JJJ)J
220 */
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);
227 auto* old_txn =
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);
232
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);
237
238 return reinterpret_cast<jlong>(txn);
239 }
240
241 /*
242 * Class: org_rocksdb_TransactionDB
243 * Method: beginTransaction_withOld
244 * Signature: (JJJJ)J
245 */
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);
254 auto* old_txn =
255 reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jold_txn_handle);
256 ROCKSDB_NAMESPACE::Transaction* txn =
257 txn_db->BeginTransaction(*write_options, *txn_options, old_txn);
258
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);
263
264 return reinterpret_cast<jlong>(txn);
265 }
266
267 /*
268 * Class: org_rocksdb_TransactionDB
269 * Method: getTransactionByName
270 * Signature: (JLjava/lang/String;)J
271 */
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
278 return 0;
279 }
280 ROCKSDB_NAMESPACE::Transaction* txn = txn_db->GetTransactionByName(name);
281 env->ReleaseStringUTFChars(jname, name);
282 return reinterpret_cast<jlong>(txn);
283 }
284
285 /*
286 * Class: org_rocksdb_TransactionDB
287 * Method: getAllPreparedTransactions
288 * Signature: (J)[J
289 */
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);
295
296 const size_t size = txns.size();
297 assert(size < UINT32_MAX); // does it fit in a jint?
298
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]);
303 }
304
305 jlongArray jtxns = env->NewLongArray(len);
306 if (jtxns == nullptr) {
307 // exception thrown: OutOfMemoryError
308 return nullptr;
309 }
310 env->SetLongArrayRegion(jtxns, 0, len, tmp.data());
311 if (env->ExceptionCheck()) {
312 // exception thrown: ArrayIndexOutOfBoundsException
313 env->DeleteLocalRef(jtxns);
314 return nullptr;
315 }
316
317 return jtxns;
318 }
319
320 /*
321 * Class: org_rocksdb_TransactionDB
322 * Method: getLockStatusData
323 * Signature: (J)Ljava/util/Map;
324 */
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
334 return nullptr;
335 }
336
337 const ROCKSDB_NAMESPACE::HashMapJni::FnMapKV<
338 const int32_t, const ROCKSDB_NAMESPACE::KeyLockInfo, jobject, jobject>
339 fn_map_kv =
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) {
345 // an error occurred
346 return std::unique_ptr<std::pair<jobject, jobject>>(nullptr);
347 }
348 const jobject jkey_lock_info =
349 ROCKSDB_NAMESPACE::KeyLockInfoJni::construct(env, pair.second);
350 if (jkey_lock_info == nullptr) {
351 // an error occurred
352 return std::unique_ptr<std::pair<jobject, jobject>>(nullptr);
353 }
354 return std::unique_ptr<std::pair<jobject, jobject>>(
355 new std::pair<jobject, jobject>(jlong_column_family_id,
356 jkey_lock_info));
357 };
358
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
363 return nullptr;
364 }
365
366 return jlock_status_data;
367 }
368
369 /*
370 * Class: org_rocksdb_TransactionDB
371 * Method: getDeadlockInfoBuffer
372 * Signature: (J)[Lorg/rocksdb/TransactionDB/DeadlockPath;
373 */
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();
379
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
387 return nullptr;
388 }
389 jsize jdeadlock_info_buffer_offset = 0;
390
391 auto buf_end = deadlock_info_buffer.end();
392 for (auto buf_it = deadlock_info_buffer.begin(); buf_it != buf_end;
393 ++buf_it) {
394 const ROCKSDB_NAMESPACE::DeadlockPath deadlock_path = *buf_it;
395 const std::vector<ROCKSDB_NAMESPACE::DeadlockInfo> deadlock_infos =
396 deadlock_path.path;
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),
401 nullptr);
402 if (jdeadlock_infos == nullptr) {
403 // exception thrown: OutOfMemoryError
404 env->DeleteLocalRef(jdeadlock_info_buffer);
405 return nullptr;
406 }
407 jsize jdeadlock_infos_offset = 0;
408
409 auto infos_end = deadlock_infos.end();
410 for (auto infos_it = deadlock_infos.begin(); infos_it != infos_end;
411 ++infos_it) {
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);
420 return nullptr;
421 }
422 env->SetObjectArrayElement(jdeadlock_infos, jdeadlock_infos_offset++,
423 jdeadlock_info);
424 if (env->ExceptionCheck()) {
425 // exception thrown: ArrayIndexOutOfBoundsException or
426 // ArrayStoreException
427 env->DeleteLocalRef(jdeadlock_info);
428 env->DeleteLocalRef(jdeadlock_info_buffer);
429 return nullptr;
430 }
431 }
432
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);
439 return nullptr;
440 }
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);
447 return nullptr;
448 }
449 }
450
451 return jdeadlock_info_buffer;
452 }
453
454 /*
455 * Class: org_rocksdb_TransactionDB
456 * Method: setDeadlockInfoBufferSize
457 * Signature: (JI)V
458 */
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);
463 }