1faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath/* 2faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath * Licensed to the Apache Software Foundation (ASF) under one or more 3faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath * contributor license agreements. See the NOTICE file distributed with 4faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath * this work for additional information regarding copyright ownership. 5faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath * The ASF licenses this file to You under the Apache License, Version 2.0 6faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath * (the "License"); you may not use this file except in compliance with 7faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath * the License. You may obtain a copy of the License at 8faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath * 9faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath * http://www.apache.org/licenses/LICENSE-2.0 10faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath * 11faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath * Unless required by applicable law or agreed to in writing, software 12faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath * distributed under the License is distributed on an "AS IS" BASIS, 13faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath * See the License for the specific language governing permissions and 15faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath * limitations under the License. 16faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath */ 172231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonpackage com.squareup.okhttp; 182231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 192231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport com.squareup.okhttp.internal.Platform; 202231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport com.squareup.okhttp.internal.Util; 212231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.net.SocketException; 222231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.util.ArrayList; 2354cf3446000fdcf88a9e62724f7deb0282e98da1jwilsonimport java.util.LinkedList; 242231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.util.List; 257407d6984ce69693097befc9b72609a8156463bbNarayan Kamathimport java.util.ListIterator; 2654cf3446000fdcf88a9e62724f7deb0282e98da1jwilsonimport java.util.concurrent.ExecutorService; 2754cf3446000fdcf88a9e62724f7deb0282e98da1jwilsonimport java.util.concurrent.LinkedBlockingQueue; 2854cf3446000fdcf88a9e62724f7deb0282e98da1jwilsonimport java.util.concurrent.ThreadPoolExecutor; 2954cf3446000fdcf88a9e62724f7deb0282e98da1jwilsonimport java.util.concurrent.TimeUnit; 302231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 312231db3e6bb54447a9b14cf004a6cb03c373651cjwilson/** 322231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * Manages reuse of HTTP and SPDY connections for reduced network latency. HTTP 3354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * requests that share the same {@link com.squareup.okhttp.Address} may share a 3454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * {@link com.squareup.okhttp.Connection}. This class implements the policy of 3554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * which connections to keep open for future use. 362231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * 372231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * <p>The {@link #getDefault() system-wide default} uses system properties for 382231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * tuning parameters: 392231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * <ul> 4054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * <li>{@code http.keepAlive} true if HTTP and SPDY connections should be 4154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * pooled at all. Default is true. 4254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * <li>{@code http.maxConnections} maximum number of idle connections to 4354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * each to keep in the pool. Default is 5. 4454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * <li>{@code http.keepAliveDuration} Time in milliseconds to keep the 4554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * connection alive in the pool before closing it. Default is 5 minutes. 4654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * This property isn't used by {@code HttpURLConnection}. 472231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * </ul> 482231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * 492231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * <p>The default instance <i>doesn't</i> adjust its configuration as system 502231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * properties are changed. This assumes that the applications that set these 512231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * parameters do so before making HTTP connections, and that this class is 522231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * initialized lazily. 532231db3e6bb54447a9b14cf004a6cb03c373651cjwilson */ 5454cf3446000fdcf88a9e62724f7deb0282e98da1jwilsonpublic class ConnectionPool { 5554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private static final int MAX_CONNECTIONS_TO_CLEANUP = 2; 5654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private static final long DEFAULT_KEEP_ALIVE_DURATION_MS = 5 * 60 * 1000; // 5 min 5754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 5854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private static final ConnectionPool systemDefault; 5954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 6054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson static { 6154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String keepAlive = System.getProperty("http.keepAlive"); 6254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String keepAliveDuration = System.getProperty("http.keepAliveDuration"); 6354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String maxIdleConnections = System.getProperty("http.maxConnections"); 6454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson long keepAliveDurationMs = keepAliveDuration != null ? Long.parseLong(keepAliveDuration) 6554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson : DEFAULT_KEEP_ALIVE_DURATION_MS; 6654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (keepAlive != null && !Boolean.parseBoolean(keepAlive)) { 6754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson systemDefault = new ConnectionPool(0, keepAliveDurationMs); 6854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } else if (maxIdleConnections != null) { 6954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson systemDefault = new ConnectionPool(Integer.parseInt(maxIdleConnections), keepAliveDurationMs); 7054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } else { 7154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson systemDefault = new ConnectionPool(5, keepAliveDurationMs); 722231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 7354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 7454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 7554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** The maximum number of idle connections for each address. */ 7654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private final int maxIdleConnections; 7754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private final long keepAliveDurationNs; 7854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 7954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private final LinkedList<Connection> connections = new LinkedList<Connection>(); 802231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 8154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** We use a single background thread to cleanup expired connections. */ 82faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath private final ExecutorService executorService = new ThreadPoolExecutor(0, 1, 83faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), 843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Util.threadFactory("OkHttp ConnectionPool", true)); 85f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller 86f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller private enum CleanMode { 87f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller /** 88f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller * Connection clean up is driven by usage of the pool. Each usage of the pool can schedule a 89f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller * clean up. A pool left in this state and unused may contain idle connections indefinitely. 90f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller */ 91f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller NORMAL, 92f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller /** 936257f0c1c5e6e94d446051f856207782d7188c43Neil Fuller * Entered when a pool has been orphaned and is not expected to receive more usage, except for 94f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller * references held by existing connections. See {@link #enterDrainMode()}. 95f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller * A thread runs periodically to close idle connections in the pool until the pool is empty and 96f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller * then the state moves to {@link #DRAINED}. 97f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller */ 98f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller DRAINING, 99f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller /** 100f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller * The pool is empty and no clean-up is taking place. Connections may still be added to the 101f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller * pool due to latent references to the pool, in which case the pool re-enters 102f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller * {@link #DRAINING}. If the pool is DRAINED and no longer referenced it is safe to be garbage 103f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller * collected. 104f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller */ 105f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller DRAINED 106f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller } 107f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller /** The current mode for cleaning connections in the pool */ 108f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller private CleanMode cleanMode = CleanMode.NORMAL; 109f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller 110f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller // A scheduled drainModeRunnable keeps a reference to the enclosing ConnectionPool, 111f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller // preventing the ConnectionPool from being garbage collected before all held connections have 112f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller // been explicitly closed. If this was not the case any open connections in the pool would trigger 113f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller // StrictMode violations in Android when they were garbage collected. http://b/18369687 114f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller private final Runnable drainModeRunnable = new Runnable() { 115f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller @Override public void run() { 116f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller // Close any connections we can. 117f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller connectionsCleanupRunnable.run(); 118f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller 119f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller synchronized (ConnectionPool.this) { 120f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller // See whether we should continue checking the connection pool. 121f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller if (connections.size() > 0) { 122f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller // Pause to avoid checking too regularly, which would drain the battery on mobile 123f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller // devices. The wait() surrenders the pool monitor and will not block other calls. 124f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller try { 125f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller // Use the keep alive duration as a rough indicator of a good check interval. 126f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller long keepAliveDurationMillis = keepAliveDurationNs / (1000 * 1000); 127f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller ConnectionPool.this.wait(keepAliveDurationMillis); 128f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller } catch (InterruptedException e) { 129f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller // Ignored. 130f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller } 131f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller 132f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller // Reschedule "this" to perform another clean-up. 133f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller executorService.execute(this); 134f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller } else { 135f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller cleanMode = CleanMode.DRAINED; 136f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller } 137f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller } 138f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller } 139f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller }; 140f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller 1413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private final Runnable connectionsCleanupRunnable = new Runnable() { 1423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public void run() { 14354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<Connection> expiredConnections = new ArrayList<Connection>(MAX_CONNECTIONS_TO_CLEANUP); 14454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson int idleConnectionCount = 0; 14554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson synchronized (ConnectionPool.this) { 1467407d6984ce69693097befc9b72609a8156463bbNarayan Kamath for (ListIterator<Connection> i = connections.listIterator(connections.size()); 1477407d6984ce69693097befc9b72609a8156463bbNarayan Kamath i.hasPrevious(); ) { 1487407d6984ce69693097befc9b72609a8156463bbNarayan Kamath Connection connection = i.previous(); 14954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (!connection.isAlive() || connection.isExpired(keepAliveDurationNs)) { 15054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson i.remove(); 15154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson expiredConnections.add(connection); 15254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (expiredConnections.size() == MAX_CONNECTIONS_TO_CLEANUP) break; 15354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } else if (connection.isIdle()) { 15454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson idleConnectionCount++; 15554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 15654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 1572231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 1587407d6984ce69693097befc9b72609a8156463bbNarayan Kamath for (ListIterator<Connection> i = connections.listIterator(connections.size()); 1597407d6984ce69693097befc9b72609a8156463bbNarayan Kamath i.hasPrevious() && idleConnectionCount > maxIdleConnections; ) { 1607407d6984ce69693097befc9b72609a8156463bbNarayan Kamath Connection connection = i.previous(); 16154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (connection.isIdle()) { 16254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson expiredConnections.add(connection); 16354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson i.remove(); 16454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson --idleConnectionCount; 16554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 16654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 16754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 16854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (Connection expiredConnection : expiredConnections) { 16954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Util.closeQuietly(expiredConnection); 17054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 1712231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 17254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson }; 1732231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 17454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public ConnectionPool(int maxIdleConnections, long keepAliveDurationMs) { 17554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson this.maxIdleConnections = maxIdleConnections; 17654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson this.keepAliveDurationNs = keepAliveDurationMs * 1000 * 1000; 17754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 17854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 17954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 18054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Returns a snapshot of the connections in this pool, ordered from newest to 18154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * oldest. Waits for the cleanup callable to run if it is currently scheduled. 182f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller * Only use in tests. 18354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 18454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<Connection> getConnections() { 18554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson waitForCleanupCallableToRun(); 18654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson synchronized (this) { 18754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return new ArrayList<Connection>(connections); 1882231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 18954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 1902231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 19154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 19254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Blocks until the executor service has processed all currently enqueued 19354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * jobs. 19454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 19554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void waitForCleanupCallableToRun() { 19654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 19754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson executorService.submit(new Runnable() { 19854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public void run() { 1992231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 20054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson }).get(); 20154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (Exception e) { 20254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throw new AssertionError(); 2032231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 20454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 2052231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 20654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public static ConnectionPool getDefault() { 20754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return systemDefault; 20854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 20954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 21054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** Returns total number of connections in the pool. */ 21154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public synchronized int getConnectionCount() { 21254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return connections.size(); 21354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 21454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 21554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** Returns total number of spdy connections in the pool. */ 21654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public synchronized int getSpdyConnectionCount() { 21754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson int total = 0; 21854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (Connection connection : connections) { 21954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (connection.isSpdy()) total++; 22054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 22154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return total; 22254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 22354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 22454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** Returns total number of http connections in the pool. */ 22554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public synchronized int getHttpConnectionCount() { 22654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson int total = 0; 22754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (Connection connection : connections) { 22854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (!connection.isSpdy()) total++; 22954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 23054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return total; 23154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 2322231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 23354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** Returns a recycled connection to {@code address}, or null if no such connection exists. */ 23454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public synchronized Connection get(Address address) { 23554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Connection foundConnection = null; 236faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath for (ListIterator<Connection> i = connections.listIterator(connections.size()); 237faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath i.hasPrevious(); ) { 238faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath Connection connection = i.previous(); 239faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath if (!connection.getRoute().getAddress().equals(address) 24054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson || !connection.isAlive() 24154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson || System.nanoTime() - connection.getIdleStartTimeNs() >= keepAliveDurationNs) { 24254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson continue; 24354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 24454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson i.remove(); 24554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (!connection.isSpdy()) { 2462231db3e6bb54447a9b14cf004a6cb03c373651cjwilson try { 24754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Platform.get().tagSocket(connection.getSocket()); 2482231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } catch (SocketException e) { 24954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Util.closeQuietly(connection); 25054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // When unable to tag, skip recycling and close 25154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Platform.get().logW("Unable to tagSocket(): " + e); 25254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson continue; 2532231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 25454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 25554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson foundConnection = connection; 25654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson break; 25754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 2582231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 25954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (foundConnection != null && foundConnection.isSpdy()) { 26054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connections.addFirst(foundConnection); // Add it back after iteration. 26154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 2622231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 263f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller scheduleCleanupAsRequired(); 26454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return foundConnection; 26554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 26654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 26754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 26854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Gives {@code connection} to the pool. The pool may store the connection, 26954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * or close it, as its policy describes. 27054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * 27154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * <p>It is an error to use {@code connection} after calling this method. 27254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 27354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public void recycle(Connection connection) { 27454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (connection.isSpdy()) { 27554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return; 2762231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 2772231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 27878092f38ebd93018ead53a87b53118dc829cbb8aNeil Fuller if (!connection.clearOwner()) { 27978092f38ebd93018ead53a87b53118dc829cbb8aNeil Fuller return; // This connection isn't eligible for reuse. 28078092f38ebd93018ead53a87b53118dc829cbb8aNeil Fuller } 28178092f38ebd93018ead53a87b53118dc829cbb8aNeil Fuller 28254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (!connection.isAlive()) { 28354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Util.closeQuietly(connection); 28454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return; 28554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 28654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 28754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 28854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Platform.get().untagSocket(connection.getSocket()); 28954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (SocketException e) { 29054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // When unable to remove tagging, skip recycling and close. 29154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Platform.get().logW("Unable to untagSocket(): " + e); 29254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Util.closeQuietly(connection); 29354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return; 29454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 29554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 29654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson synchronized (this) { 29754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connections.addFirst(connection); 2983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller connection.incrementRecycleCount(); 29954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.resetIdleStartTime(); 300f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller scheduleCleanupAsRequired(); 30154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 302fb0eb65be9f50e75fa37c250e97914252c587cafjwilson 30354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 30454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 30554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 30654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Shares the SPDY connection with the pool. Callers to this method may 30754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * continue to use {@code connection}. 30854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 3093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public void share(Connection connection) { 3103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (!connection.isSpdy()) throw new IllegalArgumentException(); 31154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (connection.isAlive()) { 31254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson synchronized (this) { 31354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connections.addFirst(connection); 314f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller scheduleCleanupAsRequired(); 31554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 3162231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 31754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 318faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 319faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath /** Close and remove all connections in the pool. */ 320faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath public void evictAll() { 321faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath List<Connection> connections; 322faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath synchronized (this) { 323faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath connections = new ArrayList<Connection>(this.connections); 324faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath this.connections.clear(); 325faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath } 326faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 3273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller for (int i = 0, size = connections.size(); i < size; i++) { 3283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Util.closeQuietly(connections.get(i)); 329faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath } 330faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath } 331f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller 332f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller /** 333f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller * A less abrupt way of draining the pool than {@link #evictAll()}. For use when the pool 334f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller * may still be referenced by active shared connections which cannot safely be closed. 335f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller */ 336f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller public void enterDrainMode() { 337f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller synchronized(this) { 338f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller cleanMode = CleanMode.DRAINING; 339f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller executorService.execute(drainModeRunnable); 340f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller } 341f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller } 342f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller 343f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller public boolean isDrained() { 344f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller synchronized(this) { 345f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller return cleanMode == CleanMode.DRAINED; 346f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller } 347f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller } 348f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller 3496257f0c1c5e6e94d446051f856207782d7188c43Neil Fuller // Callers must synchronize on "this". 350f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller private void scheduleCleanupAsRequired() { 351f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller switch (cleanMode) { 352f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller case NORMAL: 353f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller executorService.execute(connectionsCleanupRunnable); 354f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller break; 355f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller case DRAINING: 356f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller // Do nothing -drainModeRunnable is already scheduled, and will reschedules itself as 357f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller // needed. 358f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller break; 359f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller case DRAINED: 360f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller // A new connection has potentially been offered up to a drained pool. Restart the drain. 3616257f0c1c5e6e94d446051f856207782d7188c43Neil Fuller cleanMode = CleanMode.DRAINING; 362f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller executorService.execute(drainModeRunnable); 363f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller break; 364f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller } 365f3bcd0c7f0741b277b5d58f294df6201dafd45e8Neil Fuller } 3662231db3e6bb54447a9b14cf004a6cb03c373651cjwilson} 367