Skip to content

Commit

Permalink
Replace std::unordered_map/set with absl containers (envoyproxy#11879)
Browse files Browse the repository at this point in the history
- Replace with absl::node_hash_map/set
  - Primarily for performance optimizations and to root out any
     assumptions made about iteration order in tests or otherwise (the
     replacement absl containers have a non-deterministic iteration
     order
  - absl::node_hash_map/set should be drop-in replacements for
     std::unordered_map/set
- Note that a future refactor should reevaluate and move to
   absl::flat_hash_map/set where possible for memory optimizations
- Add format check to disallow future usage of std::unordered_map/set
- Small changes made where absl containers required it or tests needed
   to be modified for correctness

Additional Description:
- There may be an issue we should open with abseil about `emplace` and `try_emplace` when attempting to do in-place construction
  - When a constructor throws an exception, as far as I can tell the c++ language standard says the container should not be affected, however this does not seem to be the case for the absl containers so their guarantees are not the same (though they may be intended to have the same guarantees)
  - //test/server:overload_manager_impl_test demonstrates this
  - see abseil/abseil-cpp#388

Risk Level: Low, absl::node_hash_map/set should be drop-in replacements for std::unordered_map/set though this may shake loose more assumptions in tests over time we weren't able to catch locally
Testing: Small changes to unit tests, repeatedly run on Windows and Linux/clang
Docs Changes: N/A
Release Notes: N/A
Fixes envoyproxy#11825

Signed-off-by: Sunjay Bhatia <[email protected]>
Co-authored-by: William A Rowe Jr <[email protected]>
  • Loading branch information
sunjayBhatia and wrowe authored Jul 28, 2020
1 parent 8f668e9 commit cf2df8c
Show file tree
Hide file tree
Showing 174 changed files with 494 additions and 442 deletions.
2 changes: 0 additions & 2 deletions include/envoy/grpc/status.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ class Status {
public:
using GrpcStatus = int64_t;

// If this enum is changed, then the std::unordered_map in Envoy::Grpc::Utility::nameToGrpcStatus
// located at: //source/common/access_log/grpc/status.cc must also be changed.
enum WellKnownGrpcStatus {
// The RPC completed successfully.
Ok = 0,
Expand Down
1 change: 1 addition & 0 deletions include/envoy/http/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ envoy_cc_library(
envoy_cc_library(
name = "metadata_interface",
hdrs = ["metadata_interface.h"],
external_deps = ["abseil_node_hash_map"],
)

envoy_cc_library(
Expand Down
1 change: 0 additions & 1 deletion include/envoy/http/header_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#include <iostream>
#include <memory>
#include <string>
#include <unordered_set>
#include <vector>

#include "envoy/common/pure.h"
Expand Down
5 changes: 3 additions & 2 deletions include/envoy/http/metadata_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
#include <functional>
#include <iostream>
#include <memory>
#include <unordered_map>
#include <vector>

#include "absl/container/node_hash_map.h"

namespace Envoy {
namespace Http {

Expand All @@ -20,7 +21,7 @@ constexpr uint8_t END_METADATA_FLAG = 0x4;
// TODO(soya3129): Respect max_frame_size after nghttp2 #1250 is resolved.
constexpr uint64_t METADATA_MAX_PAYLOAD_SIZE = 16384;

using UnorderedStringMap = std::unordered_map<std::string, std::string>;
using UnorderedStringMap = absl::node_hash_map<std::string, std::string>;

class MetadataMap : public UnorderedStringMap {
public:
Expand Down
5 changes: 4 additions & 1 deletion include/envoy/runtime/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ envoy_package()
envoy_cc_library(
name = "runtime_interface",
hdrs = ["runtime.h"],
external_deps = ["abseil_optional"],
external_deps = [
"abseil_node_hash_map",
"abseil_optional",
],
deps = [
"//include/envoy/stats:stats_interface",
"//include/envoy/thread_local:thread_local_interface",
Expand Down
4 changes: 2 additions & 2 deletions include/envoy/runtime/runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#include <limits>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>

#include "envoy/common/pure.h"
Expand All @@ -17,6 +16,7 @@
#include "common/singleton/threadsafe_singleton.h"

#include "absl/container/flat_hash_map.h"
#include "absl/container/node_hash_map.h"
#include "absl/types/optional.h"

namespace Envoy {
Expand Down Expand Up @@ -253,7 +253,7 @@ class Loader {
* a key, use an empty string as the value.
* @param values the values to merge
*/
virtual void mergeValues(const std::unordered_map<std::string, std::string>& values) PURE;
virtual void mergeValues(const absl::node_hash_map<std::string, std::string>& values) PURE;

/**
* Initiate all RTDS subscriptions. The `on_done` callback is invoked when all RTDS requests
Expand Down
1 change: 0 additions & 1 deletion include/envoy/server/overload_manager.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#pragma once

#include <string>
#include <unordered_map>

#include "envoy/common/pure.h"
#include "envoy/thread_local/thread_local.h"
Expand Down
3 changes: 3 additions & 0 deletions include/envoy/upstream/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ envoy_package()
envoy_cc_library(
name = "cluster_manager_interface",
hdrs = ["cluster_manager.h"],
external_deps = [
"abseil_node_hash_map",
],
deps = [
":health_checker_interface",
":load_balancer_interface",
Expand Down
8 changes: 5 additions & 3 deletions include/envoy/upstream/cluster_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>

#include "envoy/access_log/access_log.h"
#include "envoy/api/api.h"
Expand Down Expand Up @@ -32,6 +31,9 @@
#include "envoy/upstream/thread_local_cluster.h"
#include "envoy/upstream/upstream.h"

#include "absl/container/flat_hash_set.h"
#include "absl/container/node_hash_map.h"

namespace Envoy {
namespace Upstream {

Expand Down Expand Up @@ -123,15 +125,15 @@ class ClusterManager {
virtual void
initializeSecondaryClusters(const envoy::config::bootstrap::v3::Bootstrap& bootstrap) PURE;

using ClusterInfoMap = std::unordered_map<std::string, std::reference_wrapper<const Cluster>>;
using ClusterInfoMap = absl::node_hash_map<std::string, std::reference_wrapper<const Cluster>>;

/**
* @return ClusterInfoMap all current clusters. These are the primary (not thread local)
* clusters which should only be used for stats/admin.
*/
virtual ClusterInfoMap clusters() PURE;

using ClusterSet = std::unordered_set<std::string>;
using ClusterSet = absl::flat_hash_set<std::string>;

/**
* @return const ClusterSet& providing the cluster names that are eligible as
Expand Down
4 changes: 2 additions & 2 deletions include/envoy/upstream/upstream.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ using HostVector = std::vector<HostSharedPtr>;
using HealthyHostVector = Phantom<HostVector, Healthy>;
using DegradedHostVector = Phantom<HostVector, Degraded>;
using ExcludedHostVector = Phantom<HostVector, Excluded>;
using HostMap = std::unordered_map<std::string, Upstream::HostSharedPtr>;
using HostMap = absl::node_hash_map<std::string, Upstream::HostSharedPtr>;
using HostVectorSharedPtr = std::shared_ptr<HostVector>;
using HostVectorConstSharedPtr = std::shared_ptr<const HostVector>;

Expand All @@ -221,7 +221,7 @@ using ExcludedHostVectorConstSharedPtr = std::shared_ptr<const ExcludedHostVecto

using HostListPtr = std::unique_ptr<HostVector>;
using LocalityWeightsMap =
std::unordered_map<envoy::config::core::v3::Locality, uint32_t, LocalityHash, LocalityEqualTo>;
absl::node_hash_map<envoy::config::core::v3::Locality, uint32_t, LocalityHash, LocalityEqualTo>;
using PriorityState = std::vector<std::pair<HostListPtr, LocalityWeightsMap>>;

/**
Expand Down
4 changes: 3 additions & 1 deletion source/common/access_log/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ envoy_cc_library(
name = "access_log_lib",
srcs = ["access_log_impl.cc"],
hdrs = ["access_log_impl.h"],
external_deps = ["abseil_hash"],
external_deps = [
"abseil_hash",
],
deps = [
"//include/envoy/access_log:access_log_interface",
"//include/envoy/config:typed_config_interface",
Expand Down
4 changes: 2 additions & 2 deletions source/common/access_log/access_log_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

#include <cstdint>
#include <string>
#include <unordered_set>
#include <vector>

#include "envoy/access_log/access_log.h"
Expand All @@ -17,6 +16,7 @@
#include "common/http/header_utility.h"
#include "common/protobuf/protobuf.h"

#include "absl/container/node_hash_set.h"
#include "absl/hash/hash.h"

namespace Envoy {
Expand Down Expand Up @@ -207,7 +207,7 @@ class ResponseFlagFilter : public Filter {
class GrpcStatusFilter : public Filter {
public:
using GrpcStatusHashSet =
std::unordered_set<Grpc::Status::GrpcStatus, absl::Hash<Grpc::Status::GrpcStatus>>;
absl::node_hash_set<Grpc::Status::GrpcStatus, absl::Hash<Grpc::Status::GrpcStatus>>;

GrpcStatusFilter(const envoy::config::accesslog::v3::GrpcStatusFilter& config);

Expand Down
5 changes: 3 additions & 2 deletions source/common/access_log/access_log_manager_impl.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#pragma once

#include <string>
#include <unordered_map>

#include "envoy/access_log/access_log.h"
#include "envoy/api/api.h"
Expand All @@ -14,6 +13,8 @@
#include "common/common/logger.h"
#include "common/common/thread.h"

#include "absl/container/node_hash_map.h"

namespace Envoy {

#define ACCESS_LOG_FILE_STATS(COUNTER, GAUGE) \
Expand Down Expand Up @@ -51,7 +52,7 @@ class AccessLogManagerImpl : public AccessLogManager, Logger::Loggable<Logger::I
Event::Dispatcher& dispatcher_;
Thread::BasicLockable& lock_;
AccessLogFileStats file_stats_;
std::unordered_map<std::string, AccessLogFileSharedPtr> access_logs_;
absl::node_hash_map<std::string, AccessLogFileSharedPtr> access_logs_;
};

/**
Expand Down
1 change: 1 addition & 0 deletions source/common/common/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ envoy_cc_library(
name = "utility_lib",
srcs = ["utility.cc"],
hdrs = ["utility.h"],
external_deps = ["abseil_node_hash_map"],
deps = [
":assert_lib",
":hash_lib",
Expand Down
2 changes: 0 additions & 2 deletions source/common/common/hash.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#pragma once

#include <string>
#include <unordered_map>
#include <unordered_set>

#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
Expand Down
4 changes: 2 additions & 2 deletions source/common/common/perf_annotation.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

#include <chrono>
#include <cstdint>
#include <unordered_map>

#include "common/common/thread.h"
#include "common/common/utility.h"

#include "absl/container/node_hash_map.h"
#include "absl/strings/string_view.h"

// Performance Annotation system, enabled with
Expand Down Expand Up @@ -139,7 +139,7 @@ class PerfAnnotationContext {
}
};

using DurationStatsMap = std::unordered_map<CategoryDescription, DurationStats, Hash>;
using DurationStatsMap = absl::node_hash_map<CategoryDescription, DurationStats, Hash>;

// Maps {category, description} to DurationStats.
#if PERF_THREAD_SAFE
Expand Down
9 changes: 6 additions & 3 deletions source/common/common/utility.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "common/common/hash.h"
#include "common/singleton/const_singleton.h"

#include "absl/container/node_hash_map.h"
#include "absl/strings/ascii.h"
#include "absl/strings/match.h"
#include "absl/strings/str_join.h"
Expand Down Expand Up @@ -85,7 +86,7 @@ std::string DateFormatter::fromTime(const SystemTime& time) const {
SpecifierOffsets specifier_offsets;
};
// A map is used to keep different formatted format strings at a given second.
std::unordered_map<std::string, const Formatted> formatted;
absl::node_hash_map<std::string, const Formatted> formatted;
};
static thread_local CachedTime cached_time;

Expand All @@ -101,9 +102,11 @@ std::string DateFormatter::fromTime(const SystemTime& time) const {
// Remove all the expired cached items.
for (auto it = cached_time.formatted.cbegin(); it != cached_time.formatted.cend();) {
if (it->second.epoch_time_seconds != epoch_time_seconds) {
it = cached_time.formatted.erase(it);
auto next_it = std::next(it);
cached_time.formatted.erase(it);
it = next_it;
} else {
it++;
++it;
}
}

Expand Down
1 change: 0 additions & 1 deletion source/common/common/utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#include <set>
#include <sstream>
#include <string>
#include <unordered_set>
#include <vector>

#include "envoy/common/interval_set.h"
Expand Down
6 changes: 3 additions & 3 deletions source/common/config/config_provider_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -391,10 +391,10 @@ class ConfigProviderManagerImplBase : public ConfigProviderManager, public Singl
protected:
// Ordered set for deterministic config dump output.
using ConfigProviderSet = std::set<ConfigProvider*>;
using ConfigProviderMap = std::unordered_map<ConfigProviderInstanceType,
std::unique_ptr<ConfigProviderSet>, EnumClassHash>;
using ConfigProviderMap = absl::node_hash_map<ConfigProviderInstanceType,
std::unique_ptr<ConfigProviderSet>, EnumClassHash>;
using ConfigSubscriptionMap =
std::unordered_map<uint64_t, std::weak_ptr<ConfigSubscriptionCommonBase>>;
absl::node_hash_map<uint64_t, std::weak_ptr<ConfigSubscriptionCommonBase>>;

ConfigProviderManagerImplBase(Server::Admin& admin, const std::string& config_name);

Expand Down
8 changes: 5 additions & 3 deletions source/common/config/delta_subscription_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include "common/config/pausable_ack_queue.h"
#include "common/config/watch_map.h"

#include "absl/container/node_hash_map.h"

namespace Envoy {
namespace Config {

Expand Down Expand Up @@ -81,7 +83,7 @@ class DeltaSubscriptionState : public Logger::Loggable<Logger::Id::config> {
// names we are currently interested in. Those in the waitingForServer state currently don't have
// any version for that resource: we need to inform the server if we lose interest in them, but we
// also need to *not* include them in the initial_resource_versions map upon a reconnect.
std::unordered_map<std::string, ResourceVersion> resource_versions_;
absl::node_hash_map<std::string, ResourceVersion> resource_versions_;
// The keys of resource_versions_. Only tracked separately because std::map does not provide an
// iterator into just its keys, e.g. for use in std::set_difference.
std::set<std::string> resource_names_;
Expand All @@ -94,8 +96,8 @@ class DeltaSubscriptionState : public Logger::Loggable<Logger::Id::config> {
bool any_request_sent_yet_in_current_stream_{};

// Tracks changes in our subscription interest since the previous DeltaDiscoveryRequest we sent.
// Can't use unordered_set due to ordering issues in gTest expectation matching.
// Feel free to change to unordered if you can figure out how to make it work.
// TODO: Can't use absl::flat_hash_set due to ordering issues in gTest expectation matching.
// Feel free to change to an unordered container once we figure out how to make it work.
std::set<std::string> names_added_;
std::set<std::string> names_removed_;
};
Expand Down
5 changes: 2 additions & 3 deletions source/common/config/grpc_mux_impl.cc
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
#include "common/config/grpc_mux_impl.h"

#include <unordered_set>

#include "envoy/service/discovery/v3/discovery.pb.h"

#include "common/config/decoded_resource_impl.h"
Expand All @@ -11,6 +9,7 @@
#include "common/protobuf/protobuf.h"

#include "absl/container/btree_map.h"
#include "absl/container/node_hash_set.h"

namespace Envoy {
namespace Config {
Expand All @@ -36,7 +35,7 @@ void GrpcMuxImpl::sendDiscoveryRequest(const std::string& type_url) {
request.mutable_resource_names()->Clear();

// Maintain a set to avoid dupes.
std::unordered_set<std::string> resources;
absl::node_hash_set<std::string> resources;
for (const auto* watch : api_state.watches_) {
for (const std::string& resource : watch->resources_) {
if (resources.count(resource) == 0) {
Expand Down
5 changes: 3 additions & 2 deletions source/common/config/grpc_mux_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include <cstdint>
#include <memory>
#include <queue>
#include <unordered_map>

#include "envoy/api/v2/discovery.pb.h"
#include "envoy/common/random_generator.h"
Expand All @@ -21,6 +20,8 @@
#include "common/config/grpc_stream.h"
#include "common/config/utility.h"

#include "absl/container/node_hash_map.h"

namespace Envoy {
namespace Config {
/**
Expand Down Expand Up @@ -131,7 +132,7 @@ class GrpcMuxImpl : public GrpcMux,
const LocalInfo::LocalInfo& local_info_;
const bool skip_subsequent_node_;
bool first_stream_request_;
std::unordered_map<std::string, ApiState> api_state_;
absl::node_hash_map<std::string, ApiState> api_state_;
// Envoy's dependency ordering.
std::list<std::string> subscriptions_;

Expand Down
Loading

0 comments on commit cf2df8c

Please sign in to comment.