diff --git src/main/ruby/hbase/hbase.rb src/main/ruby/hbase/hbase.rb index 2c37840..5ab6a72 100644 --- src/main/ruby/hbase/hbase.rb +++ src/main/ruby/hbase/hbase.rb @@ -45,8 +45,8 @@ module Hbase end # Create new one each time - def table(table, formatter) - ::Hbase::Table.new(configuration, table, formatter) + def table(table, shell) + ::Hbase::Table.new(configuration, table, shell) end def replication_admin(formatter) diff --git src/main/ruby/hbase/table.rb src/main/ruby/hbase/table.rb index 6dcf47e..a463a6a 100644 --- src/main/ruby/hbase/table.rb +++ src/main/ruby/hbase/table.rb @@ -26,8 +26,9 @@ module Hbase class Table include HBaseConstants - def initialize(configuration, table_name, formatter) + def initialize(configuration, table_name, shell) @table = org.apache.hadoop.hbase.client.HTable.new(configuration, table_name) + @shell = shell end #---------------------------------------------------------------------------------------------- @@ -204,8 +205,8 @@ module Hbase end #---------------------------------------------------------------------------------------------- - # Scans whole table or a range of keys and returns rows matching specific criterias - def scan(args = {}) + # Scans whole table or a range of keys and returns rows matching specific criteria + def scan_internal(args = {}) unless args.kind_of?(Hash) raise ArgumentError, "Arguments should be a hash. Failed to parse #{args.inspect}, #{args.class}" end @@ -345,5 +346,40 @@ module Hbase (maxlength != -1) ? val[0, maxlength] : val end + #---------------------------- + #give the general help for the table + # or the named command + def help (command = nil) + if command + return @shell.help_command(command) + end + return <<-EOF + Access an HTable. The table is accessed based on the name of the table + and the current default configuration (hbase-site.xml and hbase-default.xml). + + There are a variety of things you can do with a table. For instance, say + you have a table 't': + + hbase> t.scan + + Will get you all the rows in t. + + Similarly, to put a row into table t, assuming it was created with + the column family 'fam': + + hbase> t.put 'row', 'fam', 'value' + + Other commands include things like: get, delete, deleteall, is_meta_table?, + get_all_columns, get_counter, count, incr. These functions, along with + the standard JRuby object methods are also available via tab completion. + + For more information on how to use each of these commands, you can also just + type: + + hbase> t.help 'scan' + + which will output more information on how to use that command. + EOF + end end end diff --git src/main/ruby/shell.rb src/main/ruby/shell.rb index 53f3de8..a8930f0 100644 --- src/main/ruby/shell.rb +++ src/main/ruby/shell.rb @@ -80,7 +80,7 @@ module Shell end def hbase_table(name) - hbase.table(name, formatter) + hbase.table(name, self) end def hbase_replication_admin @@ -93,10 +93,15 @@ module Shell def export_commands(where) ::Shell.commands.keys.each do |cmd| + # here where is the IRB namespace + # this method just adds the call to the specified command + # which just references back to 'this' shell object + # a decently extensible way to add commands where.send :instance_eval, <<-EOF def #{cmd}(*args) - @shell.command('#{cmd}', *args) + ret = @shell.command('#{cmd}', *args) puts + return ret end EOF end @@ -106,8 +111,17 @@ module Shell ::Shell.commands[command.to_s].new(self) end + #call the method 'command' on the specified command def command(command, *args) - command_instance(command).command_safe(self.debug, *args) + internal_command(command, :command, *args) + end + + #call a specific internal method in the command instance + # command - name of the command to call + # method_name - name of the method on the command to call + # args - to be passed to the named method + def internal_command(command, method_name= :command, *args) + command_instance(command).command_safe(self.debug,method_name, *args) end def print_banner @@ -234,6 +248,7 @@ Shell.load_command_group( show_filters alter_status alter_async + get_table ] ) diff --git src/main/ruby/shell/commands.rb src/main/ruby/shell/commands.rb index af6df33..81d31bd 100644 --- src/main/ruby/shell/commands.rb +++ src/main/ruby/shell/commands.rb @@ -27,8 +27,8 @@ module Shell self.shell = shell end - def command_safe(debug, *args) - translate_hbase_exceptions(*args) { command(*args) } + def command_safe(debug, cmd = :command, *args) + translate_hbase_exceptions(*args) { send(cmd,*args) } rescue => e puts puts "ERROR: #{e}" @@ -37,8 +37,6 @@ module Shell puts "Here is some help for this command:" puts help puts - ensure - return nil end def admin @@ -70,6 +68,14 @@ module Shell formatter.footer(now) end + def format_and_return_simple_command + now = Time.now + ret = yield + formatter.header + formatter.footer(now) + return ret + end + def translate_hbase_exceptions(*args) yield rescue org.apache.hadoop.hbase.TableNotFoundException @@ -80,6 +86,10 @@ module Shell rescue org.apache.hadoop.hbase.TableExistsException raise "Table already exists: #{args.first}!" end + + def add_command(command, obj) + ::Hbase::Table.add_command(command, obj) + end end end end diff --git src/main/ruby/shell/commands/create.rb src/main/ruby/shell/commands/create.rb index 14c1b0f..0845ada 100644 --- src/main/ruby/shell/commands/create.rb +++ src/main/ruby/shell/commands/create.rb @@ -38,13 +38,22 @@ Examples: hbase> # Optionally pre-split the table into NUMREGIONS, using hbase> # SPLITALGO ("HexStringSplit", "UniformSplit" or classname) hbase> create 't1', 'f1', {NUMREGIONS => 15, SPLITALGO => 'HexStringSplit'} + + You can also keep around a reference to the created table: + + hbase> t1 = create 't1', 'f1' + + Which gives you a reference to the table named 't1', on which you can then + call methods. EOF end def command(table, *args) format_simple_command do - admin.create(table, *args) + ret = admin.create(table, *args) end + #and then return the table you just created + table(table) end end end diff --git src/main/ruby/shell/commands/get_table.rb src/main/ruby/shell/commands/get_table.rb new file mode 100644 index 0000000..615addd --- /dev/null +++ src/main/ruby/shell/commands/get_table.rb @@ -0,0 +1,28 @@ +module Shell + module Commands + class GetTable < Command + def help + return <<-EOF +Get the given table name and return it as an actual object to +be manipulated by the user. See table.help for more information +on how to use the table. +Eg. + + hbase> t1 = get_table 't1' + +returns the table named 't1' as a table object. You can then do + + hbase> t1.help + +which will then print the help for that table. +EOF + end + + def command(table, *args) + format_and_return_simple_command do + table(table) + end + end + end + end +end diff --git src/main/ruby/shell/commands/scan.rb src/main/ruby/shell/commands/scan.rb index e58aaac..fdad48f 100644 --- src/main/ruby/shell/commands/scan.rb +++ src/main/ruby/shell/commands/scan.rb @@ -58,14 +58,27 @@ cells). This option cannot be combined with requesting specific COLUMNS. Disabled by default. Example: hbase> scan 't1', {RAW => true, VERSIONS => 10} + +Scan can also be used directly from a table, by first getting a reference to a table, like such: + + hbase> t = get_table 't' + hbase> t.scan + +Note in the above situation, you can still provide all the filtering, columns, options, etc as +described above. EOF end def command(table, args = {}) + scan(table(table), args) + end + + def scan(table, args = {}) now = Time.now formatter.header(["ROW", "COLUMN+CELL"]) - count = table(table).scan(args) do |row, cells| + #actually do the scanning + count = table.scan_internal(args) do |row, cells| formatter.row([ row, cells ]) end @@ -74,3 +87,13 @@ EOF end end end + +#extension of the table class s.t. it will call the scan object +module Hbase + class Table + #add the ability to scan a table using the correct scan object + def scan(args = {}) + @shell.internal_command(:scan, :scan, self, args) + end + end +end diff --git src/test/ruby/hbase/admin_test.rb src/test/ruby/hbase/admin_test.rb index 0c2672b..ec4c01e 100644 --- src/test/ruby/hbase/admin_test.rb +++ src/test/ruby/hbase/admin_test.rb @@ -310,5 +310,13 @@ module Hbase assert_no_match(eval("/" + key1 + "\\$(\\d+)/"), admin.describe(@test_name)) assert_no_match(eval("/" + key2 + "/"), admin.describe(@test_name)) end + + define_test "get_table should get a real table" do + drop_test_table(@test_name) + create_test_table(@test_name) + + table = table(@test_name) + assert_not_equal(nil, table) + end end end