You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kudu.apache.org by al...@apache.org on 2020/11/04 05:36:19 UTC

[kudu] branch master updated (f9f3189 -> dbbc488)

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

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


    from f9f3189  KUDU-3210 Add lock before verifying signature
     new 62ec1e4  [client] KUDU-2966 configure connection negotiation timeout
     new 1a22d50  [test] shorter timeouts for client-negotiation-failover
     new dbbc488  [server] fix compilation under RHEL/CentOS 6

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 CMakeLists.txt                                     |  1 +
 src/kudu/client/client-internal.cc                 | 56 ++++++++++----------
 src/kudu/client/client-internal.h                  |  1 +
 src/kudu/client/client-test.cc                     | 36 +++++++++++++
 src/kudu/client/client.cc                          | 16 ++++++
 src/kudu/client/client.h                           | 20 ++++++++
 src/kudu/client/client_builder-internal.h          |  6 +--
 .../client-negotiation-failover-itest.cc           | 59 ++++++++++++----------
 src/kudu/rpc/messenger.cc                          |  4 +-
 src/kudu/rpc/messenger.h                           |  6 ++-
 src/kudu/security/openssl_util.cc                  |  3 ++
 src/kudu/server/webserver-test.cc                  |  4 ++
 src/kudu/server/webserver.cc                       |  4 ++
 13 files changed, 154 insertions(+), 62 deletions(-)


[kudu] 02/03: [test] shorter timeouts for client-negotiation-failover

Posted by al...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 1a22d50fdd7018ed7d277a229cfd26c90451d68d
Author: Alexey Serbin <al...@apache.org>
AuthorDate: Fri Oct 30 20:12:54 2020 -0700

    [test] shorter timeouts for client-negotiation-failover
    
    It's now possible to configure connection negotiation timeout in Kudu
    C++ client (see KUDU-2966), and this patch uses the newly introduced
    functionality to set shorter negotiation timeouts for all scenarios in
    client-negotiation-failover-itest.  Doing so reduces the time spent
    running the test.  Below are the results from the binary built in DEBUG
    mode:
    
      KUDU_ALLOW_SLOW_TESTS=1 ./bin/client-negotiation-failover-itest
    
    Before:
      [==========] 4 tests from 1 test case ran. (84445 ms total)
      [  PASSED  ] 4 tests.
    
    After:
      [==========] 4 tests from 1 test case ran. (46295 ms total)
      [  PASSED  ] 4 tests.
    
    Change-Id: Iabf7b6218b39c4348f87822218c3320949778cf9
    Reviewed-on: http://gerrit.cloudera.org:8080/16692
    Tested-by: Kudu Jenkins
    Reviewed-by: Andrew Wong <aw...@cloudera.com>
---
 .../client-negotiation-failover-itest.cc           | 59 ++++++++++++----------
 1 file changed, 31 insertions(+), 28 deletions(-)

