transaction_db.cc 16 KB

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