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::TransactionDB.
8 
9 #include <jni.h>
10 
11 #include "include/org_rocksdb_OptimisticTransactionDB.h"
12 
13 #include "rocksdb/options.h"
14 #include "rocksdb/utilities/optimistic_transaction_db.h"
15 #include "rocksdb/utilities/transaction.h"
16 
17 #include "rocksjni/portal.h"
18 
19 /*
20  * Class:     org_rocksdb_OptimisticTransactionDB
21  * Method:    open
22  * Signature: (JLjava/lang/String;)J
23  */
Java_org_rocksdb_OptimisticTransactionDB_open__JLjava_lang_String_2(JNIEnv * env,jclass,jlong joptions_handle,jstring jdb_path)24 jlong Java_org_rocksdb_OptimisticTransactionDB_open__JLjava_lang_String_2(
25     JNIEnv* env, jclass, jlong joptions_handle, jstring jdb_path) {
26   const char* db_path = env->GetStringUTFChars(jdb_path, nullptr);
27   if (db_path == nullptr) {
28     // exception thrown: OutOfMemoryError
29     return 0;
30   }
31 
32   auto* options =
33       reinterpret_cast<ROCKSDB_NAMESPACE::Options*>(joptions_handle);
34   ROCKSDB_NAMESPACE::OptimisticTransactionDB* otdb = nullptr;
35   ROCKSDB_NAMESPACE::Status s =
36       ROCKSDB_NAMESPACE::OptimisticTransactionDB::Open(*options, db_path,
37                                                        &otdb);
38   env->ReleaseStringUTFChars(jdb_path, db_path);
39 
40   if (s.ok()) {
41     return reinterpret_cast<jlong>(otdb);
42   } else {
43     ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
44     return 0;
45   }
46 }
47 
48 /*
49  * Class:     org_rocksdb_OptimisticTransactionDB
50  * Method:    open
51  * Signature: (JLjava/lang/String;[[B[J)[J
52  */
53 jlongArray
Java_org_rocksdb_OptimisticTransactionDB_open__JLjava_lang_String_2_3_3B_3J(JNIEnv * env,jclass,jlong jdb_options_handle,jstring jdb_path,jobjectArray jcolumn_names,jlongArray jcolumn_options_handles)54 Java_org_rocksdb_OptimisticTransactionDB_open__JLjava_lang_String_2_3_3B_3J(
55     JNIEnv* env, jclass, jlong jdb_options_handle, jstring jdb_path,
56     jobjectArray jcolumn_names, jlongArray jcolumn_options_handles) {
57   const char* db_path = env->GetStringUTFChars(jdb_path, nullptr);
58   if (db_path == nullptr) {
59     // exception thrown: OutOfMemoryError
60     return nullptr;
61   }
62 
63   std::vector<ROCKSDB_NAMESPACE::ColumnFamilyDescriptor> column_families;
64   const jsize len_cols = env->GetArrayLength(jcolumn_names);
65   if (len_cols > 0) {
66     if (env->EnsureLocalCapacity(len_cols) != 0) {
67       // out of memory
68       env->ReleaseStringUTFChars(jdb_path, db_path);
69       return nullptr;
70     }
71 
72     jlong* jco = env->GetLongArrayElements(jcolumn_options_handles, nullptr);
73     if (jco == nullptr) {
74       // exception thrown: OutOfMemoryError
75       env->ReleaseStringUTFChars(jdb_path, db_path);
76       return nullptr;
77     }
78 
79     for (int i = 0; i < len_cols; i++) {
80       const jobject jcn = env->GetObjectArrayElement(jcolumn_names, i);
81       if (env->ExceptionCheck()) {
82         // exception thrown: ArrayIndexOutOfBoundsException
83         env->ReleaseLongArrayElements(jcolumn_options_handles, jco, JNI_ABORT);
84         env->ReleaseStringUTFChars(jdb_path, db_path);
85         return nullptr;
86       }
87 
88       const jbyteArray jcn_ba = reinterpret_cast<jbyteArray>(jcn);
89       const jsize jcf_name_len = env->GetArrayLength(jcn_ba);
90       if (env->EnsureLocalCapacity(jcf_name_len) != 0) {
91         // out of memory
92         env->DeleteLocalRef(jcn);
93         env->ReleaseLongArrayElements(jcolumn_options_handles, jco, JNI_ABORT);
94         env->ReleaseStringUTFChars(jdb_path, db_path);
95         return nullptr;
96       }
97 
98       jbyte* jcf_name = env->GetByteArrayElements(jcn_ba, nullptr);
99       if (jcf_name == nullptr) {
100         // exception thrown: OutOfMemoryError
101         env->DeleteLocalRef(jcn);
102         env->ReleaseLongArrayElements(jcolumn_options_handles, jco, JNI_ABORT);
103         env->ReleaseStringUTFChars(jdb_path, db_path);
104         return nullptr;
105       }
106 
107       const std::string cf_name(reinterpret_cast<char*>(jcf_name),
108                                 jcf_name_len);
109       const ROCKSDB_NAMESPACE::ColumnFamilyOptions* cf_options =
110           reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyOptions*>(jco[i]);
111       column_families.push_back(
112           ROCKSDB_NAMESPACE::ColumnFamilyDescriptor(cf_name, *cf_options));
113 
114       env->ReleaseByteArrayElements(jcn_ba, jcf_name, JNI_ABORT);
115       env->DeleteLocalRef(jcn);
116     }
117     env->ReleaseLongArrayElements(jcolumn_options_handles, jco, JNI_ABORT);
118   }
119 
120   auto* db_options =
121       reinterpret_cast<ROCKSDB_NAMESPACE::DBOptions*>(jdb_options_handle);
122   std::vector<ROCKSDB_NAMESPACE::ColumnFamilyHandle*> handles;
123   ROCKSDB_NAMESPACE::OptimisticTransactionDB* otdb = nullptr;
124   const ROCKSDB_NAMESPACE::Status s =
125       ROCKSDB_NAMESPACE::OptimisticTransactionDB::Open(
126           *db_options, db_path, column_families, &handles, &otdb);
127 
128   env->ReleaseStringUTFChars(jdb_path, db_path);
129 
130   // check if open operation was successful
131   if (s.ok()) {
132     const jsize resultsLen = 1 + len_cols;  // db handle + column family handles
133     std::unique_ptr<jlong[]> results =
134         std::unique_ptr<jlong[]>(new jlong[resultsLen]);
135     results[0] = reinterpret_cast<jlong>(otdb);
136     for (int i = 1; i <= len_cols; i++) {
137       results[i] = reinterpret_cast<jlong>(handles[i - 1]);
138     }
139 
140     jlongArray jresults = env->NewLongArray(resultsLen);
141     if (jresults == nullptr) {
142       // exception thrown: OutOfMemoryError
143       return nullptr;
144     }
145     env->SetLongArrayRegion(jresults, 0, resultsLen, results.get());
146     if (env->ExceptionCheck()) {
147       // exception thrown: ArrayIndexOutOfBoundsException
148       return nullptr;
149     }
150     return jresults;
151   }
152 
153   ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
154   return nullptr;
155 }
156 
157 /*
158  * Class:     org_rocksdb_OptimisticTransactionDB
159  * Method:    disposeInternal
160  * Signature: (J)V
161  */
Java_org_rocksdb_OptimisticTransactionDB_disposeInternal(JNIEnv *,jobject,jlong jhandle)162 void Java_org_rocksdb_OptimisticTransactionDB_disposeInternal(
163     JNIEnv *, jobject, jlong jhandle) {
164   auto* optimistic_txn_db =
165       reinterpret_cast<ROCKSDB_NAMESPACE::OptimisticTransactionDB*>(jhandle);
166   assert(optimistic_txn_db != nullptr);
167   delete optimistic_txn_db;
168 }
169 
170 /*
171  * Class:     org_rocksdb_OptimisticTransactionDB
172  * Method:    closeDatabase
173  * Signature: (J)V
174  */
Java_org_rocksdb_OptimisticTransactionDB_closeDatabase(JNIEnv * env,jclass,jlong jhandle)175 void Java_org_rocksdb_OptimisticTransactionDB_closeDatabase(
176     JNIEnv* env, jclass, jlong jhandle) {
177   auto* optimistic_txn_db =
178       reinterpret_cast<ROCKSDB_NAMESPACE::OptimisticTransactionDB*>(jhandle);
179   assert(optimistic_txn_db != nullptr);
180   ROCKSDB_NAMESPACE::Status s = optimistic_txn_db->Close();
181   ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
182 }
183 
184 /*
185  * Class:     org_rocksdb_OptimisticTransactionDB
186  * Method:    beginTransaction
187  * Signature: (JJ)J
188  */
Java_org_rocksdb_OptimisticTransactionDB_beginTransaction__JJ(JNIEnv *,jobject,jlong jhandle,jlong jwrite_options_handle)189 jlong Java_org_rocksdb_OptimisticTransactionDB_beginTransaction__JJ(
190     JNIEnv*, jobject, jlong jhandle, jlong jwrite_options_handle) {
191   auto* optimistic_txn_db =
192       reinterpret_cast<ROCKSDB_NAMESPACE::OptimisticTransactionDB*>(jhandle);
193   auto* write_options =
194       reinterpret_cast<ROCKSDB_NAMESPACE::WriteOptions*>(jwrite_options_handle);
195   ROCKSDB_NAMESPACE::Transaction* txn =
196       optimistic_txn_db->BeginTransaction(*write_options);
197   return reinterpret_cast<jlong>(txn);
198 }
199 
200 /*
201  * Class:     org_rocksdb_OptimisticTransactionDB
202  * Method:    beginTransaction
203  * Signature: (JJJ)J
204  */
Java_org_rocksdb_OptimisticTransactionDB_beginTransaction__JJJ(JNIEnv *,jobject,jlong jhandle,jlong jwrite_options_handle,jlong joptimistic_txn_options_handle)205 jlong Java_org_rocksdb_OptimisticTransactionDB_beginTransaction__JJJ(
206     JNIEnv* /*env*/, jobject /*jobj*/, jlong jhandle,
207     jlong jwrite_options_handle, jlong joptimistic_txn_options_handle) {
208   auto* optimistic_txn_db =
209       reinterpret_cast<ROCKSDB_NAMESPACE::OptimisticTransactionDB*>(jhandle);
210   auto* write_options =
211       reinterpret_cast<ROCKSDB_NAMESPACE::WriteOptions*>(jwrite_options_handle);
212   auto* optimistic_txn_options =
213       reinterpret_cast<ROCKSDB_NAMESPACE::OptimisticTransactionOptions*>(
214           joptimistic_txn_options_handle);
215   ROCKSDB_NAMESPACE::Transaction* txn = optimistic_txn_db->BeginTransaction(
216       *write_options, *optimistic_txn_options);
217   return reinterpret_cast<jlong>(txn);
218 }
219 
220 /*
221  * Class:     org_rocksdb_OptimisticTransactionDB
222  * Method:    beginTransaction_withOld
223  * Signature: (JJJ)J
224  */
Java_org_rocksdb_OptimisticTransactionDB_beginTransaction_1withOld__JJJ(JNIEnv *,jobject,jlong jhandle,jlong jwrite_options_handle,jlong jold_txn_handle)225 jlong Java_org_rocksdb_OptimisticTransactionDB_beginTransaction_1withOld__JJJ(
226     JNIEnv*, jobject, jlong jhandle, jlong jwrite_options_handle,
227     jlong jold_txn_handle) {
228   auto* optimistic_txn_db =
229       reinterpret_cast<ROCKSDB_NAMESPACE::OptimisticTransactionDB*>(jhandle);
230   auto* write_options =
231       reinterpret_cast<ROCKSDB_NAMESPACE::WriteOptions*>(jwrite_options_handle);
232   auto* old_txn =
233       reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jold_txn_handle);
234   ROCKSDB_NAMESPACE::OptimisticTransactionOptions optimistic_txn_options;
235   ROCKSDB_NAMESPACE::Transaction* txn = optimistic_txn_db->BeginTransaction(
236       *write_options, optimistic_txn_options, old_txn);
237 
238   // RocksJava relies on the assumption that
239   // we do not allocate a new Transaction object
240   // when providing an old_optimistic_txn
241   assert(txn == old_txn);
242 
243   return reinterpret_cast<jlong>(txn);
244 }
245 
246 /*
247  * Class:     org_rocksdb_OptimisticTransactionDB
248  * Method:    beginTransaction_withOld
249  * Signature: (JJJJ)J
250  */
Java_org_rocksdb_OptimisticTransactionDB_beginTransaction_1withOld__JJJJ(JNIEnv *,jobject,jlong jhandle,jlong jwrite_options_handle,jlong joptimistic_txn_options_handle,jlong jold_txn_handle)251 jlong Java_org_rocksdb_OptimisticTransactionDB_beginTransaction_1withOld__JJJJ(
252     JNIEnv*, jobject, jlong jhandle, jlong jwrite_options_handle,
253     jlong joptimistic_txn_options_handle, jlong jold_txn_handle) {
254   auto* optimistic_txn_db =
255       reinterpret_cast<ROCKSDB_NAMESPACE::OptimisticTransactionDB*>(jhandle);
256   auto* write_options =
257       reinterpret_cast<ROCKSDB_NAMESPACE::WriteOptions*>(jwrite_options_handle);
258   auto* optimistic_txn_options =
259       reinterpret_cast<ROCKSDB_NAMESPACE::OptimisticTransactionOptions*>(
260           joptimistic_txn_options_handle);
261   auto* old_txn =
262       reinterpret_cast<ROCKSDB_NAMESPACE::Transaction*>(jold_txn_handle);
263   ROCKSDB_NAMESPACE::Transaction* txn = optimistic_txn_db->BeginTransaction(
264       *write_options, *optimistic_txn_options, old_txn);
265 
266   // RocksJava relies on the assumption that
267   // we do not allocate a new Transaction object
268   // when providing an old_optimisic_txn
269   assert(txn == old_txn);
270 
271   return reinterpret_cast<jlong>(txn);
272 }
273 
274 /*
275  * Class:     org_rocksdb_OptimisticTransactionDB
276  * Method:    getBaseDB
277  * Signature: (J)J
278  */
Java_org_rocksdb_OptimisticTransactionDB_getBaseDB(JNIEnv *,jobject,jlong jhandle)279 jlong Java_org_rocksdb_OptimisticTransactionDB_getBaseDB(
280     JNIEnv*, jobject, jlong jhandle) {
281   auto* optimistic_txn_db =
282       reinterpret_cast<ROCKSDB_NAMESPACE::OptimisticTransactionDB*>(jhandle);
283   return reinterpret_cast<jlong>(optimistic_txn_db->GetBaseDB());
284 }
285