comparatorjnicallback.cc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  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 callback "bridge" between Java and C++ for
  7. // ROCKSDB_NAMESPACE::Comparator.
  8. #include "rocksjni/comparatorjnicallback.h"
  9. #include "rocksjni/portal.h"
  10. namespace ROCKSDB_NAMESPACE {
  11. ComparatorJniCallback::ComparatorJniCallback(
  12. JNIEnv* env, jobject jcomparator,
  13. const ComparatorJniCallbackOptions* options)
  14. : JniCallback(env, jcomparator),
  15. m_options(std::make_unique<ComparatorJniCallbackOptions>(*options)) {
  16. // cache the AbstractComparatorJniBridge class as we will reuse it many times
  17. // for each callback
  18. m_abstract_comparator_jni_bridge_clazz = static_cast<jclass>(
  19. env->NewGlobalRef(AbstractComparatorJniBridge::getJClass(env)));
  20. // Note: The name of a Comparator will not change during it's lifetime,
  21. // so we cache it in a global var
  22. jmethodID jname_mid = AbstractComparatorJni::getNameMethodId(env);
  23. if (jname_mid == nullptr) {
  24. // exception thrown: NoSuchMethodException or OutOfMemoryError
  25. return;
  26. }
  27. jstring js_name = (jstring)env->CallObjectMethod(m_jcallback_obj, jname_mid);
  28. if (env->ExceptionCheck()) {
  29. // exception thrown
  30. return;
  31. }
  32. jboolean has_exception = JNI_FALSE;
  33. m_name = JniUtil::copyString(env, js_name,
  34. &has_exception); // also releases jsName
  35. if (has_exception == JNI_TRUE) {
  36. // exception thrown
  37. return;
  38. }
  39. // cache the ByteBuffer class as we will reuse it many times for each callback
  40. m_jbytebuffer_clazz =
  41. static_cast<jclass>(env->NewGlobalRef(ByteBufferJni::getJClass(env)));
  42. m_jcompare_mid = AbstractComparatorJniBridge::getCompareInternalMethodId(
  43. env, m_abstract_comparator_jni_bridge_clazz);
  44. if (m_jcompare_mid == nullptr) {
  45. // exception thrown: NoSuchMethodException or OutOfMemoryError
  46. return;
  47. }
  48. m_jshortest_mid =
  49. AbstractComparatorJniBridge::getFindShortestSeparatorInternalMethodId(
  50. env, m_abstract_comparator_jni_bridge_clazz);
  51. if (m_jshortest_mid == nullptr) {
  52. // exception thrown: NoSuchMethodException or OutOfMemoryError
  53. return;
  54. }
  55. m_jshort_mid =
  56. AbstractComparatorJniBridge::getFindShortSuccessorInternalMethodId(
  57. env, m_abstract_comparator_jni_bridge_clazz);
  58. if (m_jshort_mid == nullptr) {
  59. // exception thrown: NoSuchMethodException or OutOfMemoryError
  60. return;
  61. }
  62. // do we need reusable buffers?
  63. if (m_options->max_reused_buffer_size > -1) {
  64. if (m_options->reused_synchronisation_type ==
  65. ReusedSynchronisationType::THREAD_LOCAL) {
  66. // buffers reused per thread
  67. UnrefHandler unref = [](void* ptr) {
  68. ThreadLocalBuf* tlb = reinterpret_cast<ThreadLocalBuf*>(ptr);
  69. jboolean attached_thread = JNI_FALSE;
  70. JNIEnv* _env = JniUtil::getJniEnv(tlb->jvm, &attached_thread);
  71. if (_env != nullptr) {
  72. if (tlb->direct_buffer) {
  73. void* buf = _env->GetDirectBufferAddress(tlb->jbuf);
  74. delete[] static_cast<char*>(buf);
  75. }
  76. _env->DeleteGlobalRef(tlb->jbuf);
  77. JniUtil::releaseJniEnv(tlb->jvm, attached_thread);
  78. }
  79. };
  80. m_tl_buf_a = new ThreadLocalPtr(unref);
  81. m_tl_buf_b = new ThreadLocalPtr(unref);
  82. m_jcompare_buf_a = nullptr;
  83. m_jcompare_buf_b = nullptr;
  84. m_jshortest_buf_start = nullptr;
  85. m_jshortest_buf_limit = nullptr;
  86. m_jshort_buf_key = nullptr;
  87. } else {
  88. // buffers reused and shared across threads
  89. const bool adaptive = m_options->reused_synchronisation_type ==
  90. ReusedSynchronisationType::ADAPTIVE_MUTEX;
  91. mtx_compare = std::unique_ptr<port::Mutex>(new port::Mutex(adaptive));
  92. mtx_shortest = std::unique_ptr<port::Mutex>(new port::Mutex(adaptive));
  93. mtx_short = std::unique_ptr<port::Mutex>(new port::Mutex(adaptive));
  94. m_jcompare_buf_a = env->NewGlobalRef(ByteBufferJni::construct(
  95. env, m_options->direct_buffer, m_options->max_reused_buffer_size,
  96. m_jbytebuffer_clazz));
  97. if (m_jcompare_buf_a == nullptr) {
  98. // exception thrown: OutOfMemoryError
  99. return;
  100. }
  101. m_jcompare_buf_b = env->NewGlobalRef(ByteBufferJni::construct(
  102. env, m_options->direct_buffer, m_options->max_reused_buffer_size,
  103. m_jbytebuffer_clazz));
  104. if (m_jcompare_buf_b == nullptr) {
  105. // exception thrown: OutOfMemoryError
  106. return;
  107. }
  108. m_jshortest_buf_start = env->NewGlobalRef(ByteBufferJni::construct(
  109. env, m_options->direct_buffer, m_options->max_reused_buffer_size,
  110. m_jbytebuffer_clazz));
  111. if (m_jshortest_buf_start == nullptr) {
  112. // exception thrown: OutOfMemoryError
  113. return;
  114. }
  115. m_jshortest_buf_limit = env->NewGlobalRef(ByteBufferJni::construct(
  116. env, m_options->direct_buffer, m_options->max_reused_buffer_size,
  117. m_jbytebuffer_clazz));
  118. if (m_jshortest_buf_limit == nullptr) {
  119. // exception thrown: OutOfMemoryError
  120. return;
  121. }
  122. m_jshort_buf_key = env->NewGlobalRef(ByteBufferJni::construct(
  123. env, m_options->direct_buffer, m_options->max_reused_buffer_size,
  124. m_jbytebuffer_clazz));
  125. if (m_jshort_buf_key == nullptr) {
  126. // exception thrown: OutOfMemoryError
  127. return;
  128. }
  129. m_tl_buf_a = nullptr;
  130. m_tl_buf_b = nullptr;
  131. }
  132. } else {
  133. m_jcompare_buf_a = nullptr;
  134. m_jcompare_buf_b = nullptr;
  135. m_jshortest_buf_start = nullptr;
  136. m_jshortest_buf_limit = nullptr;
  137. m_jshort_buf_key = nullptr;
  138. m_tl_buf_a = nullptr;
  139. m_tl_buf_b = nullptr;
  140. }
  141. }
  142. ComparatorJniCallback::~ComparatorJniCallback() {
  143. jboolean attached_thread = JNI_FALSE;
  144. JNIEnv* env = getJniEnv(&attached_thread);
  145. assert(env != nullptr);
  146. env->DeleteGlobalRef(m_abstract_comparator_jni_bridge_clazz);
  147. env->DeleteGlobalRef(m_jbytebuffer_clazz);
  148. if (m_jcompare_buf_a != nullptr) {
  149. if (m_options->direct_buffer) {
  150. void* buf = env->GetDirectBufferAddress(m_jcompare_buf_a);
  151. delete[] static_cast<char*>(buf);
  152. }
  153. env->DeleteGlobalRef(m_jcompare_buf_a);
  154. }
  155. if (m_jcompare_buf_b != nullptr) {
  156. if (m_options->direct_buffer) {
  157. void* buf = env->GetDirectBufferAddress(m_jcompare_buf_b);
  158. delete[] static_cast<char*>(buf);
  159. }
  160. env->DeleteGlobalRef(m_jcompare_buf_b);
  161. }
  162. if (m_jshortest_buf_start != nullptr) {
  163. if (m_options->direct_buffer) {
  164. void* buf = env->GetDirectBufferAddress(m_jshortest_buf_start);
  165. delete[] static_cast<char*>(buf);
  166. }
  167. env->DeleteGlobalRef(m_jshortest_buf_start);
  168. }
  169. if (m_jshortest_buf_limit != nullptr) {
  170. if (m_options->direct_buffer) {
  171. void* buf = env->GetDirectBufferAddress(m_jshortest_buf_limit);
  172. delete[] static_cast<char*>(buf);
  173. }
  174. env->DeleteGlobalRef(m_jshortest_buf_limit);
  175. }
  176. if (m_jshort_buf_key != nullptr) {
  177. if (m_options->direct_buffer) {
  178. void* buf = env->GetDirectBufferAddress(m_jshort_buf_key);
  179. delete[] static_cast<char*>(buf);
  180. }
  181. env->DeleteGlobalRef(m_jshort_buf_key);
  182. }
  183. if (m_tl_buf_a != nullptr) {
  184. delete m_tl_buf_a;
  185. }
  186. if (m_tl_buf_b != nullptr) {
  187. delete m_tl_buf_b;
  188. }
  189. releaseJniEnv(attached_thread);
  190. }
  191. const char* ComparatorJniCallback::Name() const { return m_name.get(); }
  192. int ComparatorJniCallback::Compare(const Slice& a, const Slice& b) const {
  193. jboolean attached_thread = JNI_FALSE;
  194. JNIEnv* env = getJniEnv(&attached_thread);
  195. assert(env != nullptr);
  196. const bool reuse_jbuf_a =
  197. static_cast<int64_t>(a.size()) <= m_options->max_reused_buffer_size;
  198. const bool reuse_jbuf_b =
  199. static_cast<int64_t>(b.size()) <= m_options->max_reused_buffer_size;
  200. MaybeLockForReuse(mtx_compare, reuse_jbuf_a || reuse_jbuf_b);
  201. jobject jcompare_buf_a =
  202. GetBuffer(env, a, reuse_jbuf_a, m_tl_buf_a, m_jcompare_buf_a);
  203. if (jcompare_buf_a == nullptr) {
  204. // exception occurred
  205. MaybeUnlockForReuse(mtx_compare, reuse_jbuf_a || reuse_jbuf_b);
  206. env->ExceptionDescribe(); // print out exception to stderr
  207. releaseJniEnv(attached_thread);
  208. return 0;
  209. }
  210. jobject jcompare_buf_b =
  211. GetBuffer(env, b, reuse_jbuf_b, m_tl_buf_b, m_jcompare_buf_b);
  212. if (jcompare_buf_b == nullptr) {
  213. // exception occurred
  214. if (!reuse_jbuf_a) {
  215. DeleteBuffer(env, jcompare_buf_a);
  216. }
  217. MaybeUnlockForReuse(mtx_compare, reuse_jbuf_a || reuse_jbuf_b);
  218. env->ExceptionDescribe(); // print out exception to stderr
  219. releaseJniEnv(attached_thread);
  220. return 0;
  221. }
  222. jint result = env->CallStaticIntMethod(
  223. m_abstract_comparator_jni_bridge_clazz, m_jcompare_mid, m_jcallback_obj,
  224. jcompare_buf_a, reuse_jbuf_a ? a.size() : -1, jcompare_buf_b,
  225. reuse_jbuf_b ? b.size() : -1);
  226. if (env->ExceptionCheck()) {
  227. // exception thrown from CallIntMethod
  228. env->ExceptionDescribe(); // print out exception to stderr
  229. result = 0; // we could not get a result from java callback so use 0
  230. }
  231. if (!reuse_jbuf_a) {
  232. DeleteBuffer(env, jcompare_buf_a);
  233. }
  234. if (!reuse_jbuf_b) {
  235. DeleteBuffer(env, jcompare_buf_b);
  236. }
  237. MaybeUnlockForReuse(mtx_compare, reuse_jbuf_a || reuse_jbuf_b);
  238. releaseJniEnv(attached_thread);
  239. return result;
  240. }
  241. void ComparatorJniCallback::FindShortestSeparator(std::string* start,
  242. const Slice& limit) const {
  243. if (start == nullptr) {
  244. return;
  245. }
  246. jboolean attached_thread = JNI_FALSE;
  247. JNIEnv* env = getJniEnv(&attached_thread);
  248. assert(env != nullptr);
  249. const bool reuse_jbuf_start = static_cast<int64_t>(start->length()) <=
  250. m_options->max_reused_buffer_size;
  251. const bool reuse_jbuf_limit =
  252. static_cast<int64_t>(limit.size()) <= m_options->max_reused_buffer_size;
  253. MaybeLockForReuse(mtx_shortest, reuse_jbuf_start || reuse_jbuf_limit);
  254. Slice sstart(start->data(), start->length());
  255. jobject j_start_buf = GetBuffer(env, sstart, reuse_jbuf_start, m_tl_buf_a,
  256. m_jshortest_buf_start);
  257. if (j_start_buf == nullptr) {
  258. // exception occurred
  259. MaybeUnlockForReuse(mtx_shortest, reuse_jbuf_start || reuse_jbuf_limit);
  260. env->ExceptionDescribe(); // print out exception to stderr
  261. releaseJniEnv(attached_thread);
  262. return;
  263. }
  264. jobject j_limit_buf = GetBuffer(env, limit, reuse_jbuf_limit, m_tl_buf_b,
  265. m_jshortest_buf_limit);
  266. if (j_limit_buf == nullptr) {
  267. // exception occurred
  268. if (!reuse_jbuf_start) {
  269. DeleteBuffer(env, j_start_buf);
  270. }
  271. MaybeUnlockForReuse(mtx_shortest, reuse_jbuf_start || reuse_jbuf_limit);
  272. env->ExceptionDescribe(); // print out exception to stderr
  273. releaseJniEnv(attached_thread);
  274. return;
  275. }
  276. jint jstart_len = env->CallStaticIntMethod(
  277. m_abstract_comparator_jni_bridge_clazz, m_jshortest_mid, m_jcallback_obj,
  278. j_start_buf, reuse_jbuf_start ? start->length() : -1, j_limit_buf,
  279. reuse_jbuf_limit ? limit.size() : -1);
  280. if (env->ExceptionCheck()) {
  281. // exception thrown from CallIntMethod
  282. env->ExceptionDescribe(); // print out exception to stderr
  283. } else if (static_cast<size_t>(jstart_len) != start->length()) {
  284. // start buffer has changed in Java, so update `start` with the result
  285. bool copy_from_non_direct = false;
  286. if (reuse_jbuf_start) {
  287. // reused a buffer
  288. if (m_options->direct_buffer) {
  289. // reused direct buffer
  290. void* start_buf = env->GetDirectBufferAddress(j_start_buf);
  291. if (start_buf == nullptr) {
  292. if (!reuse_jbuf_start) {
  293. DeleteBuffer(env, j_start_buf);
  294. }
  295. if (!reuse_jbuf_limit) {
  296. DeleteBuffer(env, j_limit_buf);
  297. }
  298. MaybeUnlockForReuse(mtx_shortest,
  299. reuse_jbuf_start || reuse_jbuf_limit);
  300. ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(
  301. env, "Unable to get Direct Buffer Address");
  302. env->ExceptionDescribe(); // print out exception to stderr
  303. releaseJniEnv(attached_thread);
  304. return;
  305. }
  306. start->assign(static_cast<const char*>(start_buf), jstart_len);
  307. } else {
  308. // reused non-direct buffer
  309. copy_from_non_direct = true;
  310. }
  311. } else {
  312. // there was a new buffer
  313. if (m_options->direct_buffer) {
  314. // it was direct... don't forget to potentially truncate the `start`
  315. // string
  316. start->resize(jstart_len);
  317. } else {
  318. // it was non-direct
  319. copy_from_non_direct = true;
  320. }
  321. }
  322. if (copy_from_non_direct) {
  323. jbyteArray jarray =
  324. ByteBufferJni::array(env, j_start_buf, m_jbytebuffer_clazz);
  325. if (jarray == nullptr) {
  326. if (!reuse_jbuf_start) {
  327. DeleteBuffer(env, j_start_buf);
  328. }
  329. if (!reuse_jbuf_limit) {
  330. DeleteBuffer(env, j_limit_buf);
  331. }
  332. MaybeUnlockForReuse(mtx_shortest, reuse_jbuf_start || reuse_jbuf_limit);
  333. env->ExceptionDescribe(); // print out exception to stderr
  334. releaseJniEnv(attached_thread);
  335. return;
  336. }
  337. jboolean has_exception = JNI_FALSE;
  338. JniUtil::byteString<std::string>(
  339. env, jarray,
  340. [start, jstart_len](const char* data, const size_t) {
  341. return start->assign(data, static_cast<size_t>(jstart_len));
  342. },
  343. &has_exception);
  344. env->DeleteLocalRef(jarray);
  345. if (has_exception == JNI_TRUE) {
  346. if (!reuse_jbuf_start) {
  347. DeleteBuffer(env, j_start_buf);
  348. }
  349. if (!reuse_jbuf_limit) {
  350. DeleteBuffer(env, j_limit_buf);
  351. }
  352. env->ExceptionDescribe(); // print out exception to stderr
  353. MaybeUnlockForReuse(mtx_shortest, reuse_jbuf_start || reuse_jbuf_limit);
  354. releaseJniEnv(attached_thread);
  355. return;
  356. }
  357. }
  358. }
  359. if (!reuse_jbuf_start) {
  360. DeleteBuffer(env, j_start_buf);
  361. }
  362. if (!reuse_jbuf_limit) {
  363. DeleteBuffer(env, j_limit_buf);
  364. }
  365. MaybeUnlockForReuse(mtx_shortest, reuse_jbuf_start || reuse_jbuf_limit);
  366. releaseJniEnv(attached_thread);
  367. }
  368. void ComparatorJniCallback::FindShortSuccessor(std::string* key) const {
  369. if (key == nullptr) {
  370. return;
  371. }
  372. jboolean attached_thread = JNI_FALSE;
  373. JNIEnv* env = getJniEnv(&attached_thread);
  374. assert(env != nullptr);
  375. const bool reuse_jbuf_key =
  376. static_cast<int64_t>(key->length()) <= m_options->max_reused_buffer_size;
  377. MaybeLockForReuse(mtx_short, reuse_jbuf_key);
  378. Slice skey(key->data(), key->length());
  379. jobject j_key_buf =
  380. GetBuffer(env, skey, reuse_jbuf_key, m_tl_buf_a, m_jshort_buf_key);
  381. if (j_key_buf == nullptr) {
  382. // exception occurred
  383. MaybeUnlockForReuse(mtx_short, reuse_jbuf_key);
  384. env->ExceptionDescribe(); // print out exception to stderr
  385. releaseJniEnv(attached_thread);
  386. return;
  387. }
  388. jint jkey_len = env->CallStaticIntMethod(
  389. m_abstract_comparator_jni_bridge_clazz, m_jshort_mid, m_jcallback_obj,
  390. j_key_buf, reuse_jbuf_key ? key->length() : -1);
  391. if (env->ExceptionCheck()) {
  392. // exception thrown from CallObjectMethod
  393. if (!reuse_jbuf_key) {
  394. DeleteBuffer(env, j_key_buf);
  395. }
  396. MaybeUnlockForReuse(mtx_short, reuse_jbuf_key);
  397. env->ExceptionDescribe(); // print out exception to stderr
  398. releaseJniEnv(attached_thread);
  399. return;
  400. }
  401. if (static_cast<size_t>(jkey_len) != key->length()) {
  402. // key buffer has changed in Java, so update `key` with the result
  403. bool copy_from_non_direct = false;
  404. if (reuse_jbuf_key) {
  405. // reused a buffer
  406. if (m_options->direct_buffer) {
  407. // reused direct buffer
  408. void* key_buf = env->GetDirectBufferAddress(j_key_buf);
  409. if (key_buf == nullptr) {
  410. ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(
  411. env, "Unable to get Direct Buffer Address");
  412. if (!reuse_jbuf_key) {
  413. DeleteBuffer(env, j_key_buf);
  414. }
  415. MaybeUnlockForReuse(mtx_short, reuse_jbuf_key);
  416. env->ExceptionDescribe(); // print out exception to stderr
  417. releaseJniEnv(attached_thread);
  418. return;
  419. }
  420. key->assign(static_cast<const char*>(key_buf), jkey_len);
  421. } else {
  422. // reused non-direct buffer
  423. copy_from_non_direct = true;
  424. }
  425. } else {
  426. // there was a new buffer
  427. if (m_options->direct_buffer) {
  428. // it was direct... don't forget to potentially truncate the `key`
  429. // string
  430. key->resize(jkey_len);
  431. } else {
  432. // it was non-direct
  433. copy_from_non_direct = true;
  434. }
  435. }
  436. if (copy_from_non_direct) {
  437. jbyteArray jarray =
  438. ByteBufferJni::array(env, j_key_buf, m_jbytebuffer_clazz);
  439. if (jarray == nullptr) {
  440. if (!reuse_jbuf_key) {
  441. DeleteBuffer(env, j_key_buf);
  442. }
  443. MaybeUnlockForReuse(mtx_short, reuse_jbuf_key);
  444. env->ExceptionDescribe(); // print out exception to stderr
  445. releaseJniEnv(attached_thread);
  446. return;
  447. }
  448. jboolean has_exception = JNI_FALSE;
  449. JniUtil::byteString<std::string>(
  450. env, jarray,
  451. [key, jkey_len](const char* data, const size_t) {
  452. return key->assign(data, static_cast<size_t>(jkey_len));
  453. },
  454. &has_exception);
  455. env->DeleteLocalRef(jarray);
  456. if (has_exception == JNI_TRUE) {
  457. if (!reuse_jbuf_key) {
  458. DeleteBuffer(env, j_key_buf);
  459. }
  460. MaybeUnlockForReuse(mtx_short, reuse_jbuf_key);
  461. env->ExceptionDescribe(); // print out exception to stderr
  462. releaseJniEnv(attached_thread);
  463. return;
  464. }
  465. }
  466. }
  467. if (!reuse_jbuf_key) {
  468. DeleteBuffer(env, j_key_buf);
  469. }
  470. MaybeUnlockForReuse(mtx_short, reuse_jbuf_key);
  471. releaseJniEnv(attached_thread);
  472. }
  473. inline void ComparatorJniCallback::MaybeLockForReuse(
  474. const std::unique_ptr<port::Mutex>& mutex, const bool cond) const {
  475. // no need to lock if using thread_local
  476. if (m_options->reused_synchronisation_type !=
  477. ReusedSynchronisationType::THREAD_LOCAL &&
  478. cond) {
  479. mutex.get()->Lock();
  480. }
  481. }
  482. inline void ComparatorJniCallback::MaybeUnlockForReuse(
  483. const std::unique_ptr<port::Mutex>& mutex, const bool cond) const {
  484. // no need to unlock if using thread_local
  485. if (m_options->reused_synchronisation_type !=
  486. ReusedSynchronisationType::THREAD_LOCAL &&
  487. cond) {
  488. mutex.get()->Unlock();
  489. }
  490. }
  491. jobject ComparatorJniCallback::GetBuffer(JNIEnv* env, const Slice& src,
  492. bool reuse_buffer,
  493. ThreadLocalPtr* tl_buf,
  494. jobject jreuse_buffer) const {
  495. if (reuse_buffer) {
  496. if (m_options->reused_synchronisation_type ==
  497. ReusedSynchronisationType::THREAD_LOCAL) {
  498. // reuse thread-local bufffer
  499. ThreadLocalBuf* tlb = reinterpret_cast<ThreadLocalBuf*>(tl_buf->Get());
  500. if (tlb == nullptr) {
  501. // thread-local buffer has not yet been created, so create it
  502. jobject jtl_buf = env->NewGlobalRef(ByteBufferJni::construct(
  503. env, m_options->direct_buffer, m_options->max_reused_buffer_size,
  504. m_jbytebuffer_clazz));
  505. if (jtl_buf == nullptr) {
  506. // exception thrown: OutOfMemoryError
  507. return nullptr;
  508. }
  509. tlb = new ThreadLocalBuf(m_jvm, m_options->direct_buffer, jtl_buf);
  510. tl_buf->Reset(tlb);
  511. }
  512. return ReuseBuffer(env, src, tlb->jbuf);
  513. } else {
  514. // reuse class member buffer
  515. return ReuseBuffer(env, src, jreuse_buffer);
  516. }
  517. } else {
  518. // new buffer
  519. return NewBuffer(env, src);
  520. }
  521. }
  522. jobject ComparatorJniCallback::ReuseBuffer(JNIEnv* env, const Slice& src,
  523. jobject jreuse_buffer) const {
  524. // we can reuse the buffer
  525. if (m_options->direct_buffer) {
  526. // copy into direct buffer
  527. void* buf = env->GetDirectBufferAddress(jreuse_buffer);
  528. if (buf == nullptr) {
  529. // either memory region is undefined, given object is not a direct
  530. // java.nio.Buffer, or JNI access to direct buffers is not supported by
  531. // this virtual machine.
  532. ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(
  533. env, "Unable to get Direct Buffer Address");
  534. return nullptr;
  535. }
  536. memcpy(buf, src.data(), src.size());
  537. } else {
  538. // copy into non-direct buffer
  539. const jbyteArray jarray =
  540. ByteBufferJni::array(env, jreuse_buffer, m_jbytebuffer_clazz);
  541. if (jarray == nullptr) {
  542. // exception occurred
  543. return nullptr;
  544. }
  545. env->SetByteArrayRegion(
  546. jarray, 0, static_cast<jsize>(src.size()),
  547. const_cast<jbyte*>(reinterpret_cast<const jbyte*>(src.data())));
  548. if (env->ExceptionCheck()) {
  549. // exception occurred
  550. env->DeleteLocalRef(jarray);
  551. return nullptr;
  552. }
  553. env->DeleteLocalRef(jarray);
  554. }
  555. return jreuse_buffer;
  556. }
  557. jobject ComparatorJniCallback::NewBuffer(JNIEnv* env, const Slice& src) const {
  558. // we need a new buffer
  559. jobject jbuf =
  560. ByteBufferJni::constructWith(env, m_options->direct_buffer, src.data(),
  561. src.size(), m_jbytebuffer_clazz);
  562. if (jbuf == nullptr) {
  563. // exception occurred
  564. return nullptr;
  565. }
  566. return jbuf;
  567. }
  568. void ComparatorJniCallback::DeleteBuffer(JNIEnv* env, jobject jbuffer) const {
  569. env->DeleteLocalRef(jbuffer);
  570. }
  571. } // namespace ROCKSDB_NAMESPACE