portal.h 28.8 KB
Newer Older
1
// Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2 3 4 5 6 7 8 9 10 11 12 13
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.

// This file is designed for caching those frequently used IDs and provide
// efficient portal (i.e, a set of static functions) to access java code
// from c++.

#ifndef JAVA_ROCKSJNI_PORTAL_H_
#define JAVA_ROCKSJNI_PORTAL_H_

#include <jni.h>
14
#include <functional>
15
#include <limits>
16
#include <string>
17
#include <vector>
18

19
#include "rocksdb/db.h"
A
Ankit Gupta 已提交
20
#include "rocksdb/filter_policy.h"
21
#include "rocksdb/status.h"
22
#include "rocksdb/utilities/backupable_db.h"
23
#include "rocksdb/utilities/write_batch_with_index.h"
24
#include "rocksjni/comparatorjnicallback.h"
F
fyrz 已提交
25
#include "rocksjni/loggerjnicallback.h"
A
Adam Retter 已提交
26
#include "rocksjni/writebatchhandlerjnicallback.h"
27

28 29 30 31 32
// Remove macro on windows
#ifdef DELETE
#undef DELETE
#endif

33 34
namespace rocksdb {

F
fyrz 已提交
35
// Detect if jlong overflows size_t
36 37 38 39 40 41
inline Status check_if_jlong_fits_size_t(const jlong& jvalue) {
  Status s = Status::OK();
  if (static_cast<uint64_t>(jvalue) > std::numeric_limits<size_t>::max()) {
    s = Status::InvalidArgument(Slice("jlong overflows 32 bit value."));
  }
  return s;
42 43
}

F
fyrz 已提交
44 45
// Native class template
template<class PTR, class DERIVED> class RocksDBNativeClass {
46
 public:
F
fyrz 已提交
47 48 49
  // Get the java class id
  static jclass getJClass(JNIEnv* env, const char* jclazz_name) {
    jclass jclazz = env->FindClass(jclazz_name);
50 51 52
    assert(jclazz != nullptr);
    return jclazz;
  }
53
};
54

55
// Native class template for sub-classes of RocksMutableObject
56 57
template<class PTR, class DERIVED> class NativeRocksMutableObject
    : public RocksDBNativeClass<PTR, DERIVED> {
58
 public:
59 60 61 62 63 64 65 66

  static jmethodID getSetNativeHandleMethod(JNIEnv* env) {
    static jmethodID mid = env->GetMethodID(
        DERIVED::getJClass(env), "setNativeHandle", "(JZ)V");
    assert(mid != nullptr);
    return mid;
  }

F
fyrz 已提交
67
  // Pass the pointer to the java side.
68 69 70 71
  static void setHandle(JNIEnv* env, jobject jobj, PTR ptr,
      jboolean java_owns_handle) {
    env->CallVoidMethod(jobj, getSetNativeHandleMethod(env),
      reinterpret_cast<jlong>(ptr), java_owns_handle);
F
fyrz 已提交
72 73 74
  }
};

F
fyrz 已提交
75 76
// Java Exception template
template<class DERIVED> class RocksDBJavaException {
77
 public:
F
fyrz 已提交
78 79 80
  // Get the java class id
  static jclass getJClass(JNIEnv* env, const char* jclazz_name) {
    jclass jclazz = env->FindClass(jclazz_name);
81 82 83 84
    assert(jclazz != nullptr);
    return jclazz;
  }

85 86 87
  // Create and throw a java exception with the provided message
  static void ThrowNew(JNIEnv* env, const std::string& msg) {
    jstring jmsg = env->NewStringUTF(msg.c_str());
88
    // get the constructor id of org.rocksdb.RocksDBException
89
    static jmethodID mid = env->GetMethodID(
F
fyrz 已提交
90
        DERIVED::getJClass(env), "<init>", "(Ljava/lang/String;)V");
91 92
    assert(mid != nullptr);

93
    env->Throw((jthrowable)env->NewObject(DERIVED::getJClass(env), mid, jmsg));
94 95 96
  }
};

F
fyrz 已提交
97 98 99 100 101 102 103 104 105
// The portal class for org.rocksdb.RocksDB
class RocksDBJni : public RocksDBNativeClass<rocksdb::DB*, RocksDBJni> {
 public:
  // Get the java class id of org.rocksdb.RocksDB.
  static jclass getJClass(JNIEnv* env) {
    return RocksDBNativeClass::getJClass(env, "org/rocksdb/RocksDB");
  }
};

106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
// The portal class for org.rocksdb.Status
class StatusJni : public RocksDBNativeClass<rocksdb::Status*, StatusJni> {
 public:
  // Get the java class id of org.rocksdb.Status.
  static jclass getJClass(JNIEnv* env) {
    return RocksDBNativeClass::getJClass(env, "org/rocksdb/Status");
  }

