multi_threaded_proxy_resolver.h revision c407dc5cd9bdc5668497f21b26b09d988ab439de
1// Copyright (c) 2010 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 NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_
6#define NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_
7
8#include <deque>
9#include <string>
10#include <vector>
11
12#include "base/basictypes.h"
13#include "base/non_thread_safe.h"
14#include "base/ref_counted.h"
15#include "base/scoped_ptr.h"
16#include "net/proxy/proxy_resolver.h"
17
18namespace base {
19class Thread;
20}  // namespace base
21
22namespace net {
23
24// ProxyResolverFactory is an interface for creating ProxyResolver instances.
25class ProxyResolverFactory {
26 public:
27  explicit ProxyResolverFactory(bool resolvers_expect_pac_bytes)
28      : resolvers_expect_pac_bytes_(resolvers_expect_pac_bytes) {}
29
30  virtual ~ProxyResolverFactory() {}
31
32  // Creates a new ProxyResolver. The caller is responsible for freeing this
33  // object.
34  virtual ProxyResolver* CreateProxyResolver() = 0;
35
36  bool resolvers_expect_pac_bytes() const {
37    return resolvers_expect_pac_bytes_;
38  }
39
40 private:
41  bool resolvers_expect_pac_bytes_;
42  DISALLOW_COPY_AND_ASSIGN(ProxyResolverFactory);
43};
44
45// MultiThreadedProxyResolver is a ProxyResolver implementation that runs
46// synchronous ProxyResolver implementations on worker threads.
47//
48// Threads are created lazily on demand, up to a maximum total. The advantage
49// of having a pool of threads, is faster performance. In particular, being
50// able to keep servicing PAC requests even if one blocks its execution.
51//
52// During initialization (SetPacScript), a single thread is spun up to test
53// the script. If this succeeds, we cache the input script, and will re-use
54// this to lazily provision any new threads as needed.
55//
56// For each new thread that we spawn, a corresponding new ProxyResolver is
57// created using ProxyResolverFactory.
58//
59// Because we are creating multiple ProxyResolver instances, this means we
60// are duplicating script contexts for what is ordinarily seen as being a
61// single script. This can affect compatibility on some classes of PAC
62// script:
63//
64// (a) Scripts whose initialization has external dependencies on network or
65//     time may end up successfully initializing on some threads, but not
66//     others. So depending on what thread services the request, the result
67//     may jump between several possibilities.
68//
69// (b) Scripts whose FindProxyForURL() depends on side-effects may now
70//     work differently. For example, a PAC script which was incrementing
71//     a global counter and using that to make a decision. In the
72//     multi-threaded model, each thread may have a different value for this
73//     counter, so it won't globally be seen as monotonically increasing!
74class MultiThreadedProxyResolver : public ProxyResolver, public NonThreadSafe {
75 public:
76  // Creates an asynchronous ProxyResolver that runs requests on up to
77  // |max_num_threads|.
78  //
79  // For each thread that is created, an accompanying synchronous ProxyResolver
80  // will be provisioned using |resolver_factory|. All methods on these
81  // ProxyResolvers will be called on the one thread, with the exception of
82  // ProxyResolver::Shutdown() which will be called from the origin thread
83  // prior to destruction.
84  //
85  // The constructor takes ownership of |resolver_factory|.
86  MultiThreadedProxyResolver(ProxyResolverFactory* resolver_factory,
87                             size_t max_num_threads);
88
89  virtual ~MultiThreadedProxyResolver();
90
91  // ProxyResolver implementation:
92  virtual int GetProxyForURL(const GURL& url,
93                             ProxyInfo* results,
94                             CompletionCallback* callback,
95                             RequestHandle* request,
96                             const BoundNetLog& net_log);
97  virtual void CancelRequest(RequestHandle request);
98  virtual void CancelSetPacScript();
99  virtual void PurgeMemory();
100  virtual int SetPacScript(
101      const scoped_refptr<ProxyResolverScriptData>& script_data,
102      CompletionCallback* callback);
103
104 private:
105  class Executor;
106  class Job;
107  class SetPacScriptJob;
108  class GetProxyForURLJob;
109  // FIFO queue of pending jobs waiting to be started.
110  // TODO(eroman): Make this priority queue.
111  typedef std::deque<scoped_refptr<Job> > PendingJobsQueue;
112  typedef std::vector<scoped_refptr<Executor> > ExecutorList;
113
114  // Asserts that there are no outstanding user-initiated jobs on any of the
115  // worker threads.
116  void CheckNoOutstandingUserRequests() const;
117
118  // Stops and deletes all of the worker threads.
119  void ReleaseAllExecutors();
120
121  // Returns an idle worker thread which is ready to receive GetProxyForURL()
122  // requests. If all threads are occupied, returns NULL.
123  Executor* FindIdleExecutor();
124
125  // Creates a new worker thread, and appends it to |executors_|.
126  Executor* AddNewExecutor();
127
128  // Starts the next job from |pending_jobs_| if possible.
129  void OnExecutorReady(Executor* executor);
130
131  const scoped_ptr<ProxyResolverFactory> resolver_factory_;
132  const size_t max_num_threads_;
133  PendingJobsQueue pending_jobs_;
134  ExecutorList executors_;
135  scoped_refptr<ProxyResolverScriptData> current_script_data_;
136};
137
138}  // namespace net
139
140#endif  // NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_
141