]> git.proxmox.com Git - ceph.git/blame - ceph/src/rocksdb/java/rocksjni/comparatorjnicallback.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / rocksdb / java / rocksjni / comparatorjnicallback.cc
CommitLineData
7c673cae 1// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
11fdf7f2
TL
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).
7c673cae
FG
5//
6// This file implements the callback "bridge" between Java and C++ for
7// rocksdb::Comparator.
8
9#include "rocksjni/comparatorjnicallback.h"
10#include "rocksjni/portal.h"
11
12namespace rocksdb {
13BaseComparatorJniCallback::BaseComparatorJniCallback(
14 JNIEnv* env, jobject jComparator,
15 const ComparatorJniCallbackOptions* copt)
11fdf7f2
TL
16 : JniCallback(env, jComparator),
17 mtx_compare(new port::Mutex(copt->use_adaptive_mutex)),
7c673cae 18 mtx_findShortestSeparator(new port::Mutex(copt->use_adaptive_mutex)) {
7c673cae
FG
19
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 jNameMethodId = AbstractComparatorJni::getNameMethodId(env);
23 if(jNameMethodId == nullptr) {
24 // exception thrown: NoSuchMethodException or OutOfMemoryError
25 return;
26 }
11fdf7f2 27 jstring jsName = (jstring)env->CallObjectMethod(m_jcallback_obj, jNameMethodId);
7c673cae
FG
28 if(env->ExceptionCheck()) {
29 // exception thrown
30 return;
31 }
32 jboolean has_exception = JNI_FALSE;
33 m_name = JniUtil::copyString(env, jsName,
34 &has_exception); // also releases jsName
35 if (has_exception == JNI_TRUE) {
36 // exception thrown
37 return;
38 }
39
40 m_jCompareMethodId = AbstractComparatorJni::getCompareMethodId(env);
41 if(m_jCompareMethodId == nullptr) {
42 // exception thrown: NoSuchMethodException or OutOfMemoryError
43 return;
44 }
45
46 m_jFindShortestSeparatorMethodId =
47 AbstractComparatorJni::getFindShortestSeparatorMethodId(env);
48 if(m_jFindShortestSeparatorMethodId == nullptr) {
49 // exception thrown: NoSuchMethodException or OutOfMemoryError
50 return;
51 }
52
53 m_jFindShortSuccessorMethodId =
54 AbstractComparatorJni::getFindShortSuccessorMethodId(env);
55 if(m_jFindShortSuccessorMethodId == nullptr) {
56 // exception thrown: NoSuchMethodException or OutOfMemoryError
57 return;
58 }
59}
60
61const char* BaseComparatorJniCallback::Name() const {
11fdf7f2 62 return m_name.get();
7c673cae
FG
63}
64
65int BaseComparatorJniCallback::Compare(const Slice& a, const Slice& b) const {
66 jboolean attached_thread = JNI_FALSE;
11fdf7f2 67 JNIEnv* env = getJniEnv(&attached_thread);
7c673cae
FG
68 assert(env != nullptr);
69
70 // TODO(adamretter): slice objects can potentially be cached using thread
71 // local variables to avoid locking. Could make this configurable depending on
72 // performance.
11fdf7f2 73 mtx_compare.get()->Lock();
7c673cae
FG
74
75 bool pending_exception =
76 AbstractSliceJni::setHandle(env, m_jSliceA, &a, JNI_FALSE);
77 if(pending_exception) {
78 if(env->ExceptionCheck()) {
79 // exception thrown from setHandle or descendant
80 env->ExceptionDescribe(); // print out exception to stderr
81 }
11fdf7f2 82 releaseJniEnv(attached_thread);
7c673cae
FG
83 return 0;
84 }
85
86 pending_exception =
87 AbstractSliceJni::setHandle(env, m_jSliceB, &b, JNI_FALSE);
88 if(pending_exception) {
89 if(env->ExceptionCheck()) {
90 // exception thrown from setHandle or descendant
91 env->ExceptionDescribe(); // print out exception to stderr
92 }
11fdf7f2 93 releaseJniEnv(attached_thread);
7c673cae
FG
94 return 0;
95 }
11fdf7f2 96
7c673cae 97 jint result =
11fdf7f2 98 env->CallIntMethod(m_jcallback_obj, m_jCompareMethodId, m_jSliceA,
7c673cae
FG
99 m_jSliceB);
100
11fdf7f2 101 mtx_compare.get()->Unlock();
7c673cae
FG
102
103 if(env->ExceptionCheck()) {
104 // exception thrown from CallIntMethod
105 env->ExceptionDescribe(); // print out exception to stderr
106 result = 0; // we could not get a result from java callback so use 0
107 }
108
11fdf7f2 109 releaseJniEnv(attached_thread);
7c673cae
FG
110
111 return result;
112}
113
114void BaseComparatorJniCallback::FindShortestSeparator(
11fdf7f2 115 std::string* start, const Slice& limit) const {
7c673cae
FG
116 if (start == nullptr) {
117 return;
118 }
119
120 jboolean attached_thread = JNI_FALSE;
11fdf7f2 121 JNIEnv* env = getJniEnv(&attached_thread);
7c673cae
FG
122 assert(env != nullptr);
123
124 const char* startUtf = start->c_str();
125 jstring jsStart = env->NewStringUTF(startUtf);
126 if(jsStart == nullptr) {
127 // unable to construct string
128 if(env->ExceptionCheck()) {
129 env->ExceptionDescribe(); // print out exception to stderr
130 }
11fdf7f2 131 releaseJniEnv(attached_thread);
7c673cae
FG
132 return;
133 }
134 if(env->ExceptionCheck()) {
135 // exception thrown: OutOfMemoryError
136 env->ExceptionDescribe(); // print out exception to stderr
137 env->DeleteLocalRef(jsStart);
11fdf7f2 138 releaseJniEnv(attached_thread);
7c673cae
FG
139 return;
140 }
141
142 // TODO(adamretter): slice object can potentially be cached using thread local
143 // variable to avoid locking. Could make this configurable depending on
144 // performance.
11fdf7f2 145 mtx_findShortestSeparator.get()->Lock();
7c673cae
FG
146
147 bool pending_exception =
148 AbstractSliceJni::setHandle(env, m_jSliceLimit, &limit, JNI_FALSE);
149 if(pending_exception) {
150 if(env->ExceptionCheck()) {
151 // exception thrown from setHandle or descendant
152 env->ExceptionDescribe(); // print out exception to stderr
153 }
154 if(jsStart != nullptr) {
155 env->DeleteLocalRef(jsStart);
156 }
11fdf7f2 157 releaseJniEnv(attached_thread);
7c673cae
FG
158 return;
159 }
160
161 jstring jsResultStart =
11fdf7f2 162 (jstring)env->CallObjectMethod(m_jcallback_obj,
7c673cae
FG
163 m_jFindShortestSeparatorMethodId, jsStart, m_jSliceLimit);
164
11fdf7f2 165 mtx_findShortestSeparator.get()->Unlock();
7c673cae
FG
166
167 if(env->ExceptionCheck()) {
168 // exception thrown from CallObjectMethod
169 env->ExceptionDescribe(); // print out exception to stderr
170 env->DeleteLocalRef(jsStart);
11fdf7f2 171 releaseJniEnv(attached_thread);
7c673cae
FG
172 return;
173 }
174
175 env->DeleteLocalRef(jsStart);
176
177 if (jsResultStart != nullptr) {
178 // update start with result
179 jboolean has_exception = JNI_FALSE;
11fdf7f2 180 std::unique_ptr<const char[]> result_start = JniUtil::copyString(env, jsResultStart,
7c673cae
FG
181 &has_exception); // also releases jsResultStart
182 if (has_exception == JNI_TRUE) {
183 if (env->ExceptionCheck()) {
184 env->ExceptionDescribe(); // print out exception to stderr
185 }
11fdf7f2 186 releaseJniEnv(attached_thread);
7c673cae
FG
187 return;
188 }
189
11fdf7f2 190 start->assign(result_start.get());
7c673cae 191 }
11fdf7f2 192 releaseJniEnv(attached_thread);
7c673cae
FG
193}
194
11fdf7f2
TL
195void BaseComparatorJniCallback::FindShortSuccessor(
196 std::string* key) const {
7c673cae
FG
197 if (key == nullptr) {
198 return;
199 }
200
201 jboolean attached_thread = JNI_FALSE;
11fdf7f2 202 JNIEnv* env = getJniEnv(&attached_thread);
7c673cae
FG
203 assert(env != nullptr);
204
205 const char* keyUtf = key->c_str();
206 jstring jsKey = env->NewStringUTF(keyUtf);
207 if(jsKey == nullptr) {
208 // unable to construct string
209 if(env->ExceptionCheck()) {
210 env->ExceptionDescribe(); // print out exception to stderr
211 }
11fdf7f2 212 releaseJniEnv(attached_thread);
7c673cae
FG
213 return;
214 } else if(env->ExceptionCheck()) {
215 // exception thrown: OutOfMemoryError
216 env->ExceptionDescribe(); // print out exception to stderr
217 env->DeleteLocalRef(jsKey);
11fdf7f2 218 releaseJniEnv(attached_thread);
7c673cae
FG
219 return;
220 }
221
222 jstring jsResultKey =
11fdf7f2 223 (jstring)env->CallObjectMethod(m_jcallback_obj,
7c673cae
FG
224 m_jFindShortSuccessorMethodId, jsKey);
225
226 if(env->ExceptionCheck()) {
227 // exception thrown from CallObjectMethod
228 env->ExceptionDescribe(); // print out exception to stderr
229 env->DeleteLocalRef(jsKey);
11fdf7f2 230 releaseJniEnv(attached_thread);
7c673cae
FG
231 return;
232 }
233
234 env->DeleteLocalRef(jsKey);
235
236 if (jsResultKey != nullptr) {
237 // updates key with result, also releases jsResultKey.
238 jboolean has_exception = JNI_FALSE;
11fdf7f2
TL
239 std::unique_ptr<const char[]> result_key = JniUtil::copyString(env, jsResultKey,
240 &has_exception); // also releases jsResultKey
7c673cae
FG
241 if (has_exception == JNI_TRUE) {
242 if (env->ExceptionCheck()) {
243 env->ExceptionDescribe(); // print out exception to stderr
244 }
11fdf7f2 245 releaseJniEnv(attached_thread);
7c673cae
FG
246 return;
247 }
248
11fdf7f2 249 key->assign(result_key.get());
7c673cae
FG
250 }
251
11fdf7f2 252 releaseJniEnv(attached_thread);
7c673cae
FG
253}
254
255ComparatorJniCallback::ComparatorJniCallback(
256 JNIEnv* env, jobject jComparator,
257 const ComparatorJniCallbackOptions* copt) :
258 BaseComparatorJniCallback(env, jComparator, copt) {
259 m_jSliceA = env->NewGlobalRef(SliceJni::construct0(env));
260 if(m_jSliceA == nullptr) {
261 // exception thrown: OutOfMemoryError
262 return;
263 }
264
265 m_jSliceB = env->NewGlobalRef(SliceJni::construct0(env));
266 if(m_jSliceB == nullptr) {
267 // exception thrown: OutOfMemoryError
268 return;
269 }
270
271 m_jSliceLimit = env->NewGlobalRef(SliceJni::construct0(env));
272 if(m_jSliceLimit == nullptr) {
273 // exception thrown: OutOfMemoryError
274 return;
275 }
276}
277
278ComparatorJniCallback::~ComparatorJniCallback() {
279 jboolean attached_thread = JNI_FALSE;
11fdf7f2 280 JNIEnv* env = getJniEnv(&attached_thread);
7c673cae
FG
281 assert(env != nullptr);
282
283 if(m_jSliceA != nullptr) {
284 env->DeleteGlobalRef(m_jSliceA);
285 }
286
287 if(m_jSliceB != nullptr) {
288 env->DeleteGlobalRef(m_jSliceB);
289 }
290
291 if(m_jSliceLimit != nullptr) {
292 env->DeleteGlobalRef(m_jSliceLimit);
293 }
294
11fdf7f2 295 releaseJniEnv(attached_thread);
7c673cae
FG
296}
297
298DirectComparatorJniCallback::DirectComparatorJniCallback(
299 JNIEnv* env, jobject jComparator,
300 const ComparatorJniCallbackOptions* copt) :
301 BaseComparatorJniCallback(env, jComparator, copt) {
302 m_jSliceA = env->NewGlobalRef(DirectSliceJni::construct0(env));
303 if(m_jSliceA == nullptr) {
304 // exception thrown: OutOfMemoryError
305 return;
306 }
307
308 m_jSliceB = env->NewGlobalRef(DirectSliceJni::construct0(env));
309 if(m_jSliceB == nullptr) {
310 // exception thrown: OutOfMemoryError
311 return;
312 }
313
314 m_jSliceLimit = env->NewGlobalRef(DirectSliceJni::construct0(env));
315 if(m_jSliceLimit == nullptr) {
316 // exception thrown: OutOfMemoryError
317 return;
318 }
319}
320
321DirectComparatorJniCallback::~DirectComparatorJniCallback() {
322 jboolean attached_thread = JNI_FALSE;
11fdf7f2 323 JNIEnv* env = getJniEnv(&attached_thread);
7c673cae
FG
324 assert(env != nullptr);
325
326 if(m_jSliceA != nullptr) {
327 env->DeleteGlobalRef(m_jSliceA);
328 }
329
330 if(m_jSliceB != nullptr) {
331 env->DeleteGlobalRef(m_jSliceB);
332 }
333
334 if(m_jSliceLimit != nullptr) {
335 env->DeleteGlobalRef(m_jSliceLimit);
336 }
337
11fdf7f2 338 releaseJniEnv(attached_thread);
7c673cae
FG
339}
340} // namespace rocksdb