  // Create a new org.rocksdb.Status with the same properties as the
  // provided C++ rocksdb::Status object
  static jobject construct(JNIEnv* env, const Status& status) {
    static jmethodID mid =
        env->GetMethodID(getJClass(env), "<init>", "(BBLjava/lang/String;)V");
    assert(mid != nullptr);

    jstring jstate = nullptr;
    if (status.getState() != nullptr) {
      std::string s(status.getState());
      jstate = env->NewStringUTF(s.c_str());
    }
    return env->NewObject(getJClass(env), mid, toJavaStatusCode(status.code()),
                          toJavaStatusSubCode(status.subcode()), jstate);
  }

  // Returns the equivalent org.rocksdb.Status.Code for the provided
  // C++ rocksdb::Status::Code enum
  static jbyte toJavaStatusCode(const rocksdb::Status::Code& code) {
    switch (code) {
      case rocksdb::Status::Code::kOk:
        return 0x0;
      case rocksdb::Status::Code::kNotFound:
        return 0x1;
      case rocksdb::Status::Code::kCorruption:
        return 0x2;
      case rocksdb::Status::Code::kNotSupported:
        return 0x3;
      case rocksdb::Status::Code::kInvalidArgument:
        return 0x4;
      case rocksdb::Status::Code::kIOError:
        return 0x5;
      case rocksdb::Status::Code::kMergeInProgress:
        return 0x6;
      case rocksdb::Status::Code::kIncomplete:
        return 0x7;
      case rocksdb::Status::Code::kShutdownInProgress:
        return 0x8;
      case rocksdb::Status::Code::kTimedOut:
        return 0x9;
      case rocksdb::Status::Code::kAborted:
        return 0xA;
      case rocksdb::Status::Code::kBusy:
        return 0xB;
      case rocksdb::Status::Code::kExpired:
        return 0xC;
      case rocksdb::Status::Code::kTryAgain:
        return 0xD;
      default:
A
Adam Retter 已提交
163
        return 0x7F;  // undefined
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
    }
  }

  // Returns the equivalent org.rocksdb.Status.SubCode for the provided
  // C++ rocksdb::Status::SubCode enum
  static jbyte toJavaStatusSubCode(const rocksdb::Status::SubCode& subCode) {
    switch (subCode) {
      case rocksdb::Status::SubCode::kNone:
        return 0x0;
      case rocksdb::Status::SubCode::kMutexTimeout:
        return 0x1;
      case rocksdb::Status::SubCode::kLockTimeout:
        return 0x2;
      case rocksdb::Status::SubCode::kLockLimit:
        return 0x3;
      case rocksdb::Status::SubCode::kMaxSubCode:
A
Adam Retter 已提交
180
        return 0x7E;
181
      default:
A
Adam Retter 已提交
182
        return 0x7F;  // undefined
183 184 185 186
    }
  }
};

F
fyrz 已提交
187 188 189 190 191 192 193 194 195
// The portal class for org.rocksdb.RocksDBException
class RocksDBExceptionJni :
    public RocksDBJavaException<RocksDBExceptionJni> {
 public:
  // Get the java class id of java.lang.IllegalArgumentException
  static jclass getJClass(JNIEnv* env) {
    return RocksDBJavaException::getJClass(env,
        "org/rocksdb/RocksDBException");
  }
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230

  static void ThrowNew(JNIEnv* env, const std::string& msg) {
    RocksDBJavaException::ThrowNew(env, msg);
  }

  static void ThrowNew(JNIEnv* env, const Status& s) {
    if (s.ok()) {
      return;
    }

    jobject jstatus = StatusJni::construct(env, s);

    // get the constructor id of org.rocksdb.RocksDBException
    static jmethodID mid =
        env->GetMethodID(getJClass(env), "<init>", "(Lorg/rocksdb/Status;)V");
    assert(mid != nullptr);

    env->Throw((jthrowable)env->NewObject(getJClass(env), mid, jstatus));
  }

  static void ThrowNew(JNIEnv* env, const std::string& msg, const Status& s) {
    if (s.ok()) {
      return;
    }

    jstring jmsg = env->NewStringUTF(msg.c_str());
    jobject jstatus = StatusJni::construct(env, s);

    // get the constructor id of org.rocksdb.RocksDBException
    static jmethodID mid = env->GetMethodID(
        getJClass(env), "<init>", "(Ljava/lang/String;Lorg/rocksdb/Status;)V");
    assert(mid != nullptr);

    env->Throw((jthrowable)env->NewObject(getJClass(env), mid, jmsg, jstatus));
  }
F
fyrz 已提交
231 232 233 234 235 236 237 238 239 240 241
};

// The portal class for java.lang.IllegalArgumentException
class IllegalArgumentExceptionJni :
    public RocksDBJavaException<IllegalArgumentExceptionJni> {
 public:
  // Get the java class id of java.lang.IllegalArgumentException
  static jclass getJClass(JNIEnv* env) {
    return RocksDBJavaException::getJClass(env,
        "java/lang/IllegalArgumentException");
  }
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259

  // Create and throw a IllegalArgumentException by converting the input
  // Status.
  //
  // In case s.ok() is true, then this function will not throw any
  // exception.
  static void ThrowNew(JNIEnv* env, const Status& s) {
    if (s.ok()) {
      return;
    }
    jstring msg = env->NewStringUTF(s.ToString().c_str());
    // get the constructor id of org.rocksdb.RocksDBException
    static jmethodID mid =
        env->GetMethodID(getJClass(env), "<init>", "(Ljava/lang/String;)V");
    assert(mid != nullptr);

    env->Throw((jthrowable)env->NewObject(getJClass(env), mid, msg));
  }
F
fyrz 已提交
260 261 262
};


F
fyrz 已提交
263
// The portal class for org.rocksdb.Options
264 265
class OptionsJni : public RocksDBNativeClass<
    rocksdb::Options*, OptionsJni> {
266 267
 public:
  static jclass getJClass(JNIEnv* env) {
F
fyrz 已提交
268
    return RocksDBNativeClass::getJClass(env, "org/rocksdb/Options");
269 270 271
  }
};

F
fyrz 已提交
272
// The portal class for org.rocksdb.DBOptions
273 274
class DBOptionsJni : public RocksDBNativeClass<
    rocksdb::DBOptions*, DBOptionsJni> {
275 276
 public:
  static jclass getJClass(JNIEnv* env) {
F
fyrz 已提交
277
    return RocksDBNativeClass::getJClass(env, "org/rocksdb/DBOptions");
278 279 280
  }
};

281 282 283 284 285 286 287 288 289 290 291 292 293
class ColumnFamilyDescriptorJni {
 public:
  // Get the java class id of org.rocksdb.ColumnFamilyDescriptor
  static jclass getColumnFamilyDescriptorClass(JNIEnv* env) {
    jclass jclazz = env->FindClass("org/rocksdb/ColumnFamilyDescriptor");
    assert(jclazz != nullptr);
    return jclazz;
  }

