You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by jy...@apache.org on 2016/03/05 20:16:15 UTC

[1/3] hbase git commit: HBASE-14703 HTable.mutateRow does not collect stats (Heng Chen)

Repository: hbase
Updated Branches:
  refs/heads/master d083e4f29 -> ef712df94


http://git-wip-us.apache.org/repos/asf/hbase/blob/ef712df9/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestClientPushback.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestClientPushback.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestClientPushback.java
index bba38f77..e82b1c7 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestClientPushback.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestClientPushback.java
@@ -17,6 +17,7 @@
  */
 package org.apache.hadoop.hbase.client;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
@@ -166,4 +167,32 @@ public class TestClientPushback {
     assertNotEquals("AsyncProcess did not submit the work time", endTime.get(), 0);
     assertTrue("AsyncProcess did not delay long enough", endTime.get() - startTime >= backoffTime);
   }
+
+  @Test
+  public void testMutateRowStats() throws IOException {
+    Configuration conf = UTIL.getConfiguration();
+    ClusterConnection conn = (ClusterConnection) ConnectionFactory.createConnection(conf);
+    HTable table = (HTable) conn.getTable(tableName);
+    HRegionServer rs = UTIL.getHBaseCluster().getRegionServer(0);
+    Region region = rs.getOnlineRegions(tableName).get(0);
+
+    RowMutations mutations = new RowMutations(Bytes.toBytes("row"));
+    Put p = new Put(Bytes.toBytes("row"));
+    p.addColumn(family, qualifier, Bytes.toBytes("value2"));
+    mutations.add(p);
+    table.mutateRow(mutations);
+
+    ServerStatisticTracker stats = conn.getStatisticsTracker();
+    assertNotNull( "No stats configured for the client!", stats);
+    // get the names so we can query the stats
+    ServerName server = rs.getServerName();
+    byte[] regionName = region.getRegionInfo().getRegionName();
+
+    // check to see we found some load on the memstore
+    ServerStatistics serverStats = stats.getServerStatsForTesting(server);
+    ServerStatistics.RegionStatistics regionStats = serverStats.getStatsForRegion(regionName);
+
+    assertNotNull(regionStats);
+    assertTrue(regionStats.getMemstoreLoadPercent() > 0);
+    }
 }

http://git-wip-us.apache.org/repos/asf/hbase/blob/ef712df9/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java
index 63d9cd0..3b88184 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java
@@ -4365,7 +4365,13 @@ public class TestFromClientSide {
       arm.add(p);
       t.mutateRow(arm);
       fail("Expected NoSuchColumnFamilyException");
-    } catch(NoSuchColumnFamilyException e) {
+    } catch(RetriesExhaustedWithDetailsException e) {
+      for(Throwable rootCause: e.getCauses()){
+        if(rootCause instanceof NoSuchColumnFamilyException){
+          return;
+        }
+      }
+      throw e;
     }
   }
 

http://git-wip-us.apache.org/repos/asf/hbase/blob/ef712df9/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestReplicasClient.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestReplicasClient.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestReplicasClient.java
index d2e775d..9690a89 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestReplicasClient.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestReplicasClient.java
@@ -573,10 +573,11 @@ public class TestReplicasClient {
         Assert.assertTrue(((Result)r).isStale());
         Assert.assertTrue(((Result)r).getExists());
       }
-      Set<MultiServerCallable<Row>> set = ((AsyncRequestFutureImpl<?>)reqs).getCallsInProgress();
+      Set<PayloadCarryingServerCallable> set =
+          ((AsyncRequestFutureImpl<?>)reqs).getCallsInProgress();
       // verify we did cancel unneeded calls
       Assert.assertTrue(!set.isEmpty());
