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

[kudu] branch master updated: metrics: replace kudu::Bind usage with lambdas in FunctionGauge

This is an automated email from the ASF dual-hosted git repository.

adar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kudu.git


The following commit(s) were added to refs/heads/master by this push:
     new 7dd10ba  metrics: replace kudu::Bind usage with lambdas in FunctionGauge
7dd10ba is described below

commit 7dd10ba35d3db36f25b2920c6aa098eddeacc3e5
Author: Adar Dembo <ad...@cloudera.com>
AuthorDate: Wed Mar 18 01:16:26 2020 -0700

    metrics: replace kudu::Bind usage with lambdas in FunctionGauge
    
    Let's start with a little history lesson. Back in 2014, we imported
    Chromium's Bind (and associated machinery) into gutil as kudu::Bind. At the
    time we hadn't migrated to C++11, so we couldn't use lambdas, and the
    kudu::Bind feature set was rich[1], at least as compared to boost::bind.
    
    Now that we're on C++11 and can use lambdas, there's very little that
    kudu::Bind can do that lambdas can't. The only thing that comes to mind is
    passing ownership of an object to a callback via the kudu::Owned() or
    kudu::Passed() wrappers, and we're not using those features. So in the
    interest of modernizing the Kudu codebase a bit, I'm going to replace
    kudu::Bind with lambdas. Lambdas are simpler, can be more easily inlined by
    the compiler, and will result in a reduction of code at the end when we
    remove kudu::Bind and friends from the repo.
    
    This patch kicks off the conversion process by using lambdas in
    FunctionGauge, which is a heavily used source of kudu::Bind.
    
    1. See commit 66282df07.
    
    Change-Id: If60a0dabde1fde1465d73dd9e8edc244fc780c37
    Reviewed-on: http://gerrit.cloudera.org:8080/15474
    Reviewed-by: Bankim Bhavsar <ba...@cloudera.com>
    Tested-by: Adar Dembo <ad...@cloudera.com>
    Reviewed-by: Andrew Wong <aw...@cloudera.com>
---
 src/kudu/clock/builtin_ntp.cc            | 17 ++++-------
 src/kudu/clock/hybrid_clock.cc           |  8 ++----
 src/kudu/clock/logical_clock.cc          |  6 ++--
 src/kudu/codegen/compilation_manager.cc  | 15 +++-------
 src/kudu/consensus/consensus-test-util.h |  1 +
 src/kudu/consensus/raft_consensus.cc     |  6 ++--
 src/kudu/master/ts_manager.cc            |  7 ++---
 src/kudu/rpc/retriable_rpc.h             |  1 +
 src/kudu/server/tcmalloc_metrics.cc      | 28 +++++++++++++------
 src/kudu/tablet/tablet.cc                | 23 +++++++--------
 src/kudu/tablet/tablet_replica-test.cc   |  4 +--
 src/kudu/tablet/tablet_replica.cc        |  9 ++----
 src/kudu/tserver/scanners.cc             |  7 ++---
 src/kudu/tserver/tablet_server-test.cc   |  5 ++--
 src/kudu/tserver/ts_tablet_manager.cc    | 48 ++++++++++++++++----------------
 src/kudu/util/metrics-test.cc            | 22 +++++++--------
 src/kudu/util/metrics.cc                 |  4 +--
 src/kudu/util/metrics.h                  | 47 +++++++++++++------------------
 src/kudu/util/net/dns_resolver.cc        |  1 +
 src/kudu/util/spinlock_profiling.cc      |  3 +-
 src/kudu/util/thread.cc                  | 26 ++++++++---------
 21 files changed, 131 insertions(+), 157 deletions(-)

diff --git a/src/kudu/clock/builtin_ntp.cc b/src/kudu/clock/builtin_ntp.cc
index 613a71e..3331eda 100644
--- a/src/kudu/clock/builtin_ntp.cc
+++ b/src/kudu/clock/builtin_ntp.cc
@@ -39,8 +39,6 @@
 #include <glog/logging.h>
 
 #include "kudu/clock/builtin_ntp-internal.h"
-#include "kudu/gutil/bind.h"
-#include "kudu/gutil/bind_helpers.h"
 #include "kudu/gutil/port.h"
 #include "kudu/gutil/strings/join.h"
 #include "kudu/gutil/strings/strcat.h"
@@ -1108,17 +1106,14 @@ Status BuiltInNtp::CombineClocks() {
 
 void BuiltInNtp::RegisterMetrics(const scoped_refptr<MetricEntity>& entity) {
   METRIC_builtin_ntp_local_clock_delta.InstantiateFunctionGauge(
-      entity,
-      Bind(&BuiltInNtp::LocalClockDeltaForMetrics, Unretained(this)))->
-          AutoDetachToLastValue(&metric_detacher_);
+      entity, [this]() { return this->LocalClockDeltaForMetrics(); })->
+      AutoDetachToLastValue(&metric_detacher_);
   METRIC_builtin_ntp_time.InstantiateFunctionGauge(
-      entity,
-      Bind(&BuiltInNtp::WalltimeForMetrics, Unretained(this)))->
-          AutoDetachToLastValue(&metric_detacher_);
+      entity, [this]() { return this->WalltimeForMetrics(); })->
+      AutoDetachToLastValue(&metric_detacher_);
   METRIC_builtin_ntp_error.InstantiateFunctionGauge(
-      entity,
-      Bind(&BuiltInNtp::MaxErrorForMetrics, Unretained(this)))->
-          AutoDetachToLastValue(&metric_detacher_);
+      entity, [this]() { return this->MaxErrorForMetrics(); })->
+      AutoDetachToLastValue(&metric_detacher_);
   max_errors_histogram_ =
       METRIC_builtin_ntp_max_errors.Instantiate(entity);
 }
diff --git a/src/kudu/clock/hybrid_clock.cc b/src/kudu/clock/hybrid_clock.cc
index 8caa5e8..08cc2fd 100644
--- a/src/kudu/clock/hybrid_clock.cc
+++ b/src/kudu/clock/hybrid_clock.cc
@@ -33,8 +33,6 @@
 #include "kudu/clock/mock_ntp.h"
 #include "kudu/clock/system_ntp.h"
 #include "kudu/clock/system_unsync_time.h"
