Home | History | Annotate | Download | only in loader
      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.
      4 
      5 #ifndef CONTENT_BROWSER_LOADER_RESOURCE_SCHEDULER_H_
      6 #define CONTENT_BROWSER_LOADER_RESOURCE_SCHEDULER_H_
      7 
      8 #include <map>
      9 #include <set>
     10 
     11 #include "base/basictypes.h"
     12 #include "base/compiler_specific.h"
     13 #include "base/memory/scoped_ptr.h"
     14 #include "base/threading/non_thread_safe.h"
     15 #include "base/timer/timer.h"
     16 #include "content/common/content_export.h"
     17 #include "net/base/priority_queue.h"
     18 #include "net/base/request_priority.h"
     19 
     20 namespace net {
     21 class HostPortPair;
     22 class URLRequest;
     23 }
     24 
     25 namespace content {
     26 class ResourceThrottle;
     27 
     28 // There is one ResourceScheduler. All renderer-initiated HTTP requests are
     29 // expected to pass through it.
     30 //
     31 // There are two types of input to the scheduler:
     32 // 1. Requests to start, cancel, or finish fetching a resource.
     33 // 2. Notifications for renderer events, such as new tabs, navigation and
     34 //    painting.
     35 //
     36 // These input come from different threads, so they may not be in sync. The UI
     37 // thread is considered the authority on renderer lifetime, which means some
     38 // IPCs may be meaningless if they arrive after the UI thread signals a renderer
     39 // has been deleted.
     40 //
     41 // The ResourceScheduler tracks many Clients, which should correlate with tabs.
     42 // A client is uniquely identified by its child_id and route_id.
     43 //
     44 // Each Client may have many Requests in flight. Requests are uniquely
     45 // identified within a Client by its ScheduledResourceRequest.
     46 //
     47 // Users should call ScheduleRequest() to notify this ResourceScheduler of a
     48 // new request. The returned ResourceThrottle should be destroyed when the load
     49 // finishes or is canceled.
     50 //
     51 // The scheduler may defer issuing the request via the ResourceThrottle
     52 // interface or it may alter the request's priority by calling set_priority() on
     53 // the URLRequest.
     54 class CONTENT_EXPORT ResourceScheduler : public base::NonThreadSafe {
     55  public:
     56   enum ClientThrottleState {
     57     // TODO(aiolos): Add logic to ShouldStartRequest for PAUSED Clients to only
     58     // issue synchronous requests.
     59     // TODO(aiolos): Add max number of THROTTLED Clients, and logic to set
     60     // subsquent Clients to PAUSED instead. Also add logic to unpause a Client
     61     // when a background Client becomes COALESCED (ie, finishes loading.)
     62     // TODO(aiolos): Add tests for the above mentioned logic.
     63 
     64     // Currently being deleted client.
     65     // This state currently follows the same logic for loading requests as
     66     // UNTHROTTLED/ACTIVE_AND_LOADING Clients. See above TODO's.
     67     PAUSED,
     68     // Loaded background client, all observable clients loaded.
     69     COALESCED,
     70     // Background client, an observable client is loading.
     71     THROTTLED,
     72     // Observable (active) loaded client or
     73     // Loading background client, all observable clients loaded.
     74     // Note that clients which would be COALESCED are UNTHROTTLED until
     75     // coalescing is turned on.
     76     UNTHROTTLED,
     77     // Observable (active) loading client.
     78     ACTIVE_AND_LOADING,
     79   };
     80 
     81   enum RequestClassification {
     82     NORMAL_REQUEST,
     83     // Low priority in-flight requests
     84     IN_FLIGHT_DELAYABLE_REQUEST,
     85     // High-priority requests received before the renderer has a <body>
     86     LAYOUT_BLOCKING_REQUEST,
     87   };
     88 
     89   ResourceScheduler();
     90   ~ResourceScheduler();
     91 
     92   // Use a mock timer when testing.
     93   void set_timer_for_testing(scoped_ptr<base::Timer> timer) {
     94     coalescing_timer_.reset(timer.release());
     95   }
     96 
     97   // TODO(aiolos): Remove when throttling and coalescing have landed
     98   void SetThrottleOptionsForTesting(bool should_throttle, bool should_coalesce);
     99 
    100   bool should_coalesce() const { return should_coalesce_; }
    101   bool should_throttle() const { return should_throttle_; }
    102 
    103   ClientThrottleState GetClientStateForTesting(int child_id, int route_id);
    104 
    105   // Requests that this ResourceScheduler schedule, and eventually loads, the
    106   // specified |url_request|. Caller should delete the returned ResourceThrottle
    107   // when the load completes or is canceled.
    108   scoped_ptr<ResourceThrottle> ScheduleRequest(
    109       int child_id, int route_id, net::URLRequest* url_request);
    110 
    111   // Signals from the UI thread, posted as tasks on the IO thread:
    112 
    113   // Called when a renderer is created.
    114   void OnClientCreated(int child_id, int route_id, bool is_visible);
    115 
    116   // Called when a renderer is destroyed.
    117   void OnClientDeleted(int child_id, int route_id);
    118 
    119   // Called when a renderer stops or restarts loading.
    120   void OnLoadingStateChanged(int child_id, int route_id, bool is_loaded);
    121 
    122   // Called when a Client is shown or hidden.
    123   void OnVisibilityChanged(int child_id, int route_id, bool is_visible);
    124 
    125   // Signals from IPC messages directly from the renderers:
    126 
    127   // Called when a client navigates to a new main document.
    128   void OnNavigate(int child_id, int route_id);
    129 
    130   // Called when the client has parsed the <body> element. This is a signal that
    131   // resource loads won't interfere with first paint.
    132   void OnWillInsertBody(int child_id, int route_id);
    133 
    134   // Signals from the IO thread:
    135 
    136   // Called when we received a response to a http request that was served
    137   // from a proxy using SPDY.
    138   void OnReceivedSpdyProxiedHttpResponse(int child_id, int route_id);
    139 
    140   // Client functions:
    141 
    142   // Called to check if all user observable tabs have completed loading.
    143   bool active_clients_loaded() const { return active_clients_loading_ == 0; }
    144 
    145   // Called when a Client starts or stops playing audio.
    146   void OnAudibilityChanged(int child_id, int route_id, bool is_audible);
    147 
    148   bool IsClientVisibleForTesting(int child_id, int route_id);
    149 
    150  private:
    151   class RequestQueue;
    152   class ScheduledResourceRequest;
    153   struct RequestPriorityParams;
    154   struct ScheduledResourceSorter {
    155     bool operator()(const ScheduledResourceRequest* a,
    156                     const ScheduledResourceRequest* b) const;
    157   };
    158   class Client;
    159 
    160   typedef int64 ClientId;
    161   typedef std::map<ClientId, Client*> ClientMap;
    162   typedef std::set<ScheduledResourceRequest*> RequestSet;
    163 
    164   // Called when a ScheduledResourceRequest is destroyed.
    165   void RemoveRequest(ScheduledResourceRequest* request);
    166 
    167   // These calls may update the ThrottleState of all clients, and have the
    168   // potential to be re-entrant.
    169   // Called when a Client newly becomes active loading.
    170   void IncrementActiveClientsLoading();
    171   // Called when an active and loading Client either completes loading or
    172   // becomes inactive.
    173   void DecrementActiveClientsLoading();
    174 
    175   void OnLoadingActiveClientsStateChangedForAllClients();
    176 
    177   size_t CountActiveClientsLoading() const;
    178 
    179   // Called when a Client becomes coalesced.
    180   void IncrementCoalescedClients();
    181   // Called when a client stops being coalesced.
    182   void DecrementCoalescedClients();
    183 
    184   void LoadCoalescedRequests();
    185 
    186   size_t CountCoalescedClients() const;
    187 
    188   // Update the queue position for |request|, possibly causing it to start
    189   // loading.
    190   //
    191   // Queues are maintained for each priority level. When |request| is
    192   // reprioritized, it will move to the end of the queue for that priority
    193   // level.
    194   void ReprioritizeRequest(ScheduledResourceRequest* request,
    195                            net::RequestPriority new_priority,
    196                            int intra_priority_value);
    197 
    198   // Returns the client ID for the given |child_id| and |route_id| combo.
    199   ClientId MakeClientId(int child_id, int route_id);
    200 
    201   // Returns the client for the given |child_id| and |route_id| combo.
    202   Client* GetClient(int child_id, int route_id);
    203 
    204   bool should_coalesce_;
    205   bool should_throttle_;
    206   ClientMap client_map_;
    207   size_t active_clients_loading_;
    208   size_t coalesced_clients_;
    209   // This is a repeating timer to initiate requests on COALESCED Clients.
    210   scoped_ptr<base::Timer> coalescing_timer_;
    211   RequestSet unowned_requests_;
    212 };
    213 
    214 }  // namespace content
    215 
    216 #endif  // CONTENT_BROWSER_LOADER_RESOURCE_SCHEDULER_H_
    217