  // Get the java method id of columnFamilyName
  static jmethodID getColumnFamilyNameMethod(JNIEnv* env) {
    static jmethodID mid = env->GetMethodID(
        getColumnFamilyDescriptorClass(env),
294
        "columnFamilyName", "()[B");
295 296 297 298 299 300 301 302 303 304 305 306 307 308
    assert(mid != nullptr);
    return mid;
  }

  // Get the java method id of columnFamilyOptions
  static jmethodID getColumnFamilyOptionsMethod(JNIEnv* env) {
    static jmethodID mid = env->GetMethodID(
        getColumnFamilyDescriptorClass(env),
        "columnFamilyOptions", "()Lorg/rocksdb/ColumnFamilyOptions;");
    assert(mid != nullptr);
    return mid;
  }
};

F
fyrz 已提交
309 310 311
// The portal class for org.rocksdb.ColumnFamilyOptions
class ColumnFamilyOptionsJni : public RocksDBNativeClass<
    rocksdb::ColumnFamilyOptions*, ColumnFamilyOptionsJni> {
312 313
 public:
  static jclass getJClass(JNIEnv* env) {
F
fyrz 已提交
314 315
    return RocksDBNativeClass::getJClass(env,
        "org/rocksdb/ColumnFamilyOptions");
316 317 318
  }
};

F
fyrz 已提交
319 320 321
// The portal class for org.rocksdb.WriteOptions
class WriteOptionsJni : public RocksDBNativeClass<
    rocksdb::WriteOptions*, WriteOptionsJni> {
322 323
 public:
  static jclass getJClass(JNIEnv* env) {
F
fyrz 已提交
324 325
    return RocksDBNativeClass::getJClass(env,
        "org/rocksdb/WriteOptions");
326 327 328
  }
};

F
fyrz 已提交
329 330 331
// The portal class for org.rocksdb.ReadOptions
class ReadOptionsJni : public RocksDBNativeClass<
    rocksdb::ReadOptions*, ReadOptionsJni> {
332 333
 public:
  static jclass getJClass(JNIEnv* env) {
F
fyrz 已提交
334 335
    return RocksDBNativeClass::getJClass(env,
        "org/rocksdb/ReadOptions");
336 337 338
  }
};

F
fyrz 已提交
339 340 341
// The portal class for org.rocksdb.ReadOptions
class WriteBatchJni : public RocksDBNativeClass<
    rocksdb::WriteBatch*, WriteBatchJni> {
342 343
 public:
  static jclass getJClass(JNIEnv* env) {
F
fyrz 已提交
344 345
    return RocksDBNativeClass::getJClass(env,
        "org/rocksdb/WriteBatch");
346 347
  }
};
A
Ankit Gupta 已提交
348

F
fyrz 已提交
349 350 351 352
// The portal class for org.rocksdb.WriteBatch.Handler
class WriteBatchHandlerJni : public RocksDBNativeClass<
    const rocksdb::WriteBatchHandlerJniCallback*,
    WriteBatchHandlerJni> {
A
Adam Retter 已提交
353 354
 public:
  static jclass getJClass(JNIEnv* env) {
F
fyrz 已提交
355 356
    return RocksDBNativeClass::getJClass(env,
        "org/rocksdb/WriteBatch$Handler");
A
Adam Retter 已提交
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
  }

  // Get the java method `put` of org.rocksdb.WriteBatch.Handler.
  static jmethodID getPutMethodId(JNIEnv* env) {
    static jmethodID mid = env->GetMethodID(
        getJClass(env), "put", "([B[B)V");
    assert(mid != nullptr);
    return mid;
  }

  // Get the java method `merge` of org.rocksdb.WriteBatch.Handler.
  static jmethodID getMergeMethodId(JNIEnv* env) {
    static jmethodID mid = env->GetMethodID(
        getJClass(env), "merge", "([B[B)V");
    assert(mid != nullptr);
    return mid;
  }

  // Get the java method `delete` of org.rocksdb.WriteBatch.Handler.
  static jmethodID getDeleteMethodId(JNIEnv* env) {
    static jmethodID mid = env->GetMethodID(
        getJClass(env), "delete", "([B)V");
    assert(mid != nullptr);
    return mid;
  }

  // Get the java method `logData` of org.rocksdb.WriteBatch.Handler.
  static jmethodID getLogDataMethodId(JNIEnv* env) {
    static jmethodID mid = env->GetMethodID(
        getJClass(env), "logData", "([B)V");
    assert(mid != nullptr);
    return mid;
  }

  // Get the java method `shouldContinue` of org.rocksdb.WriteBatch.Handler.
  static jmethodID getContinueMethodId(JNIEnv* env) {
    static jmethodID mid = env->GetMethodID(
        getJClass(env), "shouldContinue", "()Z");
    assert(mid != nullptr);
    return mid;
  }
};

F
fyrz 已提交
400 401 402
// The portal class for org.rocksdb.WriteBatchWithIndex
class WriteBatchWithIndexJni : public RocksDBNativeClass<
    rocksdb::WriteBatchWithIndex*, WriteBatchWithIndexJni> {
403 404
 public:
  static jclass getJClass(JNIEnv* env) {
F
fyrz 已提交
405 406
    return RocksDBNativeClass::getJClass(env,
        "org/rocksdb/WriteBatch");
407 408 409
  }
};

A
Ankit Gupta 已提交
410 411 412
class HistogramDataJni {
 public:
  static jmethodID getConstructorMethodId(JNIEnv* env, jclass jclazz) {
413
    static jmethodID mid = env->GetMethodID(jclazz, "<init>", "(DDDDD)V");
A
Ankit Gupta 已提交
414 415
    assert(mid != nullptr);
    return mid;
A
Ankit Gupta 已提交
416 417
  }
};
A
Ankit Gupta 已提交
418

F
fyrz 已提交
419 420 421
// The portal class for org.rocksdb.WriteBatchWithIndex
class BackupableDBOptionsJni : public RocksDBNativeClass<
    rocksdb::BackupableDBOptions*, BackupableDBOptionsJni> {
422 423
 public:
  static jclass getJClass(JNIEnv* env) {
F
fyrz 已提交
424 425
    return RocksDBNativeClass::getJClass(env,
        "org/rocksdb/BackupableDBOptions");
A
Ankit Gupta 已提交
426 427
  }
};
A
Ankit Gupta 已提交
428

429 430 431 432 433 434 435 436 437
class BackupEngineJni : public RocksDBNativeClass<
    rocksdb::BackupEngine*, BackupEngineJni> {
 public:
  static jclass getJClass(JNIEnv* env) {
    return RocksDBNativeClass::getJClass(env,
        "org/rocksdb/BackupEngine");
  }
};

F
fyrz 已提交
438 439 440
// The portal class for org.rocksdb.RocksIterator
class IteratorJni : public RocksDBNativeClass<
    rocksdb::Iterator*, IteratorJni> {
A
Ankit Gupta 已提交
441 442
 public:
  static jclass getJClass(JNIEnv* env) {
F
fyrz 已提交
443 444
    return RocksDBNativeClass::getJClass(env,
        "org/rocksdb/RocksIterator");
A
Ankit Gupta 已提交
445 446
  }
};
A
Ankit Gupta 已提交
447

F
fyrz 已提交
448 449 450
// The portal class for org.rocksdb.Filter
class FilterJni : public RocksDBNativeClass<
    std::shared_ptr<rocksdb::FilterPolicy>*, FilterJni> {
A
Ankit Gupta 已提交
451 452
 public:
  static jclass getJClass(JNIEnv* env) {
F
fyrz 已提交
453 454
    return RocksDBNativeClass::getJClass(env,
        "org/rocksdb/Filter");
F
fyrz 已提交
455 456 457
  }
};

F
fyrz 已提交
458 459 460
// The portal class for org.rocksdb.ColumnFamilyHandle
class ColumnFamilyHandleJni : public RocksDBNativeClass<
    rocksdb::ColumnFamilyHandle*, ColumnFamilyHandleJni> {
F
fyrz 已提交
461 462
 public:
  static jclass getJClass(JNIEnv* env) {
F
fyrz 已提交
463 464
    return RocksDBNativeClass::getJClass(env,
        "org/rocksdb/ColumnFamilyHandle");
A
Ankit Gupta 已提交
465 466
  }
};
A
Ankit Gupta 已提交
467

F
fyrz 已提交
468 469 470
// The portal class for org.rocksdb.FlushOptions
class FlushOptionsJni : public RocksDBNativeClass<
    rocksdb::FlushOptions*, FlushOptionsJni> {
F
fyrz 已提交
471
 public:
F
fyrz 已提交
472 473 474 475
  static jclass getJClass(JNIEnv* env) {
    return RocksDBNativeClass::getJClass(env,
        "org/rocksdb/FlushOptions");
  }
F
fyrz 已提交
476 477
};

F
fyrz 已提交
478 479 480
// The portal class for org.rocksdb.ComparatorOptions
class ComparatorOptionsJni : public RocksDBNativeClass<
    rocksdb::ComparatorJniCallbackOptions*, ComparatorOptionsJni> {
481
 public:
F
fyrz 已提交
482 483 484 485
  static jclass getJClass(JNIEnv* env) {
    return RocksDBNativeClass::getJClass(env,
        "org/rocksdb/ComparatorOptions");
  }
486 487
};

F
fyrz 已提交
488 489 490 491
// The portal class for org.rocksdb.AbstractComparator
class AbstractComparatorJni : public RocksDBNativeClass<
    const rocksdb::BaseComparatorJniCallback*,
    AbstractComparatorJni> {
492 493
 public:
  static jclass getJClass(JNIEnv* env) {
F
fyrz 已提交
494 495
    return RocksDBNativeClass::getJClass(env,
        "org/rocksdb/AbstractComparator");
496 497 498 499 500 501 502 503 504 505 506 507
  }

  // Get the java method `name` of org.rocksdb.Comparator.
  static jmethodID getNameMethodId(JNIEnv* env) {
    static jmethodID mid = env->GetMethodID(
        getJClass(env), "name", "()Ljava/lang/String;");
    assert(mid != nullptr);
    return mid;
  }

  // Get the java method `compare` of org.rocksdb.Comparator.
  static jmethodID getCompareMethodId(JNIEnv* env) {
508 509 510
    static jmethodID mid = env->GetMethodID(getJClass(env),
      "compare",
      "(Lorg/rocksdb/AbstractSlice;Lorg/rocksdb/AbstractSlice;)I");
511 512 513 514 515 516
    assert(mid != nullptr);
    return mid;
  }

  // Get the java method `findShortestSeparator` of org.rocksdb.Comparator.
  static jmethodID getFindShortestSeparatorMethodId(JNIEnv* env) {
517 518 519
    static jmethodID mid = env->GetMethodID(getJClass(env),
      "findShortestSeparator",
      "(Ljava/lang/String;Lorg/rocksdb/AbstractSlice;)Ljava/lang/String;");
520 521 522 523 524 525
    assert(mid != nullptr);
    return mid;
  }

  // Get the java method `findShortSuccessor` of org.rocksdb.Comparator.
  static jmethodID getFindShortSuccessorMethodId(JNIEnv* env) {
526 527 528
    static jmethodID mid = env->GetMethodID(getJClass(env),
      "findShortSuccessor",
      "(Ljava/lang/String;)Ljava/lang/String;");
529 530 531 532 533
    assert(mid != nullptr);
    return mid;
  }
};

F
fyrz 已提交
534
// The portal class for org.rocksdb.AbstractSlice
535
class AbstractSliceJni : public NativeRocksMutableObject<
F
fyrz 已提交
536
    const rocksdb::Slice*, AbstractSliceJni> {
537 538
 public:
  static jclass getJClass(JNIEnv* env) {
F
fyrz 已提交
539 540
    return RocksDBNativeClass::getJClass(env,
        "org/rocksdb/AbstractSlice");
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
  }
};

class SliceJni {
 public:
  // Get the java class id of org.rocksdb.Slice.
  static jclass getJClass(JNIEnv* env) {
    jclass jclazz = env->FindClass("org/rocksdb/Slice");
    assert(jclazz != nullptr);
    return jclazz;
  }