-#include "kudu/gutil/bind.h"
-#include "kudu/gutil/bind_helpers.h"
 #include "kudu/gutil/macros.h"
 #include "kudu/gutil/port.h"
 #include "kudu/gutil/strings/substitute.h"
@@ -605,12 +603,10 @@ Status HybridClock::InitWithTimeSource(TimeSource time_source,
   // values when the object is not ready for that yet. Gauges produce special
   // values for corresponding metrics, but there is no value in that anyways.
   METRIC_hybrid_clock_timestamp.InstantiateFunctionGauge(
-      metric_entity_,
-      Bind(&HybridClock::NowForMetrics, Unretained(this)))->
+      metric_entity_, [this]() { return this->NowForMetrics(); })->
           AutoDetachToLastValue(&metric_detacher_);
   METRIC_hybrid_clock_error.InstantiateFunctionGauge(
-      metric_entity_,
-      Bind(&HybridClock::ErrorForMetrics, Unretained(this)))->
+      metric_entity_, [this]() { return this->ErrorForMetrics(); })->
           AutoDetachToLastValue(&metric_detacher_);
 
   return Status::OK();
diff --git a/src/kudu/clock/logical_clock.cc b/src/kudu/clock/logical_clock.cc
index 3403e01..fa46611 100644
--- a/src/kudu/clock/logical_clock.cc
+++ b/src/kudu/clock/logical_clock.cc
@@ -20,12 +20,11 @@
 #include <memory>
 #include <ostream>
 #include <string>
+#include <utility>
 
 #include <glog/logging.h>
 
 #include "kudu/gutil/atomicops.h"
-#include "kudu/gutil/bind.h"
-#include "kudu/gutil/bind_helpers.h"
 #include "kudu/gutil/port.h"
 #include "kudu/gutil/strings/substitute.h"
 #include "kudu/util/metrics.h"
@@ -51,8 +50,7 @@ LogicalClock::LogicalClock(const Timestamp& timestamp,
     : now_(timestamp.value() - 1) {
   if (metric_entity) {
     METRIC_logical_clock_timestamp.InstantiateFunctionGauge(
-        metric_entity,
-        Bind(&LogicalClock::GetCurrentTime, Unretained(this)))->
+        metric_entity, [this]() { return this->GetCurrentTime(); })->
             AutoDetachToLastValue(&metric_detacher_);
   }
 }
diff --git a/src/kudu/codegen/compilation_manager.cc b/src/kudu/codegen/compilation_manager.cc
index 3a7e5af..2dd97f5 100644
--- a/src/kudu/codegen/compilation_manager.cc
+++ b/src/kudu/codegen/compilation_manager.cc
@@ -30,9 +30,6 @@
 #include "kudu/codegen/jit_wrapper.h"
 #include "kudu/codegen/row_projector.h"
 #include "kudu/common/schema.h"
-#include "kudu/gutil/bind.h"
-#include "kudu/gutil/bind_helpers.h"
-#include "kudu/gutil/callback.h"
 #include "kudu/gutil/casts.h"
 #include "kudu/gutil/ref_counted.h"
 #include "kudu/util/faststring.h"
@@ -162,16 +159,12 @@ Status CompilationManager::StartInstrumentation(const scoped_refptr<MetricEntity
   // register the same metric in multiple registries. Using a gauge which loads
   // an atomic int is a suitable workaround: each TS's registry ends up with a
   // unique gauge which reads the value of the singleton's integer.
-  Callback<int64_t(void)> hits = Bind(&AtomicInt<int64_t>::Load,
-                                      Unretained(&hit_counter_),
-                                      kMemOrderNoBarrier);
-  Callback<int64_t(void)> queries = Bind(&AtomicInt<int64_t>::Load,
-                                         Unretained(&query_counter_),
-                                         kMemOrderNoBarrier);
   metric_entity->NeverRetire(
-      METRIC_code_cache_hits.InstantiateFunctionGauge(metric_entity, hits));
+      METRIC_code_cache_hits.InstantiateFunctionGauge(
+          metric_entity, [this]() { return this->hit_counter_.Load(kMemOrderNoBarrier); }));
   metric_entity->NeverRetire(
-      METRIC_code_cache_queries.InstantiateFunctionGauge(metric_entity, queries));
+      METRIC_code_cache_queries.InstantiateFunctionGauge(
+          metric_entity, [this]() { return this->query_counter_.Load(kMemOrderNoBarrier); }));
   return Status::OK();
 }
 
diff --git a/src/kudu/consensus/consensus-test-util.h b/src/kudu/consensus/consensus-test-util.h
index b749611..2b21cef 100644
--- a/src/kudu/consensus/consensus-test-util.h
+++ b/src/kudu/consensus/consensus-test-util.h
@@ -36,6 +36,7 @@
 #include "kudu/consensus/log.h"
 #include "kudu/consensus/opid_util.h"
 #include "kudu/consensus/raft_consensus.h"
+#include "kudu/gutil/bind.h"
 #include "kudu/gutil/map-util.h"
 #include "kudu/gutil/strings/substitute.h"
 #include "kudu/rpc/messenger.h"
diff --git a/src/kudu/consensus/raft_consensus.cc b/src/kudu/consensus/raft_consensus.cc
index 2e9eb97..b7174f3 100644
--- a/src/kudu/consensus/raft_consensus.cc
+++ b/src/kudu/consensus/raft_consensus.cc
@@ -47,7 +47,6 @@
 #include "kudu/consensus/quorum_util.h"
 #include "kudu/consensus/time_manager.h"
 #include "kudu/gutil/bind.h"
-#include "kudu/gutil/bind_helpers.h"
 #include "kudu/gutil/macros.h"
 #include "kudu/gutil/map-util.h"
 #include "kudu/gutil/port.h"
