| /** |
| * 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 <stdio.h> |
| #include <unistd.h> |
| #include <sys/time.h> |
| #include <poll.h> |
| |
| #include <iostream> |
| |
| #include <protocol/TBinaryProtocol.h> |
| #include <transport/TSocket.h> |
| #include <transport/TTransportUtils.h> |
| |
| #include "Hbase.h" |
| |
| using namespace apache::thrift; |
| using namespace apache::thrift::protocol; |
| using namespace apache::thrift::transport; |
| |
| using namespace apache::hadoop::hbase::thrift; |
| |
| namespace { |
| |
| typedef std::vector<std::string> StrVec; |
| typedef std::map<std::string,std::string> StrMap; |
| typedef std::vector<ColumnDescriptor> ColVec; |
| typedef std::map<std::string,ColumnDescriptor> ColMap; |
| typedef std::vector<TCell> CellVec; |
| typedef std::map<std::string,TCell> CellMap; |
| |
| |
| static void |
| printRow(const std::vector<TRowResult> &rowResult) |
| { |
| for (size_t i = 0; i < rowResult.size(); i++) { |
| std::cout << "row: " << rowResult[i].row << ", cols: "; |
| for (CellMap::const_iterator it = rowResult[i].columns.begin(); |
| it != rowResult[i].columns.end(); ++it) { |
| std::cout << it->first << " => " << it->second.value << "; "; |
| } |
| std::cout << std::endl; |
| } |
| } |
| |
| static void |
| printVersions(const std::string &row, const CellVec &versions) |
| { |
| std::cout << "row: " << row << ", values: "; |
| for (CellVec::const_iterator it = versions.begin(); it != versions.end(); ++it) { |
| std::cout << (*it).value << "; "; |
| } |
| std::cout << std::endl; |
| } |
| |
| } |
| |
| int |
| main(int argc, char** argv) |
| { |
| if (argc < 3) { |
| std::cerr << "Invalid arguments!\n" << "Usage: DemoClient host port" << std::endl; |
| return -1; |
| } |
| bool isFramed = false; |
| std::shared_ptr<TTransport> socket = std::make_shared<TSocket>(argv[1], std::stoi(argv[2])); |
| std::shared_ptr<TTransport> transport; |
| |
| if (isFramed) { |
| transport = std::make_shared<TFramedTransport>(socket); |
| } else { |
| transport = std::make_shared<TBufferedTransport>(socket); |
| } |
| std::shared_ptr<TProtocol> protocol = std::make_shared<TBinaryProtocol>(transport); |
| |
| const std::map<Text, Text> dummyAttributes; // see HBASE-6806 HBASE-4658 |
| HbaseClient client(protocol); |
| try { |
| transport->open(); |
| |
| std::string t("demo_table"); |
| |
| // |
| // Scan all tables, look for the demo table and delete it. |
| // |
| std::cout << "scanning tables..." << std::endl; |
| StrVec tables; |
| client.getTableNames(tables); |
| for (StrVec::const_iterator it = tables.begin(); it != tables.end(); ++it) { |
| std::cout << " found: " << *it << std::endl; |
| if (t == *it) { |
| if (client.isTableEnabled(*it)) { |
| std::cout << " disabling table: " << *it << std::endl; |
| client.disableTable(*it); |
| } |
| std::cout << " deleting table: " << *it << std::endl; |
| client.deleteTable(*it); |
| } |
| } |
| |
| // |
| // Create the demo table with two column families, entry: and unused: |
| // |
| ColVec columns; |
| columns.push_back(ColumnDescriptor()); |
| columns.back().name = "entry:"; |
| columns.back().maxVersions = 10; |
| columns.push_back(ColumnDescriptor()); |
| columns.back().name = "unused:"; |
| |
| std::cout << "creating table: " << t << std::endl; |
| try { |
| client.createTable(t, columns); |
| } catch (const AlreadyExists &ae) { |
| std::cerr << "WARN: " << ae.message << std::endl; |
| } |
| |
| ColMap columnMap; |
| client.getColumnDescriptors(columnMap, t); |
| std::cout << "column families in " << t << ": " << std::endl; |
| for (ColMap::const_iterator it = columnMap.begin(); it != columnMap.end(); ++it) { |
| std::cout << " column: " << it->second.name << ", maxVer: " << it->second.maxVersions << std::endl; |
| } |
| |
| // |
| // Test UTF-8 handling |
| // |
| std::string invalid("foo-\xfc\xa1\xa1\xa1\xa1\xa1"); |
| std::string valid("foo-\xE7\x94\x9F\xE3\x83\x93\xE3\x83\xBC\xE3\x83\xAB"); |
| |
| // non-utf8 is fine for data |
| std::vector<Mutation> mutations; |
| mutations.push_back(Mutation()); |
| mutations.back().column = "entry:foo"; |
| mutations.back().value = invalid; |
| client.mutateRow(t, "foo", mutations, dummyAttributes); |
| |
| // try empty strings |
| mutations.clear(); |
| mutations.push_back(Mutation()); |
| mutations.back().column = "entry:"; |
| mutations.back().value = ""; |
| client.mutateRow(t, "", mutations, dummyAttributes); |
| |
| // this row name is valid utf8 |
| mutations.clear(); |
| mutations.push_back(Mutation()); |
| mutations.back().column = "entry:foo"; |
| mutations.back().value = valid; |
| client.mutateRow(t, valid, mutations, dummyAttributes); |
| |
| // non-utf8 is now allowed in row names because HBase stores values as binary |
| mutations.clear(); |
| mutations.push_back(Mutation()); |
| mutations.back().column = "entry:foo"; |
| mutations.back().value = invalid; |
| client.mutateRow(t, invalid, mutations, dummyAttributes); |
| |
| // Run a scanner on the rows we just created |
| StrVec columnNames; |
| columnNames.push_back("entry:"); |
| |
| std::cout << "Starting scanner..." << std::endl; |
| int scanner = client.scannerOpen(t, "", columnNames, dummyAttributes); |
| try { |
| while (true) { |
| std::vector<TRowResult> value; |
| client.scannerGet(value, scanner); |
| if (value.size() == 0) |
| break; |
| printRow(value); |
| } |
| } catch (const IOError &ioe) { |
| std::cerr << "FATAL: Scanner raised IOError" << std::endl; |
| } |
| |
| client.scannerClose(scanner); |
| std::cout << "Scanner finished" << std::endl; |
| |
| // |
| // Run some operations on a bunch of rows. |
| // |
| for (int i = 100; i >= 0; --i) { |
| // format row keys as "00000" to "00100" |
| char buf[32]; |
| sprintf(buf, "%05d", i); |
| std::string row(buf); |
| std::vector<TRowResult> rowResult; |
| |
| mutations.clear(); |
| mutations.push_back(Mutation()); |
| mutations.back().column = "unused:"; |
| mutations.back().value = "DELETE_ME"; |
| client.mutateRow(t, row, mutations, dummyAttributes); |
| client.getRow(rowResult, t, row, dummyAttributes); |
| printRow(rowResult); |
| client.deleteAllRow(t, row, dummyAttributes); |
| |
| mutations.clear(); |
| mutations.push_back(Mutation()); |
| mutations.back().column = "entry:num"; |
| mutations.back().value = "0"; |
| mutations.push_back(Mutation()); |
| mutations.back().column = "entry:foo"; |
| mutations.back().value = "FOO"; |
| client.mutateRow(t, row, mutations, dummyAttributes); |
| client.getRow(rowResult, t, row, dummyAttributes); |
| printRow(rowResult); |
| |
| // sleep to force later timestamp |
| poll(0, 0, 50); |
| |
| mutations.clear(); |
| mutations.push_back(Mutation()); |
| mutations.back().column = "entry:foo"; |
| mutations.back().isDelete = true; |
| mutations.push_back(Mutation()); |
| mutations.back().column = "entry:num"; |
| mutations.back().value = "-1"; |
| client.mutateRow(t, row, mutations, dummyAttributes); |
| client.getRow(rowResult, t, row, dummyAttributes); |
| printRow(rowResult); |
| |
| mutations.clear(); |
| mutations.push_back(Mutation()); |
| mutations.back().column = "entry:num"; |
| mutations.back().value = std::to_string(i); |
| mutations.push_back(Mutation()); |
| mutations.back().column = "entry:sqr"; |
| mutations.back().value = std::to_string(i * i); |
| client.mutateRow(t, row, mutations, dummyAttributes); |
| client.getRow(rowResult, t, row, dummyAttributes); |
| printRow(rowResult); |
| |
| mutations.clear(); |
| mutations.push_back(Mutation()); |
| mutations.back().column = "entry:num"; |
| mutations.back().value = "-999"; |
| mutations.push_back(Mutation()); |
| mutations.back().column = "entry:sqr"; |
| mutations.back().isDelete = true; |
| client.mutateRowTs(t, row, mutations, 1, dummyAttributes); // shouldn't override latest |
| client.getRow(rowResult, t, row, dummyAttributes); |
| printRow(rowResult); |
| |
| CellVec versions; |
| client.getVer(versions, t, row, "entry:num", 10, dummyAttributes); |
| printVersions(row, versions); |
| assert(versions.size()); |
| std::cout << std::endl; |
| |
| try { |
| std::vector<TCell> value; |
| client.get(value, t, row, "entry:foo", dummyAttributes); |
| if (value.size()) { |
| std::cerr << "FATAL: shouldn't get here!" << std::endl; |
| return -1; |
| } |
| } catch (const IOError &ioe) { |
| // blank |
| } |
| } |
| |
| // scan all rows/columns |
| |
| columnNames.clear(); |
| client.getColumnDescriptors(columnMap, t); |
| std::cout << "The number of columns: " << columnMap.size() << std::endl; |
| for (ColMap::const_iterator it = columnMap.begin(); it != columnMap.end(); ++it) { |
| std::cout << " column with name: " + it->second.name << std::endl; |
| columnNames.push_back(it->second.name); |
| } |
| std::cout << std::endl; |
| |
| std::cout << "Starting scanner..." << std::endl; |
| scanner = client.scannerOpenWithStop(t, "00020", "00040", columnNames, dummyAttributes); |
| try { |
| while (true) { |
| std::vector<TRowResult> value; |
| client.scannerGet(value, scanner); |
| if (value.size() == 0) |
| break; |
| printRow(value); |
| } |
| } catch (const IOError &ioe) { |
| std::cerr << "FATAL: Scanner raised IOError" << std::endl; |
| } |
| |
| client.scannerClose(scanner); |
| std::cout << "Scanner finished" << std::endl; |
| |
| transport->close(); |
| } catch (const TException &tx) { |
| std::cerr << "ERROR: " << tx.what() << std::endl; |
| } |
| } |