  static jobject construct0(JNIEnv* env) {
    static jmethodID mid = env->GetMethodID(getJClass(env), "<init>", "()V");
    assert(mid != nullptr);
    return env->NewObject(getJClass(env), mid);
  }
};

class DirectSliceJni {
 public:
  // Get the java class id of org.rocksdb.DirectSlice.
  static jclass getJClass(JNIEnv* env) {
    jclass jclazz = env->FindClass("org/rocksdb/DirectSlice");
    assert(jclazz != nullptr);
    return jclazz;
  }

  static jobject construct0(JNIEnv* env) {
    static jmethodID mid = env->GetMethodID(getJClass(env), "<init>", "()V");
    assert(mid != nullptr);
    return env->NewObject(getJClass(env), mid);
  }
};

A
Ankit Gupta 已提交
576 577 578 579
class ListJni {
 public:
  // Get the java class id of java.util.List.
  static jclass getListClass(JNIEnv* env) {
580
    jclass jclazz = env->FindClass("java/util/List");
A
Ankit Gupta 已提交
581 582 583
    assert(jclazz != nullptr);
    return jclazz;
  }
A
Ankit Gupta 已提交
584

A
Ankit Gupta 已提交
585 586
  // Get the java class id of java.util.ArrayList.
  static jclass getArrayListClass(JNIEnv* env) {
587
    jclass jclazz = env->FindClass("java/util/ArrayList");
A
Ankit Gupta 已提交
588 589 590 591 592 593
    assert(jclazz != nullptr);
    return jclazz;
  }

