Index: net/proxy/multi_threaded_proxy_resolver.h |
=================================================================== |
--- net/proxy/multi_threaded_proxy_resolver.h (revision 51914) |
+++ net/proxy/multi_threaded_proxy_resolver.h (working copy) |
@@ -2,12 +2,15 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-#ifndef NET_PROXY_SINGLE_THREADED_PROXY_RESOLVER_H_ |
-#define NET_PROXY_SINGLE_THREADED_PROXY_RESOLVER_H_ |
+#ifndef NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_ |
+#define NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_ |
#include <deque> |
#include <string> |
+#include <vector> |
+#include "base/basictypes.h" |
+#include "base/non_thread_safe.h" |
#include "base/ref_counted.h" |
#include "base/scoped_ptr.h" |
#include "net/proxy/proxy_resolver.h" |
@@ -18,18 +21,73 @@ |
namespace net { |
-// ProxyResolver implementation that wraps a synchronous ProxyResolver, and |
-// runs it on a single worker thread. If multiple requests accumulate, they |
-// are serviced in FIFO order. |
-class SingleThreadedProxyResolver : public ProxyResolver { |
+// ProxyResolverFactory is an interface for creating ProxyResolver instances. |
+class ProxyResolverFactory { |
public: |
- // |resolver| is a synchronous ProxyResolver implementation. It doesn't |
- // have to be thread-safe, since it is run on exactly one thread. The |
- // constructor takes ownership of |resolver|. |
- explicit SingleThreadedProxyResolver(ProxyResolver* resolver); |
+ explicit ProxyResolverFactory(bool resolvers_expect_pac_bytes) |
+ : resolvers_expect_pac_bytes_(resolvers_expect_pac_bytes) {} |
- virtual ~SingleThreadedProxyResolver(); |
+ virtual ~ProxyResolverFactory() {} |
+ // Creates a new ProxyResolver. The caller is responsible for freeing this |
+ // object. |
+ virtual ProxyResolver* CreateProxyResolver() = 0; |
+ |
+ bool resolvers_expect_pac_bytes() const { |
+ return resolvers_expect_pac_bytes_; |
+ } |
+ |
+ private: |
+ bool resolvers_expect_pac_bytes_; |
+ DISALLOW_COPY_AND_ASSIGN(ProxyResolverFactory); |
+}; |
+ |
+// MultiThreadedProxyResolver is a ProxyResolver implementation that runs |
+// synchronous ProxyResolver implementations on worker threads. |
+// |
+// Threads are created lazily on demand, up to a maximum total. The advantage |
+// of having a pool of threads, is faster performance. In particular, being |
+// able to keep servicing PAC requests even if one blocks its execution. |
+// |
+// During initialization (SetPacScript), a single thread is spun up to test |
+// the script. If this succeeds, we cache the input script, and will re-use |
+// this to lazily provision any new threads as needed. |
+// |
+// For each new thread that we spawn, a corresponding new ProxyResolver is |
+// created using ProxyResolverFactory. |
+// |
+// Because we are creating multiple ProxyResolver instances, this means we |
+// are duplicating script contexts for what is ordinarily seen as being a |
+// single script. This can affect compatibility on some classes of PAC |
+// script: |
+// |
+// (a) Scripts whose initialization has external dependencies on network or |
+// time may end up successfully initializing on some threads, but not |
+// others. So depending on what thread services the request, the result |
+// may jump between several possibilities. |
+// |
+// (b) Scripts whose FindProxyForURL() depends on side-effects may now |
+// work differently. For example, a PAC script which was incrementing |
+// a global counter and using that to make a decision. In the |
+// multi-threaded model, each thread may have a different value for this |
+// counter, so it won't globally be seen as monotonically increasing! |
+class MultiThreadedProxyResolver : public ProxyResolver, public NonThreadSafe { |
+ public: |
+ // Creates an asynchronous ProxyResolver that runs requests on up to |
+ // |max_num_threads|. |
+ // |
+ // For each thread that is created, an accompanying synchronous ProxyResolver |
+ // will be provisioned using |resolver_factory|. All methods on these |
+ // ProxyResolvers will be called on the one thread, with the exception of |
+ // ProxyResolver::Shutdown() which will be called from the origin thread |
+ // prior to destruction. |
+ // |
+ // The constructor takes ownership of |resolver_factory|. |
+ MultiThreadedProxyResolver(ProxyResolverFactory* resolver_factory, |
+ size_t max_num_threads); |
+ |
+ virtual ~MultiThreadedProxyResolver(); |
+ |
// ProxyResolver implementation: |
virtual int GetProxyForURL(const GURL& url, |
ProxyInfo* results, |
@@ -40,55 +98,47 @@ |
virtual void CancelSetPacScript(); |
virtual void PurgeMemory(); |
- protected: |
- // The wrapped (synchronous) ProxyResolver. |
- ProxyResolver* resolver() { return resolver_.get(); } |
- |
private: |
- // Refcounted helper class that bridges between origin thread and worker |
- // thread. |
+ class Executor; |
class Job; |
- friend class Job; |
- class SetPacScriptTask; |
- friend class SetPacScriptTask; |
- // FIFO queue that contains the in-progress job, and any pending jobs. |
+ class SetPacScriptJob; |
+ class GetProxyForURLJob; |
+ // FIFO queue of pending jobs waiting to be started. |
+ // TODO(eroman): Make this priority queue. |
typedef std::deque<scoped_refptr<Job> > PendingJobsQueue; |
+ typedef std::vector<scoped_refptr<Executor> > ExecutorList; |
- base::Thread* thread() { return thread_.get(); } |
- |
// ProxyResolver implementation: |
virtual int SetPacScript(const GURL& pac_url, |
const string16& pac_script, |
CompletionCallback* callback); |
- // Starts the worker thread if it isn't already running. |
- void EnsureThreadStarted(); |
+ // Asserts that there are no outstanding user-initiated jobs on any of the |
+ // worker threads. |
+ void CheckNoOutstandingUserRequests() const; |
- // Starts the next job from |pending_jobs_| if possible. |
- void ProcessPendingJobs(); |
+ // Stops and deletes all of the worker threads. |
+ void ReleaseAllExecutors(); |
- // Removes the front entry of the jobs queue. |expected_job| is our |
- // expectation of what the front of the job queue is; it is only used by |
- // DCHECK for verification purposes. |
- void RemoveFrontOfJobsQueueAndStartNext(Job* expected_job); |
+ // Returns an idle worker thread which is ready to receive GetProxyForURL() |
+ // requests. If all threads are occupied, returns NULL. |
+ Executor* FindIdleExecutor(); |
- // Clears |outstanding_set_pac_script_task_|. |
- // Called when |task| has just finished. |
- void RemoveOutstandingSetPacScriptTask(SetPacScriptTask* task); |
+ // Creates a new worker thread, and appends it to |executors_|. |
+ Executor* AddNewExecutor(); |
- // The synchronous resolver implementation. |
- scoped_ptr<ProxyResolver> resolver_; |
+ // Starts the next job from |pending_jobs_| if possible. |
+ void OnExecutorReady(Executor* executor); |
- // The thread where |resolver_| is run on. |
- // Note that declaration ordering is important here. |thread_| needs to be |
- // destroyed *before* |resolver_|, in case |resolver_| is currently |
- // executing on |thread_|. |
- scoped_ptr<base::Thread> thread_; |
- |
+ const scoped_ptr<ProxyResolverFactory> resolver_factory_; |
+ const size_t max_num_threads_; |
PendingJobsQueue pending_jobs_; |
- scoped_refptr<SetPacScriptTask> outstanding_set_pac_script_task_; |
+ ExecutorList executors_; |
+ bool was_set_pac_script_called_; |
+ GURL current_pac_url_; |
+ string16 current_pac_script_; |
}; |
} // namespace net |
-#endif // NET_PROXY_SINGLE_THREADED_PROXY_RESOLVER_H_ |
+#endif // NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_ |