1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #include <stdio.h>
20 #include <unistd.h>
21 #include <sys/time.h>
22 #include <poll.h>
23 
24 #include <iostream>
25 
26 #include <boost/lexical_cast.hpp>
27 #include <protocol/TBinaryProtocol.h>
28 #include <transport/TSocket.h>
29 #include <transport/TTransportUtils.h>
30 
31 #include "Hbase.h"
32 
33 using namespace apache::thrift;
34 using namespace apache::thrift::protocol;
35 using namespace apache::thrift::transport;
36 
37 using namespace apache::hadoop::hbase::thrift;
38 
39 namespace {
40 
41 typedef std::vector<std::string> StrVec;
42 typedef std::map<std::string,std::string> StrMap;
43 typedef std::vector<ColumnDescriptor> ColVec;
44 typedef std::map<std::string,ColumnDescriptor> ColMap;
45 typedef std::vector<TCell> CellVec;
46 typedef std::map<std::string,TCell> CellMap;
47 
48 
49 static void
printRow(const std::vector<TRowResult> & rowResult)50 printRow(const std::vector<TRowResult> &rowResult)
51 {
52   for (size_t i = 0; i < rowResult.size(); i++) {
53     std::cout << "row: " << rowResult[i].row << ", cols: ";
54     for (CellMap::const_iterator it = rowResult[i].columns.begin();
55          it != rowResult[i].columns.end(); ++it) {
56       std::cout << it->first << " => " << it->second.value << "; ";
57     }
58     std::cout << std::endl;
59   }
60 }
61 
62 static void
printVersions(const std::string & row,const CellVec & versions)63 printVersions(const std::string &row, const CellVec &versions)
64 {
65   std::cout << "row: " << row << ", values: ";
66   for (CellVec::const_iterator it = versions.begin(); it != versions.end(); ++it) {
67     std::cout << (*it).value << "; ";
68   }
69   std::cout << std::endl;
70 }
71 
72 }
73 
74 int
main(int argc,char ** argv)75 main(int argc, char** argv)
76 {
77   if (argc < 3) {
78     std::cerr << "Invalid arguments!\n" << "Usage: DemoClient host port" << std::endl;
79     return -1;
80   }
81   bool isFramed = false;
82   boost::shared_ptr<TTransport> socket(new TSocket(argv[1], boost::lexical_cast<int>(argv[2])));
83   boost::shared_ptr<TTransport> transport;
84 
85   if (isFramed) {
86     transport.reset(new TFramedTransport(socket));
87   } else {
88     transport.reset(new TBufferedTransport(socket));
89   }
90   boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
91 
92   const std::map<Text, Text>  dummyAttributes; // see HBASE-6806 HBASE-4658
93   HbaseClient client(protocol);
94   try {
95     transport->open();
96 
97     std::string t("demo_table");
98 
99     //
100     // Scan all tables, look for the demo table and delete it.
101     //
102     std::cout << "scanning tables..." << std::endl;
103     StrVec tables;
104     client.getTableNames(tables);
105     for (StrVec::const_iterator it = tables.begin(); it != tables.end(); ++it) {
106       std::cout << "  found: " << *it << std::endl;
107       if (t == *it) {
108         if (client.isTableEnabled(*it)) {
109           std::cout << "    disabling table: " << *it << std::endl;
110           client.disableTable(*it);
111         }
112         std::cout << "    deleting table: " << *it << std::endl;
113         client.deleteTable(*it);
114       }
115     }
116 
117     //
118     // Create the demo table with two column families, entry: and unused:
119     //
120     ColVec columns;
121     columns.push_back(ColumnDescriptor());
122     columns.back().name = "entry:";
123     columns.back().maxVersions = 10;
124     columns.push_back(ColumnDescriptor());
125     columns.back().name = "unused:";
126 
127     std::cout << "creating table: " << t << std::endl;
128     try {
129       client.createTable(t, columns);
130     } catch (const AlreadyExists &ae) {
131       std::cerr << "WARN: " << ae.message << std::endl;
132     }
133 
134     ColMap columnMap;
135     client.getColumnDescriptors(columnMap, t);
136     std::cout << "column families in " << t << ": " << std::endl;
137     for (ColMap::const_iterator it = columnMap.begin(); it != columnMap.end(); ++it) {
138       std::cout << "  column: " << it->second.name << ", maxVer: " << it->second.maxVersions << std::endl;
139     }
140 
141     //
142     // Test UTF-8 handling
143     //
144     std::string invalid("foo-\xfc\xa1\xa1\xa1\xa1\xa1");
145     std::string valid("foo-\xE7\x94\x9F\xE3\x83\x93\xE3\x83\xBC\xE3\x83\xAB");
146 
147     // non-utf8 is fine for data
148     std::vector<Mutation> mutations;
149     mutations.push_back(Mutation());
150     mutations.back().column = "entry:foo";
151     mutations.back().value = invalid;
152     client.mutateRow(t, "foo", mutations, dummyAttributes);
153 
154     // try empty strings
155     mutations.clear();
156     mutations.push_back(Mutation());
157     mutations.back().column = "entry:";
158     mutations.back().value = "";
159     client.mutateRow(t, "", mutations, dummyAttributes);
160 
161     // this row name is valid utf8
162     mutations.clear();
163     mutations.push_back(Mutation());
164     mutations.back().column = "entry:foo";
165     mutations.back().value = valid;
166     client.mutateRow(t, valid, mutations, dummyAttributes);
167 
168     // non-utf8 is now allowed in row names because HBase stores values as binary
169     mutations.clear();
170     mutations.push_back(Mutation());
171     mutations.back().column = "entry:foo";
172     mutations.back().value = invalid;
173     client.mutateRow(t, invalid, mutations, dummyAttributes);
174 
175     // Run a scanner on the rows we just created
176     StrVec columnNames;
177     columnNames.push_back("entry:");
178 
179     std::cout << "Starting scanner..." << std::endl;
180     int scanner = client.scannerOpen(t, "", columnNames, dummyAttributes);
181     try {
182       while (true) {
183         std::vector<TRowResult> value;
184         client.scannerGet(value, scanner);
185         if (value.size() == 0)
186           break;
187         printRow(value);
188       }
189     } catch (const IOError &ioe) {
190       std::cerr << "FATAL: Scanner raised IOError" << std::endl;
191     }
192 
193     client.scannerClose(scanner);
194     std::cout << "Scanner finished" << std::endl;
195 
196     //
197     // Run some operations on a bunch of rows.
198     //
199     for (int i = 100; i >= 0; --i) {
200       // format row keys as "00000" to "00100"
201       char buf[32];
202       sprintf(buf, "%05d", i);
203       std::string row(buf);
204       std::vector<TRowResult> rowResult;
205 
206       mutations.clear();
207       mutations.push_back(Mutation());
208       mutations.back().column = "unused:";
209       mutations.back().value = "DELETE_ME";
210       client.mutateRow(t, row, mutations, dummyAttributes);
211       client.getRow(rowResult, t, row, dummyAttributes);
212       printRow(rowResult);
213       client.deleteAllRow(t, row, dummyAttributes);
214 
215       mutations.clear();
216       mutations.push_back(Mutation());
217       mutations.back().column = "entry:num";
218       mutations.back().value = "0";
219       mutations.push_back(Mutation());
220       mutations.back().column = "entry:foo";
221       mutations.back().value = "FOO";
222       client.mutateRow(t, row, mutations, dummyAttributes);
223       client.getRow(rowResult, t, row, dummyAttributes);
224       printRow(rowResult);
225 
226       // sleep to force later timestamp
227       poll(0, 0, 50);
228 
229       mutations.clear();
230       mutations.push_back(Mutation());
231       mutations.back().column = "entry:foo";
232       mutations.back().isDelete = true;
233       mutations.push_back(Mutation());
234       mutations.back().column = "entry:num";
235       mutations.back().value = "-1";
236       client.mutateRow(t, row, mutations, dummyAttributes);
237       client.getRow(rowResult, t, row, dummyAttributes);
238       printRow(rowResult);
239 
240       mutations.clear();
241       mutations.push_back(Mutation());
242       mutations.back().column = "entry:num";
243       mutations.back().value = boost::lexical_cast<std::string>(i);
244       mutations.push_back(Mutation());
245       mutations.back().column = "entry:sqr";
246       mutations.back().value = boost::lexical_cast<std::string>(i*i);
247       client.mutateRow(t, row, mutations, dummyAttributes);
248       client.getRow(rowResult, t, row, dummyAttributes);
249       printRow(rowResult);
250 
251       mutations.clear();
252       mutations.push_back(Mutation());
253       mutations.back().column = "entry:num";
254       mutations.back().value = "-999";
255       mutations.push_back(Mutation());
256       mutations.back().column = "entry:sqr";
257       mutations.back().isDelete = true;
258       client.mutateRowTs(t, row, mutations, 1, dummyAttributes); // shouldn't override latest
259       client.getRow(rowResult, t, row, dummyAttributes);
260       printRow(rowResult);
261 
262       CellVec versions;
263       client.getVer(versions, t, row, "entry:num", 10, dummyAttributes);
264       printVersions(row, versions);
265       assert(versions.size());
266       std::cout << std::endl;
267 
268       try {
269         std::vector<TCell> value;
270         client.get(value, t, row, "entry:foo", dummyAttributes);
271         if (value.size()) {
272           std::cerr << "FATAL: shouldn't get here!" << std::endl;
273           return -1;
274         }
275       } catch (const IOError &ioe) {
276         // blank
277       }
278     }
279 
280     // scan all rows/columns
281 
282     columnNames.clear();
283     client.getColumnDescriptors(columnMap, t);
284     std::cout << "The number of columns: " << columnMap.size() << std::endl;
285     for (ColMap::const_iterator it = columnMap.begin(); it != columnMap.end(); ++it) {
286       std::cout << " column with name: " + it->second.name << std::endl;
287       columnNames.push_back(it->second.name);
288     }
289     std::cout << std::endl;
290 
291     std::cout << "Starting scanner..." << std::endl;
292     scanner = client.scannerOpenWithStop(t, "00020", "00040", columnNames, dummyAttributes);
293     try {
294       while (true) {
295         std::vector<TRowResult> value;
296         client.scannerGet(value, scanner);
297         if (value.size() == 0)
298           break;
299         printRow(value);
300       }
301     } catch (const IOError &ioe) {
302       std::cerr << "FATAL: Scanner raised IOError" << std::endl;
303     }
304 
305     client.scannerClose(scanner);
306     std::cout << "Scanner finished" << std::endl;
307 
308     transport->close();
309   } catch (const TException &tx) {
310     std::cerr << "ERROR: " << tx.what() << std::endl;
311   }
312 }
313