transaction_db.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  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. #include <jni.h>
  9. #include <functional>
  10. #include <memory>
  11. #include <utility>
  12. #include "include/org_rocksdb_TransactionDB.h"
  13. #include "rocksdb/options.h"
  14. #include "rocksdb/utilities/transaction.h"
  15. #include "rocksdb/utilities/transaction_db.h"
  16. #include "rocksjni/portal.h"
  17. /*
  18. * Class: org_rocksdb_TransactionDB
  19. * Method: open
  20. * Signature: (JJLjava/lang/String;)J
  21. */
  22. jlong Java_org_rocksdb_TransactionDB_open__JJLjava_lang_String_2(
  23. JNIEnv* env, jclass, jlong joptions_handle,
  24. jlong jtxn_db_options_handle, jstring jdb_path) {
  25. auto* options =
  26. reinterpret_cast<ROCKSDB_NAMESPACE::Options*>(joptions_handle);
  27. auto* txn_db_options =
  28. reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDBOptions*>(
  29. jtxn_db_options_handle);
  30. ROCKSDB_NAMESPACE::TransactionDB* tdb = nullptr;
  31. const char* db_path = env->GetStringUTFChars(jdb_path, nullptr);
  32. if (db_path == nullptr) {
  33. // exception thrown: OutOfMemoryError
  34. return 0;
  35. }
  36. ROCKSDB_NAMESPACE::Status s = ROCKSDB_NAMESPACE::TransactionDB::Open(
  37. *options, *txn_db_options, db_path, &tdb);
  38. env->ReleaseStringUTFChars(jdb_path, db_path);
  39. if (s.ok()) {
  40. return reinterpret_cast<jlong>(tdb);
  41. } else {
  42. ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
  43. return 0;
  44. }
  45. }
  46. /*
  47. * Class: org_rocksdb_TransactionDB
  48. * Method: open
  49. * Signature: (JJLjava/lang/String;[[B[J)[J
  50. */
  51. jlongArray Java_org_rocksdb_TransactionDB_open__JJLjava_lang_String_2_3_3B_3J(
  52. JNIEnv* env, jclass, jlong jdb_options_handle,
  53. jlong jtxn_db_options_handle, jstring jdb_path, jobjectArray jcolumn_names,
  54. jlongArray jcolumn_options_handles) {
  55. const char* db_path = env->GetStringUTFChars(jdb_path, nullptr);
  56. if (db_path == nullptr) {
  57. // exception thrown: OutOfMemoryError
  58. return nullptr;
  59. }
  60. const jsize len_cols = env->GetArrayLength(jcolumn_names);
  61. if (env->EnsureLocalCapacity(len_cols) != 0) {
  62. // out of memory
  63. env->ReleaseStringUTFChars(jdb_path, db_path);
  64. return nullptr;
  65. }
  66. jlong* jco = env->GetLongArrayElements(jcolumn_options_handles, nullptr);
  67. if (jco == nullptr) {
  68. // exception thrown: OutOfMemoryError
  69. env->ReleaseStringUTFChars(jdb_path, db_path);
  70. return nullptr;
  71. }
  72. std::vector<ROCKSDB_NAMESPACE::ColumnFamilyDescriptor> column_families;
  73. for (int i = 0; i < len_cols; i++) {
  74. const jobject jcn = env->GetObjectArrayElement(jcolumn_names, i);
  75. if (env->ExceptionCheck()) {
  76. // exception thrown: ArrayIndexOutOfBoundsException
  77. env->ReleaseLongArrayElements(jcolumn_options_handles, jco, JNI_ABORT);
  78. env->ReleaseStringUTFChars(jdb_path, db_path);
  79. return nullptr;
  80. }
  81. const jbyteArray jcn_ba = reinterpret_cast<jbyteArray>(jcn);
  82. jbyte* jcf_name = env->GetByteArrayElements(jcn_ba, nullptr);
  83. if (jcf_name == nullptr) {
  84. // exception thrown: OutOfMemoryError
  85. env->DeleteLocalRef(jcn);
  86. env->ReleaseLongArrayElements(jcolumn_options_handles, jco, JNI_ABORT);
  87. env->ReleaseStringUTFChars(jdb_path, db_path);
  88. return nullptr;
  89. }
  90. const int jcf_name_len = env->GetArrayLength(jcn_ba);
  91. if (env->EnsureLocalCapacity(jcf_name_len) != 0) {
  92. // out of memory
  93. env->ReleaseByteArrayElements(jcn_ba, jcf_name, JNI_ABORT);
  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. const std::string cf_name(reinterpret_cast<char*>(jcf_name), jcf_name_len);
  100. const ROCKSDB_NAMESPACE::ColumnFamilyOptions* cf_options =
  101. reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyOptions*>(jco[i]);
  102. column_families.push_back(
  103. ROCKSDB_NAMESPACE::ColumnFamilyDescriptor(cf_name, *cf_options));
  104. env->ReleaseByteArrayElements(jcn_ba, jcf_name, JNI_ABORT);
  105. env->DeleteLocalRef(jcn);
  106. }
  107. env->ReleaseLongArrayElements(jcolumn_options_handles, jco, JNI_ABORT);
  108. auto* db_options =
  109. reinterpret_cast<ROCKSDB_NAMESPACE::DBOptions*>(jdb_options_handle);
  110. auto* txn_db_options =
  111. reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDBOptions*>(
  112. jtxn_db_options_handle);
  113. std::vector<ROCKSDB_NAMESPACE::ColumnFamilyHandle*> handles;
  114. ROCKSDB_NAMESPACE::TransactionDB* tdb = nullptr;
  115. const ROCKSDB_NAMESPACE::Status s = ROCKSDB_NAMESPACE::TransactionDB::Open(
  116. *db_options, *txn_db_options, db_path, column_families, &handles, &tdb);
  117. // check if open operation was successful
  118. if (s.ok()) {
  119. const jsize resultsLen = 1 + len_cols; // db handle + column family handles
  120. std::unique_ptr<jlong[]> results =
  121. std::unique_ptr<jlong[]>(new jlong[resultsLen]);
  122. results[0] = reinterpret_cast<jlong>(tdb);
  123. for (int i = 1; i <= len_cols; i++) {
  124. results[i] = reinterpret_cast<jlong>(handles[i - 1]);
  125. }
  126. jlongArray jresults = env->NewLongArray(resultsLen);
  127. if (jresults == nullptr) {
  128. // exception thrown: OutOfMemoryError
  129. return nullptr;
  130. }
  131. env->SetLongArrayRegion(jresults, 0, resultsLen, results.get());
  132. if (env->ExceptionCheck()) {
  133. // exception thrown: ArrayIndexOutOfBoundsException
  134. env->DeleteLocalRef(jresults);
  135. return nullptr;
  136. }
  137. return jresults;
  138. } else {
  139. ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
  140. return nullptr;
  141. }
  142. }
  143. /*
  144. * Class: org_rocksdb_TransactionDB
  145. * Method: disposeInternal
  146. * Signature: (J)V
  147. */
  148. void Java_org_rocksdb_TransactionDB_disposeInternal(
  149. JNIEnv*, jobject, jlong jhandle) {
  150. auto* txn_db = reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDB*>(jhandle);
  151. assert(txn_db != nullptr);
  152. delete txn_db;
  153. }
  154. /*
  155. * Class: org_rocksdb_TransactionDB
  156. * Method: closeDatabase
  157. * Signature: (J)V
  158. */
  159. void Java_org_rocksdb_TransactionDB_closeDatabase(
  160. JNIEnv* env, jclass, jlong jhandle) {
  161. auto* txn_db = reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDB*>(jhandle);
  162. assert(txn_db != nullptr);
  163. ROCKSDB_NAMESPACE::Status s = txn_db->Close();
  164. ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
  165. }
  166. /*
  167. * Class: org_rocksdb_TransactionDB
  168. * Method: beginTransaction
  169. * Signature: (JJ)J
  170. */
  171. jlong Java_org_rocksdb_TransactionDB_beginTransaction__JJ(
  172. JNIEnv*, jobject, jlong jhandle, jlong jwrite_options_handle) {
  173. auto* txn_db = reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDB*>(jhandle);
  174. auto* write_options =
  175. reinterpret_cast<ROCKSDB_NAMESPACE::WriteOptions*>(jwrite_options_handle);
  176. ROCKSDB_NAMESPACE::Transaction* txn =
  177. txn_db->BeginTransaction(*write_options);
  178. return reinterpret_cast<jlong>(txn);
  179. }
  180. /*
  181. * Class: org_rocksdb_TransactionDB
  182. * Method: beginTransaction
  183. * Signature: (JJJ)J
  184. */
  185. jlong Java_org_rocksdb_TransactionDB_beginTransaction__JJJ(
  186. JNIEnv*, jobject, jlong jhandle, jlong jwrite_options_handle,
  187. jlong jtxn_options_handle) {
  188. auto* txn_db = reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDB*>(jhandle);
  189. auto* write_options =
  190. reinterpret_cast<ROCKSDB_NAMESPACE::WriteOptions*>(jwrite_options_handle);
  191. auto* txn_options = reinterpret_cast<ROCKSDB_NAMESPACE::TransactionOptions*>(
  192. jtxn_options_handle);
  193. ROCKSDB_NAMESPACE::Transaction* txn =
  194. txn_db->BeginTransaction(*write_options, *txn_options);
  195. return reinterpret_cast<jlong>(txn);
  196. }
  197. /*
  198. * Class: org_rocksdb_TransactionDB
  199. * Method: beginTransaction_withOld
  200. * Signature: (JJJ)J
  201. */
  202. jlong Java_org_rocksdb_TransactionDB_beginTransaction_1withOld__JJJ(
  203. JNIEnv*, jobject, jlong jhandle, jlong jwrite_options_handle,
  204. jlong jold_txn_handle) {
  205. auto* txn_db = reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDB*>(jhandle);
  206. auto* write_options =
  207. reinterpret_cast<ROCKSDB_NAMESPACE::WriteOptions*>(jwrite_options_handle);
  208. auto* old_txn =
  209. reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jold_txn_handle);
  210. ROCKSDB_NAMESPACE::TransactionOptions txn_options;
  211. ROCKSDB_NAMESPACE::Transaction* txn =
  212. txn_db->BeginTransaction(*write_options, txn_options, old_txn);
  213. // RocksJava relies on the assumption that
  214. // we do not allocate a new Transaction object
  215. // when providing an old_txn
  216. assert(txn == old_txn);
  217. return reinterpret_cast<jlong>(txn);
  218. }
  219. /*
  220. * Class: org_rocksdb_TransactionDB
  221. * Method: beginTransaction_withOld
  222. * Signature: (JJJJ)J
  223. */
  224. jlong Java_org_rocksdb_TransactionDB_beginTransaction_1withOld__JJJJ(
  225. JNIEnv*, jobject, jlong jhandle, jlong jwrite_options_handle,
  226. jlong jtxn_options_handle, jlong jold_txn_handle) {
  227. auto* txn_db = reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDB*>(jhandle);
  228. auto* write_options =
  229. reinterpret_cast<ROCKSDB_NAMESPACE::WriteOptions*>(jwrite_options_handle);
  230. auto* txn_options = reinterpret_cast<ROCKSDB_NAMESPACE::TransactionOptions*>(
  231. jtxn_options_handle);
  232. auto* old_txn =
  233. reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jold_txn_handle);
  234. ROCKSDB_NAMESPACE::Transaction* txn =
  235. txn_db->BeginTransaction(*write_options, *txn_options, old_txn);
  236. // RocksJava relies on the assumption that
  237. // we do not allocate a new Transaction object
  238. // when providing an old_txn
  239. assert(txn == old_txn);
  240. return reinterpret_cast<jlong>(txn);
  241. }
  242. /*
  243. * Class: org_rocksdb_TransactionDB
  244. * Method: getTransactionByName
  245. * Signature: (JLjava/lang/String;)J
  246. */
  247. jlong Java_org_rocksdb_TransactionDB_getTransactionByName(
  248. JNIEnv* env, jobject, jlong jhandle, jstring jname) {
  249. auto* txn_db = reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDB*>(jhandle);
  250. const char* name = env->GetStringUTFChars(jname, nullptr);
  251. if (name == nullptr) {
  252. // exception thrown: OutOfMemoryError
  253. return 0;
  254. }
  255. ROCKSDB_NAMESPACE::Transaction* txn = txn_db->GetTransactionByName(name);
  256. env->ReleaseStringUTFChars(jname, name);
  257. return reinterpret_cast<jlong>(txn);
  258. }
  259. /*
  260. * Class: org_rocksdb_TransactionDB
  261. * Method: getAllPreparedTransactions
  262. * Signature: (J)[J
  263. */
  264. jlongArray Java_org_rocksdb_TransactionDB_getAllPreparedTransactions(
  265. JNIEnv* env, jobject, jlong jhandle) {
  266. auto* txn_db = reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDB*>(jhandle);
  267. std::vector<ROCKSDB_NAMESPACE::Transaction*> txns;
  268. txn_db->GetAllPreparedTransactions(&txns);
  269. const size_t size = txns.size();
  270. assert(size < UINT32_MAX); // does it fit in a jint?
  271. const jsize len = static_cast<jsize>(size);
  272. std::vector<jlong> tmp(len);
  273. for (jsize i = 0; i < len; ++i) {
  274. tmp[i] = reinterpret_cast<jlong>(txns[i]);
  275. }
  276. jlongArray jtxns = env->NewLongArray(len);
  277. if (jtxns == nullptr) {
  278. // exception thrown: OutOfMemoryError
  279. return nullptr;
  280. }
  281. env->SetLongArrayRegion(jtxns, 0, len, tmp.data());
  282. if (env->ExceptionCheck()) {
  283. // exception thrown: ArrayIndexOutOfBoundsException
  284. env->DeleteLocalRef(jtxns);
  285. return nullptr;
  286. }
  287. return jtxns;
  288. }
  289. /*
  290. * Class: org_rocksdb_TransactionDB
  291. * Method: getLockStatusData
  292. * Signature: (J)Ljava/util/Map;
  293. */
  294. jobject Java_org_rocksdb_TransactionDB_getLockStatusData(
  295. JNIEnv* env, jobject, jlong jhandle) {
  296. auto* txn_db = reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDB*>(jhandle);
  297. const std::unordered_multimap<uint32_t, ROCKSDB_NAMESPACE::KeyLockInfo>
  298. lock_status_data = txn_db->GetLockStatusData();
  299. const jobject jlock_status_data = ROCKSDB_NAMESPACE::HashMapJni::construct(
  300. env, static_cast<uint32_t>(lock_status_data.size()));
  301. if (jlock_status_data == nullptr) {
  302. // exception occurred
  303. return nullptr;
  304. }
  305. const ROCKSDB_NAMESPACE::HashMapJni::FnMapKV<
  306. const int32_t, const ROCKSDB_NAMESPACE::KeyLockInfo, jobject, jobject>
  307. fn_map_kv =
  308. [env](const std::pair<const int32_t,
  309. const ROCKSDB_NAMESPACE::KeyLockInfo>& pair) {
  310. const jobject jlong_column_family_id =
  311. ROCKSDB_NAMESPACE::LongJni::valueOf(env, pair.first);
  312. if (jlong_column_family_id == nullptr) {
  313. // an error occurred
  314. return std::unique_ptr<std::pair<jobject, jobject>>(nullptr);
  315. }
  316. const jobject jkey_lock_info =
  317. ROCKSDB_NAMESPACE::KeyLockInfoJni::construct(env, pair.second);
  318. if (jkey_lock_info == nullptr) {
  319. // an error occurred
  320. return std::unique_ptr<std::pair<jobject, jobject>>(nullptr);
  321. }
  322. return std::unique_ptr<std::pair<jobject, jobject>>(
  323. new std::pair<jobject, jobject>(jlong_column_family_id,
  324. jkey_lock_info));
  325. };
  326. if (!ROCKSDB_NAMESPACE::HashMapJni::putAll(
  327. env, jlock_status_data, lock_status_data.begin(),
  328. lock_status_data.end(), fn_map_kv)) {
  329. // exception occcurred
  330. return nullptr;
  331. }
  332. return jlock_status_data;
  333. }
  334. /*
  335. * Class: org_rocksdb_TransactionDB
  336. * Method: getDeadlockInfoBuffer
  337. * Signature: (J)[Lorg/rocksdb/TransactionDB/DeadlockPath;
  338. */
  339. jobjectArray Java_org_rocksdb_TransactionDB_getDeadlockInfoBuffer(
  340. JNIEnv* env, jobject jobj, jlong jhandle) {
  341. auto* txn_db = reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDB*>(jhandle);
  342. const std::vector<ROCKSDB_NAMESPACE::DeadlockPath> deadlock_info_buffer =
  343. txn_db->GetDeadlockInfoBuffer();
  344. const jsize deadlock_info_buffer_len =
  345. static_cast<jsize>(deadlock_info_buffer.size());
  346. jobjectArray jdeadlock_info_buffer = env->NewObjectArray(
  347. deadlock_info_buffer_len,
  348. ROCKSDB_NAMESPACE::DeadlockPathJni::getJClass(env), nullptr);
  349. if (jdeadlock_info_buffer == nullptr) {
  350. // exception thrown: OutOfMemoryError
  351. return nullptr;
  352. }
  353. jsize jdeadlock_info_buffer_offset = 0;
  354. auto buf_end = deadlock_info_buffer.end();
  355. for (auto buf_it = deadlock_info_buffer.begin(); buf_it != buf_end;
  356. ++buf_it) {
  357. const ROCKSDB_NAMESPACE::DeadlockPath deadlock_path = *buf_it;
  358. const std::vector<ROCKSDB_NAMESPACE::DeadlockInfo> deadlock_infos =
  359. deadlock_path.path;
  360. const jsize deadlock_infos_len =
  361. static_cast<jsize>(deadlock_info_buffer.size());
  362. jobjectArray jdeadlock_infos = env->NewObjectArray(
  363. deadlock_infos_len, ROCKSDB_NAMESPACE::DeadlockInfoJni::getJClass(env),
  364. nullptr);
  365. if (jdeadlock_infos == nullptr) {
  366. // exception thrown: OutOfMemoryError
  367. env->DeleteLocalRef(jdeadlock_info_buffer);
  368. return nullptr;
  369. }
  370. jsize jdeadlock_infos_offset = 0;
  371. auto infos_end = deadlock_infos.end();
  372. for (auto infos_it = deadlock_infos.begin(); infos_it != infos_end;
  373. ++infos_it) {
  374. const ROCKSDB_NAMESPACE::DeadlockInfo deadlock_info = *infos_it;
  375. const jobject jdeadlock_info =
  376. ROCKSDB_NAMESPACE::TransactionDBJni::newDeadlockInfo(
  377. env, jobj, deadlock_info.m_txn_id, deadlock_info.m_cf_id,
  378. deadlock_info.m_waiting_key, deadlock_info.m_exclusive);
  379. if (jdeadlock_info == nullptr) {
  380. // exception occcurred
  381. env->DeleteLocalRef(jdeadlock_info_buffer);
  382. return nullptr;
  383. }
  384. env->SetObjectArrayElement(jdeadlock_infos, jdeadlock_infos_offset++,
  385. jdeadlock_info);
  386. if (env->ExceptionCheck()) {
  387. // exception thrown: ArrayIndexOutOfBoundsException or
  388. // ArrayStoreException
  389. env->DeleteLocalRef(jdeadlock_info);
  390. env->DeleteLocalRef(jdeadlock_info_buffer);
  391. return nullptr;
  392. }
  393. }
  394. const jobject jdeadlock_path =
  395. ROCKSDB_NAMESPACE::DeadlockPathJni::construct(
  396. env, jdeadlock_infos, deadlock_path.limit_exceeded);
  397. if (jdeadlock_path == nullptr) {
  398. // exception occcurred
  399. env->DeleteLocalRef(jdeadlock_info_buffer);
  400. return nullptr;
  401. }
  402. env->SetObjectArrayElement(jdeadlock_info_buffer,
  403. jdeadlock_info_buffer_offset++, jdeadlock_path);
  404. if (env->ExceptionCheck()) {
  405. // exception thrown: ArrayIndexOutOfBoundsException or ArrayStoreException
  406. env->DeleteLocalRef(jdeadlock_path);
  407. env->DeleteLocalRef(jdeadlock_info_buffer);
  408. return nullptr;
  409. }
  410. }
  411. return jdeadlock_info_buffer;
  412. }
  413. /*
  414. * Class: org_rocksdb_TransactionDB
  415. * Method: setDeadlockInfoBufferSize
  416. * Signature: (JI)V
  417. */
  418. void Java_org_rocksdb_TransactionDB_setDeadlockInfoBufferSize(
  419. JNIEnv*, jobject, jlong jhandle, jint jdeadlock_info_buffer_size) {
  420. auto* txn_db = reinterpret_cast<ROCKSDB_NAMESPACE::TransactionDB*>(jhandle);
  421. txn_db->SetDeadlockInfoBufferSize(jdeadlock_info_buffer_size);
  422. }