-      for (MultiServerCallable<Row> m : set) {
+      for (PayloadCarryingServerCallable m : set) {
         Assert.assertTrue(m.isCancelled());
       }
     } finally {


[2/3] hbase git commit: HBASE-14703 HTable.mutateRow does not collect stats (Heng Chen)

Posted by jy...@apache.org.
http://git-wip-us.apache.org/repos/asf/hbase/blob/ef712df9/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/ClientProtos.java
----------------------------------------------------------------------
diff --git a/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/ClientProtos.java b/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/ClientProtos.java
index d188531..0a9922c 100644
--- a/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/ClientProtos.java
+++ b/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/ClientProtos.java
@@ -29027,6 +29027,1095 @@ public final class ClientProtos {
     // @@protoc_insertion_point(class_scope:hbase.pb.RegionLoadStats)
   }
 
+  public interface MultiRegionLoadStatsOrBuilder
+      extends com.google.protobuf.MessageOrBuilder {
+
+    // repeated .hbase.pb.RegionSpecifier region = 1;
+    /**
+     * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+     */
+    java.util.List<org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier>
+        getRegionList();
+    /**
+     * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+     */
+    org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier getRegion(int index);
+    /**
+     * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+     */
+    int getRegionCount();
+    /**
+     * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+     */
+    java.util.List<? extends org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifierOrBuilder>
+        getRegionOrBuilderList();
+    /**
+     * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+     */
+    org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifierOrBuilder getRegionOrBuilder(
+        int index);
+
+    // repeated .hbase.pb.RegionLoadStats stat = 2;
+    /**
+     * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+     */
+    java.util.List<org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats>
+        getStatList();
+    /**
+     * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+     */
+    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats getStat(int index);
+    /**
+     * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+     */
+    int getStatCount();
+    /**
+     * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+     */
+    java.util.List<? extends org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStatsOrBuilder>
+        getStatOrBuilderList();
+    /**
+     * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+     */
+    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStatsOrBuilder getStatOrBuilder(
+        int index);
+  }
+  /**
+   * Protobuf type {@code hbase.pb.MultiRegionLoadStats}
+   */
+  public static final class MultiRegionLoadStats extends
+      com.google.protobuf.GeneratedMessage
+      implements MultiRegionLoadStatsOrBuilder {
+    // Use MultiRegionLoadStats.newBuilder() to construct.
+    private MultiRegionLoadStats(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
+      super(builder);
+      this.unknownFields = builder.getUnknownFields();
+    }
+    private MultiRegionLoadStats(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
+
+    private static final MultiRegionLoadStats defaultInstance;
+    public static MultiRegionLoadStats getDefaultInstance() {
+      return defaultInstance;
+    }
+
+    public MultiRegionLoadStats getDefaultInstanceForType() {
+      return defaultInstance;
+    }
+
+    private final com.google.protobuf.UnknownFieldSet unknownFields;
+    @java.lang.Override
+    public final com.google.protobuf.UnknownFieldSet
+        getUnknownFields() {
+      return this.unknownFields;
+    }
+    private MultiRegionLoadStats(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      initFields();
+      int mutable_bitField0_ = 0;
+      com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+          com.google.protobuf.UnknownFieldSet.newBuilder();
+      try {
+        boolean done = false;
+        while (!done) {
+          int tag = input.readTag();
+          switch (tag) {
+            case 0:
+              done = true;
+              break;
+            default: {
+              if (!parseUnknownField(input, unknownFields,
+                                     extensionRegistry, tag)) {
+                done = true;
+              }
+              break;
+            }
+            case 10: {
+              if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {
+                region_ = new java.util.ArrayList<org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier>();
+                mutable_bitField0_ |= 0x00000001;
+              }
+              region_.add(input.readMessage(org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier.PARSER, extensionRegistry));
+              break;
+            }
+            case 18: {
+              if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) {
+                stat_ = new java.util.ArrayList<org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats>();
+                mutable_bitField0_ |= 0x00000002;
+              }
+              stat_.add(input.readMessage(org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats.PARSER, extensionRegistry));
+              break;
+            }
+          }
+        }
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(this);
+      } catch (java.io.IOException e) {
+        throw new com.google.protobuf.InvalidProtocolBufferException(
+            e.getMessage()).setUnfinishedMessage(this);
+      } finally {
+        if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) {
+          region_ = java.util.Collections.unmodifiableList(region_);
+        }
+        if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) {
+          stat_ = java.util.Collections.unmodifiableList(stat_);
+        }
+        this.unknownFields = unknownFields.build();
+        makeExtensionsImmutable();
+      }
+    }
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return org.apache.hadoop.hbase.protobuf.generated.ClientProtos.internal_static_hbase_pb_MultiRegionLoadStats_descriptor;
+    }
+
+    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return org.apache.hadoop.hbase.protobuf.generated.ClientProtos.internal_static_hbase_pb_MultiRegionLoadStats_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats.class, org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats.Builder.class);
+    }
+
+    public static com.google.protobuf.Parser<MultiRegionLoadStats> PARSER =
+        new com.google.protobuf.AbstractParser<MultiRegionLoadStats>() {
+      public MultiRegionLoadStats parsePartialFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws com.google.protobuf.InvalidProtocolBufferException {
+        return new MultiRegionLoadStats(input, extensionRegistry);
+      }
+    };
+
+    @java.lang.Override
+    public com.google.protobuf.Parser<MultiRegionLoadStats> getParserForType() {
+      return PARSER;
+    }
+
+    // repeated .hbase.pb.RegionSpecifier region = 1;
+    public static final int REGION_FIELD_NUMBER = 1;
+    private java.util.List<org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier> region_;
+    /**
+     * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+     */
+    public java.util.List<org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier> getRegionList() {
+      return region_;
+    }
+    /**
+     * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+     */
+    public java.util.List<? extends org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifierOrBuilder>
+        getRegionOrBuilderList() {
+      return region_;
+    }
+    /**
+     * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+     */
+    public int getRegionCount() {
+      return region_.size();
+    }
+    /**
+     * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+     */
+    public org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier getRegion(int index) {
+      return region_.get(index);
+    }
+    /**
+     * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+     */
+    public org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifierOrBuilder getRegionOrBuilder(
+        int index) {
+      return region_.get(index);
+    }
+
+    // repeated .hbase.pb.RegionLoadStats stat = 2;
+    public static final int STAT_FIELD_NUMBER = 2;
+    private java.util.List<org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats> stat_;
+    /**
+     * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+     */
+    public java.util.List<org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats> getStatList() {
+      return stat_;
+    }
+    /**
+     * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+     */
+    public java.util.List<? extends org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStatsOrBuilder>
+        getStatOrBuilderList() {
+      return stat_;
+    }
+    /**
+     * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+     */
+    public int getStatCount() {
+      return stat_.size();
+    }
+    /**
+     * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+     */
+    public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats getStat(int index) {
+      return stat_.get(index);
+    }
+    /**
+     * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+     */
+    public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStatsOrBuilder getStatOrBuilder(
+        int index) {
+      return stat_.get(index);
+    }
+
+    private void initFields() {
+      region_ = java.util.Collections.emptyList();
+      stat_ = java.util.Collections.emptyList();
+    }
+    private byte memoizedIsInitialized = -1;
+    public final boolean isInitialized() {
+      byte isInitialized = memoizedIsInitialized;
+      if (isInitialized != -1) return isInitialized == 1;
+
+      for (int i = 0; i < getRegionCount(); i++) {
+        if (!getRegion(i).isInitialized()) {
+          memoizedIsInitialized = 0;
+          return false;
+        }
+      }
+      memoizedIsInitialized = 1;
+      return true;
+    }
+
+    public void writeTo(com.google.protobuf.CodedOutputStream output)
+                        throws java.io.IOException {
+      getSerializedSize();
+      for (int i = 0; i < region_.size(); i++) {
+        output.writeMessage(1, region_.get(i));
+      }
+      for (int i = 0; i < stat_.size(); i++) {
+        output.writeMessage(2, stat_.get(i));
+      }
+      getUnknownFields().writeTo(output);
+    }
+
+    private int memoizedSerializedSize = -1;
+    public int getSerializedSize() {
+      int size = memoizedSerializedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      for (int i = 0; i < region_.size(); i++) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(1, region_.get(i));
+      }
+      for (int i = 0; i < stat_.size(); i++) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(2, stat_.get(i));
+      }
+      size += getUnknownFields().getSerializedSize();
+      memoizedSerializedSize = size;
+      return size;
+    }
+
+    private static final long serialVersionUID = 0L;
+    @java.lang.Override
+    protected java.lang.Object writeReplace()
+        throws java.io.ObjectStreamException {
+      return super.writeReplace();
+    }
+
+    @java.lang.Override
+    public boolean equals(final java.lang.Object obj) {
+      if (obj == this) {
+       return true;
+      }
+      if (!(obj instanceof org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats)) {
+        return super.equals(obj);
+      }
+      org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats other = (org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats) obj;
+
+      boolean result = true;
+      result = result && getRegionList()
+          .equals(other.getRegionList());
+      result = result && getStatList()
+          .equals(other.getStatList());
+      result = result &&
+          getUnknownFields().equals(other.getUnknownFields());
+      return result;
+    }
+
+    private int memoizedHashCode = 0;
+    @java.lang.Override
+    public int hashCode() {
+      if (memoizedHashCode != 0) {
+        return memoizedHashCode;
+      }
+      int hash = 41;
+      hash = (19 * hash) + getDescriptorForType().hashCode();
+      if (getRegionCount() > 0) {
+        hash = (37 * hash) + REGION_FIELD_NUMBER;
+        hash = (53 * hash) + getRegionList().hashCode();
+      }
+      if (getStatCount() > 0) {
+        hash = (37 * hash) + STAT_FIELD_NUMBER;
+        hash = (53 * hash) + getStatList().hashCode();
+      }
+      hash = (29 * hash) + getUnknownFields().hashCode();
+      memoizedHashCode = hash;
+      return hash;
+    }
+
+    public static org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats parseFrom(
+        com.google.protobuf.ByteString data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats parseFrom(
+        com.google.protobuf.ByteString data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats parseFrom(byte[] data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats parseFrom(
+        byte[] data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats parseFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats parseFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+    public static org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats parseDelimitedFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input);
+    }
+    public static org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats parseDelimitedFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input, extensionRegistry);
+    }
+    public static org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats parseFrom(
+        com.google.protobuf.CodedInputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats parseFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+
+    public static Builder newBuilder() { return Builder.create(); }
+    public Builder newBuilderForType() { return newBuilder(); }
+    public static Builder newBuilder(org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats prototype) {
+      return newBuilder().mergeFrom(prototype);
+    }
+    public Builder toBuilder() { return newBuilder(this); }
+
+    @java.lang.Override
+    protected Builder newBuilderForType(
+        com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+      Builder builder = new Builder(parent);
+      return builder;
+    }
+    /**
+     * Protobuf type {@code hbase.pb.MultiRegionLoadStats}
+     */
+    public static final class Builder extends
+        com.google.protobuf.GeneratedMessage.Builder<Builder>
+       implements org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStatsOrBuilder {
+      public static final com.google.protobuf.Descriptors.Descriptor
+          getDescriptor() {
+        return org.apache.hadoop.hbase.protobuf.generated.ClientProtos.internal_static_hbase_pb_MultiRegionLoadStats_descriptor;
+      }
+
+      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+          internalGetFieldAccessorTable() {
+        return org.apache.hadoop.hbase.protobuf.generated.ClientProtos.internal_static_hbase_pb_MultiRegionLoadStats_fieldAccessorTable
+            .ensureFieldAccessorsInitialized(
+                org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats.class, org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats.Builder.class);
+      }
+
+      // Construct using org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats.newBuilder()
+      private Builder() {
+        maybeForceBuilderInitialization();
+      }
+
+      private Builder(
+          com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+        super(parent);
+        maybeForceBuilderInitialization();
+      }
+      private void maybeForceBuilderInitialization() {
+        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+          getRegionFieldBuilder();
+          getStatFieldBuilder();
+        }
+      }
+      private static Builder create() {
+        return new Builder();
+      }
+
+      public Builder clear() {
+        super.clear();
+        if (regionBuilder_ == null) {
+          region_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000001);
+        } else {
+          regionBuilder_.clear();
+        }
+        if (statBuilder_ == null) {
+          stat_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000002);
+        } else {
+          statBuilder_.clear();
+        }
+        return this;
+      }
+
+      public Builder clone() {
+        return create().mergeFrom(buildPartial());
+      }
+
+      public com.google.protobuf.Descriptors.Descriptor
+          getDescriptorForType() {
+        return org.apache.hadoop.hbase.protobuf.generated.ClientProtos.internal_static_hbase_pb_MultiRegionLoadStats_descriptor;
+      }
+
+      public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats getDefaultInstanceForType() {
+        return org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats.getDefaultInstance();
+      }
+
+      public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats build() {
+        org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats result = buildPartial();
+        if (!result.isInitialized()) {
+          throw newUninitializedMessageException(result);
+        }
+        return result;
+      }
+
+      public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats buildPartial() {
+        org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats result = new org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats(this);
+        int from_bitField0_ = bitField0_;
+        if (regionBuilder_ == null) {
+          if (((bitField0_ & 0x00000001) == 0x00000001)) {
+            region_ = java.util.Collections.unmodifiableList(region_);
+            bitField0_ = (bitField0_ & ~0x00000001);
+          }
+          result.region_ = region_;
+        } else {
+          result.region_ = regionBuilder_.build();
+        }
+        if (statBuilder_ == null) {
+          if (((bitField0_ & 0x00000002) == 0x00000002)) {
+            stat_ = java.util.Collections.unmodifiableList(stat_);
+            bitField0_ = (bitField0_ & ~0x00000002);
+          }
+          result.stat_ = stat_;
+        } else {
+          result.stat_ = statBuilder_.build();
+        }
+        onBuilt();
+        return result;
+      }
+
+      public Builder mergeFrom(com.google.protobuf.Message other) {
+        if (other instanceof org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats) {
+          return mergeFrom((org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats)other);
+        } else {
+          super.mergeFrom(other);
+          return this;
+        }
+      }
+
+      public Builder mergeFrom(org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats other) {
+        if (other == org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats.getDefaultInstance()) return this;
+        if (regionBuilder_ == null) {
+          if (!other.region_.isEmpty()) {
+            if (region_.isEmpty()) {
+              region_ = other.region_;
+              bitField0_ = (bitField0_ & ~0x00000001);
+            } else {
+              ensureRegionIsMutable();
+              region_.addAll(other.region_);
+            }
+            onChanged();
+          }
+        } else {
+          if (!other.region_.isEmpty()) {
+            if (regionBuilder_.isEmpty()) {
+              regionBuilder_.dispose();
+              regionBuilder_ = null;
+              region_ = other.region_;
+              bitField0_ = (bitField0_ & ~0x00000001);
+              regionBuilder_ =
+                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?
+                   getRegionFieldBuilder() : null;
+            } else {
+              regionBuilder_.addAllMessages(other.region_);
+            }
+          }
+        }
+        if (statBuilder_ == null) {
+          if (!other.stat_.isEmpty()) {
+            if (stat_.isEmpty()) {
+              stat_ = other.stat_;
+              bitField0_ = (bitField0_ & ~0x00000002);
+            } else {
+              ensureStatIsMutable();
+              stat_.addAll(other.stat_);
+            }
+            onChanged();
+          }
+        } else {
+          if (!other.stat_.isEmpty()) {
+            if (statBuilder_.isEmpty()) {
+              statBuilder_.dispose();
+              statBuilder_ = null;
+              stat_ = other.stat_;
+              bitField0_ = (bitField0_ & ~0x00000002);
+              statBuilder_ =
+                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?
+                   getStatFieldBuilder() : null;
+            } else {
+              statBuilder_.addAllMessages(other.stat_);
+            }
+          }
+        }
+        this.mergeUnknownFields(other.getUnknownFields());
+        return this;
+      }
+
+      public final boolean isInitialized() {
+        for (int i = 0; i < getRegionCount(); i++) {
+          if (!getRegion(i).isInitialized()) {
+
+            return false;
+          }
+        }
+        return true;
+      }
+
+      public Builder mergeFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws java.io.IOException {
+        org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats parsedMessage = null;
+        try {
+          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+          parsedMessage = (org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats) e.getUnfinishedMessage();
+          throw e;
+        } finally {
+          if (parsedMessage != null) {
+            mergeFrom(parsedMessage);
+          }
+        }
+        return this;
+      }
+      private int bitField0_;
+
+      // repeated .hbase.pb.RegionSpecifier region = 1;
+      private java.util.List<org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier> region_ =
+        java.util.Collections.emptyList();
+      private void ensureRegionIsMutable() {
+        if (!((bitField0_ & 0x00000001) == 0x00000001)) {
+          region_ = new java.util.ArrayList<org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier>(region_);
+          bitField0_ |= 0x00000001;
+         }
+      }
+
+      private com.google.protobuf.RepeatedFieldBuilder<
+          org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier, org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier.Builder, org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifierOrBuilder> regionBuilder_;
+
+      /**
+       * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+       */
+      public java.util.List<org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier> getRegionList() {
+        if (regionBuilder_ == null) {
+          return java.util.Collections.unmodifiableList(region_);
+        } else {
+          return regionBuilder_.getMessageList();
+        }
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+       */
+      public int getRegionCount() {
+        if (regionBuilder_ == null) {
+          return region_.size();
+        } else {
+          return regionBuilder_.getCount();
+        }
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+       */
+      public org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier getRegion(int index) {
+        if (regionBuilder_ == null) {
+          return region_.get(index);
+        } else {
+          return regionBuilder_.getMessage(index);
+        }
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+       */
+      public Builder setRegion(
+          int index, org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier value) {
+        if (regionBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureRegionIsMutable();
+          region_.set(index, value);
+          onChanged();
+        } else {
+          regionBuilder_.setMessage(index, value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+       */
+      public Builder setRegion(
+          int index, org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier.Builder builderForValue) {
+        if (regionBuilder_ == null) {
+          ensureRegionIsMutable();
+          region_.set(index, builderForValue.build());
+          onChanged();
+        } else {
+          regionBuilder_.setMessage(index, builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+       */
+      public Builder addRegion(org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier value) {
+        if (regionBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureRegionIsMutable();
+          region_.add(value);
+          onChanged();
+        } else {
+          regionBuilder_.addMessage(value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+       */
+      public Builder addRegion(
+          int index, org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier value) {
+        if (regionBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureRegionIsMutable();
+          region_.add(index, value);
+          onChanged();
+        } else {
+          regionBuilder_.addMessage(index, value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+       */
+      public Builder addRegion(
+          org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier.Builder builderForValue) {
+        if (regionBuilder_ == null) {
+          ensureRegionIsMutable();
+          region_.add(builderForValue.build());
+          onChanged();
+        } else {
+          regionBuilder_.addMessage(builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+       */
+      public Builder addRegion(
+          int index, org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier.Builder builderForValue) {
+        if (regionBuilder_ == null) {
+          ensureRegionIsMutable();
+          region_.add(index, builderForValue.build());
+          onChanged();
+        } else {
+          regionBuilder_.addMessage(index, builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+       */
+      public Builder addAllRegion(
+          java.lang.Iterable<? extends org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier> values) {
+        if (regionBuilder_ == null) {
+          ensureRegionIsMutable();
+          super.addAll(values, region_);
+          onChanged();
+        } else {
+          regionBuilder_.addAllMessages(values);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+       */
+      public Builder clearRegion() {
+        if (regionBuilder_ == null) {
+          region_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000001);
+          onChanged();
+        } else {
+          regionBuilder_.clear();
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+       */
+      public Builder removeRegion(int index) {
+        if (regionBuilder_ == null) {
+          ensureRegionIsMutable();
+          region_.remove(index);
+          onChanged();
+        } else {
+          regionBuilder_.remove(index);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+       */
+      public org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier.Builder getRegionBuilder(
+          int index) {
+        return getRegionFieldBuilder().getBuilder(index);
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+       */
+      public org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifierOrBuilder getRegionOrBuilder(
+          int index) {
+        if (regionBuilder_ == null) {
+          return region_.get(index);  } else {
+          return regionBuilder_.getMessageOrBuilder(index);
+        }
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+       */
+      public java.util.List<? extends org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifierOrBuilder>
+           getRegionOrBuilderList() {
+        if (regionBuilder_ != null) {
+          return regionBuilder_.getMessageOrBuilderList();
+        } else {
+          return java.util.Collections.unmodifiableList(region_);
+        }
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+       */
+      public org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier.Builder addRegionBuilder() {
+        return getRegionFieldBuilder().addBuilder(
+            org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier.getDefaultInstance());
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+       */
+      public org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier.Builder addRegionBuilder(
+          int index) {
+        return getRegionFieldBuilder().addBuilder(
+            index, org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier.getDefaultInstance());
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionSpecifier region = 1;</code>
+       */
+      public java.util.List<org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier.Builder>
+           getRegionBuilderList() {
+        return getRegionFieldBuilder().getBuilderList();
+      }
+      private com.google.protobuf.RepeatedFieldBuilder<
+          org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier, org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier.Builder, org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifierOrBuilder>
+          getRegionFieldBuilder() {
+        if (regionBuilder_ == null) {
+          regionBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<
+              org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier, org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifier.Builder, org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionSpecifierOrBuilder>(
+                  region_,
+                  ((bitField0_ & 0x00000001) == 0x00000001),
+                  getParentForChildren(),
+                  isClean());
+          region_ = null;
+        }
+        return regionBuilder_;
+      }
+
+      // repeated .hbase.pb.RegionLoadStats stat = 2;
+      private java.util.List<org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats> stat_ =
+        java.util.Collections.emptyList();
+      private void ensureStatIsMutable() {
+        if (!((bitField0_ & 0x00000002) == 0x00000002)) {
+          stat_ = new java.util.ArrayList<org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats>(stat_);
+          bitField0_ |= 0x00000002;
+         }
+      }
+
+      private com.google.protobuf.RepeatedFieldBuilder<
+          org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats, org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats.Builder, org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStatsOrBuilder> statBuilder_;
+
+      /**
+       * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+       */
+      public java.util.List<org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats> getStatList() {
+        if (statBuilder_ == null) {
+          return java.util.Collections.unmodifiableList(stat_);
+        } else {
+          return statBuilder_.getMessageList();
+        }
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+       */
+      public int getStatCount() {
+        if (statBuilder_ == null) {
+          return stat_.size();
+        } else {
+          return statBuilder_.getCount();
+        }
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+       */
+      public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats getStat(int index) {
+        if (statBuilder_ == null) {
+          return stat_.get(index);
+        } else {
+          return statBuilder_.getMessage(index);
+        }
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+       */
+      public Builder setStat(
+          int index, org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats value) {
+        if (statBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureStatIsMutable();
+          stat_.set(index, value);
+          onChanged();
+        } else {
+          statBuilder_.setMessage(index, value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+       */
+      public Builder setStat(
+          int index, org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats.Builder builderForValue) {
+        if (statBuilder_ == null) {
+          ensureStatIsMutable();
+          stat_.set(index, builderForValue.build());
+          onChanged();
+        } else {
+          statBuilder_.setMessage(index, builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+       */
+      public Builder addStat(org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats value) {
+        if (statBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureStatIsMutable();
+          stat_.add(value);
+          onChanged();
+        } else {
+          statBuilder_.addMessage(value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+       */
+      public Builder addStat(
+          int index, org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats value) {
+        if (statBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureStatIsMutable();
+          stat_.add(index, value);
+          onChanged();
+        } else {
+          statBuilder_.addMessage(index, value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+       */
+      public Builder addStat(
+          org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats.Builder builderForValue) {
+        if (statBuilder_ == null) {
+          ensureStatIsMutable();
+          stat_.add(builderForValue.build());
+          onChanged();
+        } else {
+          statBuilder_.addMessage(builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+       */
+      public Builder addStat(
+          int index, org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats.Builder builderForValue) {
+        if (statBuilder_ == null) {
+          ensureStatIsMutable();
+          stat_.add(index, builderForValue.build());
+          onChanged();
+        } else {
+          statBuilder_.addMessage(index, builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+       */
+      public Builder addAllStat(
+          java.lang.Iterable<? extends org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats> values) {
+        if (statBuilder_ == null) {
+          ensureStatIsMutable();
+          super.addAll(values, stat_);
+          onChanged();
+        } else {
+          statBuilder_.addAllMessages(values);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+       */
+      public Builder clearStat() {
+        if (statBuilder_ == null) {
+          stat_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000002);
+          onChanged();
+        } else {
+          statBuilder_.clear();
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+       */
+      public Builder removeStat(int index) {
+        if (statBuilder_ == null) {
+          ensureStatIsMutable();
+          stat_.remove(index);
+          onChanged();
+        } else {
+          statBuilder_.remove(index);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+       */
+      public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats.Builder getStatBuilder(
+          int index) {
+        return getStatFieldBuilder().getBuilder(index);
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+       */
+      public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStatsOrBuilder getStatOrBuilder(
+          int index) {
+        if (statBuilder_ == null) {
+          return stat_.get(index);  } else {
+          return statBuilder_.getMessageOrBuilder(index);
+        }
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+       */
+      public java.util.List<? extends org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStatsOrBuilder>
+           getStatOrBuilderList() {
+        if (statBuilder_ != null) {
+          return statBuilder_.getMessageOrBuilderList();
+        } else {
+          return java.util.Collections.unmodifiableList(stat_);
+        }
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+       */
+      public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats.Builder addStatBuilder() {
+        return getStatFieldBuilder().addBuilder(
+            org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats.getDefaultInstance());
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+       */
+      public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats.Builder addStatBuilder(
+          int index) {
+        return getStatFieldBuilder().addBuilder(
+            index, org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats.getDefaultInstance());
+      }
+      /**
+       * <code>repeated .hbase.pb.RegionLoadStats stat = 2;</code>
+       */
+      public java.util.List<org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats.Builder>
+           getStatBuilderList() {
+        return getStatFieldBuilder().getBuilderList();
+      }
+      private com.google.protobuf.RepeatedFieldBuilder<
+          org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats, org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats.Builder, org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStatsOrBuilder>
+          getStatFieldBuilder() {
+        if (statBuilder_ == null) {
+          statBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<
+              org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats, org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats.Builder, org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStatsOrBuilder>(
+                  stat_,
+                  ((bitField0_ & 0x00000002) == 0x00000002),
+                  getParentForChildren(),
+                  isClean());
+          stat_ = null;
+        }
+        return statBuilder_;
+      }
+
+      // @@protoc_insertion_point(builder_scope:hbase.pb.MultiRegionLoadStats)
+    }
+
+    static {
+      defaultInstance = new MultiRegionLoadStats(true);
+      defaultInstance.initFields();
+    }
+
+    // @@protoc_insertion_point(class_scope:hbase.pb.MultiRegionLoadStats)
+  }
+
   public interface ResultOrExceptionOrBuilder
       extends com.google.protobuf.MessageOrBuilder {
 
@@ -29104,31 +30193,31 @@ public final class ClientProtos {
      */
     org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceResultOrBuilder getServiceResultOrBuilder();
 
-    // optional .hbase.pb.RegionLoadStats loadStats = 5;
+    // optional .hbase.pb.RegionLoadStats loadStats = 5 [deprecated = true];
     /**
-     * <code>optional .hbase.pb.RegionLoadStats loadStats = 5;</code>
+     * <code>optional .hbase.pb.RegionLoadStats loadStats = 5 [deprecated = true];</code>
      *
      * <pre>
      * current load on the region
      * </pre>
      */
-    boolean hasLoadStats();
+    @java.lang.Deprecated boolean hasLoadStats();
     /**
-     * <code>optional .hbase.pb.RegionLoadStats loadStats = 5;</code>
+     * <code>optional .hbase.pb.RegionLoadStats loadStats = 5 [deprecated = true];</code>
      *
      * <pre>
      * current load on the region
      * </pre>
      */
-    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats getLoadStats();
+    @java.lang.Deprecated org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats getLoadStats();
     /**
-     * <code>optional .hbase.pb.RegionLoadStats loadStats = 5;</code>
+     * <code>optional .hbase.pb.RegionLoadStats loadStats = 5 [deprecated = true];</code>
      *
      * <pre>
      * current load on the region
      * </pre>
      */
-    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStatsOrBuilder getLoadStatsOrBuilder();
+    @java.lang.Deprecated org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStatsOrBuilder getLoadStatsOrBuilder();
   }
   /**
    * Protobuf type {@code hbase.pb.ResultOrException}
@@ -29389,37 +30478,37 @@ public final class ClientProtos {
       return serviceResult_;
     }
 
-    // optional .hbase.pb.RegionLoadStats loadStats = 5;
+    // optional .hbase.pb.RegionLoadStats loadStats = 5 [deprecated = true];
     public static final int LOADSTATS_FIELD_NUMBER = 5;
     private org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats loadStats_;
     /**
-     * <code>optional .hbase.pb.RegionLoadStats loadStats = 5;</code>
+     * <code>optional .hbase.pb.RegionLoadStats loadStats = 5 [deprecated = true];</code>
      *
      * <pre>
      * current load on the region
      * </pre>
      */
-    public boolean hasLoadStats() {
+    @java.lang.Deprecated public boolean hasLoadStats() {
       return ((bitField0_ & 0x00000010) == 0x00000010);
     }
     /**
-     * <code>optional .hbase.pb.RegionLoadStats loadStats = 5;</code>
+     * <code>optional .hbase.pb.RegionLoadStats loadStats = 5 [deprecated = true];</code>
      *
      * <pre>
      * current load on the region
      * </pre>
      */
-    public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats getLoadStats() {
+    @java.lang.Deprecated public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats getLoadStats() {
       return loadStats_;
     }
     /**
-     * <code>optional .hbase.pb.RegionLoadStats loadStats = 5;</code>
+     * <code>optional .hbase.pb.RegionLoadStats loadStats = 5 [deprecated = true];</code>
      *
      * <pre>
      * current load on the region
      * </pre>
      */
-    public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStatsOrBuilder getLoadStatsOrBuilder() {
+    @java.lang.Deprecated public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStatsOrBuilder getLoadStatsOrBuilder() {
       return loadStats_;
     }
 
@@ -30299,28 +31388,28 @@ public final class ClientProtos {
         return serviceResultBuilder_;
       }
 
-      // optional .hbase.pb.RegionLoadStats loadStats = 5;
+      // optional .hbase.pb.RegionLoadStats loadStats = 5 [deprecated = true];
       private org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats loadStats_ = org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats.getDefaultInstance();
       private com.google.protobuf.SingleFieldBuilder<
           org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats, org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats.Builder, org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStatsOrBuilder> loadStatsBuilder_;
       /**
-       * <code>optional .hbase.pb.RegionLoadStats loadStats = 5;</code>
+       * <code>optional .hbase.pb.RegionLoadStats loadStats = 5 [deprecated = true];</code>
        *
        * <pre>
        * current load on the region
        * </pre>
        */
-      public boolean hasLoadStats() {
+      @java.lang.Deprecated public boolean hasLoadStats() {
         return ((bitField0_ & 0x00000010) == 0x00000010);
       }
       /**
-       * <code>optional .hbase.pb.RegionLoadStats loadStats = 5;</code>
+       * <code>optional .hbase.pb.RegionLoadStats loadStats = 5 [deprecated = true];</code>
        *
        * <pre>
        * current load on the region
        * </pre>
        */
-      public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats getLoadStats() {
+      @java.lang.Deprecated public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats getLoadStats() {
         if (loadStatsBuilder_ == null) {
           return loadStats_;
         } else {
@@ -30328,13 +31417,13 @@ public final class ClientProtos {
         }
       }
       /**
-       * <code>optional .hbase.pb.RegionLoadStats loadStats = 5;</code>
+       * <code>optional .hbase.pb.RegionLoadStats loadStats = 5 [deprecated = true];</code>
        *
        * <pre>
        * current load on the region
        * </pre>
        */
-      public Builder setLoadStats(org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats value) {
+      @java.lang.Deprecated public Builder setLoadStats(org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats value) {
         if (loadStatsBuilder_ == null) {
           if (value == null) {
             throw new NullPointerException();
@@ -30348,13 +31437,13 @@ public final class ClientProtos {
         return this;
       }
       /**
-       * <code>optional .hbase.pb.RegionLoadStats loadStats = 5;</code>
+       * <code>optional .hbase.pb.RegionLoadStats loadStats = 5 [deprecated = true];</code>
        *
        * <pre>
        * current load on the region
        * </pre>
        */
-      public Builder setLoadStats(
+      @java.lang.Deprecated public Builder setLoadStats(
           org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats.Builder builderForValue) {
         if (loadStatsBuilder_ == null) {
           loadStats_ = builderForValue.build();
@@ -30366,13 +31455,13 @@ public final class ClientProtos {
         return this;
       }
       /**
-       * <code>optional .hbase.pb.RegionLoadStats loadStats = 5;</code>
+       * <code>optional .hbase.pb.RegionLoadStats loadStats = 5 [deprecated = true];</code>
        *
        * <pre>
        * current load on the region
        * </pre>
        */
-      public Builder mergeLoadStats(org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats value) {
+      @java.lang.Deprecated public Builder mergeLoadStats(org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats value) {
         if (loadStatsBuilder_ == null) {
           if (((bitField0_ & 0x00000010) == 0x00000010) &&
               loadStats_ != org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats.getDefaultInstance()) {
@@ -30389,13 +31478,13 @@ public final class ClientProtos {
         return this;
       }
       /**
-       * <code>optional .hbase.pb.RegionLoadStats loadStats = 5;</code>
+       * <code>optional .hbase.pb.RegionLoadStats loadStats = 5 [deprecated = true];</code>
        *
        * <pre>
        * current load on the region
        * </pre>
        */
-      public Builder clearLoadStats() {
+      @java.lang.Deprecated public Builder clearLoadStats() {
         if (loadStatsBuilder_ == null) {
           loadStats_ = org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats.getDefaultInstance();
           onChanged();
@@ -30406,25 +31495,25 @@ public final class ClientProtos {
         return this;
       }
       /**
-       * <code>optional .hbase.pb.RegionLoadStats loadStats = 5;</code>
+       * <code>optional .hbase.pb.RegionLoadStats loadStats = 5 [deprecated = true];</code>
        *
        * <pre>
        * current load on the region
        * </pre>
        */
-      public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats.Builder getLoadStatsBuilder() {
+      @java.lang.Deprecated public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStats.Builder getLoadStatsBuilder() {
         bitField0_ |= 0x00000010;
         onChanged();
         return getLoadStatsFieldBuilder().getBuilder();
       }
       /**
-       * <code>optional .hbase.pb.RegionLoadStats loadStats = 5;</code>
+       * <code>optional .hbase.pb.RegionLoadStats loadStats = 5 [deprecated = true];</code>
        *
        * <pre>
        * current load on the region
        * </pre>
        */
-      public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStatsOrBuilder getLoadStatsOrBuilder() {
+      @java.lang.Deprecated public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionLoadStatsOrBuilder getLoadStatsOrBuilder() {
         if (loadStatsBuilder_ != null) {
           return loadStatsBuilder_.getMessageOrBuilder();
         } else {
@@ -30432,7 +31521,7 @@ public final class ClientProtos {
         }
       }
       /**
-       * <code>optional .hbase.pb.RegionLoadStats loadStats = 5;</code>
+       * <code>optional .hbase.pb.RegionLoadStats loadStats = 5 [deprecated = true];</code>
        *
        * <pre>
        * current load on the region
@@ -32560,6 +33649,20 @@ public final class ClientProtos {
      * </pre>
      */
     boolean getProcessed();
+
+    // optional .hbase.pb.MultiRegionLoadStats regionStatistics = 3;
+    /**
+     * <code>optional .hbase.pb.MultiRegionLoadStats regionStatistics = 3;</code>
+     */
+    boolean hasRegionStatistics();
+    /**
+     * <code>optional .hbase.pb.MultiRegionLoadStats regionStatistics = 3;</code>
+     */
+    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats getRegionStatistics();
+    /**
+     * <code>optional .hbase.pb.MultiRegionLoadStats regionStatistics = 3;</code>
+     */
+    org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStatsOrBuilder getRegionStatisticsOrBuilder();
   }
   /**
    * Protobuf type {@code hbase.pb.MultiResponse}
@@ -32625,6 +33728,19 @@ public final class ClientProtos {
               processed_ = input.readBool();
               break;
             }
+            case 26: {
+              org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats.Builder subBuilder = null;
+              if (((bitField0_ & 0x00000002) == 0x00000002)) {
+                subBuilder = regionStatistics_.toBuilder();
+              }
+              regionStatistics_ = input.readMessage(org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats.PARSER, extensionRegistry);
+              if (subBuilder != null) {
+                subBuilder.mergeFrom(regionStatistics_);
+                regionStatistics_ = subBuilder.buildPartial();
+              }
+              bitField0_ |= 0x00000002;
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -32728,9 +33844,32 @@ public final class ClientProtos {
       return processed_;
     }
 
+    // optional .hbase.pb.MultiRegionLoadStats regionStatistics = 3;
+    public static final int REGIONSTATISTICS_FIELD_NUMBER = 3;
+    private org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats regionStatistics_;
+    /**
+     * <code>optional .hbase.pb.MultiRegionLoadStats regionStatistics = 3;</code>
+     */
+    public boolean hasRegionStatistics() {
+      return ((bitField0_ & 0x00000002) == 0x00000002);
+    }
+    /**
+     * <code>optional .hbase.pb.MultiRegionLoadStats regionStatistics = 3;</code>
+     */
+    public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats getRegionStatistics() {
+      return regionStatistics_;
+    }
+    /**
+     * <code>optional .hbase.pb.MultiRegionLoadStats regionStatistics = 3;</code>
+     */
+    public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStatsOrBuilder getRegionStatisticsOrBuilder() {
+      return regionStatistics_;
+    }
+
     private void initFields() {
       regionActionResult_ = java.util.Collections.emptyList();
       processed_ = false;
+      regionStatistics_ = org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats.getDefaultInstance();
     }
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
@@ -32743,6 +33882,12 @@ public final class ClientProtos {
           return false;
         }
       }
+      if (hasRegionStatistics()) {
+        if (!getRegionStatistics().isInitialized()) {
+          memoizedIsInitialized = 0;
+          return false;
+        }
+      }
       memoizedIsInitialized = 1;
       return true;
     }
@@ -32756,6 +33901,9 @@ public final class ClientProtos {
       if (((bitField0_ & 0x00000001) == 0x00000001)) {
         output.writeBool(2, processed_);
       }
+      if (((bitField0_ & 0x00000002) == 0x00000002)) {
+        output.writeMessage(3, regionStatistics_);
+      }
       getUnknownFields().writeTo(output);
     }
 
@@ -32773,6 +33921,10 @@ public final class ClientProtos {
         size += com.google.protobuf.CodedOutputStream
           .computeBoolSize(2, processed_);
       }
+      if (((bitField0_ & 0x00000002) == 0x00000002)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(3, regionStatistics_);
+      }
       size += getUnknownFields().getSerializedSize();
       memoizedSerializedSize = size;
       return size;
@@ -32803,6 +33955,11 @@ public final class ClientProtos {
         result = result && (getProcessed()
             == other.getProcessed());
       }
+      result = result && (hasRegionStatistics() == other.hasRegionStatistics());
+      if (hasRegionStatistics()) {
+        result = result && getRegionStatistics()
+            .equals(other.getRegionStatistics());
+      }
       result = result &&
           getUnknownFields().equals(other.getUnknownFields());
       return result;
@@ -32824,6 +33981,10 @@ public final class ClientProtos {
         hash = (37 * hash) + PROCESSED_FIELD_NUMBER;
         hash = (53 * hash) + hashBoolean(getProcessed());
       }
+      if (hasRegionStatistics()) {
+        hash = (37 * hash) + REGIONSTATISTICS_FIELD_NUMBER;
+        hash = (53 * hash) + getRegionStatistics().hashCode();
+      }
       hash = (29 * hash) + getUnknownFields().hashCode();
       memoizedHashCode = hash;
       return hash;
@@ -32926,6 +34087,7 @@ public final class ClientProtos {
       private void maybeForceBuilderInitialization() {
         if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
           getRegionActionResultFieldBuilder();
+          getRegionStatisticsFieldBuilder();
         }
       }
       private static Builder create() {
@@ -32942,6 +34104,12 @@ public final class ClientProtos {
         }
         processed_ = false;
         bitField0_ = (bitField0_ & ~0x00000002);
+        if (regionStatisticsBuilder_ == null) {
+          regionStatistics_ = org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats.getDefaultInstance();
+        } else {
+          regionStatisticsBuilder_.clear();
+        }
+        bitField0_ = (bitField0_ & ~0x00000004);
         return this;
       }
 
@@ -32983,6 +34151,14 @@ public final class ClientProtos {
           to_bitField0_ |= 0x00000001;
         }
         result.processed_ = processed_;
+        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
+          to_bitField0_ |= 0x00000002;
+        }
+        if (regionStatisticsBuilder_ == null) {
+          result.regionStatistics_ = regionStatistics_;
+        } else {
+          result.regionStatistics_ = regionStatisticsBuilder_.build();
+        }
         result.bitField0_ = to_bitField0_;
         onBuilt();
         return result;
@@ -33028,6 +34204,9 @@ public final class ClientProtos {
         if (other.hasProcessed()) {
           setProcessed(other.getProcessed());
         }
+        if (other.hasRegionStatistics()) {
+          mergeRegionStatistics(other.getRegionStatistics());
+        }
         this.mergeUnknownFields(other.getUnknownFields());
         return this;
       }
@@ -33039,6 +34218,12 @@ public final class ClientProtos {
             return false;
           }
         }
+        if (hasRegionStatistics()) {
+          if (!getRegionStatistics().isInitialized()) {
+
+            return false;
+          }
+        }
         return true;
       }
 
@@ -33350,6 +34535,123 @@ public final class ClientProtos {
         return this;
       }
 
+      // optional .hbase.pb.MultiRegionLoadStats regionStatistics = 3;
+      private org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats regionStatistics_ = org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats.getDefaultInstance();
+      private com.google.protobuf.SingleFieldBuilder<
+          org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats, org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats.Builder, org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStatsOrBuilder> regionStatisticsBuilder_;
+      /**
+       * <code>optional .hbase.pb.MultiRegionLoadStats regionStatistics = 3;</code>
+       */
+      public boolean hasRegionStatistics() {
+        return ((bitField0_ & 0x00000004) == 0x00000004);
+      }
+      /**
+       * <code>optional .hbase.pb.MultiRegionLoadStats regionStatistics = 3;</code>
+       */
+      public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats getRegionStatistics() {
+        if (regionStatisticsBuilder_ == null) {
+          return regionStatistics_;
+        } else {
+          return regionStatisticsBuilder_.getMessage();
+        }
+      }
+      /**
+       * <code>optional .hbase.pb.MultiRegionLoadStats regionStatistics = 3;</code>
+       */
+      public Builder setRegionStatistics(org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats value) {
+        if (regionStatisticsBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          regionStatistics_ = value;
+          onChanged();
+        } else {
+          regionStatisticsBuilder_.setMessage(value);
+        }
+        bitField0_ |= 0x00000004;
+        return this;
+      }
+      /**
+       * <code>optional .hbase.pb.MultiRegionLoadStats regionStatistics = 3;</code>
+       */
+      public Builder setRegionStatistics(
+          org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats.Builder builderForValue) {
+        if (regionStatisticsBuilder_ == null) {
+          regionStatistics_ = builderForValue.build();
+          onChanged();
+        } else {
+          regionStatisticsBuilder_.setMessage(builderForValue.build());
+        }
+        bitField0_ |= 0x00000004;
+        return this;
+      }
+      /**
+       * <code>optional .hbase.pb.MultiRegionLoadStats regionStatistics = 3;</code>
+       */
+      public Builder mergeRegionStatistics(org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats value) {
+        if (regionStatisticsBuilder_ == null) {
+          if (((bitField0_ & 0x00000004) == 0x00000004) &&
+              regionStatistics_ != org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats.getDefaultInstance()) {
+            regionStatistics_ =
+              org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats.newBuilder(regionStatistics_).mergeFrom(value).buildPartial();
+          } else {
+            regionStatistics_ = value;
+          }
+          onChanged();
+        } else {
+          regionStatisticsBuilder_.mergeFrom(value);
+        }
+        bitField0_ |= 0x00000004;
+        return this;
+      }
+      /**
+       * <code>optional .hbase.pb.MultiRegionLoadStats regionStatistics = 3;</code>
+       */
+      public Builder clearRegionStatistics() {
+        if (regionStatisticsBuilder_ == null) {
+          regionStatistics_ = org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats.getDefaultInstance();
+          onChanged();
+        } else {
+          regionStatisticsBuilder_.clear();
+        }
+        bitField0_ = (bitField0_ & ~0x00000004);
+        return this;
+      }
+      /**
+       * <code>optional .hbase.pb.MultiRegionLoadStats regionStatistics = 3;</code>
+       */
+      public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats.Builder getRegionStatisticsBuilder() {
+        bitField0_ |= 0x00000004;
+        onChanged();
+        return getRegionStatisticsFieldBuilder().getBuilder();
+      }
+      /**
+       * <code>optional .hbase.pb.MultiRegionLoadStats regionStatistics = 3;</code>
+       */
+      public org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStatsOrBuilder getRegionStatisticsOrBuilder() {
+        if (regionStatisticsBuilder_ != null) {
+          return regionStatisticsBuilder_.getMessageOrBuilder();
+        } else {
+          return regionStatistics_;
+        }
+      }
+      /**
+       * <code>optional .hbase.pb.MultiRegionLoadStats regionStatistics = 3;</code>
+       */
+      private com.google.protobuf.SingleFieldBuilder<
+          org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats, org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats.Builder, org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStatsOrBuilder>
+          getRegionStatisticsFieldBuilder() {
+        if (regionStatisticsBuilder_ == null) {
+          regionStatisticsBuilder_ = new com.google.protobuf.SingleFieldBuilder<
+              org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats, org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats.Builder, org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStatsOrBuilder>(
+                  regionStatistics_,
+                  getParentForChildren(),
+                  isClean());
+          regionStatistics_ = null;
+        }
+        return regionStatisticsBuilder_;
+      }
+
       // @@protoc_insertion_point(builder_scope:hbase.pb.MultiResponse)
     }
 
@@ -34150,6 +35452,11 @@ public final class ClientProtos {
     com.google.protobuf.GeneratedMessage.FieldAccessorTable
       internal_static_hbase_pb_RegionLoadStats_fieldAccessorTable;
   private static com.google.protobuf.Descriptors.Descriptor
+    internal_static_hbase_pb_MultiRegionLoadStats_descriptor;
+  private static
+    com.google.protobuf.GeneratedMessage.FieldAccessorTable
+      internal_static_hbase_pb_MultiRegionLoadStats_fieldAccessorTable;
+  private static com.google.protobuf.Descriptors.Descriptor
     internal_static_hbase_pb_ResultOrException_descriptor;
   private static
     com.google.protobuf.GeneratedMessage.FieldAccessorTable
@@ -34286,36 +35593,41 @@ public final class ClientProtos {
       "\030\003 \003(\0132\020.hbase.pb.Action\"c\n\017RegionLoadSt" +
       "ats\022\027\n\014memstoreLoad\030\001 \001(\005:\0010\022\030\n\rheapOccu" +
       "pancy\030\002 \001(\005:\0010\022\035\n\022compactionPressure\030\003 \001" +
-      "(\005:\0010\"\332\001\n\021ResultOrException\022\r\n\005index\030\001 \001" +
-      "(\r\022 \n\006result\030\002 \001(\0132\020.hbase.pb.Result\022*\n\t",
-      "exception\030\003 \001(\0132\027.hbase.pb.NameBytesPair" +
-      "\022:\n\016service_result\030\004 \001(\0132\".hbase.pb.Copr" +
-      "ocessorServiceResult\022,\n\tloadStats\030\005 \001(\0132" +
-      "\031.hbase.pb.RegionLoadStats\"x\n\022RegionActi" +
-      "onResult\0226\n\021resultOrException\030\001 \003(\0132\033.hb" +
-      "ase.pb.ResultOrException\022*\n\texception\030\002 " +
-      "\001(\0132\027.hbase.pb.NameBytesPair\"x\n\014MultiReq" +
-      "uest\022,\n\014regionAction\030\001 \003(\0132\026.hbase.pb.Re" +
-      "gionAction\022\022\n\nnonceGroup\030\002 \001(\004\022&\n\tcondit" +
-      "ion\030\003 \001(\0132\023.hbase.pb.Condition\"\\\n\rMultiR",
-      "esponse\0228\n\022regionActionResult\030\001 \003(\0132\034.hb" +
-      "ase.pb.RegionActionResult\022\021\n\tprocessed\030\002" +
-      " \001(\010*\'\n\013Consistency\022\n\n\006STRONG\020\000\022\014\n\010TIMEL" +
-      "INE\020\0012\203\004\n\rClientService\0222\n\003Get\022\024.hbase.p" +
-      "b.GetRequest\032\025.hbase.pb.GetResponse\022;\n\006M" +
-      "utate\022\027.hbase.pb.MutateRequest\032\030.hbase.p" +
-      "b.MutateResponse\0225\n\004Scan\022\025.hbase.pb.Scan" +
-      "Request\032\026.hbase.pb.ScanResponse\022P\n\rBulkL" +
-      "oadHFile\022\036.hbase.pb.BulkLoadHFileRequest" +
-      "\032\037.hbase.pb.BulkLoadHFileResponse\022X\n\013Exe",
-      "cService\022#.hbase.pb.CoprocessorServiceRe" +
-      "quest\032$.hbase.pb.CoprocessorServiceRespo" +
-      "nse\022d\n\027ExecRegionServerService\022#.hbase.p" +
-      "b.CoprocessorServiceRequest\032$.hbase.pb.C" +
-      "oprocessorServiceResponse\0228\n\005Multi\022\026.hba" +
-      "se.pb.MultiRequest\032\027.hbase.pb.MultiRespo" +
-      "nseBB\n*org.apache.hadoop.hbase.protobuf." +
-      "generatedB\014ClientProtosH\001\210\001\001\240\001\001"
+      "(\005:\0010\"j\n\024MultiRegionLoadStats\022)\n\006region\030" +
+      "\001 \003(\0132\031.hbase.pb.RegionSpecifier\022\'\n\004stat",
+      "\030\002 \003(\0132\031.hbase.pb.RegionLoadStats\"\336\001\n\021Re" +
+      "sultOrException\022\r\n\005index\030\001 \001(\r\022 \n\006result" +
+      "\030\002 \001(\0132\020.hbase.pb.Result\022*\n\texception\030\003 " +
+      "\001(\0132\027.hbase.pb.NameBytesPair\022:\n\016service_" +
+      "result\030\004 \001(\0132\".hbase.pb.CoprocessorServi" +
+      "ceResult\0220\n\tloadStats\030\005 \001(\0132\031.hbase.pb.R" +
+      "egionLoadStatsB\002\030\001\"x\n\022RegionActionResult" +
+      "\0226\n\021resultOrException\030\001 \003(\0132\033.hbase.pb.R" +
+      "esultOrException\022*\n\texception\030\002 \001(\0132\027.hb" +
+      "ase.pb.NameBytesPair\"x\n\014MultiRequest\022,\n\014",
+      "regionAction\030\001 \003(\0132\026.hbase.pb.RegionActi" +
+      "on\022\022\n\nnonceGroup\030\002 \001(\004\022&\n\tcondition\030\003 \001(" +
+      "\0132\023.hbase.pb.Condition\"\226\001\n\rMultiResponse" +
+      "\0228\n\022regionActionResult\030\001 \003(\0132\034.hbase.pb." +
+      "RegionActionResult\022\021\n\tprocessed\030\002 \001(\010\0228\n" +
+      "\020regionStatistics\030\003 \001(\0132\036.hbase.pb.Multi" +
+      "RegionLoadStats*\'\n\013Consistency\022\n\n\006STRONG" +
+      "\020\000\022\014\n\010TIMELINE\020\0012\203\004\n\rClientService\0222\n\003Ge" +
+      "t\022\024.hbase.pb.GetRequest\032\025.hbase.pb.GetRe" +
+      "sponse\022;\n\006Mutate\022\027.hbase.pb.MutateReques",
+      "t\032\030.hbase.pb.MutateResponse\0225\n\004Scan\022\025.hb" +
+      "ase.pb.ScanRequest\032\026.hbase.pb.ScanRespon" +
+      "se\022P\n\rBulkLoadHFile\022\036.hbase.pb.BulkLoadH" +
+      "FileRequest\032\037.hbase.pb.BulkLoadHFileResp" +
+      "onse\022X\n\013ExecService\022#.hbase.pb.Coprocess" +
+      "orServiceRequest\032$.hbase.pb.CoprocessorS" +
+      "erviceResponse\022d\n\027ExecRegionServerServic" +
+      "e\022#.hbase.pb.CoprocessorServiceRequest\032$" +
+      ".hbase.pb.CoprocessorServiceResponse\0228\n\005" +
+      "Multi\022\026.hbase.pb.MultiRequest\032\027.hbase.pb",
+      ".MultiResponseBB\n*org.apache.hadoop.hbas" +
+      "e.protobuf.generatedB\014ClientProtosH\001\210\001\001\240" +
+      "\001\001"
     };
     com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
       new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@@ -34478,30 +35790,36 @@ public final class ClientProtos {
             com.google.protobuf.GeneratedMessage.FieldAccessorTable(
               internal_static_hbase_pb_RegionLoadStats_descriptor,
               new java.lang.String[] { "MemstoreLoad", "HeapOccupancy", "CompactionPressure", });
-          internal_static_hbase_pb_ResultOrException_descriptor =
+          internal_static_hbase_pb_MultiRegionLoadStats_descriptor =
             getDescriptor().getMessageTypes().get(23);
+          internal_static_hbase_pb_MultiRegionLoadStats_fieldAccessorTable = new
+            com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+              internal_static_hbase_pb_MultiRegionLoadStats_descriptor,
+              new java.lang.String[] { "Region", "Stat", });
+          internal_static_hbase_pb_ResultOrException_descriptor =
+            getDescriptor().getMessageTypes().get(24);
           internal_static_hbase_pb_ResultOrException_fieldAccessorTable = new
             com.google.protobuf.GeneratedMessage.FieldAccessorTable(
               internal_static_hbase_pb_ResultOrException_descriptor,
               new java.lang.String[] { "Index", "Result", "Exception", "ServiceResult", "LoadStats", });
           internal_static_hbase_pb_RegionActionResult_descriptor =
-            getDescriptor().getMessageTypes().get(24);
+            getDescriptor().getMessageTypes().get(25);
           internal_static_hbase_pb_RegionActionResult_fieldAccessorTable = new
             com.google.protobuf.GeneratedMessage.FieldAccessorTable(
               internal_static_hbase_pb_RegionActionResult_descriptor,
               new java.lang.String[] { "ResultOrException", "Exception", });
           internal_static_hbase_pb_MultiRequest_descriptor =
-            getDescriptor().getMessageTypes().get(25);
+            getDescriptor().getMessageTypes().get(26);
           internal_static_hbase_pb_MultiRequest_fieldAccessorTable = new
             com.google.protobuf.GeneratedMessage.FieldAccessorTable(
               internal_static_hbase_pb_MultiRequest_descriptor,
               new java.lang.String[] { "RegionAction", "NonceGroup", "Condition", });
           internal_static_hbase_pb_MultiResponse_descriptor =
-            getDescriptor().getMessageTypes().get(26);
+            getDescriptor().getMessageTypes().get(27);
           internal_static_hbase_pb_MultiResponse_fieldAccessorTable = new
             com.google.protobuf.GeneratedMessage.FieldAccessorTable(
               internal_static_hbase_pb_MultiResponse_descriptor,
-              new java.lang.String[] { "RegionActionResult", "Processed", });
+              new java.lang.String[] { "RegionActionResult", "Processed", "RegionStatistics", });
           return null;
         }
       };

http://git-wip-us.apache.org/repos/asf/hbase/blob/ef712df9/hbase-protocol/src/main/protobuf/Client.proto
----------------------------------------------------------------------
diff --git a/hbase-protocol/src/main/protobuf/Client.proto b/hbase-protocol/src/main/protobuf/Client.proto
index ca9abdc..8a4d459 100644
--- a/hbase-protocol/src/main/protobuf/Client.proto
+++ b/hbase-protocol/src/main/protobuf/Client.proto
@@ -402,6 +402,11 @@ message RegionLoadStats {
   optional int32 compactionPressure = 3 [default = 0];
 }
 
+message MultiRegionLoadStats{
+  repeated RegionSpecifier region = 1;
+  repeated RegionLoadStats stat = 2;
+}
+
 /**
  * Either a Result or an Exception NameBytesPair (keyed by
  * exception name whose value is the exception stringified)
@@ -416,7 +421,7 @@ message ResultOrException {
   // result if this was a coprocessor service call
   optional CoprocessorServiceResult service_result = 4;
   // current load on the region
-  optional RegionLoadStats loadStats = 5;
+  optional RegionLoadStats loadStats = 5 [deprecated=true];
 }
 
 /**
@@ -445,6 +450,7 @@ message MultiResponse {
   repeated RegionActionResult regionActionResult = 1;
   // used for mutate to indicate processed only
   optional bool processed = 2;
+  optional MultiRegionLoadStats regionStatistics = 3;
 }
 
 

http://git-wip-us.apache.org/repos/asf/hbase/blob/ef712df9/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java
index 406850e..c090b54 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java
@@ -6768,9 +6768,9 @@ public class HRegion implements HeapSize, PropagatingConfigurationObserver, Regi
   }
 
   /**
-   * @return the current load statistics for the the region
+   * @return statistics about the current load of the region
    */
-  public ClientProtos.RegionLoadStats getRegionStats() {
+  public ClientProtos.RegionLoadStats getLoadStatistics() {
     if (!regionStatsEnabled) {
       return null;
     }

http://git-wip-us.apache.org/repos/asf/hbase/blob/ef712df9/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RSRpcServices.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RSRpcServices.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RSRpcServices.java
index 7bcde52..c77b7e4 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RSRpcServices.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RSRpcServices.java
@@ -139,6 +139,7 @@ import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServic
 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.CoprocessorServiceResponse;
 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.GetRequest;
 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.GetResponse;
+import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRegionLoadStats;
 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRequest;
 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiResponse;
 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutateRequest;
@@ -397,9 +398,9 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
     }
   }
 
-  private static ResultOrException getResultOrException(
-      final ClientProtos.Result r, final int index, final ClientProtos.RegionLoadStats stats) {
-    return getResultOrException(ResponseConverter.buildActionResult(r, stats), index);
+  private static ResultOrException getResultOrException(final ClientProtos.Result r,
+                                                        final int index){
+    return getResultOrException(ResponseConverter.buildActionResult(r), index);
   }
 
   private static ResultOrException getResultOrException(final Exception e, final int index) {
@@ -501,13 +502,16 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
    * @param cellScanner if non-null, the mutation data -- the Cell content.
    * @throws IOException
    */
-  private ClientProtos.RegionLoadStats mutateRows(final Region region,
+  private void mutateRows(final Region region,
       final List<ClientProtos.Action> actions,
-      final CellScanner cellScanner) throws IOException {
+      final CellScanner cellScanner, RegionActionResult.Builder builder) throws IOException {
     if (!region.getRegionInfo().isMetaTable()) {
       regionServer.cacheFlusher.reclaimMemStoreMemory();
     }
     RowMutations rm = null;
+    int i = 0;
+    ClientProtos.ResultOrException.Builder resultOrExceptionOrBuilder =
+        ClientProtos.ResultOrException.newBuilder();
     for (ClientProtos.Action action: actions) {
       if (action.hasGet()) {
         throw new DoNotRetryIOException("Atomic put and/or delete only, not a Get=" +
@@ -527,9 +531,14 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
         default:
           throw new DoNotRetryIOException("Atomic put and/or delete only, not " + type.name());
       }
+      // To unify the response format with doNonAtomicRegionMutation and read through client's
+      // AsyncProcess we have to add an empty result instance per operation
+      resultOrExceptionOrBuilder.clear();
+      resultOrExceptionOrBuilder.setIndex(i++);
+      builder.addResultOrException(
+          resultOrExceptionOrBuilder.build());
     }
     region.mutateRow(rm);
-    return ((HRegion)region).getRegionStats();
   }
 
   /**
@@ -546,11 +555,15 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
    */
   private boolean checkAndRowMutate(final Region region, final List<ClientProtos.Action> actions,
       final CellScanner cellScanner, byte[] row, byte[] family, byte[] qualifier,
-      CompareOp compareOp, ByteArrayComparable comparator) throws IOException {
+      CompareOp compareOp, ByteArrayComparable comparator,
+                                    RegionActionResult.Builder builder) throws IOException {
     if (!region.getRegionInfo().isMetaTable()) {
       regionServer.cacheFlusher.reclaimMemStoreMemory();
     }
     RowMutations rm = null;
+    int i = 0;
+    ClientProtos.ResultOrException.Builder resultOrExceptionOrBuilder =
+        ClientProtos.ResultOrException.newBuilder();
     for (ClientProtos.Action action: actions) {
       if (action.hasGet()) {
         throw new DoNotRetryIOException("Atomic put and/or delete only, not a Get=" +
@@ -570,8 +583,15 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
         default:
           throw new DoNotRetryIOException("Atomic put and/or delete only, not " + type.name());
       }
+      // To unify the response format with doNonAtomicRegionMutation and read through client's
+      // AsyncProcess we have to add an empty result instance per operation
+      resultOrExceptionOrBuilder.clear();
+      resultOrExceptionOrBuilder.setIndex(i++);
+      builder.addResultOrException(
+          resultOrExceptionOrBuilder.build());
     }
-    return region.checkAndRowMutate(row, family, qualifier, compareOp, comparator, rm, Boolean.TRUE);
+    return region.checkAndRowMutate(row, family, qualifier, compareOp,
+        comparator, rm, Boolean.TRUE);
   }
 
   /**
@@ -868,8 +888,7 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
 
           case SUCCESS:
             builder.addResultOrException(getResultOrException(
-                ClientProtos.Result.getDefaultInstance(), index,
-                ((HRegion) region).getRegionStats()));
+              ClientProtos.Result.getDefaultInstance(), index));
             break;
         }
       }
@@ -2246,13 +2265,16 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
     RegionScannersCloseCallBack closeCallBack = null;
     RpcCallContext context = RpcServer.getCurrentCall();
     this.rpcMultiRequestCount.increment();
+    Map<RegionSpecifier, ClientProtos.RegionLoadStats> regionStats = new HashMap<>(request
+      .getRegionActionCount());
     for (RegionAction regionAction : request.getRegionActionList()) {
       this.requestCount.add(regionAction.getActionCount());
       OperationQuota quota;
       Region region;
       regionActionResultBuilder.clear();
+      RegionSpecifier regionSpecifier = regionAction.getRegion();
       try {
-        region = getRegion(regionAction.getRegion());
+        region = getRegion(regionSpecifier);
         quota = getQuotaManager().checkQuota(region, regionAction.getActionList());
       } catch (IOException e) {
         rpcServer.getMetrics().exception(e);
@@ -2280,15 +2302,11 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
             ByteArrayComparable comparator =
                 ProtobufUtil.toComparator(condition.getComparator());
             processed = checkAndRowMutate(region, regionAction.getActionList(),
-                  cellScanner, row, family, qualifier, compareOp, comparator);
+                  cellScanner, row, family, qualifier, compareOp,
+                  comparator, regionActionResultBuilder);
           } else {
-            ClientProtos.RegionLoadStats stats = mutateRows(region, regionAction.getActionList(),
-                cellScanner);
-            // add the stats to the request
-            if(stats != null) {
-              responseBuilder.addRegionActionResult(RegionActionResult.newBuilder()
-                  .addResultOrException(ResultOrException.newBuilder().setLoadStats(stats)));
-            }
+            mutateRows(region, regionAction.getActionList(), cellScanner,
+                regionActionResultBuilder);
             processed = Boolean.TRUE;
           }
         } catch (IOException e) {
@@ -2310,14 +2328,26 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
       }
       responseBuilder.addRegionActionResult(regionActionResultBuilder.build());
       quota.close();
+      ClientProtos.RegionLoadStats regionLoadStats = ((HRegion)region).getLoadStatistics();
+      if(regionLoadStats != null) {
+        regionStats.put(regionSpecifier, regionLoadStats);
+      }
     }
     // Load the controller with the Cells to return.
     if (cellsToReturn != null && !cellsToReturn.isEmpty() && controller != null) {
       controller.setCellScanner(CellUtil.createCellScanner(cellsToReturn));
     }
+
     if (processed != null) {
       responseBuilder.setProcessed(processed);
     }
+
+    MultiRegionLoadStats.Builder builder = MultiRegionLoadStats.newBuilder();
+    for(Entry<RegionSpecifier, ClientProtos.RegionLoadStats> stat: regionStats.entrySet()){
+      builder.addRegion(stat.getKey());
+      builder.addStat(stat.getValue());
+    }
+    responseBuilder.setRegionStatistics(builder);
     return responseBuilder.build();
   }
 

http://git-wip-us.apache.org/repos/asf/hbase/blob/ef712df9/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestCheckAndMutate.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestCheckAndMutate.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestCheckAndMutate.java
index 082de09..1234194 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestCheckAndMutate.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestCheckAndMutate.java
@@ -53,7 +53,7 @@ public class TestCheckAndMutate {
   }
 
   @Test
-  public void testCheckAndMutate() throws Exception {
+  public void testCheckAndMutate() throws Throwable {
     final TableName tableName = TableName.valueOf("TestPutWithDelete");
     final byte[] rowKey = Bytes.toBytes("12345");
     final byte[] family = Bytes.toBytes("cf");
@@ -109,7 +109,12 @@ public class TestCheckAndMutate {
         table.checkAndMutate(rowKey, family, Bytes.toBytes("A"), CompareFilter.CompareOp.EQUAL,
             Bytes.toBytes("a"), rm);
         fail("Expected NoSuchColumnFamilyException");
-      } catch(NoSuchColumnFamilyException e) {
+      } catch (RetriesExhaustedWithDetailsException e) {
+        try {
+          throw e.getCause(0);
+        } catch (NoSuchColumnFamilyException e1) {
+          // expected
+        }
       }
     } finally {
       table.close();


[3/3] hbase git commit: HBASE-14703 HTable.mutateRow does not collect stats (Heng Chen)

Posted by jy...@apache.org.
HBASE-14703 HTable.mutateRow does not collect stats (Heng Chen)


Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/ef712df9
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/ef712df9
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/ef712df9

Branch: refs/heads/master
Commit: ef712df944b0745892bc13bcecdfd6e358a71b66
Parents: d083e4f
Author: Jesse Yates <jy...@apache.org>
Authored: Fri Mar 4 19:07:59 2016 -0800
Committer: Jesse Yates <jy...@apache.org>
Committed: Sat Mar 5 11:01:45 2016 -0800

----------------------------------------------------------------------
 .../hadoop/hbase/client/AsyncProcess.java       |  114 +-
 .../org/apache/hadoop/hbase/client/HTable.java  |  151 +-
 .../hadoop/hbase/client/MetricsConnection.java  |   10 +-
 .../hadoop/hbase/client/MultiResponse.java      |   57 +-
 .../hbase/client/MultiServerCallable.java       |   17 +-
 .../client/PayloadCarryingServerCallable.java   |   48 +
 .../hadoop/hbase/client/ResultStatsUtil.java    |   12 +-
 .../hbase/client/RetryingTimeTracker.java       |   57 +
 .../hbase/client/RpcRetryingCallerFactory.java  |    6 -
 .../hbase/client/RpcRetryingCallerImpl.java     |   34 +-
 .../hbase/client/ServerStatisticTracker.java    |    3 +-
 .../hadoop/hbase/client/StatisticTrackable.java |   33 +
 .../client/StatsTrackingRpcRetryingCaller.java  |   77 -
 .../hadoop/hbase/protobuf/ProtobufUtil.java     |    4 +-
 .../hbase/protobuf/ResponseConverter.java       |   28 +-
 .../hadoop/hbase/client/TestAsyncProcess.java   |   18 +-
 .../hbase/protobuf/generated/ClientProtos.java  | 1452 +++++++++++++++++-
 hbase-protocol/src/main/protobuf/Client.proto   |    8 +-
 .../hadoop/hbase/regionserver/HRegion.java      |    4 +-
 .../hbase/regionserver/RSRpcServices.java       |   68 +-
 .../hadoop/hbase/client/TestCheckAndMutate.java |    9 +-
 .../hadoop/hbase/client/TestClientPushback.java |   29 +
 .../hadoop/hbase/client/TestFromClientSide.java |    8 +-
 .../hadoop/hbase/client/TestReplicasClient.java |    5 +-
 24 files changed, 1891 insertions(+), 361 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hbase/blob/ef712df9/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncProcess.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncProcess.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncProcess.java
index 65c15ce..7b0016c 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncProcess.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncProcess.java
@@ -55,6 +55,7 @@ import org.apache.hadoop.hbase.client.backoff.ServerStatistics;
 import org.apache.hadoop.hbase.client.coprocessor.Batch;
 import org.apache.hadoop.hbase.exceptions.ClientExceptionsUtil;
 import org.apache.hadoop.hbase.ipc.RpcControllerFactory;
+import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
 import org.apache.htrace.Trace;
@@ -428,7 +429,7 @@ class AsyncProcess {
     if (retainedActions.isEmpty()) return NO_REQS_RESULT;
 
     return submitMultiActions(tableName, retainedActions, nonceGroup, callback, null, needResults,
-      locationErrors, locationErrorRows, actionsByServer, pool);
+        locationErrors, locationErrorRows, actionsByServer, pool);
   }
 
   <CResult> AsyncRequestFuture submitMultiActions(TableName tableName,
@@ -444,7 +445,7 @@ class AsyncProcess {
         int originalIndex = locationErrorRows.get(i);
         Row row = retainedActions.get(originalIndex).getAction();
         ars.manageError(originalIndex, row,
-          Retry.NO_LOCATION_PROBLEM, locationErrors.get(i), null);
+            Retry.NO_LOCATION_PROBLEM, locationErrors.get(i), null);
       }
     }
     ars.sendMultiAction(actionsByServer, 1, null, false);
@@ -546,9 +547,13 @@ class AsyncProcess {
    */
   public <CResult> AsyncRequestFuture submitAll(TableName tableName,
       List<? extends Row> rows, Batch.Callback<CResult> callback, Object[] results) {
-    return submitAll(null, tableName, rows, callback, results);
+    return submitAll(null, tableName, rows, callback, results, null, timeout);
   }
 
+  public <CResult> AsyncRequestFuture submitAll(ExecutorService pool, TableName tableName,
+      List<? extends Row> rows, Batch.Callback<CResult> callback, Object[] results) {
+    return submitAll(pool, tableName, rows, callback, results, null, timeout);
+  }
   /**
    * Submit immediately the list of rows, whatever the server status. Kept for backward
    * compatibility: it allows to be used with the batch interface that return an array of objects.
@@ -560,7 +565,8 @@ class AsyncProcess {
    * @param results Optional array to return the results thru; backward compat.
    */
   public <CResult> AsyncRequestFuture submitAll(ExecutorService pool, TableName tableName,
-      List<? extends Row> rows, Batch.Callback<CResult> callback, Object[] results) {
+      List<? extends Row> rows, Batch.Callback<CResult> callback, Object[] results,
+      PayloadCarryingServerCallable callable, int curTimeout) {
     List<Action<Row>> actions = new ArrayList<Action<Row>>(rows.size());
 
     // The position will be used by the processBatch to match the object array returned.
@@ -579,7 +585,8 @@ class AsyncProcess {
       actions.add(action);
     }
     AsyncRequestFutureImpl<CResult> ars = createAsyncRequestFuture(
-        tableName, actions, ng.getNonceGroup(), getPool(pool), callback, results, results != null);
+        tableName, actions, ng.getNonceGroup(), getPool(pool), callback, results, results != null,
+        callable, curTimeout);
     ars.groupAndSendMultiAction(actions, 1);
     return ars;
   }
@@ -711,11 +718,11 @@ class AsyncProcess {
       private final MultiAction<Row> multiAction;
       private final int numAttempt;
       private final ServerName server;
-      private final Set<MultiServerCallable<Row>> callsInProgress;
+      private final Set<PayloadCarryingServerCallable> callsInProgress;
 
       private SingleServerRequestRunnable(
           MultiAction<Row> multiAction, int numAttempt, ServerName server,
-          Set<MultiServerCallable<Row>> callsInProgress) {
+          Set<PayloadCarryingServerCallable> callsInProgress) {
         this.multiAction = multiAction;
         this.numAttempt = numAttempt;
         this.server = server;
@@ -725,19 +732,22 @@ class AsyncProcess {
       @Override
       public void run() {
         MultiResponse res;
-        MultiServerCallable<Row> callable = null;
+        PayloadCarryingServerCallable callable = currentCallable;
         try {
-          callable = createCallable(server, tableName, multiAction);
+          // setup the callable based on the actions, if we don't have one already from the request
+          if (callable == null) {
+            callable = createCallable(server, tableName, multiAction);
+          }
+          RpcRetryingCaller<MultiResponse> caller = createCaller(callable);
           try {
-            RpcRetryingCaller<MultiResponse> caller = createCaller(callable);
-            if (callsInProgress != null) callsInProgress.add(callable);
-            res = caller.callWithoutRetries(callable, timeout);
-
+            if (callsInProgress != null) {
+              callsInProgress.add(callable);
+            }
+            res = caller.callWithoutRetries(callable, currentCallTotalTimeout);
             if (res == null) {
               // Cancelled
               return;
             }
-
           } catch (IOException e) {
             // The service itself failed . It may be an error coming from the communication
             //   layer, but, as well, a functional error raised by the server.
@@ -771,7 +781,7 @@ class AsyncProcess {
     private final BatchErrors errors;
     private final ConnectionImplementation.ServerErrorTracker errorsByServer;
     private final ExecutorService pool;
-    private final Set<MultiServerCallable<Row>> callsInProgress;
+    private final Set<PayloadCarryingServerCallable> callsInProgress;
 
 
     private final TableName tableName;
@@ -798,10 +808,12 @@ class AsyncProcess {
     private final int[] replicaGetIndices;
     private final boolean hasAnyReplicaGets;
     private final long nonceGroup;
+    private PayloadCarryingServerCallable currentCallable;
+    private int currentCallTotalTimeout;
 
     public AsyncRequestFutureImpl(TableName tableName, List<Action<Row>> actions, long nonceGroup,
         ExecutorService pool, boolean needResults, Object[] results,
-        Batch.Callback<CResult> callback) {
+        Batch.Callback<CResult> callback, PayloadCarryingServerCallable callable, int timeout) {
       this.pool = pool;
       this.callback = callback;
       this.nonceGroup = nonceGroup;
@@ -865,13 +877,16 @@ class AsyncProcess {
         this.replicaGetIndices = null;
       }
       this.callsInProgress = !hasAnyReplicaGets ? null :
-          Collections.newSetFromMap(new ConcurrentHashMap<MultiServerCallable<Row>, Boolean>());
+          Collections.newSetFromMap(
+              new ConcurrentHashMap<PayloadCarryingServerCallable, Boolean>());
 
       this.errorsByServer = createServerErrorTracker();
       this.errors = (globalErrors != null) ? globalErrors : new BatchErrors();
+      this.currentCallable = callable;
+      this.currentCallTotalTimeout = timeout;
     }
 
-    public Set<MultiServerCallable<Row>> getCallsInProgress() {
+    public Set<PayloadCarryingServerCallable> getCallsInProgress() {
       return callsInProgress;
     }
 
@@ -1275,11 +1290,15 @@ class AsyncProcess {
       int failureCount = 0;
       boolean canRetry = true;
 
-      // Go by original action.
+      Map<byte[], MultiResponse.RegionResult> results = responses.getResults();
+      updateStats(server, results);
+
       int failed = 0, stopped = 0;
+      // Go by original action.
       for (Map.Entry<byte[], List<Action<Row>>> regionEntry : multiAction.actions.entrySet()) {
         byte[] regionName = regionEntry.getKey();
-        Map<Integer, Object> regionResults = responses.getResults().get(regionName);
+        Map<Integer, Object> regionResults = results.get(regionName) == null
+            ?  null : results.get(regionName).result;
         if (regionResults == null) {
           if (!responses.getExceptions().containsKey(regionName)) {
             LOG.error("Server sent us neither results nor exceptions for "
@@ -1308,7 +1327,7 @@ class AsyncProcess {
             }
             ++failureCount;
             Retry retry = manageError(sentAction.getOriginalIndex(), row,
-                canRetry ? Retry.YES : Retry.NO_RETRIES_EXHAUSTED, (Throwable)result, server);
+                canRetry ? Retry.YES : Retry.NO_RETRIES_EXHAUSTED, (Throwable) result, server);
             if (retry == Retry.YES) {
               toReplay.add(sentAction);
             } else if (retry == Retry.NO_OTHER_SUCCEEDED) {
@@ -1317,24 +1336,11 @@ class AsyncProcess {
               ++failed;
             }
           } else {
-
-            if (AsyncProcess.this.connection.getConnectionMetrics() != null) {
-              AsyncProcess.this.connection.getConnectionMetrics().
-                      updateServerStats(server, regionName, result);
-            }
-
-            // update the stats about the region, if its a user table. We don't want to slow down
-            // updates to meta tables, especially from internal updates (master, etc).
-            if (AsyncProcess.this.connection.getStatisticsTracker() != null) {
-              result = ResultStatsUtil.updateStats(result,
-                  AsyncProcess.this.connection.getStatisticsTracker(), server, regionName);
-            }
-
             if (callback != null) {
               try {
                 //noinspection unchecked
                 // TODO: would callback expect a replica region name if it gets one?
-                this.callback.update(regionName, sentAction.getAction().getRow(), (CResult)result);
+                this.callback.update(regionName, sentAction.getAction().getRow(), (CResult) result);
               } catch (Throwable t) {
                 LOG.error("User callback threw an exception for "
                     + Bytes.toStringBinary(regionName) + ", ignoring", t);
@@ -1384,7 +1390,6 @@ class AsyncProcess {
           }
         }
       }
-
       if (toReplay.isEmpty()) {
         logNoResubmit(server, numAttempt, failureCount, throwable, failed, stopped);
       } else {
@@ -1438,8 +1443,8 @@ class AsyncProcess {
       boolean isStale = !RegionReplicaUtil.isDefaultReplica(action.getReplicaId());
       int index = action.getOriginalIndex();
       if (results == null) {
-         decActionCounter(index);
-         return; // Simple case, no replica requests.
+        decActionCounter(index);
+        return; // Simple case, no replica requests.
       }
       state = trySetResultSimple(index, action.getAction(), false, result, null, isStale);
       if (state == null) {
@@ -1618,7 +1623,7 @@ class AsyncProcess {
         throw new InterruptedIOException(iex.getMessage());
       } finally {
         if (callsInProgress != null) {
-          for (MultiServerCallable<Row> clb : callsInProgress) {
+          for (PayloadCarryingServerCallable clb : callsInProgress) {
             clb.cancel();
           }
         }
@@ -1675,13 +1680,38 @@ class AsyncProcess {
     }
   }
 
+  private void updateStats(ServerName server, Map<byte[], MultiResponse.RegionResult> results) {
+    boolean metrics = AsyncProcess.this.connection.getConnectionMetrics() != null;
+    boolean stats = AsyncProcess.this.connection.getStatisticsTracker() != null;
+    if (!stats && !metrics) {
+      return;
+    }
+    for (Map.Entry<byte[], MultiResponse.RegionResult> regionStats : results.entrySet()) {
+      byte[] regionName = regionStats.getKey();
+      ClientProtos.RegionLoadStats stat = regionStats.getValue().getStat();
+      ResultStatsUtil.updateStats(AsyncProcess.this.connection.getStatisticsTracker(), server,
+          regionName, stat);
+      ResultStatsUtil.updateStats(AsyncProcess.this.connection.getConnectionMetrics(),
+          server, regionName, stat);
+    }
+  }
+
+  protected <CResult> AsyncRequestFutureImpl<CResult> createAsyncRequestFuture(
+      TableName tableName, List<Action<Row>> actions, long nonceGroup, ExecutorService pool,
+      Batch.Callback<CResult> callback, Object[] results, boolean needResults,
+      PayloadCarryingServerCallable callable, int curTimeout) {
+    return new AsyncRequestFutureImpl<CResult>(
+        tableName, actions, nonceGroup, getPool(pool), needResults,
+        results, callback, callable, curTimeout);
+  }
+
   @VisibleForTesting
   /** Create AsyncRequestFuture. Isolated to be easily overridden in the tests. */
   protected <CResult> AsyncRequestFutureImpl<CResult> createAsyncRequestFuture(
       TableName tableName, List<Action<Row>> actions, long nonceGroup, ExecutorService pool,
       Batch.Callback<CResult> callback, Object[] results, boolean needResults) {
-    return new AsyncRequestFutureImpl<CResult>(
-        tableName, actions, nonceGroup, getPool(pool), needResults, results, callback);
+    return createAsyncRequestFuture(
+        tableName, actions, nonceGroup, pool, callback, results, needResults, null, timeout);
   }
 
   /**
@@ -1697,7 +1727,7 @@ class AsyncProcess {
    * Create a caller. Isolated to be easily overridden in the tests.
    */
   @VisibleForTesting
-  protected RpcRetryingCaller<MultiResponse> createCaller(MultiServerCallable<Row> callable) {
+  protected RpcRetryingCaller<MultiResponse> createCaller(PayloadCarryingServerCallable callable) {
     return rpcCallerFactory.<MultiResponse> newCaller();
   }
 

http://git-wip-us.apache.org/repos/asf/hbase/blob/ef712df9/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HTable.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HTable.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HTable.java
index ce5a44c..33fd94e 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HTable.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HTable.java
@@ -37,6 +37,7 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.Cell;
+import org.apache.hadoop.hbase.DoNotRetryIOException;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.HRegionLocation;
 import org.apache.hadoop.hbase.HTableDescriptor;
@@ -55,6 +56,7 @@ import org.apache.hadoop.hbase.ipc.RegionCoprocessorRpcChannel;
 import org.apache.hadoop.hbase.ipc.RpcControllerFactory;
 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
 import org.apache.hadoop.hbase.protobuf.RequestConverter;
+import org.apache.hadoop.hbase.protobuf.ResponseConverter;
 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MultiRequest;
 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutateRequest;
@@ -263,7 +265,8 @@ public class HTable implements HTableInterface {
    */
   @Override
   public HTableDescriptor getTableDescriptor() throws IOException {
-    HTableDescriptor htd = HBaseAdmin.getTableDescriptor(tableName, connection, rpcCallerFactory, operationTimeout);
+    HTableDescriptor htd = HBaseAdmin.getTableDescriptor(tableName, connection,
+        rpcCallerFactory, operationTimeout);
     if (htd != null) {
       return new UnmodifyableHTableDescriptor(htd);
     }
@@ -450,10 +453,10 @@ public class HTable implements HTableInterface {
 
     // Call that takes into account the replica
     RpcRetryingCallerWithReadReplicas callable = new RpcRetryingCallerWithReadReplicas(
-      rpcControllerFactory, tableName, this.connection, get, pool,
-      tableConfiguration.getRetriesNumber(),
-      operationTimeout,
-      tableConfiguration.getPrimaryCallTimeoutMicroSecond());
+        rpcControllerFactory, tableName, this.connection, get, pool,
+        tableConfiguration.getRetriesNumber(),
+        operationTimeout,
+        tableConfiguration.getPrimaryCallTimeoutMicroSecond());
     return callable.call();
   }
 
@@ -587,35 +590,47 @@ public class HTable implements HTableInterface {
    */
   @Override
   public void mutateRow(final RowMutations rm) throws IOException {
-    RegionServerCallable<Void> callable =
-        new RegionServerCallable<Void>(connection, getName(), rm.getRow()) {
-      @Override
-      public Void call(int callTimeout) throws IOException {
-        PayloadCarryingRpcController controller = rpcControllerFactory.newController();
-        controller.setPriority(tableName);
-        controller.setCallTimeout(callTimeout);
-        try {
-          RegionAction.Builder regionMutationBuilder = RequestConverter.buildRegionAction(
-            getLocation().getRegionInfo().getRegionName(), rm);
-          regionMutationBuilder.setAtomic(true);
-          MultiRequest request =
-            MultiRequest.newBuilder().addRegionAction(regionMutationBuilder.build()).build();
-          ClientProtos.MultiResponse response = getStub().multi(controller, request);
-          ClientProtos.RegionActionResult res = response.getRegionActionResultList().get(0);
-          if (res.hasException()) {
-            Throwable ex = ProtobufUtil.toException(res.getException());
-            if(ex instanceof IOException) {
-              throw (IOException)ex;
+    final RetryingTimeTracker tracker = new RetryingTimeTracker();
+    PayloadCarryingServerCallable<MultiResponse> callable =
+      new PayloadCarryingServerCallable<MultiResponse>(connection, getName(), rm.getRow(),
+          rpcControllerFactory) {
+        @Override
+        public MultiResponse call(int callTimeout) throws IOException {
+          tracker.start();
+          controller.setPriority(tableName);
+          int remainingTime = tracker.getRemainingTime(callTimeout);
+          if (remainingTime == 0) {
+            throw new DoNotRetryIOException("Timeout for mutate row");
+          }
+          controller.setCallTimeout(remainingTime);
+          try {
+            RegionAction.Builder regionMutationBuilder = RequestConverter.buildRegionAction(
+                getLocation().getRegionInfo().getRegionName(), rm);
+            regionMutationBuilder.setAtomic(true);
+            MultiRequest request =
+                MultiRequest.newBuilder().addRegionAction(regionMutationBuilder.build()).build();
+            ClientProtos.MultiResponse response = getStub().multi(controller, request);
+            ClientProtos.RegionActionResult res = response.getRegionActionResultList().get(0);
+            if (res.hasException()) {
+              Throwable ex = ProtobufUtil.toException(res.getException());
+              if (ex instanceof IOException) {
+                throw (IOException) ex;
+              }
+              throw new IOException("Failed to mutate row: " +
+                  Bytes.toStringBinary(rm.getRow()), ex);
             }
-            throw new IOException("Failed to mutate row: "+Bytes.toStringBinary(rm.getRow()), ex);
+            return ResponseConverter.getResults(request, response, controller.cellScanner());
+          } catch (ServiceException se) {
+            throw ProtobufUtil.getRemoteException(se);
           }
-        } catch (ServiceException se) {
-          throw ProtobufUtil.getRemoteException(se);
         }
-        return null;
-      }
-    };
-    rpcCallerFactory.<Void> newCaller().callWithRetries(callable, this.operationTimeout);
+      };
+    AsyncRequestFuture ars = multiAp.submitAll(pool, tableName, rm.getMutations(),
+        null, null, callable, operationTimeout);
+    ars.waitUntilDone();
+    if (ars.hasError()) {
+      throw ars.getErrors();
+    }
   }
 
   /**
@@ -860,37 +875,55 @@ public class HTable implements HTableInterface {
    */
   @Override
   public boolean checkAndMutate(final byte [] row, final byte [] family, final byte [] qualifier,
-      final CompareOp compareOp, final byte [] value, final RowMutations rm)
-  throws IOException {
-    RegionServerCallable<Boolean> callable =
-        new RegionServerCallable<Boolean>(connection, getName(), row) {
-          @Override
-          public Boolean call(int callTimeout) throws IOException {
-            PayloadCarryingRpcController controller = rpcControllerFactory.newController();
-            controller.setPriority(tableName);
-            controller.setCallTimeout(callTimeout);
-            try {
-              CompareType compareType = CompareType.valueOf(compareOp.name());
-              MultiRequest request = RequestConverter.buildMutateRequest(
-                  getLocation().getRegionInfo().getRegionName(), row, family, qualifier,
-                  new BinaryComparator(value), compareType, rm);
-              ClientProtos.MultiResponse response = getStub().multi(controller, request);
-              ClientProtos.RegionActionResult res = response.getRegionActionResultList().get(0);
-              if (res.hasException()) {
-                Throwable ex = ProtobufUtil.toException(res.getException());
-                if(ex instanceof IOException) {
-                  throw (IOException)ex;
-                }
-                throw new IOException("Failed to checkAndMutate row: "+
-                    Bytes.toStringBinary(rm.getRow()), ex);
+    final CompareOp compareOp, final byte [] value, final RowMutations rm)
+    throws IOException {
+    final RetryingTimeTracker tracker = new RetryingTimeTracker();
+    PayloadCarryingServerCallable<MultiResponse> callable =
+      new PayloadCarryingServerCallable<MultiResponse>(connection, getName(), rm.getRow(),
+        rpcControllerFactory) {
+        @Override
+        public MultiResponse call(int callTimeout) throws IOException {
+          tracker.start();
+          controller.setPriority(tableName);
+          int remainingTime = tracker.getRemainingTime(callTimeout);
+          if (remainingTime == 0) {
+            throw new DoNotRetryIOException("Timeout for mutate row");
+          }
+          controller.setCallTimeout(remainingTime);
+          try {
+            CompareType compareType = CompareType.valueOf(compareOp.name());
+            MultiRequest request = RequestConverter.buildMutateRequest(
+              getLocation().getRegionInfo().getRegionName(), row, family, qualifier,
+              new BinaryComparator(value), compareType, rm);
+            ClientProtos.MultiResponse response = getStub().multi(controller, request);
+            ClientProtos.RegionActionResult res = response.getRegionActionResultList().get(0);
+            if (res.hasException()) {
+              Throwable ex = ProtobufUtil.toException(res.getException());
+              if(ex instanceof IOException) {
+                throw (IOException)ex;
               }
-              return Boolean.valueOf(response.getProcessed());
-            } catch (ServiceException se) {
-              throw ProtobufUtil.getRemoteException(se);
+              throw new IOException("Failed to checkAndMutate row: "+
+                                    Bytes.toStringBinary(rm.getRow()), ex);
             }
+            return ResponseConverter.getResults(request, response, controller.cellScanner());
+          } catch (ServiceException se) {
+            throw ProtobufUtil.getRemoteException(se);
           }
-        };
-    return rpcCallerFactory.<Boolean> newCaller().callWithRetries(callable, this.operationTimeout);
+        }
+      };
+    /**
+     *  Currently, we use one array to store 'processed' flag which is returned by server.
+     *  It is excessive to send such a large array, but that is required by the framework right now
+     * */
+    Object[] results = new Object[rm.getMutations().size()];
+    AsyncRequestFuture ars = multiAp.submitAll(pool, tableName, rm.getMutations(),
+      null, results, callable, operationTimeout);
+    ars.waitUntilDone();
+    if (ars.hasError()) {
+      throw ars.getErrors();
+    }
+
+    return ((Result)results[0]).getExists();
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/hbase/blob/ef712df9/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MetricsConnection.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MetricsConnection.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MetricsConnection.java
index 6a292bc..400f505 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MetricsConnection.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MetricsConnection.java
@@ -52,7 +52,7 @@ import static com.codahale.metrics.MetricRegistry.name;
  * {@link #shutdown()} to terminate the thread pools they allocate.
  */
 @InterfaceAudience.Private
-public class MetricsConnection {
+public class MetricsConnection implements StatisticTrackable {
 
   /** Set this key to {@code true} to enable metrics collection of client requests. */
   public static final String CLIENT_SIDE_METRICS_ENABLED_KEY = "hbase.client.metrics.enable";
@@ -199,9 +199,15 @@ public class MetricsConnection {
     }
     Result result = (Result) r;
     ClientProtos.RegionLoadStats stats = result.getStats();
-    if(stats == null){
+    if (stats == null) {
       return;
     }
+    updateRegionStats(serverName, regionName, stats);
+  }
+
+  @Override
+  public void updateRegionStats(ServerName serverName, byte[] regionName,
+    ClientProtos.RegionLoadStats stats) {
     String name = serverName.getServerName() + "," + Bytes.toStringBinary(regionName);
     ConcurrentMap<byte[], RegionStats> rsStats = null;
     if (serverStats.containsKey(serverName)) {

http://git-wip-us.apache.org/repos/asf/hbase/blob/ef712df9/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MultiResponse.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MultiResponse.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MultiResponse.java
index 089ccff..79a9ed3 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MultiResponse.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MultiResponse.java
@@ -24,6 +24,7 @@ import java.util.Map;
 import java.util.TreeMap;
 
 import org.apache.hadoop.hbase.classification.InterfaceAudience;
+import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
 import org.apache.hadoop.hbase.util.Bytes;
 
 /**
@@ -33,8 +34,7 @@ import org.apache.hadoop.hbase.util.Bytes;
 public class MultiResponse {
 
   // map of regionName to map of Results by the original index for that Result
-  private Map<byte[], Map<Integer, Object>> results =
-      new TreeMap<byte[], Map<Integer, Object>>(Bytes.BYTES_COMPARATOR);
+  private Map<byte[], RegionResult> results = new TreeMap<>(Bytes.BYTES_COMPARATOR);
 
   /**
    * The server can send us a failure for the region itself, instead of individual failure.
@@ -52,8 +52,8 @@ public class MultiResponse {
    */
   public int size() {
     int size = 0;
-    for (Map<?,?> c : results.values()) {
-      size += c.size();
+    for (RegionResult result: results.values()) {
+      size += result.size();
     }
     return size;
   }
@@ -66,16 +66,7 @@ public class MultiResponse {
    * @param resOrEx the result or error; will be empty for successful Put and Delete actions.
    */
   public void add(byte[] regionName, int originalIndex, Object resOrEx) {
-    Map<Integer, Object> rs = results.get(regionName);
-    if (rs == null) {
-      rs = new HashMap<Integer, Object>();
-      results.put(regionName, rs);
-    }
-    rs.put(originalIndex, resOrEx);
-  }
-
-  public Map<byte[], Map<Integer, Object>> getResults() {
-    return results;
+    getResult(regionName).addResult(originalIndex, resOrEx);
   }
 
   public void addException(byte []regionName, Throwable ie){
@@ -92,4 +83,42 @@ public class MultiResponse {
   public Map<byte[], Throwable> getExceptions() {
     return exceptions;
   }
+
+  public void addStatistic(byte[] regionName, ClientProtos.RegionLoadStats stat) {
+    getResult(regionName).setStat(stat);
+  }
+
+  private RegionResult getResult(byte[] region){
+    RegionResult rs = results.get(region);
+    if (rs == null) {
+      rs = new RegionResult();
+      results.put(region, rs);
+    }
+    return rs;
+  }
+
+  public Map<byte[], RegionResult> getResults(){
+    return this.results;
+  }
+
+  static class RegionResult{
+    Map<Integer, Object> result = new HashMap<>();
+    ClientProtos.RegionLoadStats stat;
+
+    public void addResult(int index, Object result){
+      this.result.put(index, result);
+    }
+
+    public void setStat(ClientProtos.RegionLoadStats stat){
+      this.stat = stat;
+    }
+
+    public int size() {
+      return this.result.size();
+    }
+
+    public ClientProtos.RegionLoadStats getStat() {
+      return this.stat;
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/hbase/blob/ef712df9/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MultiServerCallable.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MultiServerCallable.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MultiServerCallable.java
index 85b401e..f78f348 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MultiServerCallable.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/MultiServerCallable.java
@@ -30,7 +30,6 @@ import org.apache.hadoop.hbase.HRegionInfo;
 import org.apache.hadoop.hbase.HRegionLocation;
 import org.apache.hadoop.hbase.ServerName;
 import org.apache.hadoop.hbase.TableName;
-import org.apache.hadoop.hbase.ipc.PayloadCarryingRpcController;
 import org.apache.hadoop.hbase.ipc.RpcControllerFactory;
 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
 import org.apache.hadoop.hbase.protobuf.RequestConverter;
@@ -50,21 +49,19 @@ import com.google.protobuf.ServiceException;
  * {@link RegionServerCallable} that goes against multiple regions.
  * @param <R>
  */
-class MultiServerCallable<R> extends RegionServerCallable<MultiResponse> implements Cancellable {
+class MultiServerCallable<R> extends PayloadCarryingServerCallable<MultiResponse> {
   private final MultiAction<R> multiAction;
   private final boolean cellBlock;
-  private final PayloadCarryingRpcController controller;
 
   MultiServerCallable(final ClusterConnection connection, final TableName tableName,
       final ServerName location, RpcControllerFactory rpcFactory, final MultiAction<R> multi) {
-    super(connection, tableName, null);
+    super(connection, tableName, null, rpcFactory);
     this.multiAction = multi;
     // RegionServerCallable has HRegionLocation field, but this is a multi-region request.
     // Using region info from parent HRegionLocation would be a mistake for this class; so
     // we will store the server here, and throw if someone tries to obtain location/regioninfo.
     this.location = new HRegionLocation(null, location);
     this.cellBlock = isCellBlock();
-    controller = rpcFactory.newController();
   }
 
   @Override
@@ -133,16 +130,6 @@ class MultiServerCallable<R> extends RegionServerCallable<MultiResponse> impleme
     return ResponseConverter.getResults(requestProto, responseProto, controller.cellScanner());
   }
 
-  @Override
-  public void cancel() {
-    controller.startCancel();
-  }
-
-  @Override
-  public boolean isCancelled() {
-    return controller.isCanceled();
-  }
-
   /**
    * @return True if we should send data in cellblocks.  This is an expensive call.  Cache the
    * result if you can rather than call each time.

http://git-wip-us.apache.org/repos/asf/hbase/blob/ef712df9/hbase-client/src/main/java/org/apache/hadoop/hbase/client/PayloadCarryingServerCallable.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/PayloadCarryingServerCallable.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/PayloadCarryingServerCallable.java
new file mode 100644
index 0000000..d94f069
--- /dev/null
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/PayloadCarryingServerCallable.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * 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,
+ * 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.
+ */
+package org.apache.hadoop.hbase.client;
+
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.classification.InterfaceAudience;
+import org.apache.hadoop.hbase.ipc.PayloadCarryingRpcController;
+import org.apache.hadoop.hbase.ipc.RpcControllerFactory;
+
+/**
+ * This class is used to unify HTable calls with AsyncProcess Framework.
+ * HTable can use AsyncProcess directly though this class.
+ */
+@InterfaceAudience.Private
+public abstract class PayloadCarryingServerCallable<T>
+    extends RegionServerCallable<T> implements Cancellable {
+  protected PayloadCarryingRpcController controller;
+
+  public PayloadCarryingServerCallable(Connection connection, TableName tableName, byte[] row,
+    RpcControllerFactory rpcControllerFactory) {
+    super(connection, tableName, row);
+    this.controller = rpcControllerFactory.newController();
+  }
+
+  @Override
+  public void cancel() {
+    controller.startCancel();
+  }
+
+  @Override
+  public boolean isCancelled() {
+    return controller.isCanceled();
+  }
+}

http://git-wip-us.apache.org/repos/asf/hbase/blob/ef712df9/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ResultStatsUtil.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ResultStatsUtil.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ResultStatsUtil.java
index 3caa63e..6537d79 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ResultStatsUtil.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ResultStatsUtil.java
@@ -55,13 +55,17 @@ public final class ResultStatsUtil {
       return r;
     }
 
-    if (regionName != null) {
-      serverStats.updateRegionStats(server, regionName, stats);
-    }
-
+    updateStats(serverStats, server, regionName, stats);
     return r;
   }
 
+  public static void updateStats(StatisticTrackable tracker, ServerName server, byte[] regionName,
+    ClientProtos.RegionLoadStats stats) {
+    if (regionName != null && stats != null && tracker != null) {
+      tracker.updateRegionStats(server, regionName, stats);
+    }
+  }
+
   public static <T> T updateStats(T r, ServerStatisticTracker stats,
       HRegionLocation regionLocation) {
     byte[] regionName = null;

http://git-wip-us.apache.org/repos/asf/hbase/blob/ef712df9/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RetryingTimeTracker.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RetryingTimeTracker.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RetryingTimeTracker.java
new file mode 100644
index 0000000..24288e6
--- /dev/null
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RetryingTimeTracker.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * 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,
+ * 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.
+ */
+package org.apache.hadoop.hbase.client;
+
+import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
+
+/**
+ * Tracks the amount of time remaining for an operation.
+ */
+class RetryingTimeTracker {
+
+  private long globalStartTime = -1;
+
+  public void start() {
+    if (this.globalStartTime < 0) {
+      this.globalStartTime = EnvironmentEdgeManager.currentTime();
+    }
+  }
+
+  public int getRemainingTime(int callTimeout) {
+    if (callTimeout <= 0) {
+      return 0;
+    } else {
+      if (callTimeout == Integer.MAX_VALUE) {
+        return Integer.MAX_VALUE;
+      }
+      int remainingTime = (int) (
+        callTimeout -
+        (EnvironmentEdgeManager.currentTime() - this.globalStartTime));
+      if (remainingTime < 1) {
+        // If there is no time left, we're trying anyway. It's too late.
+        // 0 means no timeout, and it's not the intent here. So we secure both cases by
+        // resetting to the minimum.
+        remainingTime = 1;
+      }
+      return remainingTime;
+    }
+  }
+
+  public long getStartTime() {
+    return this.globalStartTime;
+  }
+}

http://git-wip-us.apache.org/repos/asf/hbase/blob/ef712df9/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RpcRetryingCallerFactory.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RpcRetryingCallerFactory.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RpcRetryingCallerFactory.java
index 0af8210..550812f 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RpcRetryingCallerFactory.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RpcRetryingCallerFactory.java
@@ -67,12 +67,6 @@ public class RpcRetryingCallerFactory {
     //  is cheap as it does not require parsing a complex structure.
     RpcRetryingCaller<T> caller = new RpcRetryingCallerImpl<T>(pause, retries, interceptor,
         startLogErrorsCnt);
-
-    // wrap it with stats, if we are tracking them
-    if (enableBackPressure && this.stats != null) {
-      caller = new StatsTrackingRpcRetryingCaller<T>(caller, this.stats);
-    }
-
     return caller;
   }
 

http://git-wip-us.apache.org/repos/asf/hbase/blob/ef712df9/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RpcRetryingCallerImpl.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RpcRetryingCallerImpl.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RpcRetryingCallerImpl.java
index 12abc6a..6ce4956 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RpcRetryingCallerImpl.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RpcRetryingCallerImpl.java
@@ -51,10 +51,6 @@ import com.google.protobuf.ServiceException;
 public class RpcRetryingCallerImpl<T> implements RpcRetryingCaller<T> {
   // LOG is being used in TestMultiRowRangeFilter, hence leaving it public
   public static final Log LOG = LogFactory.getLog(RpcRetryingCallerImpl.class);
-  /**
-   * When we started making calls.
-   */
-  private long globalStartTime;
 
   /** How many retries are allowed before we start to log */
   private final int startLogErrorsCnt;
@@ -64,6 +60,7 @@ public class RpcRetryingCallerImpl<T> implements RpcRetryingCaller<T> {
   private final AtomicBoolean cancelled = new AtomicBoolean(false);
   private final RetryingCallerInterceptor interceptor;
   private final RetryingCallerInterceptorContext context;
+  private final RetryingTimeTracker tracker;
 
   public RpcRetryingCallerImpl(long pause, int retries, int startLogErrorsCnt) {
     this(pause, retries, RetryingCallerInterceptorFactory.NO_OP_INTERCEPTOR, startLogErrorsCnt);
@@ -76,23 +73,7 @@ public class RpcRetryingCallerImpl<T> implements RpcRetryingCaller<T> {
     this.interceptor = interceptor;
     context = interceptor.createEmptyContext();
     this.startLogErrorsCnt = startLogErrorsCnt;
-  }
-
-  private int getRemainingTime(int callTimeout) {
-    if (callTimeout <= 0) {
-      return 0;
-    } else {
-      if (callTimeout == Integer.MAX_VALUE) return Integer.MAX_VALUE;
-      int remainingTime = (int) (callTimeout -
-          (EnvironmentEdgeManager.currentTime() - this.globalStartTime));
-      if (remainingTime < 1) {
-        // If there is no time left, we're trying anyway. It's too late.
-        // 0 means no timeout, and it's not the intent here. So we secure both cases by
-        // resetting to the minimum.
-        remainingTime = 1;
-      }
-      return remainingTime;
-    }
+    this.tracker = new RetryingTimeTracker();
   }
   
   @Override
@@ -108,21 +89,21 @@ public class RpcRetryingCallerImpl<T> implements RpcRetryingCaller<T> {
   throws IOException, RuntimeException {
     List<RetriesExhaustedException.ThrowableWithExtraContext> exceptions =
       new ArrayList<RetriesExhaustedException.ThrowableWithExtraContext>();
-    this.globalStartTime = EnvironmentEdgeManager.currentTime();
+    tracker.start();
     context.clear();
     for (int tries = 0;; tries++) {
       long expectedSleep;
       try {
         callable.prepare(tries != 0); // if called with false, check table status on ZK
         interceptor.intercept(context.prepare(callable, tries));
-        return callable.call(getRemainingTime(callTimeout));
+        return callable.call(tracker.getRemainingTime(callTimeout));
       } catch (PreemptiveFastFailException e) {
         throw e;
       } catch (Throwable t) {
         ExceptionUtil.rethrowIfInterrupt(t);
         if (tries > startLogErrorsCnt) {
           LOG.info("Call exception, tries=" + tries + ", maxAttempts=" + maxAttempts + ", started="
-              + (EnvironmentEdgeManager.currentTime() - this.globalStartTime) + " ms ago, "
+              + (EnvironmentEdgeManager.currentTime() - tracker.getStartTime()) + " ms ago, "
               + "cancelled=" + cancelled.get() + ", msg="
               + callable.getExceptionMessageAdditionalDetail());
         }
@@ -172,14 +153,13 @@ public class RpcRetryingCallerImpl<T> implements RpcRetryingCaller<T> {
    * @return Calculate how long a single call took
    */
   private long singleCallDuration(final long expectedSleep) {
-    return (EnvironmentEdgeManager.currentTime() - this.globalStartTime) + expectedSleep;
+    return (EnvironmentEdgeManager.currentTime() - tracker.getStartTime()) + expectedSleep;
   }
 
   @Override
   public T callWithoutRetries(RetryingCallable<T> callable, int callTimeout)
   throws IOException, RuntimeException {
     // The code of this method should be shared with withRetries.
-    this.globalStartTime = EnvironmentEdgeManager.currentTime();
     try {
       callable.prepare(false);
       return callable.call(callTimeout);
@@ -231,7 +211,7 @@ public class RpcRetryingCallerImpl<T> implements RpcRetryingCaller<T> {
 
   @Override
   public String toString() {
-    return "RpcRetryingCaller{" + "globalStartTime=" + globalStartTime +
+    return "RpcRetryingCaller{" + "globalStartTime=" + tracker.getStartTime() +
         ", pause=" + pause + ", maxAttempts=" + maxAttempts + '}';
   }
 }

http://git-wip-us.apache.org/repos/asf/hbase/blob/ef712df9/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ServerStatisticTracker.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ServerStatisticTracker.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ServerStatisticTracker.java
index d03ecf6..b8e7923 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ServerStatisticTracker.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ServerStatisticTracker.java
@@ -31,11 +31,12 @@ import java.util.concurrent.ConcurrentHashMap;
  * Tracks the statistics for multiple regions
  */
 @InterfaceAudience.Private
-public class ServerStatisticTracker {
+public class ServerStatisticTracker implements StatisticTrackable {
 
   private final ConcurrentHashMap<ServerName, ServerStatistics> stats =
       new ConcurrentHashMap<ServerName, ServerStatistics>();
 
+  @Override
   public void updateRegionStats(ServerName server, byte[] region, ClientProtos.RegionLoadStats
       currentStats) {
     ServerStatistics stat = stats.get(server);

http://git-wip-us.apache.org/repos/asf/hbase/blob/ef712df9/hbase-client/src/main/java/org/apache/hadoop/hbase/client/StatisticTrackable.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/StatisticTrackable.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/StatisticTrackable.java
new file mode 100644
index 0000000..7bb49e7
--- /dev/null
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/StatisticTrackable.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * 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,
+ * 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.
+ */
+package org.apache.hadoop.hbase.client;
+
+import org.apache.hadoop.hbase.ServerName;
+import org.apache.hadoop.hbase.classification.InterfaceAudience;
+import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
+
+/**
+ * Parent interface for an object to get updates about per-region statistics.
+ */
+@InterfaceAudience.Private
+public interface StatisticTrackable {
+  /**
+   *  Update stats per region.
+   * */
+  void updateRegionStats(ServerName server, byte[] region, ClientProtos.RegionLoadStats
+    stats);
+}

http://git-wip-us.apache.org/repos/asf/hbase/blob/ef712df9/hbase-client/src/main/java/org/apache/hadoop/hbase/client/StatsTrackingRpcRetryingCaller.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/StatsTrackingRpcRetryingCaller.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/StatsTrackingRpcRetryingCaller.java
deleted file mode 100644
index e82f1e8..0000000
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/StatsTrackingRpcRetryingCaller.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     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,
- * 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.
- */
-package org.apache.hadoop.hbase.client;
-
-import org.apache.hadoop.hbase.HRegionLocation;
-import org.apache.hadoop.hbase.classification.InterfaceAudience;
-
-import java.io.IOException;
-
-/**
- * An {@link RpcRetryingCaller} that will update the per-region stats for the call on return,
- * if stats are available
- */
-@InterfaceAudience.Private
-public class StatsTrackingRpcRetryingCaller<T> implements RpcRetryingCaller<T> {
-  private final ServerStatisticTracker stats;
-  private final RpcRetryingCaller<T> delegate;
-
-  public StatsTrackingRpcRetryingCaller(RpcRetryingCaller<T> delegate,
-      ServerStatisticTracker stats) {
-    this.delegate = delegate;
-    this.stats = stats;
-  }
-
-  @Override
-  public void cancel() {
-    delegate.cancel();
-  }
-
-  @Override
-  public T callWithRetries(RetryingCallable<T> callable, int callTimeout)
-      throws IOException, RuntimeException {
-    T result = delegate.callWithRetries(callable, callTimeout);
-    return updateStatsAndUnwrap(result, callable);
-  }
-
-  @Override
-  public T callWithoutRetries(RetryingCallable<T> callable, int callTimeout)
-      throws IOException, RuntimeException {
-    T result = delegate.callWithRetries(callable, callTimeout);
-    return updateStatsAndUnwrap(result, callable);
-  }
-
-  private T updateStatsAndUnwrap(T result, RetryingCallable<T> callable) {
-    // don't track stats about requests that aren't to regionservers
-    if (!(callable instanceof RegionServerCallable)) {
-      return result;
-    }
-
-    // mutli-server callables span multiple regions, so they don't have a location,
-    // but they are region server callables, so we have to handle them when we process the
-    // result in AsyncProcess#receiveMultiAction, not in here
-    if (callable instanceof MultiServerCallable) {
-      return result;
-    }
-
-    // update the stats for the single server callable
-    RegionServerCallable<T> regionCallable = (RegionServerCallable) callable;
-    HRegionLocation location = regionCallable.getLocation();
-    return ResultStatsUtil.updateStats(result, stats, location);
-  }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/hbase/blob/ef712df9/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/ProtobufUtil.java
----------------------------------------------------------------------
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 261a9aa..b052e63 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
@@ -193,8 +193,8 @@ public final class ProtobufUtil {
    */
   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);
+  final static Result EMPTY_RESULT_EXISTS_TRUE = Result.create(null, true);
+  final static Result EMPTY_RESULT_EXISTS_FALSE = Result.create(null, false);
   private final static Result EMPTY_RESULT_STALE = Result.create(EMPTY_CELL_ARRAY, null, true);
   private final static Result EMPTY_RESULT_EXISTS_TRUE_STALE
     = Result.create((Cell[])null, true, true);

http://git-wip-us.apache.org/repos/asf/hbase/blob/ef712df9/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/ResponseConverter.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/ResponseConverter.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/ResponseConverter.java
index 177b1c7..421907d 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/ResponseConverter.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/protobuf/ResponseConverter.java
@@ -89,7 +89,7 @@ public final class ResponseConverter {
     int requestRegionActionCount = request.getRegionActionCount();
     int responseRegionActionResultCount = response.getRegionActionResultCount();
     if (requestRegionActionCount != responseRegionActionResultCount) {
-      throw new IllegalStateException("Request mutation count=" + responseRegionActionResultCount +
+      throw new IllegalStateException("Request mutation count=" + requestRegionActionCount +
           " does not match response mutation result count=" + responseRegionActionResultCount);
     }
 
@@ -125,21 +125,27 @@ public final class ResponseConverter {
           responseValue = ProtobufUtil.toException(roe.getException());
         } else if (roe.hasResult()) {
           responseValue = ProtobufUtil.toResult(roe.getResult(), cells);
-          // add the load stats, if we got any
-          if (roe.hasLoadStats()) {
-            ((Result) responseValue).addResults(roe.getLoadStats());
-          }
         } else if (roe.hasServiceResult()) {
           responseValue = roe.getServiceResult();
-        } else {
-          // no result & no exception. Unexpected.
-          throw new IllegalStateException("No result & no exception roe=" + roe +
-              " for region " + actions.getRegion());
+        } else{
+          // Sometimes, the response is just "it was processed". Generally, this occurs for things
+          // like mutateRows where either we get back 'processed' (or not) and optionally some
+          // statistics about the regions we touched.
+          responseValue = response.getProcessed() ?
+                          ProtobufUtil.EMPTY_RESULT_EXISTS_TRUE :
+                          ProtobufUtil.EMPTY_RESULT_EXISTS_FALSE;
         }
         results.add(regionName, roe.getIndex(), responseValue);
       }
     }
 
+    if (response.hasRegionStatistics()) {
+      ClientProtos.MultiRegionLoadStats stats = response.getRegionStatistics();
+      for (int i = 0; i < stats.getRegionCount(); i++) {
+        results.addStatistic(stats.getRegion(i).getValue().toByteArray(), stats.getStat(i));
+      }
+    }
+
     return results;
   }
 
@@ -161,11 +167,9 @@ public final class ResponseConverter {
    * @param r
    * @return an action result builder
    */
-  public static ResultOrException.Builder buildActionResult(final ClientProtos.Result r,
-      ClientProtos.RegionLoadStats stats) {
+  public static ResultOrException.Builder buildActionResult(final ClientProtos.Result r) {
     ResultOrException.Builder builder = ResultOrException.newBuilder();
     if (r != null) builder.setResult(r);
-    if(stats != null) builder.setLoadStats(stats);
     return builder;
   }
 

http://git-wip-us.apache.org/repos/asf/hbase/blob/ef712df9/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestAsyncProcess.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestAsyncProcess.java b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestAsyncProcess.java
index 645cc42..1003d24 100644
--- a/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestAsyncProcess.java
+++ b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestAsyncProcess.java
@@ -185,10 +185,12 @@ public class TestAsyncProcess {
     }
 
     @Override
-    protected RpcRetryingCaller<MultiResponse> createCaller(MultiServerCallable<Row> callable) {
+    protected RpcRetryingCaller<MultiResponse> createCaller(
+        PayloadCarryingServerCallable callable) {
       callsCt.incrementAndGet();
+      MultiServerCallable callable1 = (MultiServerCallable) callable;
       final MultiResponse mr = createMultiResponse(
-          callable.getMulti(), nbMultiResponse, nbActions, new ResponseGenerator() {
+          callable1.getMulti(), nbMultiResponse, nbActions, new ResponseGenerator() {
             @Override
             public void addResponse(MultiResponse mr, byte[] regionName, Action<Row> a) {
               if (Arrays.equals(FAILS, a.getAction().getRow())) {
@@ -227,7 +229,8 @@ public class TestAsyncProcess {
     }
 
     @Override
-    public MultiResponse callWithoutRetries(RetryingCallable<MultiResponse> callable, int callTimeout)
+    public MultiResponse callWithoutRetries(RetryingCallable<MultiResponse> callable,
+                                            int callTimeout)
         throws IOException, RuntimeException {
       throw e;
     }
@@ -245,7 +248,8 @@ public class TestAsyncProcess {
     }
 
     @Override
-    protected RpcRetryingCaller<MultiResponse> createCaller(MultiServerCallable<Row> callable) {
+    protected RpcRetryingCaller<MultiResponse> createCaller(
+      PayloadCarryingServerCallable callable) {
       callsCt.incrementAndGet();
       return new CallerWithFailure(ioe);
     }
@@ -282,7 +286,8 @@ public class TestAsyncProcess {
 
     @Override
     protected RpcRetryingCaller<MultiResponse> createCaller(
-        MultiServerCallable<Row> callable) {
+        PayloadCarryingServerCallable payloadCallable) {
+      MultiServerCallable<Row> callable = (MultiServerCallable) payloadCallable;
       final MultiResponse mr = createMultiResponse(
           callable.getMulti(), nbMultiResponse, nbActions, new ResponseGenerator() {
             @Override
@@ -312,7 +317,8 @@ public class TestAsyncProcess {
 
       return new RpcRetryingCallerImpl<MultiResponse>(100, 10, 9) {
         @Override
-        public MultiResponse callWithoutRetries(RetryingCallable<MultiResponse> callable, int callTimeout)
+        public MultiResponse callWithoutRetries(RetryingCallable<MultiResponse> callable,
+                                                int callTimeout)
         throws IOException, RuntimeException {
           long sleep = -1;
           if (isDefault) {