Fix quadratic behavior in HostResolverImpl.
Canceling a single request is currently linear in the number of
requests, making the overall behavior quadratic. Fix it to be linear, so
we scale well and avoid upsetting the fuzzer.
Bug: 834578
Change-Id: Ieb17b106b0a8308b7b5a882fa1f61f899ee4dbcd
Reviewed-on: https://chromium-review.googlesource.com/1020022
Reviewed-by: Eric Roman <[email protected]>
Commit-Queue: David Benjamin <[email protected]>
Cr-Commit-Position: refs/heads/master@{#552891}
diff --git a/net/dns/host_resolver_impl.cc b/net/dns/host_resolver_impl.cc
index 3a279aa..32ddb48 100644
--- a/net/dns/host_resolver_impl.cc
+++ b/net/dns/host_resolver_impl.cc
@@ -30,7 +30,7 @@
#include "base/callback.h"
#include "base/callback_helpers.h"
#include "base/compiler_specific.h"
-#include "base/containers/circular_deque.h"
+#include "base/containers/linked_list.h"
#include "base/debug/debugger.h"
#include "base/debug/stack_trace.h"
#include "base/macros.h"
@@ -588,7 +588,9 @@
// Holds the data for a request that could not be completed synchronously.
// It is owned by a Job. Canceled Requests are only marked as canceled rather
// than removed from the Job's |requests_| list.
-class HostResolverImpl::RequestImpl : public HostResolver::Request {
+class HostResolverImpl::RequestImpl
+ : public HostResolver::Request,
+ public base::LinkNode<HostResolverImpl::RequestImpl> {
public:
RequestImpl(const NetLogWithSource& source_net_log,
const RequestInfo& info,
@@ -1254,14 +1256,13 @@
net_log_.EndEvent(NetLogEventType::HOST_RESOLVER_IMPL_JOB);
}
// else CompleteRequests logged EndEvent.
- if (!requests_.empty()) {
+ while (!requests_.empty()) {
// Log any remaining Requests as cancelled.
- for (RequestImpl* req : requests_) {
- DCHECK_EQ(this, req->job());
- LogCancelRequest(req->source_net_log(), req->info());
- req->OnJobCancelled(this);
- }
- requests_.clear();
+ RequestImpl* req = requests_.head()->value();
+ req->RemoveFromList();
+ DCHECK_EQ(this, req->job());
+ LogCancelRequest(req->source_net_log(), req->info());
+ req->OnJobCancelled(this);
}
}
@@ -1301,7 +1302,7 @@
if (!request->info().is_speculative())
had_non_speculative_request_ = true;
- requests_.push_back(request);
+ requests_.Append(request);
UpdatePriority();
}
@@ -1331,7 +1332,7 @@
if (num_active_requests() > 0) {
UpdatePriority();
- RemoveRequest(request);
+ request->RemoveFromList();
} else {
// If we were called from a Request's callback within CompleteRequests,
// that Request could not have been cancelled, so num_active_requests()
@@ -1340,12 +1341,6 @@
}
}
- void RemoveRequest(RequestImpl* request) {
- auto it = std::find(requests_.begin(), requests_.end(), request);
- DCHECK(it != requests_.end());
- requests_.erase(it);
- }
-
// Called from AbortAllInProgressJobs. Completes all requests and destroys
// the job. This currently assumes the abort is due to a network change.
// TODO This should not delete |this|.
@@ -1381,8 +1376,7 @@
bool ServeFromHosts() {
DCHECK_GT(num_active_requests(), 0u);
AddressList addr_list;
- if (resolver_->ServeFromHosts(key(),
- requests_.front()->info(),
+ if (resolver_->ServeFromHosts(key(), requests_.head()->value()->info(),
&addr_list)) {
// This will destroy the Job.
CompleteRequests(
@@ -1452,7 +1446,8 @@
AddressList MakeAddressListForRequest(const AddressList& list) const {
if (requests_.empty())
return list;
- return AddressList::CopyWithPort(list, requests_.front()->info().port());
+ return AddressList::CopyWithPort(list,
+ requests_.head()->value()->info().port());
}
void UpdatePriority() {
@@ -1792,8 +1787,8 @@
// Complete all of the requests that were attached to the job and
// detach them.
while (!requests_.empty()) {
- RequestImpl* req = requests_.front();
- requests_.pop_front();
+ RequestImpl* req = requests_.head()->value();
+ req->RemoveFromList();
DCHECK_EQ(this, req->job());
// Update the net log and notify registered observers.
LogFinishRequest(req->source_net_log(), req->info(), entry.error());
@@ -1865,7 +1860,7 @@
std::unique_ptr<DnsTask> dns_task_;
// All Requests waiting for the result of this Job. Some can be canceled.
- base::circular_deque<RequestImpl*> requests_;
+ base::LinkedList<RequestImpl> requests_;
// A handle used in |HostResolverImpl::dispatcher_|.
PrioritizedDispatcher::Handle handle_;