| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548 | // Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.//  This source code is licensed under both the GPLv2 (found in the//  COPYING file in the root directory) and Apache 2.0 License//  (found in the LICENSE.Apache file in the root directory).//// This file implements the callback "bridge" between Java and C++ for// ROCKSDB_NAMESPACE::Comparator.#include "rocksjni/writebatchhandlerjnicallback.h"#include "rocksjni/portal.h"namespace ROCKSDB_NAMESPACE {WriteBatchHandlerJniCallback::WriteBatchHandlerJniCallback(    JNIEnv* env, jobject jWriteBatchHandler)    : JniCallback(env, jWriteBatchHandler), m_env(env) {  m_jPutCfMethodId = WriteBatchHandlerJni::getPutCfMethodId(env);  if(m_jPutCfMethodId == nullptr) {    // exception thrown    return;  }  m_jPutMethodId = WriteBatchHandlerJni::getPutMethodId(env);  if(m_jPutMethodId == nullptr) {    // exception thrown    return;  }  m_jMergeCfMethodId = WriteBatchHandlerJni::getMergeCfMethodId(env);  if(m_jMergeCfMethodId == nullptr) {    // exception thrown    return;  }  m_jMergeMethodId = WriteBatchHandlerJni::getMergeMethodId(env);  if(m_jMergeMethodId == nullptr) {    // exception thrown    return;  }  m_jDeleteCfMethodId = WriteBatchHandlerJni::getDeleteCfMethodId(env);  if(m_jDeleteCfMethodId == nullptr) {    // exception thrown    return;  }  m_jDeleteMethodId = WriteBatchHandlerJni::getDeleteMethodId(env);  if(m_jDeleteMethodId == nullptr) {    // exception thrown    return;  }  m_jSingleDeleteCfMethodId =      WriteBatchHandlerJni::getSingleDeleteCfMethodId(env);  if(m_jSingleDeleteCfMethodId == nullptr) {    // exception thrown    return;  }  m_jSingleDeleteMethodId = WriteBatchHandlerJni::getSingleDeleteMethodId(env);  if(m_jSingleDeleteMethodId == nullptr) {    // exception thrown    return;  }  m_jDeleteRangeCfMethodId =      WriteBatchHandlerJni::getDeleteRangeCfMethodId(env);  if (m_jDeleteRangeCfMethodId == nullptr) {    // exception thrown    return;  }  m_jDeleteRangeMethodId = WriteBatchHandlerJni::getDeleteRangeMethodId(env);  if (m_jDeleteRangeMethodId == nullptr) {    // exception thrown    return;  }  m_jLogDataMethodId = WriteBatchHandlerJni::getLogDataMethodId(env);  if(m_jLogDataMethodId == nullptr) {    // exception thrown    return;  }  m_jPutBlobIndexCfMethodId =      WriteBatchHandlerJni::getPutBlobIndexCfMethodId(env);  if(m_jPutBlobIndexCfMethodId == nullptr) {    // exception thrown    return;  }  m_jMarkBeginPrepareMethodId =      WriteBatchHandlerJni::getMarkBeginPrepareMethodId(env);  if(m_jMarkBeginPrepareMethodId == nullptr) {    // exception thrown    return;  }  m_jMarkEndPrepareMethodId =      WriteBatchHandlerJni::getMarkEndPrepareMethodId(env);  if(m_jMarkEndPrepareMethodId == nullptr) {    // exception thrown    return;  }  m_jMarkNoopMethodId = WriteBatchHandlerJni::getMarkNoopMethodId(env);  if(m_jMarkNoopMethodId == nullptr) {    // exception thrown    return;  }      m_jMarkRollbackMethodId = WriteBatchHandlerJni::getMarkRollbackMethodId(env);  if(m_jMarkRollbackMethodId == nullptr) {    // exception thrown    return;  }  m_jMarkCommitMethodId = WriteBatchHandlerJni::getMarkCommitMethodId(env);  if(m_jMarkCommitMethodId == nullptr) {    // exception thrown    return;  }  m_jContinueMethodId = WriteBatchHandlerJni::getContinueMethodId(env);  if(m_jContinueMethodId == nullptr) {    // exception thrown    return;  }}ROCKSDB_NAMESPACE::Status WriteBatchHandlerJniCallback::PutCF(    uint32_t column_family_id, const Slice& key, const Slice& value) {  auto put = [this, column_family_id] (      jbyteArray j_key, jbyteArray j_value) {    m_env->CallVoidMethod(      m_jcallback_obj,      m_jPutCfMethodId,      static_cast<jint>(column_family_id),      j_key,      j_value);  };  auto status = WriteBatchHandlerJniCallback::kv_op(key, value, put);  if(status == nullptr) {    return ROCKSDB_NAMESPACE::Status::OK();  // TODO(AR) what to do if there is                                             // an Exception but we don't know                                             // the ROCKSDB_NAMESPACE::Status?  } else {    return ROCKSDB_NAMESPACE::Status(*status);  }}void WriteBatchHandlerJniCallback::Put(const Slice& key, const Slice& value) {  auto put = [this] (        jbyteArray j_key, jbyteArray j_value) {    m_env->CallVoidMethod(      m_jcallback_obj,      m_jPutMethodId,      j_key,      j_value);  };  WriteBatchHandlerJniCallback::kv_op(key, value, put);}ROCKSDB_NAMESPACE::Status WriteBatchHandlerJniCallback::MergeCF(    uint32_t column_family_id, const Slice& key, const Slice& value) {  auto merge = [this, column_family_id] (        jbyteArray j_key, jbyteArray j_value) {    m_env->CallVoidMethod(      m_jcallback_obj,      m_jMergeCfMethodId,      static_cast<jint>(column_family_id),      j_key,      j_value);  };  auto status = WriteBatchHandlerJniCallback::kv_op(key, value, merge);  if(status == nullptr) {    return ROCKSDB_NAMESPACE::Status::OK();  // TODO(AR) what to do if there is                                             // an Exception but we don't know                                             // the ROCKSDB_NAMESPACE::Status?  } else {    return ROCKSDB_NAMESPACE::Status(*status);  }}void WriteBatchHandlerJniCallback::Merge(const Slice& key, const Slice& value) {  auto merge = [this] (        jbyteArray j_key, jbyteArray j_value) {    m_env->CallVoidMethod(      m_jcallback_obj,      m_jMergeMethodId,      j_key,      j_value);  };  WriteBatchHandlerJniCallback::kv_op(key, value, merge);}ROCKSDB_NAMESPACE::Status WriteBatchHandlerJniCallback::DeleteCF(    uint32_t column_family_id, const Slice& key) {  auto remove = [this, column_family_id] (jbyteArray j_key) {    m_env->CallVoidMethod(      m_jcallback_obj,      m_jDeleteCfMethodId,      static_cast<jint>(column_family_id),      j_key);  };  auto status = WriteBatchHandlerJniCallback::k_op(key, remove);  if(status == nullptr) {    return ROCKSDB_NAMESPACE::Status::OK();  // TODO(AR) what to do if there is                                             // an Exception but we don't know                                             // the ROCKSDB_NAMESPACE::Status?  } else {    return ROCKSDB_NAMESPACE::Status(*status);  }}void WriteBatchHandlerJniCallback::Delete(const Slice& key) {  auto remove = [this] (jbyteArray j_key) {    m_env->CallVoidMethod(      m_jcallback_obj,      m_jDeleteMethodId,      j_key);  };  WriteBatchHandlerJniCallback::k_op(key, remove);}ROCKSDB_NAMESPACE::Status WriteBatchHandlerJniCallback::SingleDeleteCF(    uint32_t column_family_id, const Slice& key) {  auto singleDelete = [this, column_family_id] (jbyteArray j_key) {    m_env->CallVoidMethod(      m_jcallback_obj,      m_jSingleDeleteCfMethodId,      static_cast<jint>(column_family_id),      j_key);  };  auto status = WriteBatchHandlerJniCallback::k_op(key, singleDelete);  if(status == nullptr) {    return ROCKSDB_NAMESPACE::Status::OK();  // TODO(AR) what to do if there is                                             // an Exception but we don't know                                             // the ROCKSDB_NAMESPACE::Status?  } else {    return ROCKSDB_NAMESPACE::Status(*status);  }}void WriteBatchHandlerJniCallback::SingleDelete(const Slice& key) {  auto singleDelete = [this] (jbyteArray j_key) {    m_env->CallVoidMethod(      m_jcallback_obj,      m_jSingleDeleteMethodId,      j_key);  };  WriteBatchHandlerJniCallback::k_op(key, singleDelete);}ROCKSDB_NAMESPACE::Status WriteBatchHandlerJniCallback::DeleteRangeCF(    uint32_t column_family_id, const Slice& beginKey, const Slice& endKey) {  auto deleteRange = [this, column_family_id] (        jbyteArray j_beginKey, jbyteArray j_endKey) {    m_env->CallVoidMethod(      m_jcallback_obj,      m_jDeleteRangeCfMethodId,      static_cast<jint>(column_family_id),      j_beginKey,      j_endKey);  };  auto status = WriteBatchHandlerJniCallback::kv_op(beginKey, endKey, deleteRange);  if(status == nullptr) {    return ROCKSDB_NAMESPACE::Status::OK();  // TODO(AR) what to do if there is                                             // an Exception but we don't know                                             // the ROCKSDB_NAMESPACE::Status?  } else {    return ROCKSDB_NAMESPACE::Status(*status);  }}void WriteBatchHandlerJniCallback::DeleteRange(const Slice& beginKey,    const Slice& endKey) {  auto deleteRange = [this] (        jbyteArray j_beginKey, jbyteArray j_endKey) {    m_env->CallVoidMethod(      m_jcallback_obj,      m_jDeleteRangeMethodId,      j_beginKey,      j_endKey);  };  WriteBatchHandlerJniCallback::kv_op(beginKey, endKey, deleteRange);}void WriteBatchHandlerJniCallback::LogData(const Slice& blob) {  auto logData = [this] (jbyteArray j_blob) {    m_env->CallVoidMethod(      m_jcallback_obj,      m_jLogDataMethodId,      j_blob);  };  WriteBatchHandlerJniCallback::k_op(blob, logData);}ROCKSDB_NAMESPACE::Status WriteBatchHandlerJniCallback::PutBlobIndexCF(    uint32_t column_family_id, const Slice& key, const Slice& value) {  auto putBlobIndex = [this, column_family_id] (      jbyteArray j_key, jbyteArray j_value) {    m_env->CallVoidMethod(      m_jcallback_obj,      m_jPutBlobIndexCfMethodId,      static_cast<jint>(column_family_id),      j_key,      j_value);  };  auto status = WriteBatchHandlerJniCallback::kv_op(key, value, putBlobIndex);  if(status == nullptr) {    return ROCKSDB_NAMESPACE::Status::OK();  // TODO(AR) what to do if there is                                             // an Exception but we don't know                                             // the ROCKSDB_NAMESPACE::Status?  } else {    return ROCKSDB_NAMESPACE::Status(*status);  }}ROCKSDB_NAMESPACE::Status WriteBatchHandlerJniCallback::MarkBeginPrepare(    bool unprepare) {#ifndef DEBUG  (void) unprepare;#else  assert(!unprepare);#endif  m_env->CallVoidMethod(m_jcallback_obj, m_jMarkBeginPrepareMethodId);  // check for Exception, in-particular RocksDBException  if (m_env->ExceptionCheck()) {    // exception thrown    jthrowable exception = m_env->ExceptionOccurred();    std::unique_ptr<ROCKSDB_NAMESPACE::Status> status =        ROCKSDB_NAMESPACE::RocksDBExceptionJni::toCppStatus(m_env, exception);    if (status == nullptr) {      // unkown status or exception occurred extracting status      m_env->ExceptionDescribe();      return ROCKSDB_NAMESPACE::Status::OK();  // TODO(AR) probably need a                                               // better error code here    } else {      m_env->ExceptionClear();  // clear the exception, as we have extracted the status      return ROCKSDB_NAMESPACE::Status(*status);    }  }  return ROCKSDB_NAMESPACE::Status::OK();}ROCKSDB_NAMESPACE::Status WriteBatchHandlerJniCallback::MarkEndPrepare(    const Slice& xid) {  auto markEndPrepare = [this] (      jbyteArray j_xid) {    m_env->CallVoidMethod(      m_jcallback_obj,      m_jMarkEndPrepareMethodId,      j_xid);  };  auto status = WriteBatchHandlerJniCallback::k_op(xid, markEndPrepare);  if(status == nullptr) {    return ROCKSDB_NAMESPACE::Status::OK();  // TODO(AR) what to do if there is                                             // an Exception but we don't know                                             // the ROCKSDB_NAMESPACE::Status?  } else {    return ROCKSDB_NAMESPACE::Status(*status);  }}ROCKSDB_NAMESPACE::Status WriteBatchHandlerJniCallback::MarkNoop(    bool empty_batch) {  m_env->CallVoidMethod(m_jcallback_obj, m_jMarkNoopMethodId, static_cast<jboolean>(empty_batch));  // check for Exception, in-particular RocksDBException  if (m_env->ExceptionCheck()) {    // exception thrown    jthrowable exception = m_env->ExceptionOccurred();    std::unique_ptr<ROCKSDB_NAMESPACE::Status> status =        ROCKSDB_NAMESPACE::RocksDBExceptionJni::toCppStatus(m_env, exception);    if (status == nullptr) {      // unkown status or exception occurred extracting status      m_env->ExceptionDescribe();      return ROCKSDB_NAMESPACE::Status::OK();  // TODO(AR) probably need a                                               // better error code here    } else {      m_env->ExceptionClear();  // clear the exception, as we have extracted the status      return ROCKSDB_NAMESPACE::Status(*status);    }  }  return ROCKSDB_NAMESPACE::Status::OK();}ROCKSDB_NAMESPACE::Status WriteBatchHandlerJniCallback::MarkRollback(    const Slice& xid) {  auto markRollback = [this] (      jbyteArray j_xid) {    m_env->CallVoidMethod(      m_jcallback_obj,      m_jMarkRollbackMethodId,      j_xid);  };  auto status = WriteBatchHandlerJniCallback::k_op(xid, markRollback);  if(status == nullptr) {    return ROCKSDB_NAMESPACE::Status::OK();  // TODO(AR) what to do if there is                                             // an Exception but we don't know                                             // the ROCKSDB_NAMESPACE::Status?  } else {    return ROCKSDB_NAMESPACE::Status(*status);  }}ROCKSDB_NAMESPACE::Status WriteBatchHandlerJniCallback::MarkCommit(    const Slice& xid) {  auto markCommit = [this] (      jbyteArray j_xid) {    m_env->CallVoidMethod(      m_jcallback_obj,      m_jMarkCommitMethodId,      j_xid);  };  auto status = WriteBatchHandlerJniCallback::k_op(xid, markCommit);  if(status == nullptr) {    return ROCKSDB_NAMESPACE::Status::OK();  // TODO(AR) what to do if there is                                             // an Exception but we don't know                                             // the ROCKSDB_NAMESPACE::Status?  } else {    return ROCKSDB_NAMESPACE::Status(*status);  }}bool WriteBatchHandlerJniCallback::Continue() {  jboolean jContinue = m_env->CallBooleanMethod(      m_jcallback_obj,      m_jContinueMethodId);  if(m_env->ExceptionCheck()) {    // exception thrown    m_env->ExceptionDescribe();  }  return static_cast<bool>(jContinue == JNI_TRUE);}std::unique_ptr<ROCKSDB_NAMESPACE::Status> WriteBatchHandlerJniCallback::kv_op(    const Slice& key, const Slice& value,    std::function<void(jbyteArray, jbyteArray)> kvFn) {  const jbyteArray j_key = JniUtil::copyBytes(m_env, key);  if (j_key == nullptr) {    // exception thrown    if (m_env->ExceptionCheck()) {      m_env->ExceptionDescribe();    }    return nullptr;  }  const jbyteArray j_value = JniUtil::copyBytes(m_env, value);  if (j_value == nullptr) {    // exception thrown    if (m_env->ExceptionCheck()) {      m_env->ExceptionDescribe();    }    if (j_key != nullptr) {      m_env->DeleteLocalRef(j_key);    }    return nullptr;  }  kvFn(j_key, j_value);  // check for Exception, in-particular RocksDBException  if (m_env->ExceptionCheck()) {    if (j_value != nullptr) {      m_env->DeleteLocalRef(j_value);    }    if (j_key != nullptr) {      m_env->DeleteLocalRef(j_key);    }    // exception thrown    jthrowable exception = m_env->ExceptionOccurred();    std::unique_ptr<ROCKSDB_NAMESPACE::Status> status =        ROCKSDB_NAMESPACE::RocksDBExceptionJni::toCppStatus(m_env, exception);    if (status == nullptr) {      // unkown status or exception occurred extracting status      m_env->ExceptionDescribe();      return nullptr;    } else {      m_env->ExceptionClear();  // clear the exception, as we have extracted the status      return status;    }  }  if (j_value != nullptr) {    m_env->DeleteLocalRef(j_value);  }  if (j_key != nullptr) {    m_env->DeleteLocalRef(j_key);  }  // all OK  return std::unique_ptr<ROCKSDB_NAMESPACE::Status>(      new ROCKSDB_NAMESPACE::Status(ROCKSDB_NAMESPACE::Status::OK()));}std::unique_ptr<ROCKSDB_NAMESPACE::Status> WriteBatchHandlerJniCallback::k_op(    const Slice& key, std::function<void(jbyteArray)> kFn) {  const jbyteArray j_key = JniUtil::copyBytes(m_env, key);  if (j_key == nullptr) {    // exception thrown    if (m_env->ExceptionCheck()) {      m_env->ExceptionDescribe();    }    return nullptr;  }  kFn(j_key);  // check for Exception, in-particular RocksDBException  if (m_env->ExceptionCheck()) {    if (j_key != nullptr) {      m_env->DeleteLocalRef(j_key);    }    // exception thrown    jthrowable exception = m_env->ExceptionOccurred();    std::unique_ptr<ROCKSDB_NAMESPACE::Status> status =        ROCKSDB_NAMESPACE::RocksDBExceptionJni::toCppStatus(m_env, exception);    if (status == nullptr) {      // unkown status or exception occurred extracting status      m_env->ExceptionDescribe();      return nullptr;    } else {      m_env->ExceptionClear();  // clear the exception, as we have extracted the status      return status;    }  }  if (j_key != nullptr) {    m_env->DeleteLocalRef(j_key);  }  // all OK  return std::unique_ptr<ROCKSDB_NAMESPACE::Status>(      new ROCKSDB_NAMESPACE::Status(ROCKSDB_NAMESPACE::Status::OK()));}}  // namespace ROCKSDB_NAMESPACE
 |