InIndex: src/java/org/apache/hadoop/hbase/thrift/Hbase.thrift =================================================================== --- src/java/org/apache/hadoop/hbase/thrift/Hbase.thrift (revision 692532) +++ src/java/org/apache/hadoop/hbase/thrift/Hbase.thrift (working copy) @@ -34,6 +34,7 @@ namespace java org.apache.hadoop.hbase.thrift.generated namespace cpp apache.hadoop.hbase.thrift namespace rb Apache.Hadoop.Hbase.Thrift +namespace py hbase // note: other language namespaces tbd... Index: src/examples/thrift/DemoClient.java =================================================================== --- src/examples/thrift/DemoClient.java (revision 692532) +++ src/examples/thrift/DemoClient.java (working copy) @@ -47,14 +47,30 @@ import com.facebook.thrift.transport.TSocket; import com.facebook.thrift.transport.TTransport; +/* + * Instructions: + * 1. Run Thrift to generate the java module HBase + * thrift --gen java ../../../src/java/org/apache/hadoop/hbase/thrift/Hbase.thrift + * 2. Acquire a jar of compiled Thrift java classes. As of this writing, HBase ships + * with this jar (libthrift-[VERSION].jar). If this jar is not present, or it is + * out-of-date with your current version of thrift, you can compile the jar + * yourself by executing {ant} in {$THRIFT_HOME}/lib/java. + * 3. Compile and execute this file with both the libthrift jar and the gen-java/ + * directory in the classpath. This can be done on the command-line with the + * following lines: (from the directory containing this file and gen-java/) + * + * javac -cp /path/to/libthrift/jar.jar:gen-java/ DemoClient.java + * mv DemoClient.class gen-java/org/apache/hadoop/hbase/thrift/ + * java -cp /path/to/libthrift/jar.jar:gen-java/ org.apache.hadoop.hbase.thrift.DemoClient + * + */ public class DemoClient { protected int port = 9090; CharsetDecoder decoder = null; public static void main(String[] args) - throws IOError, TException, NotFound, UnsupportedEncodingException, IllegalArgument, AlreadyExists - { + throws IOError, TException, NotFound, UnsupportedEncodingException, IllegalArgument, AlreadyExists { DemoClient client = new DemoClient(); client.run(); } @@ -100,9 +116,10 @@ for (byte[] name : client.getTableNames()) { System.out.println(" found: " + utf8(name)); if (utf8(name).equals(utf8(t))) { - System.out.println(" disabling table: " + utf8(name)); - if (client.isTableEnabled(name)) + if (client.isTableEnabled(name)) { + System.out.println(" disabling table: " + utf8(name)); client.disableTable(name); + } System.out.println(" deleting table: " + utf8(name)); client.deleteTable(name); } @@ -154,7 +171,7 @@ // this row name is valid utf8 mutations = new ArrayList(); mutations.add(new Mutation(false, bytes("entry:foo"), valid)); - client.mutateRow(t, bytes("foo"), mutations); + client.mutateRow(t, valid, mutations); // non-utf8 is not allowed in row names try { @@ -264,7 +281,7 @@ columnNames.clear(); for (ColumnDescriptor col2 : client.getColumnDescriptors(t).values()) { - System.out.println("column name is " + new String(col2.name)); + System.out.println("column with name: " + new String(col2.name)); System.out.println(col2.toString()); columnNames.add((utf8(col2.name) + ":").getBytes()); } Index: src/examples/thrift/DemoClient.cpp =================================================================== --- src/examples/thrift/DemoClient.cpp (revision 692532) +++ src/examples/thrift/DemoClient.cpp (working copy) @@ -17,6 +17,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +/* + * Instructions: + * 1. Run Thrift to generate the cpp module HBase + * thrift --gen cpp ../../../src/java/org/apache/hadoop/hbase/thrift/Hbase.thrift + * 2. Execute {make}. + * 3. Execute {./DemoClient}. + */ + #include #include #include @@ -40,30 +49,27 @@ typedef std::map StrMap; typedef std::vector ColVec; typedef std::map ColMap; +typedef std::vector CellVec; +typedef std::map CellMap; static void -printRow(const std::string &row, const StrMap &columns) +printRow(const TRowResult &rowResult) { - std::cout << "row: " << row << ", cols: "; - for (StrMap::const_iterator it = columns.begin(); it != columns.end(); ++it) { - std::cout << it->first << " => " << it->second << "; "; + std::cout << "row: " << rowResult.row << ", cols: "; + for (CellMap::const_iterator it = rowResult.columns.begin(); + it != rowResult.columns.end(); ++it) { + std::cout << it->first << " => " << it->second.value << "; "; } std::cout << std::endl; } -static void -printEntry(const ScanEntry &entry) -{ - printRow(entry.row, entry.columns); -} - static void -printVersions(const std::string &row, const StrVec &versions) +printVersions(const std::string &row, const CellVec &versions) { std::cout << "row: " << row << ", values: "; - for (StrVec::const_iterator it = versions.begin(); it != versions.end(); ++it) { - std::cout << *it << "; "; + for (CellVec::const_iterator it = versions.begin(); it != versions.end(); ++it) { + std::cout << (*it).value << "; "; } std::cout << std::endl; } @@ -90,6 +96,10 @@ 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); } @@ -126,17 +136,33 @@ std::string valid("foo-\xE7\x94\x9F\xE3\x83\x93\xE3\x83\xBC\xE3\x83\xAB"); // non-utf8 is fine for data - client.put(t, "foo", "entry:foo", invalid); + std::vector mutations; + mutations.push_back(Mutation()); + mutations.back().column = "entry:foo"; + mutations.back().value = invalid; + client.mutateRow(t, "foo", mutations); // try empty strings - client.put(t, "", "entry:", ""); + mutations.clear(); + mutations.push_back(Mutation()); + mutations.back().column = "entry:"; + mutations.back().value = ""; + client.mutateRow(t, "", mutations); // this row name is valid utf8 - client.put(t, valid, "entry:foo", valid); + mutations.clear(); + mutations.push_back(Mutation()); + mutations.back().column = "entry:foo"; + mutations.back().value = valid; + client.mutateRow(t, valid, mutations); // non-utf8 is not allowed in row names try { - client.put(t, invalid, "entry:foo", invalid); + mutations.clear(); + mutations.push_back(Mutation()); + mutations.back().column = "entry:foo"; + mutations.back().value = invalid; + client.mutateRow(t, invalid, mutations); std::cout << "FATAL: shouldn't get here!" << std::endl; exit(-1); } catch (IOError e) { @@ -151,9 +177,9 @@ int scanner = client.scannerOpen(t, "", columnNames); try { while (true) { - ScanEntry value; + TRowResult value; client.scannerGet(value, scanner); - printEntry(value); + printRow(value); } } catch (NotFound &nf) { client.scannerClose(scanner); @@ -169,22 +195,32 @@ sprintf(buf, "%0.5d", i); std::string row(buf); - StrMap values; + TRowResult rowResult; - client.put(t, row, "unused:", "DELETE_ME"); - client.getRow(values, t, row); - printRow(row, values); + mutations.clear(); + mutations.push_back(Mutation()); + mutations.back().column = "unused:"; + mutations.back().value = "DELETE_ME"; + client.mutateRow(t, row, mutations); + client.getRow(rowResult, t, row); + printRow(rowResult); client.deleteAllRow(t, row); - client.put(t, row, "entry:num", "0"); - client.put(t, row, "entry:foo", "FOO"); - client.getRow(values, t, row); - printRow(row, values); + 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); + client.getRow(rowResult, t, row); + printRow(rowResult); // sleep to force later timestamp poll(0, 0, 50); - std::vector mutations; + mutations.clear(); mutations.push_back(Mutation()); mutations.back().column = "entry:foo"; mutations.back().isDelete = true; @@ -192,33 +228,39 @@ mutations.back().column = "entry:num"; mutations.back().value = "-1"; client.mutateRow(t, row, mutations); - client.getRow(values, t, row); - printRow(row, values); - - client.put(t, row, "entry:num", boost::lexical_cast(i)); - client.put(t, row, "entry:sqr", boost::lexical_cast(i*i)); - client.getRow(values, t, row); - printRow(row, values); + client.getRow(rowResult, t, row); + printRow(rowResult); mutations.clear(); mutations.push_back(Mutation()); mutations.back().column = "entry:num"; + mutations.back().value = boost::lexical_cast(i); + mutations.push_back(Mutation()); + mutations.back().column = "entry:sqr"; + mutations.back().value = boost::lexical_cast(i*i); + client.mutateRow(t, row, mutations); + client.getRow(rowResult, t, row); + 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); // shouldn't override latest - client.getRow(values, t, row); - printRow(row, values); + client.getRow(rowResult, t, row); + printRow(rowResult); - StrVec versions; + CellVec versions; client.getVer(versions, t, row, "entry:num", 10); printVersions(row, versions); assert(versions.size() == 4); std::cout << std::endl; try { - std::string value; + TCell value; client.get(value, t, row, "entry:foo"); std::cout << "FATAL: shouldn't get here!" << std::endl; exit(-1); @@ -232,16 +274,17 @@ columnNames.clear(); client.getColumnDescriptors(columnMap, t); for (ColMap::const_iterator it = columnMap.begin(); it != columnMap.end(); ++it) { - columnNames.push_back(it->first); + std::cout << "column with name: " + it->second.name << std::endl; + columnNames.push_back(it->second.name + ":"); } std::cout << "Starting scanner..." << std::endl; scanner = client.scannerOpenWithStop(t, "00020", "00040", columnNames); try { while (true) { - ScanEntry value; + TRowResult value; client.scannerGet(value, scanner); - printEntry(value); + printRow(value); } } catch (NotFound &nf) { client.scannerClose(scanner); Index: src/examples/thrift/DemoClient.rb =================================================================== --- src/examples/thrift/DemoClient.rb (revision 692532) +++ src/examples/thrift/DemoClient.rb (working copy) @@ -18,7 +18,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -$:.push('~/thrift/trunk/lib/rb/lib') +# Instructions: +# 1. Run Thrift to generate the ruby module HBase +# thrift --gen rb ../../../src/java/org/apache/hadoop/hbase/thrift/Hbase.thrift +# 2. Modify the import string below to point to {$THRIFT_HOME}/lib/rb/lib. +# 3. Execute {ruby DemoClient.rb}. + +# You will need to modify this import string: +$:.push('~/Thrift/thrift-20080411p1/lib/rb/lib') $:.push('./gen-rb') require 'thrift/transport/tsocket' @@ -26,18 +33,14 @@ require 'Hbase' -def printRow(row, values) - print "row: #{row}, cols: " - values.sort.each do |k,v| - print "#{k} => #{v}; " +def printRow(rowresult) + print "row: #{rowresult.row}, cols: " + rowresult.columns.sort.each do |k,v| + print "#{k} => #{v.value}; " end puts "" end -def printEntry(entry) - printRow(entry.row, entry.columns) -end - transport = TBufferedTransport.new(TSocket.new("localhost", 9090)) protocol = TBinaryProtocol.new(transport) client = Apache::Hadoop::Hbase::Thrift::Hbase::Client.new(protocol) @@ -52,7 +55,11 @@ puts "scanning tables..." client.getTableNames().sort.each do |name| puts " found: #{name}" - if (name == t) + if (name == t) + if (client.isTableEnabled(name)) + puts " disabling table: #{name}" + client.disableTable(name) + end puts " deleting table: #{name}" client.deleteTable(name) end @@ -89,17 +96,37 @@ valid = "foo-\xE7\x94\x9F\xE3\x83\x93\xE3\x83\xBC\xE3\x83\xAB"; # non-utf8 is fine for data -client.put(t, "foo", "entry:foo", invalid) +mutations = [] +m = Apache::Hadoop::Hbase::Thrift::Mutation.new +m.column = "entry:foo" +m.value = invalid +mutations << m +client.mutateRow(t, "foo", mutations) # try empty strings -client.put(t, "", "entry:", ""); +mutations = [] +m = Apache::Hadoop::Hbase::Thrift::Mutation.new +m.column = "entry:" +m.value = "" +mutations << m +client.mutateRow(t, "", mutations) # this row name is valid utf8 -client.put(t, valid, "entry:foo", valid) +mutations = [] +m = Apache::Hadoop::Hbase::Thrift::Mutation.new +m.column = "entry:foo" +m.value = valid +mutations << m +client.mutateRow(t, valid, mutations) # non-utf8 is not allowed in row names begin - client.put(t, invalid, "entry:foo", invalid) + mutations = [] + m = Apache::Hadoop::Hbase::Thrift::Mutation.new + m.column = "entry:foo" + m.value = invalid + mutations << m + client.mutateRow(t, invalid, mutations) raise "shouldn't get here!" rescue Apache::Hadoop::Hbase::Thrift::IOError => e puts "expected error: #{e.message}" @@ -110,7 +137,7 @@ scanner = client.scannerOpen(t, "", ["entry:"]) begin while (true) - printEntry(client.scannerGet(scanner)) + printRow(client.scannerGet(scanner)) end rescue Apache::Hadoop::Hbase::Thrift::NotFound => nf client.scannerClose(scanner) @@ -124,13 +151,26 @@ # format row keys as "00000" to "00100" row = format("%0.5d", e) - client.put(t, row, "unused:", "DELETE_ME"); - printRow(row, client.getRow(t, row)); + mutations = [] + m = Apache::Hadoop::Hbase::Thrift::Mutation.new + m.column = "unused:" + m.value = "DELETE_ME" + mutations << m + client.mutateRow(t, row, mutations) + printRow(client.getRow(t, row)) client.deleteAllRow(t, row) - client.put(t, row, "entry:num", "0") - client.put(t, row, "entry:foo", "FOO") - printRow(row, client.getRow(t, row)); + mutations = [] + m = Apache::Hadoop::Hbase::Thrift::Mutation.new + m.column = "entry:num" + m.value = "0" + mutations << m + m = Apache::Hadoop::Hbase::Thrift::Mutation.new + m.column = "entry:foo" + m.value = "FOO" + mutations << m + client.mutateRow(t, row, mutations) + printRow(client.getRow(t, row)) mutations = [] m = Apache::Hadoop::Hbase::Thrift::Mutation.new @@ -142,11 +182,19 @@ m.value = "-1" mutations << m client.mutateRow(t, row, mutations) - printRow(row, client.getRow(t, row)); + printRow(client.getRow(t, row)); - client.put(t, row, "entry:num", e.to_s) - client.put(t, row, "entry:sqr", (e*e).to_s) - printRow(row, client.getRow(t, row)); + mutations = [] + m = Apache::Hadoop::Hbase::Thrift::Mutation.new + m.column = "entry:num" + m.value = e.to_s + mutations << m + m = Apache::Hadoop::Hbase::Thrift::Mutation.new + m.column = "entry:sqr" + m.value = (e*e).to_s + mutations << m + client.mutateRow(t, row, mutations) + printRow(client.getRow(t, row)) mutations = [] m = Apache::Hadoop::Hbase::Thrift::Mutation.new @@ -158,12 +206,12 @@ m.isDelete = 1 mutations << m client.mutateRowTs(t, row, mutations, 1) # shouldn't override latest - printRow(row, client.getRow(t, row)); + printRow(client.getRow(t, row)); versions = client.getVer(t, row, "entry:num", 10) print "row: #{row}, values: " versions.each do |v| - print "#{v}; " + print "#{v.value}; " end puts "" @@ -179,14 +227,15 @@ columns = [] client.getColumnDescriptors(t).each do |col, desc| - columns << col + puts "column with name: #{desc.name}" + columns << desc.name + ":" end puts "Starting scanner..." scanner = client.scannerOpenWithStop(t, "00020", "00040", columns) begin while (true) - printEntry(client.scannerGet(scanner)) + printRow(client.scannerGet(scanner)) end rescue Apache::Hadoop::Hbase::Thrift::NotFound => nf client.scannerClose(scanner) Index: src/examples/thrift/DemoClient.php =================================================================== --- src/examples/thrift/DemoClient.php (revision 692532) +++ src/examples/thrift/DemoClient.php (working copy) @@ -19,8 +19,15 @@ * limitations under the License. */ +# Instructions: +# 1. Run Thrift to generate the php module HBase +# thrift -php ../../../src/java/org/apache/hadoop/hbase/thrift/Hbase.thrift +# 2. Modify the import string below to point to {$THRIFT_HOME}/lib/php/src. +# 3. Execute {php DemoClient.php}. Note that you must use php5 or higher. +# 4. See {$THRIFT_HOME}/lib/php/README for additional help. + # Change this to match your thrift root -$GLOBALS['THRIFT_ROOT'] = dirname(__FILE__).'/thrift'; +$GLOBALS['THRIFT_ROOT'] = '/Users/irubin/Thrift/thrift-20080411p1/lib/php/src'; require_once( $GLOBALS['THRIFT_ROOT'].'/Thrift.php' ); @@ -29,21 +36,19 @@ require_once( $GLOBALS['THRIFT_ROOT'].'/protocol/TBinaryProtocol.php' ); # According to the thrift documentation, compiled PHP thrift libraries should -# reside under the THRIFT_ROOT/packages directory. +# reside under the THRIFT_ROOT/packages directory. If these compiled libraries +# are not present in this directory, move them there from gen-php/. require_once( $GLOBALS['THRIFT_ROOT'].'/packages/Hbase/Hbase.php' ); -function printRow( $row, $values ) { - echo( "row: {$row}, cols: \n" ); +function printRow( $rowresult ) { + echo( "row: {$rowresult->row}, cols: \n" ); + $values = $rowresult->columns; asort( $values ); foreach ( $values as $k=>$v ) { - echo( " {$k} => {$v}\n" ); + echo( " {$k} => {$v->value}\n" ); } } -function printEntry( $entry ) { - printRow( $entry->row, $entry->columns ); -} - $socket = new TSocket( 'localhost', 9090 ); $socket->setSendTimeout( 10000 ); // Ten seconds (too long for production, but this is just a demo ;) $socket->setRecvTimeout( 20000 ); // Twenty seconds @@ -72,6 +77,10 @@ foreach ( $tables as $name ) { echo( " found: {$name}\n" ); if ( $name == $t ) { + if ($client->isTableEnabled( $name )) { + echo( " disabling table: {$name}\n"); + $client->disableTable( $name ); + } echo( " deleting table: {$name}\n" ); $client->deleteTable( $name ); } @@ -111,17 +120,41 @@ $valid = "foo-\xE7\x94\x9F\xE3\x83\x93\xE3\x83\xBC\xE3\x83\xAB"; # non-utf8 is fine for data -$client->put( $t, "foo", "entry:foo", $invalid ); +$mutations = array( + new Mutation( array( + 'column' => 'entry:foo', + 'value' => $invalid + ) ), +); +$client->mutateRow( $t, "foo", $mutations ); # try empty strings -$client->put( $t, "", "entry:", "" ); +$mutations = array( + new Mutation( array( + 'column' => 'entry:', + 'value' => "" + ) ), +); +$client->mutateRow( $t, "", $mutations ); # this row name is valid utf8 -$client->put( $t, $valid, "entry:foo", $valid ); +$mutations = array( + new Mutation( array( + 'column' => 'entry:foo', + 'value' => $valid + ) ), +); +$client->mutateRow( $t, $valid, $mutations ); # non-utf8 is not allowed in row names try { - $client->put( $t, $invalid, "entry:foo", $invalid ); + $mutations = array( + new Mutation( array( + 'column' => 'entry:foo', + 'value' => $invalid + ) ), + ); + $client->mutateRow( $t, $invalid, $mutations ); throw new Exception( "shouldn't get here!" ); } catch ( IOError $e ) { echo( "expected error: {$e->message}\n" ); @@ -131,7 +164,7 @@ echo( "Starting scanner...\n" ); $scanner = $client->scannerOpen( $t, "", array( "entry:" ) ); try { - while (true) printEntry( $client->scannerGet( $scanner ) ); + while (true) printRow( $client->scannerGet( $scanner ) ); } catch ( NotFound $nf ) { $client->scannerClose( $scanner ); echo( "Scanner finished\n" ); @@ -145,13 +178,28 @@ # format row keys as "00000" to "00100" $row = str_pad( $e, 5, '0', STR_PAD_LEFT ); - $client->put( $t, $row, "unused:", "DELETE_ME" ); - printRow( $row, $client->getRow( $t, $row ) ); + $mutations = array( + new Mutation( array( + 'column' => 'unused:', + 'value' => "DELETE_ME" + ) ), + ); + $client->mutateRow( $t, $row, $mutations); + printRow( $client->getRow( $t, $row )); $client->deleteAllRow( $t, $row ); - $client->put( $t, $row, "entry:num", "0" ); - $client->put( $t, $row, "entry:foo", "FOO"); - printRow( $row, $client->getRow( $t, $row ) ); + $mutations = array( + new Mutation( array( + 'column' => 'entry:num', + 'value' => "0" + ) ), + new Mutation( array( + 'column' => 'entry:foo', + 'value' => "FOO" + ) ), + ); + $client->mutateRow( $t, $row, $mutations ); + printRow( $client->getRow( $t, $row )); $mutations = array( new Mutation( array( @@ -164,16 +212,25 @@ ) ), ); $client->mutateRow( $t, $row, $mutations ); - printRow( $row, $client->getRow( $t, $row ) ); + printRow( $client->getRow( $t, $row ) ); - $client->put( $t, $row, "entry:num", $e ); - $client->put( $t, $row, "entry:sqr", $e * $e ); - printRow( $row, $client->getRow( $t, $row ) ); + $mutations = array( + new Mutation( array( + 'column' => "entry:num", + 'value' => $e + ) ), + new Mutation( array( + 'column' => "entry:sqr", + 'value' => $e * $e + ) ), + ); + $client->mutateRow( $t, $row, $mutations ); + printRow( $client->getRow( $t, $row )); $mutations = array( new Mutation( array( 'column' => 'entry:num', - 'isDelete' => '-999' + 'value' => '-999' ) ), new Mutation( array( 'column' => 'entry:sqr', @@ -181,11 +238,11 @@ ) ), ); $client->mutateRowTs( $t, $row, $mutations, 1 ); # shouldn't override latest - printRow( $row, $client->getRow( $t, $row ) ); + printRow( $client->getRow( $t, $row ) ); $versions = $client->getVer( $t, $row, "entry:num", 10 ); echo( "row: {$row}, values: \n" ); - foreach ( $versions as $v ) echo( " {$v};\n" ); + foreach ( $versions as $v ) echo( " {$v->value};\n" ); try { $client->get( $t, $row, "entry:foo"); @@ -197,12 +254,15 @@ } $columns = array(); -foreach ( $client->getColumnDescriptors($t) as $col=>$desc ) $columns[] = $col; +foreach ( $client->getColumnDescriptors($t) as $col=>$desc ) { + echo("column with name: {$desc->name}\n"); + $columns[] = $desc->name.":"; +} echo( "Starting scanner...\n" ); $scanner = $client->scannerOpenWithStop( $t, "00020", "00040", $columns ); try { - while (true) printEntry( $client->scannerGet( $scanner ) ); + while (true) printRow( $client->scannerGet( $scanner ) ); } catch ( NotFound $nf ) { $client->scannerClose( $scanner ); echo( "Scanner finished\n" ); Index: src/examples/thrift/DemoClient.py =================================================================== --- src/examples/thrift/DemoClient.py (revision 692532) +++ src/examples/thrift/DemoClient.py (working copy) @@ -18,10 +18,15 @@ limitations under the License. ''' # Instructions: -# 1. Run Thrift to generate python module HBase +# 1. Run Thrift to generate the python module HBase # thrift --gen py ../../../src/java/org/apache/hadoop/hbase/thrift/Hbase.thrift -# 2. Copy gen-py/HBase module into your project tree and change import string -# Contributed by: Ivan Begtin (ibegtin@gmail.com, ibegtin@enotpoiskun.ru) +# 2. Create a directory of your choosing that contains: +# a. This file (DemoClient.py). +# b. The directory gen-py/hbase (generated by instruction step 1). +# c. The directory {$THRIFT_HOME}/lib/py/build/lib.{YOUR_SYSTEM}/thrift. +# Or, modify the import statements below such that this file can access the +# directories from steps 3b and 3c. +# 3. Execute {python DemoClient.py}. import sys import time @@ -29,22 +34,21 @@ from thrift import Thrift from thrift.transport import TSocket, TTransport from thrift.protocol import TBinaryProtocol -from Hbase import ttypes -from Hbase.Hbase import Client, ColumnDescriptor, Mutation +from hbase import ttypes +from hbase.Hbase import Client, ColumnDescriptor, Mutation def printVersions(row, versions): - print "row: " + row + ", values: ", - for cell in versions: - print cell.value + "; ", - print + print "row: " + row + ", values: ", + for cell in versions: + print cell.value + "; ", + print def printRow(entry): - print "row: " + entry.row + ", cols", - for k in sorted(entry.columns): - print k + " => " + entry.columns[k].value, - print + print "row: " + entry.row + ", cols:", + for k in sorted(entry.columns): + print k + " => " + entry.columns[k].value, + print - # Make socket transport = TSocket.TSocket('localhost', 9090) @@ -67,13 +71,13 @@ # print "scanning tables..." for table in client.getTableNames(): - print " found: %s" %(table) - if table == t: - print " disabling table: %s" %(t) - if client.isTableEnabled(table): - client.disableTable(table) - print " deleting table: %s" %(t) - client.deleteTable(table) + print " found: %s" %(table) + if table == t: + if client.isTableEnabled(table): + print " disabling table: %s" %(t) + client.disableTable(table) + print " deleting table: %s" %(t) + client.deleteTable(table) columns = [] col = ColumnDescriptor() @@ -85,14 +89,16 @@ columns.append(col) try: - client.createTable(t, columns) + print "creating table: %s" %(t) + client.createTable(t, columns) except AlreadyExists, ae: - print "WARN: " + ae.message + print "WARN: " + ae.message cols = client.getColumnDescriptors(t) +print "column families in %s" %(t) for col_name in cols.keys(): - col = cols[col_name] - print " column: %s, maxVer: %d" % (col.name, col.maxVersions) + col = cols[col_name] + print " column: %s, maxVer: %d" % (col.name, col.maxVersions) # # Test UTF-8 handling # @@ -105,96 +111,95 @@ # try empty strings mutations = [Mutation({"column":"entry:", "value":""})] -client.mutateRow(t, "foo", mutations) +client.mutateRow(t, "", mutations) # this row name is valid utf8 mutations = [Mutation({"column":"entry:foo", "value":valid})] -client.mutateRow(t, "foo", mutations) +client.mutateRow(t, valid, mutations) # non-utf8 is not allowed in row names try: - mutations = [Mutation({"column":"entry:foo", "value":invalid})] - client.mutateRow(t, invalid, mutations) + mutations = [Mutation({"column":"entry:foo", "value":invalid})] + client.mutateRow(t, invalid, mutations) except ttypes.IOError, e: - print 'expected exception: %s' %(e.message) + print 'expected exception: %s' %(e.message) # Run a scanner on the rows we just created print "Starting scanner..." -scanner = client.scannerOpen(t, "", ["entry::"]) +scanner = client.scannerOpen(t, "", ["entry:"]) try: - while 1: - printRow(client.scannerGet(scanner)) + while 1: + printRow(client.scannerGet(scanner)) except ttypes.NotFound, e: - print "Scanner finished" + print "Scanner finished" # # Run some operations on a bunch of rows. # for e in range(100, 0, -1): # format row keys as "00000" to "00100" - row = "%0.5d" % (e) + row = "%0.5d" % (e) - mutations = [Mutation({"column":"unused:", "value":"DELETE_ME"})] - client.mutateRow(t, row, mutations) - printRow(client.getRow(t, row)) - client.deleteAllRow(t, row) - - mutations = [Mutation({"column":"entry:num", "value":"0"}), - Mutation({"column":"entry:foo", "value":"FOO"})] - client.mutateRow(t, row, mutations) - printRow(client.getRow(t, row)); + mutations = [Mutation({"column":"unused:", "value":"DELETE_ME"})] + client.mutateRow(t, row, mutations) + printRow(client.getRow(t, row)) + client.deleteAllRow(t, row) - mutations = [] - m = Mutation() - m.column = "entry:foo" - m.isDelete = 1 - mutations.append(m) - m = Mutation() - m.column = "entry:num" - m.value = "-1" - mutations.append(m) - client.mutateRow(t, row, mutations) - printRow(client.getRow(t, row)); + mutations = [Mutation({"column":"entry:num", "value":"0"}), + Mutation({"column":"entry:foo", "value":"FOO"})] + client.mutateRow(t, row, mutations) + printRow(client.getRow(t, row)); - mutations = [Mutation({"column":"entry:num", "value":str(e)}), - Mutation({"column":"entry:sqr", "value":str(e*e)})] - client.mutateRow(t, row, mutations) - printRow(client.getRow(t, row)); + mutations = [] + m = Mutation() + m.column = "entry:foo" + m.isDelete = 1 + mutations.append(m) + m = Mutation() + m.column = "entry:num" + m.value = "-1" + mutations.append(m) + client.mutateRow(t, row, mutations) + printRow(client.getRow(t, row)) - time.sleep(0.05) - - mutations = [] - m = Mutation() - m.column = "entry:num" - m.value = "-999" - mutations.append(m) - m = Mutation() - m.column = "entry:sqr" - m.isDelete = 1 - mutations.append(m) - client.mutateRowTs(t, row, mutations, 1) # shouldn't override latest - printRow(client.getRow(t, row)) + mutations = [Mutation({"column":"entry:num", "value":str(e)}), + Mutation({"column":"entry:sqr", "value":str(e*e)})] + client.mutateRow(t, row, mutations) + printRow(client.getRow(t, row)); - versions = client.getVer(t, row, "entry:num", 10) - printVersions(row, versions) - if len(versions) != 4: - print("FATAL: wrong # of versions") - sys.exit(-1) - - try: - client.get(t, row, "entry:foo") - print("FATAL: shouldn't get here") - sys.exit(-1) - except ttypes.NotFound: + time.sleep(0.05) + + mutations = [] + m = Mutation() + m.column = "entry:num" + m.value = "-999" + mutations.append(m) + m = Mutation() + m.column = "entry:sqr" + m.isDelete = 1 + mutations.append(m) + client.mutateRowTs(t, row, mutations, 1) # shouldn't override latest + printRow(client.getRow(t, row)) + + versions = client.getVer(t, row, "entry:num", 10) + printVersions(row, versions) + if len(versions) != 4: + print("FATAL: wrong # of versions") + sys.exit(-1) + + try: + client.get(t, row, "entry:foo") + raise "shouldn't get here!" + except ttypes.NotFound, e: pass - print + print columnNames = [] -for col2 in client.getColumnDescriptors(t): - print "column name is "+col2.name - print col2 - columnNames.append(col2.name+":") +for (col, desc) in client.getColumnDescriptors(t).items(): + print "column with name: "+desc.name + print desc + columnNames.append(desc.name+":") print "Starting scanner..." scanner = client.scannerOpenWithStop(t, "00020", "00040", columnNames) @@ -202,7 +207,7 @@ while 1: printRow(client.scannerGet(scanner)) except ttypes.NotFound: - client.scannerClose(scanner) - print "Scanner finished" - + client.scannerClose(scanner) + print "Scanner finished" + transport.close() Index: src/examples/thrift/README.txt =================================================================== --- src/examples/thrift/README.txt (revision 692532) +++ src/examples/thrift/README.txt (working copy) @@ -2,13 +2,15 @@ ============================ Included in this directory are sample clients of the HBase ThriftServer. They -all perform the same actions but are implemented in C++, Java, Ruby, and PHP -respectively. +all perform the same actions but are implemented in C++, Java, Ruby, PHP, and +Python respectively. To run/compile this clients, you will first need to install the thrift package (from http://developers.facebook.com/thrift/) and then run thrift to generate the language files: -thrift --gen cpp --gen java --gen rb --gen php \ +thrift --gen cpp --gen java --gen rb --gen py -php \ ../../../src/java/org/apache/hadoop/hbase/thrift/Hbase.thrift +See the individual DemoClient test files for more specific instructions on +running each test.