mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/conn/tsccm/RouteSpecificPool.java

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 /*
michael@0 2 * ====================================================================
michael@0 3 *
michael@0 4 * Licensed to the Apache Software Foundation (ASF) under one or more
michael@0 5 * contributor license agreements. See the NOTICE file distributed with
michael@0 6 * this work for additional information regarding copyright ownership.
michael@0 7 * The ASF licenses this file to You under the Apache License, Version 2.0
michael@0 8 * (the "License"); you may not use this file except in compliance with
michael@0 9 * the License. You may obtain a copy of the License at
michael@0 10 *
michael@0 11 * http://www.apache.org/licenses/LICENSE-2.0
michael@0 12 *
michael@0 13 * Unless required by applicable law or agreed to in writing, software
michael@0 14 * distributed under the License is distributed on an "AS IS" BASIS,
michael@0 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
michael@0 16 * See the License for the specific language governing permissions and
michael@0 17 * limitations under the License.
michael@0 18 * ====================================================================
michael@0 19 *
michael@0 20 * This software consists of voluntary contributions made by many
michael@0 21 * individuals on behalf of the Apache Software Foundation. For more
michael@0 22 * information on the Apache Software Foundation, please see
michael@0 23 * <http://www.apache.org/>.
michael@0 24 *
michael@0 25 */
michael@0 26
michael@0 27 package ch.boye.httpclientandroidlib.impl.conn.tsccm;
michael@0 28
michael@0 29 import java.io.IOException;
michael@0 30 import java.util.ListIterator;
michael@0 31 import java.util.Queue;
michael@0 32 import java.util.LinkedList;
michael@0 33
michael@0 34 import ch.boye.httpclientandroidlib.annotation.NotThreadSafe;
michael@0 35
michael@0 36 import ch.boye.httpclientandroidlib.androidextra.HttpClientAndroidLog;
michael@0 37 /* LogFactory removed by HttpClient for Android script. */
michael@0 38 import ch.boye.httpclientandroidlib.conn.OperatedClientConnection;
michael@0 39 import ch.boye.httpclientandroidlib.conn.params.ConnPerRoute;
michael@0 40 import ch.boye.httpclientandroidlib.conn.routing.HttpRoute;
michael@0 41 import ch.boye.httpclientandroidlib.util.LangUtils;
michael@0 42
michael@0 43
michael@0 44 /**
michael@0 45 * A connection sub-pool for a specific route, used by {@link ConnPoolByRoute}.
michael@0 46 * The methods in this class are unsynchronized. It is expected that the
michael@0 47 * containing pool takes care of synchronization.
michael@0 48 *
michael@0 49 * @since 4.0
michael@0 50 */
michael@0 51 @NotThreadSafe // e.g. numEntries, freeEntries,
michael@0 52 public class RouteSpecificPool {
michael@0 53
michael@0 54 public HttpClientAndroidLog log = new HttpClientAndroidLog(getClass());
michael@0 55
michael@0 56 /** The route this pool is for. */
michael@0 57 protected final HttpRoute route; //Immutable
michael@0 58
michael@0 59 @Deprecated
michael@0 60 protected final int maxEntries;
michael@0 61
michael@0 62 /** Connections per route */
michael@0 63 protected final ConnPerRoute connPerRoute;
michael@0 64
michael@0 65 /**
michael@0 66 * The list of free entries.
michael@0 67 * This list is managed LIFO, to increase idle times and
michael@0 68 * allow for closing connections that are not really needed.
michael@0 69 */
michael@0 70 protected final LinkedList<BasicPoolEntry> freeEntries;
michael@0 71
michael@0 72 /** The list of threads waiting for this pool. */
michael@0 73 protected final Queue<WaitingThread> waitingThreads;
michael@0 74
michael@0 75 /** The number of created entries. */
michael@0 76 protected int numEntries;
michael@0 77
michael@0 78
michael@0 79 /**
michael@0 80 * @deprecated use {@link RouteSpecificPool#RouteSpecificPool(HttpRoute, ConnPerRoute)}
michael@0 81 */
michael@0 82 @Deprecated
michael@0 83 public RouteSpecificPool(HttpRoute route, int maxEntries) {
michael@0 84 this.route = route;
michael@0 85 this.maxEntries = maxEntries;
michael@0 86 this.connPerRoute = new ConnPerRoute() {
michael@0 87 public int getMaxForRoute(HttpRoute route) {
michael@0 88 return RouteSpecificPool.this.maxEntries;
michael@0 89 }
michael@0 90 };
michael@0 91 this.freeEntries = new LinkedList<BasicPoolEntry>();
michael@0 92 this.waitingThreads = new LinkedList<WaitingThread>();
michael@0 93 this.numEntries = 0;
michael@0 94 }
michael@0 95
michael@0 96
michael@0 97 /**
michael@0 98 * Creates a new route-specific pool.
michael@0 99 *
michael@0 100 * @param route the route for which to pool
michael@0 101 * @param connPerRoute the connections per route configuration
michael@0 102 */
michael@0 103 public RouteSpecificPool(HttpRoute route, ConnPerRoute connPerRoute) {
michael@0 104 this.route = route;
michael@0 105 this.connPerRoute = connPerRoute;
michael@0 106 this.maxEntries = connPerRoute.getMaxForRoute(route);
michael@0 107 this.freeEntries = new LinkedList<BasicPoolEntry>();
michael@0 108 this.waitingThreads = new LinkedList<WaitingThread>();
michael@0 109 this.numEntries = 0;
michael@0 110 }
michael@0 111
michael@0 112
michael@0 113 /**
michael@0 114 * Obtains the route for which this pool is specific.
michael@0 115 *
michael@0 116 * @return the route
michael@0 117 */
michael@0 118 public final HttpRoute getRoute() {
michael@0 119 return route;
michael@0 120 }
michael@0 121
michael@0 122
michael@0 123 /**
michael@0 124 * Obtains the maximum number of entries allowed for this pool.
michael@0 125 *
michael@0 126 * @return the max entry number
michael@0 127 */
michael@0 128 public final int getMaxEntries() {
michael@0 129 return maxEntries;
michael@0 130 }
michael@0 131
michael@0 132
michael@0 133 /**
michael@0 134 * Indicates whether this pool is unused.
michael@0 135 * A pool is unused if there is neither an entry nor a waiting thread.
michael@0 136 * All entries count, not only the free but also the allocated ones.
michael@0 137 *
michael@0 138 * @return <code>true</code> if this pool is unused,
michael@0 139 * <code>false</code> otherwise
michael@0 140 */
michael@0 141 public boolean isUnused() {
michael@0 142 return (numEntries < 1) && waitingThreads.isEmpty();
michael@0 143 }
michael@0 144
michael@0 145
michael@0 146 /**
michael@0 147 * Return remaining capacity of this pool
michael@0 148 *
michael@0 149 * @return capacity
michael@0 150 */
michael@0 151 public int getCapacity() {
michael@0 152 return connPerRoute.getMaxForRoute(route) - numEntries;
michael@0 153 }
michael@0 154
michael@0 155
michael@0 156 /**
michael@0 157 * Obtains the number of entries.
michael@0 158 * This includes not only the free entries, but also those that
michael@0 159 * have been created and are currently issued to an application.
michael@0 160 *
michael@0 161 * @return the number of entries for the route of this pool
michael@0 162 */
michael@0 163 public final int getEntryCount() {
michael@0 164 return numEntries;
michael@0 165 }
michael@0 166
michael@0 167
michael@0 168 /**
michael@0 169 * Obtains a free entry from this pool, if one is available.
michael@0 170 *
michael@0 171 * @return an available pool entry, or <code>null</code> if there is none
michael@0 172 */
michael@0 173 public BasicPoolEntry allocEntry(final Object state) {
michael@0 174 if (!freeEntries.isEmpty()) {
michael@0 175 ListIterator<BasicPoolEntry> it = freeEntries.listIterator(freeEntries.size());
michael@0 176 while (it.hasPrevious()) {
michael@0 177 BasicPoolEntry entry = it.previous();
michael@0 178 if (entry.getState() == null || LangUtils.equals(state, entry.getState())) {
michael@0 179 it.remove();
michael@0 180 return entry;
michael@0 181 }
michael@0 182 }
michael@0 183 }
michael@0 184 if (getCapacity() == 0 && !freeEntries.isEmpty()) {
michael@0 185 BasicPoolEntry entry = freeEntries.remove();
michael@0 186 entry.shutdownEntry();
michael@0 187 OperatedClientConnection conn = entry.getConnection();
michael@0 188 try {
michael@0 189 conn.close();
michael@0 190 } catch (IOException ex) {
michael@0 191 log.debug("I/O error closing connection", ex);
michael@0 192 }
michael@0 193 return entry;
michael@0 194 }
michael@0 195 return null;
michael@0 196 }
michael@0 197
michael@0 198
michael@0 199 /**
michael@0 200 * Returns an allocated entry to this pool.
michael@0 201 *
michael@0 202 * @param entry the entry obtained from {@link #allocEntry allocEntry}
michael@0 203 * or presented to {@link #createdEntry createdEntry}
michael@0 204 */
michael@0 205 public void freeEntry(BasicPoolEntry entry) {
michael@0 206
michael@0 207 if (numEntries < 1) {
michael@0 208 throw new IllegalStateException
michael@0 209 ("No entry created for this pool. " + route);
michael@0 210 }
michael@0 211 if (numEntries <= freeEntries.size()) {
michael@0 212 throw new IllegalStateException
michael@0 213 ("No entry allocated from this pool. " + route);
michael@0 214 }
michael@0 215 freeEntries.add(entry);
michael@0 216 }
michael@0 217
michael@0 218
michael@0 219 /**
michael@0 220 * Indicates creation of an entry for this pool.
michael@0 221 * The entry will <i>not</i> be added to the list of free entries,
michael@0 222 * it is only recognized as belonging to this pool now. It can then
michael@0 223 * be passed to {@link #freeEntry freeEntry}.
michael@0 224 *
michael@0 225 * @param entry the entry that was created for this pool
michael@0 226 */
michael@0 227 public void createdEntry(BasicPoolEntry entry) {
michael@0 228
michael@0 229 if (!route.equals(entry.getPlannedRoute())) {
michael@0 230 throw new IllegalArgumentException
michael@0 231 ("Entry not planned for this pool." +
michael@0 232 "\npool: " + route +
michael@0 233 "\nplan: " + entry.getPlannedRoute());
michael@0 234 }
michael@0 235
michael@0 236 numEntries++;
michael@0 237 }
michael@0 238
michael@0 239
michael@0 240 /**
michael@0 241 * Deletes an entry from this pool.
michael@0 242 * Only entries that are currently free in this pool can be deleted.
michael@0 243 * Allocated entries can not be deleted.
michael@0 244 *
michael@0 245 * @param entry the entry to delete from this pool
michael@0 246 *
michael@0 247 * @return <code>true</code> if the entry was found and deleted, or
michael@0 248 * <code>false</code> if the entry was not found
michael@0 249 */
michael@0 250 public boolean deleteEntry(BasicPoolEntry entry) {
michael@0 251
michael@0 252 final boolean found = freeEntries.remove(entry);
michael@0 253 if (found)
michael@0 254 numEntries--;
michael@0 255 return found;
michael@0 256 }
michael@0 257
michael@0 258
michael@0 259 /**
michael@0 260 * Forgets about an entry from this pool.
michael@0 261 * This method is used to indicate that an entry
michael@0 262 * {@link #allocEntry allocated}
michael@0 263 * from this pool has been lost and will not be returned.
michael@0 264 */
michael@0 265 public void dropEntry() {
michael@0 266 if (numEntries < 1) {
michael@0 267 throw new IllegalStateException
michael@0 268 ("There is no entry that could be dropped.");
michael@0 269 }
michael@0 270 numEntries--;
michael@0 271 }
michael@0 272
michael@0 273
michael@0 274 /**
michael@0 275 * Adds a waiting thread.
michael@0 276 * This pool makes no attempt to match waiting threads with pool entries.
michael@0 277 * It is the caller's responsibility to check that there is no entry
michael@0 278 * before adding a waiting thread.
michael@0 279 *
michael@0 280 * @param wt the waiting thread
michael@0 281 */
michael@0 282 public void queueThread(WaitingThread wt) {
michael@0 283 if (wt == null) {
michael@0 284 throw new IllegalArgumentException
michael@0 285 ("Waiting thread must not be null.");
michael@0 286 }
michael@0 287 this.waitingThreads.add(wt);
michael@0 288 }
michael@0 289
michael@0 290
michael@0 291 /**
michael@0 292 * Checks whether there is a waiting thread in this pool.
michael@0 293 *
michael@0 294 * @return <code>true</code> if there is a waiting thread,
michael@0 295 * <code>false</code> otherwise
michael@0 296 */
michael@0 297 public boolean hasThread() {
michael@0 298 return !this.waitingThreads.isEmpty();
michael@0 299 }
michael@0 300
michael@0 301
michael@0 302 /**
michael@0 303 * Returns the next thread in the queue.
michael@0 304 *
michael@0 305 * @return a waiting thread, or <code>null</code> if there is none
michael@0 306 */
michael@0 307 public WaitingThread nextThread() {
michael@0 308 return this.waitingThreads.peek();
michael@0 309 }
michael@0 310
michael@0 311
michael@0 312 /**
michael@0 313 * Removes a waiting thread, if it is queued.
michael@0 314 *
michael@0 315 * @param wt the waiting thread
michael@0 316 */
michael@0 317 public void removeThread(WaitingThread wt) {
michael@0 318 if (wt == null)
michael@0 319 return;
michael@0 320
michael@0 321 this.waitingThreads.remove(wt);
michael@0 322 }
michael@0 323
michael@0 324
michael@0 325 } // class RouteSpecificPool

mercurial