191 lines
6.1 KiB
Java
191 lines
6.1 KiB
Java
/* GENERATED SOURCE. DO NOT MODIFY. */
|
|
/*
|
|
* Copyright (C) 2013 Square, Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
package com.android.okhttp;
|
|
|
|
import com.android.okhttp.Call.AsyncCall;
|
|
import com.android.okhttp.internal.Util;
|
|
import com.android.okhttp.internal.http.HttpEngine;
|
|
import java.util.ArrayDeque;
|
|
import java.util.Deque;
|
|
import java.util.Iterator;
|
|
import java.util.concurrent.ExecutorService;
|
|
import java.util.concurrent.SynchronousQueue;
|
|
import java.util.concurrent.ThreadPoolExecutor;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
/**
|
|
* Policy on when async requests are executed.
|
|
*
|
|
* <p>Each dispatcher uses an {@link ExecutorService} to run calls internally. If you
|
|
* supply your own executor, it should be able to run {@linkplain #getMaxRequests the
|
|
* configured maximum} number of calls concurrently.
|
|
* @hide This class is not part of the Android public SDK API
|
|
*/
|
|
public final class Dispatcher {
|
|
private int maxRequests = 64;
|
|
private int maxRequestsPerHost = 5;
|
|
|
|
/** Executes calls. Created lazily. */
|
|
private ExecutorService executorService;
|
|
|
|
/** Ready calls in the order they'll be run. */
|
|
private final Deque<AsyncCall> readyCalls = new ArrayDeque<>();
|
|
|
|
/** Running calls. Includes canceled calls that haven't finished yet. */
|
|
private final Deque<AsyncCall> runningCalls = new ArrayDeque<>();
|
|
|
|
/** In-flight synchronous calls. Includes canceled calls that haven't finished yet. */
|
|
private final Deque<Call> executedCalls = new ArrayDeque<>();
|
|
|
|
public Dispatcher(ExecutorService executorService) {
|
|
this.executorService = executorService;
|
|
}
|
|
|
|
public Dispatcher() {
|
|
}
|
|
|
|
public synchronized ExecutorService getExecutorService() {
|
|
if (executorService == null) {
|
|
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
|
|
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
|
|
}
|
|
return executorService;
|
|
}
|
|
|
|
/**
|
|
* Set the maximum number of requests to execute concurrently. Above this
|
|
* requests queue in memory, waiting for the running calls to complete.
|
|
*
|
|
* <p>If more than {@code maxRequests} requests are in flight when this is
|
|
* invoked, those requests will remain in flight.
|
|
*/
|
|
public synchronized void setMaxRequests(int maxRequests) {
|
|
if (maxRequests < 1) {
|
|
throw new IllegalArgumentException("max < 1: " + maxRequests);
|
|
}
|
|
this.maxRequests = maxRequests;
|
|
promoteCalls();
|
|
}
|
|
|
|
public synchronized int getMaxRequests() {
|
|
return maxRequests;
|
|
}
|
|
|
|
/**
|
|
* Set the maximum number of requests for each host to execute concurrently.
|
|
* This limits requests by the URL's host name. Note that concurrent requests
|
|
* to a single IP address may still exceed this limit: multiple hostnames may
|
|
* share an IP address or be routed through the same HTTP proxy.
|
|
*
|
|
* <p>If more than {@code maxRequestsPerHost} requests are in flight when this
|
|
* is invoked, those requests will remain in flight.
|
|
*/
|
|
public synchronized void setMaxRequestsPerHost(int maxRequestsPerHost) {
|
|
if (maxRequestsPerHost < 1) {
|
|
throw new IllegalArgumentException("max < 1: " + maxRequestsPerHost);
|
|
}
|
|
this.maxRequestsPerHost = maxRequestsPerHost;
|
|
promoteCalls();
|
|
}
|
|
|
|
public synchronized int getMaxRequestsPerHost() {
|
|
return maxRequestsPerHost;
|
|
}
|
|
|
|
synchronized void enqueue(AsyncCall call) {
|
|
if (runningCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
|
|
runningCalls.add(call);
|
|
getExecutorService().execute(call);
|
|
} else {
|
|
readyCalls.add(call);
|
|
}
|
|
}
|
|
|
|
/** Cancel all calls with the tag {@code tag}. */
|
|
public synchronized void cancel(Object tag) {
|
|
for (AsyncCall call : readyCalls) {
|
|
if (Util.equal(tag, call.tag())) {
|
|
call.cancel();
|
|
}
|
|
}
|
|
|
|
for (AsyncCall call : runningCalls) {
|
|
if (Util.equal(tag, call.tag())) {
|
|
call.get().canceled = true;
|
|
HttpEngine engine = call.get().engine;
|
|
if (engine != null) engine.cancel();
|
|
}
|
|
}
|
|
|
|
for (Call call : executedCalls) {
|
|
if (Util.equal(tag, call.tag())) {
|
|
call.cancel();
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Used by {@code AsyncCall#run} to signal completion. */
|
|
synchronized void finished(AsyncCall call) {
|
|
if (!runningCalls.remove(call)) throw new AssertionError("AsyncCall wasn't running!");
|
|
promoteCalls();
|
|
}
|
|
|
|
private void promoteCalls() {
|
|
if (runningCalls.size() >= maxRequests) return; // Already running max capacity.
|
|
if (readyCalls.isEmpty()) return; // No ready calls to promote.
|
|
|
|
for (Iterator<AsyncCall> i = readyCalls.iterator(); i.hasNext(); ) {
|
|
AsyncCall call = i.next();
|
|
|
|
if (runningCallsForHost(call) < maxRequestsPerHost) {
|
|
i.remove();
|
|
runningCalls.add(call);
|
|
getExecutorService().execute(call);
|
|
}
|
|
|
|
if (runningCalls.size() >= maxRequests) return; // Reached max capacity.
|
|
}
|
|
}
|
|
|
|
/** Returns the number of running calls that share a host with {@code call}. */
|
|
private int runningCallsForHost(AsyncCall call) {
|
|
int result = 0;
|
|
for (AsyncCall c : runningCalls) {
|
|
if (c.host().equals(call.host())) result++;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/** Used by {@code Call#execute} to signal it is in-flight. */
|
|
synchronized void executed(Call call) {
|
|
executedCalls.add(call);
|
|
}
|
|
|
|
/** Used by {@code Call#execute} to signal completion. */
|
|
synchronized void finished(Call call) {
|
|
if (!executedCalls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
|
|
}
|
|
|
|
public synchronized int getRunningCallCount() {
|
|
return runningCalls.size();
|
|
}
|
|
|
|
public synchronized int getQueuedCallCount() {
|
|
return readyCalls.size();
|
|
}
|
|
}
|