| // Copyright (c) 2012 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_TEST_TOOLS_SIMULATOR_QUEUE_H_ |
| #define QUICHE_QUIC_TEST_TOOLS_SIMULATOR_QUEUE_H_ |
| |
| #include "quic/core/quic_alarm.h" |
| #include "quic/test_tools/simulator/link.h" |
| #include "common/quiche_circular_deque.h" |
| |
| namespace quic { |
| namespace simulator { |
| |
| // A finitely sized queue which egresses packets onto a constrained link. The |
| // capacity of the queue is measured in bytes as opposed to packets. |
| class Queue : public Actor, public UnconstrainedPortInterface { |
| public: |
| class ListenerInterface { |
| public: |
| virtual ~ListenerInterface(); |
| |
| // Called whenever a packet is removed from the queue. |
| virtual void OnPacketDequeued() = 0; |
| }; |
| |
| Queue(Simulator* simulator, std::string name, QuicByteCount capacity); |
| Queue(const Queue&) = delete; |
| Queue& operator=(const Queue&) = delete; |
| ~Queue() override; |
| |
| void set_tx_port(ConstrainedPortInterface* port); |
| |
| void AcceptPacket(std::unique_ptr<Packet> packet) override; |
| |
| void Act() override; |
| |
| inline QuicByteCount capacity() const { return capacity_; } |
| inline QuicByteCount bytes_queued() const { return bytes_queued_; } |
| inline QuicPacketCount packets_queued() const { return queue_.size(); } |
| |
| inline void set_listener_interface(ListenerInterface* listener) { |
| listener_ = listener; |
| } |
| |
| // Enables packet aggregation on the queue. Packet aggregation makes the |
| // queue bundle packets up until they reach certain size. When the |
| // aggregation is enabled, the packets are not dequeued until the total size |
| // of packets in the queue reaches |aggregation_threshold|. The packets are |
| // automatically flushed from the queue if the oldest packet has been in it |
| // for |aggregation_timeout|. |
| // |
| // This method may only be called when the queue is empty. Once enabled, |
| // aggregation cannot be disabled. |
| void EnableAggregation(QuicByteCount aggregation_threshold, |
| QuicTime::Delta aggregation_timeout); |
| |
| private: |
| using AggregationBundleNumber = uint64_t; |
| |
| // In order to implement packet aggregation, each packet is tagged with a |
| // bundle number. The queue keeps a bundle counter, and whenever a bundle is |
| // ready, it increments the number of the current bundle. Only the packets |
| // outside of the current bundle are allowed to leave the queue. |
| struct EnqueuedPacket { |
| EnqueuedPacket(std::unique_ptr<Packet> packet, |
| AggregationBundleNumber bundle); |
| EnqueuedPacket(EnqueuedPacket&& other); |
| ~EnqueuedPacket(); |
| |
| std::unique_ptr<Packet> packet; |
| AggregationBundleNumber bundle; |
| }; |
| |
| // Alarm handler for aggregation timeout. |
| class AggregationAlarmDelegate : public QuicAlarm::DelegateWithoutContext { |
| public: |
| explicit AggregationAlarmDelegate(Queue* queue); |
| |
| void OnAlarm() override; |
| |
| private: |
| Queue* queue_; |
| }; |
| |
| inline bool IsAggregationEnabled() const { |
| return aggregation_threshold_ > 0; |
| } |
| |
| // Increment the bundle counter and reset the bundle state. This causes all |
| // packets currently in the bundle to be flushed onto the link. |
| void NextBundle(); |
| |
| void ScheduleNextPacketDequeue(); |
| |
| const QuicByteCount capacity_; |
| QuicByteCount bytes_queued_; |
| |
| QuicByteCount aggregation_threshold_; |
| QuicTime::Delta aggregation_timeout_; |
| // The number of the current aggregation bundle. Monotonically increasing. |
| // All packets in the previous bundles are allowed to leave the queue, and |
| // none of the packets in the current one are. |
| AggregationBundleNumber current_bundle_; |
| // Size of the current bundle. Whenever it exceeds |aggregation_threshold_|, |
| // the next bundle is created. |
| QuicByteCount current_bundle_bytes_; |
| // Alarm responsible for flushing the current bundle upon timeout. Set when |
| // the first packet in the bundle is enqueued. |
| std::unique_ptr<QuicAlarm> aggregation_timeout_alarm_; |
| |
| ConstrainedPortInterface* tx_port_; |
| quiche::QuicheCircularDeque<EnqueuedPacket> queue_; |
| |
| ListenerInterface* listener_; |
| }; |
| |
| } // namespace simulator |
| } // namespace quic |
| |
| #endif // QUICHE_QUIC_TEST_TOOLS_SIMULATOR_QUEUE_H_ |