@@ -249,10 +248,9 @@ Status RaftConsensus::Start(const ConsensusBootstrapInfo& info,
                                        failed_elections_since_stable_leader_);
 
   METRIC_time_since_last_leader_heartbeat.InstantiateFunctionGauge(
-      metric_entity,
-      Bind(&RaftConsensus::GetMillisSinceLastLeaderHeartbeat, Unretained(this)),
+      metric_entity, [this]() { return this->GetMillisSinceLastLeaderHeartbeat(); },
       MergeType::kMax)
-    ->AutoDetach(&metric_detacher_);
+      ->AutoDetach(&metric_detacher_);
 
   // A single Raft thread pool token is shared between RaftConsensus and
   // PeerManager. Because PeerManager is owned by RaftConsensus, it receives a
diff --git a/src/kudu/master/ts_manager.cc b/src/kudu/master/ts_manager.cc
index de77c97..cc1b89d 100644
--- a/src/kudu/master/ts_manager.cc
+++ b/src/kudu/master/ts_manager.cc
@@ -30,8 +30,6 @@
 
 #include "kudu/common/common.pb.h"
 #include "kudu/common/wire_protocol.pb.h"
-#include "kudu/gutil/bind.h"
-#include "kudu/gutil/bind_helpers.h"
 #include "kudu/gutil/map-util.h"
 #include "kudu/gutil/port.h"
 #include "kudu/gutil/strings/substitute.h"
@@ -97,9 +95,8 @@ TSManager::TSManager(LocationCache* location_cache,
     : ts_state_lock_(RWMutex::Priority::PREFER_READING),
       location_cache_(location_cache) {
   METRIC_cluster_replica_skew.InstantiateFunctionGauge(
-      metric_entity,
-      Bind(&TSManager::ClusterSkew, Unretained(this)))
-    ->AutoDetach(&metric_detacher_);
+      metric_entity, [this]() { return this->ClusterSkew(); })
+      ->AutoDetach(&metric_detacher_);
 }
 
 TSManager::~TSManager() {
diff --git a/src/kudu/rpc/retriable_rpc.h b/src/kudu/rpc/retriable_rpc.h
index 6e19e89..8bca0c4 100644
--- a/src/kudu/rpc/retriable_rpc.h
+++ b/src/kudu/rpc/retriable_rpc.h
@@ -21,6 +21,7 @@
 
 #include <boost/bind.hpp>
 
+#include "kudu/gutil/bind.h"
 #include "kudu/gutil/ref_counted.h"
 #include "kudu/gutil/strings/substitute.h"
 #include "kudu/rpc/messenger.h"
diff --git a/src/kudu/server/tcmalloc_metrics.cc b/src/kudu/server/tcmalloc_metrics.cc
index 15f3eac..0e9f147 100644
--- a/src/kudu/server/tcmalloc_metrics.cc
+++ b/src/kudu/server/tcmalloc_metrics.cc
@@ -19,14 +19,13 @@
 #include <cstddef>
 #include <cstdint>
 #include <ostream>
+#include <utility>
 
 #include <glog/logging.h>
 #ifdef TCMALLOC_ENABLED
 #include <gperftools/malloc_extension.h>
 #endif
 
-#include "kudu/gutil/bind.h"
-#include "kudu/gutil/bind_helpers.h"
 #include "kudu/util/metrics.h"
 
 #ifndef TCMALLOC_ENABLED
@@ -96,23 +95,34 @@ static uint64_t GetTCMallocPropValue(const char* prop) {
 void RegisterMetrics(const scoped_refptr<MetricEntity>& entity) {
   entity->NeverRetire(
       METRIC_generic_current_allocated_bytes.InstantiateFunctionGauge(
-          entity, Bind(GetTCMallocPropValue, Unretained("generic.current_allocated_bytes"))));
+          entity, []() {
+            return GetTCMallocPropValue("generic.current_allocated_bytes");
+          }));
   entity->NeverRetire(
       METRIC_generic_heap_size.InstantiateFunctionGauge(
-          entity, Bind(GetTCMallocPropValue, Unretained("generic.heap_size"))));
+          entity, []() {
+            return GetTCMallocPropValue("generic.heap_size");
+          }));
   entity->NeverRetire(
       METRIC_tcmalloc_pageheap_free_bytes.InstantiateFunctionGauge(
-          entity, Bind(GetTCMallocPropValue, Unretained("tcmalloc.pageheap_free_bytes"))));
+          entity, []() {
+            return GetTCMallocPropValue("tcmalloc.pageheap_free_bytes");
+          }));
   entity->NeverRetire(
       METRIC_tcmalloc_pageheap_unmapped_bytes.InstantiateFunctionGauge(
-          entity, Bind(GetTCMallocPropValue, Unretained("tcmalloc.pageheap_unmapped_bytes"))));
+          entity, []() {
+            return GetTCMallocPropValue("tcmalloc.pageheap_unmapped_bytes");
+          }));
   entity->NeverRetire(
       METRIC_tcmalloc_max_total_thread_cache_bytes.InstantiateFunctionGauge(
-          entity, Bind(GetTCMallocPropValue, Unretained("tcmalloc.max_total_thread_cache_bytes"))));
+          entity, []() {
+            return GetTCMallocPropValue("tcmalloc.max_total_thread_cache_bytes");
+          }));
   entity->NeverRetire(
       METRIC_tcmalloc_current_total_thread_cache_bytes.InstantiateFunctionGauge(
-          entity, Bind(GetTCMallocPropValue,
-                       Unretained("tcmalloc.current_total_thread_cache_bytes"))));
+          entity, []() {
+            return GetTCMallocPropValue("tcmalloc.current_total_thread_cache_bytes");
+          }));
 }
 
 } // namespace tcmalloc
diff --git a/src/kudu/tablet/tablet.cc b/src/kudu/tablet/tablet.cc
index 32541cf..06661f8 100644
--- a/src/kudu/tablet/tablet.cc
+++ b/src/kudu/tablet/tablet.cc
@@ -51,7 +51,6 @@
 #include "kudu/fs/fs_manager.h"
 #include "kudu/fs/io_context.h"
 #include "kudu/gutil/bind.h"