  // Get the java class id of java.util.Iterator.
  static jclass getIteratorClass(JNIEnv* env) {
594
    jclass jclazz = env->FindClass("java/util/Iterator");
A
Ankit Gupta 已提交
595 596 597
    assert(jclazz != nullptr);
    return jclazz;
  }
A
Ankit Gupta 已提交
598

A
Ankit Gupta 已提交
599 600
  // Get the java method id of java.util.List.iterator().
  static jmethodID getIteratorMethod(JNIEnv* env) {
601
    static jmethodID mid = env->GetMethodID(
A
Ankit Gupta 已提交
602 603 604 605
        getListClass(env), "iterator", "()Ljava/util/Iterator;");
    assert(mid != nullptr);
    return mid;
  }
A
Ankit Gupta 已提交
606

A
Ankit Gupta 已提交
607 608
  // Get the java method id of java.util.Iterator.hasNext().
  static jmethodID getHasNextMethod(JNIEnv* env) {
609
    static jmethodID mid = env->GetMethodID(
A
Ankit Gupta 已提交
610 611 612 613
        getIteratorClass(env), "hasNext", "()Z");
    assert(mid != nullptr);
    return mid;
  }
A
Ankit Gupta 已提交
614

A
Ankit Gupta 已提交
615 616
  // Get the java method id of java.util.Iterator.next().
  static jmethodID getNextMethod(JNIEnv* env) {
617
    static jmethodID mid = env->GetMethodID(
A
Ankit Gupta 已提交
618 619 620 621
        getIteratorClass(env), "next", "()Ljava/lang/Object;");
    assert(mid != nullptr);
    return mid;
  }
A
Ankit Gupta 已提交
622

A
Ankit Gupta 已提交
623 624
  // Get the java method id of arrayList constructor.
  static jmethodID getArrayListConstructorMethodId(JNIEnv* env, jclass jclazz) {
625
    static jmethodID mid = env->GetMethodID(
A
Ankit Gupta 已提交
626 627 628 629
        jclazz, "<init>", "(I)V");
    assert(mid != nullptr);
    return mid;
  }
A
Ankit Gupta 已提交
630

A
Ankit Gupta 已提交
631 632
  // Get the java method id of java.util.List.add().
  static jmethodID getListAddMethodId(JNIEnv* env) {
633
    static jmethodID mid = env->GetMethodID(
A
Ankit Gupta 已提交
634 635 636 637 638
        getListClass(env), "add", "(Ljava/lang/Object;)Z");
    assert(mid != nullptr);
    return mid;
  }
};
639

640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657
class ByteJni {
 public:
  // Get the java class id of java.lang.Byte.
  static jclass getByteClass(JNIEnv* env) {
    jclass jclazz = env->FindClass("java/lang/Byte");
    assert(jclazz != nullptr);
    return jclazz;
  }

