Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(8)

Side by Side Diff: chrome/browser/renderer_host/resource_dispatcher_host.cc

Issue 18541: Add a constraint on how many requests can be outstanding for any given render (browser-side). (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // See http://dev.chromium.org/developers/design-documents/multi-process-resourc e-loading 5 // See http://dev.chromium.org/developers/design-documents/multi-process-resourc e-loading
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "chrome/browser/renderer_host/resource_dispatcher_host.h" 9 #include "chrome/browser/renderer_host/resource_dispatcher_host.h"
10 10
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
65 65
66 // ---------------------------------------------------------------------------- 66 // ----------------------------------------------------------------------------
67 67
68 // The interval for calls to ResourceDispatcherHost::UpdateLoadStates 68 // The interval for calls to ResourceDispatcherHost::UpdateLoadStates
69 static const int kUpdateLoadStatesIntervalMsec = 100; 69 static const int kUpdateLoadStatesIntervalMsec = 100;
70 70
71 // Maximum number of pending data messages sent to the renderer at any 71 // Maximum number of pending data messages sent to the renderer at any
72 // given time for a given request. 72 // given time for a given request.
73 static const int kMaxPendingDataMessages = 20; 73 static const int kMaxPendingDataMessages = 20;
74 74
75 // Maximum byte "cost" of all the outstanding requests for a renderer.
76 // See delcaration of |max_outstanding_requests_cost_per_process_| for details.
77 // This bound is 25MB, which allows for around 6000 outstanding requests.
78 static const int kMaxOutstandingRequestsCostPerProcess = 26214400;
79
75 // A ShutdownTask proxies a shutdown task from the UI thread to the IO thread. 80 // A ShutdownTask proxies a shutdown task from the UI thread to the IO thread.
76 // It should be constructed on the UI thread and run in the IO thread. 81 // It should be constructed on the UI thread and run in the IO thread.
77 class ResourceDispatcherHost::ShutdownTask : public Task { 82 class ResourceDispatcherHost::ShutdownTask : public Task {
78 public: 83 public:
79 explicit ShutdownTask(ResourceDispatcherHost* resource_dispatcher_host) 84 explicit ShutdownTask(ResourceDispatcherHost* resource_dispatcher_host)
80 : rdh_(resource_dispatcher_host) { } 85 : rdh_(resource_dispatcher_host) { }
81 86
82 void Run() { 87 void Run() {
83 rdh_->OnShutdown(); 88 rdh_->OnShutdown();
84 } 89 }
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
128 ResourceDispatcherHost::ResourceDispatcherHost(MessageLoop* io_loop) 133 ResourceDispatcherHost::ResourceDispatcherHost(MessageLoop* io_loop)
129 : ui_loop_(MessageLoop::current()), 134 : ui_loop_(MessageLoop::current()),
130 io_loop_(io_loop), 135 io_loop_(io_loop),
131 download_file_manager_(new DownloadFileManager(ui_loop_, this)), 136 download_file_manager_(new DownloadFileManager(ui_loop_, this)),
132 download_request_manager_(new DownloadRequestManager(io_loop, ui_loop_)), 137 download_request_manager_(new DownloadRequestManager(io_loop, ui_loop_)),
133 save_file_manager_(new SaveFileManager(ui_loop_, io_loop, this)), 138 save_file_manager_(new SaveFileManager(ui_loop_, io_loop, this)),
134 safe_browsing_(new SafeBrowsingService), 139 safe_browsing_(new SafeBrowsingService),
135 request_id_(-1), 140 request_id_(-1),
136 plugin_service_(PluginService::GetInstance()), 141 plugin_service_(PluginService::GetInstance()),
137 method_runner_(this), 142 method_runner_(this),
138 is_shutdown_(false) { 143 is_shutdown_(false),
144 max_outstanding_requests_cost_per_process_(kMaxOutstandingRequestsCostPerP rocess) {
139 } 145 }
140 146
141 ResourceDispatcherHost::~ResourceDispatcherHost() { 147 ResourceDispatcherHost::~ResourceDispatcherHost() {
142 AsyncResourceHandler::GlobalCleanup(); 148 AsyncResourceHandler::GlobalCleanup();
143 STLDeleteValues(&pending_requests_); 149 STLDeleteValues(&pending_requests_);
144 150
145 // Clear blocked requests if any left. 151 // Clear blocked requests if any left.
146 // Note that we have to do this in 2 passes as we cannot call 152 // Note that we have to do this in 2 passes as we cannot call
147 // CancelBlockedRequestsForRenderView while iterating over 153 // CancelBlockedRequestsForRenderView while iterating over
148 // blocked_requests_map_, as it modifies it. 154 // blocked_requests_map_, as it modifies it.
(...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after
561 567
562 // If we're resuming, kick the request to start reading again. Run the read 568 // If we're resuming, kick the request to start reading again. Run the read
563 // asynchronously to avoid recursion problems. 569 // asynchronously to avoid recursion problems.
564 if (info->pause_count == 0) { 570 if (info->pause_count == 0) {
565 MessageLoop::current()->PostTask(FROM_HERE, 571 MessageLoop::current()->PostTask(FROM_HERE,
566 method_runner_.NewRunnableMethod( 572 method_runner_.NewRunnableMethod(
567 &ResourceDispatcherHost::ResumeRequest, global_id)); 573 &ResourceDispatcherHost::ResumeRequest, global_id));
568 } 574 }
569 } 575 }
570 576
577 int ResourceDispatcherHost::GetOutstandingRequestsMemoryCost(
578 int render_process_host_id) const {
579 OutstandingRequestsMemoryCostMap::const_iterator entry =
580 outstanding_requests_memory_cost_map_.find(render_process_host_id);
581 return (entry == outstanding_requests_memory_cost_map_.end()) ?
582 0 : entry->second;
583 }
584
571 void ResourceDispatcherHost::OnClosePageACK(int render_process_host_id, 585 void ResourceDispatcherHost::OnClosePageACK(int render_process_host_id,
572 int request_id) { 586 int request_id) {
573 GlobalRequestID global_id(render_process_host_id, request_id); 587 GlobalRequestID global_id(render_process_host_id, request_id);
574 PendingRequestList::iterator i = pending_requests_.find(global_id); 588 PendingRequestList::iterator i = pending_requests_.find(global_id);
575 if (i == pending_requests_.end()) { 589 if (i == pending_requests_.end()) {
576 // If there are no matching pending requests, then this is not a 590 // If there are no matching pending requests, then this is not a
577 // cross-site navigation and we are just closing the tab/browser. 591 // cross-site navigation and we are just closing the tab/browser.
578 ui_loop_->PostTask(FROM_HERE, NewRunnableFunction( 592 ui_loop_->PostTask(FROM_HERE, NewRunnableFunction(
579 &RenderViewHost::ClosePageIgnoringUnloadEvents, 593 &RenderViewHost::ClosePageIgnoringUnloadEvents,
580 render_process_host_id, 594 render_process_host_id,
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
667 GlobalRequestID(render_process_host_id, request_id)); 681 GlobalRequestID(render_process_host_id, request_id));
668 if (i == pending_requests_.end()) { 682 if (i == pending_requests_.end()) {
669 NOTREACHED() << "Trying to remove a request that's not here"; 683 NOTREACHED() << "Trying to remove a request that's not here";
670 return; 684 return;
671 } 685 }
672 RemovePendingRequest(i); 686 RemovePendingRequest(i);
673 } 687 }
674 688
675 void ResourceDispatcherHost::RemovePendingRequest( 689 void ResourceDispatcherHost::RemovePendingRequest(
676 const PendingRequestList::iterator& iter) { 690 const PendingRequestList::iterator& iter) {
691 ExtraRequestInfo* info = ExtraInfoForRequest(iter->second);
692
693 // Remove the memory credit that we added when pushing the request onto
694 // the pending list.
695 IncrementOutstandingRequestsMemoryCost(-1 * info->memory_cost,
696 info->render_process_host_id);
697
677 // Notify the login handler that this request object is going away. 698 // Notify the login handler that this request object is going away.
678 ExtraRequestInfo* info = ExtraInfoForRequest(iter->second);
679 if (info && info->login_handler) 699 if (info && info->login_handler)
680 info->login_handler->OnRequestCancelled(); 700 info->login_handler->OnRequestCancelled();
681 701
682 delete iter->second; 702 delete iter->second;
683 pending_requests_.erase(iter); 703 pending_requests_.erase(iter);
684 704
685 // If we have no more pending requests, then stop the load state monitor 705 // If we have no more pending requests, then stop the load state monitor
686 if (pending_requests_.empty()) 706 if (pending_requests_.empty())
687 update_load_states_timer_.Stop(); 707 update_load_states_timer_.Stop();
688 } 708 }
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
816 DCHECK(!request->ssl_info().cert_status && 836 DCHECK(!request->ssl_info().cert_status &&
817 (request->ssl_info().security_bits == -1 || 837 (request->ssl_info().security_bits == -1 ||
818 request->ssl_info().security_bits == 0)); 838 request->ssl_info().security_bits == 0));
819 } 839 }
820 840
821 NotifyResponseStarted(request, info->render_process_host_id); 841 NotifyResponseStarted(request, info->render_process_host_id);
822 return info->resource_handler->OnResponseStarted(info->request_id, 842 return info->resource_handler->OnResponseStarted(info->request_id,
823 response.get()); 843 response.get());
824 } 844 }
825 845
846 int ResourceDispatcherHost::IncrementOutstandingRequestsMemoryCost(
847 int cost, int render_process_host_id) {
848 // Retrieve the previous value (defaulting to 0 if not found).
849 OutstandingRequestsMemoryCostMap::iterator prev_entry =
850 outstanding_requests_memory_cost_map_.find(render_process_host_id);
851 int new_cost = 0;
852 if (prev_entry != outstanding_requests_memory_cost_map_.end())
853 new_cost = prev_entry->second;
854
855 // Insert/update the total; delete entries when their value reaches 0.
856 new_cost += cost;
857 CHECK(new_cost >= 0);
858 if (new_cost == 0)
859 outstanding_requests_memory_cost_map_.erase(prev_entry);
860 else
861 outstanding_requests_memory_cost_map_[render_process_host_id] = new_cost;
862
863 return new_cost;
864 }
865
866 // static
867 int ResourceDispatcherHost::CalculateApproximateMemoryCost(
868 URLRequest* request) {
869 // The following fields should be a minor size contribution (experimentally
870 // on the order of 100). However since they are variable length, it could
871 // in theory be a sizeable contribution.
872 int strings_cost = request->extra_request_headers().size() +
873 request->original_url().spec().size() +
874 request->referrer().size() +
875 request->method().size();
876
877 int upload_cost = 0;
878
879 // TODO(eroman): don't enable the upload throttling until we have data
880 // showing what a reasonable limit is (restricting to 25MB of uploads may
881 // be too restrictive).
882 #if 0
883 // Sum all the (non-file) upload data attached to the request, if any.
884 if (request->has_upload()) {
885 const std::vector<net::UploadData::Element>& uploads =
886 request->get_upload()->elements();
887 std::vector<net::UploadData::Element>::const_iterator iter;
888 for (iter = uploads.begin(); iter != uploads.end(); ++iter) {
889 if (iter->type() == net::UploadData::TYPE_BYTES) {
890 int64 element_size = iter->GetContentLength();
891 // This cast should not result in truncation.
892 upload_cost += static_cast<int>(element_size);
893 }
894 }
895 }
896 #endif
897
898 // Note that this expression will typically be dominated by:
899 // |kAvgBytesPerOutstandingRequest|.
900 return kAvgBytesPerOutstandingRequest + strings_cost + upload_cost;
901 }
902
826 void ResourceDispatcherHost::BeginRequestInternal(URLRequest* request, 903 void ResourceDispatcherHost::BeginRequestInternal(URLRequest* request,
827 bool mixed_content) { 904 bool mixed_content) {
905 DCHECK(!request->is_pending());
828 ExtraRequestInfo* info = ExtraInfoForRequest(request); 906 ExtraRequestInfo* info = ExtraInfoForRequest(request);
829 907
908 // Add the memory estimate that starting this request will consume.
909 info->memory_cost = CalculateApproximateMemoryCost(request);
910 int memory_cost = IncrementOutstandingRequestsMemoryCost(
911 info->memory_cost,
912 info->render_process_host_id);
913
914 // If enqueing/starting this request will exceed our per-process memory
915 // bound, abort it right away.
916 if (memory_cost > max_outstanding_requests_cost_per_process_) {
917 // We call "CancelWithError()" as a way of setting the URLRequest's
918 // status -- it has no effect beyond this, since the request hasn't started.
919 request->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
920
921 // TODO(eroman): this is kinda funky -- we insert the unstarted request into
922 // |pending_requests_| simply to please OnResponseCompleted().
923 GlobalRequestID global_id(info->render_process_host_id, info->request_id);
924 pending_requests_[global_id] = request;
925 OnResponseCompleted(request);
926 return;
927 }
928
830 std::pair<int, int> pair_id(info->render_process_host_id, 929 std::pair<int, int> pair_id(info->render_process_host_id,
831 info->render_view_id); 930 info->render_view_id);
832 BlockedRequestMap::const_iterator iter = blocked_requests_map_.find(pair_id); 931 BlockedRequestMap::const_iterator iter = blocked_requests_map_.find(pair_id);
833 if (iter != blocked_requests_map_.end()) { 932 if (iter != blocked_requests_map_.end()) {
834 // The request should be blocked. 933 // The request should be blocked.
835 iter->second->push_back(BlockedRequest(request, mixed_content)); 934 iter->second->push_back(BlockedRequest(request, mixed_content));
836 return; 935 return;
837 } 936 }
838 937
839 GlobalRequestID global_id(info->render_process_host_id, info->request_id); 938 GlobalRequestID global_id(info->render_process_host_id, info->request_id);
(...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after
1310 return; 1409 return;
1311 } 1410 }
1312 1411
1313 BlockedRequestsList* requests = iter->second; 1412 BlockedRequestsList* requests = iter->second;
1314 1413
1315 // Removing the vector from the map unblocks any subsequent requests. 1414 // Removing the vector from the map unblocks any subsequent requests.
1316 blocked_requests_map_.erase(iter); 1415 blocked_requests_map_.erase(iter);
1317 1416
1318 for (BlockedRequestsList::iterator req_iter = requests->begin(); 1417 for (BlockedRequestsList::iterator req_iter = requests->begin();
1319 req_iter != requests->end(); ++req_iter) { 1418 req_iter != requests->end(); ++req_iter) {
1419 // Remove the memory credit that we added when pushing the request onto
1420 // the blocked list.
1421 ExtraRequestInfo* info = ExtraInfoForRequest(req_iter->url_request);
1422 IncrementOutstandingRequestsMemoryCost(-1 * info->memory_cost,
1423 info->render_process_host_id);
1320 if (cancel_requests) 1424 if (cancel_requests)
1321 delete req_iter->url_request; 1425 delete req_iter->url_request;
1322 else 1426 else
1323 BeginRequestInternal(req_iter->url_request, req_iter->mixed_content); 1427 BeginRequestInternal(req_iter->url_request, req_iter->mixed_content);
1324 } 1428 }
1325 1429
1326 delete requests; 1430 delete requests;
1327 } 1431 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698