-#include "kudu/gutil/bind_helpers.h"
 #include "kudu/gutil/casts.h"
 #include "kudu/gutil/stl_util.h"
 #include "kudu/gutil/strings/human_readable.h"
@@ -240,20 +239,22 @@ Tablet::Tablet(scoped_refptr<TabletMetadata> metadata,
     metric_entity_ = METRIC_ENTITY_tablet.Instantiate(metric_registry, tablet_id(), attrs);
     metrics_.reset(new TabletMetrics(metric_entity_));
     METRIC_memrowset_size.InstantiateFunctionGauge(
-      metric_entity_, Bind(&Tablet::MemRowSetSize, Unretained(this)))
-      ->AutoDetach(&metric_detacher_);
+        metric_entity_, [this]() { return this->MemRowSetSize(); })
+        ->AutoDetach(&metric_detacher_);
     METRIC_on_disk_data_size.InstantiateFunctionGauge(
-      metric_entity_, Bind(&Tablet::OnDiskDataSize, Unretained(this)))
-      ->AutoDetach(&metric_detacher_);
+        metric_entity_, [this]() { return this->OnDiskDataSize(); })
+        ->AutoDetach(&metric_detacher_);
     METRIC_num_rowsets_on_disk.InstantiateFunctionGauge(
-      metric_entity_, Bind(&Tablet::num_rowsets, Unretained(this)))
-      ->AutoDetach(&metric_detacher_);
+        metric_entity_, [this]() { return this->num_rowsets(); })
+        ->AutoDetach(&metric_detacher_);
     METRIC_last_read_elapsed_time.InstantiateFunctionGauge(
-      metric_entity_, Bind(&Tablet::LastReadElapsedSeconds, Unretained(this)), MergeType::kMin)
-      ->AutoDetach(&metric_detacher_);
+        metric_entity_, [this]() { return this->LastReadElapsedSeconds(); },
+        MergeType::kMin)
+        ->AutoDetach(&metric_detacher_);
     METRIC_last_write_elapsed_time.InstantiateFunctionGauge(
-      metric_entity_, Bind(&Tablet::LastWriteElapsedSeconds, Unretained(this)), MergeType::kMin)
-      ->AutoDetach(&metric_detacher_);
+        metric_entity_, [this]() { return this->LastWriteElapsedSeconds(); },
+        MergeType::kMin)
+        ->AutoDetach(&metric_detacher_);
   }
 
   if (FLAGS_tablet_throttler_rpc_per_sec > 0 || FLAGS_tablet_throttler_bytes_per_sec > 0) {
diff --git a/src/kudu/tablet/tablet_replica-test.cc b/src/kudu/tablet/tablet_replica-test.cc
index e6e9c19..d805735 100644
--- a/src/kudu/tablet/tablet_replica-test.cc
+++ b/src/kudu/tablet/tablet_replica-test.cc
@@ -48,7 +48,6 @@
 #include "kudu/fs/fs_manager.h"
 #include "kudu/gutil/bind.h"
 #include "kudu/gutil/bind_helpers.h"
-#include "kudu/gutil/callback.h"
 #include "kudu/gutil/macros.h"
 #include "kudu/gutil/ref_counted.h"
 #include "kudu/rpc/messenger.h"
@@ -781,8 +780,9 @@ TEST_F(TabletReplicaTest, TestLiveRowCountMetric) {
   ConsensusBootstrapInfo info;
   ASSERT_OK(StartReplicaAndWaitUntilLeader(info));
 
+  // We don't care what the function is, since the metric is already instantiated.
   auto live_row_count = METRIC_live_row_count.InstantiateFunctionGauge(
-      tablet_replica_->tablet()->GetMetricEntity(), Callback<uint64_t(void)>());
+      tablet_replica_->tablet()->GetMetricEntity(), [](){ return 0; });
   ASSERT_EQ(0, live_row_count->value());
 
   // Insert some rows.
diff --git a/src/kudu/tablet/tablet_replica.cc b/src/kudu/tablet/tablet_replica.cc
index a6ed025..ff93e09 100644
--- a/src/kudu/tablet/tablet_replica.cc
+++ b/src/kudu/tablet/tablet_replica.cc
@@ -39,8 +39,6 @@
 #include "kudu/consensus/time_manager.h"
 #include "kudu/fs/data_dirs.h"
 #include "kudu/gutil/basictypes.h"
-#include "kudu/gutil/bind.h"
-#include "kudu/gutil/bind_helpers.h"
 #include "kudu/gutil/port.h"
 #include "kudu/gutil/stl_util.h"
 #include "kudu/gutil/strings/substitute.h"
@@ -208,15 +206,14 @@ Status TabletReplica::Start(const ConsensusBootstrapInfo& bootstrap_info,
         txn_tracker_.StartInstrumentation(tablet_->GetMetricEntity());
 
         METRIC_on_disk_size.InstantiateFunctionGauge(
-            tablet_->GetMetricEntity(), Bind(&TabletReplica::OnDiskSize, Unretained(this)))
+            tablet_->GetMetricEntity(), [this]() { return this->OnDiskSize(); })
             ->AutoDetach(&metric_detacher_);
         METRIC_state.InstantiateFunctionGauge(
-            tablet_->GetMetricEntity(), Bind(&TabletReplica::StateName, Unretained(this)))
+            tablet_->GetMetricEntity(), [this]() { return this->StateName(); })
             ->AutoDetach(&metric_detacher_);
         if (tablet_->metadata()->supports_live_row_count()) {
           METRIC_live_row_count.InstantiateFunctionGauge(
-              tablet_->GetMetricEntity(),
-              Bind(&TabletReplica::CountLiveRowsNoFail, Unretained(this)))
+              tablet_->GetMetricEntity(), [this]() { return this->CountLiveRowsNoFail(); })
               ->AutoDetach(&metric_detacher_);
         } else {
           METRIC_live_row_count.InstantiateInvalid(tablet_->GetMetricEntity(), 0);
diff --git a/src/kudu/tserver/scanners.cc b/src/kudu/tserver/scanners.cc
index a98f251..db46c38 100644
--- a/src/kudu/tserver/scanners.cc
+++ b/src/kudu/tserver/scanners.cc
@@ -29,8 +29,6 @@
 #include "kudu/common/iterator.h"
 #include "kudu/common/scan_spec.h"
 #include "kudu/common/schema.h"
-#include "kudu/gutil/bind.h"
-#include "kudu/gutil/bind_helpers.h"
 #include "kudu/gutil/hash/string_hash.h"
 #include "kudu/gutil/map-util.h"
 #include "kudu/gutil/stl_util.h"
@@ -86,9 +84,8 @@ ScannerManager::ScannerManager(const scoped_refptr<MetricEntity>& metric_entity)
   if (metric_entity) {
     metrics_.reset(new ScannerMetrics(metric_entity));
     METRIC_active_scanners.InstantiateFunctionGauge(
-        metric_entity, Bind(&ScannerManager::CountActiveScanners,
-                               Unretained(this)))
-      ->AutoDetach(&metric_detacher_);
+        metric_entity, [this]() { return this->CountActiveScanners(); })
+        ->AutoDetach(&metric_detacher_);
   }
   for (size_t i = 0; i < kNumScannerMapStripes; i++) {
     scanner_maps_.push_back(new ScannerMapStripe());
diff --git a/src/kudu/tserver/tablet_server-test.cc b/src/kudu/tserver/tablet_server-test.cc
index f49475f..b6afdce 100644
--- a/src/kudu/tserver/tablet_server-test.cc
+++ b/src/kudu/tserver/tablet_server-test.cc
@@ -64,7 +64,6 @@
 #include "kudu/fs/fs.pb.h"
 #include "kudu/fs/fs_manager.h"
 #include "kudu/gutil/basictypes.h"
-#include "kudu/gutil/callback.h"
 #include "kudu/gutil/casts.h"
 #include "kudu/gutil/map-util.h"
 #include "kudu/gutil/port.h"
@@ -1859,7 +1858,7 @@ TEST_F(TabletServerTest, TestReadLatest) {
   ASSERT_TRUE(mini_server_->server()->metric_entity());
   // We don't care what the function is, since the metric is already instantiated.
   auto active_scanners = METRIC_active_scanners.InstantiateFunctionGauge(
-      mini_server_->server()->metric_entity(), Callback<size_t(void)>());
+      mini_server_->server()->metric_entity(), []() {return 0; });
   scoped_refptr<TabletReplica> tablet;
   ASSERT_TRUE(mini_server_->server()->tablet_manager()->LookupTablet(kTabletId, &tablet));
   ASSERT_TRUE(tablet->tablet()->GetMetricEntity());
@@ -3991,7 +3990,7 @@ TEST_F(TabletServerTest, TestTabletNumberOfDiskRowSetsMetric) {
 
   // We don't care what the function is, since the metric is already instantiated.
   auto num_diskrowsets = METRIC_num_rowsets_on_disk.InstantiateFunctionGauge(
-      tablet->tablet()->GetMetricEntity(), Callback<size_t(void)>());
+      tablet->tablet()->GetMetricEntity(), []() { return 0; });
 
   // No data, no diskrowsets.
   ASSERT_EQ(0, num_diskrowsets->value());
diff --git a/src/kudu/tserver/ts_tablet_manager.cc b/src/kudu/tserver/ts_tablet_manager.cc
index 09c33f0..7a1481a 100644
--- a/src/kudu/tserver/ts_tablet_manager.cc
+++ b/src/kudu/tserver/ts_tablet_manager.cc
@@ -261,44 +261,44 @@ TSTabletManager::TSTabletManager(TabletServer* server)
   next_update_time_ = MonoTime::Now();
 
   METRIC_tablets_num_not_initialized.InstantiateFunctionGauge(
-          server->metric_entity(),
-          Bind(&TSTabletManager::RefreshTabletStateCacheAndReturnCount,
-               Unretained(this), tablet::NOT_INITIALIZED))
+      server->metric_entity(), [this]() {
+        return this->RefreshTabletStateCacheAndReturnCount(tablet::NOT_INITIALIZED);
+      })
       ->AutoDetach(&metric_detacher_);
   METRIC_tablets_num_initialized.InstantiateFunctionGauge(
-          server->metric_entity(),
-          Bind(&TSTabletManager::RefreshTabletStateCacheAndReturnCount,
-               Unretained(this), tablet::INITIALIZED))
+      server->metric_entity(), [this]() {
+        return this->RefreshTabletStateCacheAndReturnCount(tablet::INITIALIZED);
+      })
       ->AutoDetach(&metric_detacher_);
   METRIC_tablets_num_bootstrapping.InstantiateFunctionGauge(
-          server->metric_entity(),
-          Bind(&TSTabletManager::RefreshTabletStateCacheAndReturnCount,
-               Unretained(this), tablet::BOOTSTRAPPING))
+      server->metric_entity(), [this]() {
+        return this->RefreshTabletStateCacheAndReturnCount(tablet::BOOTSTRAPPING);
+      })
       ->AutoDetach(&metric_detacher_);
   METRIC_tablets_num_running.InstantiateFunctionGauge(
-          server->metric_entity(),
-          Bind(&TSTabletManager::RefreshTabletStateCacheAndReturnCount,
-               Unretained(this), tablet::RUNNING))
+      server->metric_entity(), [this]() {
+        return this->RefreshTabletStateCacheAndReturnCount(tablet::RUNNING);
+      })
       ->AutoDetach(&metric_detacher_);
   METRIC_tablets_num_failed.InstantiateFunctionGauge(
-          server->metric_entity(),
-          Bind(&TSTabletManager::RefreshTabletStateCacheAndReturnCount,
-               Unretained(this), tablet::FAILED))
+      server->metric_entity(), [this]() {
+        return this->RefreshTabletStateCacheAndReturnCount(tablet::FAILED);
+      })
       ->AutoDetach(&metric_detacher_);
   METRIC_tablets_num_stopping.InstantiateFunctionGauge(
-          server->metric_entity(),
-          Bind(&TSTabletManager::RefreshTabletStateCacheAndReturnCount,
-               Unretained(this), tablet::STOPPING))
+      server->metric_entity(), [this]() {
+        return this->RefreshTabletStateCacheAndReturnCount(tablet::STOPPING);
+      })
       ->AutoDetach(&metric_detacher_);
   METRIC_tablets_num_stopped.InstantiateFunctionGauge(
-          server->metric_entity(),
-          Bind(&TSTabletManager::RefreshTabletStateCacheAndReturnCount,
-               Unretained(this), tablet::STOPPED))
+      server->metric_entity(), [this]() {
+        return this->RefreshTabletStateCacheAndReturnCount(tablet::STOPPED);
+      })
       ->AutoDetach(&metric_detacher_);
   METRIC_tablets_num_shutdown.InstantiateFunctionGauge(
-          server->metric_entity(),
-          Bind(&TSTabletManager::RefreshTabletStateCacheAndReturnCount,
-               Unretained(this), tablet::SHUTDOWN))
+      server->metric_entity(), [this]() {
+        return this->RefreshTabletStateCacheAndReturnCount(tablet::SHUTDOWN);
+      })
       ->AutoDetach(&metric_detacher_);
 }
 
