Commit b9e98c52 authored by Paras Garg's avatar Paras Garg

Added basic JNI to send and recived data from c++

parent 36aa2047
.build
.build/*
client
.vscode/*
\ No newline at end of file
.vscode/*
*.log
*.so
\ No newline at end of file
SRCS := $(shell ls src/)
TARGET := client
# export LD_LIBRARY_PATH=.
#java path /usr/lib/jvm/java-11-openjdk-amd64/
SRC_DIR := src
OBJS := $(SRCS:.cpp=.o)
BUILD_DIR := .build
HEADERS := $(shell find -name '*.hpp')
OBJS := $(addprefix $(BUILD_DIR)/, $(OBJS))
OBJ_DIR := .build
JBUILD = .jbin
JSRCS := $(wildcard jsrc/*.java)
SRCS := $(wildcard $(SRC_DIR)/*.cpp)
OBJS := $(SRCS:$(SRC_DIR)/%.cpp=$(OBJ_DIR)/%.o)
#SRCS := $(shell ls src/)
#OBJS := $(SRCS:.cpp=.o)
#OBJS := $(addprefix $(BUILD_DIR)/, $(OBJS))
CXX = g++
CXXFLAGS += -g -O3 -Wall -I header
#compiling flags
CXXFLAGS += -g -O3 -Wall -std=c++17 -Iheader -fPIC
CXXFLAGS += -I/usr/lib/jvm/java-11-openjdk-amd64/include
CXXFLAGS += -I/usr/lib/jvm/java-11-openjdk-amd64/include/linux
#libraries
LIBS += -libverbs
LIBS += -lrdmacm
LIBS += -pthread
LIBS += -lrocksdb
Target := client
.phony = clean
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CXX) -o $@ $(CXXFLAGS) -c $< $(LIBS)
$(Target) : $(OBJS) | $(BUILD_DIR)
@echo "Compiled "$<" successfully!"
#$(BINDIR)/$(TARGET): $(OBJS)
$(TARGET) : $(OBJS)
$(CXX) -o $@ $^ $(LIBS)
$(BUILD_DIR) :
mkdir -p $@
\ No newline at end of file
@echo "Linked "$<" successfully!"
.PHONY = clean
clean:
rm -f $(OBJ_DIR)/*
rm -f $(TARGET)
.PHONY: count
count:
find . -type f -name "*.hpp"|xargs wc -l
find . -type f -name "*.cpp"|xargs wc -l
@echo "Lines of code counted!"
Jclient: $(OBJS)
$(CXX) -o libHelloImpl.so -shared .build/Hello.o $(LIBS)
@echo "jclient "$<" successfully!"
#jcompile: javac $(JSRCS) -d JBUILD
JniHeader:
javac $(JSRCS) -h header
\ No newline at end of file
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Hello */
#ifndef _Included_Hello
#define _Included_Hello
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Hello
* Method: put
* Signature: ([B[B)I
*/
JNIEXPORT jint JNICALL Java_Hello_put
(JNIEnv *, jobject, jbyteArray, jbyteArray);
/*
* Class: Hello
* Method: get
* Signature: ([B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_Hello_get
(JNIEnv *, jobject, jbyteArray);
/*
* Class: Hello
* Method: delete
* Signature: ([B)I
*/
JNIEXPORT jint JNICALL Java_Hello_delete
(JNIEnv *, jobject, jbyteArray);
#ifdef __cplusplus
}
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// @File Name: Logger.h //
// @Author: Pankaj Choudhary //
// @Version: 0.0.1 //
// @L.M.D: 13th April 2015 //
// @Description: For Logging into file //
// //
// Detail Description: //
// Implemented complete logging mechanism, Supporting multiple logging type //
// like as file based logging, console base logging etc. It also supported //
// for different log type. //
// //
// Thread Safe logging mechanism. Compatible with VC++ (Windows platform) //
// as well as G++ (Linux platform) //
// //
// Supported Log Type: ERROR, ALARM, ALWAYS, INFO, BUFFER, TRACE, DEBUG //
// //
// No control for ERROR, ALRAM and ALWAYS messages. These type of messages //
// should be always captured. //
// //
// BUFFER log type should be use while logging raw buffer or raw messages //
// //
// Having direct interface as well as C++ Singleton inface. can use //
// whatever interface want. //
// //
///////////////////////////////////////////////////////////////////////////////
#ifndef _LOGGER_H_
#define _LOGGER_H_
// C++ Header File(s)
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#ifdef WIN32
// Win Socket Header File(s)
#include <Windows.h>
#include <process.h>
#else
// POSIX Socket Header File(s)
#include <errno.h>
#include <pthread.h>
#endif
namespace CPPLog
{
// Direct Interface for logging into log file or console using MACRO(s)
#define LOG_ERROR(x) Logger::getInstance()->error(x)
#define LOG_ALARM(x) Logger::getInstance()->alarm(x)
#define LOG_ALWAYS(x) Logger::getInstance()->always(x)
#define LOG_INFO(x) Logger::getInstance()->info(x)
#define LOG_BUFFER(x) Logger::getInstance()->buffer(x)
#define LOG_TRACE(x) Logger::getInstance()->trace(x)
#define LOG_DEBUG(x) Logger::getInstance()->debug(x)
// enum for LOG_LEVEL
typedef enum LOG_LEVEL
{
DISABLE_LOG = 1,
LOG_LEVEL_INFO = 2,
LOG_LEVEL_BUFFER = 3,
LOG_LEVEL_TRACE = 4,
LOG_LEVEL_DEBUG = 5,
ENABLE_LOG = 6,
}LogLevel;
// enum for LOG_TYPE
typedef enum LOG_TYPE
{
NO_LOG = 1,
CONSOLE = 2,
FILE_LOG = 3,
}LogType;
class Logger
{
public:
static Logger* getInstance() throw ();
// Interface for Error Log
void error(const char* text) throw();
void error(std::string& text) throw();
void error(std::ostringstream& stream) throw();
// Interface for Alarm Log
void alarm(const char* text) throw();
void alarm(std::string& text) throw();
void alarm(std::ostringstream& stream) throw();
// Interface for Always Log
void always(const char* text) throw();
void always(std::string& text) throw();
void always(std::ostringstream& stream) throw();
// Interface for Buffer Log
void buffer(const char* text) throw();
void buffer(std::string& text) throw();
void buffer(std::ostringstream& stream) throw();
// Interface for Info Log
void info(const char* text) throw();
void info(std::string& text) throw();
void info(std::ostringstream& stream) throw();
// Interface for Trace log
void trace(const char* text) throw();
void trace(std::string& text) throw();
void trace(std::ostringstream& stream) throw();
// Interface for Debug log
void debug(const char* text) throw();
void debug(std::string& text) throw();
void debug(std::ostringstream& stream) throw();
// Error and Alarm log must be always enable
// Hence, there is no interfce to control error and alarm logs
// Interfaces to control log levels
void updateLogLevel(LogLevel logLevel);
void enaleLog(); // Enable all log levels
void disableLog(); // Disable all log levels, except error and alarm
// Interfaces to control log Types
void updateLogType(LogType logType);
void enableConsoleLogging();
void enableFileLogging();
protected:
Logger();
~Logger();
// Wrapper function for lock/unlock
// For Extensible feature, lock and unlock should be in protected
void lock();
void unlock();
std::string getCurrentTime();
private:
void logIntoFile(std::string& data);
void logOnConsole(std::string& data);
Logger(const Logger& obj) {}
void operator=(const Logger& obj) {}
private:
static Logger* m_Instance;
std::ofstream m_File;
#ifdef WIN32
CRITICAL_SECTION m_Mutex;
#else
pthread_mutexattr_t m_Attr;
pthread_mutex_t m_Mutex;
#endif
LogLevel m_LogLevel;
LogType m_LogType;
};
} // End of namespace
#endif // End of _LOGGER_H_
......@@ -7,7 +7,11 @@ enum RequestType
DELETE,
INVALIDATE
};
enum ResponseStatus
{
SUCCESS,
FAILURE
};
struct __attribute__ ((__packed__)) SalRequestHeader
{
......@@ -20,25 +24,29 @@ struct __attribute__ ((__packed__)) SalRequestHeader
struct __attribute__ ((__packed__)) SalResponseHeader
{
uint32_t id;
enum RequestType type;
uint32_t size;
enum ResponseStatus status;
/*
* Note value will be present only in case of response status is success
*/
uint32_t valueSize;
};
struct __attribute__ ((__packed__)) InvRequestHeader
{
//private:
uint32_t id;
enum RequestType type;
//public:
uint32_t keySize;
uint32_t keySize;
};
static uint32_t SUCCESS = 0;
static uint32_t FAILURE = 1;
static int32_t SalRequestHeaderSize = sizeof(SalRequestHeader);
static int32_t SalResponseSize = sizeof(SalResponseHeader);
struct __attribute__ ((__packed__)) InvResponseHeader
{
uint32_t id;
enum ResponseStatus status;
};
static uint32_t SalRequestHeaderSize = sizeof(SalRequestHeader);
static uint32_t SalResponseHeaderSize = sizeof(SalResponseHeader);
static uint32_t InvRequestHeaderSize = sizeof(InvRequestHeader);
static uint32_t InvResponseHeaderSize = sizeof(InvResponseHeader);
#endif
\ No newline at end of file
public class Hello {
public native int put(byte[] key, byte[] value);
public native byte[] get(byte[] key);
public native int delete(byte[] key);
static { System.loadLibrary("HelloImpl"); }
public static void main (String[] args) {
Hello hello = new Hello();
System.out.println(hello.put("paras".getBytes(), "garg".getBytes()));
System.out.println(hello.get("paras".getBytes()));
System.out.println(hello.delete("paras".getBytes()));
}
}
\ No newline at end of file
......@@ -4,33 +4,46 @@
int main()
{
RdmaClientEndpointGroup *group = new RdmaClientEndpointGroup(5, 5, 5, 50, 50, 0, 1000);
RdmaClientEndpointGroup *group = new RdmaClientEndpointGroup(5, 5, 5, 500, 500, 0, 1000);
RdmaClientEndpoint *clientEp = group->createEndpoint();
clientEp->connect("192.168.200.20", "1921", "sal");
while (!clientEp->isConnected());
std::cout << "client : connected" << std::endl;
char *message = new char[30];
char *message = new char[100];
struct SalRequestHeader *request = (struct SalRequestHeader *)message;
request->id = clientEp->_requestId.fetch_add(1, std::memory_order_relaxed);
request->type = RequestType::DELETE;
request->keySize = 14;
memcpy((char *)request + SalRequestHeaderSize, "key1sendkey1s", 13);
((char*)request)[SalRequestHeaderSize+14] = '\0';
std::cout << "send Request for atomic int " << request->id << "\n";
// memcpy(re->value,"aa",2);
request->type = RequestType::PUT;
request->keySize = 10;
request->valueSize = 5;
memcpy((char *)request + SalRequestHeaderSize, "parasgarg1", 10);
memcpy((char *)request + SalRequestHeaderSize + request->keySize, "paras", 5);
std::cout << "send" << clientEp->sendMessage(message, SalRequestHeaderSize + 14) << std::endl;
// std::cout << "send" << clientEp->sendMessage((char*)re, SalRequestHeaderSize + 2) << std::endl;
std::cout << "send" << clientEp->sendMessage(message, SalRequestHeaderSize + 14) << std::endl;
std::cout << "send" << clientEp->sendMessage(message, SalRequestHeaderSize + 14) << std::endl;
std::cout << "send" << clientEp->sendMessage(message, SalRequestHeaderSize + 14) << std::endl;
request->id = clientEp->_requestId.fetch_add(1, std::memory_order_relaxed);
request->type = RequestType::GET;
request->keySize = 10;
memcpy((char *)request + SalRequestHeaderSize, "parasgarg1", 10);
std::cout << "send" << clientEp->sendMessage(message, SalRequestHeaderSize + 14) << std::endl;
std::cout << "send" << clientEp->sendMessage(message, SalRequestHeaderSize + 14) << std::endl;
request->id = clientEp->_requestId.fetch_add(1, std::memory_order_relaxed);
request->type = RequestType::DELETE;
request->keySize = 10;
memcpy((char *)request + SalRequestHeaderSize, "parasgarg1", 10);
std::cout << "send" << clientEp->sendMessage(message, SalRequestHeaderSize + 14) << std::endl;
std::cout << "send" << clientEp->sendMessage(message, SalRequestHeaderSize + 14) << std::endl;
int send = 0;
// memcpy(re->value,"aa",2);
int send = 0;
while (1)
{
std::cin >> send;
......
#include <stdio.h>
#include "Hello.h" // generated by javah
#include "RdmaClientEndpoint.hpp"
/*
bool rocksdb_put_helper(JNIEnv* env, ROCKSDB_NAMESPACE::DB* db,
const ROCKSDB_NAMESPACE::WriteOptions& write_options,
ROCKSDB_NAMESPACE::ColumnFamilyHandle* cf_handle,
jbyteArray jkey, jint jkey_off, jint jkey_len,
jbyteArray jval, jint jval_off, jint jval_len) {
jbyte* key = new jbyte[jkey_len];
env->GetByteArrayRegion(jkey, jkey_off, jkey_len, key);
if (env->ExceptionCheck()) {
// exception thrown: ArrayIndexOutOfBoundsException
delete[] key;
return false;
}
jbyte* value = new jbyte[jval_len];
env->GetByteArrayRegion(jval, jval_off, jval_len, value);
if (env->ExceptionCheck()) {
// exception thrown: ArrayIndexOutOfBoundsException
delete[] value;
delete[] key;
return false;
}
*/
JNIEXPORT jbyteArray JNICALL Java_Hello_get(JNIEnv *jenv, jobject jobj, jbyteArray jkey)
{
int keyLen = jenv->GetArrayLength(jkey);
char* key = new char[keyLen];
jenv->GetByteArrayRegion(jkey,0,keyLen,reinterpret_cast<jbyte*>( key));
if(jenv->ExceptionCheck())
{
std::cout<<"exception occurs get"<<std::endl;
delete[] key;
}
std::cout<<"get "<<key<< "len "<<keyLen<<std::endl;
int valLen;
valLen = 6;
jbyteArray jvalue = jenv->NewByteArray(valLen);
jenv->SetByteArrayRegion(jvalue,0,5,reinterpret_cast<const jbyte*>("paras"));
delete[] key;
return jvalue;
}
JNIEXPORT jint JNICALL Java_Hello_put(JNIEnv *jenv, jobject jobj, jbyteArray jkey, jbyteArray jval)
{
int keyLen = jenv->GetArrayLength(jkey);
char* key = new char[keyLen];
jenv->GetByteArrayRegion(jkey,0,keyLen,reinterpret_cast<jbyte*>(key));
int valLen = jenv->GetArrayLength(jval);
char* val = new char[valLen];
jenv->GetByteArrayRegion(jval,0,valLen,reinterpret_cast<jbyte*>(val));
if(jenv->ExceptionCheck())
{
std::cout<<"put exception occur"<<std::endl;
delete[] key;
delete[] val;
}
std::cout<<"put "<<key<< " len "<<keyLen<<" "<<val<<" len "<<valLen<<std::endl;
delete[] key;
delete[] val;
return 1;
}
JNIEXPORT jint JNICALL Java_Hello_delete(JNIEnv *jenv, jobject jobj, jbyteArray jkey)
{
int keyLen = jenv->GetArrayLength(jkey);
char* key = new char[keyLen];
jenv->GetByteArrayRegion(jkey,0,keyLen,reinterpret_cast<jbyte*>(key));
if(jenv->ExceptionCheck())
{
std::cout<<"exception occurs delete"<<std::endl;
delete[] key;
}
std::cout<<"delete "<<key<< "len "<<keyLen<<std::endl;
delete[] key;
return 1;
}
\ No newline at end of file
///////////////////////////////////////////////////////////////////////////////
// @File Name: Logger.cpp //
// @Author: Pankaj Choudhary //
// @Version: 0.0.1 //
// @L.M.D: 13th April 2015 //
// @Description: For Logging into file //
// //
// Detail Description: //
// Implemented complete logging mechanism, Supporting multiple logging type //
// like as file based logging, console base logging etc. It also supported //
// for different log type. //
// //
// Thread Safe logging mechanism. Compatible with VC++ (Windows platform) //
// as well as G++ (Linux platform) //
// //
// Supported Log Type: ERROR, ALARM, ALWAYS, INFO, BUFFER, TRACE, DEBUG //
// //
// No control for ERROR, ALRAM and ALWAYS messages. These type of messages //
// should be always captured. //
// //
// BUFFER log type should be use while logging raw buffer or raw messages //
// //
// Having direct interface as well as C++ Singleton inface. can use //
// whatever interface want. //
// //
///////////////////////////////////////////////////////////////////////////////
// C++ Header File(s)
#include <iostream>
#include <cstdlib>
#include <ctime>
// Code Specific Header Files(s)
#include "Logger.hpp"
using namespace std;
using namespace CPPLog;
Logger* Logger::m_Instance = 0;
// Log file name. File name should be change from here only
const string logFileName = "LogFile.log";
Logger::Logger()
{
m_File.open(logFileName.c_str(), ios::out|ios::app);
m_LogLevel = LOG_LEVEL_TRACE;
m_LogType = FILE_LOG;
// Initialize mutex
#ifdef WIN32
InitializeCriticalSection(&m_Mutex);
#else
int ret=0;
ret = pthread_mutexattr_settype(&m_Attr, PTHREAD_MUTEX_ERRORCHECK_NP);
if(ret != 0)
{
printf("Logger::Logger() -- Mutex attribute not initialize!!\n");
exit(0);
}
ret = pthread_mutex_init(&m_Mutex,&m_Attr);
if(ret != 0)
{
printf("Logger::Logger() -- Mutex not initialize!!\n");
exit(0);
}
#endif
}
Logger::~Logger()
{
m_File.close();
#ifdef WIN32
DeleteCriticalSection(&m_Mutex);
#else
pthread_mutexattr_destroy(&m_Attr);
pthread_mutex_destroy(&m_Mutex);
#endif
}
Logger* Logger::getInstance() throw ()
{
if (m_Instance == 0)
{
m_Instance = new Logger();
}
return m_Instance;
}
void Logger::lock()
{
#ifdef WIN32
EnterCriticalSection(&m_Mutex);
#else
pthread_mutex_lock(&m_Mutex);
#endif
}
void Logger::unlock()
{
#ifdef WIN32
LeaveCriticalSection(&m_Mutex);
#else
pthread_mutex_unlock(&m_Mutex);
#endif
}
void Logger::logIntoFile(std::string& data)
{
lock();
m_File << getCurrentTime() << " " << data << endl;
unlock();
}
void Logger::logOnConsole(std::string& data)
{
cout << getCurrentTime() << " " << data << endl;
}
string Logger::getCurrentTime()
{
return "";
string currTime;
//Current date/time based on current time
time_t now = time(0);
// Convert current time to string
currTime.assign(ctime(&now));
// Last charactor of currentTime is "\n", so remove it
string currentTime = currTime.substr(0, currTime.size()-1);
return currentTime;
}
// Interface for Error Log
void Logger::error(const char* text) throw()
{
string data;
data.append("[ERROR]: ");
data.append(text);
// ERROR must be capture
if(m_LogType == FILE_LOG)
{
logIntoFile(data);
}
else if(m_LogType == CONSOLE)
{
logOnConsole(data);
}
}
void Logger::error(std::string& text) throw()
{
error(text.data());
}
void Logger::error(std::ostringstream& stream) throw()
{
string text = stream.str();
error(text.data());
}
// Interface for Alarm Log
void Logger::alarm(const char* text) throw()
{
string data;
data.append("[ALARM]: ");
data.append(text);
// ALARM must be capture
if(m_LogType == FILE_LOG)
{
logIntoFile(data);
}
else if(m_LogType == CONSOLE)
{
logOnConsole(data);
}
}
void Logger::alarm(std::string& text) throw()
{
alarm(text.data());
}
void Logger::alarm(std::ostringstream& stream) throw()
{
string text = stream.str();
alarm(text.data());
}
// Interface for Always Log
void Logger::always(const char* text) throw()
{
string data;
data.append("[ALWAYS]: ");
data.append(text);
// No check for ALWAYS logs
if(m_LogType == FILE_LOG)
{
logIntoFile(data);
}
else if(m_LogType == CONSOLE)
{
logOnConsole(data);
}
}
void Logger::always(std::string& text) throw()
{
always(text.data());
}
void Logger::always(std::ostringstream& stream) throw()
{
string text = stream.str();
always(text.data());
}
// Interface for Buffer Log
void Logger::buffer(const char* text) throw()
{
// Buffer is the special case. So don't add log level
// and timestamp in the buffer message. Just log the raw bytes.
if((m_LogType == FILE_LOG) && (m_LogLevel >= LOG_LEVEL_BUFFER))
{
lock();
m_File << text << endl;
unlock();
}
else if((m_LogType == CONSOLE) && (m_LogLevel >= LOG_LEVEL_BUFFER))
{
cout << text << endl;
}
}
void Logger::buffer(std::string& text) throw()