diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/ProtobufUtil.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/ProtobufUtil.java index eabf5a5e274..eeb090d32e2 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/ProtobufUtil.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/ProtobufUtil.java @@ -10,7 +10,7 @@ * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * distributed under the License is distr=ibuted on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -154,6 +154,35 @@ public final class ProtobufUtil { private final static Map> PRIMITIVES = new HashMap>(); + + /** + * Many results are simple: no cell, exists true or false. To save on object creations, + * we reuse them across calls. + */ + private final static Cell[] EMPTY_CELL_ARRAY = new Cell[]{}; + private final static Result EMPTY_RESULT = Result.create(EMPTY_CELL_ARRAY); + private final static Result EMPTY_RESULT_EXISTS_TRUE = Result.create(null, true); + private final static Result EMPTY_RESULT_EXISTS_FALSE = Result.create(null, false); + + private final static ClientProtos.Result EMPTY_RESULT_PB; + private final static ClientProtos.Result EMPTY_RESULT_PB_EXISTS_TRUE; + private final static ClientProtos.Result EMPTY_RESULT_PB_EXISTS_FALSE; + + static { + ClientProtos.Result.Builder builder = ClientProtos.Result.newBuilder(); + + builder.setExists(true); + EMPTY_RESULT_PB_EXISTS_TRUE = builder.build(); + + builder.clear(); + builder.setExists(false); + EMPTY_RESULT_PB_EXISTS_FALSE = builder.build(); + + builder.clear(); + builder.setAssociatedCellCount(0); + EMPTY_RESULT_PB = builder.build(); + } + /** * Dynamic class loader to load filter/comparators */ @@ -1083,16 +1112,20 @@ public final class ProtobufUtil { * @return the converted protocol buffer Result */ public static ClientProtos.Result toResult(final Result result) { + if (result.getExists() != null) { + return toResult(result.getExists()); + } + + Cell[] cells = result.rawCells(); + if (cells == null || cells.length == 0) { + return EMPTY_RESULT_PB; + } + ClientProtos.Result.Builder builder = ClientProtos.Result.newBuilder(); - Cell [] cells = result.rawCells(); - if (cells != null) { - for (Cell c : cells) { - builder.addCell(toCell(c)); - } - } - if (result.getExists() != null){ - builder.setExists(result.getExists()); + for (Cell c : cells) { + builder.addCell(toCell(c)); } + return builder.build(); } @@ -1103,9 +1136,7 @@ public final class ProtobufUtil { * @return the converted protocol buffer Result */ public static ClientProtos.Result toResult(final boolean existence) { - ClientProtos.Result.Builder builder = ClientProtos.Result.newBuilder(); - builder.setExists(existence); - return builder.build(); + return existence ? EMPTY_RESULT_PB_EXISTS_TRUE : EMPTY_RESULT_PB_EXISTS_FALSE; } /** @@ -1116,11 +1147,19 @@ public final class ProtobufUtil { * @return the converted protocol buffer Result */ public static ClientProtos.Result toResultNoData(final Result result) { - ClientProtos.Result.Builder builder = ClientProtos.Result.newBuilder(); - builder.setAssociatedCellCount(result.size()); if (result.getExists() != null){ - builder.setExists(result.getExists()); + return result.getExists() ? EMPTY_RESULT_PB_EXISTS_TRUE : EMPTY_RESULT_PB_EXISTS_FALSE; } + + int size = result.size(); + + if (size == 0){ + return EMPTY_RESULT_PB; + } + + ClientProtos.Result.Builder builder = ClientProtos.Result.newBuilder(); + builder.setAssociatedCellCount(size); + return builder.build(); } @@ -1132,10 +1171,14 @@ public final class ProtobufUtil { */ public static Result toResult(final ClientProtos.Result proto) { if (proto.hasExists()) { - return Result.create(null, proto.getExists()); + return proto.getExists() ? EMPTY_RESULT_EXISTS_TRUE : EMPTY_RESULT_EXISTS_FALSE; } List values = proto.getCellList(); + if (values.isEmpty()){ + return EMPTY_RESULT; + } + List cells = new ArrayList(values.size()); for (CellProtos.Cell c : values) { cells.add(toCell(c)); @@ -1153,28 +1196,38 @@ public final class ProtobufUtil { */ public static Result toResult(final ClientProtos.Result proto, final CellScanner scanner) throws IOException { - if (proto.hasExists()){ - return Result.create(null, proto.getExists()); + List values = proto.getCellList(); + + if (proto.hasExists()) { + if ((values != null && !values.isEmpty()) || + (proto.hasAssociatedCellCount() && proto.getAssociatedCellCount() > 0)) { + throw new IllegalArgumentException("bad proto: exists with cells is no allowed " + proto); + } + return proto.getExists() ? EMPTY_RESULT_EXISTS_TRUE : EMPTY_RESULT_EXISTS_FALSE; } // TODO: Unit test that has some Cells in scanner and some in the proto. List cells = null; if (proto.hasAssociatedCellCount()) { int count = proto.getAssociatedCellCount(); - cells = new ArrayList(count); + cells = new ArrayList(count + values.size()); for (int i = 0; i < count; i++) { if (!scanner.advance()) throw new IOException("Failed get " + i + " of " + count); cells.add(scanner.current()); } } - List values = proto.getCellList(); - if (cells == null) cells = new ArrayList(values.size()); - for (CellProtos.Cell c: values) { - cells.add(toCell(c)); + + if (!values.isEmpty()){ + if (cells == null) cells = new ArrayList(values.size()); + for (CellProtos.Cell c: values) { + cells.add(toCell(c)); + } } - return Result.create(cells, null); + + return (cells == null || cells.isEmpty()) ? EMPTY_RESULT : Result.create(cells, null); } + /** * Convert a ByteArrayComparable to a protocol buffer Comparator * diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/RequestConverter.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/RequestConverter.java index 6dca80c8538..77cd5ee2eef 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/RequestConverter.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/RequestConverter.java @@ -488,7 +488,6 @@ public final class RequestConverter { throws IOException { RegionAction.Builder builder = getRegionActionBuilderWithRegion(regionName); ClientProtos.Action.Builder actionBuilder = ClientProtos.Action.newBuilder(); - MutationProto.Builder mutationBuilder = ClientProtos.MutationProto.newBuilder(); for (Action action: actions) { Row row = action.getAction(); actionBuilder.clear();