diff --git a/src/kudu/integration-tests/client-negotiation-failover-itest.cc b/src/kudu/integration-tests/client-negotiation-failover-itest.cc
index 68ed99d..7b80bba 100644
--- a/src/kudu/integration-tests/client-negotiation-failover-itest.cc
+++ b/src/kudu/integration-tests/client-negotiation-failover-itest.cc
@@ -77,16 +77,6 @@ class ClientFailoverOnNegotiationTimeoutITest : public KuduTest {
     // let's make the client re-establishing connections on every RPC.
     FLAGS_rpc_reopen_outbound_connections = true;
 
-    // Set the connection negotiation timeout shorter than its default value
-    // to run the test faster. For sanitizer builds we don't want the timeout
-    // to be too short: running the test concurrently with other activities
-    // might lead client to fail even if the client retries again and again.
-#if defined(THREAD_SANITIZER) || defined(ADDRESS_SANITIZER)
-    FLAGS_rpc_negotiation_timeout_ms = 3000;
-#else
-    FLAGS_rpc_negotiation_timeout_ms = 1000;
-#endif
-
     cluster_opts_.extra_tserver_flags = {
         // Speed up Raft elections.
         "--raft_heartbeat_interval_ms=25",
@@ -106,13 +96,37 @@ class ClientFailoverOnNegotiationTimeoutITest : public KuduTest {
     return cluster_->Start();
   }
 
+  shared_ptr<KuduClient> CreateClient(
+      const MonoDelta& rpc_timeout,
+      const MonoDelta& negotiation_timeout = {}) {
+    KuduClientBuilder b;
+    b.default_admin_operation_timeout(rpc_timeout);
+    b.default_rpc_timeout(rpc_timeout);
+    if (negotiation_timeout.Initialized()) {
+      b.connection_negotiation_timeout(negotiation_timeout);
+    }
+    shared_ptr<KuduClient> client;
+    CHECK_OK(cluster_->CreateClient(&b, &client));
+    return client;
+  }
+
   void TearDown() override {
     if (cluster_) {
       cluster_->Shutdown();
     }
     KuduTest::TearDown();
   }
+
  protected:
+  // Set the connection negotiation timeout shorter than its default value
+  // to run the test faster. For sanitizer builds we don't want the timeout
+  // to be too short: running the test concurrently with other activities
+  // might lead client to fail even if the client retries again and again.
+#if defined(THREAD_SANITIZER) || defined(ADDRESS_SANITIZER)
+  const MonoDelta kNegotiationTimeout = MonoDelta::FromMilliseconds(3000);
+#else
+  const MonoDelta kNegotiationTimeout = MonoDelta::FromMilliseconds(500);
+#endif
   ExternalMiniClusterOptions cluster_opts_;
   shared_ptr<ExternalMiniCluster> cluster_;
 };
@@ -132,12 +146,9 @@ TEST_F(ClientFailoverOnNegotiationTimeoutITest, Kudu1580ConnectToTServer) {
   cluster_opts_.num_tablet_servers = kNumTabletServers;
   ASSERT_OK(CreateAndStartCluster());
 
-  shared_ptr<KuduClient> client;
-  ASSERT_OK(cluster_->CreateClient(
-      &KuduClientBuilder()
-          .default_admin_operation_timeout(MonoDelta::FromMilliseconds(kTimeoutMs))
-          .default_rpc_timeout(MonoDelta::FromMilliseconds(kTimeoutMs)),
-      &client));
+  shared_ptr<KuduClient> client = CreateClient(
+      MonoDelta::FromMilliseconds(kTimeoutMs), kNegotiationTimeout);
+  ASSERT_NE(nullptr, client.get());
   unique_ptr<KuduTableCreator> table_creator(client->NewTableCreator());
   KuduSchema schema(KuduSchema::FromSchema(CreateKeyValueTestSchema()));
   ASSERT_OK(table_creator->table_name(kTableName)
@@ -240,12 +251,8 @@ TEST_F(ClientFailoverOnNegotiationTimeoutITest, Kudu2021ConnectToMaster) {
   cluster_opts_.num_tablet_servers = 1;
   ASSERT_OK(CreateAndStartCluster());
 
-  shared_ptr<KuduClient> client;
-  ASSERT_OK(cluster_->CreateClient(
-      &KuduClientBuilder()
-          .default_admin_operation_timeout(kTimeout)
-          .default_rpc_timeout(kTimeout),
-      &client));
+  shared_ptr<KuduClient> client = CreateClient(kTimeout, kNegotiationTimeout);
+  ASSERT_NE(nullptr, client.get());
 
   // Make a call to the master to populate the client's metadata cache.
   vector<string> tables;
@@ -274,12 +281,8 @@ TEST_F(ClientFailoverOnNegotiationTimeoutITest, Kudu2021NegotiateWithMaster) {
   cluster_opts_.num_tablet_servers = 1;
   ASSERT_OK(CreateAndStartCluster());
 
-  shared_ptr<KuduClient> client;
-  ASSERT_OK(cluster_->CreateClient(
-      &KuduClientBuilder()
-          .default_admin_operation_timeout(kTimeout)
-          .default_rpc_timeout(kTimeout),
-      &client));
+  shared_ptr<KuduClient> client = CreateClient(kTimeout, kNegotiationTimeout);
+  ASSERT_NE(nullptr, client.get());
 
   // Check client can successfully call ListTables().
   vector<string> tables;


[kudu] 03/03: [server] fix compilation under RHEL/CentOS 6

Posted by al...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit dbbc48893a743bb5d96a7b17007450f1a94463cb
Author: Alexey Serbin <al...@apache.org>
AuthorDate: Tue Nov 3 18:39:18 2020 -0800

    [server] fix compilation under RHEL/CentOS 6
    
    It seems the version of the OpenSSL library used to work around
    versioned symbols in RHEL/CentOS 6.5+ doesn't contain declaration
    of FIPS_mode() function in openssl/crypto.h file.  That breaks the
    compilation after the introduction of the two changelist mentioned
    below.  This patch fixes the compilation breakage, adding
    openssl/fips.h header file when necessary.
    
    This is a follow-up to changelists 46231c52f and 6d2c79a4f.
    
    Change-Id: I3714365801f7de4e4768f4c4e2cf063ff5a65c57
    Reviewed-on: http://gerrit.cloudera.org:8080/16696
    Reviewed-by: Andrew Wong <aw...@cloudera.com>
    Tested-by: Kudu Jenkins
---
 CMakeLists.txt                    | 1 +
 src/kudu/security/openssl_util.cc | 3 +++
 src/kudu/server/webserver-test.cc | 4 ++++
 src/kudu/server/webserver.cc      | 4 ++++
 4 files changed, 12 insertions(+)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4b5dcbd..5a3b607 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1067,6 +1067,7 @@ ADD_THIRDPARTY_LIB(mustache
 set(CENTOS_6_4_OPENSSL_DIR "${THIRDPARTY_INSTALL_DIR}/openssl-el6-workaround/usr/")
 if (NOT OPENSSL_ROOT_DIR AND EXISTS "${CENTOS_6_4_OPENSSL_DIR}")
   set(OPENSSL_ROOT_DIR "${CENTOS_6_4_OPENSSL_DIR}")
+  add_definitions("-DKUDU_OPENSSL_REQUIRE_FIPS_HEADER")
 endif()
 find_package(OpenSSL 1.0.0 REQUIRED)
 include_directories(SYSTEM ${OPENSSL_INCLUDE_DIR})
diff --git a/src/kudu/security/openssl_util.cc b/src/kudu/security/openssl_util.cc
index 7198db3..3604964 100644
--- a/src/kudu/security/openssl_util.cc
+++ b/src/kudu/security/openssl_util.cc
@@ -18,6 +18,9 @@
 #include "kudu/security/openssl_util.h"
 
 #include <openssl/crypto.h>
+#if defined(KUDU_OPENSSL_REQUIRE_FIPS_HEADER)
+#include <openssl/fips.h>
+#endif
 #include <openssl/err.h>
 #include <openssl/rand.h> // IWYU pragma: keep
 
diff --git a/src/kudu/server/webserver-test.cc b/src/kudu/server/webserver-test.cc
index 652b9a6..942bad8 100644
--- a/src/kudu/server/webserver-test.cc
+++ b/src/kudu/server/webserver-test.cc
@@ -17,7 +17,11 @@
 
 #include "kudu/server/webserver.h"
 
+#if defined(KUDU_OPENSSL_REQUIRE_FIPS_HEADER)
+#include <openssl/fips.h>
+#else
 #include <openssl/crypto.h>
+#endif
 
 #include <cstdlib>
 #include <functional>
diff --git a/src/kudu/server/webserver.cc b/src/kudu/server/webserver.cc
index 420984f..9e7202d 100644
--- a/src/kudu/server/webserver.cc
+++ b/src/kudu/server/webserver.cc
@@ -18,7 +18,11 @@
 #include "kudu/server/webserver.h"
 
 #include <netinet/in.h>
+#if defined(KUDU_OPENSSL_REQUIRE_FIPS_HEADER)
+#include <openssl/fips.h>
+#else
 #include <openssl/crypto.h>
+#endif
 #include <sys/socket.h>
 
 #include <algorithm>


[kudu] 01/03: [client] KUDU-2966 configure connection negotiation timeout

Posted by al...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 62ec1e474167d79de298cd14d9e1b975bcdbdd8a
Author: Alexey Serbin <al...@apache.org>
AuthorDate: Sat Oct 31 00:48:48 2020 -0700

    [client] KUDU-2966 configure connection negotiation timeout
    
    This patch addresses KUDU-2966 for the Kudu C++ client, making
    the timeout for the connection negotiation configurable.  This patch
    also contains a unit test for the newly introduced functionality.
    
    As for the motivation for this patch: we have observed a few clusters
    in the wild where connection negotiations were a bit slow when servers
    are under heavy load.  It would be nice to control the connection
    negotiation timeout at the client side as well, so at least kudu CLI
    tool could use this functionality.
    
    The newly introduced functionality is to be used at least in kudu CLI
    (will be posted in a separate follow-up patch).
    
    Change-Id: I8573a572887be041637e28e518a7cd3a6d1f1693
    Reviewed-on: http://gerrit.cloudera.org:8080/16687
    Tested-by: Alexey Serbin <as...@cloudera.com>
    Reviewed-by: Andrew Wong <aw...@cloudera.com>
---
 src/kudu/client/client-internal.cc        | 56 +++++++++++++++----------------
 src/kudu/client/client-internal.h         |  1 +
 src/kudu/client/client-test.cc            | 36 ++++++++++++++++++++
 src/kudu/client/client.cc                 | 16 +++++++++
 src/kudu/client/client.h                  | 20 +++++++++++
 src/kudu/client/client_builder-internal.h |  6 ++--
 src/kudu/rpc/messenger.cc                 |  4 ++-
 src/kudu/rpc/messenger.h                  |  6 +++-
 8 files changed, 111 insertions(+), 34 deletions(-)

diff --git a/src/kudu/client/client-internal.cc b/src/kudu/client/client-internal.cc
index 1f23ccd..26fd9c9 100644
--- a/src/kudu/client/client-internal.cc
+++ b/src/kudu/client/client-internal.cc
@@ -73,7 +73,34 @@ DECLARE_int32(dns_resolver_max_threads_num);
 DECLARE_uint32(dns_resolver_cache_capacity_mb);
 DECLARE_uint32(dns_resolver_cache_ttl_sec);
 
+
 using boost::container::small_vector;
+using kudu::client::internal::AsyncLeaderMasterRpc;
+using kudu::client::internal::ConnectToClusterRpc;
+using kudu::client::internal::RemoteTablet;
+using kudu::client::internal::RemoteTabletServer;
+using kudu::master::AlterTableRequestPB;
+using kudu::master::AlterTableResponsePB;
+using kudu::master::ConnectToMasterResponsePB;
+using kudu::master::CreateTableRequestPB;
+using kudu::master::CreateTableResponsePB;
+using kudu::master::DeleteTableRequestPB;
+using kudu::master::DeleteTableResponsePB;
+using kudu::master::GetTableSchemaRequestPB;
+using kudu::master::GetTableSchemaResponsePB;
+using kudu::master::IsAlterTableDoneRequestPB;
+using kudu::master::IsAlterTableDoneResponsePB;
+using kudu::master::IsCreateTableDoneRequestPB;
+using kudu::master::IsCreateTableDoneResponsePB;
+using kudu::master::ListTabletServersRequestPB;
+using kudu::master::ListTabletServersResponsePB;
+using kudu::master::MasterFeatures;
+using kudu::master::MasterServiceProxy;
+using kudu::master::TableIdentifierPB;
+using kudu::rpc::BackoffType;
+using kudu::rpc::CredentialsPolicy;
+using kudu::rpc::MessengerBuilder;
+using kudu::security::SignedTokenPB;
 using std::map;
 using std::pair;
 using std::set;
@@ -81,6 +108,7 @@ using std::shared_ptr;
 using std::string;
 using std::unique_ptr;
 using std::vector;
+using strings::Substitute;
 
 namespace kudu {
 
@@ -88,36 +116,8 @@ namespace security {
 class SignedTokenPB;
 } // namespace security
 
-using master::AlterTableRequestPB;
-using master::AlterTableResponsePB;
-using master::ConnectToMasterResponsePB;
-using master::CreateTableRequestPB;
-using master::CreateTableResponsePB;
-using master::DeleteTableRequestPB;
-using master::DeleteTableResponsePB;
-using master::GetTableSchemaRequestPB;
-using master::GetTableSchemaResponsePB;
-using master::IsAlterTableDoneRequestPB;
-using master::IsAlterTableDoneResponsePB;
-using master::IsCreateTableDoneRequestPB;
-using master::IsCreateTableDoneResponsePB;
-using master::ListTabletServersResponsePB;
-using master::ListTabletServersRequestPB;
-using master::MasterFeatures;
-using master::MasterServiceProxy;
-using master::TableIdentifierPB;
-using rpc::BackoffType;
-using rpc::CredentialsPolicy;
-using security::SignedTokenPB;
-using strings::Substitute;
-
 namespace client {
 
-using internal::AsyncLeaderMasterRpc;
-using internal::ConnectToClusterRpc;
-using internal::RemoteTablet;
-using internal::RemoteTabletServer;
-
 Status RetryFunc(const MonoTime& deadline,
                  const string& retry_msg,
                  const string& timeout_msg,
diff --git a/src/kudu/client/client-internal.h b/src/kudu/client/client-internal.h
index 3adeb62..dc7dade 100644
--- a/src/kudu/client/client-internal.h
+++ b/src/kudu/client/client-internal.h
@@ -279,6 +279,7 @@ class KuduClient::Data {
   std::vector<std::string> master_server_addrs_;
   MonoDelta default_admin_operation_timeout_;
   MonoDelta default_rpc_timeout_;
+  MonoDelta connection_negotiation_timeout_;
 
   // The host port of the leader master. This is set in
   // ConnectedToClusterCb, which is invoked as a callback by
diff --git a/src/kudu/client/client-test.cc b/src/kudu/client/client-test.cc
index 4445a49..6849c6a 100644
--- a/src/kudu/client/client-test.cc
+++ b/src/kudu/client/client-test.cc
@@ -183,6 +183,7 @@ using kudu::itest::GetClusterId;
 using kudu::master::CatalogManager;
 using kudu::master::GetTableLocationsRequestPB;
 using kudu::master::GetTableLocationsResponsePB;
+using kudu::rpc::MessengerBuilder;
 using kudu::security::SignedTokenPB;
 using kudu::client::sp::shared_ptr;
 using kudu::tablet::TabletReplica;
@@ -884,6 +885,41 @@ TEST_F(ClientTest, ConnectToClusterNoMasterAddressSpecified) {
   ASSERT_STR_CONTAINS(s.ToString(), "no master address specified");
 }
 
+// Verify setting of the connection negotiation timeout (KUDU-2966).
+TEST_F(ClientTest, ConnectionNegotiationTimeout) {
+  const auto master_addr = cluster_->mini_master()->bound_rpc_addr().ToString();
+
+  // The connection negotiation timeout isn't set explicitly: it should be
+  // equal to the default setting for the RPC messenger.
+  {
+    KuduClientBuilder b;
+    b.add_master_server_addr(master_addr);
+    shared_ptr<KuduClient> c;
+    ASSERT_OK(b.Build(&c));
+    auto t = c->connection_negotiation_timeout();
+    ASSERT_TRUE(t.Initialized());
+    ASSERT_EQ(MessengerBuilder::kRpcNegotiationTimeoutMs, t.ToMilliseconds());
+    auto t_ms = c->data_->messenger_->rpc_negotiation_timeout_ms();
+    ASSERT_EQ(t_ms, t.ToMilliseconds());
+  }
+
+  // The connection negotiation timeout is set explicitly via KuduBuilder. It
+  // should be propagated to the RPC messenger and reported back correspondingly
+  // by the KuduClient::connection_negotiaton_timeout() method.
+  {
+    const MonoDelta kNegotiationTimeout = MonoDelta::FromMilliseconds(12321);
+    KuduClientBuilder b;
+    b.add_master_server_addr(master_addr);
+    b.connection_negotiation_timeout(kNegotiationTimeout);
+    shared_ptr<KuduClient> c;
+    ASSERT_OK(b.Build(&c));
+    auto t = c->connection_negotiation_timeout();
+    ASSERT_EQ(kNegotiationTimeout, t);
+    auto t_ms = c->data_->messenger_->rpc_negotiation_timeout_ms();
+    ASSERT_EQ(t_ms, t.ToMilliseconds());
+  }
+}
+
 // Test that, if the master is down, we experience a network error talking
 // to it (no "find the new leader master" since there's only one master).
 TEST_F(ClientTest, TestMasterDown) {
diff --git a/src/kudu/client/client.cc b/src/kudu/client/client.cc
index 181db49..ebc4fc1 100644
--- a/src/kudu/client/client.cc
+++ b/src/kudu/client/client.cc
@@ -304,6 +304,12 @@ KuduClientBuilder& KuduClientBuilder::default_rpc_timeout(const MonoDelta& timeo
   return *this;
 }
 
+KuduClientBuilder& KuduClientBuilder::connection_negotiation_timeout(
+    const MonoDelta& timeout) {
+  data_->connection_negotiation_timeout_ = timeout;
+  return *this;
+}
+
 KuduClientBuilder& KuduClientBuilder::import_authentication_credentials(string authn_creds) {
   data_->authn_creds_ = std::move(authn_creds);
   return *this;
@@ -350,6 +356,10 @@ Status KuduClientBuilder::Build(shared_ptr<KuduClient>* client) {
 
   // Init messenger.
   MessengerBuilder builder("client");
+  if (data_->connection_negotiation_timeout_.Initialized()) {
+    builder.set_rpc_negotiation_timeout_ms(
+        data_->connection_negotiation_timeout_.ToMilliseconds());
+  }
   if (data_->num_reactors_) {
     builder.set_num_reactors(data_->num_reactors_.get());
   }
@@ -632,6 +642,12 @@ const MonoDelta& KuduClient::default_rpc_timeout() const {
   return data_->default_rpc_timeout_;
 }
 
+MonoDelta KuduClient::connection_negotiation_timeout() const {
+  DCHECK(data_->messenger_);
+  return MonoDelta::FromMilliseconds(
+      data_->messenger_->rpc_negotiation_timeout_ms());
+}
+
 const uint64_t KuduClient::kNoTimestamp = 0;
 
 uint64_t KuduClient::GetLatestObservedTimestamp() const {
diff --git a/src/kudu/client/client.h b/src/kudu/client/client.h
index 16193d3..5001543 100644
--- a/src/kudu/client/client.h
+++ b/src/kudu/client/client.h
@@ -263,6 +263,22 @@ class KUDU_EXPORT KuduClientBuilder {
   /// @return Reference to the updated object.
   KuduClientBuilder& default_rpc_timeout(const MonoDelta& timeout);
 
+  /// Set the timeout for negotiating a connection to a remote server.
+  ///
+  /// If not provided, the underlying messenger is created with reasonable
+  /// default. The result value could be retrieved using
+  /// @c KuduClient.connection_negotiation_timeout() after an instance of
+  /// @c KuduClient is created. Sometimes it makes sense to customize the
+  /// timeout for connection negotiation, e.g. when running on a cluster with
+  /// heavily loaded tablet servers. For details on the connection negotiation,
+  /// see ../../../docs/design-docs/rpc.md#negotiation.
+  ///
+  /// @param [in] timeout
+  ///   Timeout value to set.
+  /// @return Reference to the updated object.
+  KuduClientBuilder& connection_negotiation_timeout(const MonoDelta& timeout);
+
+
   /// Import serialized authentication credentials from another client.
   ///
   /// @param [in] authn_creds
@@ -518,6 +534,9 @@ class KUDU_EXPORT KuduClient : public sp::enable_shared_from_this<KuduClient> {
   /// @return Default timeout for RPCs.
   const MonoDelta& default_rpc_timeout() const;
 
+  /// @return Timeout for connection negotiation to a remote server.
+  MonoDelta connection_negotiation_timeout() const;
+
   /// Value for the latest observed timestamp when none has been observed
   /// or set.
   static const uint64_t kNoTimestamp;
@@ -637,6 +656,7 @@ class KUDU_EXPORT KuduClient : public sp::enable_shared_from_this<KuduClient> {
   friend class tools::RemoteKsckCluster;
 
   FRIEND_TEST(kudu::ClientStressTest, TestUniqueClientIds);
+  FRIEND_TEST(ClientTest, ConnectionNegotiationTimeout);
   FRIEND_TEST(ClientTest, TestCacheAuthzTokens);
   FRIEND_TEST(ClientTest, TestGetSecurityInfoFromMaster);
   FRIEND_TEST(ClientTest, TestGetTabletServerBlacklist);
diff --git a/src/kudu/client/client_builder-internal.h b/src/kudu/client/client_builder-internal.h
index 329c41f..f30cc7b 100644
--- a/src/kudu/client/client_builder-internal.h
+++ b/src/kudu/client/client_builder-internal.h
@@ -14,8 +14,7 @@
 // KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License.
-#ifndef KUDU_CLIENT_CLIENT_BUILDER_INTERNAL_H
-#define KUDU_CLIENT_CLIENT_BUILDER_INTERNAL_H
+#pragma once
 
 #include <string>
 #include <vector>
@@ -39,6 +38,7 @@ class KuduClientBuilder::Data {
   std::vector<std::string> master_server_addrs_;
   MonoDelta default_admin_operation_timeout_;
   MonoDelta default_rpc_timeout_;
+  MonoDelta connection_negotiation_timeout_;
   std::string authn_creds_;
   internal::ReplicaController::Visibility replica_visibility_;
   boost::optional<int> num_reactors_;
@@ -48,5 +48,3 @@ class KuduClientBuilder::Data {
 
 } // namespace client
 } // namespace kudu
-
-#endif
diff --git a/src/kudu/rpc/messenger.cc b/src/kudu/rpc/messenger.cc
index c000303..784188f 100644
--- a/src/kudu/rpc/messenger.cc
+++ b/src/kudu/rpc/messenger.cc
@@ -62,6 +62,8 @@ using strings::Substitute;
 namespace kudu {
 namespace rpc {
 
+const int64_t MessengerBuilder::kRpcNegotiationTimeoutMs = 3000;
+
 MessengerBuilder::MessengerBuilder(std::string name)
     : name_(std::move(name)),
       connection_keepalive_time_(MonoDelta::FromMilliseconds(65000)),
@@ -69,7 +71,7 @@ MessengerBuilder::MessengerBuilder(std::string name)
       min_negotiation_threads_(0),
       max_negotiation_threads_(4),
       coarse_timer_granularity_(MonoDelta::FromMilliseconds(100)),
-      rpc_negotiation_timeout_ms_(3000),
+      rpc_negotiation_timeout_ms_(kRpcNegotiationTimeoutMs),
       sasl_proto_name_("kudu"),
       rpc_authentication_("optional"),
       rpc_encryption_("optional"),
diff --git a/src/kudu/rpc/messenger.h b/src/kudu/rpc/messenger.h
index 2cb1ecd..10b94f8 100644
--- a/src/kudu/rpc/messenger.h
+++ b/src/kudu/rpc/messenger.h
@@ -82,6 +82,8 @@ class MessengerBuilder {
   friend class Messenger;
   friend class ReactorThread;
 
+  static const int64_t kRpcNegotiationTimeoutMs;
+
   explicit MessengerBuilder(std::string name);
 
   // Set the length of time we will keep a TCP connection will alive with no traffic.
@@ -308,7 +310,9 @@ class Messenger {
 
   scoped_refptr<MetricEntity> metric_entity() const { return metric_entity_; }
 
-  const int64_t rpc_negotiation_timeout_ms() const { return rpc_negotiation_timeout_ms_; }
+  int64_t rpc_negotiation_timeout_ms() const {
+    return rpc_negotiation_timeout_ms_;
+  }
 
   const std::string& sasl_proto_name() const {
     return sasl_proto_name_;