  // Get the java method id of java.lang.Byte.byteValue.
  static jmethodID getByteValueMethod(JNIEnv* env) {
    static jmethodID mid = env->GetMethodID(
        getByteClass(env), "byteValue", "()B");
    assert(mid != nullptr);
    return mid;
  }
};

658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701
class BackupInfoJni {
 public:
  // Get the java class id of org.rocksdb.BackupInfo.
  static jclass getJClass(JNIEnv* env) {
    jclass jclazz = env->FindClass("org/rocksdb/BackupInfo");
    assert(jclazz != nullptr);
    return jclazz;
  }

  static jobject construct0(JNIEnv* env, uint32_t backup_id, int64_t timestamp,
      uint64_t size, uint32_t number_files) {
    static jmethodID mid = env->GetMethodID(getJClass(env), "<init>",
        "(IJJI)V");
    assert(mid != nullptr);
    return env->NewObject(getJClass(env), mid,
        backup_id, timestamp, size, number_files);
  }
};

class BackupInfoListJni {
 public:
  static jobject getBackupInfo(JNIEnv* env,
      std::vector<BackupInfo> backup_infos) {
    jclass jclazz = env->FindClass("java/util/ArrayList");
    jmethodID mid = rocksdb::ListJni::getArrayListConstructorMethodId(
        env, jclazz);
    jobject jbackup_info_handle_list = env->NewObject(jclazz, mid,
        backup_infos.size());
    // insert in java list
    for (std::vector<rocksdb::BackupInfo>::size_type i = 0;
        i != backup_infos.size(); i++) {
      rocksdb::BackupInfo backup_info = backup_infos[i];
      jobject obj = rocksdb::BackupInfoJni::construct0(env,
          backup_info.backup_id,
          backup_info.timestamp,
          backup_info.size,
          backup_info.number_files);
      env->CallBooleanMethod(jbackup_info_handle_list,
          rocksdb::ListJni::getListAddMethodId(env), obj);
    }
    return jbackup_info_handle_list;
  }
};

702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778
class WBWIRocksIteratorJni {
 public:
    // Get the java class id of org.rocksdb.WBWIRocksIterator.
    static jclass getJClass(JNIEnv* env) {
      static jclass jclazz = env->FindClass("org/rocksdb/WBWIRocksIterator");
      assert(jclazz != nullptr);
      return jclazz;
    }

