Index: src/test/java/org/apache/hadoop/hbase/thrift/TestThriftServer.java =================================================================== --- src/test/java/org/apache/hadoop/hbase/thrift/TestThriftServer.java (revision 1188884) +++ src/test/java/org/apache/hadoop/hbase/thrift/TestThriftServer.java (working copy) @@ -135,12 +135,12 @@ // Apply a few Mutations to rowA // mutations.add(new Mutation(false, columnAname, valueAname)); // mutations.add(new Mutation(false, columnBname, valueBname)); - handler.mutateRow(tableAname, rowAname, getMutations()); + handler.mutateRow(tableAname, rowAname, getMutations(), null); // Assert that the changes were made assertEquals(valueAname, - handler.get(tableAname, rowAname, columnAname).get(0).value); - TRowResult rowResult1 = handler.getRow(tableAname, rowAname).get(0); + handler.get(tableAname, rowAname, columnAname, null).get(0).value); + TRowResult rowResult1 = handler.getRow(tableAname, rowAname, null).get(0); assertEquals(rowAname, rowResult1.row); assertEquals(valueBname, rowResult1.columns.get(columnBname).value); @@ -153,30 +153,30 @@ // rowBmutations.add(new Mutation(false, columnAname, valueCname)); // rowBmutations.add(new Mutation(false, columnBname, valueDname)); // batchMutations.add(new BatchMutation(rowBname, rowBmutations)); - handler.mutateRows(tableAname, getBatchMutations()); + handler.mutateRows(tableAname, getBatchMutations(), null); // Assert that changes were made to rowA - List cells = handler.get(tableAname, rowAname, columnAname); + List cells = handler.get(tableAname, rowAname, columnAname, null); assertFalse(cells.size() > 0); - assertEquals(valueCname, handler.get(tableAname, rowAname, columnBname).get(0).value); - List versions = handler.getVer(tableAname, rowAname, columnBname, MAXVERSIONS); + assertEquals(valueCname, handler.get(tableAname, rowAname, columnBname, null).get(0).value); + List versions = handler.getVer(tableAname, rowAname, columnBname, MAXVERSIONS, null); assertEquals(valueCname, versions.get(0).value); assertEquals(valueBname, versions.get(1).value); // Assert that changes were made to rowB - TRowResult rowResult2 = handler.getRow(tableAname, rowBname).get(0); + TRowResult rowResult2 = handler.getRow(tableAname, rowBname, null).get(0); assertEquals(rowBname, rowResult2.row); assertEquals(valueCname, rowResult2.columns.get(columnAname).value); assertEquals(valueDname, rowResult2.columns.get(columnBname).value); // Apply some deletes - handler.deleteAll(tableAname, rowAname, columnBname); - handler.deleteAllRow(tableAname, rowBname); + handler.deleteAll(tableAname, rowAname, columnBname, null); + handler.deleteAllRow(tableAname, rowBname, null); // Assert that the deletes were applied - int size = handler.get(tableAname, rowAname, columnBname).size(); + int size = handler.get(tableAname, rowAname, columnBname, null).size(); assertEquals(0, size); - size = handler.getRow(tableAname, rowBname).size(); + size = handler.getRow(tableAname, rowBname, null).size(); assertEquals(0, size); // Teardown @@ -199,16 +199,16 @@ // Apply timestamped Mutations to rowA long time1 = System.currentTimeMillis(); - handler.mutateRowTs(tableAname, rowAname, getMutations(), time1); + handler.mutateRowTs(tableAname, rowAname, getMutations(), time1, null); Thread.sleep(1000); // Apply timestamped BatchMutations for rowA and rowB long time2 = System.currentTimeMillis(); - handler.mutateRowsTs(tableAname, getBatchMutations(), time2); + handler.mutateRowsTs(tableAname, getBatchMutations(), time2, null); // Apply an overlapping timestamped mutation to rowB - handler.mutateRowTs(tableAname, rowBname, getMutations(), time2); + handler.mutateRowTs(tableAname, rowBname, getMutations(), time2, null); // the getVerTs is [inf, ts) so you need to increment one. time1 += 1; @@ -216,12 +216,12 @@ // Assert that the timestamp-related methods retrieve the correct data assertEquals(2, handler.getVerTs(tableAname, rowAname, columnBname, time2, - MAXVERSIONS).size()); + MAXVERSIONS, null).size()); assertEquals(1, handler.getVerTs(tableAname, rowAname, columnBname, time1, - MAXVERSIONS).size()); + MAXVERSIONS, null).size()); - TRowResult rowResult1 = handler.getRowTs(tableAname, rowAname, time1).get(0); - TRowResult rowResult2 = handler.getRowTs(tableAname, rowAname, time2).get(0); + TRowResult rowResult1 = handler.getRowTs(tableAname, rowAname, time1, null).get(0); + TRowResult rowResult2 = handler.getRowTs(tableAname, rowAname, time2, null).get(0); // columnA was completely deleted //assertTrue(Bytes.equals(rowResult1.columns.get(columnAname).value, valueAname)); assertEquals(rowResult1.columns.get(columnBname).value, valueBname); @@ -233,31 +233,31 @@ List columns = new ArrayList(); columns.add(columnBname); - rowResult1 = handler.getRowWithColumns(tableAname, rowAname, columns).get(0); + rowResult1 = handler.getRowWithColumns(tableAname, rowAname, columns, null).get(0); assertEquals(rowResult1.columns.get(columnBname).value, valueCname); assertFalse(rowResult1.columns.containsKey(columnAname)); - rowResult1 = handler.getRowWithColumnsTs(tableAname, rowAname, columns, time1).get(0); + rowResult1 = handler.getRowWithColumnsTs(tableAname, rowAname, columns, time1, null).get(0); assertEquals(rowResult1.columns.get(columnBname).value, valueBname); assertFalse(rowResult1.columns.containsKey(columnAname)); // Apply some timestamped deletes // this actually deletes _everything_. // nukes everything in columnB: forever. - handler.deleteAllTs(tableAname, rowAname, columnBname, time1); - handler.deleteAllRowTs(tableAname, rowBname, time2); + handler.deleteAllTs(tableAname, rowAname, columnBname, time1, null); + handler.deleteAllRowTs(tableAname, rowBname, time2, null); // Assert that the timestamp-related methods retrieve the correct data - int size = handler.getVerTs(tableAname, rowAname, columnBname, time1, MAXVERSIONS).size(); + int size = handler.getVerTs(tableAname, rowAname, columnBname, time1, MAXVERSIONS, null).size(); assertEquals(0, size); - size = handler.getVerTs(tableAname, rowAname, columnBname, time2, MAXVERSIONS).size(); + size = handler.getVerTs(tableAname, rowAname, columnBname, time2, MAXVERSIONS, null).size(); assertEquals(1, size); // should be available.... - assertEquals(handler.get(tableAname, rowAname, columnBname).get(0).value, valueCname); + assertEquals(handler.get(tableAname, rowAname, columnBname, null).get(0).value, valueCname); - assertEquals(0, handler.getRow(tableAname, rowBname).size()); + assertEquals(0, handler.getRow(tableAname, rowBname, null).size()); // Teardown handler.disableTable(tableAname); @@ -278,7 +278,7 @@ // Apply timestamped Mutations to rowA long time1 = System.currentTimeMillis(); - handler.mutateRowTs(tableAname, rowAname, getMutations(), time1); + handler.mutateRowTs(tableAname, rowAname, getMutations(), time1, null); // Sleep to assure that 'time1' and 'time2' will be different even with a // coarse grained system timer. @@ -286,12 +286,12 @@ // Apply timestamped BatchMutations for rowA and rowB long time2 = System.currentTimeMillis(); - handler.mutateRowsTs(tableAname, getBatchMutations(), time2); + handler.mutateRowsTs(tableAname, getBatchMutations(), time2, null); time1 += 1; // Test a scanner on all rows and all columns, no timestamp - int scanner1 = handler.scannerOpen(tableAname, rowAname, getColumnList(true, true)); + int scanner1 = handler.scannerOpen(tableAname, rowAname, getColumnList(true, true), null); TRowResult rowResult1a = handler.scannerGet(scanner1).get(0); assertEquals(rowResult1a.row, rowAname); // This used to be '1'. I don't know why when we are asking for two columns @@ -308,7 +308,7 @@ closeScanner(scanner1, handler); // Test a scanner on all rows and all columns, with timestamp - int scanner2 = handler.scannerOpenTs(tableAname, rowAname, getColumnList(true, true), time1); + int scanner2 = handler.scannerOpenTs(tableAname, rowAname, getColumnList(true, true), time1, null); TRowResult rowResult2a = handler.scannerGet(scanner2).get(0); assertEquals(rowResult2a.columns.size(), 1); // column A deleted, does not exist. @@ -318,12 +318,12 @@ // Test a scanner on the first row and first column only, no timestamp int scanner3 = handler.scannerOpenWithStop(tableAname, rowAname, rowBname, - getColumnList(true, false)); + getColumnList(true, false), null); closeScanner(scanner3, handler); // Test a scanner on the first row and second column only, with timestamp int scanner4 = handler.scannerOpenWithStopTs(tableAname, rowAname, rowBname, - getColumnList(false, true), time1); + getColumnList(false, true), time1, null); TRowResult rowResult4a = handler.scannerGet(scanner4).get(0); assertEquals(rowResult4a.columns.size(), 1); assertEquals(rowResult4a.columns.get(columnBname).value, valueBname); Index: src/main/java/org/apache/hadoop/hbase/thrift/ThriftServer.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/thrift/ThriftServer.java (revision 1188884) +++ src/main/java/org/apache/hadoop/hbase/thrift/ThriftServer.java (working copy) @@ -28,8 +28,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.TreeMap; import org.apache.commons.cli.CommandLine; @@ -54,6 +56,7 @@ import org.apache.hadoop.hbase.client.Get; import org.apache.hadoop.hbase.client.HBaseAdmin; import org.apache.hadoop.hbase.client.HTable; +import org.apache.hadoop.hbase.client.OperationWithAttributes; import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.ResultScanner; @@ -296,22 +299,24 @@ @Deprecated @Override - public List get(ByteBuffer tableName, ByteBuffer row, ByteBuffer column) - throws IOError { + public List get(ByteBuffer tableName, ByteBuffer row, ByteBuffer column, + Map attributes) throws IOError { byte [][] famAndQf = KeyValue.parseColumn(getBytes(column)); if(famAndQf.length == 1) { - return get(tableName, row, famAndQf[0], new byte[0]); + return get(tableName, row, famAndQf[0], new byte[0], attributes); } - return get(tableName, row, famAndQf[0], famAndQf[1]); + return get(tableName, row, famAndQf[0], famAndQf[1], attributes); } protected List get(ByteBuffer tableName, ByteBuffer row, byte[] family, - byte[] qualifier) throws IOError { + byte[] qualifier, + Map attributes) throws IOError { try { HTable table = getTable(tableName); Get get = new Get(getBytes(row)); + addAttributes(get, attributes); if (qualifier == null || qualifier.length == 0) { get.addFamily(family); } else { @@ -327,22 +332,24 @@ @Deprecated @Override public List getVer(ByteBuffer tableName, ByteBuffer row, - ByteBuffer column, int numVersions) throws IOError { + ByteBuffer column, int numVersions, + Map attributes) throws IOError { byte [][] famAndQf = KeyValue.parseColumn(getBytes(column)); if(famAndQf.length == 1) { return getVer(tableName, row, famAndQf[0], - new byte[0], numVersions); + new byte[0], numVersions, attributes); } return getVer(tableName, row, - famAndQf[0], famAndQf[1], numVersions); + famAndQf[0], famAndQf[1], numVersions, attributes); } public List getVer(ByteBuffer tableName, ByteBuffer row, - byte[] family, - byte[] qualifier, int numVersions) throws IOError { + byte[] family, byte[] qualifier, int numVersions, + Map attributes) throws IOError { try { HTable table = getTable(tableName); Get get = new Get(getBytes(row)); + addAttributes(get, attributes); get.addColumn(family, qualifier); get.setMaxVersions(numVersions); Result result = table.get(get); @@ -355,25 +362,25 @@ @Deprecated @Override public List getVerTs(ByteBuffer tableName, - ByteBuffer row, - ByteBuffer column, - long timestamp, - int numVersions) throws IOError { + ByteBuffer row, ByteBuffer column, long timestamp, int numVersions, + Map attributes) throws IOError { byte [][] famAndQf = KeyValue.parseColumn(getBytes(column)); if(famAndQf.length == 1) { return getVerTs(tableName, row, famAndQf[0], new byte[0], timestamp, - numVersions); + numVersions, attributes); } return getVerTs(tableName, row, famAndQf[0], famAndQf[1], timestamp, - numVersions); + numVersions, attributes); } protected List getVerTs(ByteBuffer tableName, ByteBuffer row, byte [] family, - byte [] qualifier, long timestamp, int numVersions) throws IOError { + byte [] qualifier, long timestamp, int numVersions, + Map attributes) throws IOError { try { HTable table = getTable(tableName); Get get = new Get(getBytes(row)); + addAttributes(get, attributes); get.addColumn(family, qualifier); get.setTimeRange(Long.MIN_VALUE, timestamp); get.setMaxVersions(numVersions); @@ -385,39 +392,44 @@ } @Override - public List getRow(ByteBuffer tableName, ByteBuffer row) - throws IOError { + public List getRow(ByteBuffer tableName, ByteBuffer row, + Map attributes) throws IOError { return getRowWithColumnsTs(tableName, row, null, - HConstants.LATEST_TIMESTAMP); + HConstants.LATEST_TIMESTAMP, + attributes); } @Override public List getRowWithColumns(ByteBuffer tableName, ByteBuffer row, - List columns) throws IOError { + List columns, Map attributes) + throws IOError { return getRowWithColumnsTs(tableName, row, columns, - HConstants.LATEST_TIMESTAMP); + HConstants.LATEST_TIMESTAMP, attributes); } @Override public List getRowTs(ByteBuffer tableName, ByteBuffer row, - long timestamp) throws IOError { + long timestamp, Map attributes) throws IOError { return getRowWithColumnsTs(tableName, row, null, - timestamp); + timestamp, attributes); } @Override public List getRowWithColumnsTs(ByteBuffer tableName, ByteBuffer row, - List columns, long timestamp) throws IOError { + List columns, long timestamp, + Map attributes) throws IOError { try { HTable table = getTable(tableName); if (columns == null) { Get get = new Get(getBytes(row)); + addAttributes(get, attributes); get.setTimeRange(Long.MIN_VALUE, timestamp); Result result = table.get(get); return ThriftUtilities.rowResultFromHBase(result); } Get get = new Get(getBytes(row)); + addAttributes(get, attributes); for(ByteBuffer column : columns) { byte [][] famAndQf = KeyValue.parseColumn(getBytes(column)); if (famAndQf.length == 1) { @@ -436,37 +448,42 @@ @Override public List getRows(ByteBuffer tableName, - List rows) + List rows, + Map attributes) throws IOError { return getRowsWithColumnsTs(tableName, rows, null, - HConstants.LATEST_TIMESTAMP); + HConstants.LATEST_TIMESTAMP, attributes); } @Override public List getRowsWithColumns(ByteBuffer tableName, List rows, - List columns) throws IOError { + List columns, + Map attributes) throws IOError { return getRowsWithColumnsTs(tableName, rows, columns, - HConstants.LATEST_TIMESTAMP); + HConstants.LATEST_TIMESTAMP, attributes); } @Override public List getRowsTs(ByteBuffer tableName, List rows, - long timestamp) throws IOError { + long timestamp, Map attributes) + throws IOError { return getRowsWithColumnsTs(tableName, rows, null, - timestamp); + timestamp, attributes); } @Override public List getRowsWithColumnsTs(ByteBuffer tableName, List rows, - List columns, long timestamp) throws IOError { + List columns, long timestamp, + Map attributes) throws IOError { try { List gets = new ArrayList(rows.size()); HTable table = getTable(tableName); for (ByteBuffer row : rows) { Get get = new Get(getBytes(row)); + addAttributes(get, attributes); if (columns != null) { for(ByteBuffer column : columns) { @@ -489,19 +506,19 @@ } @Override - public void deleteAll(ByteBuffer tableName, ByteBuffer row, ByteBuffer column) + public void deleteAll(ByteBuffer tableName, ByteBuffer row, ByteBuffer column, + Map attributes) throws IOError { - deleteAllTs(tableName, row, column, HConstants.LATEST_TIMESTAMP); + deleteAllTs(tableName, row, column, HConstants.LATEST_TIMESTAMP, attributes); } @Override - public void deleteAllTs(ByteBuffer tableName, - ByteBuffer row, - ByteBuffer column, - long timestamp) throws IOError { + public void deleteAllTs(ByteBuffer tableName, ByteBuffer row, ByteBuffer column, + long timestamp, Map attributes) throws IOError { try { HTable table = getTable(tableName); Delete delete = new Delete(getBytes(row)); + addAttributes(delete, attributes); byte [][] famAndQf = KeyValue.parseColumn(getBytes(column)); if (famAndQf.length == 1) { delete.deleteFamily(famAndQf[0], timestamp); @@ -516,16 +533,19 @@ } @Override - public void deleteAllRow(ByteBuffer tableName, ByteBuffer row) throws IOError { - deleteAllRowTs(tableName, row, HConstants.LATEST_TIMESTAMP); + public void deleteAllRow(ByteBuffer tableName, ByteBuffer row, + Map attributes) throws IOError { + deleteAllRowTs(tableName, row, HConstants.LATEST_TIMESTAMP, attributes); } @Override - public void deleteAllRowTs(ByteBuffer tableName, ByteBuffer row, long timestamp) + public void deleteAllRowTs(ByteBuffer tableName, ByteBuffer row, long timestamp, + Map attributes) throws IOError { try { HTable table = getTable(tableName); Delete delete = new Delete(getBytes(row), timestamp, null); + addAttributes(delete, attributes); table.delete(delete); } catch (IOException e) { throw new IOError(e.getMessage()); @@ -572,19 +592,24 @@ @Override public void mutateRow(ByteBuffer tableName, ByteBuffer row, - List mutations) throws IOError, IllegalArgument { - mutateRowTs(tableName, row, mutations, HConstants.LATEST_TIMESTAMP); + List mutations, Map attributes) + throws IOError, IllegalArgument { + mutateRowTs(tableName, row, mutations, HConstants.LATEST_TIMESTAMP, + attributes); } @Override public void mutateRowTs(ByteBuffer tableName, ByteBuffer row, - List mutations, long timestamp) throws IOError, IllegalArgument { + List mutations, long timestamp, + Map attributes) throws IOError, IllegalArgument { HTable table = null; try { table = getTable(tableName); Put put = new Put(getBytes(row), timestamp, null); + addAttributes(put, attributes); Delete delete = new Delete(getBytes(row)); + addAttributes(delete, attributes); // I apologize for all this mess :) for (Mutation m : mutations) { @@ -615,13 +640,15 @@ } @Override - public void mutateRows(ByteBuffer tableName, List rowBatches) + public void mutateRows(ByteBuffer tableName, List rowBatches, + Map attributes) throws IOError, IllegalArgument, TException { - mutateRowsTs(tableName, rowBatches, HConstants.LATEST_TIMESTAMP); + mutateRowsTs(tableName, rowBatches, HConstants.LATEST_TIMESTAMP, attributes); } @Override - public void mutateRowsTs(ByteBuffer tableName, List rowBatches, long timestamp) + public void mutateRowsTs(ByteBuffer tableName, List rowBatches, + long timestamp, Map attributes) throws IOError, IllegalArgument, TException { List puts = new ArrayList(); List deletes = new ArrayList(); @@ -630,7 +657,9 @@ byte[] row = getBytes(batch.row); List mutations = batch.mutations; Delete delete = new Delete(row); + addAttributes(delete, attributes); Put put = new Put(row, timestamp, null); + addAttributes(put, attributes); for (Mutation m : mutations) { byte[][] famAndQf = KeyValue.parseColumn(getBytes(m.column)); if (m.isDelete) { @@ -727,10 +756,12 @@ return scannerGetList(id,1); } - public int scannerOpenWithScan(ByteBuffer tableName, TScan tScan) throws IOError { + public int scannerOpenWithScan(ByteBuffer tableName, TScan tScan, + Map attributes) throws IOError { try { HTable table = getTable(tableName); Scan scan = new Scan(); + addAttributes(scan, attributes); if (tScan.isSetStartRow()) { scan.setStartRow(tScan.getStartRow()); } @@ -765,10 +796,12 @@ @Override public int scannerOpen(ByteBuffer tableName, ByteBuffer startRow, - List columns) throws IOError { + List columns, + Map attributes) throws IOError { try { HTable table = getTable(tableName); Scan scan = new Scan(getBytes(startRow)); + addAttributes(scan, attributes); if(columns != null && columns.size() != 0) { for(ByteBuffer column : columns) { byte [][] famQf = KeyValue.parseColumn(getBytes(column)); @@ -787,10 +820,12 @@ @Override public int scannerOpenWithStop(ByteBuffer tableName, ByteBuffer startRow, - ByteBuffer stopRow, List columns) throws IOError, TException { + ByteBuffer stopRow, List columns, + Map attributes) throws IOError, TException { try { HTable table = getTable(tableName); Scan scan = new Scan(getBytes(startRow), getBytes(stopRow)); + addAttributes(scan, attributes); if(columns != null && columns.size() != 0) { for(ByteBuffer column : columns) { byte [][] famQf = KeyValue.parseColumn(getBytes(column)); @@ -809,12 +844,13 @@ @Override public int scannerOpenWithPrefix(ByteBuffer tableName, - ByteBuffer startAndPrefix, - List columns) + ByteBuffer startAndPrefix, List columns, + Map attributes) throws IOError, TException { try { HTable table = getTable(tableName); Scan scan = new Scan(getBytes(startAndPrefix)); + addAttributes(scan, attributes); Filter f = new WhileMatchFilter( new PrefixFilter(getBytes(startAndPrefix))); scan.setFilter(f); @@ -836,10 +872,12 @@ @Override public int scannerOpenTs(ByteBuffer tableName, ByteBuffer startRow, - List columns, long timestamp) throws IOError, TException { + List columns, long timestamp, + Map attributes) throws IOError, TException { try { HTable table = getTable(tableName); Scan scan = new Scan(getBytes(startRow)); + addAttributes(scan, attributes); scan.setTimeRange(Long.MIN_VALUE, timestamp); if(columns != null && columns.size() != 0) { for(ByteBuffer column : columns) { @@ -859,11 +897,13 @@ @Override public int scannerOpenWithStopTs(ByteBuffer tableName, ByteBuffer startRow, - ByteBuffer stopRow, List columns, long timestamp) + ByteBuffer stopRow, List columns, long timestamp, + Map attributes) throws IOError, TException { try { HTable table = getTable(tableName); Scan scan = new Scan(getBytes(startRow), getBytes(stopRow)); + addAttributes(scan, attributes); scan.setTimeRange(Long.MIN_VALUE, timestamp); if(columns != null && columns.size() != 0) { for(ByteBuffer column : columns) { @@ -957,6 +997,23 @@ } } + /** + * Adds all the attributes into the Operation object + */ + private static void addAttributes(OperationWithAttributes op, + Map attributes) { + if (attributes == null || attributes.size() == 0) { + return; + } + for (Iterator> iter = + attributes.entrySet().iterator(); iter.hasNext(); ) { + Map.Entry entry = iter.next(); + String name = Bytes.toStringBinary(entry.getKey()); + byte[] value = Bytes.toBytes(entry.getValue()); + op.setAttribute(name, value); + } + } + // // Main program and support routines // Index: src/main/java/org/apache/hadoop/hbase/regionserver/HRegionThriftServer.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/regionserver/HRegionThriftServer.java (revision 1188884) +++ src/main/java/org/apache/hadoop/hbase/regionserver/HRegionThriftServer.java (working copy) @@ -24,6 +24,7 @@ import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.util.List; +import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -107,8 +108,8 @@ public List getRowWithColumnsTs(ByteBuffer tableName, ByteBuffer rowb, List columns, - long timestamp) - throws IOError { + long timestamp, + Map attributes) throws IOError { try { byte [] row = rowb.array(); HTable table = getTable(tableName.array()); @@ -137,7 +138,8 @@ return ThriftUtilities.rowResultFromHBase(result); } catch (NotServingRegionException e) { LOG.info("ThriftServer redirecting getRowWithColumnsTs"); - return super.getRowWithColumnsTs(tableName, rowb, columns, timestamp); + return super.getRowWithColumnsTs(tableName, rowb, columns, timestamp, + attributes); } catch (IOException e) { throw new IOError(e.getMessage()); } Index: src/main/resources/org/apache/hadoop/hbase/thrift/Hbase.thrift =================================================================== --- src/main/resources/org/apache/hadoop/hbase/thrift/Hbase.thrift (revision 1188884) +++ src/main/resources/org/apache/hadoop/hbase/thrift/Hbase.thrift (working copy) @@ -265,7 +265,10 @@ 2:Text row, /** column name */ - 3:Text column + 3:Text column, + + /** Get attributes */ + 4:map attributes ) throws (1:IOError io) /** @@ -285,7 +288,10 @@ 3:Text column, /** number of versions to retrieve */ - 4:i32 numVersions + 4:i32 numVersions, + + /** Get attributes */ + 5:map attributes ) throws (1:IOError io) /** @@ -309,7 +315,10 @@ 4:i64 timestamp, /** number of versions to retrieve */ - 5:i32 numVersions + 5:i32 numVersions, + + /** Get attributes */ + 6:map attributes ) throws (1:IOError io) /** @@ -323,7 +332,10 @@ 1:Text tableName, /** row key */ - 2:Text row + 2:Text row, + + /** Get attributes */ + 3:map attributes ) throws (1:IOError io) /** @@ -340,7 +352,10 @@ 2:Text row, /** List of columns to return, null for all columns */ - 3:list columns + 3:list columns, + + /** Get attributes */ + 4:map attributes ) throws (1:IOError io) /** @@ -357,7 +372,10 @@ 2:Text row, /** timestamp */ - 3:i64 timestamp + 3:i64 timestamp, + + /** Get attributes */ + 4:map attributes ) throws (1:IOError io) /** @@ -375,7 +393,10 @@ /** List of columns to return, null for all columns */ 3:list columns, - 4:i64 timestamp + 4:i64 timestamp, + + /** Get attributes */ + 5:map attributes ) throws (1:IOError io) /** @@ -390,6 +411,9 @@ /** row keys */ 2:list rows + + /** Get attributes */ + 3:map attributes ) throws (1:IOError io) /** @@ -403,10 +427,13 @@ 1:Text tableName, /** row keys */ - 2:list rows + 2:list rows, /** List of columns to return, null for all columns */ - 3:list columns + 3:list columns, + + /** Get attributes */ + 4:map attributes ) throws (1:IOError io) /** @@ -423,7 +450,10 @@ 2:list rows /** timestamp */ - 3:i64 timestamp + 3:i64 timestamp, + + /** Get attributes */ + 4:map attributes ) throws (1:IOError io) /** @@ -441,7 +471,10 @@ /** List of columns to return, null for all columns */ 3:list columns, - 4:i64 timestamp + 4:i64 timestamp, + + /** Get attributes */ + 5:map attributes ) throws (1:IOError io) /** @@ -458,7 +491,10 @@ 2:Text row, /** list of mutation commands */ - 3:list mutations + 3:list mutations, + + /** Put attributes */ + 4:map attributes ) throws (1:IOError io, 2:IllegalArgument ia) /** @@ -478,7 +514,10 @@ 3:list mutations, /** timestamp */ - 4:i64 timestamp + 4:i64 timestamp, + + /** Put attributes */ + 5:map attributes ) throws (1:IOError io, 2:IllegalArgument ia) /** @@ -492,7 +531,10 @@ 1:Text tableName, /** list of row batches */ - 2:list rowBatches + 2:list rowBatches, + + /** Put attributes */ + 3:map attributes ) throws (1:IOError io, 2:IllegalArgument ia) /** @@ -509,7 +551,10 @@ 2:list rowBatches, /** timestamp */ - 3:i64 timestamp + 3:i64 timestamp, + + /** Put attributes */ + 4:map attributes ) throws (1:IOError io, 2:IllegalArgument ia) /** @@ -540,7 +585,10 @@ 2:Text row, /** name of column whose value is to be deleted */ - 3:Text column + 3:Text column, + + /** Delete attributes */ + 4:map attributes ) throws (1:IOError io) /** @@ -558,7 +606,10 @@ 3:Text column, /** timestamp */ - 4:i64 timestamp + 4:i64 timestamp, + + /** Delete attributes */ + 5:map attributes ) throws (1:IOError io) /** @@ -569,7 +620,10 @@ 1:Text tableName, /** key of the row to be completely deleted. */ - 2:Text row + 2:Text row, + + /** Delete attributes */ + 3:map attributes ) throws (1:IOError io) /** @@ -584,7 +638,10 @@ 2:Text row, /** timestamp */ - 3:i64 timestamp + 3:i64 timestamp, + + /** Delete attributes */ + 4:map attributes ) throws (1:IOError io) /** @@ -596,7 +653,10 @@ 1:Text tableName, /** Scan instance */ - 2:TScan scan + 2:TScan scan, + + /** Scan attributes */ + 3:map attributes ) throws (1:IOError io) /** @@ -620,7 +680,10 @@ * columns of the specified column family are returned. It's also possible * to pass a regex in the column qualifier. */ - 3:list columns + 3:list columns, + + /** Scan attributes */ + 4:map attributes ) throws (1:IOError io) /** @@ -651,7 +714,10 @@ * columns of the specified column family are returned. It's also possible * to pass a regex in the column qualifier. */ - 4:list columns + 4:list columns, + + /** Scan attributes */ + 5:map attributes ) throws (1:IOError io) /** @@ -668,7 +734,10 @@ 2:Text startAndPrefix, /** the columns you want returned */ - 3:list columns + 3:list columns, + + /** Scan attributes */ + 4:map attributes ) throws (1:IOError io) /** @@ -696,7 +765,10 @@ 3:list columns, /** timestamp */ - 4:i64 timestamp + 4:i64 timestamp, + + /** Scan attributes */ + 5:map attributes ) throws (1:IOError io) /** @@ -731,7 +803,10 @@ 4:list columns, /** timestamp */ - 5:i64 timestamp + 5:i64 timestamp, + + /** Scan attributes */ + 6:map attributes ) throws (1:IOError io) /**