You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kudu.apache.org by to...@apache.org on 2016/06/03 14:08:53 UTC

[3/3] incubator-kudu git commit: KUDU-1444. Get resource metrics of a scan.

KUDU-1444. Get resource metrics of a scan.

This patch supports to get the resource metrics of a scan in client side. The
resource metrics will be sent back to client in every scan RPC response. This
is useful for impala to show these stats in a query profile.

For now, the resource metrics only contains cfile_cache_miss_bytes and
cfile_cache_hit_bytes. We may add more in the future as needed.

Change-Id: Iedaf570a7601651c93275ae0a8565f1e33da842d
Reviewed-on: http://gerrit.cloudera.org:8080/3013
Tested-by: Kudu Jenkins
Reviewed-by: Todd Lipcon <to...@apache.org>


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

Branch: refs/heads/master
Commit: ece7b5653998db318e4baa5d57f27ba3a836731d
Parents: 6034b85
Author: zhangzhen <zh...@xiaomi.com>
Authored: Tue May 10 19:35:36 2016 +0800
Committer: Todd Lipcon <to...@apache.org>
Committed: Fri Jun 3 13:49:55 2016 +0000

----------------------------------------------------------------------
 src/kudu/cfile/cfile_reader.cc              |  9 ++-
 src/kudu/client/CMakeLists.txt              |  2 +
 src/kudu/client/client-test.cc              | 40 +++++++++++--
 src/kudu/client/client.cc                   |  4 ++
 src/kudu/client/client.h                    |  4 ++
 src/kudu/client/resource_metrics-internal.h | 53 ++++++++++++++++++
 src/kudu/client/resource_metrics.cc         | 71 ++++++++++++++++++++++++
 src/kudu/client/resource_metrics.h          | 53 ++++++++++++++++++
 src/kudu/client/scanner-internal.cc         | 24 +++++++-
 src/kudu/client/scanner-internal.h          |  6 ++
 src/kudu/tserver/tablet_service.cc          | 12 +++-
 src/kudu/tserver/tserver.proto              | 10 ++++
 src/kudu/util/trace_metrics.h               | 12 ++++
 13 files changed, 289 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/ece7b565/src/kudu/cfile/cfile_reader.cc