    static jfieldID getWriteEntryField(JNIEnv* env) {
      static jfieldID fid =
          env->GetFieldID(getJClass(env), "entry",
          "Lorg/rocksdb/WBWIRocksIterator$WriteEntry;");
      assert(fid != nullptr);
      return fid;
    }

    static jobject getWriteEntry(JNIEnv* env, jobject jwbwi_rocks_iterator) {
      jobject jwe =
          env->GetObjectField(jwbwi_rocks_iterator, getWriteEntryField(env));
      assert(jwe != nullptr);
      return jwe;
    }
};

class WriteTypeJni {
 public:
    // Get the PUT enum field of org.rocksdb.WBWIRocksIterator.WriteType
    static jobject PUT(JNIEnv* env) {
      return getEnum(env, "PUT");
    }

    // Get the MERGE enum field of org.rocksdb.WBWIRocksIterator.WriteType
    static jobject MERGE(JNIEnv* env) {
      return getEnum(env, "MERGE");
    }

    // Get the DELETE enum field of org.rocksdb.WBWIRocksIterator.WriteType
    static jobject DELETE(JNIEnv* env) {
      return getEnum(env, "DELETE");
    }

    // Get the LOG enum field of org.rocksdb.WBWIRocksIterator.WriteType
    static jobject LOG(JNIEnv* env) {
      return getEnum(env, "LOG");
    }

 private:
    // Get the java class id of org.rocksdb.WBWIRocksIterator.WriteType.
    static jclass getJClass(JNIEnv* env) {
      jclass jclazz = env->FindClass("org/rocksdb/WBWIRocksIterator$WriteType");
      assert(jclazz != nullptr);
      return jclazz;
    }

    // Get an enum field of org.rocksdb.WBWIRocksIterator.WriteType
    static jobject getEnum(JNIEnv* env, const char name[]) {
      jclass jclazz = getJClass(env);
      jfieldID jfid =
          env->GetStaticFieldID(jclazz, name,
          "Lorg/rocksdb/WBWIRocksIterator$WriteType;");
      assert(jfid != nullptr);
      return env->GetStaticObjectField(jclazz, jfid);
    }
};

class WriteEntryJni {
 public:
    // Get the java class id of org.rocksdb.WBWIRocksIterator.WriteEntry.
    static jclass getJClass(JNIEnv* env) {
      static jclass jclazz =
          env->FindClass("org/rocksdb/WBWIRocksIterator$WriteEntry");
      assert(jclazz != nullptr);
      return jclazz;
    }
};

F
fyrz 已提交
779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805
class InfoLogLevelJni {
 public:
    // Get the DEBUG_LEVEL enum field of org.rocksdb.InfoLogLevel
    static jobject DEBUG_LEVEL(JNIEnv* env) {
      return getEnum(env, "DEBUG_LEVEL");
    }

    // Get the INFO_LEVEL enum field of org.rocksdb.InfoLogLevel
    static jobject INFO_LEVEL(JNIEnv* env) {
      return getEnum(env, "INFO_LEVEL");
    }

    // Get the WARN_LEVEL enum field of org.rocksdb.InfoLogLevel
    static jobject WARN_LEVEL(JNIEnv* env) {
      return getEnum(env, "WARN_LEVEL");
    }

    // Get the ERROR_LEVEL enum field of org.rocksdb.InfoLogLevel
    static jobject ERROR_LEVEL(JNIEnv* env) {
      return getEnum(env, "ERROR_LEVEL");
    }

