quic/state/OutstandingPacket.h (188 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #pragma once #include <folly/container/F14Map.h> #include <quic/codec/Types.h> #include <quic/state/LossState.h> #include <quic/state/PacketEvent.h> namespace quic { struct OutstandingPacketMetadata { // Time that the packet was sent. TimePoint time; // Size of the packet sent on the wire. uint32_t encodedSize; // Size of only the body within the packet sent on the wire. uint32_t encodedBodySize; // Whether this packet has any data from stream 0 bool isHandshake; // Whether the packet is a d6d probe bool isD6DProbe; // Total sent bytes on this connection including this packet itself when this // packet is sent. uint64_t totalBytesSent; // Total sent body bytes on this connection including this packet itself when // this packet is sent. uint64_t totalBodyBytesSent; // Bytes in flight on this connection including this packet itself when this // packet is sent. uint64_t inflightBytes; // Packets in flight on this connection including this packet itself. uint64_t packetsInflight; // Total number of packets sent on this connection. uint32_t totalPacketsSent{0}; // Total number of ack-eliciting packets sent on this connection. uint32_t totalAckElicitingPacketsSent{0}; // Write Count is the value of the monotonically increasing counter which // tracks the number of writes on this socket. uint64_t writeCount{0}; struct StreamDetails { template <class T> using IntervalSetVec = SmallVec<T, 2 /* stack size */, uint16_t>; using StreamIntervals = IntervalSet<uint64_t, 1, IntervalSetVec>; StreamIntervals streamIntervals; bool finObserved{false}; uint64_t streamBytesSent{0}; uint64_t newStreamBytesSent{0}; folly::Optional<uint64_t> maybeFirstNewStreamByteOffset; }; class DetailsPerStream : private folly::F14FastMap<StreamId, StreamDetails> { public: void addFrame(const WriteStreamFrame& frame, const bool newData) { auto ret = emplace( std::piecewise_construct, std::make_tuple(frame.streamId), std::make_tuple()); auto& streamDetails = ret.first->second; if (frame.len) { // could be zero byte if just contains a fin streamDetails.streamIntervals.insert( StreamDetails::StreamIntervals::interval_type( frame.offset, frame.offset + frame.len - 1)); } if (frame.fin) { streamDetails.finObserved = true; } streamDetails.streamBytesSent += frame.len; if (newData) { streamDetails.newStreamBytesSent += frame.len; if (streamDetails.maybeFirstNewStreamByteOffset) { streamDetails.maybeFirstNewStreamByteOffset = std::min( frame.offset, *streamDetails.maybeFirstNewStreamByteOffset); } else { streamDetails.maybeFirstNewStreamByteOffset = frame.offset; } } } [[nodiscard]] auto at(StreamId id) const { return folly::F14FastMap<StreamId, StreamDetails>::at(id); } [[nodiscard]] auto begin() const { return cbegin(); } [[nodiscard]] auto end() const { return cend(); } using folly::F14FastMap<StreamId, StreamDetails>::cbegin; using folly::F14FastMap<StreamId, StreamDetails>::cend; using folly::F14FastMap<StreamId, StreamDetails>::const_iterator; using folly::F14FastMap<StreamId, StreamDetails>::empty; using folly::F14FastMap<StreamId, StreamDetails>::find; using folly::F14FastMap<StreamId, StreamDetails>::mapped_type; using folly::F14FastMap<StreamId, StreamDetails>::size; using folly::F14FastMap<StreamId, StreamDetails>::value_type; }; // Details about each stream with frames in this packet DetailsPerStream detailsPerStream; OutstandingPacketMetadata( TimePoint timeIn, uint32_t encodedSizeIn, uint32_t encodedBodySizeIn, bool isHandshakeIn, bool isD6DProbeIn, uint64_t totalBytesSentIn, uint64_t totalBodyBytesSentIn, uint64_t inflightBytesIn, uint64_t packetsInflightIn, const LossState& lossStateIn, uint64_t writeCount, DetailsPerStream detailsPerStream) : time(timeIn), encodedSize(encodedSizeIn), encodedBodySize(encodedBodySizeIn), isHandshake(isHandshakeIn), isD6DProbe(isD6DProbeIn), totalBytesSent(totalBytesSentIn), totalBodyBytesSent(totalBodyBytesSentIn), inflightBytes(inflightBytesIn), packetsInflight(packetsInflightIn), totalPacketsSent(lossStateIn.totalPacketsSent), totalAckElicitingPacketsSent(lossStateIn.totalAckElicitingPacketsSent), writeCount(writeCount), detailsPerStream(std::move(detailsPerStream)) {} }; // Data structure to represent outstanding retransmittable packets struct OutstandingPacket { using Metadata = OutstandingPacketMetadata; // Structure representing the frames that are outstanding including the header // that was sent. RegularQuicWritePacket packet; // Structure representing a collection of metrics and important information // about the packet. OutstandingPacketMetadata metadata; // Information regarding the last acked packet on this connection when this // packet is sent. struct LastAckedPacketInfo { TimePoint sentTime; TimePoint ackTime; TimePoint adjustedAckTime; // Total sent bytes on this connection when the last acked packet is acked. uint64_t totalBytesSent; // Total acked bytes on this connection when last acked packet is acked, // including the last acked packet. uint64_t totalBytesAcked; LastAckedPacketInfo( TimePoint sentTimeIn, TimePoint ackTimeIn, TimePoint adjustedAckTimeIn, uint64_t totalBytesSentIn, uint64_t totalBytesAckedIn) : sentTime(sentTimeIn), ackTime(ackTimeIn), adjustedAckTime(adjustedAckTimeIn), totalBytesSent(totalBytesSentIn), totalBytesAcked(totalBytesAckedIn) {} }; folly::Optional<LastAckedPacketInfo> lastAckedPacketInfo; // PacketEvent associated with this OutstandingPacket. This will be a // folly::none if the packet isn't a clone and hasn't been cloned. folly::Optional<PacketEvent> associatedEvent; // Whether this is a DSR packet. A DSR packet's stream data isn't written // by transport directly. bool isDSRPacket{false}; /** * Whether the packet is sent when congestion controller is in app-limited * state. */ bool isAppLimited{false}; // True if spurious loss detection is enabled and this packet was declared // lost. bool declaredLost{false}; // Has value if the packet is lost by timout. The value is the loss timeout // dividend that was used to declare this packet. folly::Optional<DurationRep> lossTimeoutDividend; // Has value if the packet is lost by reorder. The value is the distance // between this packet and the acknowleded packet when it was declared lost // due to reordering folly::Optional<uint32_t> lossReorderDistance; OutstandingPacket( RegularQuicWritePacket packetIn, TimePoint timeIn, uint32_t encodedSizeIn, uint32_t encodedBodySizeIn, bool isHandshakeIn, uint64_t totalBytesSentIn, uint64_t totalBodyBytesSentIn, uint64_t inflightBytesIn, uint64_t packetsInflightIn, const LossState& lossStateIn, uint64_t writeCount, Metadata::DetailsPerStream detailsPerStream) : packet(std::move(packetIn)), metadata(OutstandingPacketMetadata( timeIn, encodedSizeIn, encodedBodySizeIn, isHandshakeIn, false /* isD6DProbeIn */, totalBytesSentIn, totalBodyBytesSentIn, inflightBytesIn, packetsInflightIn, lossStateIn, writeCount, std::move(detailsPerStream))) {} OutstandingPacket( RegularQuicWritePacket packetIn, TimePoint timeIn, uint32_t encodedSizeIn, uint32_t encodedBodySizeIn, bool isHandshakeIn, bool isD6DProbeIn, uint64_t totalBytesSentIn, uint64_t totalBodyBytesSentIn, uint64_t inflightBytesIn, uint64_t packetsInflightIn, const LossState& lossStateIn, uint64_t writeCount, Metadata::DetailsPerStream detailsPerStream) : packet(std::move(packetIn)), metadata(OutstandingPacketMetadata( timeIn, encodedSizeIn, encodedBodySizeIn, isHandshakeIn, isD6DProbeIn, totalBytesSentIn, totalBodyBytesSentIn, inflightBytesIn, packetsInflightIn, lossStateIn, writeCount, std::move(detailsPerStream))) {} }; } // namespace quic