Home | History | Annotate | Download | only in http
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /**
     18  * Hangs onto idle live connections for a little while
     19  */
     20 
     21 package android.net.http;
     22 
     23 import org.apache.http.HttpHost;
     24 
     25 import android.os.SystemClock;
     26 
     27 class IdleCache {
     28 
     29     class Entry {
     30         HttpHost mHost;
     31         Connection mConnection;
     32         long mTimeout;
     33     };
     34 
     35     private final static int IDLE_CACHE_MAX = 8;
     36 
     37     /* Allow five consecutive empty queue checks before shutdown */
     38     private final static int EMPTY_CHECK_MAX = 5;
     39 
     40     /* six second timeout for connections */
     41     private final static int TIMEOUT = 6 * 1000;
     42     private final static int CHECK_INTERVAL = 2 * 1000;
     43     private Entry[] mEntries = new Entry[IDLE_CACHE_MAX];
     44 
     45     private int mCount = 0;
     46 
     47     private IdleReaper mThread = null;
     48 
     49     /* stats */
     50     private int mCached = 0;
     51     private int mReused = 0;
     52 
     53     IdleCache() {
     54         for (int i = 0; i < IDLE_CACHE_MAX; i++) {
     55             mEntries[i] = new Entry();
     56         }
     57     }
     58 
     59     /**
     60      * Caches connection, if there is room.
     61      * @return true if connection cached
     62      */
     63     synchronized boolean cacheConnection(
     64             HttpHost host, Connection connection) {
     65 
     66         boolean ret = false;
     67 
     68         if (HttpLog.LOGV) {
     69             HttpLog.v("IdleCache size " + mCount + " host "  + host);
     70         }
     71 
     72         if (mCount < IDLE_CACHE_MAX) {
     73             long time = SystemClock.uptimeMillis();
     74             for (int i = 0; i < IDLE_CACHE_MAX; i++) {
     75                 Entry entry = mEntries[i];
     76                 if (entry.mHost == null) {
     77                     entry.mHost = host;
     78                     entry.mConnection = connection;
     79                     entry.mTimeout = time + TIMEOUT;
     80                     mCount++;
     81                     if (HttpLog.LOGV) mCached++;
     82                     ret = true;
     83                     if (mThread == null) {
     84                         mThread = new IdleReaper();
     85                         mThread.start();
     86                     }
     87                     break;
     88                 }
     89             }
     90         }
     91         return ret;
     92     }
     93 
     94     synchronized Connection getConnection(HttpHost host) {
     95         Connection ret = null;
     96 
     97         if (mCount > 0) {
     98             for (int i = 0; i < IDLE_CACHE_MAX; i++) {
     99                 Entry entry = mEntries[i];
    100                 HttpHost eHost = entry.mHost;
    101                 if (eHost != null && eHost.equals(host)) {
    102                     ret = entry.mConnection;
    103                     entry.mHost = null;
    104                     entry.mConnection = null;
    105                     mCount--;
    106                     if (HttpLog.LOGV) mReused++;
    107                     break;
    108                 }
    109             }
    110         }
    111         return ret;
    112     }
    113 
    114     synchronized void clear() {
    115         for (int i = 0; mCount > 0 && i < IDLE_CACHE_MAX; i++) {
    116             Entry entry = mEntries[i];
    117             if (entry.mHost != null) {
    118                 entry.mHost = null;
    119                 entry.mConnection.closeConnection();
    120                 entry.mConnection = null;
    121                 mCount--;
    122             }
    123         }
    124     }
    125 
    126     private synchronized void clearIdle() {
    127         if (mCount > 0) {
    128             long time = SystemClock.uptimeMillis();
    129             for (int i = 0; i < IDLE_CACHE_MAX; i++) {
    130                 Entry entry = mEntries[i];
    131                 if (entry.mHost != null && time > entry.mTimeout) {
    132                     entry.mHost = null;
    133                     entry.mConnection.closeConnection();
    134                     entry.mConnection = null;
    135                     mCount--;
    136                 }
    137             }
    138         }
    139     }
    140 
    141     private class IdleReaper extends Thread {
    142 
    143         public void run() {
    144             int check = 0;
    145 
    146             setName("IdleReaper");
    147             android.os.Process.setThreadPriority(
    148                     android.os.Process.THREAD_PRIORITY_BACKGROUND);
    149             synchronized (IdleCache.this) {
    150                 while (check < EMPTY_CHECK_MAX) {
    151                     try {
    152                         IdleCache.this.wait(CHECK_INTERVAL);
    153                     } catch (InterruptedException ex) {
    154                     }
    155                     if (mCount == 0) {
    156                         check++;
    157                     } else {
    158                         check = 0;
    159                         clearIdle();
    160                     }
    161                 }
    162                 mThread = null;
    163             }
    164             if (HttpLog.LOGV) {
    165                 HttpLog.v("IdleCache IdleReaper shutdown: cached " + mCached +
    166                           " reused " + mReused);
    167                 mCached = 0;
    168                 mReused = 0;
    169             }
    170         }
    171     }
    172 }
    173