1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/base/prioritized_dispatcher.h"
7 #include "base/logging.h"
11 PrioritizedDispatcher::Limits::Limits(Priority num_priorities,
13 : total_jobs(total_jobs), reserved_slots(num_priorities) {}
15 PrioritizedDispatcher::Limits::~Limits() {}
17 PrioritizedDispatcher::PrioritizedDispatcher(const Limits& limits)
18 : queue_(limits.reserved_slots.size()),
19 max_running_jobs_(limits.reserved_slots.size()),
20 num_running_jobs_(0) {
24 PrioritizedDispatcher::~PrioritizedDispatcher() {}
26 PrioritizedDispatcher::Handle PrioritizedDispatcher::Add(
27 Job* job, Priority priority) {
29 DCHECK_LT(priority, num_priorities());
30 if (num_running_jobs_ < max_running_jobs_[priority]) {
35 return queue_.Insert(job, priority);
38 PrioritizedDispatcher::Handle PrioritizedDispatcher::AddAtHead(
39 Job* job, Priority priority) {
41 DCHECK_LT(priority, num_priorities());
42 if (num_running_jobs_ < max_running_jobs_[priority]) {
47 return queue_.InsertAtFront(job, priority);
50 void PrioritizedDispatcher::Cancel(const Handle& handle) {
54 PrioritizedDispatcher::Job* PrioritizedDispatcher::EvictOldestLowest() {
55 Handle handle = queue_.FirstMin();
58 Job* job = handle.value();
63 PrioritizedDispatcher::Handle PrioritizedDispatcher::ChangePriority(
64 const Handle& handle, Priority priority) {
65 DCHECK(!handle.is_null());
66 DCHECK_LT(priority, num_priorities());
67 DCHECK_GE(num_running_jobs_, max_running_jobs_[handle.priority()]) <<
68 "Job should not be in queue when limits permit it to start.";
70 if (handle.priority() == priority)
73 if (MaybeDispatchJob(handle, priority))
75 Job* job = handle.value();
77 return queue_.Insert(job, priority);
80 void PrioritizedDispatcher::OnJobFinished() {
81 DCHECK_GT(num_running_jobs_, 0u);
83 MaybeDispatchNextJob();
86 PrioritizedDispatcher::Limits PrioritizedDispatcher::GetLimits() const {
87 size_t num_priorities = max_running_jobs_.size();
88 Limits limits(num_priorities, max_running_jobs_.back());
90 // Calculate the number of jobs reserved for each priority and higher. Leave
91 // the number of jobs reserved for the lowest priority or higher as 0.
92 for (size_t i = 1; i < num_priorities; ++i) {
93 limits.reserved_slots[i] = max_running_jobs_[i] - max_running_jobs_[i - 1];
99 void PrioritizedDispatcher::SetLimits(const Limits& limits) {
100 DCHECK_EQ(queue_.num_priorities(), limits.reserved_slots.size());
102 for (size_t i = 0; i < limits.reserved_slots.size(); ++i) {
103 total += limits.reserved_slots[i];
104 max_running_jobs_[i] = total;
106 // Unreserved slots are available for all priorities.
107 DCHECK_LE(total, limits.total_jobs) << "sum(reserved_slots) <= total_jobs";
108 size_t spare = limits.total_jobs - total;
109 for (size_t i = limits.reserved_slots.size(); i > 0; --i) {
110 max_running_jobs_[i - 1] += spare;
113 // Start pending jobs, if limits permit.
115 if (!MaybeDispatchNextJob())
120 void PrioritizedDispatcher::SetLimitsToZero() {
121 SetLimits(Limits(queue_.num_priorities(), 0));
124 bool PrioritizedDispatcher::MaybeDispatchJob(const Handle& handle,
125 Priority job_priority) {
126 DCHECK_LT(job_priority, num_priorities());
127 if (num_running_jobs_ >= max_running_jobs_[job_priority])
129 Job* job = handle.value();
130 queue_.Erase(handle);
136 bool PrioritizedDispatcher::MaybeDispatchNextJob() {
137 Handle handle = queue_.FirstMax();
138 if (handle.is_null()) {
139 DCHECK_EQ(0u, queue_.size());
142 return MaybeDispatchJob(handle, handle.priority());