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 callback "bridge" between Java and C++ for
7 // ROCKSDB_NAMESPACE::TraceWriter.
8 
9 #include "rocksjni/trace_writer_jnicallback.h"
10 #include "rocksjni/portal.h"
11 
12 namespace ROCKSDB_NAMESPACE {
TraceWriterJniCallback(JNIEnv * env,jobject jtrace_writer)13 TraceWriterJniCallback::TraceWriterJniCallback(
14     JNIEnv* env, jobject jtrace_writer)
15     : JniCallback(env, jtrace_writer) {
16   m_jwrite_proxy_methodid =
17       AbstractTraceWriterJni::getWriteProxyMethodId(env);
18   if(m_jwrite_proxy_methodid == nullptr) {
19     // exception thrown: NoSuchMethodException or OutOfMemoryError
20     return;
21   }
22 
23   m_jclose_writer_proxy_methodid =
24       AbstractTraceWriterJni::getCloseWriterProxyMethodId(env);
25   if(m_jclose_writer_proxy_methodid == nullptr) {
26     // exception thrown: NoSuchMethodException or OutOfMemoryError
27     return;
28   }
29 
30   m_jget_file_size_methodid =
31       AbstractTraceWriterJni::getGetFileSizeMethodId(env);
32   if(m_jget_file_size_methodid == nullptr) {
33     // exception thrown: NoSuchMethodException or OutOfMemoryError
34     return;
35   }
36 }
37 
Write(const Slice & data)38 Status TraceWriterJniCallback::Write(const Slice& data) {
39   jboolean attached_thread = JNI_FALSE;
40   JNIEnv* env = getJniEnv(&attached_thread);
41   if (env == nullptr) {
42     return Status::IOError("Unable to attach JNI Environment");
43   }
44 
45   jshort jstatus = env->CallShortMethod(m_jcallback_obj,
46       m_jwrite_proxy_methodid,
47       &data);
48 
49   if(env->ExceptionCheck()) {
50     // exception thrown from CallShortMethod
51     env->ExceptionDescribe();  // print out exception to stderr
52     releaseJniEnv(attached_thread);
53     return Status::IOError("Unable to call AbstractTraceWriter#writeProxy(long)");
54   }
55 
56   // unpack status code and status sub-code from jstatus
57   jbyte jcode_value = (jstatus >> 8) & 0xFF;
58   jbyte jsub_code_value = jstatus & 0xFF;
59   std::unique_ptr<Status> s = StatusJni::toCppStatus(jcode_value, jsub_code_value);
60 
61   releaseJniEnv(attached_thread);
62 
63   return Status(*s);
64 }
65 
Close()66 Status TraceWriterJniCallback::Close() {
67   jboolean attached_thread = JNI_FALSE;
68   JNIEnv* env = getJniEnv(&attached_thread);
69   if (env == nullptr) {
70     return Status::IOError("Unable to attach JNI Environment");
71   }
72 
73   jshort jstatus = env->CallShortMethod(m_jcallback_obj,
74       m_jclose_writer_proxy_methodid);
75 
76   if(env->ExceptionCheck()) {
77     // exception thrown from CallShortMethod
78     env->ExceptionDescribe();  // print out exception to stderr
79     releaseJniEnv(attached_thread);
80     return Status::IOError("Unable to call AbstractTraceWriter#closeWriterProxy()");
81   }
82 
83   // unpack status code and status sub-code from jstatus
84   jbyte code_value = (jstatus >> 8) & 0xFF;
85   jbyte sub_code_value = jstatus & 0xFF;
86   std::unique_ptr<Status> s = StatusJni::toCppStatus(code_value, sub_code_value);
87 
88   releaseJniEnv(attached_thread);
89 
90   return Status(*s);
91 }
92 
GetFileSize()93 uint64_t TraceWriterJniCallback::GetFileSize() {
94   jboolean attached_thread = JNI_FALSE;
95   JNIEnv* env = getJniEnv(&attached_thread);
96   if (env == nullptr) {
97     return 0;
98   }
99 
100   jlong jfile_size = env->CallLongMethod(m_jcallback_obj,
101       m_jget_file_size_methodid);
102 
103   if(env->ExceptionCheck()) {
104     // exception thrown from CallLongMethod
105     env->ExceptionDescribe();  // print out exception to stderr
106     releaseJniEnv(attached_thread);
107     return 0;
108   }
109 
110   releaseJniEnv(attached_thread);
111 
112   return static_cast<uint64_t>(jfile_size);
113 }
114 
115 }  // namespace ROCKSDB_NAMESPACE
116