----------------------------------------------------------------------
diff --git a/src/kudu/cfile/cfile_reader.cc b/src/kudu/cfile/cfile_reader.cc
index d05e1d7..0644f1c 100644
--- a/src/kudu/cfile/cfile_reader.cc
+++ b/src/kudu/cfile/cfile_reader.cc
@@ -54,6 +54,9 @@ using strings::Substitute;
 namespace kudu {
 namespace cfile {
 
+const char* CFILE_CACHE_MISS_BYTES_METRIC_NAME = "cfile_cache_miss_bytes";
+const char* CFILE_CACHE_HIT_BYTES_METRIC_NAME = "cfile_cache_hit_bytes";
+
 // Magic+Length: 8-byte magic, followed by 4-byte header size
 static const size_t kMagicAndLengthSize = 12;
 static const size_t kMaxHeaderFooterPBSize = 64*1024;
@@ -318,7 +321,7 @@ Status CFileReader::ReadBlock(const BlockPointer &ptr, CacheControl cache_contro
   BlockCache::CacheKey key(block_->id(), ptr.offset());
   if (cache->Lookup(key, cache_behavior, &bc_handle)) {
     TRACE_COUNTER_INCREMENT("cfile_cache_hit", 1);
-    TRACE_COUNTER_INCREMENT("cfile_cache_hit_bytes", ptr.size());
+    TRACE_COUNTER_INCREMENT(CFILE_CACHE_HIT_BYTES_METRIC_NAME, ptr.size());
     *ret = BlockHandle::WithDataFromCache(&bc_handle);
     // Cache hit
     return Status::OK();
@@ -331,9 +334,9 @@ Status CFileReader::ReadBlock(const BlockPointer &ptr, CacheControl cache_contro
   TRACE_EVENT1("io", "CFileReader::ReadBlock(cache miss)",
                "cfile", ToString());
   TRACE_COUNTER_INCREMENT("cfile_cache_miss", 1);
-  TRACE_COUNTER_INCREMENT("cfile_cache_miss_bytes", ptr.size());
-  ScratchMemory scratch;
+  TRACE_COUNTER_INCREMENT(CFILE_CACHE_MISS_BYTES_METRIC_NAME, ptr.size());
 
+  ScratchMemory scratch;
   // If we are reading uncompressed data and plan to cache the result,
   // then we should allocate our scratch memory directly from the cache.
   // This avoids an extra memory copy in the case of an NVM cache.

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/ece7b565/src/kudu/client/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/kudu/client/CMakeLists.txt b/src/kudu/client/CMakeLists.txt
index 8c56e9b..eb38862 100644
--- a/src/kudu/client/CMakeLists.txt
+++ b/src/kudu/client/CMakeLists.txt
@@ -40,6 +40,7 @@ set(CLIENT_SRCS
   scan_predicate.cc
   scan_token-internal.cc
   scanner-internal.cc
+  resource_metrics.cc
   schema.cc
   session-internal.cc
   table-internal.cc
@@ -176,6 +177,7 @@ install(FILES
   stubs.h
   value.h
   write_op.h
+  resource_metrics.h
   DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/kudu/client)
 
 # Headers: common

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/ece7b565/src/kudu/client/client-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/client/client-test.cc b/src/kudu/client/client-test.cc
index 1aae285..9f4e3d8 100644
--- a/src/kudu/client/client-test.cc
+++ b/src/kudu/client/client-test.cc
@@ -20,6 +20,7 @@
 #include <glog/stl_logging.h>
 
 #include <algorithm>
+#include <map>
 #include <memory>
 #include <vector>
 
@@ -36,6 +37,7 @@
 #include "kudu/common/wire_protocol.h"
 #include "kudu/consensus/consensus.proxy.h"
 #include "kudu/gutil/atomicops.h"
+#include "kudu/gutil/map-util.h"
 #include "kudu/gutil/stl_util.h"
 #include "kudu/gutil/strings/substitute.h"
 #include "kudu/integration-tests/mini_cluster.h"
@@ -82,6 +84,7 @@ using std::set;
 using std::string;
 using std::unique_ptr;
 using std::vector;
+using std::map;
 
 namespace kudu {
 namespace client {
@@ -172,6 +175,15 @@ class ClientTest : public KuduTest {
     return resp.tablet_locations(0).tablet_id();
   }
 
+  void FlushTablet(const string& tablet_id) {
+    for (int i = 0; i < cluster_->num_tablet_servers(); i++) {
+      scoped_refptr<TabletPeer> tablet_peer;
+      ASSERT_TRUE(cluster_->mini_tablet_server(i)->server()->tablet_manager()->LookupTablet(
+          tablet_id, &tablet_peer));
+      ASSERT_OK(tablet_peer->tablet()->Flush());
+    }
+  }
+
   void CheckNoRpcOverflow() {
     for (int i = 0; i < cluster_->num_tablet_servers(); i++) {
       MiniTabletServer* server = cluster_->mini_tablet_server(i);
@@ -264,6 +276,26 @@ class ClientTest : public KuduTest {
     return std::move(del);
   }
 
+  void DoTestScanResourceMetrics() {
+    KuduScanner scanner(client_table_.get());
+    string tablet_id = GetFirstTabletId(client_table_.get());
+    // flush to ensure we scan disk later
+    FlushTablet(tablet_id);
+    ASSERT_OK(scanner.SetProjectedColumns({ "key" }));
+    LOG_TIMING(INFO, "Scanning disk with no predicates") {
+      ASSERT_OK(scanner.Open());
+      ASSERT_TRUE(scanner.HasMoreRows());
+      KuduScanBatch batch;
+      while (scanner.HasMoreRows()) {
+        ASSERT_OK(scanner.NextBatch(&batch));
+      }
+      std::map<std::string, int64_t> metrics = scanner.GetResourceMetrics().Get();
+      ASSERT_TRUE(ContainsKey(metrics, "cfile_cache_miss_bytes"));
+      ASSERT_TRUE(ContainsKey(metrics, "cfile_cache_hit_bytes"));
+      ASSERT_GT(metrics["cfile_cache_miss_bytes"] + metrics["cfile_cache_hit_bytes"], 0);
+    }
+  }
+
   void DoTestScanWithoutPredicates() {
     KuduScanner scanner(client_table_.get());
     ASSERT_OK(scanner.SetProjectedColumns({ "key" }));
@@ -521,6 +553,7 @@ TEST_F(ClientTest, TestScan) {
 
   // Scan after insert
   DoTestScanWithoutPredicates();
+  DoTestScanResourceMetrics();
   DoTestScanWithStringPredicate();
   DoTestScanWithKeyPredicate();
 
@@ -989,12 +1022,7 @@ TEST_F(ClientTest, TestScanFaultTolerance) {
     // disk.
     if (with_flush) {
       string tablet_id = GetFirstTabletId(table.get());
-      for (int i = 0; i < cluster_->num_tablet_servers(); i++) {
-        scoped_refptr<TabletPeer> tablet_peer;
-        ASSERT_TRUE(cluster_->mini_tablet_server(i)->server()->tablet_manager()->LookupTablet(
-                tablet_id, &tablet_peer));
-        ASSERT_OK(tablet_peer->tablet()->Flush());
-      }
+      FlushTablet(tablet_id);
     }
 
     // Test a few different recoverable server-side error conditions.

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/ece7b565/src/kudu/client/client.cc
----------------------------------------------------------------------
diff --git a/src/kudu/client/client.cc b/src/kudu/client/client.cc
index 781e917..e605b9b 100644
--- a/src/kudu/client/client.cc
+++ b/src/kudu/client/client.cc
@@ -993,6 +993,10 @@ KuduSchema KuduScanner::GetProjectionSchema() const {
   return KuduSchema(*data_->configuration().projection());
 }
 
+const ResourceMetrics& KuduScanner::GetResourceMetrics() const {
+  return data_->resource_metrics_;
+}
+
 namespace {
 // Callback for the RPC sent by Close().
 // We can't use the KuduScanner response and RPC controller members for this

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/ece7b565/src/kudu/client/client.h
----------------------------------------------------------------------
diff --git a/src/kudu/client/client.h b/src/kudu/client/client.h
index f7f3702..93edad7 100644
--- a/src/kudu/client/client.h
+++ b/src/kudu/client/client.h
@@ -21,6 +21,7 @@
 #include <string>
 #include <vector>
 
+#include "kudu/client/resource_metrics.h"
 #include "kudu/client/row_result.h"
 #include "kudu/client/scan_batch.h"
 #include "kudu/client/scan_predicate.h"
@@ -1024,6 +1025,9 @@ class KUDU_EXPORT KuduScanner {
   // RPC made by the server.
   Status GetCurrentServer(KuduTabletServer** server);
 
+  // Returns the cumulative resource metrics since the scan was started.
+  const ResourceMetrics& GetResourceMetrics() const;
+
   // Set the hint for the size of the next batch in bytes.
   // If setting to 0 before calling Open(), it means that the first call
   // to the tablet server won't return data.

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/ece7b565/src/kudu/client/resource_metrics-internal.h
----------------------------------------------------------------------
diff --git a/src/kudu/client/resource_metrics-internal.h b/src/kudu/client/resource_metrics-internal.h
new file mode 100644
index 0000000..d9a522d
--- /dev/null
+++ b/src/kudu/client/resource_metrics-internal.h
@@ -0,0 +1,53 @@
+// 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.
+#ifndef KUDU_CLIENT_RESOURCE_METRICS_INTERNAL_H
+#define KUDU_CLIENT_RESOURCE_METRICS_INTERNAL_H
+
+#include <map>
+#include <mutex>
+#include <stdint.h>
+#include <string>
+
+#include "kudu/util/locks.h"
+
+namespace kudu {
+
+namespace client {
+
+class ResourceMetrics::Data {
+ public:
+  Data();
+  ~Data();
+
+  // Return a copy of the current counter map.
+  std::map<std::string, int64_t> Get() const;
+
+  // Increment the given counter.
+  void Increment(const std::string& name, int64_t amount);
+
+  // Return metric's current value.
+  int64_t GetMetric(const std::string& name) const;
+
+ private:
+  mutable simple_spinlock lock_;
+  std::map<std::string, int64_t> counters_;
+};
+
+} // namespace client
+} // namespace kudu
+
+#endif

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/ece7b565/src/kudu/client/resource_metrics.cc
----------------------------------------------------------------------
diff --git a/src/kudu/client/resource_metrics.cc b/src/kudu/client/resource_metrics.cc
new file mode 100644
index 0000000..f8ccc2a
--- /dev/null
+++ b/src/kudu/client/resource_metrics.cc
@@ -0,0 +1,71 @@
+// 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.
+
+#include "kudu/client/resource_metrics.h"
+#include "kudu/client/resource_metrics-internal.h"
+
+#include <map>
+#include <mutex>
+#include <stdint.h>
+#include <string>
+
+#include "kudu/gutil/map-util.h"
+
+namespace kudu {
+
+namespace client {
+
+ResourceMetrics::ResourceMetrics() :
+  data_(new Data) {}
+
+ResourceMetrics::~ResourceMetrics() {
+  delete data_;
+}
+
+void ResourceMetrics::Increment(const std::string& name, int64_t amount) {
+  data_->Increment(name, amount);
+}
+
+std::map<std::string, int64_t> ResourceMetrics::Get() const {
+  return data_->Get();
+}
+
+int64_t ResourceMetrics::GetMetric(const std::string& name) const {
+  return data_->GetMetric(name);
+}
+
+ResourceMetrics::Data::Data() {}
+
+ResourceMetrics::Data::~Data() {}
+
+void ResourceMetrics::Data::Increment(const std::string& name, int64_t amount) {
+  std::lock_guard<simple_spinlock> l(lock_);
+  counters_[name] += amount;
+}
+
+std::map<std::string, int64_t> ResourceMetrics::Data::Get() const {
+  std::lock_guard<simple_spinlock> l(lock_);
+  return counters_;
+}
+
+int64_t ResourceMetrics::Data::GetMetric(const std::string& name) const {
+  std::lock_guard<simple_spinlock> l(lock_);
+  return FindWithDefault(counters_, name, 0);
+}
+
+} // namespace client
+} // namespace kudu

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/ece7b565/src/kudu/client/resource_metrics.h
----------------------------------------------------------------------
diff --git a/src/kudu/client/resource_metrics.h b/src/kudu/client/resource_metrics.h
new file mode 100644
index 0000000..d31edaf
--- /dev/null
+++ b/src/kudu/client/resource_metrics.h
@@ -0,0 +1,53 @@
+// 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.
+#ifndef KUDU_CLIENT_RESOURCE_METRICS_H
+#define KUDU_CLIENT_RESOURCE_METRICS_H
+
+#include <map>
+#include <stdint.h>
+#include <string>
+
+#include "kudu/util/kudu_export.h"
+
+namespace kudu {
+namespace client {
+
+class KUDU_EXPORT ResourceMetrics {
+ public:
+  ResourceMetrics();
+
+  ~ResourceMetrics();
+
+  // Return a map that contains all metrics, its key is the metric name
+  // and its value is corresponding metric count.
+  std::map<std::string, int64_t> Get() const;
+
+  // Increment the given metric.
+  void Increment(const std::string& name, int64_t amount);
+
+  // Return the metric's current count.
+  int64_t GetMetric(const std::string& name) const;
+
+ private:
+  class KUDU_NO_EXPORT Data;
+  Data* data_;
+};
+
+} // namespace client
+} // namespace kudu
+
+#endif

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/ece7b565/src/kudu/client/scanner-internal.cc
----------------------------------------------------------------------
diff --git a/src/kudu/client/scanner-internal.cc b/src/kudu/client/scanner-internal.cc
index afb9316..c52e1c5 100644
--- a/src/kudu/client/scanner-internal.cc
+++ b/src/kudu/client/scanner-internal.cc
@@ -33,6 +33,9 @@
 #include "kudu/rpc/rpc_controller.h"
 #include "kudu/util/hexdump.h"
 
+using google::protobuf::FieldDescriptor;
+using google::protobuf::Reflection;
+
 using std::set;
 using std::string;
 
@@ -142,6 +145,21 @@ Status KuduScanner::Data::HandleError(const ScanRpcStatus& err,
   return err.status;
 }
 
+void KuduScanner::Data::UpdateResourceMetrics() {
+  if (last_response_.has_resource_metrics()) {
+    tserver::ResourceMetricsPB resource_metrics = last_response_.resource_metrics();
+    const Reflection* reflection = resource_metrics.GetReflection();
+    vector<const FieldDescriptor*> fields;
+    reflection->ListFields(resource_metrics, &fields);
+    for (const FieldDescriptor* field : fields) {
+      if (reflection->HasField(resource_metrics, field) &&
+          field->cpp_type() == FieldDescriptor::CPPTYPE_INT64) {
+        resource_metrics_.Increment(field->name(), reflection->GetInt64(resource_metrics, field));
+      }
+    }
+  }
+}
+
 ScanRpcStatus KuduScanner::Data::AnalyzeResponse(const Status& rpc_status,
                                                  const MonoTime& overall_deadline,
                                                  const MonoTime& deadline) {
@@ -227,11 +245,15 @@ ScanRpcStatus KuduScanner::Data::SendScanRpc(const MonoTime& overall_deadline,
   if (!configuration_.spec().predicates().empty()) {
     controller_.RequireServerFeature(TabletServerFeatures::COLUMN_PREDICATES);
   }
-  return AnalyzeResponse(
+  ScanRpcStatus scan_status = AnalyzeResponse(
       proxy_->Scan(next_req_,
                    &last_response_,
                    &controller_),
       rpc_deadline, overall_deadline);
+  if (scan_status.result == ScanRpcStatus::OK) {
+    UpdateResourceMetrics();
+  }
+  return scan_status;
 }
 
 Status KuduScanner::Data::OpenTablet(const string& partition_key,

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/ece7b565/src/kudu/client/scanner-internal.h
----------------------------------------------------------------------
diff --git a/src/kudu/client/scanner-internal.h b/src/kudu/client/scanner-internal.h
index f5657c7..e3a8ef5 100644
--- a/src/kudu/client/scanner-internal.h
+++ b/src/kudu/client/scanner-internal.h
@@ -22,6 +22,7 @@
 #include <vector>
 
 #include "kudu/client/client.h"
+#include "kudu/client/resource_metrics.h"
 #include "kudu/client/row_result.h"
 #include "kudu/client/scan_configuration.h"
 #include "kudu/common/partition_pruner.h"
@@ -206,6 +207,9 @@ class KuduScanner::Data {
   // TODO: This and the overall scan retry logic duplicates much of RpcRetrier.
   Status last_error_;
 
+  // The scanner's cumulative resource metrics since the scan was started.
+  ResourceMetrics resource_metrics_;
+
  private:
   // Analyze the response of the last Scan RPC made by this scanner.
   //
@@ -223,6 +227,8 @@ class KuduScanner::Data {
                                 const MonoTime& overall_deadline,
                                 const MonoTime& rpc_deadline);
 
+  void UpdateResourceMetrics();
+
   DISALLOW_COPY_AND_ASSIGN(Data);
 };
 

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/ece7b565/src/kudu/tserver/tablet_service.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tserver/tablet_service.cc b/src/kudu/tserver/tablet_service.cc
index adb5149..bed74b8 100644
--- a/src/kudu/tserver/tablet_service.cc
+++ b/src/kudu/tserver/tablet_service.cc
@@ -84,6 +84,13 @@ TAG_FLAG(scanner_inject_latency_on_each_batch_ms, unsafe);
 DECLARE_int32(memory_limit_warn_threshold_percentage);
 
 namespace kudu {
+namespace cfile {
+extern const char* CFILE_CACHE_MISS_BYTES_METRIC_NAME;
+extern const char* CFILE_CACHE_HIT_BYTES_METRIC_NAME;
+}
+}
+
+namespace kudu {
 namespace tserver {
 
 using consensus::ChangeConfigRequestPB;
@@ -1082,7 +1089,10 @@ void TabletServiceImpl::Scan(const ScanRequestPB* req,
       resp->set_last_primary_key(last.ToString());
     }
   }
-
+  resp->mutable_resource_metrics()->set_cfile_cache_miss_bytes(
+    context->trace()->metrics()->GetMetric(cfile::CFILE_CACHE_MISS_BYTES_METRIC_NAME));
+  resp->mutable_resource_metrics()->set_cfile_cache_hit_bytes(
+    context->trace()->metrics()->GetMetric(cfile::CFILE_CACHE_HIT_BYTES_METRIC_NAME));
   context->RespondSuccess();
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/ece7b565/src/kudu/tserver/tserver.proto
----------------------------------------------------------------------
diff --git a/src/kudu/tserver/tserver.proto b/src/kudu/tserver/tserver.proto
index 93850a5..9df226a 100644
--- a/src/kudu/tserver/tserver.proto
+++ b/src/kudu/tserver/tserver.proto
@@ -298,6 +298,13 @@ message ScanRequestPB {
   optional bool close_scanner = 5;
 }
 
+// RPC's resource metrics.
+message ResourceMetricsPB {
+  // all metrics MUST be the type of int64.
+  optional int64 cfile_cache_miss_bytes = 1;
+  optional int64 cfile_cache_hit_bytes = 2;
+}
+
 message ScanResponsePB {
   // The error, if an error occurred with this request.
   optional TabletServerErrorPB error = 1;
@@ -330,6 +337,9 @@ message ScanResponsePB {
   // If this is a fault-tolerant scanner, this is set to the encoded primary
   // key of the last row returned in the response.
   optional bytes last_primary_key = 7;
+
+  // The resource usage of this RPC.
+  optional ResourceMetricsPB resource_metrics = 8;
 }
 
 // A scanner keep-alive request.

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/ece7b565/src/kudu/util/trace_metrics.h
----------------------------------------------------------------------
diff --git a/src/kudu/util/trace_metrics.h b/src/kudu/util/trace_metrics.h
index fbe1774..a230821 100644
--- a/src/kudu/util/trace_metrics.h
+++ b/src/kudu/util/trace_metrics.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include "kudu/gutil/macros.h"
+#include "kudu/gutil/map-util.h"
 #include "kudu/util/atomic.h"
 #include "kudu/util/locks.h"
 
@@ -65,6 +66,12 @@ class TraceMetrics {
     tcmalloc_contention_cycles_.IncrementBy(cycles);
   }
 
+  // Return metric's current value.
+  //
+  // NOTE: the 'name' MUST be the same const char* which is used for
+  // insertion. This is because we do pointer-wise comparison internally.
+  int64_t GetMetric(const char* name) const;
+
  private:
   mutable simple_spinlock lock_;
   std::map<const char*, int64_t> counters_;
@@ -90,4 +97,9 @@ inline std::map<const char*, int64_t> TraceMetrics::Get() const {
   return m;
 }
 
+inline int64_t TraceMetrics::GetMetric(const char* name) const {
+  std::lock_guard<simple_spinlock> l(lock_);
+  return FindWithDefault(counters_, name, 0);
+}
+
 } // namespace kudu