diff --git a/src/kudu/util/metrics-test.cc b/src/kudu/util/metrics-test.cc
index 24ea4d0..b34dbde 100644
--- a/src/kudu/util/metrics-test.cc
+++ b/src/kudu/util/metrics-test.cc
@@ -33,8 +33,6 @@
 #include <gtest/gtest.h>
 #include <rapidjson/document.h>
 
-#include "kudu/gutil/bind.h"
-#include "kudu/gutil/bind_helpers.h"
 #include "kudu/gutil/casts.h"
 #include "kudu/gutil/map-util.h"
 #include "kudu/gutil/ref_counted.h"
@@ -310,7 +308,7 @@ TEST_F(MetricsTest, SimpleFunctionGaugeTest) {
   int metric_val = 1000;
   scoped_refptr<FunctionGauge<int64_t> > gauge =
     METRIC_test_func_gauge.InstantiateFunctionGauge(
-      entity_, Bind(&MyFunction, Unretained(&metric_val)));
+        entity_, [&metric_val]() { return MyFunction(&metric_val); });
 
   ASSERT_EQ(1000, gauge->value());
   ASSERT_EQ(1001, gauge->value());
@@ -331,9 +329,9 @@ METRIC_DEFINE_gauge_int64(test_entity, test_func_gauge_snapshot, "Test Function
 class FunctionGaugeOwner {
  public:
   explicit FunctionGaugeOwner(const scoped_refptr<MetricEntity>& entity) {
-    METRIC_test_func_gauge_snapshot.InstantiateFunctionGauge(entity,
-       Bind(&FunctionGaugeOwner::Count, Unretained(this)))
-       ->AutoDetach(&metric_detacher_);
+    METRIC_test_func_gauge_snapshot.InstantiateFunctionGauge(
+        entity, [this]() { return this->Count(); })
+        ->AutoDetach(&metric_detacher_);
   }
 
   int64_t Count() {
@@ -379,12 +377,14 @@ TEST_F(MetricsTest, SimpleFunctionGaugeMergeTest) {
   int metric_val = 1000;
   scoped_refptr<FunctionGauge<int64_t> > gauge =
     METRIC_test_func_gauge.InstantiateFunctionGauge(
-      entity_, Bind(&MyFunction, Unretained(&metric_val)));
+        entity_, [&metric_val]() { return MyFunction(&metric_val); });
 
   int metric_val_for_merge = 1234;
   scoped_refptr<FunctionGauge<int64_t> > gauge_for_merge =
     METRIC_test_func_gauge.InstantiateFunctionGauge(
-      entity_same_attr_, Bind(&MyFunction, Unretained(&metric_val_for_merge)));
+        entity_same_attr_, [&metric_val_for_merge]() {
+          return MyFunction(&metric_val_for_merge);
+        });
 
   gauge_for_merge->MergeFrom(gauge);
   ASSERT_EQ(1001, gauge->value());
@@ -402,7 +402,7 @@ TEST_F(MetricsTest, AutoDetachToLastValue) {
   int metric_val = 1000;
   scoped_refptr<FunctionGauge<int64_t> > gauge =
     METRIC_test_func_gauge.InstantiateFunctionGauge(
-        entity_, Bind(&MyFunction, Unretained(&metric_val)));
+        entity_, [&metric_val]() { return MyFunction(&metric_val); });
 
   ASSERT_EQ(1000, gauge->value());
   ASSERT_EQ(1001, gauge->value());
@@ -421,7 +421,7 @@ TEST_F(MetricsTest, AutoDetachToConstant) {
   int metric_val = 1000;
   scoped_refptr<FunctionGauge<int64_t> > gauge =
     METRIC_test_func_gauge.InstantiateFunctionGauge(
-        entity_, Bind(&MyFunction, Unretained(&metric_val)));
+        entity_, [&metric_val]() { return MyFunction(&metric_val); });
 
   ASSERT_EQ(1000, gauge->value());
   ASSERT_EQ(1001, gauge->value());
@@ -844,7 +844,7 @@ TEST_F(MetricsTest, TestDontDumpUntouched) {
   scoped_refptr<Histogram> hist = METRIC_test_hist.Instantiate(entity_);
   scoped_refptr<FunctionGauge<int64_t> > function_gauge =
     METRIC_test_func_gauge.InstantiateFunctionGauge(
-        entity_, Bind(&MyFunction, Unretained(&metric_val)));
+        entity_, [&metric_val]() { return MyFunction(&metric_val); });
   scoped_refptr<AtomicGauge<uint64_t> > atomic_gauge =
     METRIC_test_gauge.Instantiate(entity_, 0);
 
diff --git a/src/kudu/util/metrics.cc b/src/kudu/util/metrics.cc
index d250387..f84edab 100644
--- a/src/kudu/util/metrics.cc
+++ b/src/kudu/util/metrics.cc
@@ -650,8 +650,8 @@ FunctionGaugeDetacher::FunctionGaugeDetacher() {
 }
 
 FunctionGaugeDetacher::~FunctionGaugeDetacher() {
-  for (const Closure& c : callbacks_) {
-    c.Run();
+  for (const auto& f : functions_) {
+    f();
   }
 }
 
diff --git a/src/kudu/util/metrics.h b/src/kudu/util/metrics.h
index ff665ae..1ea48a9 100644
--- a/src/kudu/util/metrics.h
+++ b/src/kudu/util/metrics.h
@@ -230,6 +230,7 @@
 #include <cstddef>
 #include <cstdint>
 #include <cstring>
+#include <functional>
 #include <limits>
 #include <memory>
 #include <mutex>
@@ -241,8 +242,6 @@
 
 #include <gtest/gtest_prod.h>
 
-#include "kudu/gutil/bind.h"
-#include "kudu/gutil/callback.h"
 #include "kudu/gutil/casts.h"
 #include "kudu/gutil/macros.h"
 #include "kudu/gutil/map-util.h"
@@ -344,8 +343,6 @@ class Metric;
 class MetricEntity;
 class MetricEntityPrototype;
 class MetricRegistry;
-template <typename Sig>
-class Callback;
 template<typename T>
 class AtomicGauge;
 template<typename T>
@@ -655,9 +652,9 @@ class MetricEntity : public RefCountedThreadSafe<MetricEntity> {
   scoped_refptr<MeanGauge> FindOrCreateMeanGauge(const GaugePrototype<double>* proto);
 
   template<typename T>
-  scoped_refptr<FunctionGauge<T> > FindOrCreateFunctionGauge(const GaugePrototype<T>* proto,
-                                                             const Callback<T()>& function,
-                                                             MergeType type = MergeType::kSum);
+  scoped_refptr<FunctionGauge<T>> FindOrCreateFunctionGauge(const GaugePrototype<T>* proto,
+                                                            std::function<T()> function,
+                                                            MergeType type = MergeType::kSum);
 
   // Return the metric instantiated from the given prototype, or NULL if none has been
   // instantiated. Primarily used by tests trying to read metric values.
@@ -969,9 +966,9 @@ class GaugePrototype : public MetricPrototype {
   // Instantiate a gauge that is backed by the given callback.
   scoped_refptr<FunctionGauge<T> > InstantiateFunctionGauge(
       const scoped_refptr<MetricEntity>& entity,
-      const Callback<T()>& function,
+      std::function<T()> function,
       MergeType type = MergeType::kSum) const {
-    return entity->FindOrCreateFunctionGauge(this, function, type);
+    return entity->FindOrCreateFunctionGauge(this, std::move(function), type);
   }
 
   // Instantiate a "manual" gauge and hide it. It will appear
@@ -1193,11 +1190,11 @@ class FunctionGaugeDetacher {
   template<typename T>
   friend class FunctionGauge;
 
-  void OnDestructor(const Closure& c) {
-    callbacks_.push_back(c);
+  void OnDestructor(std::function<void()> f) {
+    functions_.emplace_back(std::move(f));
   }
 
-  std::vector<Closure> callbacks_;
+  std::vector<std::function<void()>> functions_;
 
   DISALLOW_COPY_AND_ASSIGN(FunctionGaugeDetacher);
 };
@@ -1218,7 +1215,7 @@ class FunctionGauge : public Gauge {
  public:
   scoped_refptr<Metric> snapshot() const override {
     auto p = new FunctionGauge(down_cast<const GaugePrototype<T>*>(prototype_),
-                               Callback<T()>(function_), type_);
+                               function_, type_);
     // The bounded function is associated with another MetricEntity instance, here we don't know
     // when it release, it's not safe to keep the function as a member, so it's needed to
     // call DetachToCurrentValue() to make it safe.
@@ -1231,7 +1228,7 @@ class FunctionGauge : public Gauge {
 
   T value() const {
     std::lock_guard<simple_spinlock> l(lock_);
-    return function_.Run();
+    return function_();
   }
 
   virtual void WriteValue(JsonWriter* writer) const OVERRIDE {
@@ -1243,7 +1240,7 @@ class FunctionGauge : public Gauge {
   // Gauge, use a normal Gauge instead of a FunctionGauge.
   void DetachToConstant(T v) {
     std::lock_guard<simple_spinlock> l(lock_);
-    function_ = Bind(&FunctionGauge::Return, v);
+    function_ = [v]() { return v; };
   }
 
   // Get the current value of the gauge, and detach so that it continues to return this
@@ -1256,8 +1253,8 @@ class FunctionGauge : public Gauge {
   // Automatically detach this gauge when the given 'detacher' destructs.
   // After detaching, the metric will return 'value' in perpetuity.
   void AutoDetach(FunctionGaugeDetacher* detacher, T value = T()) {
-    detacher->OnDestructor(Bind(&FunctionGauge<T>::DetachToConstant,
-                                this, value));
+    scoped_refptr<FunctionGauge<T>> self(this);
+    detacher->OnDestructor([self, value]() { self->DetachToConstant(value); });
   }
 
   // Automatically detach this gauge when the given 'detacher' destructs.
@@ -1270,8 +1267,8 @@ class FunctionGauge : public Gauge {
   // should declare the detacher member after all other class members that might be
   // accessed by the gauge function implementation.
   void AutoDetachToLastValue(FunctionGaugeDetacher* detacher) {
-    detacher->OnDestructor(Bind(&FunctionGauge<T>::DetachToCurrentValue,
-                                this));
+    scoped_refptr<FunctionGauge<T>> self(this);
+    detacher->OnDestructor([self]() { self->DetachToCurrentValue(); });
   }
 
   virtual bool IsUntouched() const override {
@@ -1309,19 +1306,15 @@ class FunctionGauge : public Gauge {
  private:
   friend class MetricEntity;
 
-  FunctionGauge(const GaugePrototype<T>* proto, Callback<T()> function, MergeType type)
+  FunctionGauge(const GaugePrototype<T>* proto, std::function<T()> function, MergeType type)
       : Gauge(proto), function_(std::move(function)), type_(type) {
     // Override the modification epoch to the maximum, since we don't have any idea
     // when the bound function changes value.
     m_epoch_ = std::numeric_limits<decltype(m_epoch_.load())>::max();
   }
 
-  static T Return(T v) {
-    return v;
-  }
-
   mutable simple_spinlock lock_;
-  Callback<T()> function_;
+  std::function<T()> function_;
   MergeType type_;
 
   DISALLOW_COPY_AND_ASSIGN(FunctionGauge);
@@ -1548,14 +1541,14 @@ inline scoped_refptr<MeanGauge> MetricEntity::FindOrCreateMeanGauge(
 template<typename T>
 inline scoped_refptr<FunctionGauge<T> > MetricEntity::FindOrCreateFunctionGauge(
     const GaugePrototype<T>* proto,
-    const Callback<T()>& function,
+    std::function<T()> function,
     MergeType type) {
   CheckInstantiation(proto);
   std::lock_guard<simple_spinlock> l(lock_);
   scoped_refptr<FunctionGauge<T> > m = down_cast<FunctionGauge<T>*>(
       FindPtrOrNull(metric_map_, proto).get());
   if (!m) {
-    m = new FunctionGauge<T>(proto, function, type);
+    m = new FunctionGauge<T>(proto, std::move(function), type);
     InsertOrDie(&metric_map_, proto, m);
   }
   return m;
diff --git a/src/kudu/util/net/dns_resolver.cc b/src/kudu/util/net/dns_resolver.cc
index 2e22073..b3ba1ed 100644
--- a/src/kudu/util/net/dns_resolver.cc
+++ b/src/kudu/util/net/dns_resolver.cc
@@ -24,6 +24,7 @@
 #include <gflags/gflags.h>
 #include <glog/logging.h>
 
+#include "kudu/gutil/callback.h" // IWYU pragma: keep
 #include "kudu/gutil/port.h"
 #include "kudu/util/flag_tags.h"
 #include "kudu/util/malloc.h"
diff --git a/src/kudu/util/spinlock_profiling.cc b/src/kudu/util/spinlock_profiling.cc
index e665f87..ca1437a 100644
--- a/src/kudu/util/spinlock_profiling.cc
+++ b/src/kudu/util/spinlock_profiling.cc
@@ -24,7 +24,6 @@
 #include <gflags/gflags.h>
 
 #include "kudu/gutil/atomicops.h"
-#include "kudu/gutil/bind.h"
 #include "kudu/gutil/casts.h"
 #include "kudu/gutil/macros.h"
 #include "kudu/gutil/once.h"
@@ -273,7 +272,7 @@ void RegisterSpinLockContentionMetrics(const scoped_refptr<MetricEntity>& entity
   InitSpinLockContentionProfiling();
   entity->NeverRetire(
       METRIC_spinlock_contention_time.InstantiateFunctionGauge(
-          entity, Bind(&GetSpinLockContentionMicros)));
+          entity, []() { return GetSpinLockContentionMicros(); }));
 }
 
 uint64_t GetSpinLockContentionMicros() {
diff --git a/src/kudu/util/thread.cc b/src/kudu/util/thread.cc
index 2fab076..24301c9 100644
--- a/src/kudu/util/thread.cc
+++ b/src/kudu/util/thread.cc
@@ -41,8 +41,6 @@
 #include <glog/logging.h>
 
 #include "kudu/gutil/atomicops.h"
-#include "kudu/gutil/bind.h"
-#include "kudu/gutil/bind_helpers.h"
 #include "kudu/gutil/dynamic_annotations.h"
 #include "kudu/gutil/map-util.h"
 #include "kudu/gutil/mathlimits.h"
@@ -286,23 +284,23 @@ Status ThreadMgr::StartInstrumentation(const scoped_refptr<MetricEntity>& metric
   // Use function gauges here so that we can register a unique copy of these metrics in
   // multiple tservers, even though the ThreadMgr is itself a singleton.
   metrics->NeverRetire(
-      METRIC_threads_started.InstantiateFunctionGauge(metrics,
-        Bind(&ThreadMgr::ReadThreadsStarted, Unretained(this))));
+      METRIC_threads_started.InstantiateFunctionGauge(
+          metrics, [this]() { return this->ReadThreadsStarted(); }));
   metrics->NeverRetire(
-      METRIC_threads_running.InstantiateFunctionGauge(metrics,
-        Bind(&ThreadMgr::ReadThreadsRunning, Unretained(this))));
+      METRIC_threads_running.InstantiateFunctionGauge(
+          metrics, [this]() { return this->ReadThreadsRunning(); }));
   metrics->NeverRetire(
-      METRIC_cpu_utime.InstantiateFunctionGauge(metrics,
-        Bind(&GetCpuUTime)));
+      METRIC_cpu_utime.InstantiateFunctionGauge(
+          metrics, []() { return GetCpuUTime(); }));
   metrics->NeverRetire(
-      METRIC_cpu_stime.InstantiateFunctionGauge(metrics,
-        Bind(&GetCpuSTime)));
+      METRIC_cpu_stime.InstantiateFunctionGauge(
+          metrics, []() { return GetCpuSTime(); }));
   metrics->NeverRetire(
-      METRIC_voluntary_context_switches.InstantiateFunctionGauge(metrics,
-        Bind(&GetVoluntaryContextSwitches)));
+      METRIC_voluntary_context_switches.InstantiateFunctionGauge(
+          metrics, []() { return GetVoluntaryContextSwitches(); }));
   metrics->NeverRetire(
-      METRIC_involuntary_context_switches.InstantiateFunctionGauge(metrics,
-        Bind(&GetInVoluntaryContextSwitches)));
+      METRIC_involuntary_context_switches.InstantiateFunctionGauge(
+          metrics, []() { return GetInVoluntaryContextSwitches(); }));
 
   if (web) {
     DCHECK_NOTNULL(web)->RegisterPathHandler(