diff --git hbase-native-client/core/BUCK hbase-native-client/core/BUCK index 20e4736..948e3ce 100644 --- hbase-native-client/core/BUCK +++ hbase-native-client/core/BUCK @@ -32,6 +32,8 @@ cxx_library( "configuration.h", "hbase_configuration_loader.h", "scan.h", + "result.h", + "result_scanner.h", ], srcs=[ "cell.cc", @@ -43,6 +45,8 @@ cxx_library( "configuration.cc", "hbase_configuration_loader.cc", "scan.cc", + "result.cc", + "result_scanner.cc", ], deps=[ "//connection:connection", @@ -87,6 +91,16 @@ cxx_test( srcs=["scan-test.cc",], deps=[":core",], run_test_separately=True,) +cxx_test( + name="result-test", + srcs=["result-test.cc",], + deps=[":core",], + run_test_separately=True,) +cxx_test( + name="result_scanner-test", + srcs=["result_scanner-test.cc",], + deps=[":core",], + run_test_separately=True,) cxx_binary( name="simple-client", srcs=["simple-client.cc",], diff --git hbase-native-client/core/result-test.cc hbase-native-client/core/result-test.cc new file mode 100644 index 0000000..4e11774 --- /dev/null +++ hbase-native-client/core/result-test.cc @@ -0,0 +1,178 @@ +/* + * 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/result.h" + +#include +#include +#include +#include +#include + +#include "core/cell.h" +using namespace hbase; + +void PopulateCells(std::vector> &cells) { + // Populate some Result + for (int i = 0; i < 10; i++) { + std::string row = "row-" + std::to_string(i); + std::string family = "family-" + std::to_string(i); + std::string column = "column-" + std::to_string(i); + std::string value = "value-" + std::to_string(i); + cells.push_back( + std::make_unique < Cell + > (row, family, column, std::numeric_limits::max(), value, CellType::PUT)); + // Add some more cells + switch (i) { + case 5: { + cells.push_back( + std::make_unique < Cell + > ("row-X", family, column, std::numeric_limits::max(), "value-X", CellType::PUT)); + break; + } + case 8: { + cells.push_back( + std::make_unique < Cell + > ("row-X", family, column, std::numeric_limits::max(), "value-X", CellType::PUT)); + cells.push_back( + std::make_unique < Cell + > ("row-Y", family, column, std::numeric_limits::max(), "value-Y", CellType::PUT)); + break; + } + case 9: { + cells.push_back( + std::make_unique < Cell + > ("row-X", family, column, std::numeric_limits::max(), "value-X", CellType::PUT)); + cells.push_back( + std::make_unique < Cell + > ("row-Y", family, column, std::numeric_limits::max(), "value-Y", CellType::PUT)); + cells.push_back( + std::make_unique < Cell + > ("row-Z", family, column, std::numeric_limits::max(), "value-Z", CellType::PUT)); + break; + } + } + } + return; +} + +TEST(Result, EmptyResult) { + Result result; + EXPECT_EQ(true, result.IsEmpty()); +} + +TEST(Result, FilledResult) { + std::vector> cells; + PopulateCells(cells); + + Result result(cells, true, false, false); + EXPECT_EQ(false, result.IsEmpty()); + + // Get Latest Cell for the given family and qualifier. + auto latest_cell(result.ColumnLatestCell("family", "column")); + // Nothing of the above sort is there so it should be nullptr + ASSERT_FALSE(latest_cell.get()); + + // Try to get the latest cell for the given family and qualifier. + latest_cell = result.ColumnLatestCell("family-4", "column-4"); + // Now shouldn't be a nullptr + ASSERT_TRUE(latest_cell.get()); + + // And Value must match too + EXPECT_EQ("value-4", latest_cell->Value()); + + // Value will be nullptr as no such family and qualifier is present + ASSERT_FALSE(result.Value("family-4", "qualifier")); + // Value will be present as family and qualifier is present + ASSERT_TRUE(result.Value("family-4", "column-4")); + // Value should be present and match. + EXPECT_EQ(latest_cell->Value(), (*result.ColumnLatestCell("family-4", "column-4")).Value()); + // Value should be present and match. + EXPECT_EQ("value-7", *result.Value("family-7", "column-7")); + + // Get cells for the given family and qualifier + auto column_cells = result.ColumnCells("family", "column"); + // Size should be 0 + EXPECT_EQ(0, column_cells.size()); + + // Size shouldn't be 0 and Row() and Value() must match + column_cells = result.ColumnCells("family-5", "column-5"); + EXPECT_EQ(2, column_cells.size()); + EXPECT_EQ("row-5", column_cells[0]->Row()); + EXPECT_EQ("row-X", column_cells[1]->Row()); + EXPECT_EQ("value-5", column_cells[0]->Value()); + EXPECT_EQ("value-X", column_cells[1]->Value()); + // Size shouldn't be 0 and Row() and Value() must match + column_cells = result.ColumnCells("family-8", "column-8"); + EXPECT_EQ(3, column_cells.size()); + EXPECT_EQ("row-8", column_cells[0]->Row()); + EXPECT_EQ("row-X", column_cells[1]->Row()); + EXPECT_EQ("row-Y", column_cells[2]->Row()); + EXPECT_EQ("value-8", column_cells[0]->Value()); + EXPECT_EQ("value-X", column_cells[1]->Value()); + EXPECT_EQ("value-Y", column_cells[2]->Value()); + + // Size shouldn't be 0 and Row() and Value() must match + column_cells = result.ColumnCells("family-9", "column-9"); + EXPECT_EQ(4, column_cells.size()); + EXPECT_EQ("row-9", column_cells[0]->Row()); + EXPECT_EQ("row-X", column_cells[1]->Row()); + EXPECT_EQ("row-Y", column_cells[2]->Row()); + EXPECT_EQ("row-Z", column_cells[3]->Row()); + EXPECT_EQ("value-9", column_cells[0]->Value()); + EXPECT_EQ("value-X", column_cells[1]->Value()); + EXPECT_EQ("value-Y", column_cells[2]->Value()); + EXPECT_EQ("value-Z", column_cells[3]->Value()); + + // Test all the Cell values + const auto& result_cells = result.Cells(); + int i = 0, j = 0; + for (const auto &cell : result_cells) { + std::string row = "row-" + std::to_string(i); + std::string family = "family-" + std::to_string(i); + std::string column = "column-" + std::to_string(i); + std::string value = "value-" + std::to_string(i); + switch (j) { + case 6: + case 10: + case 13: { + EXPECT_EQ("row-X", cell->Row()); + ++j; + continue; + } + case 11: + case 14: { + EXPECT_EQ("row-Y", cell->Row()); + ++j; + continue; + } + case 15: { + EXPECT_EQ("row-Z", cell->Row()); + ++j; + continue; + } + } + EXPECT_EQ(row, cell->Row()); + EXPECT_EQ(family, cell->Family()); + EXPECT_EQ(column, cell->Qualifier()); + EXPECT_EQ(value, cell->Value()); + ++i; + ++j; + } +} diff --git hbase-native-client/core/result.cc hbase-native-client/core/result.cc new file mode 100644 index 0000000..ec9ef78 --- /dev/null +++ hbase-native-client/core/result.cc @@ -0,0 +1,91 @@ +/* + * 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/result.h" + +namespace hbase { + +Result::Result() { +} + +Result::~Result() { +} + +Result::Result(const Result& result) { + exists_ = result.exists_; + stale_ = result.stale_; + partial_ = result.partial_; + for (const auto &cell : result.cells_) { + cells_.push_back(std::make_unique < Cell > (*cell)); + } +} + +Result::Result(std::vector>& cells, bool exists, bool stale, bool partial) + : exists_(exists), + stale_(stale), + partial_(partial) { + for (const auto &cell : cells) { + cells_.push_back(std::make_unique < Cell > (*cell)); + } +} + +const std::vector>& Result::Cells() const { + return cells_; +} + +std::vector> Result::ColumnCells(const std::string& family, + const std::string& qualifier) const { + std::vector> column_cells; + for (const auto &cell : cells_) { + if (cell->Family() == family && cell->Qualifier() == qualifier) { + column_cells.push_back(std::make_unique < Cell > (*cell)); + } + } + return column_cells; +} + +std::unique_ptr Result::ColumnLatestCell(const std::string& family, + const std::string& qualifier) const { + std::unique_ptr latest_cell; + for (const auto &cell : cells_) { + if (cell->Family() == family && cell->Qualifier() == qualifier) + latest_cell = std::make_unique < Cell > (*cell); + } + return std::move(latest_cell); +} + +std::unique_ptr Result::Value(const std::string& family, + const std::string& qualifier) const { + std::unique_ptr value; + std::unique_ptr latest_cell(ColumnLatestCell(family, qualifier)); + if (latest_cell.get()) { + value = std::make_unique < std::string > (latest_cell->Value()); + } + return std::move(value); +} + +bool Result::IsEmpty() const { + return cells_.empty(); +} + +const std::string &Result::Row() const { + return row_; +} + +} /* namespace hbase */ diff --git hbase-native-client/core/result.h hbase-native-client/core/result.h new file mode 100644 index 0000000..746d62a --- /dev/null +++ hbase-native-client/core/result.h @@ -0,0 +1,52 @@ +/* + * 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 +#include +#include + +#include "core/cell.h" + +namespace hbase { + +class Result { + public: + Result(); + Result(const Result& result); + Result(std::vector> &cells, bool exists, bool stale, bool partial); + ~Result(); + const std::vector>& Cells() const; + std::vector> ColumnCells(const std::string &family, + const std::string &qualifier) const; + std::unique_ptr ColumnLatestCell(const std::string &family, + const std::string &qualifier) const; + std::unique_ptr Value(const std::string &family, const std::string &qualifier) const; + bool IsEmpty() const; + const std::string &Row() const; + + private: + bool exists_ = false; + bool stale_ = false; + bool partial_ = false; + std::string row_ = ""; + std::vector> cells_; +}; +} /* namespace hbase */ diff --git hbase-native-client/core/result_scanner-test.cc hbase-native-client/core/result_scanner-test.cc new file mode 100644 index 0000000..9cacba2 --- /dev/null +++ hbase-native-client/core/result_scanner-test.cc @@ -0,0 +1,88 @@ +/* + * 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/result_scanner.h" + +#include +#include +#include + +#include + +#include "core/cell.h" +#include "core/result.h" + +using namespace hbase; + +void PopulateCellsForResult(std::vector> &cells, const std::string &suffix) { + // Populate some Result + for (int i = 0; i < 10; i++) { + std::string row = "row-" + suffix + "-" + std::to_string(i); + std::string family = "family-" + std::to_string(i); + std::string column = "column-" + std::to_string(i); + std::string value = "value-" + suffix + "-" + std::to_string(i); + cells.push_back( + std::make_unique < Cell + > (row, family, column, std::numeric_limits::max(), value, CellType::PUT)); + } + return; +} + +TEST(ResultScanner, Object) { + std::vector> results; + for (int i = 0; i < 5; i++) { + std::string suffix = "res-" + std::to_string(i); + std::vector> cells; + PopulateCellsForResult(cells, suffix); + results.push_back(std::make_unique < Result > (cells, true, false, false)); + } + + + ResultScanner res_scanner(results); + + std::vector> res_rows(res_scanner.Next(3)); + ASSERT_EQ(3, res_rows.size()); + int i = 0; + for (const auto &result : res_rows) { + std::string value = "value-res-" + std::to_string(i) + "-4"; + ASSERT_EQ(value, *result->Value("family-4", "column-4")); + i += 1; + } + + res_rows = res_scanner.Next(5); + ASSERT_EQ(5, res_rows.size()); + i = 0; + for (const auto &result : res_rows) { + std::string value = "value-res-" + std::to_string(i) + "-4"; + ASSERT_EQ(value, *result->Value("family-4", "column-4")); + i += 1; + } + + i = 0; + while (std::unique_ptr result = res_scanner.Next()) { + ASSERT_TRUE(result); + std::string value = "value-res-" + std::to_string(i) + "-4"; + ASSERT_EQ(value, *result->Value("family-4", "column-4")); + i += 1; + } + std::unique_ptr result = res_scanner.Next(); + ASSERT_FALSE(result); + +} + diff --git hbase-native-client/core/result_scanner.cc hbase-native-client/core/result_scanner.cc new file mode 100644 index 0000000..e22166d --- /dev/null +++ hbase-native-client/core/result_scanner.cc @@ -0,0 +1,69 @@ +/* + * 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/result_scanner.h" + +namespace hbase { + +ResultScanner::ResultScanner(std::vector> &results) { + for (const auto &result : results) { + results_.push_back(std::make_unique < Result > (*result)); + } +} + +ResultScanner::ResultScanner(const ResultScanner& res_scanner) { + for (const auto &result : res_scanner.results_) { + results_.push_back(std::make_unique < Result > (*result)); + } +} + +ResultScanner::~ResultScanner() { + results_.clear(); +} + +std::unique_ptr ResultScanner::Next() { + std::unique_ptr result; + if (results_.size() > 0) { + result = std::make_unique < Result > (*results_.front()); + results_.erase(results_.begin()); + } + return std::move(result); +} + +std::vector> ResultScanner::Next(int num_rows) { + std::vector> results; + for (int i = 0; i < num_rows; i++) { + std::unique_ptr result = std::make_unique < Result > (*results_[i]); + if (result.get()) { + results.push_back(std::move(result)); + } + } + return results; +} + +bool ResultScanner::RenewLease() const { + return true; +} + +void ResultScanner::Close() { + close_scanner_ = true; +} + +} /* namespace hbase */ + diff --git hbase-native-client/core/result_scanner.h hbase-native-client/core/result_scanner.h new file mode 100644 index 0000000..37520b8 --- /dev/null +++ hbase-native-client/core/result_scanner.h @@ -0,0 +1,43 @@ +/* + * 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 +#include + +#include "core/result.h" +namespace hbase { + +class ResultScanner { + public: + ResultScanner(std::vector> &results); + ResultScanner(const ResultScanner &res_scanner); + ~ResultScanner(); + std::unique_ptr Next(); + std::vector> Next(int num_rows); + bool RenewLease() const; + void Close(); + + private: + bool close_scanner_ = false; + std::vector> results_; +}; + +} /* namespace hbase */