From 417593e3aac4b4ccebc6d7801abaa417e12794b4 Mon Sep 17 00:00:00 2001 From: Jean-Daniel Cryans Date: Mon, 29 Jul 2013 23:29:04 +0000 Subject: [PATCH] HBASE-7826 Improve Hbase Thrift v1 to return results in sorted order git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1508240 13f79535-47bb-0310-9956-ffa450edef68 --- .../hbase/thrift/ThriftServerRunner.java | 58 +- .../hadoop/hbase/thrift/ThriftUtilities.java | 44 +- .../hbase/thrift/generated/TColumn.java | 504 ++++++++++++++++++ .../hbase/thrift/generated/TRowResult.java | 231 ++++++-- .../hadoop/hbase/thrift/generated/TScan.java | 135 ++++- .../apache/hadoop/hbase/thrift/Hbase.thrift | 14 +- .../hadoop/hbase/thrift/TestThriftServer.java | 41 ++ 7 files changed, 943 insertions(+), 84 deletions(-) create mode 100644 hbase-server/src/main/java/org/apache/hadoop/hbase/thrift/generated/TColumn.java diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/thrift/ThriftServerRunner.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/thrift/ThriftServerRunner.java index dbf599a4cd1..cf44841008e 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/thrift/ThriftServerRunner.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/thrift/ThriftServerRunner.java @@ -385,6 +385,25 @@ public class ThriftServerRunner implements Runnable { return InetAddress.getByName(bindAddressStr); } + protected static class ResultScannerWrapper { + + private final ResultScanner scanner; + private final boolean sortColumns; + public ResultScannerWrapper(ResultScanner resultScanner, + boolean sortResultColumns) { + scanner = resultScanner; + sortColumns = sortResultColumns; + } + + public ResultScanner getScanner() { + return scanner; + } + + public boolean isColumnSorted() { + return sortColumns; + } + } + /** * The HBaseHandler is a glue object that connects Thrift RPC calls to the * HBase client API primarily defined in the HBaseAdmin and HTable objects. @@ -396,7 +415,7 @@ public class ThriftServerRunner implements Runnable { // nextScannerId and scannerMap are used to manage scanner state protected int nextScannerId = 0; - protected HashMap scannerMap = null; + protected HashMap scannerMap = null; private ThriftMetrics metrics = null; private static ThreadLocal> threadLocalTables = @@ -456,9 +475,10 @@ public class ThriftServerRunner implements Runnable { * @param scanner * @return integer scanner id */ - protected synchronized int addScanner(ResultScanner scanner) { + protected synchronized int addScanner(ResultScanner scanner,boolean sortColumns) { int id = nextScannerId++; - scannerMap.put(id, scanner); + ResultScannerWrapper resultScannerWrapper = new ResultScannerWrapper(scanner, sortColumns); + scannerMap.put(id, resultScannerWrapper); return id; } @@ -468,7 +488,7 @@ public class ThriftServerRunner implements Runnable { * @param id * @return a Scanner, or null if ID was invalid. */ - protected synchronized ResultScanner getScanner(int id) { + protected synchronized ResultScannerWrapper getScanner(int id) { return scannerMap.get(id); } @@ -479,7 +499,7 @@ public class ThriftServerRunner implements Runnable { * @param id * @return a Scanner, or null if ID was invalid. */ - protected synchronized ResultScanner removeScanner(int id) { + protected synchronized ResultScannerWrapper removeScanner(int id) { return scannerMap.remove(id); } @@ -494,7 +514,7 @@ public class ThriftServerRunner implements Runnable { protected HBaseHandler(final Configuration c) throws IOException { this.conf = c; - scannerMap = new HashMap(); + scannerMap = new HashMap(); this.coalescer = new IncrementCoalescer(this); } @@ -1103,13 +1123,13 @@ public class ThriftServerRunner implements Runnable { public void scannerClose(int id) throws IOError, IllegalArgument { LOG.debug("scannerClose: id=" + id); - ResultScanner scanner = getScanner(id); - if (scanner == null) { + ResultScannerWrapper resultScannerWrapper = getScanner(id); + if (resultScannerWrapper == null) { String message = "scanner ID is invalid"; LOG.warn(message); throw new IllegalArgument("scanner ID is invalid"); } - scanner.close(); + resultScannerWrapper.getScanner().close(); removeScanner(id); } @@ -1117,8 +1137,8 @@ public class ThriftServerRunner implements Runnable { public List scannerGetList(int id,int nbRows) throws IllegalArgument, IOError { LOG.debug("scannerGetList: id=" + id); - ResultScanner scanner = getScanner(id); - if (null == scanner) { + ResultScannerWrapper resultScannerWrapper = getScanner(id); + if (null == resultScannerWrapper) { String message = "scanner ID is invalid"; LOG.warn(message); throw new IllegalArgument("scanner ID is invalid"); @@ -1126,7 +1146,7 @@ public class ThriftServerRunner implements Runnable { Result [] results = null; try { - results = scanner.next(nbRows); + results = resultScannerWrapper.getScanner().next(nbRows); if (null == results) { return new ArrayList(); } @@ -1134,7 +1154,7 @@ public class ThriftServerRunner implements Runnable { LOG.warn(e.getMessage(), e); throw new IOError(e.getMessage()); } - return ThriftUtilities.rowResultFromHBase(results); + return ThriftUtilities.rowResultFromHBase(results, resultScannerWrapper.isColumnSorted()); } @Override @@ -1179,7 +1199,7 @@ public class ThriftServerRunner implements Runnable { scan.setFilter( parseFilter.parseFilterString(tScan.getFilterString())); } - return addScanner(table.getScanner(scan)); + return addScanner(table.getScanner(scan), tScan.sortColumns); } catch (IOException e) { LOG.warn(e.getMessage(), e); throw new IOError(e.getMessage()); @@ -1204,7 +1224,7 @@ public class ThriftServerRunner implements Runnable { } } } - return addScanner(table.getScanner(scan)); + return addScanner(table.getScanner(scan), false); } catch (IOException e) { LOG.warn(e.getMessage(), e); throw new IOError(e.getMessage()); @@ -1230,7 +1250,7 @@ public class ThriftServerRunner implements Runnable { } } } - return addScanner(table.getScanner(scan)); + return addScanner(table.getScanner(scan), false); } catch (IOException e) { LOG.warn(e.getMessage(), e); throw new IOError(e.getMessage()); @@ -1260,7 +1280,7 @@ public class ThriftServerRunner implements Runnable { } } } - return addScanner(table.getScanner(scan)); + return addScanner(table.getScanner(scan), false); } catch (IOException e) { LOG.warn(e.getMessage(), e); throw new IOError(e.getMessage()); @@ -1286,7 +1306,7 @@ public class ThriftServerRunner implements Runnable { } } } - return addScanner(table.getScanner(scan)); + return addScanner(table.getScanner(scan), false); } catch (IOException e) { LOG.warn(e.getMessage(), e); throw new IOError(e.getMessage()); @@ -1314,7 +1334,7 @@ public class ThriftServerRunner implements Runnable { } } scan.setTimeRange(Long.MIN_VALUE, timestamp); - return addScanner(table.getScanner(scan)); + return addScanner(table.getScanner(scan), false); } catch (IOException e) { LOG.warn(e.getMessage(), e); throw new IOError(e.getMessage()); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/thrift/ThriftUtilities.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/thrift/ThriftUtilities.java index 63e6e9ad267..da335116997 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/thrift/ThriftUtilities.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/thrift/ThriftUtilities.java @@ -34,6 +34,7 @@ import org.apache.hadoop.hbase.thrift.generated.ColumnDescriptor; import org.apache.hadoop.hbase.thrift.generated.IllegalArgument; import org.apache.hadoop.hbase.thrift.generated.TCell; import org.apache.hadoop.hbase.thrift.generated.TIncrement; +import org.apache.hadoop.hbase.thrift.generated.TColumn; import org.apache.hadoop.hbase.thrift.generated.TRowResult; import org.apache.hadoop.hbase.util.Bytes; @@ -131,9 +132,15 @@ public class ThriftUtilities { * * @param in * Hbase RowResult object + * @param sortColumns + * This boolean dictates if row data is returned in a sorted order + * sortColumns = True will set TRowResult's sortedColumns member + * which is an ArrayList of TColumn struct + * sortColumns = False will set TRowResult's columns member which is + * a map of columnName and TCell struct * @return Thrift TRowResult array */ - static public List rowResultFromHBase(Result[] in) { + static public List rowResultFromHBase(Result[] in, boolean sortColumns) { List results = new ArrayList(); for ( Result result_ : in) { if(result_ == null || result_.isEmpty()) { @@ -141,18 +148,41 @@ public class ThriftUtilities { } TRowResult result = new TRowResult(); result.row = ByteBuffer.wrap(result_.getRow()); - result.columns = new TreeMap(); - for(KeyValue kv : result_.raw()) { - result.columns.put( - ByteBuffer.wrap(KeyValue.makeColumn(kv.getFamily(), - kv.getQualifier())), - new TCell(ByteBuffer.wrap(kv.getValue()), kv.getTimestamp())); + if (sortColumns) { + result.sortedColumns = new ArrayList(); + for (KeyValue kv : result_.raw()) { + result.sortedColumns.add(new TColumn( + ByteBuffer.wrap(KeyValue.makeColumn(kv.getFamily(), + kv.getQualifier())), + new TCell(ByteBuffer.wrap(kv.getValue()), kv.getTimestamp()))); + } + } else { + result.columns = new TreeMap(); + for (KeyValue kv : result_.raw()) { + result.columns.put( + ByteBuffer.wrap(KeyValue.makeColumn(kv.getFamily(), + kv.getQualifier())), + new TCell(ByteBuffer.wrap(kv.getValue()), kv.getTimestamp())); + } } results.add(result); } return results; } + /** + * This utility method creates a list of Thrift TRowResult "struct" based on + * an array of Hbase RowResult objects. The empty list is returned if the input is + * null. + * + * @param in + * Array of Hbase RowResult objects + * @return Thrift TRowResult array + */ + static public List rowResultFromHBase(Result[] in) { + return rowResultFromHBase(in, false); + } + static public List rowResultFromHBase(Result in) { Result [] result = { in }; return rowResultFromHBase(result); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/thrift/generated/TColumn.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/thrift/generated/TColumn.java new file mode 100644 index 00000000000..53c64cc7c9f --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/thrift/generated/TColumn.java @@ -0,0 +1,504 @@ +/** + * Autogenerated by Thrift Compiler (0.9.0) + * + * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + * @generated + */ +package org.apache.hadoop.hbase.thrift.generated; + +import org.apache.thrift.scheme.IScheme; +import org.apache.thrift.scheme.SchemeFactory; +import org.apache.thrift.scheme.StandardScheme; + +import org.apache.thrift.scheme.TupleScheme; +import org.apache.thrift.protocol.TTupleProtocol; +import org.apache.thrift.protocol.TProtocolException; +import org.apache.thrift.EncodingUtils; +import org.apache.thrift.TException; +import java.util.List; +import java.util.ArrayList; +import java.util.Map; +import java.util.HashMap; +import java.util.EnumMap; +import java.util.Set; +import java.util.HashSet; +import java.util.EnumSet; +import java.util.Collections; +import java.util.BitSet; +import java.nio.ByteBuffer; +import java.util.Arrays; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Holds column name and the cell. + */ +public class TColumn implements org.apache.thrift.TBase, java.io.Serializable, Cloneable { + private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("TColumn"); + + private static final org.apache.thrift.protocol.TField COLUMN_NAME_FIELD_DESC = new org.apache.thrift.protocol.TField("columnName", org.apache.thrift.protocol.TType.STRING, (short)1); + private static final org.apache.thrift.protocol.TField CELL_FIELD_DESC = new org.apache.thrift.protocol.TField("cell", org.apache.thrift.protocol.TType.STRUCT, (short)2); + + private static final Map, SchemeFactory> schemes = new HashMap, SchemeFactory>(); + static { + schemes.put(StandardScheme.class, new TColumnStandardSchemeFactory()); + schemes.put(TupleScheme.class, new TColumnTupleSchemeFactory()); + } + + public ByteBuffer columnName; // required + public TCell cell; // required + + /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ + public enum _Fields implements org.apache.thrift.TFieldIdEnum { + COLUMN_NAME((short)1, "columnName"), + CELL((short)2, "cell"); + + private static final Map byName = new HashMap(); + + static { + for (_Fields field : EnumSet.allOf(_Fields.class)) { + byName.put(field.getFieldName(), field); + } + } + + /** + * Find the _Fields constant that matches fieldId, or null if its not found. + */ + public static _Fields findByThriftId(int fieldId) { + switch(fieldId) { + case 1: // COLUMN_NAME + return COLUMN_NAME; + case 2: // CELL + return CELL; + default: + return null; + } + } + + /** + * Find the _Fields constant that matches fieldId, throwing an exception + * if it is not found. + */ + public static _Fields findByThriftIdOrThrow(int fieldId) { + _Fields fields = findByThriftId(fieldId); + if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!"); + return fields; + } + + /** + * Find the _Fields constant that matches name, or null if its not found. + */ + public static _Fields findByName(String name) { + return byName.get(name); + } + + private final short _thriftId; + private final String _fieldName; + + _Fields(short thriftId, String fieldName) { + _thriftId = thriftId; + _fieldName = fieldName; + } + + public short getThriftFieldId() { + return _thriftId; + } + + public String getFieldName() { + return _fieldName; + } + } + + // isset id assignments + public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; + static { + Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); + tmpMap.put(_Fields.COLUMN_NAME, new org.apache.thrift.meta_data.FieldMetaData("columnName", org.apache.thrift.TFieldRequirementType.DEFAULT, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING , "Text"))); + tmpMap.put(_Fields.CELL, new org.apache.thrift.meta_data.FieldMetaData("cell", org.apache.thrift.TFieldRequirementType.DEFAULT, + new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, TCell.class))); + metaDataMap = Collections.unmodifiableMap(tmpMap); + org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(TColumn.class, metaDataMap); + } + + public TColumn() { + } + + public TColumn( + ByteBuffer columnName, + TCell cell) + { + this(); + this.columnName = columnName; + this.cell = cell; + } + + /** + * Performs a deep copy on other. + */ + public TColumn(TColumn other) { + if (other.isSetColumnName()) { + this.columnName = other.columnName; + } + if (other.isSetCell()) { + this.cell = new TCell(other.cell); + } + } + + public TColumn deepCopy() { + return new TColumn(this); + } + + @Override + public void clear() { + this.columnName = null; + this.cell = null; + } + + public byte[] getColumnName() { + setColumnName(org.apache.thrift.TBaseHelper.rightSize(columnName)); + return columnName == null ? null : columnName.array(); + } + + public ByteBuffer bufferForColumnName() { + return columnName; + } + + public TColumn setColumnName(byte[] columnName) { + setColumnName(columnName == null ? (ByteBuffer)null : ByteBuffer.wrap(columnName)); + return this; + } + + public TColumn setColumnName(ByteBuffer columnName) { + this.columnName = columnName; + return this; + } + + public void unsetColumnName() { + this.columnName = null; + } + + /** Returns true if field columnName is set (has been assigned a value) and false otherwise */ + public boolean isSetColumnName() { + return this.columnName != null; + } + + public void setColumnNameIsSet(boolean value) { + if (!value) { + this.columnName = null; + } + } + + public TCell getCell() { + return this.cell; + } + + public TColumn setCell(TCell cell) { + this.cell = cell; + return this; + } + + public void unsetCell() { + this.cell = null; + } + + /** Returns true if field cell is set (has been assigned a value) and false otherwise */ + public boolean isSetCell() { + return this.cell != null; + } + + public void setCellIsSet(boolean value) { + if (!value) { + this.cell = null; + } + } + + public void setFieldValue(_Fields field, Object value) { + switch (field) { + case COLUMN_NAME: + if (value == null) { + unsetColumnName(); + } else { + setColumnName((ByteBuffer)value); + } + break; + + case CELL: + if (value == null) { + unsetCell(); + } else { + setCell((TCell)value); + } + break; + + } + } + + public Object getFieldValue(_Fields field) { + switch (field) { + case COLUMN_NAME: + return getColumnName(); + + case CELL: + return getCell(); + + } + throw new IllegalStateException(); + } + + /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ + public boolean isSet(_Fields field) { + if (field == null) { + throw new IllegalArgumentException(); + } + + switch (field) { + case COLUMN_NAME: + return isSetColumnName(); + case CELL: + return isSetCell(); + } + throw new IllegalStateException(); + } + + @Override + public boolean equals(Object that) { + if (that == null) + return false; + if (that instanceof TColumn) + return this.equals((TColumn)that); + return false; + } + + public boolean equals(TColumn that) { + if (that == null) + return false; + + boolean this_present_columnName = true && this.isSetColumnName(); + boolean that_present_columnName = true && that.isSetColumnName(); + if (this_present_columnName || that_present_columnName) { + if (!(this_present_columnName && that_present_columnName)) + return false; + if (!this.columnName.equals(that.columnName)) + return false; + } + + boolean this_present_cell = true && this.isSetCell(); + boolean that_present_cell = true && that.isSetCell(); + if (this_present_cell || that_present_cell) { + if (!(this_present_cell && that_present_cell)) + return false; + if (!this.cell.equals(that.cell)) + return false; + } + + return true; + } + + @Override + public int hashCode() { + return 0; + } + + public int compareTo(TColumn other) { + if (!getClass().equals(other.getClass())) { + return getClass().getName().compareTo(other.getClass().getName()); + } + + int lastComparison = 0; + TColumn typedOther = (TColumn)other; + + lastComparison = Boolean.valueOf(isSetColumnName()).compareTo(typedOther.isSetColumnName()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetColumnName()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.columnName, typedOther.columnName); + if (lastComparison != 0) { + return lastComparison; + } + } + lastComparison = Boolean.valueOf(isSetCell()).compareTo(typedOther.isSetCell()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetCell()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.cell, typedOther.cell); + if (lastComparison != 0) { + return lastComparison; + } + } + return 0; + } + + public _Fields fieldForId(int fieldId) { + return _Fields.findByThriftId(fieldId); + } + + public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { + schemes.get(iprot.getScheme()).getScheme().read(iprot, this); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { + schemes.get(oprot.getScheme()).getScheme().write(oprot, this); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("TColumn("); + boolean first = true; + + sb.append("columnName:"); + if (this.columnName == null) { + sb.append("null"); + } else { + sb.append(this.columnName); + } + first = false; + if (!first) sb.append(", "); + sb.append("cell:"); + if (this.cell == null) { + sb.append("null"); + } else { + sb.append(this.cell); + } + first = false; + sb.append(")"); + return sb.toString(); + } + + public void validate() throws org.apache.thrift.TException { + // check for required fields + // check for sub-struct validity + if (cell != null) { + cell.validate(); + } + } + + private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { + try { + write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { + try { + read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private static class TColumnStandardSchemeFactory implements SchemeFactory { + public TColumnStandardScheme getScheme() { + return new TColumnStandardScheme(); + } + } + + private static class TColumnStandardScheme extends StandardScheme { + + public void read(org.apache.thrift.protocol.TProtocol iprot, TColumn struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TField schemeField; + iprot.readStructBegin(); + while (true) + { + schemeField = iprot.readFieldBegin(); + if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { + break; + } + switch (schemeField.id) { + case 1: // COLUMN_NAME + if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { + struct.columnName = iprot.readBinary(); + struct.setColumnNameIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + case 2: // CELL + if (schemeField.type == org.apache.thrift.protocol.TType.STRUCT) { + struct.cell = new TCell(); + struct.cell.read(iprot); + struct.setCellIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + default: + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + iprot.readFieldEnd(); + } + iprot.readStructEnd(); + + // check for required fields of primitive type, which can't be checked in the validate method + struct.validate(); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot, TColumn struct) throws org.apache.thrift.TException { + struct.validate(); + + oprot.writeStructBegin(STRUCT_DESC); + if (struct.columnName != null) { + oprot.writeFieldBegin(COLUMN_NAME_FIELD_DESC); + oprot.writeBinary(struct.columnName); + oprot.writeFieldEnd(); + } + if (struct.cell != null) { + oprot.writeFieldBegin(CELL_FIELD_DESC); + struct.cell.write(oprot); + oprot.writeFieldEnd(); + } + oprot.writeFieldStop(); + oprot.writeStructEnd(); + } + + } + + private static class TColumnTupleSchemeFactory implements SchemeFactory { + public TColumnTupleScheme getScheme() { + return new TColumnTupleScheme(); + } + } + + private static class TColumnTupleScheme extends TupleScheme { + + @Override + public void write(org.apache.thrift.protocol.TProtocol prot, TColumn struct) throws org.apache.thrift.TException { + TTupleProtocol oprot = (TTupleProtocol) prot; + BitSet optionals = new BitSet(); + if (struct.isSetColumnName()) { + optionals.set(0); + } + if (struct.isSetCell()) { + optionals.set(1); + } + oprot.writeBitSet(optionals, 2); + if (struct.isSetColumnName()) { + oprot.writeBinary(struct.columnName); + } + if (struct.isSetCell()) { + struct.cell.write(oprot); + } + } + + @Override + public void read(org.apache.thrift.protocol.TProtocol prot, TColumn struct) throws org.apache.thrift.TException { + TTupleProtocol iprot = (TTupleProtocol) prot; + BitSet incoming = iprot.readBitSet(2); + if (incoming.get(0)) { + struct.columnName = iprot.readBinary(); + struct.setColumnNameIsSet(true); + } + if (incoming.get(1)) { + struct.cell = new TCell(); + struct.cell.read(iprot); + struct.setCellIsSet(true); + } + } + } + +} + diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/thrift/generated/TRowResult.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/thrift/generated/TRowResult.java index e65ae6e33ac..17d88dc4d74 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/thrift/generated/TRowResult.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/thrift/generated/TRowResult.java @@ -38,6 +38,7 @@ public class TRowResult implements org.apache.thrift.TBase, SchemeFactory> schemes = new HashMap, SchemeFactory>(); static { @@ -46,12 +47,14 @@ public class TRowResult implements org.apache.thrift.TBase columns; // required + public Map columns; // optional + public List sortedColumns; // optional /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ public enum _Fields implements org.apache.thrift.TFieldIdEnum { ROW((short)1, "row"), - COLUMNS((short)2, "columns"); + COLUMNS((short)2, "columns"), + SORTED_COLUMNS((short)3, "sortedColumns"); private static final Map byName = new HashMap(); @@ -70,6 +73,8 @@ public class TRowResult implements org.apache.thrift.TBase metaDataMap; static { Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); tmpMap.put(_Fields.ROW, new org.apache.thrift.meta_data.FieldMetaData("row", org.apache.thrift.TFieldRequirementType.DEFAULT, new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING , "Text"))); - tmpMap.put(_Fields.COLUMNS, new org.apache.thrift.meta_data.FieldMetaData("columns", org.apache.thrift.TFieldRequirementType.DEFAULT, + tmpMap.put(_Fields.COLUMNS, new org.apache.thrift.meta_data.FieldMetaData("columns", org.apache.thrift.TFieldRequirementType.OPTIONAL, new org.apache.thrift.meta_data.MapMetaData(org.apache.thrift.protocol.TType.MAP, new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING , "Text"), new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, TCell.class)))); + tmpMap.put(_Fields.SORTED_COLUMNS, new org.apache.thrift.meta_data.FieldMetaData("sortedColumns", org.apache.thrift.TFieldRequirementType.OPTIONAL, + new org.apache.thrift.meta_data.ListMetaData(org.apache.thrift.protocol.TType.LIST, + new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, TColumn.class)))); metaDataMap = Collections.unmodifiableMap(tmpMap); org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(TRowResult.class, metaDataMap); } @@ -127,12 +136,10 @@ public class TRowResult implements org.apache.thrift.TBase columns) + ByteBuffer row) { this(); this.row = row; - this.columns = columns; } /** @@ -157,6 +164,13 @@ public class TRowResult implements org.apache.thrift.TBase __this__sortedColumns = new ArrayList(); + for (TColumn other_element : other.sortedColumns) { + __this__sortedColumns.add(new TColumn(other_element)); + } + this.sortedColumns = __this__sortedColumns; + } } public TRowResult deepCopy() { @@ -167,6 +181,7 @@ public class TRowResult implements org.apache.thrift.TBase getSortedColumnsIterator() { + return (this.sortedColumns == null) ? null : this.sortedColumns.iterator(); + } + + public void addToSortedColumns(TColumn elem) { + if (this.sortedColumns == null) { + this.sortedColumns = new ArrayList(); + } + this.sortedColumns.add(elem); + } + + public List getSortedColumns() { + return this.sortedColumns; + } + + public TRowResult setSortedColumns(List sortedColumns) { + this.sortedColumns = sortedColumns; + return this; + } + + public void unsetSortedColumns() { + this.sortedColumns = null; + } + + /** Returns true if field sortedColumns is set (has been assigned a value) and false otherwise */ + public boolean isSetSortedColumns() { + return this.sortedColumns != null; + } + + public void setSortedColumnsIsSet(boolean value) { + if (!value) { + this.sortedColumns = null; + } + } + public void setFieldValue(_Fields field, Object value) { switch (field) { case ROW: @@ -256,6 +310,14 @@ public class TRowResult implements org.apache.thrift.TBase)value); + } + break; + } } @@ -267,6 +329,9 @@ public class TRowResult implements org.apache.thrift.TBase(_list12.size); + for (int _i13 = 0; _i13 < _list12.size; ++_i13) + { + TColumn _elem14; // required + _elem14 = new TColumn(); + _elem14.read(iprot); + struct.sortedColumns.add(_elem14); + } + iprot.readListEnd(); + } + struct.setSortedColumnsIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; default: org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); } @@ -481,17 +598,33 @@ public class TRowResult implements org.apache.thrift.TBase _iter12 : struct.columns.entrySet()) + if (struct.isSetColumns()) { + oprot.writeFieldBegin(COLUMNS_FIELD_DESC); { - oprot.writeBinary(_iter12.getKey()); - _iter12.getValue().write(oprot); + oprot.writeMapBegin(new org.apache.thrift.protocol.TMap(org.apache.thrift.protocol.TType.STRING, org.apache.thrift.protocol.TType.STRUCT, struct.columns.size())); + for (Map.Entry _iter15 : struct.columns.entrySet()) + { + oprot.writeBinary(_iter15.getKey()); + _iter15.getValue().write(oprot); + } + oprot.writeMapEnd(); } - oprot.writeMapEnd(); + oprot.writeFieldEnd(); + } + } + if (struct.sortedColumns != null) { + if (struct.isSetSortedColumns()) { + oprot.writeFieldBegin(SORTED_COLUMNS_FIELD_DESC); + { + oprot.writeListBegin(new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRUCT, struct.sortedColumns.size())); + for (TColumn _iter16 : struct.sortedColumns) + { + _iter16.write(oprot); + } + oprot.writeListEnd(); + } + oprot.writeFieldEnd(); } - oprot.writeFieldEnd(); } oprot.writeFieldStop(); oprot.writeStructEnd(); @@ -517,17 +650,29 @@ public class TRowResult implements org.apache.thrift.TBase _iter13 : struct.columns.entrySet()) + for (Map.Entry _iter17 : struct.columns.entrySet()) { - oprot.writeBinary(_iter13.getKey()); - _iter13.getValue().write(oprot); + oprot.writeBinary(_iter17.getKey()); + _iter17.getValue().write(oprot); + } + } + } + if (struct.isSetSortedColumns()) { + { + oprot.writeI32(struct.sortedColumns.size()); + for (TColumn _iter18 : struct.sortedColumns) + { + _iter18.write(oprot); } } } @@ -536,27 +681,41 @@ public class TRowResult implements org.apache.thrift.TBase(2*_map14.size); - for (int _i15 = 0; _i15 < _map14.size; ++_i15) + org.apache.thrift.protocol.TMap _map19 = new org.apache.thrift.protocol.TMap(org.apache.thrift.protocol.TType.STRING, org.apache.thrift.protocol.TType.STRUCT, iprot.readI32()); + struct.columns = new HashMap(2*_map19.size); + for (int _i20 = 0; _i20 < _map19.size; ++_i20) { - ByteBuffer _key16; // required - TCell _val17; // optional - _key16 = iprot.readBinary(); - _val17 = new TCell(); - _val17.read(iprot); - struct.columns.put(_key16, _val17); + ByteBuffer _key21; // required + TCell _val22; // required + _key21 = iprot.readBinary(); + _val22 = new TCell(); + _val22.read(iprot); + struct.columns.put(_key21, _val22); } } struct.setColumnsIsSet(true); } + if (incoming.get(2)) { + { + org.apache.thrift.protocol.TList _list23 = new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRUCT, iprot.readI32()); + struct.sortedColumns = new ArrayList(_list23.size); + for (int _i24 = 0; _i24 < _list23.size; ++_i24) + { + TColumn _elem25; // required + _elem25 = new TColumn(); + _elem25.read(iprot); + struct.sortedColumns.add(_elem25); + } + } + struct.setSortedColumnsIsSet(true); + } } } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/thrift/generated/TScan.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/thrift/generated/TScan.java index 479f7eed38d..baa86102005 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/thrift/generated/TScan.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/thrift/generated/TScan.java @@ -43,6 +43,7 @@ public class TScan implements org.apache.thrift.TBase, jav private static final org.apache.thrift.protocol.TField CACHING_FIELD_DESC = new org.apache.thrift.protocol.TField("caching", org.apache.thrift.protocol.TType.I32, (short)5); private static final org.apache.thrift.protocol.TField FILTER_STRING_FIELD_DESC = new org.apache.thrift.protocol.TField("filterString", org.apache.thrift.protocol.TType.STRING, (short)6); private static final org.apache.thrift.protocol.TField BATCH_SIZE_FIELD_DESC = new org.apache.thrift.protocol.TField("batchSize", org.apache.thrift.protocol.TType.I32, (short)7); + private static final org.apache.thrift.protocol.TField SORT_COLUMNS_FIELD_DESC = new org.apache.thrift.protocol.TField("sortColumns", org.apache.thrift.protocol.TType.BOOL, (short)8); private static final Map, SchemeFactory> schemes = new HashMap, SchemeFactory>(); static { @@ -57,6 +58,7 @@ public class TScan implements org.apache.thrift.TBase, jav public int caching; // optional public ByteBuffer filterString; // optional public int batchSize; // optional + public boolean sortColumns; // optional /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ public enum _Fields implements org.apache.thrift.TFieldIdEnum { @@ -66,7 +68,8 @@ public class TScan implements org.apache.thrift.TBase, jav COLUMNS((short)4, "columns"), CACHING((short)5, "caching"), FILTER_STRING((short)6, "filterString"), - BATCH_SIZE((short)7, "batchSize"); + BATCH_SIZE((short)7, "batchSize"), + SORT_COLUMNS((short)8, "sortColumns"); private static final Map byName = new HashMap(); @@ -95,6 +98,8 @@ public class TScan implements org.apache.thrift.TBase, jav return FILTER_STRING; case 7: // BATCH_SIZE return BATCH_SIZE; + case 8: // SORT_COLUMNS + return SORT_COLUMNS; default: return null; } @@ -138,8 +143,9 @@ public class TScan implements org.apache.thrift.TBase, jav private static final int __TIMESTAMP_ISSET_ID = 0; private static final int __CACHING_ISSET_ID = 1; private static final int __BATCHSIZE_ISSET_ID = 2; + private static final int __SORTCOLUMNS_ISSET_ID = 3; private byte __isset_bitfield = 0; - private _Fields optionals[] = {_Fields.START_ROW,_Fields.STOP_ROW,_Fields.TIMESTAMP,_Fields.COLUMNS,_Fields.CACHING,_Fields.FILTER_STRING,_Fields.BATCH_SIZE}; + private _Fields optionals[] = {_Fields.START_ROW,_Fields.STOP_ROW,_Fields.TIMESTAMP,_Fields.COLUMNS,_Fields.CACHING,_Fields.FILTER_STRING,_Fields.BATCH_SIZE,_Fields.SORT_COLUMNS}; public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; static { Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); @@ -158,6 +164,8 @@ public class TScan implements org.apache.thrift.TBase, jav new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING , "Text"))); tmpMap.put(_Fields.BATCH_SIZE, new org.apache.thrift.meta_data.FieldMetaData("batchSize", org.apache.thrift.TFieldRequirementType.OPTIONAL, new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32))); + tmpMap.put(_Fields.SORT_COLUMNS, new org.apache.thrift.meta_data.FieldMetaData("sortColumns", org.apache.thrift.TFieldRequirementType.OPTIONAL, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.BOOL))); metaDataMap = Collections.unmodifiableMap(tmpMap); org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(TScan.class, metaDataMap); } @@ -189,6 +197,7 @@ public class TScan implements org.apache.thrift.TBase, jav this.filterString = other.filterString; } this.batchSize = other.batchSize; + this.sortColumns = other.sortColumns; } public TScan deepCopy() { @@ -207,6 +216,8 @@ public class TScan implements org.apache.thrift.TBase, jav this.filterString = null; setBatchSizeIsSet(false); this.batchSize = 0; + setSortColumnsIsSet(false); + this.sortColumns = false; } public byte[] getStartRow() { @@ -419,6 +430,29 @@ public class TScan implements org.apache.thrift.TBase, jav __isset_bitfield = EncodingUtils.setBit(__isset_bitfield, __BATCHSIZE_ISSET_ID, value); } + public boolean isSortColumns() { + return this.sortColumns; + } + + public TScan setSortColumns(boolean sortColumns) { + this.sortColumns = sortColumns; + setSortColumnsIsSet(true); + return this; + } + + public void unsetSortColumns() { + __isset_bitfield = EncodingUtils.clearBit(__isset_bitfield, __SORTCOLUMNS_ISSET_ID); + } + + /** Returns true if field sortColumns is set (has been assigned a value) and false otherwise */ + public boolean isSetSortColumns() { + return EncodingUtils.testBit(__isset_bitfield, __SORTCOLUMNS_ISSET_ID); + } + + public void setSortColumnsIsSet(boolean value) { + __isset_bitfield = EncodingUtils.setBit(__isset_bitfield, __SORTCOLUMNS_ISSET_ID, value); + } + public void setFieldValue(_Fields field, Object value) { switch (field) { case START_ROW: @@ -477,6 +511,14 @@ public class TScan implements org.apache.thrift.TBase, jav } break; + case SORT_COLUMNS: + if (value == null) { + unsetSortColumns(); + } else { + setSortColumns((Boolean)value); + } + break; + } } @@ -503,6 +545,9 @@ public class TScan implements org.apache.thrift.TBase, jav case BATCH_SIZE: return Integer.valueOf(getBatchSize()); + case SORT_COLUMNS: + return Boolean.valueOf(isSortColumns()); + } throw new IllegalStateException(); } @@ -528,6 +573,8 @@ public class TScan implements org.apache.thrift.TBase, jav return isSetFilterString(); case BATCH_SIZE: return isSetBatchSize(); + case SORT_COLUMNS: + return isSetSortColumns(); } throw new IllegalStateException(); } @@ -608,6 +655,15 @@ public class TScan implements org.apache.thrift.TBase, jav return false; } + boolean this_present_sortColumns = true && this.isSetSortColumns(); + boolean that_present_sortColumns = true && that.isSetSortColumns(); + if (this_present_sortColumns || that_present_sortColumns) { + if (!(this_present_sortColumns && that_present_sortColumns)) + return false; + if (this.sortColumns != that.sortColumns) + return false; + } + return true; } @@ -694,6 +750,16 @@ public class TScan implements org.apache.thrift.TBase, jav return lastComparison; } } + lastComparison = Boolean.valueOf(isSetSortColumns()).compareTo(typedOther.isSetSortColumns()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetSortColumns()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.sortColumns, typedOther.sortColumns); + if (lastComparison != 0) { + return lastComparison; + } + } return 0; } @@ -771,6 +837,12 @@ public class TScan implements org.apache.thrift.TBase, jav sb.append(this.batchSize); first = false; } + if (isSetSortColumns()) { + if (!first) sb.append(", "); + sb.append("sortColumns:"); + sb.append(this.sortColumns); + first = false; + } sb.append(")"); return sb.toString(); } @@ -843,13 +915,13 @@ public class TScan implements org.apache.thrift.TBase, jav case 4: // COLUMNS if (schemeField.type == org.apache.thrift.protocol.TType.LIST) { { - org.apache.thrift.protocol.TList _list18 = iprot.readListBegin(); - struct.columns = new ArrayList(_list18.size); - for (int _i19 = 0; _i19 < _list18.size; ++_i19) + org.apache.thrift.protocol.TList _list26 = iprot.readListBegin(); + struct.columns = new ArrayList(_list26.size); + for (int _i27 = 0; _i27 < _list26.size; ++_i27) { - ByteBuffer _elem20; // required - _elem20 = iprot.readBinary(); - struct.columns.add(_elem20); + ByteBuffer _elem28; // required + _elem28 = iprot.readBinary(); + struct.columns.add(_elem28); } iprot.readListEnd(); } @@ -882,6 +954,14 @@ public class TScan implements org.apache.thrift.TBase, jav org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); } break; + case 8: // SORT_COLUMNS + if (schemeField.type == org.apache.thrift.protocol.TType.BOOL) { + struct.sortColumns = iprot.readBool(); + struct.setSortColumnsIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; default: org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); } @@ -921,9 +1001,9 @@ public class TScan implements org.apache.thrift.TBase, jav oprot.writeFieldBegin(COLUMNS_FIELD_DESC); { oprot.writeListBegin(new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRING, struct.columns.size())); - for (ByteBuffer _iter21 : struct.columns) + for (ByteBuffer _iter29 : struct.columns) { - oprot.writeBinary(_iter21); + oprot.writeBinary(_iter29); } oprot.writeListEnd(); } @@ -947,6 +1027,11 @@ public class TScan implements org.apache.thrift.TBase, jav oprot.writeI32(struct.batchSize); oprot.writeFieldEnd(); } + if (struct.isSetSortColumns()) { + oprot.writeFieldBegin(SORT_COLUMNS_FIELD_DESC); + oprot.writeBool(struct.sortColumns); + oprot.writeFieldEnd(); + } oprot.writeFieldStop(); oprot.writeStructEnd(); } @@ -986,7 +1071,10 @@ public class TScan implements org.apache.thrift.TBase, jav if (struct.isSetBatchSize()) { optionals.set(6); } - oprot.writeBitSet(optionals, 7); + if (struct.isSetSortColumns()) { + optionals.set(7); + } + oprot.writeBitSet(optionals, 8); if (struct.isSetStartRow()) { oprot.writeBinary(struct.startRow); } @@ -999,9 +1087,9 @@ public class TScan implements org.apache.thrift.TBase, jav if (struct.isSetColumns()) { { oprot.writeI32(struct.columns.size()); - for (ByteBuffer _iter22 : struct.columns) + for (ByteBuffer _iter30 : struct.columns) { - oprot.writeBinary(_iter22); + oprot.writeBinary(_iter30); } } } @@ -1014,12 +1102,15 @@ public class TScan implements org.apache.thrift.TBase, jav if (struct.isSetBatchSize()) { oprot.writeI32(struct.batchSize); } + if (struct.isSetSortColumns()) { + oprot.writeBool(struct.sortColumns); + } } @Override public void read(org.apache.thrift.protocol.TProtocol prot, TScan struct) throws org.apache.thrift.TException { TTupleProtocol iprot = (TTupleProtocol) prot; - BitSet incoming = iprot.readBitSet(7); + BitSet incoming = iprot.readBitSet(8); if (incoming.get(0)) { struct.startRow = iprot.readBinary(); struct.setStartRowIsSet(true); @@ -1034,13 +1125,13 @@ public class TScan implements org.apache.thrift.TBase, jav } if (incoming.get(3)) { { - org.apache.thrift.protocol.TList _list23 = new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRING, iprot.readI32()); - struct.columns = new ArrayList(_list23.size); - for (int _i24 = 0; _i24 < _list23.size; ++_i24) + org.apache.thrift.protocol.TList _list31 = new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRING, iprot.readI32()); + struct.columns = new ArrayList(_list31.size); + for (int _i32 = 0; _i32 < _list31.size; ++_i32) { - ByteBuffer _elem25; // required - _elem25 = iprot.readBinary(); - struct.columns.add(_elem25); + ByteBuffer _elem33; // required + _elem33 = iprot.readBinary(); + struct.columns.add(_elem33); } } struct.setColumnsIsSet(true); @@ -1057,6 +1148,10 @@ public class TScan implements org.apache.thrift.TBase, jav struct.batchSize = iprot.readI32(); struct.setBatchSizeIsSet(true); } + if (incoming.get(7)) { + struct.sortColumns = iprot.readBool(); + struct.setSortColumnsIsSet(true); + } } } diff --git a/hbase-server/src/main/resources/org/apache/hadoop/hbase/thrift/Hbase.thrift b/hbase-server/src/main/resources/org/apache/hadoop/hbase/thrift/Hbase.thrift index 82ed68d60dd..2f1f4bc11a9 100644 --- a/hbase-server/src/main/resources/org/apache/hadoop/hbase/thrift/Hbase.thrift +++ b/hbase-server/src/main/resources/org/apache/hadoop/hbase/thrift/Hbase.thrift @@ -121,12 +121,21 @@ struct TIncrement { 4:i64 ammount } +/** + * Holds column name and the cell. + */ +struct TColumn { + 1:Text columnName, + 2:TCell cell + } + /** * Holds row name and then a map of columns to cells. */ struct TRowResult { 1:Text row, - 2:map columns + 2:optional map columns, + 3:optional list sortedColumns } /** @@ -139,7 +148,8 @@ struct TScan { 4:optional list columns, 5:optional i32 caching, 6:optional Text filterString, - 7:optional i32 batchSize + 7:optional i32 batchSize, + 8:optional bool sortColumns } // diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/thrift/TestThriftServer.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/thrift/TestThriftServer.java index 79a4ddf135c..0f9aee9ee36 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/thrift/TestThriftServer.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/thrift/TestThriftServer.java @@ -45,6 +45,7 @@ import org.apache.hadoop.hbase.thrift.generated.Hbase; import org.apache.hadoop.hbase.thrift.generated.IOError; import org.apache.hadoop.hbase.thrift.generated.Mutation; import org.apache.hadoop.hbase.thrift.generated.TCell; +import org.apache.hadoop.hbase.thrift.generated.TScan; import org.apache.hadoop.hbase.thrift.generated.TIncrement; import org.apache.hadoop.hbase.thrift.generated.TRegionInfo; import org.apache.hadoop.hbase.thrift.generated.TRowResult; @@ -481,6 +482,46 @@ public class TestThriftServer { assertEquals(rowResult4a.columns.size(), 1); assertEquals(rowResult4a.columns.get(columnBname).value, valueBname); + // Test scanner using a TScan object once with sortColumns False and once with sortColumns true + TScan scanNoSortColumns = new TScan(); + scanNoSortColumns.setStartRow(rowAname); + scanNoSortColumns.setStopRow(rowBname); + + int scanner5 = handler.scannerOpenWithScan(tableAname , scanNoSortColumns, null); + TRowResult rowResult5 = handler.scannerGet(scanner5).get(0); + assertEquals(rowResult5.columns.size(), 1); + assertEquals(rowResult5.columns.get(columnBname).value, valueCname); + + TScan scanSortColumns = new TScan(); + scanSortColumns.setStartRow(rowAname); + scanSortColumns.setStopRow(rowBname); + scanSortColumns = scanSortColumns.setSortColumns(true); + + int scanner6 = handler.scannerOpenWithScan(tableAname ,scanSortColumns, null); + TRowResult rowResult6 = handler.scannerGet(scanner6).get(0); + assertEquals(rowResult6.sortedColumns.size(), 1); + assertEquals(rowResult6.sortedColumns.get(0).getCell().value, valueCname); + + List rowBmutations = new ArrayList(); + for (int i = 0; i < 20; i++) { + rowBmutations.add(new Mutation(false, asByteBuffer("columnA:" + i), valueCname, true)); + } + ByteBuffer rowC = asByteBuffer("rowC"); + handler.mutateRow(tableAname, rowC, rowBmutations, null); + + TScan scanSortMultiColumns = new TScan(); + scanSortMultiColumns.setStartRow(rowC); + scanSortMultiColumns = scanSortMultiColumns.setSortColumns(true); + int scanner7 = handler.scannerOpenWithScan(tableAname, scanSortMultiColumns, null); + TRowResult rowResult7 = handler.scannerGet(scanner7).get(0); + + ByteBuffer smallerColumn = asByteBuffer("columnA:"); + for (int i = 0; i < 20; i++) { + ByteBuffer currentColumn = rowResult7.sortedColumns.get(i).columnName; + assertTrue(Bytes.compareTo(smallerColumn.array(), currentColumn.array()) < 0); + smallerColumn = currentColumn; + } + // Teardown handler.disableTable(tableAname); handler.deleteTable(tableAname);