diff --git a/hbase-native-client/core/BUCK b/hbase-native-client/core/BUCK
index d8d15a9..4a06a45 100644
--- a/hbase-native-client/core/BUCK
+++ b/hbase-native-client/core/BUCK
@@ -64,12 +64,26 @@ cxx_library(
],
compiler_flags=['-Weffc++'],
visibility=['PUBLIC',],)
+cxx_library(
+ name="mini-cluster",
+ exported_headers=["mini-cluster.h",],
+ srcs=["mini-cluster.cc",],
+ preprocessor_flags= ['-I', '/usr/lib/jvm/java-8-openjdk-amd64/include/', '-I', '/usr/lib/jvm/java-8-openjdk-amd64/include/linux'],
+ exported_preprocessor_flags= ['-I', '/usr/lib/jvm/java-8-openjdk-amd64/include/', '-I', '/usr/lib/jvm/java-8-openjdk-amd64/include/linux'],
+ compiler_flags = ['-I', '/usr/lib/jvm/java-8-openjdk-amd64/include/', '-I', '/usr/lib/jvm/java-8-openjdk-amd64/include/linux'],
+ linker_flags = ['-ljvm', '-L/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server'],
+ exported_linker_flags = ['-ljvm', '-L/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server', '-Wl,-rpath=/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server'],
+ deps=[
+ ":core",
+ ],
+ visibility=['PUBLIC',],)
cxx_test(
name="location-cache-test",
srcs=["location-cache-test.cc",],
deps=[
":core",
"//test-util:test-util",
+ "//core:mini-cluster"
],
run_test_separately=True,)
cxx_test(
diff --git a/hbase-native-client/core/client-test.cc b/hbase-native-client/core/client-test.cc
index 0a45fff..b342f48 100644
--- a/hbase-native-client/core/client-test.cc
+++ b/hbase-native-client/core/client-test.cc
@@ -57,7 +57,8 @@ class ClientTest {
static void CreateHBaseConfWithEnv() {
// Creating Empty Config Files so that we dont get a Configuration exception @Client
CreateHBaseConf(kDefHBaseConfPath, kHBaseDefaultXml, kHBaseXmlData);
- CreateHBaseConf(kDefHBaseConfPath, kHBaseSiteXml, kHBaseXmlData);
+ // the hbase-site.xml would be persisted by MiniCluster
+ //CreateHBaseConf(kDefHBaseConfPath, kHBaseSiteXml, kHBaseXmlData);
setenv("HBASE_CONF", kDefHBaseConfPath.c_str(), 1);
}
};
@@ -84,6 +85,8 @@ const std::string ClientTest::kHBaseXmlData(
"the License.\n "
"*/\n-->\n\n\n");
+hbase::TestUtil test_util{};
+
TEST(Client, EmptyConfigurationPassedToClient) { ASSERT_ANY_THROW(hbase::Client client); }
TEST(Client, ConfigurationPassedToClient) {
@@ -115,10 +118,9 @@ TEST(Client, Get) {
ClientTest::CreateHBaseConfWithEnv();
// Using TestUtil to populate test data
- hbase::TestUtil *test_util = new hbase::TestUtil();
- test_util->RunShellCmd(
- "create 't', 'd'; put 't', 'test2', 'd:2', 'value2'; put 't', 'test2', 'd:extra', 'value for "
- "extra'");
+ test_util.create_table("t", "d");
+ test_util.tablePut("t", "test2", "d", "2", "value2");
+ test_util.tablePut("t", "test2", "d", "extra", "value for extra");
// Create TableName and Row to be fetched from HBase
auto tn = folly::to("t");
@@ -145,7 +147,6 @@ TEST(Client, Get) {
// The connection stays open and we don't want that.
// So we are stopping the connection.
// We can remove this once we have fixed the folly part
- delete test_util;
// Test the values, should be same as in put executed on hbase shell
ASSERT_TRUE(!result->IsEmpty()) << "Result shouldn't be empty.";
@@ -163,7 +164,6 @@ TEST(Client, GetForNonExistentTable) {
ClientTest::CreateHBaseConfWithEnv();
// Using TestUtil to populate test data
- hbase::TestUtil *test_util = new hbase::TestUtil();
// Create TableName and Row to be fetched from HBase
auto tn = folly::to("t_not_exists");
@@ -190,7 +190,6 @@ TEST(Client, GetForNonExistentTable) {
// The connection stays open and we don't want that.
// So we are stopping the connection.
// We can remove this once we have fixed the folly part
- delete test_util;
table->Close();
client.Close();
@@ -202,8 +201,7 @@ TEST(Client, GetForNonExistentRow) {
ClientTest::CreateHBaseConfWithEnv();
// Using TestUtil to populate test data
- hbase::TestUtil *test_util = new hbase::TestUtil();
- test_util->RunShellCmd("create 't_exists', 'd'");
+ test_util.create_table("t_exists", "d");
// Create TableName and Row to be fetched from HBase
auto tn = folly::to("t_exists");
@@ -231,7 +229,6 @@ TEST(Client, GetForNonExistentRow) {
// The connection stays open and we don't want that.
// So we are stopping the connection.
// We can remove this once we have fixed the folly part
- delete test_util;
table->Close();
client.Close();
diff --git a/hbase-native-client/core/location-cache-test.cc b/hbase-native-client/core/location-cache-test.cc
index 9a778c6..038d70a 100644
--- a/hbase-native-client/core/location-cache-test.cc
+++ b/hbase-native-client/core/location-cache-test.cc
@@ -30,8 +30,8 @@
using namespace hbase;
using namespace std::chrono;
+TestUtil test_util{};
TEST(LocationCacheTest, TestGetMetaNodeContents) {
- TestUtil test_util{};
auto cpu = std::make_shared(4);
auto io = std::make_shared(4);
auto codec = std::make_shared();
@@ -48,7 +48,6 @@ TEST(LocationCacheTest, TestGetMetaNodeContents) {
}
TEST(LocationCacheTest, TestGetRegionLocation) {
- TestUtil test_util{};
auto cpu = std::make_shared(4);
auto io = std::make_shared(4);
auto codec = std::make_shared();
@@ -59,7 +58,7 @@ TEST(LocationCacheTest, TestGetRegionLocation) {
auto tn = folly::to("t");
auto row = "test";
ASSERT_ANY_THROW(cache.LocateFromMeta(tn, row).get(milliseconds(1000)));
- test_util.RunShellCmd("create 't', 'd'");
+ test_util.create_table("t", "d");
auto loc = cache.LocateFromMeta(tn, row).get(milliseconds(1000));
ASSERT_TRUE(loc != nullptr);
cpu->stop();
@@ -68,7 +67,6 @@ TEST(LocationCacheTest, TestGetRegionLocation) {
}
TEST(LocationCacheTest, TestCaching) {
- TestUtil test_util{};
auto cpu = std::make_shared(4);
auto io = std::make_shared(4);
auto codec = std::make_shared();
@@ -83,8 +81,7 @@ TEST(LocationCacheTest, TestCaching) {
// test location pulled from meta gets cached
ASSERT_ANY_THROW(cache.LocateRegion(tn_1, row_a).get(milliseconds(1000)));
ASSERT_ANY_THROW(cache.LocateFromMeta(tn_1, row_a).get(milliseconds(1000)));
-
- test_util.RunShellCmd("create 't1', 'd'");
+ test_util.create_table("t1", "d");
ASSERT_FALSE(cache.IsLocationCached(tn_1, row_a));
auto loc = cache.LocateRegion(tn_1, row_a).get(milliseconds(1000));
@@ -92,7 +89,7 @@ TEST(LocationCacheTest, TestCaching) {
ASSERT_EQ(loc, cache.GetCachedLocation(tn_1, row_a));
// test with two regions
- test_util.RunShellCmd("create 't2', 'd', SPLITS => ['b']");
+ test_util.create_table("t2", "d", "b", NULL);
ASSERT_FALSE(cache.IsLocationCached(tn_2, "a"));
loc = cache.LocateRegion(tn_2, "a").get(milliseconds(1000));
@@ -107,7 +104,7 @@ TEST(LocationCacheTest, TestCaching) {
ASSERT_EQ(loc, cache.GetCachedLocation(tn_2, "ba"));
// test with three regions
- test_util.RunShellCmd("create 't3', 'd', SPLITS => ['b', 'c']");
+ test_util.create_table("t3", "d", "b", "c");
ASSERT_FALSE(cache.IsLocationCached(tn_3, "c"));
ASSERT_FALSE(cache.IsLocationCached(tn_3, "ca"));
diff --git a/hbase-native-client/core/location-cache.cc b/hbase-native-client/core/location-cache.cc
index da9f64a..441f8e2 100644
--- a/hbase-native-client/core/location-cache.cc
+++ b/hbase-native-client/core/location-cache.cc
@@ -106,7 +106,8 @@ ServerName LocationCache::ReadMetaLocation() {
reinterpret_cast(buf->writableData()), &len, nullptr);
if (zk_result != ZOK || len < 9) {
LOG(ERROR) << "Error getting meta location.";
- throw runtime_error("Error getting meta location");
+ throw runtime_error("Error getting meta location. Quorum "
+ + conf_->Get(kHBaseZookeeperQuorum_, ""));
}
buf->append(len);
diff --git a/hbase-native-client/test-util/BUCK b/hbase-native-client/test-util/BUCK
index c6e41f1..ee9390f 100644
--- a/hbase-native-client/test-util/BUCK
+++ b/hbase-native-client/test-util/BUCK
@@ -22,9 +22,19 @@ cxx_library(name="test-util",
srcs=["test-util.cc"],
deps=[
"//third-party:folly",
- "//core:core"
+ "//core:core",
+ "//core:mini-cluster"
],
visibility=[
'PUBLIC',
],
)
+cxx_test(
+ name="test-util-test",
+ srcs=["test-util-test.cc",],
+ deps=[
+ "//core:core",
+ "//test-util:test-util",
+ "//core:mini-cluster"
+ ],
+ run_test_separately=True,)
diff --git a/hbase-native-client/test-util/test-util.cc b/hbase-native-client/test-util/test-util.cc
index e355bdf..b1befef 100644
--- a/hbase-native-client/test-util/test-util.cc
+++ b/hbase-native-client/test-util/test-util.cc
@@ -18,6 +18,7 @@
*/
#include "test-util/test-util.h"
+#include
#include
@@ -43,14 +44,14 @@ std::string TestUtil::RandString(int len) {
TestUtil::TestUtil() : temp_dir_(TestUtil::RandString()) {
auto p = temp_dir_.path().string();
- auto cmd = std::string{"bin/start-local-hbase.sh " + p};
- auto res_code = std::system(cmd.c_str());
- CHECK_EQ(res_code, 0);
+ jobject cluster = StartMiniCluster(2);
+ std::string quorum("localhost:");
+ const char* port = mini->getConf(cluster, "hbase.zookeeper.property.clientPort");
+ conf()->Set("hbase.zookeeper.quorum", quorum + port);
}
TestUtil::~TestUtil() {
- auto res_code = std::system("bin/stop-local-hbase.sh");
- CHECK_EQ(res_code, 0);
+ StopMiniCluster();
}
void TestUtil::RunShellCmd(const std::string &command) {
@@ -58,3 +59,20 @@ void TestUtil::RunShellCmd(const std::string &command) {
auto res_code = std::system(cmd_string.c_str());
CHECK_EQ(res_code, 0);
}
+
+jobject TestUtil::StartMiniCluster(int num_region_servers) {
+ mini = new MiniCluster();
+ return mini->start_cluster(num_region_servers);
+}
+void TestUtil::StopMiniCluster() {
+ mini->stop_cluster();
+}
+jobject TestUtil::create_table(char *tblNam, char *familyName) {
+ return mini->create_table(tblNam, familyName);
+}
+jobject TestUtil::create_table(char *tblNam, char *familyName, char* key1, char*k2) {
+ return mini->create_table(tblNam, familyName, key1, k2);
+}
+jobject TestUtil::tablePut(char *table, char *row, char *fam, char *col, char *value) {
+ return mini->tablePut(table, row, fam, col, value);
+}
\ No newline at end of file
diff --git a/hbase-native-client/test-util/test-util.h b/hbase-native-client/test-util/test-util.h
index cc35511..f917a17 100644
--- a/hbase-native-client/test-util/test-util.h
+++ b/hbase-native-client/test-util/test-util.h
@@ -23,7 +23,7 @@
#include
#include
-
+#include "core/mini-cluster.h"
#include "core/configuration.h"
namespace hbase {
@@ -62,7 +62,18 @@ class TestUtil {
*/
std::shared_ptr conf() const { return conf_; }
+ /**
+ * Starts mini hbase cluster with specified number of region servers
+ */
+ jobject StartMiniCluster(int num_region_servers);
+
+ void StopMiniCluster();
+ jobject create_table(char *tblNam, char *familyName);
+ jobject create_table(char *tblNam, char *familyName, char* key1, char*k2);
+ jobject tablePut(char *table, char *row, char *fam, char *col, char *value);
+
private:
+ MiniCluster* mini;
folly::test::TemporaryDirectory temp_dir_;
std::shared_ptr conf_ = std::make_shared();
};
diff --git a/hbase-native-client/core/mini-cluster.cc b/hbase-native-client/core/mini-cluster.cc
new file mode 100644
index 0000000..24082b3
--- /dev/null
+++ b/hbase-native-client/core/mini-cluster.cc
@@ -0,0 +1,400 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "core/mini-cluster.h"
+#include "core/client.h"
+#include
+#include
+#include "core/configuration.h"
+#include "core/get.h"
+#include "core/hbase_configuration_loader.h"
+#include "core/result.h"
+#include "core/table.h"
+#include "serde/table-name.h"
+//#include "/usr/lib/jvm/java-8-openjdk-amd64/include/jni.h"
+
+#define TABLE_NAME_CLASS "org/apache/hadoop/hbase/TableName"
+#define TABLE_CLASS "org/apache/hadoop/hbase/client/Table"
+#define ADMIN_CLASS "org/apache/hadoop/hbase/client/Admin"
+#define CONN_FACTORY_CLASS "org/apache/hadoop/hbase/client/ConnectionFactory"
+#define CONN_CLASS "org/apache/hadoop/hbase/client/Connection"
+#define PUT_CLASS "org/apache/hadoop/hbase/client/Put"
+#define HTU_CLASS "org/apache/hadoop/hbase/HBaseTestingUtility"
+#define MINI_CLUSTER_CLASS "org/apache/hadoop/hbase/MiniHBaseCluster"
+#define HADOOP_CONF "org/apache/hadoop/conf/Configuration"
+
+using hbase::MiniCluster;
+JNIEnv* env;
+jclass testingUtilClass;
+jclass tableNameClass;
+jclass tableClass;
+jclass connFactoryClass;
+jclass connClass;
+jclass adminClass;
+jclass hbaseMiniClusterClass;
+jclass putClass;
+jclass confClass;
+jclass strClass;
+jmethodID stopRSMid;
+jmethodID getConfMid;
+jmethodID setConfMid;
+jmethodID tblNameValueOfMid;
+jmethodID createTableMid;
+jmethodID createTableWithSplitMid;
+jmethodID putMid;
+jmethodID putCtor;
+jmethodID addColMid;
+jmethodID createConnMid;
+jmethodID getConnMid;
+jmethodID getTableMid;
+jmethodID confGetMid;
+jmethodID getAdminMid;
+jmethodID moveMid;
+jmethodID strCtorMid;
+pthread_mutex_t count_mutex;
+jobject htu;
+jobject cluster;
+jobject encoding;
+ char buf[14000];
+
+ JNIEnv* create_vm(JavaVM **jvm)
+ {
+ JavaVMInitArgs args;
+ JavaVMOption jvm_options;
+ args.version = JNI_VERSION_1_6;
+ args.nOptions = 1;
+ char *classpath = getenv("CLASSPATH");
+ if (classpath == NULL || strstr(classpath, "-tests.jar")==NULL) {
+ FILE *fd = fopen("/tmp/clspath", "r");
+ size_t nread;
+ if (fd) {
+ int len=strlen(classpath);
+ // prefix bootstrapper.jar
+ strcpy(buf, classpath);
+ strcpy(buf+len, ":");
+ nread = fread(buf+len+1, 1, sizeof buf, fd);
+ if (nread > 0) {
+ classpath = buf;
+ *(classpath+nread) = '\0';
+ int ret = setenv("CLASSPATH", classpath, 1);
+ printf("set clspath %d\n", ret);
+ }
+ }
+ fclose(fd);
+ }
+ char *options = (char*)malloc(strlen(classpath) + strlen("-Djava.class.path=")) + 2;
+ strcpy(options, "-Djava.class.path=");
+ strcpy(options+strlen(options), classpath);
+ printf("CLASSPATH = %s", classpath);
+ jvm_options.optionString = options;
+ args.options = &jvm_options;
+ args.ignoreUnrecognized = 0;
+ int rv;
+ rv = JNI_CreateJavaVM(jvm, (void**)&env, &args);
+ if (rv < 0 || !env) {
+ printf("Unable to Launch JVM %d\n",rv);
+ } else {
+ printf("Launched JVM! %s\n", options);
+ }
+ return env;
+ }
+
+void writeConf(jobject conf, const char *filepath)
+{
+ jclass class_fdesc = (*env).FindClass("java/io/FileDescriptor");
+ // construct a new FileDescriptor
+ jmethodID const_fdesc = (*env).GetMethodID(class_fdesc, "", "()V");
+
+ jobject file = (*env).NewObject(class_fdesc, const_fdesc);
+ jfieldID field_fd = (*env).GetFieldID(class_fdesc, "fd", "I");
+
+ int fd = open(filepath, O_RDWR | O_NONBLOCK | O_CREAT, S_IRWXU);
+ if (fd < 0) {
+ printf("Couldn't open file %s\n", filepath);
+ exit(-1);
+ }
+ (*env).SetIntField(file, field_fd, fd);
+
+ jclass cls_outstream = (*env).FindClass("java/io/FileOutputStream");
+ jmethodID ctor_stream = (*env).GetMethodID(cls_outstream, "",
+ "(Ljava/io/FileDescriptor;)V");
+ if (ctor_stream == NULL) {
+ printf("Couldn't get ctor for FileOutputStream\n");
+ exit(-1);
+ }
+ jobject file_outstream = (*env).NewObject(cls_outstream, ctor_stream, file);
+ if (file_outstream == NULL) {
+ printf("Couldn't create FileOutputStream\n");
+ exit(-1);
+ }
+ jclass class_conf = (*env).FindClass(HADOOP_CONF);
+ jmethodID writeXmlMid = (*env).GetMethodID(class_conf, "writeXml",
+ "(Ljava/io/OutputStream;)V");
+ (*env).CallObjectMethod(conf, writeXmlMid, file_outstream);
+}
+void setup()
+{
+ JavaVM *jvm;
+ jmethodID constructor;
+ pthread_mutex_lock(&count_mutex);
+ if (env == NULL) {
+ env = create_vm(&jvm);
+ if (env == NULL) {
+ exit(-1);
+ }
+ testingUtilClass = (*env).FindClass(HTU_CLASS);
+ //this should be converted to a globalref I think to avoid the underlying java obj getting GC'ed
+ if (testingUtilClass == NULL) {
+ printf("Couldn't find class %s", HTU_CLASS);
+ exit(-1);
+ }
+ jmethodID mid = (*env).GetStaticMethodID(testingUtilClass, "createLocalHTU",
+ "()Lorg/apache/hadoop/hbase/HBaseTestingUtility;");
+ htu = (*env).CallStaticObjectMethod(testingUtilClass, mid);
+ //this should be converted to a globalref I think to avoid the underlying java obj getting GC'ed
+ if (htu == NULL) {
+ printf("Couldn't invoke method createLocalHTU in %s", HTU_CLASS);
+ exit(-1);
+ }
+ printf("Found createLocalHTU");
+ getConnMid = (*env).GetMethodID(testingUtilClass, "getConnection",
+ "()Lorg/apache/hadoop/hbase/client/Connection;");
+ connClass = (*env).FindClass(CONN_CLASS);
+ getAdminMid = (*env).GetMethodID(connClass, "getAdmin",
+ "()Lorg/apache/hadoop/hbase/client/Admin;");
+ getTableMid = (*env).GetMethodID(connClass, "getTable",
+ "(Lorg/apache/hadoop/hbase/TableName;)Lorg/apache/hadoop/hbase/client/Table;");
+ if (getTableMid == NULL) {
+ printf("Couldn't find getConnection\n");
+ exit(-1);
+ }
+ adminClass = (*env).FindClass(ADMIN_CLASS);
+ moveMid = (*env).GetMethodID(adminClass, "move",
+ "([B[B)V");
+ if (moveMid == NULL) {
+ printf("Couldn't find move\n");
+ exit(-1);
+ }
+ createTableMid = (*env).GetMethodID(testingUtilClass, "createTable",
+ "(Lorg/apache/hadoop/hbase/TableName;Ljava/lang/String;)Lorg/apache/hadoop/hbase/client/Table;");
+ createTableWithSplitMid = (*env).GetMethodID(testingUtilClass, "createTable",
+ "(Lorg/apache/hadoop/hbase/TableName;[[B[[B)Lorg/apache/hadoop/hbase/client/Table;");
+ if (createTableWithSplitMid == NULL) {
+ printf("Couldn't find method createTable with split\n");
+ exit(-1);
+ }
+
+ tableNameClass = (*env).FindClass(TABLE_NAME_CLASS);
+ tblNameValueOfMid = (*env).GetStaticMethodID(tableNameClass, "valueOf",
+ "(Ljava/lang/String;)Lorg/apache/hadoop/hbase/TableName;");
+ if (tblNameValueOfMid == NULL) {
+ printf("Couldn't find method valueOf in %s\n", TABLE_NAME_CLASS);
+ exit(-1);
+ }
+ hbaseMiniClusterClass = (*env).FindClass(MINI_CLUSTER_CLASS);
+ stopRSMid = (*env).GetMethodID(hbaseMiniClusterClass, "stopRegionServer",
+ "(I)Lorg/apache/hadoop/hbase/util/JVMClusterUtil$RegionServerThread;");
+ getConfMid = (*env).GetMethodID(hbaseMiniClusterClass, "getConfiguration",
+ "()Lorg/apache/hadoop/conf/Configuration;");
+
+ confClass = (*env).FindClass(HADOOP_CONF);
+ setConfMid = (*env).GetMethodID(confClass, "set",
+ "(Ljava/lang/String;Ljava/lang/String;)V");
+ if (setConfMid == NULL) {
+ printf("Couldn't find method getConf in %s\n", MINI_CLUSTER_CLASS);
+ exit(-1);
+ }
+ confGetMid = (*env).GetMethodID(confClass, "get",
+ "(Ljava/lang/String;)Ljava/lang/String;");
+
+ tableClass = (*env).FindClass(TABLE_CLASS);
+ putMid = (*env).GetMethodID(tableClass, "put",
+ "(Lorg/apache/hadoop/hbase/client/Put;)V");
+ if (putMid == NULL) {
+ printf("Couldn't find method put in %s\n", TABLE_CLASS);
+ exit(-1);
+ }
+ connFactoryClass = (*env).FindClass(CONN_FACTORY_CLASS);
+ createConnMid = (*env).GetStaticMethodID(connFactoryClass, "createConnection",
+ "()Lorg/apache/hadoop/hbase/client/Connection;");
+ if (createConnMid == NULL) {
+ printf("Couldn't find createConnection\n");
+ exit(-1);
+ }
+ putClass = (*env).FindClass(PUT_CLASS);
+ putCtor = (*env).GetMethodID(putClass, "", "([B)V");
+ addColMid = (*env).GetMethodID(putClass, "addColumn",
+ "([B[B[B)Lorg/apache/hadoop/hbase/client/Put;");
+ if (addColMid == NULL) {
+ printf("Couldn't find method addColumn\n");
+ exit(-1);
+ }
+ }
+ pthread_mutex_unlock(&count_mutex);
+}
+
+jobject getHTU()
+{
+ setup();
+ return htu;
+}
+
+JNIEnv *getEnv()
+{
+ setup();
+ return env;
+}
+// converts C char* to Java byte[]
+jbyteArray str_to_byte_array(char *str) {
+ char* p = str;
+ int n = 0;
+ while (*p++) {
+ n++;
+ }
+ if (n == 0) return NULL;
+ jbyteArray arr = (*env).NewByteArray(n);
+ (*env).SetByteArrayRegion(arr, 0, n, (jbyte*)str);
+ return arr;
+}
+
+jobject MiniCluster::create_table(char *tblNam, char *familyName)
+{
+ jstring tblNameStr = (*env).NewStringUTF(tblNam);
+ jobject tblName = (*env).CallStaticObjectMethod(tableNameClass, tblNameValueOfMid,
+ tblNameStr);
+ jstring famStr = (*env).NewStringUTF(familyName);
+ jobject tbl = (*env).CallObjectMethod(htu, createTableMid, tblName, famStr);
+ return tbl;
+}
+jobject MiniCluster::create_table(char *tblNam, char *familyName, char* key1, char*key2)
+{
+ jstring tblNameStr = (*env).NewStringUTF(tblNam);
+ jobject tblName = (*env).CallStaticObjectMethod(tableNameClass, tblNameValueOfMid,
+ tblNameStr);
+ jclass arrayElemType = env->FindClass("[B");
+
+ jobjectArray famArray = env->NewObjectArray(1, arrayElemType, env->NewByteArray(1));
+ env->SetObjectArrayElement(famArray, 0, str_to_byte_array(familyName));
+
+ int len = 2;
+ if (key2 == NULL) len = 1;
+ jobjectArray keyArray = env->NewObjectArray(len, arrayElemType, env->NewByteArray(1));
+
+ env->SetObjectArrayElement(keyArray, 0, str_to_byte_array(key1));
+ if (key2 != NULL) {
+ env->SetObjectArrayElement(keyArray, 1, str_to_byte_array(key2));
+ }
+ jobject tbl = (*env).CallObjectMethod(htu, createTableWithSplitMid, tblName, famArray, keyArray);
+ return tbl;
+}
+jobject MiniCluster::stop_region_server(jobject cluster, int idx)
+{
+ env = getEnv();
+ (*env).CallObjectMethod(cluster, stopRSMid, (jint)idx);
+}
+
+void table_put(jobject tbl, jobject put) {
+ (*env).CallObjectMethod(tbl, putMid, put);
+}
+
+// returns the Configuration for the cluster
+jobject MiniCluster::getConf(jobject cluster)
+{
+ JNIEnv* env = getEnv();
+ return (*env).CallObjectMethod(cluster, getConfMid);
+}
+// return the Admin instance for the local cluster
+jobject getAdmin()
+{
+ JNIEnv* env = getEnv();
+ jobject conn = (*env).CallObjectMethod(getHTU(), getConnMid);
+ jobject admin = (*env).CallObjectMethod(conn, getAdminMid);
+ return admin;
+}
+
+jobject MiniCluster::tablePut(char *table, char *row, char *fam, char *col, char *value)
+{
+ JNIEnv* env = getEnv();
+ jobject conn = (*env).CallObjectMethod(getHTU(), getConnMid);
+ jobject put = env->NewObject(putClass, putCtor, str_to_byte_array(row));
+ if (put == 0) {
+ printf("Couldn't create Put");
+ exit(-1);
+ }
+ (*env).CallObjectMethod(put, addColMid, str_to_byte_array(fam), str_to_byte_array(col),
+ str_to_byte_array(value));
+ jobject tblName = (*env).CallStaticObjectMethod(tableNameClass, tblNameValueOfMid,
+ (*env).NewStringUTF(table));
+ jobject tableObj = (*env).CallObjectMethod(conn, getTableMid, tblName);
+ (*env).CallObjectMethod(tableObj, putMid, put);
+ return tableObj;
+}
+
+// moves region to server
+void MiniCluster::moveRegion(char *region, char *server)
+{
+ jobject admin = getAdmin();
+ (*env).CallObjectMethod(admin, moveMid, str_to_byte_array(region),
+ str_to_byte_array(server));
+}
+
+jobject MiniCluster::start_cluster(int numRegionServers)
+{
+ env = getEnv();
+ jmethodID mid = (*env).GetMethodID(testingUtilClass, "startMiniCluster",
+ "(I)Lorg/apache/hadoop/hbase/MiniHBaseCluster;");
+ if (mid == 0) {
+ printf("Couldn't find method startMiniCluster in the class %s", HTU_CLASS);
+ exit(-1);
+ }
+ cluster = (*env).CallObjectMethod(getHTU(), mid, (jint)numRegionServers);
+ printf("retrieving port");
+ jobject conf = getConf(cluster);
+ jstring jport = (jstring)(*env).CallObjectMethod(conf, confGetMid,
+ (*env).NewStringUTF("hbase.zookeeper.property.clientPort"));
+ const char* port = (*env).GetStringUTFChars(jport, 0);
+ printf("retrieved port %s", port);
+ char buf[34];
+ strcpy(buf, "localhost:");
+ strcpy(buf+10, port);
+ (*env).CallObjectMethod(conf, setConfMid, (*env).NewStringUTF("hbase.zookeeper.quorum"), (*env).NewStringUTF(buf));
+ writeConf(conf, "./build/test-data/client-test/conf/hbase-site.xml");
+ return cluster;
+}
+
+void MiniCluster::stop_cluster()
+{
+ env = getEnv();
+ jmethodID mid = (*env).GetMethodID(testingUtilClass,
+ "shutdownMiniCluster","()V");
+ (*env).CallVoidMethod(getHTU(), mid);
+}
+
+// cluster is the object returned by start_cluster()
+//const char* getConf(jobject cluster, const std::string& key)
+const char* MiniCluster::getConf(jobject cluster, char* key)
+{
+ jobject conf = getConf(cluster);
+ printf("retrieving %s\n", key);
+ jstring jval = (jstring)(*env).CallObjectMethod(conf, confGetMid,
+ (*env).NewStringUTF(key));
+ const char* val = (*env).GetStringUTFChars(jval, 0);
+ printf("Got string %s\n", val);
+ return val;
+}
diff --git a/hbase-native-client/core/mini-cluster.h b/hbase-native-client/core/mini-cluster.h
new file mode 100644
index 0000000..a4afa30
--- /dev/null
+++ b/hbase-native-client/core/mini-cluster.h
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#pragma once
+
+#include "core/client.h"
+#include
+#include "core/configuration.h"
+#include "core/get.h"
+#include "core/hbase_configuration_loader.h"
+#include "core/result.h"
+#include "core/table.h"
+#include "serde/table-name.h"
+#include "jni.h"
+namespace hbase {
+class MiniCluster {
+ public:
+jobject start_cluster(int numRegionServers);
+void stop_cluster();
+jobject create_table(char *tblNam, char *familyName);
+jobject create_table(char *tblNam, char *familyName, char* key1, char*k2);
+jobject stop_region_server(jobject cluster, int idx);
+
+// moves region to server
+void moveRegion(char *region, char *server);
+jobject getConf(jobject cluster);
+const char* getConf(jobject cluster, char* key);
+jobject tablePut(char *table, char *row, char *fam, char *col, char *value);
+};
+} /*namespace hbase*/