blob: 2e79e6642917b309640947dedc6d2f08031b2379 [file] [log] [blame]
// Copyright (c) 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef QUICHE_QUIC_LOAD_BALANCER_LOAD_BALANCER_SERVER_ID_MAP_H_
#define QUICHE_QUIC_LOAD_BALANCER_LOAD_BALANCER_SERVER_ID_MAP_H_
#include "absl/container/flat_hash_map.h"
#include "quiche/quic/load_balancer/load_balancer_server_id.h"
#include "quiche/quic/platform/api/quic_bug_tracker.h"
namespace quic {
// This class wraps an absl::flat_hash_map which associates server IDs to an
// arbitrary type T. It validates that all server ids are of the same fixed
// length. This might be used by a load balancer to connect a server ID with a
// pool member data structure.
template <typename T>
class QUIC_EXPORT_PRIVATE LoadBalancerServerIdMap {
public:
// Returns a newly created pool for server IDs of length |server_id_len|, or
// nullptr if |server_id_len| is invalid.
static std::shared_ptr<LoadBalancerServerIdMap> Create(
const uint8_t server_id_len);
// Returns the entry associated with |server_id|, if present. For small |T|,
// use Lookup. For large |T|, use LookupNoCopy.
absl::optional<const T> Lookup(const LoadBalancerServerId server_id) const;
const T* LookupNoCopy(const LoadBalancerServerId server_id) const;
// Updates the table so that |value| is associated with |server_id|. Sets
// QUIC_BUG if the length is incorrect for this map.
void AddOrReplace(const LoadBalancerServerId server_id, T value);
// Removes the entry associated with |server_id|.
void Erase(const LoadBalancerServerId server_id) {
server_id_table_.erase(server_id);
}
uint8_t server_id_len() const { return server_id_len_; }
private:
LoadBalancerServerIdMap(uint8_t server_id_len)
: server_id_len_(server_id_len) {}
const uint8_t server_id_len_; // All server IDs must be of this length.
absl::flat_hash_map<LoadBalancerServerId, T> server_id_table_;
};
template <typename T>
std::shared_ptr<LoadBalancerServerIdMap<T>> LoadBalancerServerIdMap<T>::Create(
const uint8_t server_id_len) {
if (server_id_len == 0 || server_id_len > kLoadBalancerMaxServerIdLen) {
QUIC_BUG(quic_bug_434893339_01)
<< "Tried to configure map with server ID length "
<< static_cast<int>(server_id_len);
return nullptr;
}
return std::make_shared<LoadBalancerServerIdMap<T>>(
LoadBalancerServerIdMap(server_id_len));
}
template <typename T>
absl::optional<const T> LoadBalancerServerIdMap<T>::Lookup(
const LoadBalancerServerId server_id) const {
if (server_id.length() != server_id_len_) {
QUIC_BUG(quic_bug_434893339_02)
<< "Lookup with a " << static_cast<int>(server_id.length())
<< " byte server ID, map requires " << static_cast<int>(server_id_len_);
return absl::optional<T>();
}
auto it = server_id_table_.find(server_id);
return (it != server_id_table_.end()) ? it->second
: absl::optional<const T>();
}
template <typename T>
const T* LoadBalancerServerIdMap<T>::LookupNoCopy(
const LoadBalancerServerId server_id) const {
if (server_id.length() != server_id_len_) {
QUIC_BUG(quic_bug_434893339_02)
<< "Lookup with a " << static_cast<int>(server_id.length())
<< " byte server ID, map requires " << static_cast<int>(server_id_len_);
return nullptr;
}
auto it = server_id_table_.find(server_id);
return (it != server_id_table_.end()) ? &it->second : nullptr;
}
template <typename T>
void LoadBalancerServerIdMap<T>::AddOrReplace(
const LoadBalancerServerId server_id, T value) {
if (server_id.length() == server_id_len_) {
server_id_table_[server_id] = value;
} else {
QUIC_BUG(quic_bug_434893339_03)
<< "Server ID of " << static_cast<int>(server_id.length())
<< " bytes; this map requires " << static_cast<int>(server_id_len_);
}
}
} // namespace quic
#endif // QUICHE_QUIC_LOAD_BALANCER_LOAD_BALANCER_SERVER_ID_MAP_H_