blob: 9612c985e237f65c3c801cf704d6d9daebcc8cfb [file]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NET_SOCKET_SOCKET_POOL_ADDITIONAL_CAPACITY_H_
#define NET_SOCKET_SOCKET_POOL_ADDITIONAL_CAPACITY_H_
#include <string>
#include "base/strings/stringprintf.h"
#include "net/base/net_export.h"
namespace net {
// Socket pools update their expandability before every socket allocation and
// release.
enum class SocketPoolExpandability {
// Uncapped pools can allocate or release sockets.
kUncapped,
// Capped pools cannot allocate sockets, but can release them.
kCapped
};
// This class encapsulates the logic for the additional TCP Socket Pool capacity
// allocated (and randomized) to prevent cross-site expandability tracking.
// Stored on `ClientSocketPool` subclasses and used in capacity calculations.
// See crbug.com/415691664 for more details.
class NET_EXPORT_PRIVATE SocketPoolAdditionalCapacity {
public:
// This initializes using values from kTcpSocketPoolLimitRandomization.
// `additional_capacity` is the maximum amount of sockets (on top of the
// `socket_soft_cap`) allowed to be allocated. Usually `additional_capacity`
// equals `socket_soft_cap`, but this is not enforced.
static SocketPoolAdditionalCapacity Create(size_t additional_capacity);
// This initializes an empty pool that contains no capacity.
static SocketPoolAdditionalCapacity CreateEmpty();
static SocketPoolAdditionalCapacity CreateForTest(double base,
size_t capacity,
double minimum,
double noise);
// Calculates the next `SocketPoolExpandability` before the allocation of a
// socket. `sockets_in_use` should be counted pre-allocation and
// `socket_soft_cap` is likely being passed down from
// `g_max_sockets_per_pool`.
SocketPoolExpandability NextExpandabilityBeforeAllocation(
SocketPoolExpandability current_expandability,
size_t sockets_in_use,
size_t socket_soft_cap) const;
// Calculates the next `SocketPoolExpandability` after the release of a
// socket. `sockets_in_use` should be counted post-release and
// `socket_soft_cap` is likely being passed down from
// `g_max_sockets_per_pool`.
SocketPoolExpandability NextExpandabilityAfterRelease(
SocketPoolExpandability current_expandability,
size_t sockets_in_use,
size_t socket_soft_cap) const;
explicit operator std::string() const {
return base::StringPrintf(
"SocketPoolAdditionalCapacity(base:%e,capacity:%i,minimum:%e,noise:%e)",
base_, capacity_, minimum_, noise_);
}
friend bool operator==(const SocketPoolAdditionalCapacity& lhs,
const SocketPoolAdditionalCapacity& rhs) {
return lhs.base_ == rhs.base_ && lhs.capacity_ == rhs.capacity_ &&
lhs.minimum_ == rhs.minimum_ && lhs.noise_ == rhs.noise_;
}
private:
enum class SocketPoolAction { kAllocation, kRelease };
static void LogExpandabilityTransition(
SocketPoolAction action,
SocketPoolExpandability current_expandability,
SocketPoolExpandability next_expandability,
size_t sockets_in_use);
SocketPoolAdditionalCapacity() = default;
SocketPoolAdditionalCapacity(double base,
size_t capacity,
double minimum,
double noise);
// Helper for NextExpandabilityBeforeAllocation to avoid duplicate logging
// code.
SocketPoolExpandability NextExpandabilityBeforeAllocationImpl(
SocketPoolExpandability current_expandability,
size_t sockets_in_use,
size_t socket_soft_cap) const;
// Helper for NextExpandabilityAfterRelease to avoid duplicate logging code.
SocketPoolExpandability NextExpandabilityAfterReleaseImpl(
SocketPoolExpandability current_expandability,
size_t sockets_in_use,
size_t socket_soft_cap) const;
// This helper function for `NextExpandabilityBefore(Allocation|Release)`
// handles common logic. Returns a SocketPoolExpandability if the common logic
// is controlling, and std::nullopt otherwise.
std::optional<SocketPoolExpandability> NextExpandabilityCommonImpl(
size_t sockets_in_use,
size_t socket_soft_cap) const;
// Unlike other functions in this class, this one will CHECK on invalid
// constants and inputs. As such, all validation must be performed before we
// get to this stage. The actual way this function rolls dice are quite
// complex, please see the implementation for details.
// `actions_taken` must be between 0 and `capacity_`, and is the
// amount of `capacity_` already allocated for
// `NextExpandabilityBeforeAllocationImpl` and the amount of `capacity_` free
// for `NextExpandabilityAfterReleaseImpl`. This is done to ensure the
// probability converges toward 1 correctly for each.
bool ShouldTransitionExpandability(SocketPoolAction action,
size_t actions_taken) const;
// See the implementation of `ShouldTransitionExpandability` for how these
// constants are used and bound in calculating the probability of a
// expandability transition.
double base_ = 0.0;
size_t capacity_ = 0;
double minimum_ = 0.0;
double noise_ = 0.0;
};
} // namespace net
#endif // NET_SOCKET_SOCKET_POOL_ADDITIONAL_CAPACITY_H_