OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |