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++ and enables
7 // calling c++ ROCKSDB_NAMESPACE::WriteBatch methods testing from Java side.
8 #include <memory>
9 
10 #include "db/memtable.h"
11 #include "db/write_batch_internal.h"
12 #include "include/org_rocksdb_WriteBatch.h"
13 #include "include/org_rocksdb_WriteBatchTest.h"
14 #include "include/org_rocksdb_WriteBatchTestInternalHelper.h"
15 #include "include/org_rocksdb_WriteBatch_Handler.h"
16 #include "options/cf_options.h"
17 #include "rocksdb/db.h"
18 #include "rocksdb/env.h"
19 #include "rocksdb/memtablerep.h"
20 #include "rocksdb/status.h"
21 #include "rocksdb/write_batch.h"
22 #include "rocksdb/write_buffer_manager.h"
23 #include "rocksjni/portal.h"
24 #include "table/scoped_arena_iterator.h"
25 #include "test_util/testharness.h"
26 #include "util/string_util.h"
27 
28 /*
29  * Class:     org_rocksdb_WriteBatchTest
30  * Method:    getContents
31  * Signature: (J)[B
32  */
Java_org_rocksdb_WriteBatchTest_getContents(JNIEnv * env,jclass,jlong jwb_handle)33 jbyteArray Java_org_rocksdb_WriteBatchTest_getContents(JNIEnv* env,
34                                                        jclass /*jclazz*/,
35                                                        jlong jwb_handle) {
36   auto* b = reinterpret_cast<ROCKSDB_NAMESPACE::WriteBatch*>(jwb_handle);
37   assert(b != nullptr);
38 
39   // todo: Currently the following code is directly copied from
40   // db/write_bench_test.cc.  It could be implemented in java once
41   // all the necessary components can be accessed via jni api.
42 
43   ROCKSDB_NAMESPACE::InternalKeyComparator cmp(
44       ROCKSDB_NAMESPACE::BytewiseComparator());
45   auto factory = std::make_shared<ROCKSDB_NAMESPACE::SkipListFactory>();
46   ROCKSDB_NAMESPACE::Options options;
47   ROCKSDB_NAMESPACE::WriteBufferManager wb(options.db_write_buffer_size);
48   options.memtable_factory = factory;
49   ROCKSDB_NAMESPACE::MemTable* mem = new ROCKSDB_NAMESPACE::MemTable(
50       cmp, ROCKSDB_NAMESPACE::ImmutableCFOptions(options),
51       ROCKSDB_NAMESPACE::MutableCFOptions(options), &wb,
52       ROCKSDB_NAMESPACE::kMaxSequenceNumber, 0 /* column_family_id */);
53   mem->Ref();
54   std::string state;
55   ROCKSDB_NAMESPACE::ColumnFamilyMemTablesDefault cf_mems_default(mem);
56   ROCKSDB_NAMESPACE::Status s =
57       ROCKSDB_NAMESPACE::WriteBatchInternal::InsertInto(b, &cf_mems_default,
58                                                         nullptr, nullptr);
59   unsigned int count = 0;
60   ROCKSDB_NAMESPACE::Arena arena;
61   ROCKSDB_NAMESPACE::ScopedArenaIterator iter(
62       mem->NewIterator(ROCKSDB_NAMESPACE::ReadOptions(), &arena));
63   for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
64     ROCKSDB_NAMESPACE::ParsedInternalKey ikey;
65     ikey.clear();
66     bool parsed = ROCKSDB_NAMESPACE::ParseInternalKey(iter->key(), &ikey);
67     if (!parsed) {
68       assert(parsed);
69     }
70     switch (ikey.type) {
71       case ROCKSDB_NAMESPACE::kTypeValue:
72         state.append("Put(");
73         state.append(ikey.user_key.ToString());
74         state.append(", ");
75         state.append(iter->value().ToString());
76         state.append(")");
77         count++;
78         break;
79       case ROCKSDB_NAMESPACE::kTypeMerge:
80         state.append("Merge(");
81         state.append(ikey.user_key.ToString());
82         state.append(", ");
83         state.append(iter->value().ToString());
84         state.append(")");
85         count++;
86         break;
87       case ROCKSDB_NAMESPACE::kTypeDeletion:
88         state.append("Delete(");
89         state.append(ikey.user_key.ToString());
90         state.append(")");
91         count++;
92         break;
93       case ROCKSDB_NAMESPACE::kTypeSingleDeletion:
94         state.append("SingleDelete(");
95         state.append(ikey.user_key.ToString());
96         state.append(")");
97         count++;
98         break;
99       case ROCKSDB_NAMESPACE::kTypeRangeDeletion:
100         state.append("DeleteRange(");
101         state.append(ikey.user_key.ToString());
102         state.append(", ");
103         state.append(iter->value().ToString());
104         state.append(")");
105         count++;
106         break;
107       case ROCKSDB_NAMESPACE::kTypeLogData:
108         state.append("LogData(");
109         state.append(ikey.user_key.ToString());
110         state.append(")");
111         count++;
112         break;
113       default:
114         assert(false);
115         state.append("Err:Expected(");
116         state.append(std::to_string(ikey.type));
117         state.append(")");
118         count++;
119         break;
120     }
121     state.append("@");
122     state.append(ROCKSDB_NAMESPACE::NumberToString(ikey.sequence));
123   }
124   if (!s.ok()) {
125     state.append(s.ToString());
126   } else if (ROCKSDB_NAMESPACE::WriteBatchInternal::Count(b) != count) {
127     state.append("Err:CountMismatch(expected=");
128     state.append(
129         std::to_string(ROCKSDB_NAMESPACE::WriteBatchInternal::Count(b)));
130     state.append(", actual=");
131     state.append(std::to_string(count));
132     state.append(")");
133   }
134   delete mem->Unref();
135 
136   jbyteArray jstate = env->NewByteArray(static_cast<jsize>(state.size()));
137   if (jstate == nullptr) {
138     // exception thrown: OutOfMemoryError
139     return nullptr;
140   }
141 
142   env->SetByteArrayRegion(
143       jstate, 0, static_cast<jsize>(state.size()),
144       const_cast<jbyte*>(reinterpret_cast<const jbyte*>(state.c_str())));
145   if (env->ExceptionCheck()) {
146     // exception thrown: ArrayIndexOutOfBoundsException
147     env->DeleteLocalRef(jstate);
148     return nullptr;
149   }
150 
151   return jstate;
152 }
153 
154 /*
155  * Class:     org_rocksdb_WriteBatchTestInternalHelper
156  * Method:    setSequence
157  * Signature: (JJ)V
158  */
Java_org_rocksdb_WriteBatchTestInternalHelper_setSequence(JNIEnv *,jclass,jlong jwb_handle,jlong jsn)159 void Java_org_rocksdb_WriteBatchTestInternalHelper_setSequence(
160     JNIEnv* /*env*/, jclass /*jclazz*/, jlong jwb_handle, jlong jsn) {
161   auto* wb = reinterpret_cast<ROCKSDB_NAMESPACE::WriteBatch*>(jwb_handle);
162   assert(wb != nullptr);
163 
164   ROCKSDB_NAMESPACE::WriteBatchInternal::SetSequence(
165       wb, static_cast<ROCKSDB_NAMESPACE::SequenceNumber>(jsn));
166 }
167 
168 /*
169  * Class:     org_rocksdb_WriteBatchTestInternalHelper
170  * Method:    sequence
171  * Signature: (J)J
172  */
Java_org_rocksdb_WriteBatchTestInternalHelper_sequence(JNIEnv *,jclass,jlong jwb_handle)173 jlong Java_org_rocksdb_WriteBatchTestInternalHelper_sequence(JNIEnv* /*env*/,
174                                                              jclass /*jclazz*/,
175                                                              jlong jwb_handle) {
176   auto* wb = reinterpret_cast<ROCKSDB_NAMESPACE::WriteBatch*>(jwb_handle);
177   assert(wb != nullptr);
178 
179   return static_cast<jlong>(
180       ROCKSDB_NAMESPACE::WriteBatchInternal::Sequence(wb));
181 }
182 
183 /*
184  * Class:     org_rocksdb_WriteBatchTestInternalHelper
185  * Method:    append
186  * Signature: (JJ)V
187  */
Java_org_rocksdb_WriteBatchTestInternalHelper_append(JNIEnv *,jclass,jlong jwb_handle_1,jlong jwb_handle_2)188 void Java_org_rocksdb_WriteBatchTestInternalHelper_append(JNIEnv* /*env*/,
189                                                           jclass /*jclazz*/,
190                                                           jlong jwb_handle_1,
191                                                           jlong jwb_handle_2) {
192   auto* wb1 = reinterpret_cast<ROCKSDB_NAMESPACE::WriteBatch*>(jwb_handle_1);
193   assert(wb1 != nullptr);
194   auto* wb2 = reinterpret_cast<ROCKSDB_NAMESPACE::WriteBatch*>(jwb_handle_2);
195   assert(wb2 != nullptr);
196 
197   ROCKSDB_NAMESPACE::WriteBatchInternal::Append(wb1, wb2);
198 }
199