Index: net/base/prioritized_dispatcher.cc |
diff --git a/net/base/prioritized_dispatcher.cc b/net/base/prioritized_dispatcher.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6dc1dee569bb123e3c9153dc4a4bea0571c97345 |
--- /dev/null |
+++ b/net/base/prioritized_dispatcher.cc |
@@ -0,0 +1,120 @@ |
+// Copyright (c) 2011 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. |
+ |
+#include "net/base/prioritized_dispatcher.h" |
+ |
+#include "base/logging.h" |
+ |
+namespace net { |
+ |
+// We rely on the priority enum values being sequential having starting at 0, |
+// and increasing for lower priorities. |
+COMPILE_ASSERT(HIGHEST == 0u && |
+ LOWEST > HIGHEST && |
+ IDLE > LOWEST && |
+ NUM_PRIORITIES > IDLE, |
+ priority_indexes_incompatible); |
+ |
+PrioritizedDispatcher::PrioritizedDispatcher(const Limits& limits, |
+ size_t max_queued) |
+ : num_running_jobs_(0), max_queued_jobs_(max_queued) { |
+ size_t total = 0; |
+ for (size_t i = 0; i < NUM_PRIORITIES; ++i) { |
+ total += limits.reserved_slots[NUM_PRIORITIES - i - 1]; |
+ max_running_jobs_[NUM_PRIORITIES - i - 1] = total; |
+ } |
+ DCHECK_LE(total, limits.total_jobs) << "sum(reserved_slots) <= total_jobs"; |
+ size_t spare = limits.total_jobs - total; |
+ for (size_t i = 0; i < NUM_PRIORITIES; ++i) { |
+ max_running_jobs_[i] += spare; |
+ } |
+} |
+ |
+PrioritizedDispatcher::~PrioritizedDispatcher() {} |
+ |
+void PrioritizedDispatcher::SetMaxQueued(size_t max_queued) { |
+ DCHECK_EQ(0u, num_queued_jobs()); |
+ max_queued_jobs_ = max_queued; |
+} |
+ |
+bool PrioritizedDispatcher::WouldEvict(RequestPriority priority) const { |
+ if (num_queued_jobs() < max_queued_jobs_) |
+ return false; |
+ // Temporarily remove const to perform the check. |
+ Handle evicted = |
+ const_cast<PrioritizedDispatcher*>(this)->queue_.OldestLowest(); |
+ DCHECK(!evicted.is_null()); |
+ return evicted.priority() < priority; |
+} |
+ |
+PrioritizedDispatcher::Handle PrioritizedDispatcher::Add( |
+ Job* job, RequestPriority priority) { |
+ DCHECK(job); |
+ if (num_running_jobs_ < max_running_jobs_[priority]) { |
+ ++num_running_jobs_; |
+ job->Start(); |
+ return Handle(); |
+ } |
+ Handle handle = queue_.Insert(job, priority); |
+ if (queue_.size() > max_queued_jobs_) { |
+ // Evict oldest lowest-priority job. |
+ Handle evicted = queue_.OldestLowest(); |
+ DCHECK(!evicted.is_null()); |
+ if (evicted.equals(handle)) |
+ handle = Handle(); |
+ Job* evicted_job = evicted.value(); |
+ queue_.Erase(evicted); |
+ DCHECK(evicted_job); |
+ evicted_job->OnEvicted(); |
+ } |
+ return handle; |
+} |
+ |
+void PrioritizedDispatcher::Cancel(const Handle& handle) { |
+ queue_.Erase(handle); |
+} |
+ |
+PrioritizedDispatcher::Handle PrioritizedDispatcher::Update( |
+ const Handle& handle, RequestPriority priority) { |
+ DCHECK(!handle.is_null()); |
+ DCHECK_GE(num_running_jobs_, max_running_jobs_[handle.priority()]) << |
+ "Job should not be in queue when limits permit it to start."; |
+ DCHECK_LE(queue_.size(), max_queued_jobs_); |
+ |
+ if (handle.priority() == priority) |
+ return handle; |
+ |
+ if (DispatchJob(handle, priority)) |
+ return Handle(); |
+ Job* job = handle.value(); |
+ queue_.Erase(handle); |
+ return queue_.Insert(job, priority); |
+} |
+ |
+void PrioritizedDispatcher::OnJobFinished() { |
+ DCHECK_GT(num_running_jobs_, 0u); |
+ --num_running_jobs_; |
+ Handle handle = queue_.First(); |
+ if (handle.is_null()) { |
+ DCHECK_EQ(0u, queue_.size()); |
+ return; |
+ } |
+ DispatchJob(handle, handle.priority()); |
+} |
+ |
+bool PrioritizedDispatcher::DispatchJob(const Handle& handle, |
+ RequestPriority job_priority) { |
+ if (num_running_jobs_ >= max_running_jobs_[job_priority]) |
+ return false; |
+ Job* job = handle.value(); |
+ queue_.Erase(handle); |
+ ++num_running_jobs_; |
+ DCHECK(job); |
+ job->Start(); |
+ return true; |
+} |
+ |
+} // namespace net |
+ |
+ |