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++ for
7 // ROCKSDB_NAMESPACE::Slice.
8 
9 #include <jni.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string>
13 
14 #include "include/org_rocksdb_AbstractSlice.h"
15 #include "include/org_rocksdb_DirectSlice.h"
16 #include "include/org_rocksdb_Slice.h"
17 #include "rocksdb/slice.h"
18 #include "rocksjni/portal.h"
19 
20 // <editor-fold desc="org.rocksdb.AbstractSlice>
21 
22 /*
23  * Class:     org_rocksdb_AbstractSlice
24  * Method:    createNewSliceFromString
25  * Signature: (Ljava/lang/String;)J
26  */
Java_org_rocksdb_AbstractSlice_createNewSliceFromString(JNIEnv * env,jclass,jstring jstr)27 jlong Java_org_rocksdb_AbstractSlice_createNewSliceFromString(JNIEnv* env,
28                                                               jclass /*jcls*/,
29                                                               jstring jstr) {
30   const auto* str = env->GetStringUTFChars(jstr, nullptr);
31   if (str == nullptr) {
32     // exception thrown: OutOfMemoryError
33     return 0;
34   }
35 
36   const size_t len = strlen(str);
37 
38   // NOTE: buf will be deleted in the
39   // Java_org_rocksdb_Slice_disposeInternalBuf or
40   // or Java_org_rocksdb_DirectSlice_disposeInternalBuf methods
41   char* buf = new char[len + 1];
42   memcpy(buf, str, len);
43   buf[len] = 0;
44   env->ReleaseStringUTFChars(jstr, str);
45 
46   const auto* slice = new ROCKSDB_NAMESPACE::Slice(buf);
47   return reinterpret_cast<jlong>(slice);
48 }
49 
50 /*
51  * Class:     org_rocksdb_AbstractSlice
52  * Method:    size0
53  * Signature: (J)I
54  */
Java_org_rocksdb_AbstractSlice_size0(JNIEnv *,jobject,jlong handle)55 jint Java_org_rocksdb_AbstractSlice_size0(JNIEnv* /*env*/, jobject /*jobj*/,
56                                           jlong handle) {
57   const auto* slice = reinterpret_cast<ROCKSDB_NAMESPACE::Slice*>(handle);
58   return static_cast<jint>(slice->size());
59 }
60 
61 /*
62  * Class:     org_rocksdb_AbstractSlice
63  * Method:    empty0
64  * Signature: (J)Z
65  */
Java_org_rocksdb_AbstractSlice_empty0(JNIEnv *,jobject,jlong handle)66 jboolean Java_org_rocksdb_AbstractSlice_empty0(JNIEnv* /*env*/,
67                                                jobject /*jobj*/, jlong handle) {
68   const auto* slice = reinterpret_cast<ROCKSDB_NAMESPACE::Slice*>(handle);
69   return slice->empty();
70 }
71 
72 /*
73  * Class:     org_rocksdb_AbstractSlice
74  * Method:    toString0
75  * Signature: (JZ)Ljava/lang/String;
76  */
Java_org_rocksdb_AbstractSlice_toString0(JNIEnv * env,jobject,jlong handle,jboolean hex)77 jstring Java_org_rocksdb_AbstractSlice_toString0(JNIEnv* env, jobject /*jobj*/,
78                                                  jlong handle, jboolean hex) {
79   const auto* slice = reinterpret_cast<ROCKSDB_NAMESPACE::Slice*>(handle);
80   const std::string s = slice->ToString(hex);
81   return env->NewStringUTF(s.c_str());
82 }
83 
84 /*
85  * Class:     org_rocksdb_AbstractSlice
86  * Method:    compare0
87  * Signature: (JJ)I;
88  */
Java_org_rocksdb_AbstractSlice_compare0(JNIEnv *,jobject,jlong handle,jlong otherHandle)89 jint Java_org_rocksdb_AbstractSlice_compare0(JNIEnv* /*env*/, jobject /*jobj*/,
90                                              jlong handle, jlong otherHandle) {
91   const auto* slice = reinterpret_cast<ROCKSDB_NAMESPACE::Slice*>(handle);
92   const auto* otherSlice =
93       reinterpret_cast<ROCKSDB_NAMESPACE::Slice*>(otherHandle);
94   return slice->compare(*otherSlice);
95 }
96 
97 /*
98  * Class:     org_rocksdb_AbstractSlice
99  * Method:    startsWith0
100  * Signature: (JJ)Z;
101  */
Java_org_rocksdb_AbstractSlice_startsWith0(JNIEnv *,jobject,jlong handle,jlong otherHandle)102 jboolean Java_org_rocksdb_AbstractSlice_startsWith0(JNIEnv* /*env*/,
103                                                     jobject /*jobj*/,
104                                                     jlong handle,
105                                                     jlong otherHandle) {
106   const auto* slice = reinterpret_cast<ROCKSDB_NAMESPACE::Slice*>(handle);
107   const auto* otherSlice =
108       reinterpret_cast<ROCKSDB_NAMESPACE::Slice*>(otherHandle);
109   return slice->starts_with(*otherSlice);
110 }
111 
112 /*
113  * Class:     org_rocksdb_AbstractSlice
114  * Method:    disposeInternal
115  * Signature: (J)V
116  */
Java_org_rocksdb_AbstractSlice_disposeInternal(JNIEnv *,jobject,jlong handle)117 void Java_org_rocksdb_AbstractSlice_disposeInternal(JNIEnv* /*env*/,
118                                                     jobject /*jobj*/,
119                                                     jlong handle) {
120   delete reinterpret_cast<ROCKSDB_NAMESPACE::Slice*>(handle);
121 }
122 
123 // </editor-fold>
124 
125 // <editor-fold desc="org.rocksdb.Slice>
126 
127 /*
128  * Class:     org_rocksdb_Slice
129  * Method:    createNewSlice0
130  * Signature: ([BI)J
131  */
Java_org_rocksdb_Slice_createNewSlice0(JNIEnv * env,jclass,jbyteArray data,jint offset)132 jlong Java_org_rocksdb_Slice_createNewSlice0(JNIEnv* env, jclass /*jcls*/,
133                                              jbyteArray data, jint offset) {
134   const jsize dataSize = env->GetArrayLength(data);
135   const int len = dataSize - offset;
136 
137   // NOTE: buf will be deleted in the Java_org_rocksdb_Slice_disposeInternalBuf
138   // method
139   jbyte* buf = new jbyte[len];
140   env->GetByteArrayRegion(data, offset, len, buf);
141   if (env->ExceptionCheck()) {
142     // exception thrown: ArrayIndexOutOfBoundsException
143     return 0;
144   }
145 
146   const auto* slice = new ROCKSDB_NAMESPACE::Slice((const char*)buf, len);
147   return reinterpret_cast<jlong>(slice);
148 }
149 
150 /*
151  * Class:     org_rocksdb_Slice
152  * Method:    createNewSlice1
153  * Signature: ([B)J
154  */
Java_org_rocksdb_Slice_createNewSlice1(JNIEnv * env,jclass,jbyteArray data)155 jlong Java_org_rocksdb_Slice_createNewSlice1(JNIEnv* env, jclass /*jcls*/,
156                                              jbyteArray data) {
157   jbyte* ptrData = env->GetByteArrayElements(data, nullptr);
158   if (ptrData == nullptr) {
159     // exception thrown: OutOfMemoryError
160     return 0;
161   }
162   const int len = env->GetArrayLength(data) + 1;
163 
164   // NOTE: buf will be deleted in the Java_org_rocksdb_Slice_disposeInternalBuf
165   // method
166   char* buf = new char[len];
167   memcpy(buf, ptrData, len - 1);
168   buf[len - 1] = '\0';
169 
170   const auto* slice = new ROCKSDB_NAMESPACE::Slice(buf, len - 1);
171 
172   env->ReleaseByteArrayElements(data, ptrData, JNI_ABORT);
173 
174   return reinterpret_cast<jlong>(slice);
175 }
176 
177 /*
178  * Class:     org_rocksdb_Slice
179  * Method:    data0
180  * Signature: (J)[B
181  */
Java_org_rocksdb_Slice_data0(JNIEnv * env,jobject,jlong handle)182 jbyteArray Java_org_rocksdb_Slice_data0(JNIEnv* env, jobject /*jobj*/,
183                                         jlong handle) {
184   const auto* slice = reinterpret_cast<ROCKSDB_NAMESPACE::Slice*>(handle);
185   const jsize len = static_cast<jsize>(slice->size());
186   const jbyteArray data = env->NewByteArray(len);
187   if (data == nullptr) {
188     // exception thrown: OutOfMemoryError
189     return nullptr;
190   }
191 
192   env->SetByteArrayRegion(
193       data, 0, len,
194       const_cast<jbyte*>(reinterpret_cast<const jbyte*>(slice->data())));
195   if (env->ExceptionCheck()) {
196     // exception thrown: ArrayIndexOutOfBoundsException
197     env->DeleteLocalRef(data);
198     return nullptr;
199   }
200 
201   return data;
202 }
203 
204 /*
205  * Class:     org_rocksdb_Slice
206  * Method:    clear0
207  * Signature: (JZJ)V
208  */
Java_org_rocksdb_Slice_clear0(JNIEnv *,jobject,jlong handle,jboolean shouldRelease,jlong internalBufferOffset)209 void Java_org_rocksdb_Slice_clear0(JNIEnv* /*env*/, jobject /*jobj*/,
210                                    jlong handle, jboolean shouldRelease,
211                                    jlong internalBufferOffset) {
212   auto* slice = reinterpret_cast<ROCKSDB_NAMESPACE::Slice*>(handle);
213   if (shouldRelease == JNI_TRUE) {
214     const char* buf = slice->data_ - internalBufferOffset;
215     delete[] buf;
216   }
217   slice->clear();
218 }
219 
220 /*
221  * Class:     org_rocksdb_Slice
222  * Method:    removePrefix0
223  * Signature: (JI)V
224  */
Java_org_rocksdb_Slice_removePrefix0(JNIEnv *,jobject,jlong handle,jint length)225 void Java_org_rocksdb_Slice_removePrefix0(JNIEnv* /*env*/, jobject /*jobj*/,
226                                           jlong handle, jint length) {
227   auto* slice = reinterpret_cast<ROCKSDB_NAMESPACE::Slice*>(handle);
228   slice->remove_prefix(length);
229 }
230 
231 /*
232  * Class:     org_rocksdb_DirectSlice
233  * Method:    setLength0
234  * Signature: (JI)V
235  */
Java_org_rocksdb_DirectSlice_setLength0(JNIEnv *,jobject,jlong handle,jint length)236 void Java_org_rocksdb_DirectSlice_setLength0(JNIEnv* /*env*/, jobject /*jobj*/,
237                                              jlong handle, jint length) {
238   auto* slice = reinterpret_cast<ROCKSDB_NAMESPACE::Slice*>(handle);
239   slice->size_ = length;
240 }
241 
242 /*
243  * Class:     org_rocksdb_Slice
244  * Method:    disposeInternalBuf
245  * Signature: (JJ)V
246  */
Java_org_rocksdb_Slice_disposeInternalBuf(JNIEnv *,jobject,jlong handle,jlong internalBufferOffset)247 void Java_org_rocksdb_Slice_disposeInternalBuf(JNIEnv* /*env*/,
248                                                jobject /*jobj*/, jlong handle,
249                                                jlong internalBufferOffset) {
250   const auto* slice = reinterpret_cast<ROCKSDB_NAMESPACE::Slice*>(handle);
251   const char* buf = slice->data_ - internalBufferOffset;
252   delete[] buf;
253 }
254 
255 // </editor-fold>
256 
257 // <editor-fold desc="org.rocksdb.DirectSlice>
258 
259 /*
260  * Class:     org_rocksdb_DirectSlice
261  * Method:    createNewDirectSlice0
262  * Signature: (Ljava/nio/ByteBuffer;I)J
263  */
Java_org_rocksdb_DirectSlice_createNewDirectSlice0(JNIEnv * env,jclass,jobject data,jint length)264 jlong Java_org_rocksdb_DirectSlice_createNewDirectSlice0(JNIEnv* env,
265                                                          jclass /*jcls*/,
266                                                          jobject data,
267                                                          jint length) {
268   assert(data != nullptr);
269   void* data_addr = env->GetDirectBufferAddress(data);
270   if (data_addr == nullptr) {
271     // error: memory region is undefined, given object is not a direct
272     // java.nio.Buffer, or JNI access to direct buffers is not supported by JVM
273     ROCKSDB_NAMESPACE::IllegalArgumentExceptionJni::ThrowNew(
274         env, ROCKSDB_NAMESPACE::Status::InvalidArgument(
275                  "Could not access DirectBuffer"));
276     return 0;
277   }
278 
279   const auto* ptrData = reinterpret_cast<char*>(data_addr);
280   const auto* slice = new ROCKSDB_NAMESPACE::Slice(ptrData, length);
281   return reinterpret_cast<jlong>(slice);
282 }
283 
284 /*
285  * Class:     org_rocksdb_DirectSlice
286  * Method:    createNewDirectSlice1
287  * Signature: (Ljava/nio/ByteBuffer;)J
288  */
Java_org_rocksdb_DirectSlice_createNewDirectSlice1(JNIEnv * env,jclass,jobject data)289 jlong Java_org_rocksdb_DirectSlice_createNewDirectSlice1(JNIEnv* env,
290                                                          jclass /*jcls*/,
291                                                          jobject data) {
292   void* data_addr = env->GetDirectBufferAddress(data);
293   if (data_addr == nullptr) {
294     // error: memory region is undefined, given object is not a direct
295     // java.nio.Buffer, or JNI access to direct buffers is not supported by JVM
296     ROCKSDB_NAMESPACE::IllegalArgumentExceptionJni::ThrowNew(
297         env, ROCKSDB_NAMESPACE::Status::InvalidArgument(
298                  "Could not access DirectBuffer"));
299     return 0;
300   }
301 
302   const auto* ptrData = reinterpret_cast<char*>(data_addr);
303   const auto* slice = new ROCKSDB_NAMESPACE::Slice(ptrData);
304   return reinterpret_cast<jlong>(slice);
305 }
306 
307 /*
308  * Class:     org_rocksdb_DirectSlice
309  * Method:    data0
310  * Signature: (J)Ljava/lang/Object;
311  */
Java_org_rocksdb_DirectSlice_data0(JNIEnv * env,jobject,jlong handle)312 jobject Java_org_rocksdb_DirectSlice_data0(JNIEnv* env, jobject /*jobj*/,
313                                            jlong handle) {
314   const auto* slice = reinterpret_cast<ROCKSDB_NAMESPACE::Slice*>(handle);
315   return env->NewDirectByteBuffer(const_cast<char*>(slice->data()),
316                                   slice->size());
317 }
318 
319 /*
320  * Class:     org_rocksdb_DirectSlice
321  * Method:    get0
322  * Signature: (JI)B
323  */
Java_org_rocksdb_DirectSlice_get0(JNIEnv *,jobject,jlong handle,jint offset)324 jbyte Java_org_rocksdb_DirectSlice_get0(JNIEnv* /*env*/, jobject /*jobj*/,
325                                         jlong handle, jint offset) {
326   const auto* slice = reinterpret_cast<ROCKSDB_NAMESPACE::Slice*>(handle);
327   return (*slice)[offset];
328 }
329 
330 /*
331  * Class:     org_rocksdb_DirectSlice
332  * Method:    clear0
333  * Signature: (JZJ)V
334  */
Java_org_rocksdb_DirectSlice_clear0(JNIEnv *,jobject,jlong handle,jboolean shouldRelease,jlong internalBufferOffset)335 void Java_org_rocksdb_DirectSlice_clear0(JNIEnv* /*env*/, jobject /*jobj*/,
336                                          jlong handle, jboolean shouldRelease,
337                                          jlong internalBufferOffset) {
338   auto* slice = reinterpret_cast<ROCKSDB_NAMESPACE::Slice*>(handle);
339   if (shouldRelease == JNI_TRUE) {
340     const char* buf = slice->data_ - internalBufferOffset;
341     delete[] buf;
342   }
343   slice->clear();
344 }
345 
346 /*
347  * Class:     org_rocksdb_DirectSlice
348  * Method:    removePrefix0
349  * Signature: (JI)V
350  */
Java_org_rocksdb_DirectSlice_removePrefix0(JNIEnv *,jobject,jlong handle,jint length)351 void Java_org_rocksdb_DirectSlice_removePrefix0(JNIEnv* /*env*/,
352                                                 jobject /*jobj*/, jlong handle,
353                                                 jint length) {
354   auto* slice = reinterpret_cast<ROCKSDB_NAMESPACE::Slice*>(handle);
355   slice->remove_prefix(length);
356 }
357 
358 /*
359  * Class:     org_rocksdb_DirectSlice
360  * Method:    disposeInternalBuf
361  * Signature: (JJ)V
362  */
Java_org_rocksdb_DirectSlice_disposeInternalBuf(JNIEnv *,jobject,jlong handle,jlong internalBufferOffset)363 void Java_org_rocksdb_DirectSlice_disposeInternalBuf(
364     JNIEnv* /*env*/, jobject /*jobj*/, jlong handle,
365     jlong internalBufferOffset) {
366   const auto* slice = reinterpret_cast<ROCKSDB_NAMESPACE::Slice*>(handle);
367   const char* buf = slice->data_ - internalBufferOffset;
368   delete[] buf;
369 }
370 
371 // </editor-fold>
372