blob: 023dff1ca1f10b6117cda46ac08780c72633ad1e [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* 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.
*/
/**
* Hangs onto idle live connections for a little while
*/
package android.net.http;
import org.apache.http.HttpHost;
import android.os.SystemClock;
class IdleCache {
class Entry {
HttpHost mHost;
Connection mConnection;
long mTimeout;
};
private final static int IDLE_CACHE_MAX = 8;
/* Allow five consecutive empty queue checks before shutdown */
private final static int EMPTY_CHECK_MAX = 5;
/* six second timeout for connections */
private final static int TIMEOUT = 6 * 1000;
private final static int CHECK_INTERVAL = 2 * 1000;
private Entry[] mEntries = new Entry[IDLE_CACHE_MAX];
private int mCount = 0;
private IdleReaper mThread = null;
/* stats */
private int mCached = 0;
private int mReused = 0;
IdleCache() {
for (int i = 0; i < IDLE_CACHE_MAX; i++) {
mEntries[i] = new Entry();
}
}
/**
* Caches connection, if there is room.
* @return true if connection cached
*/
synchronized boolean cacheConnection(
HttpHost host, Connection connection) {
boolean ret = false;
if (HttpLog.LOGV) {
HttpLog.v("IdleCache size " + mCount + " host " + host);
}
if (mCount < IDLE_CACHE_MAX) {
long time = SystemClock.uptimeMillis();
for (int i = 0; i < IDLE_CACHE_MAX; i++) {
Entry entry = mEntries[i];
if (entry.mHost == null) {
entry.mHost = host;
entry.mConnection = connection;
entry.mTimeout = time + TIMEOUT;
mCount++;
if (HttpLog.LOGV) mCached++;
ret = true;
if (mThread == null) {
mThread = new IdleReaper();
mThread.start();
}
break;
}
}
}
return ret;
}
synchronized Connection getConnection(HttpHost host) {
Connection ret = null;
if (mCount > 0) {
for (int i = 0; i < IDLE_CACHE_MAX; i++) {
Entry entry = mEntries[i];
HttpHost eHost = entry.mHost;
if (eHost != null && eHost.equals(host)) {
ret = entry.mConnection;
entry.mHost = null;
entry.mConnection = null;
mCount--;
if (HttpLog.LOGV) mReused++;
break;
}
}
}
return ret;
}
synchronized void clear() {
for (int i = 0; mCount > 0 && i < IDLE_CACHE_MAX; i++) {
Entry entry = mEntries[i];
if (entry.mHost != null) {
entry.mHost = null;
entry.mConnection.closeConnection();
entry.mConnection = null;
mCount--;
}
}
}
private synchronized void clearIdle() {
if (mCount > 0) {
long time = SystemClock.uptimeMillis();
for (int i = 0; i < IDLE_CACHE_MAX; i++) {
Entry entry = mEntries[i];
if (entry.mHost != null && time > entry.mTimeout) {
entry.mHost = null;
entry.mConnection.closeConnection();
entry.mConnection = null;
mCount--;
}
}
}
}
private class IdleReaper extends Thread {
public void run() {
int check = 0;
setName("IdleReaper");
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_BACKGROUND);
synchronized (IdleCache.this) {
while (check < EMPTY_CHECK_MAX) {
try {
IdleCache.this.wait(CHECK_INTERVAL);
} catch (InterruptedException ex) {
}
if (mCount == 0) {
check++;
} else {
check = 0;
clearIdle();
}
}
mThread = null;
}
if (HttpLog.LOGV) {
HttpLog.v("IdleCache IdleReaper shutdown: cached " + mCached +
" reused " + mReused);
mCached = 0;
mReused = 0;
}
}
}
}