    // Get the FATAL_LEVEL enum field of org.rocksdb.InfoLogLevel
    static jobject FATAL_LEVEL(JNIEnv* env) {
      return getEnum(env, "FATAL_LEVEL");
    }

806 807 808 809 810
    // Get the HEADER_LEVEL enum field of org.rocksdb.InfoLogLevel
    static jobject HEADER_LEVEL(JNIEnv* env) {
      return getEnum(env, "HEADER_LEVEL");
    }

F
fyrz 已提交
811
 private:
812
    // Get the java class id of org.rocksdb.InfoLogLevel
F
fyrz 已提交
813 814 815 816 817 818
    static jclass getJClass(JNIEnv* env) {
      jclass jclazz = env->FindClass("org/rocksdb/InfoLogLevel");
      assert(jclazz != nullptr);
      return jclazz;
    }

819
    // Get an enum field of org.rocksdb.InfoLogLevel
F
fyrz 已提交
820 821 822 823 824 825 826 827 828 829
    static jobject getEnum(JNIEnv* env, const char name[]) {
      jclass jclazz = getJClass(env);
      jfieldID jfid =
          env->GetStaticFieldID(jclazz, name,
          "Lorg/rocksdb/InfoLogLevel;");
      assert(jfid != nullptr);
      return env->GetStaticObjectField(jclazz, jfid);
    }
};

F
fyrz 已提交
830 831 832
// The portal class for org.rocksdb.Logger
class LoggerJni : public RocksDBNativeClass<
    std::shared_ptr<rocksdb::LoggerJniCallback>*, LoggerJni> {
F
fyrz 已提交
833 834 835
 public:
  static jclass getJClass(JNIEnv* env) {
    return RocksDBNativeClass::getJClass(env,
F
fyrz 已提交
836
        "org/rocksdb/Logger");
F
fyrz 已提交
837 838
  }

F
fyrz 已提交
839
  // Get the java method `name` of org.rocksdb.Logger.
F
fyrz 已提交
840 841 842 843 844 845 846 847 848
  static jmethodID getLogMethodId(JNIEnv* env) {
    static jmethodID mid = env->GetMethodID(
        getJClass(env), "log",
        "(Lorg/rocksdb/InfoLogLevel;Ljava/lang/String;)V");
    assert(mid != nullptr);
    return mid;
  }
};

849
class JniUtil {
850
 public:
851
    /*
852 853 854 855 856 857 858 859 860
     * Copies a jstring to a std::string
     * and releases the original jstring
     */
    static std::string copyString(JNIEnv* env, jstring js) {
      const char *utf = env->GetStringUTFChars(js, NULL);
      std::string name(utf);
      env->ReleaseStringUTFChars(js, utf);
      return name;
    }
861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903

    /*
     * Helper for operations on a key and value
     * for example WriteBatch->Put
     *
     * TODO(AR) could be extended to cover returning rocksdb::Status
     * from `op` and used for RocksDB->Put etc.
     */
    static void kv_op(
        std::function<void(rocksdb::Slice, rocksdb::Slice)> op,
        JNIEnv* env, jobject jobj,
        jbyteArray jkey, jint jkey_len,
        jbyteArray jentry_value, jint jentry_value_len) {
      jbyte* key = env->GetByteArrayElements(jkey, nullptr);
      jbyte* value = env->GetByteArrayElements(jentry_value, nullptr);
      rocksdb::Slice key_slice(reinterpret_cast<char*>(key), jkey_len);
      rocksdb::Slice value_slice(reinterpret_cast<char*>(value),
          jentry_value_len);

      op(key_slice, value_slice);

      env->ReleaseByteArrayElements(jkey, key, JNI_ABORT);
      env->ReleaseByteArrayElements(jentry_value, value, JNI_ABORT);
    }

    /*
     * Helper for operations on a key
     * for example WriteBatch->Delete
     *
     * TODO(AR) could be extended to cover returning rocksdb::Status
     * from `op` and used for RocksDB->Delete etc.
     */
    static void k_op(
        std::function<void(rocksdb::Slice)> op,
        JNIEnv* env, jobject jobj,
        jbyteArray jkey, jint jkey_len) {
      jbyte* key = env->GetByteArrayElements(jkey, nullptr);
      rocksdb::Slice key_slice(reinterpret_cast<char*>(key), jkey_len);

      op(key_slice);

      env->ReleaseByteArrayElements(jkey, key, JNI_ABORT);
    }
904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935

    /*
     * Helper for operations on a value
     * for example WriteBatchWithIndex->GetFromBatch
     */
    static jbyteArray v_op(
        std::function<rocksdb::Status(rocksdb::Slice, std::string*)> op,
        JNIEnv* env, jbyteArray jkey, jint jkey_len) {
      jboolean isCopy;
      jbyte* key = env->GetByteArrayElements(jkey, &isCopy);
      rocksdb::Slice key_slice(reinterpret_cast<char*>(key), jkey_len);

      std::string value;
      rocksdb::Status s = op(key_slice, &value);

      env->ReleaseByteArrayElements(jkey, key, JNI_ABORT);

      if (s.IsNotFound()) {
        return nullptr;
      }

      if (s.ok()) {
        jbyteArray jret_value =
            env->NewByteArray(static_cast<jsize>(value.size()));
        env->SetByteArrayRegion(jret_value, 0, static_cast<jsize>(value.size()),
                                reinterpret_cast<const jbyte*>(value.c_str()));
        return jret_value;
      }
      rocksdb::RocksDBExceptionJni::ThrowNew(env, s);

      return nullptr;
    }
936 937
};

938 939
}  // namespace rocksdb
#endif  // JAVA_ROCKSJNI_PORTAL_H_