]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/java/rocksjni/comparatorjnicallback.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / rocksdb / java / rocksjni / comparatorjnicallback.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 callback "bridge" between Java and C++ for
7 // rocksdb::Comparator.
8
9 #include "rocksjni/comparatorjnicallback.h"
10 #include "rocksjni/portal.h"
11
12 namespace rocksdb {
13 BaseComparatorJniCallback::BaseComparatorJniCallback(
14 JNIEnv* env, jobject jComparator,
15 const ComparatorJniCallbackOptions* copt)
16 : JniCallback(env, jComparator),
17 mtx_compare(new port::Mutex(copt->use_adaptive_mutex)),
18 mtx_findShortestSeparator(new port::Mutex(copt->use_adaptive_mutex)) {
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 }
27 jstring jsName = (jstring)env->CallObjectMethod(m_jcallback_obj, jNameMethodId);
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
61 const char* BaseComparatorJniCallback::Name() const {
62 return m_name.get();
63 }
64
65 int BaseComparatorJniCallback::Compare(const Slice& a, const Slice& b) const {
66 jboolean attached_thread = JNI_FALSE;
67 JNIEnv* env = getJniEnv(&attached_thread);
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.
73 mtx_compare.get()->Lock();
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 }
82 releaseJniEnv(attached_thread);
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 }
93 releaseJniEnv(attached_thread);
94 return 0;
95 }
96
97 jint result =
98 env->CallIntMethod(m_jcallback_obj, m_jCompareMethodId, m_jSliceA,
99 m_jSliceB);
100
101 mtx_compare.get()->Unlock();
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
109 releaseJniEnv(attached_thread);
110
111 return result;
112 }
113
114 void BaseComparatorJniCallback::FindShortestSeparator(
115 std::string* start, const Slice& limit) const {
116 if (start == nullptr) {
117 return;
118 }
119
120 jboolean attached_thread = JNI_FALSE;
121 JNIEnv* env = getJniEnv(&attached_thread);
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 }
131 releaseJniEnv(attached_thread);
132 return;
133 }
134 if(env->ExceptionCheck()) {
135 // exception thrown: OutOfMemoryError
136 env->ExceptionDescribe(); // print out exception to stderr
137 env->DeleteLocalRef(jsStart);
138 releaseJniEnv(attached_thread);
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.
145 mtx_findShortestSeparator.get()->Lock();
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 }
157 releaseJniEnv(attached_thread);
158 return;
159 }
160
161 jstring jsResultStart =
162 (jstring)env->CallObjectMethod(m_jcallback_obj,
163 m_jFindShortestSeparatorMethodId, jsStart, m_jSliceLimit);
164
165 mtx_findShortestSeparator.get()->Unlock();
166
167 if(env->ExceptionCheck()) {
168 // exception thrown from CallObjectMethod
169 env->ExceptionDescribe(); // print out exception to stderr
170 env->DeleteLocalRef(jsStart);
171 releaseJniEnv(attached_thread);
172 return;
173 }
174
175 env->DeleteLocalRef(jsStart);
176
177 if (jsResultStart != nullptr) {
178 // update start with result
179 jboolean has_exception = JNI_FALSE;
180 std::unique_ptr<const char[]> result_start = JniUtil::copyString(env, jsResultStart,
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 }
186 releaseJniEnv(attached_thread);
187 return;
188 }
189
190 start->assign(result_start.get());
191 }
192 releaseJniEnv(attached_thread);
193 }
194
195 void BaseComparatorJniCallback::FindShortSuccessor(
196 std::string* key) const {
197 if (key == nullptr) {
198 return;
199 }
200
201 jboolean attached_thread = JNI_FALSE;
202 JNIEnv* env = getJniEnv(&attached_thread);
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 }
212 releaseJniEnv(attached_thread);
213 return;
214 } else if(env->ExceptionCheck()) {
215 // exception thrown: OutOfMemoryError
216 env->ExceptionDescribe(); // print out exception to stderr
217 env->DeleteLocalRef(jsKey);
218 releaseJniEnv(attached_thread);
219 return;
220 }
221
222 jstring jsResultKey =
223 (jstring)env->CallObjectMethod(m_jcallback_obj,
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);
230 releaseJniEnv(attached_thread);
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;
239 std::unique_ptr<const char[]> result_key = JniUtil::copyString(env, jsResultKey,
240 &has_exception); // also releases jsResultKey
241 if (has_exception == JNI_TRUE) {
242 if (env->ExceptionCheck()) {
243 env->ExceptionDescribe(); // print out exception to stderr
244 }
245 releaseJniEnv(attached_thread);
246 return;
247 }
248
249 key->assign(result_key.get());
250 }
251
252 releaseJniEnv(attached_thread);
253 }
254
255 ComparatorJniCallback::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
278 ComparatorJniCallback::~ComparatorJniCallback() {
279 jboolean attached_thread = JNI_FALSE;
280 JNIEnv* env = getJniEnv(&attached_thread);
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
295 releaseJniEnv(attached_thread);
296 }
297
298 DirectComparatorJniCallback::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
321 DirectComparatorJniCallback::~DirectComparatorJniCallback() {
322 jboolean attached_thread = JNI_FALSE;
323 JNIEnv* env = getJniEnv(&attached_thread);
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
338 releaseJniEnv(attached_thread);
339 }
340 } // namespace rocksdb