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::Transaction.
8 
9 #include <jni.h>
10 #include <functional>
11 
12 #include "include/org_rocksdb_Transaction.h"
13 
14 #include "rocksdb/utilities/transaction.h"
15 #include "rocksjni/portal.h"
16 
17 using namespace std::placeholders;
18 
19 #if defined(_MSC_VER)
20 #pragma warning(push)
21 #pragma warning(disable : 4503)  // identifier' : decorated name length
22                                  // exceeded, name was truncated
23 #endif
24 
25 /*
26  * Class:     org_rocksdb_Transaction
27  * Method:    setSnapshot
28  * Signature: (J)V
29  */
Java_org_rocksdb_Transaction_setSnapshot(JNIEnv *,jobject,jlong jhandle)30 void Java_org_rocksdb_Transaction_setSnapshot(JNIEnv* /*env*/, jobject /*jobj*/,
31                                               jlong jhandle) {
32   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
33   txn->SetSnapshot();
34 }
35 
36 /*
37  * Class:     org_rocksdb_Transaction
38  * Method:    setSnapshotOnNextOperation
39  * Signature: (J)V
40  */
Java_org_rocksdb_Transaction_setSnapshotOnNextOperation__J(JNIEnv *,jobject,jlong jhandle)41 void Java_org_rocksdb_Transaction_setSnapshotOnNextOperation__J(
42     JNIEnv* /*env*/, jobject /*jobj*/, jlong jhandle) {
43   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
44   txn->SetSnapshotOnNextOperation(nullptr);
45 }
46 
47 /*
48  * Class:     org_rocksdb_Transaction
49  * Method:    setSnapshotOnNextOperation
50  * Signature: (JJ)V
51  */
Java_org_rocksdb_Transaction_setSnapshotOnNextOperation__JJ(JNIEnv *,jobject,jlong jhandle,jlong jtxn_notifier_handle)52 void Java_org_rocksdb_Transaction_setSnapshotOnNextOperation__JJ(
53     JNIEnv* /*env*/, jobject /*jobj*/, jlong jhandle,
54     jlong jtxn_notifier_handle) {
55   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
56   auto* txn_notifier = reinterpret_cast<
57       std::shared_ptr<ROCKSDB_NAMESPACE::TransactionNotifierJniCallback>*>(
58       jtxn_notifier_handle);
59   txn->SetSnapshotOnNextOperation(*txn_notifier);
60 }
61 
62 /*
63  * Class:     org_rocksdb_Transaction
64  * Method:    getSnapshot
65  * Signature: (J)J
66  */
Java_org_rocksdb_Transaction_getSnapshot(JNIEnv *,jobject,jlong jhandle)67 jlong Java_org_rocksdb_Transaction_getSnapshot(JNIEnv* /*env*/,
68                                                jobject /*jobj*/,
69                                                jlong jhandle) {
70   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
71   const ROCKSDB_NAMESPACE::Snapshot* snapshot = txn->GetSnapshot();
72   return reinterpret_cast<jlong>(snapshot);
73 }
74 
75 /*
76  * Class:     org_rocksdb_Transaction
77  * Method:    clearSnapshot
78  * Signature: (J)V
79  */
Java_org_rocksdb_Transaction_clearSnapshot(JNIEnv *,jobject,jlong jhandle)80 void Java_org_rocksdb_Transaction_clearSnapshot(JNIEnv* /*env*/,
81                                                 jobject /*jobj*/,
82                                                 jlong jhandle) {
83   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
84   txn->ClearSnapshot();
85 }
86 
87 /*
88  * Class:     org_rocksdb_Transaction
89  * Method:    prepare
90  * Signature: (J)V
91  */
Java_org_rocksdb_Transaction_prepare(JNIEnv * env,jobject,jlong jhandle)92 void Java_org_rocksdb_Transaction_prepare(JNIEnv* env, jobject /*jobj*/,
93                                           jlong jhandle) {
94   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
95   ROCKSDB_NAMESPACE::Status s = txn->Prepare();
96   if (!s.ok()) {
97     ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
98   }
99 }
100 
101 /*
102  * Class:     org_rocksdb_Transaction
103  * Method:    commit
104  * Signature: (J)V
105  */
Java_org_rocksdb_Transaction_commit(JNIEnv * env,jobject,jlong jhandle)106 void Java_org_rocksdb_Transaction_commit(JNIEnv* env, jobject /*jobj*/,
107                                          jlong jhandle) {
108   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
109   ROCKSDB_NAMESPACE::Status s = txn->Commit();
110   if (!s.ok()) {
111     ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
112   }
113 }
114 
115 /*
116  * Class:     org_rocksdb_Transaction
117  * Method:    rollback
118  * Signature: (J)V
119  */
Java_org_rocksdb_Transaction_rollback(JNIEnv * env,jobject,jlong jhandle)120 void Java_org_rocksdb_Transaction_rollback(JNIEnv* env, jobject /*jobj*/,
121                                            jlong jhandle) {
122   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
123   ROCKSDB_NAMESPACE::Status s = txn->Rollback();
124   if (!s.ok()) {
125     ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
126   }
127 }
128 
129 /*
130  * Class:     org_rocksdb_Transaction
131  * Method:    setSavePoint
132  * Signature: (J)V
133  */
Java_org_rocksdb_Transaction_setSavePoint(JNIEnv *,jobject,jlong jhandle)134 void Java_org_rocksdb_Transaction_setSavePoint(JNIEnv* /*env*/,
135                                                jobject /*jobj*/,
136                                                jlong jhandle) {
137   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
138   txn->SetSavePoint();
139 }
140 
141 /*
142  * Class:     org_rocksdb_Transaction
143  * Method:    rollbackToSavePoint
144  * Signature: (J)V
145  */
Java_org_rocksdb_Transaction_rollbackToSavePoint(JNIEnv * env,jobject,jlong jhandle)146 void Java_org_rocksdb_Transaction_rollbackToSavePoint(JNIEnv* env,
147                                                       jobject /*jobj*/,
148                                                       jlong jhandle) {
149   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
150   ROCKSDB_NAMESPACE::Status s = txn->RollbackToSavePoint();
151   if (!s.ok()) {
152     ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
153   }
154 }
155 
156 typedef std::function<ROCKSDB_NAMESPACE::Status(
157     const ROCKSDB_NAMESPACE::ReadOptions&, const ROCKSDB_NAMESPACE::Slice&,
158     std::string*)>
159     FnGet;
160 
161 // TODO(AR) consider refactoring to share this between here and rocksjni.cc
txn_get_helper(JNIEnv * env,const FnGet & fn_get,const jlong & jread_options_handle,const jbyteArray & jkey,const jint & jkey_part_len)162 jbyteArray txn_get_helper(JNIEnv* env, const FnGet& fn_get,
163                           const jlong& jread_options_handle,
164                           const jbyteArray& jkey, const jint& jkey_part_len) {
165   jbyte* key = env->GetByteArrayElements(jkey, nullptr);
166   if (key == nullptr) {
167     // exception thrown: OutOfMemoryError
168     return nullptr;
169   }
170   ROCKSDB_NAMESPACE::Slice key_slice(reinterpret_cast<char*>(key),
171                                      jkey_part_len);
172 
173   auto* read_options =
174       reinterpret_cast<ROCKSDB_NAMESPACE::ReadOptions*>(jread_options_handle);
175   std::string value;
176   ROCKSDB_NAMESPACE::Status s = fn_get(*read_options, key_slice, &value);
177 
178   // trigger java unref on key.
179   // by passing JNI_ABORT, it will simply release the reference without
180   // copying the result back to the java byte array.
181   env->ReleaseByteArrayElements(jkey, key, JNI_ABORT);
182 
183   if (s.IsNotFound()) {
184     return nullptr;
185   }
186 
187   if (s.ok()) {
188     jbyteArray jret_value = env->NewByteArray(static_cast<jsize>(value.size()));
189     if (jret_value == nullptr) {
190       // exception thrown: OutOfMemoryError
191       return nullptr;
192     }
193     env->SetByteArrayRegion(jret_value, 0, static_cast<jsize>(value.size()),
194                             const_cast<jbyte*>(reinterpret_cast<const jbyte*>(value.c_str())));
195     if (env->ExceptionCheck()) {
196       // exception thrown: ArrayIndexOutOfBoundsException
197       return nullptr;
198     }
199     return jret_value;
200   }
201 
202   ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
203   return nullptr;
204 }
205 
206 /*
207  * Class:     org_rocksdb_Transaction
208  * Method:    get
209  * Signature: (JJ[BIJ)[B
210  */
Java_org_rocksdb_Transaction_get__JJ_3BIJ(JNIEnv * env,jobject,jlong jhandle,jlong jread_options_handle,jbyteArray jkey,jint jkey_part_len,jlong jcolumn_family_handle)211 jbyteArray Java_org_rocksdb_Transaction_get__JJ_3BIJ(
212     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jlong jread_options_handle,
213     jbyteArray jkey, jint jkey_part_len, jlong jcolumn_family_handle) {
214   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
215   auto* column_family_handle =
216       reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>(
217           jcolumn_family_handle);
218   FnGet fn_get =
219       std::bind<ROCKSDB_NAMESPACE::Status (ROCKSDB_NAMESPACE::Transaction::*)(
220           const ROCKSDB_NAMESPACE::ReadOptions&,
221           ROCKSDB_NAMESPACE::ColumnFamilyHandle*,
222           const ROCKSDB_NAMESPACE::Slice&, std::string*)>(
223           &ROCKSDB_NAMESPACE::Transaction::Get, txn, _1, column_family_handle,
224           _2, _3);
225   return txn_get_helper(env, fn_get, jread_options_handle, jkey, jkey_part_len);
226 }
227 
228 /*
229  * Class:     org_rocksdb_Transaction
230  * Method:    get
231  * Signature: (JJ[BI)[B
232  */
Java_org_rocksdb_Transaction_get__JJ_3BI(JNIEnv * env,jobject,jlong jhandle,jlong jread_options_handle,jbyteArray jkey,jint jkey_part_len)233 jbyteArray Java_org_rocksdb_Transaction_get__JJ_3BI(
234     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jlong jread_options_handle,
235     jbyteArray jkey, jint jkey_part_len) {
236   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
237   FnGet fn_get =
238       std::bind<ROCKSDB_NAMESPACE::Status (ROCKSDB_NAMESPACE::Transaction::*)(
239           const ROCKSDB_NAMESPACE::ReadOptions&,
240           const ROCKSDB_NAMESPACE::Slice&, std::string*)>(
241           &ROCKSDB_NAMESPACE::Transaction::Get, txn, _1, _2, _3);
242   return txn_get_helper(env, fn_get, jread_options_handle, jkey, jkey_part_len);
243 }
244 
245 // TODO(AR) consider refactoring to share this between here and rocksjni.cc
246 // used by txn_multi_get_helper below
txn_column_families_helper(JNIEnv * env,jlongArray jcolumn_family_handles,bool * has_exception)247 std::vector<ROCKSDB_NAMESPACE::ColumnFamilyHandle*> txn_column_families_helper(
248     JNIEnv* env, jlongArray jcolumn_family_handles, bool* has_exception) {
249   std::vector<ROCKSDB_NAMESPACE::ColumnFamilyHandle*> cf_handles;
250   if (jcolumn_family_handles != nullptr) {
251     const jsize len_cols = env->GetArrayLength(jcolumn_family_handles);
252     if (len_cols > 0) {
253       if (env->EnsureLocalCapacity(len_cols) != 0) {
254         // out of memory
255         *has_exception = JNI_TRUE;
256         return std::vector<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>();
257       }
258 
259       jlong* jcfh = env->GetLongArrayElements(jcolumn_family_handles, nullptr);
260       if (jcfh == nullptr) {
261         // exception thrown: OutOfMemoryError
262         *has_exception = JNI_TRUE;
263         return std::vector<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>();
264       }
265       for (int i = 0; i < len_cols; i++) {
266         auto* cf_handle =
267             reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>(jcfh[i]);
268         cf_handles.push_back(cf_handle);
269       }
270       env->ReleaseLongArrayElements(jcolumn_family_handles, jcfh, JNI_ABORT);
271     }
272   }
273   return cf_handles;
274 }
275 
276 typedef std::function<std::vector<ROCKSDB_NAMESPACE::Status>(
277     const ROCKSDB_NAMESPACE::ReadOptions&,
278     const std::vector<ROCKSDB_NAMESPACE::Slice>&, std::vector<std::string>*)>
279     FnMultiGet;
280 
free_parts(JNIEnv * env,std::vector<std::tuple<jbyteArray,jbyte *,jobject>> & parts_to_free)281 void free_parts(
282     JNIEnv* env,
283     std::vector<std::tuple<jbyteArray, jbyte*, jobject>>& parts_to_free) {
284   for (auto& value : parts_to_free) {
285     jobject jk;
286     jbyteArray jk_ba;
287     jbyte* jk_val;
288     std::tie(jk_ba, jk_val, jk) = value;
289     env->ReleaseByteArrayElements(jk_ba, jk_val, JNI_ABORT);
290     env->DeleteLocalRef(jk);
291   }
292 }
293 
294 // TODO(AR) consider refactoring to share this between here and rocksjni.cc
295 // cf multi get
txn_multi_get_helper(JNIEnv * env,const FnMultiGet & fn_multi_get,const jlong & jread_options_handle,const jobjectArray & jkey_parts)296 jobjectArray txn_multi_get_helper(JNIEnv* env, const FnMultiGet& fn_multi_get,
297                                   const jlong& jread_options_handle,
298                                   const jobjectArray& jkey_parts) {
299   const jsize len_key_parts = env->GetArrayLength(jkey_parts);
300   if (env->EnsureLocalCapacity(len_key_parts) != 0) {
301     // out of memory
302     return nullptr;
303   }
304 
305   std::vector<ROCKSDB_NAMESPACE::Slice> key_parts;
306   std::vector<std::tuple<jbyteArray, jbyte*, jobject>> key_parts_to_free;
307   for (int i = 0; i < len_key_parts; i++) {
308     const jobject jk = env->GetObjectArrayElement(jkey_parts, i);
309     if (env->ExceptionCheck()) {
310       // exception thrown: ArrayIndexOutOfBoundsException
311       free_parts(env, key_parts_to_free);
312       return nullptr;
313     }
314     jbyteArray jk_ba = reinterpret_cast<jbyteArray>(jk);
315     const jsize len_key = env->GetArrayLength(jk_ba);
316     if (env->EnsureLocalCapacity(len_key) != 0) {
317       // out of memory
318       env->DeleteLocalRef(jk);
319       free_parts(env, key_parts_to_free);
320       return nullptr;
321     }
322     jbyte* jk_val = env->GetByteArrayElements(jk_ba, nullptr);
323     if (jk_val == nullptr) {
324       // exception thrown: OutOfMemoryError
325       env->DeleteLocalRef(jk);
326       free_parts(env, key_parts_to_free);
327       return nullptr;
328     }
329 
330     ROCKSDB_NAMESPACE::Slice key_slice(reinterpret_cast<char*>(jk_val),
331                                        len_key);
332     key_parts.push_back(key_slice);
333 
334     key_parts_to_free.push_back(std::make_tuple(jk_ba, jk_val, jk));
335   }
336 
337   auto* read_options =
338       reinterpret_cast<ROCKSDB_NAMESPACE::ReadOptions*>(jread_options_handle);
339   std::vector<std::string> value_parts;
340   std::vector<ROCKSDB_NAMESPACE::Status> s =
341       fn_multi_get(*read_options, key_parts, &value_parts);
342 
343   // free up allocated byte arrays
344   free_parts(env, key_parts_to_free);
345 
346   // prepare the results
347   const jclass jcls_ba = env->FindClass("[B");
348   jobjectArray jresults =
349       env->NewObjectArray(static_cast<jsize>(s.size()), jcls_ba, nullptr);
350   if (jresults == nullptr) {
351     // exception thrown: OutOfMemoryError
352     return nullptr;
353   }
354 
355   // add to the jresults
356   for (std::vector<ROCKSDB_NAMESPACE::Status>::size_type i = 0; i != s.size();
357        i++) {
358     if (s[i].ok()) {
359       jbyteArray jentry_value =
360           env->NewByteArray(static_cast<jsize>(value_parts[i].size()));
361       if (jentry_value == nullptr) {
362         // exception thrown: OutOfMemoryError
363         return nullptr;
364       }
365 
366       env->SetByteArrayRegion(
367           jentry_value, 0, static_cast<jsize>(value_parts[i].size()),
368           const_cast<jbyte*>(reinterpret_cast<const jbyte*>(value_parts[i].c_str())));
369       if (env->ExceptionCheck()) {
370         // exception thrown: ArrayIndexOutOfBoundsException
371         env->DeleteLocalRef(jentry_value);
372         return nullptr;
373       }
374 
375       env->SetObjectArrayElement(jresults, static_cast<jsize>(i), jentry_value);
376       env->DeleteLocalRef(jentry_value);
377     }
378   }
379 
380   return jresults;
381 }
382 
383 /*
384  * Class:     org_rocksdb_Transaction
385  * Method:    multiGet
386  * Signature: (JJ[[B[J)[[B
387  */
Java_org_rocksdb_Transaction_multiGet__JJ_3_3B_3J(JNIEnv * env,jobject,jlong jhandle,jlong jread_options_handle,jobjectArray jkey_parts,jlongArray jcolumn_family_handles)388 jobjectArray Java_org_rocksdb_Transaction_multiGet__JJ_3_3B_3J(
389     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jlong jread_options_handle,
390     jobjectArray jkey_parts, jlongArray jcolumn_family_handles) {
391   bool has_exception = false;
392   const std::vector<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>
393       column_family_handles = txn_column_families_helper(
394           env, jcolumn_family_handles, &has_exception);
395   if (has_exception) {
396     // exception thrown: OutOfMemoryError
397     return nullptr;
398   }
399   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
400   FnMultiGet fn_multi_get = std::bind<std::vector<ROCKSDB_NAMESPACE::Status> (
401       ROCKSDB_NAMESPACE::Transaction::*)(
402       const ROCKSDB_NAMESPACE::ReadOptions&,
403       const std::vector<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>&,
404       const std::vector<ROCKSDB_NAMESPACE::Slice>&, std::vector<std::string>*)>(
405       &ROCKSDB_NAMESPACE::Transaction::MultiGet, txn, _1, column_family_handles,
406       _2, _3);
407   return txn_multi_get_helper(env, fn_multi_get, jread_options_handle,
408                               jkey_parts);
409 }
410 
411 /*
412  * Class:     org_rocksdb_Transaction
413  * Method:    multiGet
414  * Signature: (JJ[[B)[[B
415  */
Java_org_rocksdb_Transaction_multiGet__JJ_3_3B(JNIEnv * env,jobject,jlong jhandle,jlong jread_options_handle,jobjectArray jkey_parts)416 jobjectArray Java_org_rocksdb_Transaction_multiGet__JJ_3_3B(
417     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jlong jread_options_handle,
418     jobjectArray jkey_parts) {
419   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
420   FnMultiGet fn_multi_get = std::bind<std::vector<ROCKSDB_NAMESPACE::Status> (
421       ROCKSDB_NAMESPACE::Transaction::*)(
422       const ROCKSDB_NAMESPACE::ReadOptions&,
423       const std::vector<ROCKSDB_NAMESPACE::Slice>&, std::vector<std::string>*)>(
424       &ROCKSDB_NAMESPACE::Transaction::MultiGet, txn, _1, _2, _3);
425   return txn_multi_get_helper(env, fn_multi_get, jread_options_handle,
426                               jkey_parts);
427 }
428 
429 /*
430  * Class:     org_rocksdb_Transaction
431  * Method:    getForUpdate
432  * Signature: (JJ[BIJZZ)[B
433  */
Java_org_rocksdb_Transaction_getForUpdate__JJ_3BIJZZ(JNIEnv * env,jobject,jlong jhandle,jlong jread_options_handle,jbyteArray jkey,jint jkey_part_len,jlong jcolumn_family_handle,jboolean jexclusive,jboolean jdo_validate)434 jbyteArray Java_org_rocksdb_Transaction_getForUpdate__JJ_3BIJZZ(
435     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jlong jread_options_handle,
436     jbyteArray jkey, jint jkey_part_len, jlong jcolumn_family_handle,
437     jboolean jexclusive, jboolean jdo_validate) {
438   auto* column_family_handle =
439       reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>(
440           jcolumn_family_handle);
441   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
442   FnGet fn_get_for_update =
443       std::bind<ROCKSDB_NAMESPACE::Status (ROCKSDB_NAMESPACE::Transaction::*)(
444           const ROCKSDB_NAMESPACE::ReadOptions&,
445           ROCKSDB_NAMESPACE::ColumnFamilyHandle*,
446           const ROCKSDB_NAMESPACE::Slice&, std::string*, bool, bool)>(
447           &ROCKSDB_NAMESPACE::Transaction::GetForUpdate, txn, _1,
448           column_family_handle, _2, _3, jexclusive, jdo_validate);
449   return txn_get_helper(env, fn_get_for_update, jread_options_handle, jkey,
450                         jkey_part_len);
451 }
452 
453 /*
454  * Class:     org_rocksdb_Transaction
455  * Method:    getForUpdate
456  * Signature: (JJ[BIZZ)[B
457  */
Java_org_rocksdb_Transaction_getForUpdate__JJ_3BIZZ(JNIEnv * env,jobject,jlong jhandle,jlong jread_options_handle,jbyteArray jkey,jint jkey_part_len,jboolean jexclusive,jboolean jdo_validate)458 jbyteArray Java_org_rocksdb_Transaction_getForUpdate__JJ_3BIZZ(
459     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jlong jread_options_handle,
460     jbyteArray jkey, jint jkey_part_len, jboolean jexclusive,
461     jboolean jdo_validate) {
462   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
463   FnGet fn_get_for_update =
464       std::bind<ROCKSDB_NAMESPACE::Status (ROCKSDB_NAMESPACE::Transaction::*)(
465           const ROCKSDB_NAMESPACE::ReadOptions&,
466           const ROCKSDB_NAMESPACE::Slice&, std::string*, bool, bool)>(
467           &ROCKSDB_NAMESPACE::Transaction::GetForUpdate, txn, _1, _2, _3,
468           jexclusive, jdo_validate);
469   return txn_get_helper(env, fn_get_for_update, jread_options_handle, jkey,
470                         jkey_part_len);
471 }
472 
473 /*
474  * Class:     org_rocksdb_Transaction
475  * Method:    multiGetForUpdate
476  * Signature: (JJ[[B[J)[[B
477  */
Java_org_rocksdb_Transaction_multiGetForUpdate__JJ_3_3B_3J(JNIEnv * env,jobject,jlong jhandle,jlong jread_options_handle,jobjectArray jkey_parts,jlongArray jcolumn_family_handles)478 jobjectArray Java_org_rocksdb_Transaction_multiGetForUpdate__JJ_3_3B_3J(
479     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jlong jread_options_handle,
480     jobjectArray jkey_parts, jlongArray jcolumn_family_handles) {
481   bool has_exception = false;
482   const std::vector<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>
483       column_family_handles = txn_column_families_helper(
484           env, jcolumn_family_handles, &has_exception);
485   if (has_exception) {
486     // exception thrown: OutOfMemoryError
487     return nullptr;
488   }
489   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
490   FnMultiGet fn_multi_get_for_update = std::bind<std::vector<
491       ROCKSDB_NAMESPACE::Status> (ROCKSDB_NAMESPACE::Transaction::*)(
492       const ROCKSDB_NAMESPACE::ReadOptions&,
493       const std::vector<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>&,
494       const std::vector<ROCKSDB_NAMESPACE::Slice>&, std::vector<std::string>*)>(
495       &ROCKSDB_NAMESPACE::Transaction::MultiGetForUpdate, txn, _1,
496       column_family_handles, _2, _3);
497   return txn_multi_get_helper(env, fn_multi_get_for_update,
498                               jread_options_handle, jkey_parts);
499 }
500 
501 /*
502  * Class:     org_rocksdb_Transaction
503  * Method:    multiGetForUpdate
504  * Signature: (JJ[[B)[[B
505  */
Java_org_rocksdb_Transaction_multiGetForUpdate__JJ_3_3B(JNIEnv * env,jobject,jlong jhandle,jlong jread_options_handle,jobjectArray jkey_parts)506 jobjectArray Java_org_rocksdb_Transaction_multiGetForUpdate__JJ_3_3B(
507     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jlong jread_options_handle,
508     jobjectArray jkey_parts) {
509   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
510   FnMultiGet fn_multi_get_for_update = std::bind<std::vector<
511       ROCKSDB_NAMESPACE::Status> (ROCKSDB_NAMESPACE::Transaction::*)(
512       const ROCKSDB_NAMESPACE::ReadOptions&,
513       const std::vector<ROCKSDB_NAMESPACE::Slice>&, std::vector<std::string>*)>(
514       &ROCKSDB_NAMESPACE::Transaction::MultiGetForUpdate, txn, _1, _2, _3);
515   return txn_multi_get_helper(env, fn_multi_get_for_update,
516                               jread_options_handle, jkey_parts);
517 }
518 
519 /*
520  * Class:     org_rocksdb_Transaction
521  * Method:    getIterator
522  * Signature: (JJ)J
523  */
Java_org_rocksdb_Transaction_getIterator__JJ(JNIEnv *,jobject,jlong jhandle,jlong jread_options_handle)524 jlong Java_org_rocksdb_Transaction_getIterator__JJ(JNIEnv* /*env*/,
525                                                    jobject /*jobj*/,
526                                                    jlong jhandle,
527                                                    jlong jread_options_handle) {
528   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
529   auto* read_options =
530       reinterpret_cast<ROCKSDB_NAMESPACE::ReadOptions*>(jread_options_handle);
531   return reinterpret_cast<jlong>(txn->GetIterator(*read_options));
532 }
533 
534 /*
535  * Class:     org_rocksdb_Transaction
536  * Method:    getIterator
537  * Signature: (JJJ)J
538  */
Java_org_rocksdb_Transaction_getIterator__JJJ(JNIEnv *,jobject,jlong jhandle,jlong jread_options_handle,jlong jcolumn_family_handle)539 jlong Java_org_rocksdb_Transaction_getIterator__JJJ(
540     JNIEnv* /*env*/, jobject /*jobj*/, jlong jhandle,
541     jlong jread_options_handle, jlong jcolumn_family_handle) {
542   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
543   auto* read_options =
544       reinterpret_cast<ROCKSDB_NAMESPACE::ReadOptions*>(jread_options_handle);
545   auto* column_family_handle =
546       reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>(
547           jcolumn_family_handle);
548   return reinterpret_cast<jlong>(
549       txn->GetIterator(*read_options, column_family_handle));
550 }
551 
552 typedef std::function<ROCKSDB_NAMESPACE::Status(
553     const ROCKSDB_NAMESPACE::Slice&, const ROCKSDB_NAMESPACE::Slice&)>
554     FnWriteKV;
555 
556 // TODO(AR) consider refactoring to share this between here and rocksjni.cc
txn_write_kv_helper(JNIEnv * env,const FnWriteKV & fn_write_kv,const jbyteArray & jkey,const jint & jkey_part_len,const jbyteArray & jval,const jint & jval_len)557 void txn_write_kv_helper(JNIEnv* env, const FnWriteKV& fn_write_kv,
558                          const jbyteArray& jkey, const jint& jkey_part_len,
559                          const jbyteArray& jval, const jint& jval_len) {
560   jbyte* key = env->GetByteArrayElements(jkey, nullptr);
561   if (key == nullptr) {
562     // exception thrown: OutOfMemoryError
563     return;
564   }
565   jbyte* value = env->GetByteArrayElements(jval, nullptr);
566   if (value == nullptr) {
567     // exception thrown: OutOfMemoryError
568     env->ReleaseByteArrayElements(jkey, key, JNI_ABORT);
569     return;
570   }
571   ROCKSDB_NAMESPACE::Slice key_slice(reinterpret_cast<char*>(key),
572                                      jkey_part_len);
573   ROCKSDB_NAMESPACE::Slice value_slice(reinterpret_cast<char*>(value),
574                                        jval_len);
575 
576   ROCKSDB_NAMESPACE::Status s = fn_write_kv(key_slice, value_slice);
577 
578   // trigger java unref on key.
579   // by passing JNI_ABORT, it will simply release the reference without
580   // copying the result back to the java byte array.
581   env->ReleaseByteArrayElements(jval, value, JNI_ABORT);
582   env->ReleaseByteArrayElements(jkey, key, JNI_ABORT);
583 
584   if (s.ok()) {
585     return;
586   }
587   ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
588 }
589 
590 /*
591  * Class:     org_rocksdb_Transaction
592  * Method:    put
593  * Signature: (J[BI[BIJZ)V
594  */
Java_org_rocksdb_Transaction_put__J_3BI_3BIJZ(JNIEnv * env,jobject,jlong jhandle,jbyteArray jkey,jint jkey_part_len,jbyteArray jval,jint jval_len,jlong jcolumn_family_handle,jboolean jassume_tracked)595 void Java_org_rocksdb_Transaction_put__J_3BI_3BIJZ(
596     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jbyteArray jkey,
597     jint jkey_part_len, jbyteArray jval, jint jval_len,
598     jlong jcolumn_family_handle, jboolean jassume_tracked) {
599   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
600   auto* column_family_handle =
601       reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>(
602           jcolumn_family_handle);
603   FnWriteKV fn_put =
604       std::bind<ROCKSDB_NAMESPACE::Status (ROCKSDB_NAMESPACE::Transaction::*)(
605           ROCKSDB_NAMESPACE::ColumnFamilyHandle*,
606           const ROCKSDB_NAMESPACE::Slice&, const ROCKSDB_NAMESPACE::Slice&,
607           bool)>(&ROCKSDB_NAMESPACE::Transaction::Put, txn,
608                  column_family_handle, _1, _2, jassume_tracked);
609   txn_write_kv_helper(env, fn_put, jkey, jkey_part_len, jval, jval_len);
610 }
611 
612 /*
613  * Class:     org_rocksdb_Transaction
614  * Method:    put
615  * Signature: (J[BI[BI)V
616  */
Java_org_rocksdb_Transaction_put__J_3BI_3BI(JNIEnv * env,jobject,jlong jhandle,jbyteArray jkey,jint jkey_part_len,jbyteArray jval,jint jval_len)617 void Java_org_rocksdb_Transaction_put__J_3BI_3BI(JNIEnv* env, jobject /*jobj*/,
618                                                  jlong jhandle, jbyteArray jkey,
619                                                  jint jkey_part_len,
620                                                  jbyteArray jval,
621                                                  jint jval_len) {
622   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
623   FnWriteKV fn_put =
624       std::bind<ROCKSDB_NAMESPACE::Status (ROCKSDB_NAMESPACE::Transaction::*)(
625           const ROCKSDB_NAMESPACE::Slice&, const ROCKSDB_NAMESPACE::Slice&)>(
626           &ROCKSDB_NAMESPACE::Transaction::Put, txn, _1, _2);
627   txn_write_kv_helper(env, fn_put, jkey, jkey_part_len, jval, jval_len);
628 }
629 
630 typedef std::function<ROCKSDB_NAMESPACE::Status(
631     const ROCKSDB_NAMESPACE::SliceParts&, const ROCKSDB_NAMESPACE::SliceParts&)>
632     FnWriteKVParts;
633 
634 // TODO(AR) consider refactoring to share this between here and rocksjni.cc
txn_write_kv_parts_helper(JNIEnv * env,const FnWriteKVParts & fn_write_kv_parts,const jobjectArray & jkey_parts,const jint & jkey_parts_len,const jobjectArray & jvalue_parts,const jint & jvalue_parts_len)635 void txn_write_kv_parts_helper(JNIEnv* env,
636                                const FnWriteKVParts& fn_write_kv_parts,
637                                const jobjectArray& jkey_parts,
638                                const jint& jkey_parts_len,
639                                const jobjectArray& jvalue_parts,
640                                const jint& jvalue_parts_len) {
641 #ifndef DEBUG
642   (void) jvalue_parts_len;
643 #else
644   assert(jkey_parts_len == jvalue_parts_len);
645 #endif
646 
647   auto key_parts = std::vector<ROCKSDB_NAMESPACE::Slice>();
648   auto value_parts = std::vector<ROCKSDB_NAMESPACE::Slice>();
649   auto jparts_to_free = std::vector<std::tuple<jbyteArray, jbyte*, jobject>>();
650 
651   // convert java key_parts/value_parts byte[][] to Slice(s)
652   for (jsize i = 0; i < jkey_parts_len; ++i) {
653     const jobject jobj_key_part = env->GetObjectArrayElement(jkey_parts, i);
654     if (env->ExceptionCheck()) {
655       // exception thrown: ArrayIndexOutOfBoundsException
656       free_parts(env, jparts_to_free);
657       return;
658     }
659     const jobject jobj_value_part = env->GetObjectArrayElement(jvalue_parts, i);
660     if (env->ExceptionCheck()) {
661       // exception thrown: ArrayIndexOutOfBoundsException
662       env->DeleteLocalRef(jobj_key_part);
663       free_parts(env, jparts_to_free);
664       return;
665     }
666 
667     const jbyteArray jba_key_part = reinterpret_cast<jbyteArray>(jobj_key_part);
668     const jsize jkey_part_len = env->GetArrayLength(jba_key_part);
669     if (env->EnsureLocalCapacity(jkey_part_len) != 0) {
670       // out of memory
671       env->DeleteLocalRef(jobj_value_part);
672       env->DeleteLocalRef(jobj_key_part);
673       free_parts(env, jparts_to_free);
674       return;
675     }
676     jbyte* jkey_part = env->GetByteArrayElements(jba_key_part, nullptr);
677     if (jkey_part == nullptr) {
678       // exception thrown: OutOfMemoryError
679       env->DeleteLocalRef(jobj_value_part);
680       env->DeleteLocalRef(jobj_key_part);
681       free_parts(env, jparts_to_free);
682       return;
683     }
684 
685     const jbyteArray jba_value_part =
686         reinterpret_cast<jbyteArray>(jobj_value_part);
687     const jsize jvalue_part_len = env->GetArrayLength(jba_value_part);
688     if (env->EnsureLocalCapacity(jvalue_part_len) != 0) {
689       // out of memory
690       env->DeleteLocalRef(jobj_value_part);
691       env->DeleteLocalRef(jobj_key_part);
692       free_parts(env, jparts_to_free);
693       return;
694     }
695     jbyte* jvalue_part = env->GetByteArrayElements(jba_value_part, nullptr);
696     if (jvalue_part == nullptr) {
697       // exception thrown: OutOfMemoryError
698       env->ReleaseByteArrayElements(jba_value_part, jvalue_part, JNI_ABORT);
699       env->DeleteLocalRef(jobj_value_part);
700       env->DeleteLocalRef(jobj_key_part);
701       free_parts(env, jparts_to_free);
702       return;
703     }
704 
705     jparts_to_free.push_back(
706         std::make_tuple(jba_key_part, jkey_part, jobj_key_part));
707     jparts_to_free.push_back(
708         std::make_tuple(jba_value_part, jvalue_part, jobj_value_part));
709 
710     key_parts.push_back(ROCKSDB_NAMESPACE::Slice(
711         reinterpret_cast<char*>(jkey_part), jkey_part_len));
712     value_parts.push_back(ROCKSDB_NAMESPACE::Slice(
713         reinterpret_cast<char*>(jvalue_part), jvalue_part_len));
714   }
715 
716   // call the write_multi function
717   ROCKSDB_NAMESPACE::Status s = fn_write_kv_parts(
718       ROCKSDB_NAMESPACE::SliceParts(key_parts.data(), (int)key_parts.size()),
719       ROCKSDB_NAMESPACE::SliceParts(value_parts.data(),
720                                     (int)value_parts.size()));
721 
722   // cleanup temporary memory
723   free_parts(env, jparts_to_free);
724 
725   // return
726   if (s.ok()) {
727     return;
728   }
729 
730   ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
731 }
732 
733 /*
734  * Class:     org_rocksdb_Transaction
735  * Method:    put
736  * Signature: (J[[BI[[BIJZ)V
737  */
Java_org_rocksdb_Transaction_put__J_3_3BI_3_3BIJZ(JNIEnv * env,jobject,jlong jhandle,jobjectArray jkey_parts,jint jkey_parts_len,jobjectArray jvalue_parts,jint jvalue_parts_len,jlong jcolumn_family_handle,jboolean jassume_tracked)738 void Java_org_rocksdb_Transaction_put__J_3_3BI_3_3BIJZ(
739     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jobjectArray jkey_parts,
740     jint jkey_parts_len, jobjectArray jvalue_parts, jint jvalue_parts_len,
741     jlong jcolumn_family_handle, jboolean jassume_tracked) {
742   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
743   auto* column_family_handle =
744       reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>(
745           jcolumn_family_handle);
746   FnWriteKVParts fn_put_parts =
747       std::bind<ROCKSDB_NAMESPACE::Status (ROCKSDB_NAMESPACE::Transaction::*)(
748           ROCKSDB_NAMESPACE::ColumnFamilyHandle*,
749           const ROCKSDB_NAMESPACE::SliceParts&,
750           const ROCKSDB_NAMESPACE::SliceParts&, bool)>(
751           &ROCKSDB_NAMESPACE::Transaction::Put, txn, column_family_handle, _1,
752           _2, jassume_tracked);
753   txn_write_kv_parts_helper(env, fn_put_parts, jkey_parts, jkey_parts_len,
754                             jvalue_parts, jvalue_parts_len);
755 }
756 
757 /*
758  * Class:     org_rocksdb_Transaction
759  * Method:    put
760  * Signature: (J[[BI[[BI)V
761  */
Java_org_rocksdb_Transaction_put__J_3_3BI_3_3BI(JNIEnv * env,jobject,jlong jhandle,jobjectArray jkey_parts,jint jkey_parts_len,jobjectArray jvalue_parts,jint jvalue_parts_len)762 void Java_org_rocksdb_Transaction_put__J_3_3BI_3_3BI(
763     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jobjectArray jkey_parts,
764     jint jkey_parts_len, jobjectArray jvalue_parts, jint jvalue_parts_len) {
765   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
766   FnWriteKVParts fn_put_parts = std::bind<ROCKSDB_NAMESPACE::Status (
767       ROCKSDB_NAMESPACE::Transaction::*)(const ROCKSDB_NAMESPACE::SliceParts&,
768                                          const ROCKSDB_NAMESPACE::SliceParts&)>(
769       &ROCKSDB_NAMESPACE::Transaction::Put, txn, _1, _2);
770   txn_write_kv_parts_helper(env, fn_put_parts, jkey_parts, jkey_parts_len,
771                             jvalue_parts, jvalue_parts_len);
772 }
773 
774 /*
775  * Class:     org_rocksdb_Transaction
776  * Method:    merge
777  * Signature: (J[BI[BIJZ)V
778  */
Java_org_rocksdb_Transaction_merge__J_3BI_3BIJZ(JNIEnv * env,jobject,jlong jhandle,jbyteArray jkey,jint jkey_part_len,jbyteArray jval,jint jval_len,jlong jcolumn_family_handle,jboolean jassume_tracked)779 void Java_org_rocksdb_Transaction_merge__J_3BI_3BIJZ(
780     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jbyteArray jkey,
781     jint jkey_part_len, jbyteArray jval, jint jval_len,
782     jlong jcolumn_family_handle, jboolean jassume_tracked) {
783   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
784   auto* column_family_handle =
785       reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>(
786           jcolumn_family_handle);
787   FnWriteKV fn_merge =
788       std::bind<ROCKSDB_NAMESPACE::Status (ROCKSDB_NAMESPACE::Transaction::*)(
789           ROCKSDB_NAMESPACE::ColumnFamilyHandle*,
790           const ROCKSDB_NAMESPACE::Slice&, const ROCKSDB_NAMESPACE::Slice&,
791           bool)>(&ROCKSDB_NAMESPACE::Transaction::Merge, txn,
792                  column_family_handle, _1, _2, jassume_tracked);
793   txn_write_kv_helper(env, fn_merge, jkey, jkey_part_len, jval, jval_len);
794 }
795 
796 /*
797  * Class:     org_rocksdb_Transaction
798  * Method:    merge
799  * Signature: (J[BI[BI)V
800  */
Java_org_rocksdb_Transaction_merge__J_3BI_3BI(JNIEnv * env,jobject,jlong jhandle,jbyteArray jkey,jint jkey_part_len,jbyteArray jval,jint jval_len)801 void Java_org_rocksdb_Transaction_merge__J_3BI_3BI(
802     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jbyteArray jkey,
803     jint jkey_part_len, jbyteArray jval, jint jval_len) {
804   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
805   FnWriteKV fn_merge =
806       std::bind<ROCKSDB_NAMESPACE::Status (ROCKSDB_NAMESPACE::Transaction::*)(
807           const ROCKSDB_NAMESPACE::Slice&, const ROCKSDB_NAMESPACE::Slice&)>(
808           &ROCKSDB_NAMESPACE::Transaction::Merge, txn, _1, _2);
809   txn_write_kv_helper(env, fn_merge, jkey, jkey_part_len, jval, jval_len);
810 }
811 
812 typedef std::function<ROCKSDB_NAMESPACE::Status(
813     const ROCKSDB_NAMESPACE::Slice&)>
814     FnWriteK;
815 
816 // TODO(AR) consider refactoring to share this between here and rocksjni.cc
txn_write_k_helper(JNIEnv * env,const FnWriteK & fn_write_k,const jbyteArray & jkey,const jint & jkey_part_len)817 void txn_write_k_helper(JNIEnv* env, const FnWriteK& fn_write_k,
818                         const jbyteArray& jkey, const jint& jkey_part_len) {
819   jbyte* key = env->GetByteArrayElements(jkey, nullptr);
820   if (key == nullptr) {
821     // exception thrown: OutOfMemoryError
822     return;
823   }
824   ROCKSDB_NAMESPACE::Slice key_slice(reinterpret_cast<char*>(key),
825                                      jkey_part_len);
826 
827   ROCKSDB_NAMESPACE::Status s = fn_write_k(key_slice);
828 
829   // trigger java unref on key.
830   // by passing JNI_ABORT, it will simply release the reference without
831   // copying the result back to the java byte array.
832   env->ReleaseByteArrayElements(jkey, key, JNI_ABORT);
833 
834   if (s.ok()) {
835     return;
836   }
837   ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
838 }
839 
840 /*
841  * Class:     org_rocksdb_Transaction
842  * Method:    delete
843  * Signature: (J[BIJZ)V
844  */
Java_org_rocksdb_Transaction_delete__J_3BIJZ(JNIEnv * env,jobject,jlong jhandle,jbyteArray jkey,jint jkey_part_len,jlong jcolumn_family_handle,jboolean jassume_tracked)845 void Java_org_rocksdb_Transaction_delete__J_3BIJZ(
846     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jbyteArray jkey,
847     jint jkey_part_len, jlong jcolumn_family_handle, jboolean jassume_tracked) {
848   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
849   auto* column_family_handle =
850       reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>(
851           jcolumn_family_handle);
852   FnWriteK fn_delete =
853       std::bind<ROCKSDB_NAMESPACE::Status (ROCKSDB_NAMESPACE::Transaction::*)(
854           ROCKSDB_NAMESPACE::ColumnFamilyHandle*,
855           const ROCKSDB_NAMESPACE::Slice&, bool)>(
856           &ROCKSDB_NAMESPACE::Transaction::Delete, txn, column_family_handle,
857           _1, jassume_tracked);
858   txn_write_k_helper(env, fn_delete, jkey, jkey_part_len);
859 }
860 
861 /*
862  * Class:     org_rocksdb_Transaction
863  * Method:    delete
864  * Signature: (J[BI)V
865  */
Java_org_rocksdb_Transaction_delete__J_3BI(JNIEnv * env,jobject,jlong jhandle,jbyteArray jkey,jint jkey_part_len)866 void Java_org_rocksdb_Transaction_delete__J_3BI(JNIEnv* env, jobject /*jobj*/,
867                                                 jlong jhandle, jbyteArray jkey,
868                                                 jint jkey_part_len) {
869   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
870   FnWriteK fn_delete = std::bind<ROCKSDB_NAMESPACE::Status (
871       ROCKSDB_NAMESPACE::Transaction::*)(const ROCKSDB_NAMESPACE::Slice&)>(
872       &ROCKSDB_NAMESPACE::Transaction::Delete, txn, _1);
873   txn_write_k_helper(env, fn_delete, jkey, jkey_part_len);
874 }
875 
876 typedef std::function<ROCKSDB_NAMESPACE::Status(
877     const ROCKSDB_NAMESPACE::SliceParts&)>
878     FnWriteKParts;
879 
880 // TODO(AR) consider refactoring to share this between here and rocksjni.cc
txn_write_k_parts_helper(JNIEnv * env,const FnWriteKParts & fn_write_k_parts,const jobjectArray & jkey_parts,const jint & jkey_parts_len)881 void txn_write_k_parts_helper(JNIEnv* env,
882                               const FnWriteKParts& fn_write_k_parts,
883                               const jobjectArray& jkey_parts,
884                               const jint& jkey_parts_len) {
885   std::vector<ROCKSDB_NAMESPACE::Slice> key_parts;
886   std::vector<std::tuple<jbyteArray, jbyte*, jobject>> jkey_parts_to_free;
887 
888   // convert java key_parts byte[][] to Slice(s)
889   for (jint i = 0; i < jkey_parts_len; ++i) {
890     const jobject jobj_key_part = env->GetObjectArrayElement(jkey_parts, i);
891     if (env->ExceptionCheck()) {
892       // exception thrown: ArrayIndexOutOfBoundsException
893       free_parts(env, jkey_parts_to_free);
894       return;
895     }
896 
897     const jbyteArray jba_key_part = reinterpret_cast<jbyteArray>(jobj_key_part);
898     const jsize jkey_part_len = env->GetArrayLength(jba_key_part);
899     if (env->EnsureLocalCapacity(jkey_part_len) != 0) {
900       // out of memory
901       env->DeleteLocalRef(jobj_key_part);
902       free_parts(env, jkey_parts_to_free);
903       return;
904     }
905     jbyte* jkey_part = env->GetByteArrayElements(jba_key_part, nullptr);
906     if (jkey_part == nullptr) {
907       // exception thrown: OutOfMemoryError
908       env->DeleteLocalRef(jobj_key_part);
909       free_parts(env, jkey_parts_to_free);
910       return;
911     }
912 
913     jkey_parts_to_free.push_back(std::tuple<jbyteArray, jbyte*, jobject>(
914         jba_key_part, jkey_part, jobj_key_part));
915 
916     key_parts.push_back(ROCKSDB_NAMESPACE::Slice(
917         reinterpret_cast<char*>(jkey_part), jkey_part_len));
918   }
919 
920   // call the write_multi function
921   ROCKSDB_NAMESPACE::Status s = fn_write_k_parts(
922       ROCKSDB_NAMESPACE::SliceParts(key_parts.data(), (int)key_parts.size()));
923 
924   // cleanup temporary memory
925   free_parts(env, jkey_parts_to_free);
926 
927   // return
928   if (s.ok()) {
929     return;
930   }
931   ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
932 }
933 
934 /*
935  * Class:     org_rocksdb_Transaction
936  * Method:    delete
937  * Signature: (J[[BIJZ)V
938  */
Java_org_rocksdb_Transaction_delete__J_3_3BIJZ(JNIEnv * env,jobject,jlong jhandle,jobjectArray jkey_parts,jint jkey_parts_len,jlong jcolumn_family_handle,jboolean jassume_tracked)939 void Java_org_rocksdb_Transaction_delete__J_3_3BIJZ(
940     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jobjectArray jkey_parts,
941     jint jkey_parts_len, jlong jcolumn_family_handle,
942     jboolean jassume_tracked) {
943   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
944   auto* column_family_handle =
945       reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>(
946           jcolumn_family_handle);
947   FnWriteKParts fn_delete_parts =
948       std::bind<ROCKSDB_NAMESPACE::Status (ROCKSDB_NAMESPACE::Transaction::*)(
949           ROCKSDB_NAMESPACE::ColumnFamilyHandle*,
950           const ROCKSDB_NAMESPACE::SliceParts&, bool)>(
951           &ROCKSDB_NAMESPACE::Transaction::Delete, txn, column_family_handle,
952           _1, jassume_tracked);
953   txn_write_k_parts_helper(env, fn_delete_parts, jkey_parts, jkey_parts_len);
954 }
955 
956 /*
957  * Class:     org_rocksdb_Transaction
958  * Method:    delete
959  * Signature: (J[[BI)V
960  */
Java_org_rocksdb_Transaction_delete__J_3_3BI(JNIEnv * env,jobject,jlong jhandle,jobjectArray jkey_parts,jint jkey_parts_len)961 void Java_org_rocksdb_Transaction_delete__J_3_3BI(JNIEnv* env, jobject /*jobj*/,
962                                                   jlong jhandle,
963                                                   jobjectArray jkey_parts,
964                                                   jint jkey_parts_len) {
965   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
966   FnWriteKParts fn_delete_parts = std::bind<ROCKSDB_NAMESPACE::Status (
967       ROCKSDB_NAMESPACE::Transaction::*)(const ROCKSDB_NAMESPACE::SliceParts&)>(
968       &ROCKSDB_NAMESPACE::Transaction::Delete, txn, _1);
969   txn_write_k_parts_helper(env, fn_delete_parts, jkey_parts, jkey_parts_len);
970 }
971 
972 /*
973  * Class:     org_rocksdb_Transaction
974  * Method:    singleDelete
975  * Signature: (J[BIJZ)V
976  */
Java_org_rocksdb_Transaction_singleDelete__J_3BIJZ(JNIEnv * env,jobject,jlong jhandle,jbyteArray jkey,jint jkey_part_len,jlong jcolumn_family_handle,jboolean jassume_tracked)977 void Java_org_rocksdb_Transaction_singleDelete__J_3BIJZ(
978     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jbyteArray jkey,
979     jint jkey_part_len, jlong jcolumn_family_handle, jboolean jassume_tracked) {
980   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
981   auto* column_family_handle =
982       reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>(
983           jcolumn_family_handle);
984   FnWriteK fn_single_delete =
985       std::bind<ROCKSDB_NAMESPACE::Status (ROCKSDB_NAMESPACE::Transaction::*)(
986           ROCKSDB_NAMESPACE::ColumnFamilyHandle*,
987           const ROCKSDB_NAMESPACE::Slice&, bool)>(
988           &ROCKSDB_NAMESPACE::Transaction::SingleDelete, txn,
989           column_family_handle, _1, jassume_tracked);
990   txn_write_k_helper(env, fn_single_delete, jkey, jkey_part_len);
991 }
992 
993 /*
994  * Class:     org_rocksdb_Transaction
995  * Method:    singleDelete
996  * Signature: (J[BI)V
997  */
Java_org_rocksdb_Transaction_singleDelete__J_3BI(JNIEnv * env,jobject,jlong jhandle,jbyteArray jkey,jint jkey_part_len)998 void Java_org_rocksdb_Transaction_singleDelete__J_3BI(JNIEnv* env,
999                                                       jobject /*jobj*/,
1000                                                       jlong jhandle,
1001                                                       jbyteArray jkey,
1002                                                       jint jkey_part_len) {
1003   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1004   FnWriteK fn_single_delete = std::bind<ROCKSDB_NAMESPACE::Status (
1005       ROCKSDB_NAMESPACE::Transaction::*)(const ROCKSDB_NAMESPACE::Slice&)>(
1006       &ROCKSDB_NAMESPACE::Transaction::SingleDelete, txn, _1);
1007   txn_write_k_helper(env, fn_single_delete, jkey, jkey_part_len);
1008 }
1009 
1010 /*
1011  * Class:     org_rocksdb_Transaction
1012  * Method:    singleDelete
1013  * Signature: (J[[BIJZ)V
1014  */
Java_org_rocksdb_Transaction_singleDelete__J_3_3BIJZ(JNIEnv * env,jobject,jlong jhandle,jobjectArray jkey_parts,jint jkey_parts_len,jlong jcolumn_family_handle,jboolean jassume_tracked)1015 void Java_org_rocksdb_Transaction_singleDelete__J_3_3BIJZ(
1016     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jobjectArray jkey_parts,
1017     jint jkey_parts_len, jlong jcolumn_family_handle,
1018     jboolean jassume_tracked) {
1019   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1020   auto* column_family_handle =
1021       reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>(
1022           jcolumn_family_handle);
1023   FnWriteKParts fn_single_delete_parts =
1024       std::bind<ROCKSDB_NAMESPACE::Status (ROCKSDB_NAMESPACE::Transaction::*)(
1025           ROCKSDB_NAMESPACE::ColumnFamilyHandle*,
1026           const ROCKSDB_NAMESPACE::SliceParts&, bool)>(
1027           &ROCKSDB_NAMESPACE::Transaction::SingleDelete, txn,
1028           column_family_handle, _1, jassume_tracked);
1029   txn_write_k_parts_helper(env, fn_single_delete_parts, jkey_parts,
1030                            jkey_parts_len);
1031 }
1032 
1033 /*
1034  * Class:     org_rocksdb_Transaction
1035  * Method:    singleDelete
1036  * Signature: (J[[BI)V
1037  */
Java_org_rocksdb_Transaction_singleDelete__J_3_3BI(JNIEnv * env,jobject,jlong jhandle,jobjectArray jkey_parts,jint jkey_parts_len)1038 void Java_org_rocksdb_Transaction_singleDelete__J_3_3BI(JNIEnv* env,
1039                                                         jobject /*jobj*/,
1040                                                         jlong jhandle,
1041                                                         jobjectArray jkey_parts,
1042                                                         jint jkey_parts_len) {
1043   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1044   FnWriteKParts fn_single_delete_parts = std::bind<ROCKSDB_NAMESPACE::Status (
1045       ROCKSDB_NAMESPACE::Transaction::*)(const ROCKSDB_NAMESPACE::SliceParts&)>(
1046       &ROCKSDB_NAMESPACE::Transaction::SingleDelete, txn, _1);
1047   txn_write_k_parts_helper(env, fn_single_delete_parts, jkey_parts,
1048                            jkey_parts_len);
1049 }
1050 
1051 /*
1052  * Class:     org_rocksdb_Transaction
1053  * Method:    putUntracked
1054  * Signature: (J[BI[BIJ)V
1055  */
Java_org_rocksdb_Transaction_putUntracked__J_3BI_3BIJ(JNIEnv * env,jobject,jlong jhandle,jbyteArray jkey,jint jkey_part_len,jbyteArray jval,jint jval_len,jlong jcolumn_family_handle)1056 void Java_org_rocksdb_Transaction_putUntracked__J_3BI_3BIJ(
1057     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jbyteArray jkey,
1058     jint jkey_part_len, jbyteArray jval, jint jval_len,
1059     jlong jcolumn_family_handle) {
1060   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1061   auto* column_family_handle =
1062       reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>(
1063           jcolumn_family_handle);
1064   FnWriteKV fn_put_untracked =
1065       std::bind<ROCKSDB_NAMESPACE::Status (ROCKSDB_NAMESPACE::Transaction::*)(
1066           ROCKSDB_NAMESPACE::ColumnFamilyHandle*,
1067           const ROCKSDB_NAMESPACE::Slice&, const ROCKSDB_NAMESPACE::Slice&)>(
1068           &ROCKSDB_NAMESPACE::Transaction::PutUntracked, txn,
1069           column_family_handle, _1, _2);
1070   txn_write_kv_helper(env, fn_put_untracked, jkey, jkey_part_len, jval,
1071                       jval_len);
1072 }
1073 
1074 /*
1075  * Class:     org_rocksdb_Transaction
1076  * Method:    putUntracked
1077  * Signature: (J[BI[BI)V
1078  */
Java_org_rocksdb_Transaction_putUntracked__J_3BI_3BI(JNIEnv * env,jobject,jlong jhandle,jbyteArray jkey,jint jkey_part_len,jbyteArray jval,jint jval_len)1079 void Java_org_rocksdb_Transaction_putUntracked__J_3BI_3BI(
1080     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jbyteArray jkey,
1081     jint jkey_part_len, jbyteArray jval, jint jval_len) {
1082   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1083   FnWriteKV fn_put_untracked =
1084       std::bind<ROCKSDB_NAMESPACE::Status (ROCKSDB_NAMESPACE::Transaction::*)(
1085           const ROCKSDB_NAMESPACE::Slice&, const ROCKSDB_NAMESPACE::Slice&)>(
1086           &ROCKSDB_NAMESPACE::Transaction::PutUntracked, txn, _1, _2);
1087   txn_write_kv_helper(env, fn_put_untracked, jkey, jkey_part_len, jval,
1088                       jval_len);
1089 }
1090 
1091 /*
1092  * Class:     org_rocksdb_Transaction
1093  * Method:    putUntracked
1094  * Signature: (J[[BI[[BIJ)V
1095  */
Java_org_rocksdb_Transaction_putUntracked__J_3_3BI_3_3BIJ(JNIEnv * env,jobject,jlong jhandle,jobjectArray jkey_parts,jint jkey_parts_len,jobjectArray jvalue_parts,jint jvalue_parts_len,jlong jcolumn_family_handle)1096 void Java_org_rocksdb_Transaction_putUntracked__J_3_3BI_3_3BIJ(
1097     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jobjectArray jkey_parts,
1098     jint jkey_parts_len, jobjectArray jvalue_parts, jint jvalue_parts_len,
1099     jlong jcolumn_family_handle) {
1100   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1101   auto* column_family_handle =
1102       reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>(
1103           jcolumn_family_handle);
1104   FnWriteKVParts fn_put_parts_untracked = std::bind<ROCKSDB_NAMESPACE::Status (
1105       ROCKSDB_NAMESPACE::Transaction::*)(ROCKSDB_NAMESPACE::ColumnFamilyHandle*,
1106                                          const ROCKSDB_NAMESPACE::SliceParts&,
1107                                          const ROCKSDB_NAMESPACE::SliceParts&)>(
1108       &ROCKSDB_NAMESPACE::Transaction::PutUntracked, txn, column_family_handle,
1109       _1, _2);
1110   txn_write_kv_parts_helper(env, fn_put_parts_untracked, jkey_parts,
1111                             jkey_parts_len, jvalue_parts, jvalue_parts_len);
1112 }
1113 
1114 /*
1115  * Class:     org_rocksdb_Transaction
1116  * Method:    putUntracked
1117  * Signature: (J[[BI[[BI)V
1118  */
Java_org_rocksdb_Transaction_putUntracked__J_3_3BI_3_3BI(JNIEnv * env,jobject,jlong jhandle,jobjectArray jkey_parts,jint jkey_parts_len,jobjectArray jvalue_parts,jint jvalue_parts_len)1119 void Java_org_rocksdb_Transaction_putUntracked__J_3_3BI_3_3BI(
1120     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jobjectArray jkey_parts,
1121     jint jkey_parts_len, jobjectArray jvalue_parts, jint jvalue_parts_len) {
1122   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1123   FnWriteKVParts fn_put_parts_untracked = std::bind<ROCKSDB_NAMESPACE::Status (
1124       ROCKSDB_NAMESPACE::Transaction::*)(const ROCKSDB_NAMESPACE::SliceParts&,
1125                                          const ROCKSDB_NAMESPACE::SliceParts&)>(
1126       &ROCKSDB_NAMESPACE::Transaction::PutUntracked, txn, _1, _2);
1127   txn_write_kv_parts_helper(env, fn_put_parts_untracked, jkey_parts,
1128                             jkey_parts_len, jvalue_parts, jvalue_parts_len);
1129 }
1130 
1131 /*
1132  * Class:     org_rocksdb_Transaction
1133  * Method:    mergeUntracked
1134  * Signature: (J[BI[BIJ)V
1135  */
Java_org_rocksdb_Transaction_mergeUntracked__J_3BI_3BIJ(JNIEnv * env,jobject,jlong jhandle,jbyteArray jkey,jint jkey_part_len,jbyteArray jval,jint jval_len,jlong jcolumn_family_handle)1136 void Java_org_rocksdb_Transaction_mergeUntracked__J_3BI_3BIJ(
1137     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jbyteArray jkey,
1138     jint jkey_part_len, jbyteArray jval, jint jval_len,
1139     jlong jcolumn_family_handle) {
1140   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1141   auto* column_family_handle =
1142       reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>(
1143           jcolumn_family_handle);
1144   FnWriteKV fn_merge_untracked =
1145       std::bind<ROCKSDB_NAMESPACE::Status (ROCKSDB_NAMESPACE::Transaction::*)(
1146           ROCKSDB_NAMESPACE::ColumnFamilyHandle*,
1147           const ROCKSDB_NAMESPACE::Slice&, const ROCKSDB_NAMESPACE::Slice&)>(
1148           &ROCKSDB_NAMESPACE::Transaction::MergeUntracked, txn,
1149           column_family_handle, _1, _2);
1150   txn_write_kv_helper(env, fn_merge_untracked, jkey, jkey_part_len, jval,
1151                       jval_len);
1152 }
1153 
1154 /*
1155  * Class:     org_rocksdb_Transaction
1156  * Method:    mergeUntracked
1157  * Signature: (J[BI[BI)V
1158  */
Java_org_rocksdb_Transaction_mergeUntracked__J_3BI_3BI(JNIEnv * env,jobject,jlong jhandle,jbyteArray jkey,jint jkey_part_len,jbyteArray jval,jint jval_len)1159 void Java_org_rocksdb_Transaction_mergeUntracked__J_3BI_3BI(
1160     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jbyteArray jkey,
1161     jint jkey_part_len, jbyteArray jval, jint jval_len) {
1162   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1163   FnWriteKV fn_merge_untracked =
1164       std::bind<ROCKSDB_NAMESPACE::Status (ROCKSDB_NAMESPACE::Transaction::*)(
1165           const ROCKSDB_NAMESPACE::Slice&, const ROCKSDB_NAMESPACE::Slice&)>(
1166           &ROCKSDB_NAMESPACE::Transaction::MergeUntracked, txn, _1, _2);
1167   txn_write_kv_helper(env, fn_merge_untracked, jkey, jkey_part_len, jval,
1168                       jval_len);
1169 }
1170 
1171 /*
1172  * Class:     org_rocksdb_Transaction
1173  * Method:    deleteUntracked
1174  * Signature: (J[BIJ)V
1175  */
Java_org_rocksdb_Transaction_deleteUntracked__J_3BIJ(JNIEnv * env,jobject,jlong jhandle,jbyteArray jkey,jint jkey_part_len,jlong jcolumn_family_handle)1176 void Java_org_rocksdb_Transaction_deleteUntracked__J_3BIJ(
1177     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jbyteArray jkey,
1178     jint jkey_part_len, jlong jcolumn_family_handle) {
1179   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1180   auto* column_family_handle =
1181       reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>(
1182           jcolumn_family_handle);
1183   FnWriteK fn_delete_untracked = std::bind<ROCKSDB_NAMESPACE::Status (
1184       ROCKSDB_NAMESPACE::Transaction::*)(ROCKSDB_NAMESPACE::ColumnFamilyHandle*,
1185                                          const ROCKSDB_NAMESPACE::Slice&)>(
1186       &ROCKSDB_NAMESPACE::Transaction::DeleteUntracked, txn,
1187       column_family_handle, _1);
1188   txn_write_k_helper(env, fn_delete_untracked, jkey, jkey_part_len);
1189 }
1190 
1191 /*
1192  * Class:     org_rocksdb_Transaction
1193  * Method:    deleteUntracked
1194  * Signature: (J[BI)V
1195  */
Java_org_rocksdb_Transaction_deleteUntracked__J_3BI(JNIEnv * env,jobject,jlong jhandle,jbyteArray jkey,jint jkey_part_len)1196 void Java_org_rocksdb_Transaction_deleteUntracked__J_3BI(JNIEnv* env,
1197                                                          jobject /*jobj*/,
1198                                                          jlong jhandle,
1199                                                          jbyteArray jkey,
1200                                                          jint jkey_part_len) {
1201   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1202   FnWriteK fn_delete_untracked = std::bind<ROCKSDB_NAMESPACE::Status (
1203       ROCKSDB_NAMESPACE::Transaction::*)(const ROCKSDB_NAMESPACE::Slice&)>(
1204       &ROCKSDB_NAMESPACE::Transaction::DeleteUntracked, txn, _1);
1205   txn_write_k_helper(env, fn_delete_untracked, jkey, jkey_part_len);
1206 }
1207 
1208 /*
1209  * Class:     org_rocksdb_Transaction
1210  * Method:    deleteUntracked
1211  * Signature: (J[[BIJ)V
1212  */
Java_org_rocksdb_Transaction_deleteUntracked__J_3_3BIJ(JNIEnv * env,jobject,jlong jhandle,jobjectArray jkey_parts,jint jkey_parts_len,jlong jcolumn_family_handle)1213 void Java_org_rocksdb_Transaction_deleteUntracked__J_3_3BIJ(
1214     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jobjectArray jkey_parts,
1215     jint jkey_parts_len, jlong jcolumn_family_handle) {
1216   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1217   auto* column_family_handle =
1218       reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>(
1219           jcolumn_family_handle);
1220   FnWriteKParts fn_delete_untracked_parts =
1221       std::bind<ROCKSDB_NAMESPACE::Status (ROCKSDB_NAMESPACE::Transaction::*)(
1222           ROCKSDB_NAMESPACE::ColumnFamilyHandle*,
1223           const ROCKSDB_NAMESPACE::SliceParts&)>(
1224           &ROCKSDB_NAMESPACE::Transaction::DeleteUntracked, txn,
1225           column_family_handle, _1);
1226   txn_write_k_parts_helper(env, fn_delete_untracked_parts, jkey_parts,
1227                            jkey_parts_len);
1228 }
1229 
1230 /*
1231  * Class:     org_rocksdb_Transaction
1232  * Method:    deleteUntracked
1233  * Signature: (J[[BI)V
1234  */
Java_org_rocksdb_Transaction_deleteUntracked__J_3_3BI(JNIEnv * env,jobject,jlong jhandle,jobjectArray jkey_parts,jint jkey_parts_len)1235 void Java_org_rocksdb_Transaction_deleteUntracked__J_3_3BI(
1236     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jobjectArray jkey_parts,
1237     jint jkey_parts_len) {
1238   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1239   FnWriteKParts fn_delete_untracked_parts =
1240       std::bind<ROCKSDB_NAMESPACE::Status (ROCKSDB_NAMESPACE::Transaction::*)(
1241           const ROCKSDB_NAMESPACE::SliceParts&)>(
1242           &ROCKSDB_NAMESPACE::Transaction::DeleteUntracked, txn, _1);
1243   txn_write_k_parts_helper(env, fn_delete_untracked_parts, jkey_parts,
1244                            jkey_parts_len);
1245 }
1246 
1247 /*
1248  * Class:     org_rocksdb_Transaction
1249  * Method:    putLogData
1250  * Signature: (J[BI)V
1251  */
Java_org_rocksdb_Transaction_putLogData(JNIEnv * env,jobject,jlong jhandle,jbyteArray jkey,jint jkey_part_len)1252 void Java_org_rocksdb_Transaction_putLogData(JNIEnv* env, jobject /*jobj*/,
1253                                              jlong jhandle, jbyteArray jkey,
1254                                              jint jkey_part_len) {
1255   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1256 
1257   jbyte* key = env->GetByteArrayElements(jkey, nullptr);
1258   if (key == nullptr) {
1259     // exception thrown: OutOfMemoryError
1260     return;
1261   }
1262 
1263   ROCKSDB_NAMESPACE::Slice key_slice(reinterpret_cast<char*>(key),
1264                                      jkey_part_len);
1265   txn->PutLogData(key_slice);
1266 
1267   // trigger java unref on key.
1268   // by passing JNI_ABORT, it will simply release the reference without
1269   // copying the result back to the java byte array.
1270   env->ReleaseByteArrayElements(jkey, key, JNI_ABORT);
1271 }
1272 
1273 /*
1274  * Class:     org_rocksdb_Transaction
1275  * Method:    disableIndexing
1276  * Signature: (J)V
1277  */
Java_org_rocksdb_Transaction_disableIndexing(JNIEnv *,jobject,jlong jhandle)1278 void Java_org_rocksdb_Transaction_disableIndexing(JNIEnv* /*env*/,
1279                                                   jobject /*jobj*/,
1280                                                   jlong jhandle) {
1281   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1282   txn->DisableIndexing();
1283 }
1284 
1285 /*
1286  * Class:     org_rocksdb_Transaction
1287  * Method:    enableIndexing
1288  * Signature: (J)V
1289  */
Java_org_rocksdb_Transaction_enableIndexing(JNIEnv *,jobject,jlong jhandle)1290 void Java_org_rocksdb_Transaction_enableIndexing(JNIEnv* /*env*/,
1291                                                  jobject /*jobj*/,
1292                                                  jlong jhandle) {
1293   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1294   txn->EnableIndexing();
1295 }
1296 
1297 /*
1298  * Class:     org_rocksdb_Transaction
1299  * Method:    getNumKeys
1300  * Signature: (J)J
1301  */
Java_org_rocksdb_Transaction_getNumKeys(JNIEnv *,jobject,jlong jhandle)1302 jlong Java_org_rocksdb_Transaction_getNumKeys(JNIEnv* /*env*/, jobject /*jobj*/,
1303                                               jlong jhandle) {
1304   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1305   return txn->GetNumKeys();
1306 }
1307 
1308 /*
1309  * Class:     org_rocksdb_Transaction
1310  * Method:    getNumPuts
1311  * Signature: (J)J
1312  */
Java_org_rocksdb_Transaction_getNumPuts(JNIEnv *,jobject,jlong jhandle)1313 jlong Java_org_rocksdb_Transaction_getNumPuts(JNIEnv* /*env*/, jobject /*jobj*/,
1314                                               jlong jhandle) {
1315   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1316   return txn->GetNumPuts();
1317 }
1318 
1319 /*
1320  * Class:     org_rocksdb_Transaction
1321  * Method:    getNumDeletes
1322  * Signature: (J)J
1323  */
Java_org_rocksdb_Transaction_getNumDeletes(JNIEnv *,jobject,jlong jhandle)1324 jlong Java_org_rocksdb_Transaction_getNumDeletes(JNIEnv* /*env*/,
1325                                                  jobject /*jobj*/,
1326                                                  jlong jhandle) {
1327   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1328   return txn->GetNumDeletes();
1329 }
1330 
1331 /*
1332  * Class:     org_rocksdb_Transaction
1333  * Method:    getNumMerges
1334  * Signature: (J)J
1335  */
Java_org_rocksdb_Transaction_getNumMerges(JNIEnv *,jobject,jlong jhandle)1336 jlong Java_org_rocksdb_Transaction_getNumMerges(JNIEnv* /*env*/,
1337                                                 jobject /*jobj*/,
1338                                                 jlong jhandle) {
1339   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1340   return txn->GetNumMerges();
1341 }
1342 
1343 /*
1344  * Class:     org_rocksdb_Transaction
1345  * Method:    getElapsedTime
1346  * Signature: (J)J
1347  */
Java_org_rocksdb_Transaction_getElapsedTime(JNIEnv *,jobject,jlong jhandle)1348 jlong Java_org_rocksdb_Transaction_getElapsedTime(JNIEnv* /*env*/,
1349                                                   jobject /*jobj*/,
1350                                                   jlong jhandle) {
1351   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1352   return txn->GetElapsedTime();
1353 }
1354 
1355 /*
1356  * Class:     org_rocksdb_Transaction
1357  * Method:    getWriteBatch
1358  * Signature: (J)J
1359  */
Java_org_rocksdb_Transaction_getWriteBatch(JNIEnv *,jobject,jlong jhandle)1360 jlong Java_org_rocksdb_Transaction_getWriteBatch(JNIEnv* /*env*/,
1361                                                  jobject /*jobj*/,
1362                                                  jlong jhandle) {
1363   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1364   return reinterpret_cast<jlong>(txn->GetWriteBatch());
1365 }
1366 
1367 /*
1368  * Class:     org_rocksdb_Transaction
1369  * Method:    setLockTimeout
1370  * Signature: (JJ)V
1371  */
Java_org_rocksdb_Transaction_setLockTimeout(JNIEnv *,jobject,jlong jhandle,jlong jlock_timeout)1372 void Java_org_rocksdb_Transaction_setLockTimeout(JNIEnv* /*env*/,
1373                                                  jobject /*jobj*/,
1374                                                  jlong jhandle,
1375                                                  jlong jlock_timeout) {
1376   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1377   txn->SetLockTimeout(jlock_timeout);
1378 }
1379 
1380 /*
1381  * Class:     org_rocksdb_Transaction
1382  * Method:    getWriteOptions
1383  * Signature: (J)J
1384  */
Java_org_rocksdb_Transaction_getWriteOptions(JNIEnv *,jobject,jlong jhandle)1385 jlong Java_org_rocksdb_Transaction_getWriteOptions(JNIEnv* /*env*/,
1386                                                    jobject /*jobj*/,
1387                                                    jlong jhandle) {
1388   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1389   return reinterpret_cast<jlong>(txn->GetWriteOptions());
1390 }
1391 
1392 /*
1393  * Class:     org_rocksdb_Transaction
1394  * Method:    setWriteOptions
1395  * Signature: (JJ)V
1396  */
Java_org_rocksdb_Transaction_setWriteOptions(JNIEnv *,jobject,jlong jhandle,jlong jwrite_options_handle)1397 void Java_org_rocksdb_Transaction_setWriteOptions(JNIEnv* /*env*/,
1398                                                   jobject /*jobj*/,
1399                                                   jlong jhandle,
1400                                                   jlong jwrite_options_handle) {
1401   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1402   auto* write_options =
1403       reinterpret_cast<ROCKSDB_NAMESPACE::WriteOptions*>(jwrite_options_handle);
1404   txn->SetWriteOptions(*write_options);
1405 }
1406 
1407 /*
1408  * Class:     org_rocksdb_Transaction
1409  * Method:    undo
1410  * Signature: (J[BIJ)V
1411  */
Java_org_rocksdb_Transaction_undoGetForUpdate__J_3BIJ(JNIEnv * env,jobject,jlong jhandle,jbyteArray jkey,jint jkey_part_len,jlong jcolumn_family_handle)1412 void Java_org_rocksdb_Transaction_undoGetForUpdate__J_3BIJ(
1413     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jbyteArray jkey,
1414     jint jkey_part_len, jlong jcolumn_family_handle) {
1415   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1416   auto* column_family_handle =
1417       reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>(
1418           jcolumn_family_handle);
1419   jbyte* key = env->GetByteArrayElements(jkey, nullptr);
1420   if (key == nullptr) {
1421     // exception thrown: OutOfMemoryError
1422     return;
1423   }
1424 
1425   ROCKSDB_NAMESPACE::Slice key_slice(reinterpret_cast<char*>(key),
1426                                      jkey_part_len);
1427   txn->UndoGetForUpdate(column_family_handle, key_slice);
1428 
1429   env->ReleaseByteArrayElements(jkey, key, JNI_ABORT);
1430 }
1431 
1432 /*
1433  * Class:     org_rocksdb_Transaction
1434  * Method:    undoGetForUpdate
1435  * Signature: (J[BI)V
1436  */
Java_org_rocksdb_Transaction_undoGetForUpdate__J_3BI(JNIEnv * env,jobject,jlong jhandle,jbyteArray jkey,jint jkey_part_len)1437 void Java_org_rocksdb_Transaction_undoGetForUpdate__J_3BI(JNIEnv* env,
1438                                                           jobject /*jobj*/,
1439                                                           jlong jhandle,
1440                                                           jbyteArray jkey,
1441                                                           jint jkey_part_len) {
1442   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1443   jbyte* key = env->GetByteArrayElements(jkey, nullptr);
1444   if (key == nullptr) {
1445     // exception thrown: OutOfMemoryError
1446     return;
1447   }
1448 
1449   ROCKSDB_NAMESPACE::Slice key_slice(reinterpret_cast<char*>(key),
1450                                      jkey_part_len);
1451   txn->UndoGetForUpdate(key_slice);
1452 
1453   env->ReleaseByteArrayElements(jkey, key, JNI_ABORT);
1454 }
1455 
1456 /*
1457  * Class:     org_rocksdb_Transaction
1458  * Method:    rebuildFromWriteBatch
1459  * Signature: (JJ)V
1460  */
Java_org_rocksdb_Transaction_rebuildFromWriteBatch(JNIEnv * env,jobject,jlong jhandle,jlong jwrite_batch_handle)1461 void Java_org_rocksdb_Transaction_rebuildFromWriteBatch(
1462     JNIEnv* env, jobject /*jobj*/, jlong jhandle, jlong jwrite_batch_handle) {
1463   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1464   auto* write_batch =
1465       reinterpret_cast<ROCKSDB_NAMESPACE::WriteBatch*>(jwrite_batch_handle);
1466   ROCKSDB_NAMESPACE::Status s = txn->RebuildFromWriteBatch(write_batch);
1467   if (!s.ok()) {
1468     ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
1469   }
1470 }
1471 
1472 /*
1473  * Class:     org_rocksdb_Transaction
1474  * Method:    getCommitTimeWriteBatch
1475  * Signature: (J)J
1476  */
Java_org_rocksdb_Transaction_getCommitTimeWriteBatch(JNIEnv *,jobject,jlong jhandle)1477 jlong Java_org_rocksdb_Transaction_getCommitTimeWriteBatch(JNIEnv* /*env*/,
1478                                                            jobject /*jobj*/,
1479                                                            jlong jhandle) {
1480   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1481   return reinterpret_cast<jlong>(txn->GetCommitTimeWriteBatch());
1482 }
1483 
1484 /*
1485  * Class:     org_rocksdb_Transaction
1486  * Method:    setLogNumber
1487  * Signature: (JJ)V
1488  */
Java_org_rocksdb_Transaction_setLogNumber(JNIEnv *,jobject,jlong jhandle,jlong jlog_number)1489 void Java_org_rocksdb_Transaction_setLogNumber(JNIEnv* /*env*/,
1490                                                jobject /*jobj*/, jlong jhandle,
1491                                                jlong jlog_number) {
1492   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1493   txn->SetLogNumber(jlog_number);
1494 }
1495 
1496 /*
1497  * Class:     org_rocksdb_Transaction
1498  * Method:    getLogNumber
1499  * Signature: (J)J
1500  */
Java_org_rocksdb_Transaction_getLogNumber(JNIEnv *,jobject,jlong jhandle)1501 jlong Java_org_rocksdb_Transaction_getLogNumber(JNIEnv* /*env*/,
1502                                                 jobject /*jobj*/,
1503                                                 jlong jhandle) {
1504   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1505   return txn->GetLogNumber();
1506 }
1507 
1508 /*
1509  * Class:     org_rocksdb_Transaction
1510  * Method:    setName
1511  * Signature: (JLjava/lang/String;)V
1512  */
Java_org_rocksdb_Transaction_setName(JNIEnv * env,jobject,jlong jhandle,jstring jname)1513 void Java_org_rocksdb_Transaction_setName(JNIEnv* env, jobject /*jobj*/,
1514                                           jlong jhandle, jstring jname) {
1515   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1516   const char* name = env->GetStringUTFChars(jname, nullptr);
1517   if (name == nullptr) {
1518     // exception thrown: OutOfMemoryError
1519     return;
1520   }
1521 
1522   ROCKSDB_NAMESPACE::Status s = txn->SetName(name);
1523 
1524   env->ReleaseStringUTFChars(jname, name);
1525 
1526   if (!s.ok()) {
1527     ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
1528   }
1529 }
1530 
1531 /*
1532  * Class:     org_rocksdb_Transaction
1533  * Method:    getName
1534  * Signature: (J)Ljava/lang/String;
1535  */
Java_org_rocksdb_Transaction_getName(JNIEnv * env,jobject,jlong jhandle)1536 jstring Java_org_rocksdb_Transaction_getName(JNIEnv* env, jobject /*jobj*/,
1537                                              jlong jhandle) {
1538   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1539   ROCKSDB_NAMESPACE::TransactionName name = txn->GetName();
1540   return env->NewStringUTF(name.data());
1541 }
1542 
1543 /*
1544  * Class:     org_rocksdb_Transaction
1545  * Method:    getID
1546  * Signature: (J)J
1547  */
Java_org_rocksdb_Transaction_getID(JNIEnv *,jobject,jlong jhandle)1548 jlong Java_org_rocksdb_Transaction_getID(JNIEnv* /*env*/, jobject /*jobj*/,
1549                                          jlong jhandle) {
1550   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1551   ROCKSDB_NAMESPACE::TransactionID id = txn->GetID();
1552   return static_cast<jlong>(id);
1553 }
1554 
1555 /*
1556  * Class:     org_rocksdb_Transaction
1557  * Method:    isDeadlockDetect
1558  * Signature: (J)Z
1559  */
Java_org_rocksdb_Transaction_isDeadlockDetect(JNIEnv *,jobject,jlong jhandle)1560 jboolean Java_org_rocksdb_Transaction_isDeadlockDetect(JNIEnv* /*env*/,
1561                                                        jobject /*jobj*/,
1562                                                        jlong jhandle) {
1563   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1564   return static_cast<jboolean>(txn->IsDeadlockDetect());
1565 }
1566 
1567 /*
1568  * Class:     org_rocksdb_Transaction
1569  * Method:    getWaitingTxns
1570  * Signature: (J)Lorg/rocksdb/Transaction/WaitingTransactions;
1571  */
Java_org_rocksdb_Transaction_getWaitingTxns(JNIEnv * env,jobject jtransaction_obj,jlong jhandle)1572 jobject Java_org_rocksdb_Transaction_getWaitingTxns(JNIEnv* env,
1573                                                     jobject jtransaction_obj,
1574                                                     jlong jhandle) {
1575   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1576   uint32_t column_family_id;
1577   std::string key;
1578   std::vector<ROCKSDB_NAMESPACE::TransactionID> waiting_txns =
1579       txn->GetWaitingTxns(&column_family_id, &key);
1580   jobject jwaiting_txns =
1581       ROCKSDB_NAMESPACE::TransactionJni::newWaitingTransactions(
1582           env, jtransaction_obj, column_family_id, key, waiting_txns);
1583   return jwaiting_txns;
1584 }
1585 
1586 /*
1587  * Class:     org_rocksdb_Transaction
1588  * Method:    getState
1589  * Signature: (J)B
1590  */
Java_org_rocksdb_Transaction_getState(JNIEnv *,jobject,jlong jhandle)1591 jbyte Java_org_rocksdb_Transaction_getState(JNIEnv* /*env*/, jobject /*jobj*/,
1592                                             jlong jhandle) {
1593   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1594   ROCKSDB_NAMESPACE::Transaction::TransactionState txn_status = txn->GetState();
1595   switch (txn_status) {
1596     case ROCKSDB_NAMESPACE::Transaction::TransactionState::STARTED:
1597       return 0x0;
1598 
1599     case ROCKSDB_NAMESPACE::Transaction::TransactionState::AWAITING_PREPARE:
1600       return 0x1;
1601 
1602     case ROCKSDB_NAMESPACE::Transaction::TransactionState::PREPARED:
1603       return 0x2;
1604 
1605     case ROCKSDB_NAMESPACE::Transaction::TransactionState::AWAITING_COMMIT:
1606       return 0x3;
1607 
1608     case ROCKSDB_NAMESPACE::Transaction::TransactionState::COMMITTED:
1609       return 0x4;
1610 
1611     case ROCKSDB_NAMESPACE::Transaction::TransactionState::AWAITING_ROLLBACK:
1612       return 0x5;
1613 
1614     case ROCKSDB_NAMESPACE::Transaction::TransactionState::ROLLEDBACK:
1615       return 0x6;
1616 
1617     case ROCKSDB_NAMESPACE::Transaction::TransactionState::LOCKS_STOLEN:
1618       return 0x7;
1619   }
1620 
1621   assert(false);
1622   return static_cast<jbyte>(-1);
1623 }
1624 
1625 /*
1626  * Class:     org_rocksdb_Transaction
1627  * Method:    getId
1628  * Signature: (J)J
1629  */
Java_org_rocksdb_Transaction_getId(JNIEnv *,jobject,jlong jhandle)1630 jlong Java_org_rocksdb_Transaction_getId(JNIEnv* /*env*/, jobject /*jobj*/,
1631                                          jlong jhandle) {
1632   auto* txn = reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1633   uint64_t id = txn->GetId();
1634   return static_cast<jlong>(id);
1635 }
1636 
1637 /*
1638  * Class:     org_rocksdb_Transaction
1639  * Method:    disposeInternal
1640  * Signature: (J)V
1641  */
Java_org_rocksdb_Transaction_disposeInternal(JNIEnv *,jobject,jlong jhandle)1642 void Java_org_rocksdb_Transaction_disposeInternal(JNIEnv* /*env*/,
1643                                                   jobject /*jobj*/,
1644                                                   jlong jhandle) {
1645   delete reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jhandle);
1646 }
1647