diff --git .gitignore .gitignore index 1b1e9d5..40ad9dd 100644 --- .gitignore +++ .gitignore @@ -3,7 +3,7 @@ .project *.settings/ .classpath -/build +*/build/ /.idea/ /logs *target/ diff --git hbase-native-client/core/BUCK hbase-native-client/core/BUCK index c615426..7e9044a 100644 --- hbase-native-client/core/BUCK +++ hbase-native-client/core/BUCK @@ -27,12 +27,16 @@ cxx_library( # TODO: move this out of exported # Once meta lookup works "meta-utils.h", + "get.h", + "time_range.h", ], srcs=[ "cell.cc", "client.cc", "location-cache.cc", "meta-utils.cc", + "get.cc", + "time_range.cc", ], deps=[ "//connection:connection", @@ -59,6 +63,18 @@ cxx_test(name="cell-test", ], deps=[":core", ], run_test_separately=True, ) +cxx_test(name="get-test", + srcs=[ + "get-test.cc", + ], + deps=[":core", ], + run_test_separately=True, ) +cxx_test(name="time_range-test", + srcs=[ + "time_range-test.cc", + ], + deps=[":core", ], + run_test_separately=True, ) cxx_binary(name="simple-client", srcs=["simple-client.cc", ], deps=[":core", "//connection:connection"], ) diff --git hbase-native-client/core/get-test.cc hbase-native-client/core/get-test.cc new file mode 100644 index 0000000..8ed5f2f --- /dev/null +++ hbase-native-client/core/get-test.cc @@ -0,0 +1,150 @@ +/* + * 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/get.h" + +#include +#include + +using namespace hbase; +const int NUMBER_OF_GETS = 5; + +TEST (Get, SingleGet) { + + std::string row_str = "row-test"; + ASSERT_NO_THROW(Get tmp = Get(row_str)); + Get get = Get(row_str); + + get.SetCacheBlocks(true); + get.SetConsistency(hbase::pb::Consistency::STRONG); + get.SetMaxResultsPerColumnFamily(1); + + ASSERT_THROW(get.SetMaxVersions(0), std::runtime_error); + ASSERT_NO_THROW(get.SetMaxVersions(-10)); + ASSERT_THROW(get.SetMaxVersions(std::numeric_limits::max() + 1), + std::runtime_error); + + ASSERT_THROW(get.SetTimeRange(-100, 2000), std::runtime_error); + ASSERT_THROW(get.SetTimeRange(100, -2000), std::runtime_error); + ASSERT_THROW(get.SetTimeRange(1000, 200), std::runtime_error); + + ASSERT_NO_THROW(get.SetMaxVersions()); + ASSERT_NO_THROW(get.SetMaxVersions(2)); + ASSERT_NO_THROW(get.SetTimeRange(0, std::numeric_limits::max())); + + EXPECT_EQ(true, get.CacheBlocks()); + EXPECT_EQ(hbase::pb::Consistency::STRONG, get.Consistency()); + EXPECT_EQ(1, get.MaxResultsPerColumnFamily()); + EXPECT_EQ(2, get.MaxVersions()); + + TimeRange tr = get.Timerange(); + EXPECT_EQ(0, tr.MinTimeStamp()); + EXPECT_EQ(std::numeric_limits::max(), tr.MaxTimeStamp()); + + EXPECT_EQ("row-test", get.Row()); + + EXPECT_EQ(false, get.HasFamilies()); + + get.AddFamily("family-1"); + EXPECT_EQ(true, get.HasFamilies()); + + get.AddColumn("family-1", "column-1"); + get.AddColumn("family-1", "column-2"); + get.AddColumn("family-1", ""); + get.AddColumn("family-1", "column-3"); + get.AddFamily("family-1"); + get.AddFamily("family-2"); + get.AddFamily("family-3"); + +} + +TEST (Get, MultiGet) { + + std::vector gets; + for (int i = 0; i < NUMBER_OF_GETS; i++) { + std::string row_str = "row-test"; + row_str += std::to_string(i); + ASSERT_NO_THROW(Get tmp = Get(row_str)); + Get *get = new Get(row_str); + + get->SetCacheBlocks(true); + get->SetConsistency(hbase::pb::Consistency::STRONG); + get->SetMaxResultsPerColumnFamily(1); + + ASSERT_THROW(get->SetMaxVersions(0), std::runtime_error); + ASSERT_NO_THROW(get->SetMaxVersions(-10)); + ASSERT_THROW( + get->SetMaxVersions(std::numeric_limits::max() + 1), + std::runtime_error); + + ASSERT_THROW(get->SetTimeRange(-100, 2000), std::runtime_error); + ASSERT_THROW(get->SetTimeRange(100, -2000), std::runtime_error); + ASSERT_THROW(get->SetTimeRange(1000, 200), std::runtime_error); + + get->SetMaxVersions(); + get->SetMaxVersions(2); + get->SetTimeRange(0, std::numeric_limits::max()); + + EXPECT_EQ(true, get->CacheBlocks()); + EXPECT_EQ(hbase::pb::Consistency::STRONG, get->Consistency()); + EXPECT_EQ(1, get->MaxResultsPerColumnFamily()); + EXPECT_EQ(2, get->MaxVersions()); + + TimeRange tr = get->Timerange(); + EXPECT_EQ(0, tr.MinTimeStamp()); + EXPECT_EQ(std::numeric_limits::max(), tr.MaxTimeStamp()); + + EXPECT_EQ(false, get->HasFamilies()); + + get->AddFamily("family-1"); + EXPECT_EQ(true, get->HasFamilies()); + + get->AddColumn("family-1", "column-1"); + get->AddColumn("family-1", "column-2"); + get->AddColumn("family-1", ""); + get->AddColumn("family-1", "column-3"); + get->AddFamily("family-1"); + get->AddFamily("family-2"); + get->AddFamily("family-3"); + + gets.push_back(get); + } + EXPECT_EQ(NUMBER_OF_GETS, gets.size()); + + int i = 0; + for (const auto &get : gets) { + std::string row_str = "row-test"; + row_str += std::to_string(i); + EXPECT_EQ(row_str, get->Row()); + i++; + } + + for (const auto &get : gets) { + delete get; + } + gets.clear(); + +} + +TEST (Get, Exception) { + + std::string row(std::numeric_limits::max() + 1, 'X'); + ASSERT_THROW(Get tmp = Get(row), std::runtime_error); + ASSERT_THROW(Get tmp = Get(""), std::runtime_error); +} diff --git hbase-native-client/core/get.cc hbase-native-client/core/get.cc index 9e11332..b0d91ec 100644 --- hbase-native-client/core/get.cc +++ hbase-native-client/core/get.cc @@ -18,3 +18,156 @@ */ #include "core/get.h" +#include +#include +#include + +namespace hbase { + +Get::~Get() { + +} + +Get::Get(const std::string &row) + : row_(row), + max_versions_(1), + cache_blocks_(true), + store_limit_(-1), + store_offset_(0), + check_existence_only_(false), + consistency_(hbase::pb::Consistency::STRONG), + tr_(TimeRange()) { + Get::CheckRow(&row_); + family_map_.clear(); +} + +Get::Get(const Get &cget) { + this->row_ = cget.row_; + this->max_versions_ = cget.max_versions_; + this->cache_blocks_ = cget.cache_blocks_; + this->store_limit_ = cget.store_limit_; + this->store_offset_ = cget.store_offset_; + this->check_existence_only_ = cget.check_existence_only_; + this->consistency_ = cget.consistency_; + this->tr_ = cget.tr_; +} + +Get& Get::operator=(const Get &cget) { + this->row_ = cget.row_; + this->max_versions_ = cget.max_versions_; + this->cache_blocks_ = cget.cache_blocks_; + this->store_limit_ = cget.store_limit_; + this->store_offset_ = cget.store_offset_; + this->check_existence_only_ = cget.check_existence_only_; + this->consistency_ = cget.consistency_; + this->tr_ = cget.tr_; + return *this; +} + +Get& Get::AddFamily(const std::string &family) { + const auto &it = family_map_.find(family); + + /** + * Check if any qualifiers are already present or not. + * Remove all existing qualifiers if the given family is already present in the map + */ + if (family_map_.end() != it) { + it->second.clear(); + } else { + family_map_[family]; + } + return *this; +} + +Get& Get::AddColumn(const std::string &family, const std::string &qualifier) { + const auto &it = std::find(this->family_map_[family].begin(), + this->family_map_[family].end(), qualifier); + + /** + * Check if any qualifiers are already present or not. + * Add only if qualifiers for a given family are not present + */ + if (it == this->family_map_[family].end()) { + this->family_map_[family].push_back(qualifier); + } + return *this; +} + +const std::string& Get::Row() const { + return row_; +} + +hbase::pb::Consistency Get::Consistency() const { + return this->consistency_; +} + +Get &Get::SetConsistency(hbase::pb::Consistency consistency) { + this->consistency_ = consistency; + return *this; +} + +bool Get::HasFamilies() { + return !this->family_map_.empty(); +} + +const FAMILY_MAP &Get::FamilyMap() const { + return this->family_map_; +} + +int Get::MaxVersions() const { + return this->max_versions_; +} + +Get& Get::SetMaxVersions(uint32_t max_versions) { + if (0 == max_versions) + throw std::runtime_error("max_versions must be positive"); + + this->max_versions_ = max_versions; + return *this; +} + +bool Get::CacheBlocks() const { + return this->cache_blocks_; +} + +Get & Get::SetCacheBlocks(bool cache_blocks) { + this->cache_blocks_ = cache_blocks; + return *this; +} + +int Get::MaxResultsPerColumnFamily() const { + return this->store_limit_; +} + +Get& Get::SetMaxResultsPerColumnFamily(int store_limit) { + this->store_limit_ = store_limit; + return *this; +} + +Get& Get::SetTimeRange(long min_timestamp, long max_timestamp) { + this->tr_ = TimeRange(min_timestamp, max_timestamp); + return *this; +} + +Get& Get::SetTimeStamp(long timestamp) { + this->tr_ = TimeRange(timestamp, timestamp + 1); + return *this; +} + +const TimeRange& Get::Timerange() const { + return this->tr_; +} + +void Get::CheckRow(const std::string *row) { + int MAX_ROW_LENGTH = std::numeric_limits::max(); + int row_length = row->size(); + if (0 == row_length) { + throw std::runtime_error("Row length can't be 0"); + } + if (row_length > MAX_ROW_LENGTH) { + throw std::runtime_error( + "Length of " + *row + " is greater than max row size: " + + std::to_string(MAX_ROW_LENGTH)); + } +} +} diff --git hbase-native-client/core/get.h hbase-native-client/core/get.h index b4b5912..28141f2 100644 --- hbase-native-client/core/get.h +++ hbase-native-client/core/get.h @@ -19,4 +19,139 @@ #pragma once -class Get {}; +#include +#include +#include +#include +#include "core/time_range.h" +#include "if/Client.pb.h" + +namespace hbase { + +/** + * @brief Map consisting of column families and qualifiers to be used for Get operation + */ +using FAMILY_MAP = std::map>; + +class Get { + + public: + + /** + * Constructors + */ + Get(const std::string &row); + Get(const Get &cget); + Get& operator=(const Get &cget); + + ~Get(); + + /** + * @brief Returns the maximum number of values to fetch per CF + */ + int MaxVersions() const; + + /** + * @brief Get up to the specified number of versions of each column. default is 1. + * @param max_versions max_versons to set + */ + Get& SetMaxVersions(uint32_t max_versions = 1); + + /** + * @brief Returns whether blocks should be cached for this Get operation. + */ + bool CacheBlocks() const; + + /** + * @brief Set whether blocks should be cached for this Get operation. + * @param cache_blocks to set + */ + Get& SetCacheBlocks(bool cache_blocks); + + /** + * @brief Method for retrieving the get's maximum number of values to return per Column Family + */ + int MaxResultsPerColumnFamily() const; + + /** + * @brief Set the maximum number of values to return per row per Column Family + * @param the store_limit to be set + */ + Get& SetMaxResultsPerColumnFamily(int store_limit); + + /** + * @brief Returns the Get family map (FAMILY_MAP) for this Get operation. + */ + const FAMILY_MAP &FamilyMap() const; + + /** + * @brief Returns the timerange for this Get + */ + const TimeRange& Timerange() const; + + /** + * @brief Get versions of columns only within the specified timestamp range, [minStamp, maxStamp). + * @param minStamp the minimum timestamp, inclusive + * @param maxStamp the maximum timestamp, exclusive + */ + Get& SetTimeRange(long min_timestamp, long max_timestamp); + + /** + * @brief Get versions of columns with the specified timestamp. + * @param The timestamp to be set + */ + Get& SetTimeStamp(long timestamp); + + /** + * @brief Get all columns from the specified family. + * @param family to be retrieved + */ + Get& AddFamily(const std::string &family); + + /** + * @brief Get the column from the specific family with the specified qualifier. + * @param family to be retrieved + * @param qualifier to be retrieved + */ + Get& AddColumn(const std::string &family, const std::string &qualifier); + + /** + * @brief Returns the row for this Get operation + */ + const std::string& Row() const; + + /** + * @brief Returns true if family map (FAMILY_MAP) is non empty false otherwise + */ + bool HasFamilies(); + + /** + * @brief Returns the consistency level for this Get operation + */ + hbase::pb::Consistency Consistency() const; + + /** + * @brief Sets the consistency level for this Get operation + * @param Consistency to be set + */ + Get& SetConsistency(hbase::pb::Consistency consistency); + + private: + std::string row_; + uint32_t max_versions_; + bool cache_blocks_; + int store_limit_; + int store_offset_; + bool check_existence_only_; + FAMILY_MAP family_map_; + hbase::pb::Consistency consistency_; + TimeRange tr_; + + /** + * @brief Checks if the row for this Get operation is proper or not + * @param row Row to check + * @throws std::runtime_error if row is empty or greater than MAX_ROW_LENGTH(i.e. std::numeric_limits::max()) + */ + void CheckRow(const std::string *row); +}; +} diff --git hbase-native-client/core/time_range-test.cc hbase-native-client/core/time_range-test.cc new file mode 100644 index 0000000..c08d52a --- /dev/null +++ hbase-native-client/core/time_range-test.cc @@ -0,0 +1,50 @@ +/* + * 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/time_range.h" + +#include +#include + +using namespace hbase; + +TEST (TimeRange, DefaultObject) { + + TimeRange *timerange_def = nullptr; + ASSERT_NO_THROW(timerange_def = new TimeRange()); + + EXPECT_EQ(0, timerange_def->MinTimeStamp()); + EXPECT_EQ(std::numeric_limits::max(), timerange_def->MaxTimeStamp()); + EXPECT_NE(1000, timerange_def->MinTimeStamp()); + EXPECT_NE(2000, timerange_def->MaxTimeStamp()); + delete timerange_def; + timerange_def = nullptr; +} + +TEST (TimeRange, Exception) { + + // Negative Min TS + ASSERT_THROW(TimeRange(-1000, 2000), std::runtime_error); + + // Negative Max TS + ASSERT_THROW(TimeRange(1000, -2000), std::runtime_error); + + // Min TS > Max TS + ASSERT_THROW(TimeRange(10000, 2000), std::runtime_error); +} diff --git hbase-native-client/core/time_range.cc hbase-native-client/core/time_range.cc new file mode 100644 index 0000000..9e6ed99 --- /dev/null +++ hbase-native-client/core/time_range.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/time_range.h" +#include +#include +#include + +namespace hbase { + +TimeRange::TimeRange() + : min_timestamp_(0L), + max_timestamp_(std::numeric_limits::max()), + all_time_(true) { + +} + +TimeRange::TimeRange(const TimeRange &tr) { + this->all_time_ = tr.all_time_; + this->max_timestamp_ = tr.max_timestamp_; + this->min_timestamp_ = tr.min_timestamp_; +} + +TimeRange &TimeRange::operator =(const TimeRange &tr) { + this->all_time_ = tr.all_time_; + this->max_timestamp_ = tr.max_timestamp_; + this->min_timestamp_ = tr.min_timestamp_; + return *this; +} + +TimeRange::~TimeRange() { + +} + +TimeRange::TimeRange(long min_timestamp) { + this->min_timestamp_ = min_timestamp; + this->max_timestamp_ = std::numeric_limits::max(); + this->all_time_ = false; +} + +TimeRange::TimeRange(long min_timestamp, long max_timestamp) { + if (min_timestamp < 0 || max_timestamp < 0) { + throw std::runtime_error( + "Timestamp cannot be negative. min_timestamp: " + + std::to_string(min_timestamp) + ", max_timestamp:" + + std::to_string(max_timestamp)); + } + if (max_timestamp < min_timestamp) { + throw std::runtime_error( + "max_timestamp [" + std::to_string(max_timestamp) + + "] should be greater than min_timestamp [" + + std::to_string(min_timestamp) + "]"); + } + + this->min_timestamp_ = min_timestamp; + this->max_timestamp_ = max_timestamp; + this->all_time_ = false; +} + +long TimeRange::MinTimeStamp() const { + return this->min_timestamp_; + +} + +long TimeRange::MaxTimeStamp() const { + return this->max_timestamp_; +} + +bool TimeRange::IsAllTime() const { + return this->all_time_; +} +} diff --git hbase-native-client/core/time_range.h hbase-native-client/core/time_range.h new file mode 100644 index 0000000..5c07b4b --- /dev/null +++ hbase-native-client/core/time_range.h @@ -0,0 +1,55 @@ +/* + * 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 + +namespace hbase { +class TimeRange { + + public: + + /** + * @brief Default constructor. Represents interval [0, Long.MAX_VALUE) (allTime) + */ + TimeRange(); + TimeRange(const TimeRange &tr); + TimeRange &operator=(const TimeRange &tr); + /** + * @brief Represents interval [minStamp, Long.MAX_VALUE) + * @param minStamp the minimum timestamp value, inclusive + */ + TimeRange(long min_timestamp); + /** + * @brief Represents interval [minStamp, maxStamp) + * @param minStamp the minimum timestamp, inclusive + * @param maxStamp the maximum timestamp, exclusive + * @throws std::runtime_error if min_timestamp < 0 or max_timestamp < 0 or max_timestamp < min_timestamp + */ + TimeRange(long min_timestamp, long max_timestamp); + long MinTimeStamp() const; + long MaxTimeStamp() const; + bool IsAllTime() const; + ~TimeRange(); + + private: + long min_timestamp_; + long max_timestamp_; + bool all_time_; +}; +}