20 #include <boost/intrusive/unordered_set.hpp> 24 class HTTPTransaction;
63 using NodeMap = boost::intrusive::unordered_set<
64 Node, boost::intrusive::constant_time_size<false>>;
66 static const size_t kNumBuckets = 100;
71 : nodes_(
NodeMap::bucket_traits(nodeBuckets_, kNumBuckets)) {
76 : nodes_(
NodeMap::bucket_traits(nodeBuckets_, kNumBuckets)),
83 void detachThreadLocals();
86 maxVirtualNodes_ = maxVirtualNodes;
104 root_.dropPriorityNodes();
110 uint64_t* depth =
nullptr)
override;
116 uint64_t* depth =
nullptr)
override;
123 return activeCount_ == 0;
132 return numVirtualNodes_;
137 const std::function<
bool()>& stopFn,
bool all) {
138 updateEnqueuedWeight();
139 root_.iterate(fn, stopFn, all);
146 const std::function<
bool()>& stopFn,
bool all);
153 kNodeLifetime_ = lifetime;
176 return timeout_ && kNodeLifetime_.count() > 0;
181 VLOG(5) <<
"scheduling expiration for node=" << node->
getID();
182 DCHECK_GT(kNodeLifetime_.count(), 0);
183 timeout_.scheduleTimeout(node, kNodeLifetime_);
191 void updateEnqueuedWeight();
194 typedef boost::intrusive::link_mode<boost::intrusive::auto_unlink>
link_mode;
198 public boost::intrusive::unordered_set_base_hook<link_mode> {
211 return id == node.
id_;
214 return node.
id_ == id;
221 return boost::hash<HTTPCodec::StreamID>()(
id);
227 return lhs.
id_ == rhs.
id_;
261 Node* emplaceNode(std::unique_ptr<Node> node,
bool exclusive);
264 void removeFromTree();
275 void updateWeight(
uint8_t weight);
277 Node* reparent(
Node* newParent,
bool exclusive);
280 bool isDescendantOf(
Node *node)
const;
284 return (txn_ !=
nullptr && enqueued_);
290 return isEnqueued() || totalEnqueuedWeight_ > 0;
298 return static_cast<double>(weight_) / parent_->totalChildWeight_;
306 if (parent_->totalEnqueuedWeight_ == 0) {
310 return static_cast<double>(weight_) / parent_->totalEnqueuedWeight_;
326 const std::function<
bool()>& stopFn,
bool all);
333 id(i), node(n), ratio(r) {}
337 bool visitBFS(
double relativeParentWeight,
344 void updateEnqueuedWeight(
bool activeNodes);
346 void dropPriorityNodes();
353 void flattenSubtree();
354 void flattenSubtreeDFS(
Node* subtreeRoot);
355 static void addChildToNewSubtreeRoot(std::unique_ptr<Node>
child,
359 Node* addChild(std::unique_ptr<Node>
child);
361 void addChildren(
std::list<std::unique_ptr<Node>>&& children);
363 std::unique_ptr<Node> detachChild(
Node* node);
369 static void propagatePendingEgressSignal(
Node *node);
371 static void propagatePendingEgressClear(
Node* node);
374 VLOG(5) <<
"Node=" << id_ <<
" expired";
375 CHECK(txn_ ==
nullptr);
376 queue_.pendingWeightChange_ =
true;
381 if (!txn_ && !isPermanent_ && isScheduled()) {
382 queue_.scheduleNodeExpiration(
this);
391 bool isPermanent_{
false};
392 bool enqueued_{
false};
399 std::list<std::unique_ptr<Node>>::iterator
self_;
407 typename NodeMap::bucket_type nodeBuckets_[kNumBuckets];
409 Node root_{*
this,
nullptr, 0, 1,
nullptr};
415 bool pendingWeightChange_{
false};
std::deque< PendingNode > PendingList
void addPriorityNode(HTTPCodec::StreamID id, HTTPCodec::StreamID parent) override
boost::intrusive::unordered_set< Node, boost::intrusive::constant_time_size< false >> NodeMap
void setMaxVirtualNodes(uint32_t maxVirtualNodes)
void scheduleNodeExpiration(Node *node)
size_t operator()(const HTTPCodec::StreamID &id) const
Node * findInternal(HTTPCodec::StreamID id)
std::vector< std::pair< HTTPTransaction *, double >> NextEgressResult
virtual Handle updatePriority(Handle handle, http2::PriorityUpdate pri, uint64_t *depth=nullptr)=0
WheelTimerInstance timeout_
HTTP2PriorityQueue & queue_
std::list< std::unique_ptr< Node > >::iterator self_
folly::IntrusiveList< Node,&Node::enqueuedHook_ > enqueuedChildren_
virtual uint64_t calculateDepth(bool includeVirtual=true) const =0
requires E e noexcept(noexcept(s.error(std::move(e))))
FOLLY_PUSH_WARNING RHS rhs
HTTPCodec::StreamID getID() const
virtual void removeTransaction(Handle handle)=0
static uint32_t kMaxRebuilds_
friend std::size_t hash_value(const Node &node)
virtual Handle addTransaction(HTTPCodec::StreamID id, http2::PriorityUpdate pri, HTTPTransaction *txn, bool permanent=false, uint64_t *depth=nullptr)=0
boost::intrusive::list_member_hook< boost::intrusive::link_mode< boost::intrusive::auto_unlink >> IntrusiveListHook
uint16_t getWeight() const
virtual bool isEnqueued() const =0
folly::IntrusiveListHook enqueuedHook_
Encoder::MutableCompressedList list
bool operator()(const HTTPCodec::StreamID &id, const Node &node)
void iterate(const std::function< bool(HTTPCodec::StreamID, HTTPTransaction *, double)> &fn, const std::function< bool()> &stopFn, bool all)
PendingNode(HTTPCodec::StreamID i, Node *n, double r)
static std::chrono::milliseconds kNodeLifetime_
HTTPCodec::StreamID parentID() const
bool operator()(const Node &node, const HTTPCodec::StreamID &id)
uint64_t numPendingEgress() const
HTTPTransaction * getTransaction() const
bool isEnqueued() const override
boost::intrusive::list< T, boost::intrusive::member_hook< T, IntrusiveListHook, PtrToMember >, boost::intrusive::constant_time_size< false >> IntrusiveList
HTTP2PriorityQueue(const WheelTimerInstance &timeout)
double getRelativeEnqueuedWeight() const
Node(int v=0, Node *n=nullptr, bool=false) noexcept
bool allowDanglingNodes() const
static void setNodeLifetime(std::chrono::milliseconds lifetime)
folly::Function< void()> child
friend bool operator==(const Node &lhs, const Node &rhs)
double getRelativeWeight() const
void timeoutExpired() noexceptoverride
uint64_t numVirtualNodes() const
virtual void clearPendingEgress(Handle h)=0
bool inEgressTree() const
boost::intrusive::link_mode< boost::intrusive::auto_unlink > link_mode
folly::Function< void()> parent
std::list< std::unique_ptr< Node > > children_
uint32_t getRebuildCount() const
Composed all(Predicate pred=Predicate())
virtual void signalPendingEgress(Handle h)=0