From 968f83b2ff45234c756a93cf5bd90f39619ddd53 Mon Sep 17 00:00:00 2001 From: ramkrishna Date: Thu, 17 Oct 2013 17:34:51 +0000 Subject: [PATCH] HBASE-9689-Support using OperationAttributes through shell script (Ram) git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1533174 13f79535-47bb-0310-9956-ffa450edef68 --- hbase-shell/src/main/ruby/hbase.rb | 1 + hbase-shell/src/main/ruby/hbase/table.rb | 37 ++++++++++++++++--- .../src/main/ruby/shell/commands/get.rb | 1 + .../src/main/ruby/shell/commands/put.rb | 13 ++++--- .../src/main/ruby/shell/commands/scan.rb | 3 +- hbase-shell/src/test/ruby/hbase/table_test.rb | 21 +++++++++-- 6 files changed, 62 insertions(+), 14 deletions(-) diff --git a/hbase-shell/src/main/ruby/hbase.rb b/hbase-shell/src/main/ruby/hbase.rb index 87512bf88b1..75c5d5eb583 100644 --- a/hbase-shell/src/main/ruby/hbase.rb +++ b/hbase-shell/src/main/ruby/hbase.rb @@ -57,6 +57,7 @@ module HBaseConstants SPLITALGO = 'SPLITALGO' NUMREGIONS = 'NUMREGIONS' CONFIGURATION = org.apache.hadoop.hbase.HConstants::CONFIGURATION + ATTRIBUTES="ATTRIBUTES" # Load constants from hbase java API def self.promote_constants(constants) diff --git a/hbase-shell/src/main/ruby/hbase/table.rb b/hbase-shell/src/main/ruby/hbase/table.rb index 13d7646be32..c78700b1455 100644 --- a/hbase-shell/src/main/ruby/hbase/table.rb +++ b/hbase-shell/src/main/ruby/hbase/table.rb @@ -127,9 +127,20 @@ EOF # they will be much less likely to tab complete to the 'dangerous' internal method #---------------------------------------------------------------------------------------------- # Put a cell 'value' at specified table/row/column - def _put_internal(row, column, value, timestamp = nil) + def _put_internal(row, column, value, timestamp = nil, args = {}) p = org.apache.hadoop.hbase.client.Put.new(row.to_s.to_java_bytes) family, qualifier = parse_column_name(column) + if args.any? + attributes = args[ATTRIBUTES] + set_attributes(p, attributes) if attributes + end + #Case where attributes are specified without timestamp + if timestamp.kind_of?(Hash) + timestamp.each do |k, v| + set_attributes(p, v) if v + end + timestamp = nil + end if timestamp p.add(family, qualifier, timestamp, value.to_s.to_java_bytes) else @@ -219,7 +230,7 @@ EOF # Get maxlength parameter if passed maxlength = args.delete(MAXLENGTH) if args[MAXLENGTH] filter = args.delete(FILTER) if args[FILTER] - + attributes = args[ATTRIBUTES] unless args.empty? columns = args[COLUMN] || args[COLUMNS] if args[VERSIONS] @@ -251,9 +262,13 @@ EOF get.setTimeStamp(args[TIMESTAMP]) if args[TIMESTAMP] get.setTimeRange(args[TIMERANGE][0], args[TIMERANGE][1]) if args[TIMERANGE] else - # May have passed TIMESTAMP and row only; wants all columns from ts. - unless ts = args[TIMESTAMP] || tr = args[TIMERANGE] - raise ArgumentError, "Failed parse of #{args.inspect}, #{args.class}" + if attributes + set_attributes(get, attributes) if attributes + else + # May have passed TIMESTAMP and row only; wants all columns from ts. + unless ts = args[TIMESTAMP] || tr = args[TIMERANGE] + raise ArgumentError, "Failed parse of #{args.inspect}, #{args.class}" + end end get.setMaxVersions(vers) @@ -261,6 +276,7 @@ EOF get.setTimeStamp(ts.to_i) if args[TIMESTAMP] get.setTimeRange(args[TIMERANGE][0], args[TIMERANGE][1]) if args[TIMERANGE] end + set_attributes(get, attributes) if attributes end unless filter.class == String @@ -333,6 +349,7 @@ EOF versions = args["VERSIONS"] || 1 timerange = args[TIMERANGE] raw = args["RAW"] || false + attributes = args[ATTRIBUTES] # Normalize column names columns = [columns] if columns.class == String @@ -367,6 +384,7 @@ EOF scan.setMaxVersions(versions) if versions > 1 scan.setTimeRange(timerange[0], timerange[1]) if timerange scan.setRaw(raw) + set_attributes(scan, attributes) if attributes else scan = org.apache.hadoop.hbase.client.Scan.new end @@ -408,6 +426,15 @@ EOF return ((block_given?) ? count : res) end + # Apply OperationAttributes to puts/scans/gets + def set_attributes(oprattr, attributes) + raise(ArgumentError, "#{"ATTRIBUTES"} must be a Hash type") unless attributes.kind_of?(Hash) + for k,v in attributes + v = v.to_s unless v.nil? + oprattr.setAttribute(k.to_s, v.to_java_bytes) + end + end + #---------------------------- # Add general administration utilities to the shell # each of the names below adds this method name to the table diff --git a/hbase-shell/src/main/ruby/shell/commands/get.rb b/hbase-shell/src/main/ruby/shell/commands/get.rb index 4344d68d14f..7ac4033959f 100644 --- a/hbase-shell/src/main/ruby/shell/commands/get.rb +++ b/hbase-shell/src/main/ruby/shell/commands/get.rb @@ -36,6 +36,7 @@ a dictionary of column(s), timestamp, timerange and versions. Examples: hbase> get 't1', 'r1', 'c1' hbase> get 't1', 'r1', 'c1', 'c2' hbase> get 't1', 'r1', ['c1', 'c2'] + hbsase> get 't1','r1', {COLUMN => 'c1', ATTRIBUTES => {'mykey'=>'myvalue'}} Besides the default 'toStringBinary' format, 'get' also supports custom formatting by column. A user can define a FORMATTER by adding it to the column name in the get diff --git a/hbase-shell/src/main/ruby/shell/commands/put.rb b/hbase-shell/src/main/ruby/shell/commands/put.rb index 17e7a5f261a..56f8c09730c 100644 --- a/hbase-shell/src/main/ruby/shell/commands/put.rb +++ b/hbase-shell/src/main/ruby/shell/commands/put.rb @@ -26,22 +26,25 @@ Put a cell 'value' at specified table/row/column and optionally timestamp coordinates. To put a cell value into table 't1' at row 'r1' under column 'c1' marked with the time 'ts1', do: + hbase> put 't1', 'r1', 'c1', 'value' hbase> put 't1', 'r1', 'c1', 'value', ts1 + hbase> put 't1', 'r1', 'c1', 'value', {ATTRIBUTES=>{'mykey'=>'myvalue'} + hbase> put 't1', 'r1', 'c1', 'value', ts1, {ATTRIBUTES=>{'mykey'=>'myvalue'} The same commands also can be run on a table reference. Suppose you had a reference t to table 't1', the corresponding command would be: - hbase> t.put 'r1', 'c1', 'value', ts1 + hbase> t.put 'r1', 'c1', 'value', ts1, {ATTRIBUTES=>{'mykey'=>'myvalue'} EOF end - def command(table, row, column, value, timestamp = nil) - put table(table), row, column, value, timestamp + def command(table, row, column, value, timestamp=nil, args = {}) + put table(table), row, column, value, timestamp, args end - def put(table, row, column, value, timestamp = nil) + def put(table, row, column, value, timestamp = nil, args = {}) format_simple_command do - table._put_internal(row, column, value, timestamp) + table._put_internal(row, column, value, timestamp, args) end end end diff --git a/hbase-shell/src/main/ruby/shell/commands/scan.rb b/hbase-shell/src/main/ruby/shell/commands/scan.rb index 364fd6e0b1f..0564ad819d8 100644 --- a/hbase-shell/src/main/ruby/shell/commands/scan.rb +++ b/hbase-shell/src/main/ruby/shell/commands/scan.rb @@ -46,7 +46,8 @@ Some examples: (QualifierFilter (>=, 'binary:xyz'))) AND (TimestampsFilter ( 123, 456))"} hbase> scan 't1', {FILTER => org.apache.hadoop.hbase.filter.ColumnPaginationFilter.new(1, 0)} - +For setting the Operation Attributes + hbase> scan 't1', { COLUMNS => ['c1', 'c2'], ATTRIBUTES => {'mykey' => 'myvalue'}} For experts, there is an additional option -- CACHE_BLOCKS -- which switches block caching for the scanner on (true) or off (false). By default it is enabled. Examples: diff --git a/hbase-shell/src/test/ruby/hbase/table_test.rb b/hbase-shell/src/test/ruby/hbase/table_test.rb index 4eba3e2072d..f55e941ef13 100644 --- a/hbase-shell/src/test/ruby/hbase/table_test.rb +++ b/hbase-shell/src/test/ruby/hbase/table_test.rb @@ -106,7 +106,7 @@ module Hbase @test_table.put("101", "x:a", "1") @test_table.put("101", "x:a", "2", Time.now.to_i) - @test_table.put("102", "x:a", "1",1212) + @test_table.put("102", "x:a", "1", 1212) @test_table.put("102", "x:a", "2", 1213) @test_table.put(103, "x:a", "3") @@ -134,7 +134,10 @@ module Hbase define_test "put should work with integer values" do @test_table.put("123", "x:a", 4) end - + + define_test "put should work with attributes" do + @test_table.put("123", "x:a", 4, {ATTRIBUTES=>{'mykey'=>'myvalue'}}) + end #------------------------------------------------------------------------------- define_test "delete should work without timestamp" do @@ -213,6 +216,10 @@ module Hbase @test_table.put(2, "x:a", 11) @test_table.put(2, "x:b", 12, @test_ts) + + @test_table.put(3, "x:a", 21, {ATTRIBUTES=>{'mykey'=>'myvalue'}}) + @test_table.put(3, "x:b", 22, @test_ts, {ATTRIBUTES=>{'mykey'=>'myvalue'}}) + end define_test "count should work w/o a block passed" do @@ -237,6 +244,14 @@ module Hbase assert_not_nil(res['x:a']) assert_not_nil(res['x:b']) end + + define_test "get should work for data written with Attributes" do + res = @test_table._get_internal('3') + assert_not_nil(res) + assert_kind_of(Hash, res) + assert_not_nil(res['x:a']) + assert_not_nil(res['x:b']) + end define_test "get should work with integer keys" do res = @test_table._get_internal(1) @@ -441,7 +456,7 @@ module Hbase assert_not_nil(res['2']['x:a']) assert_not_nil(res['2']['x:b']) end - + define_test "scan should support COLUMNS parameter with a single column name" do res = @test_table._scan_internal COLUMNS => 'x:a' assert_not_nil(res)