/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.facebook.infrastructure.net;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
import org.apache.log4j.Logger;
/**
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
*/
class TcpConnectionManager
{
private Lock lock_ = new ReentrantLock();
private List<TcpConnection> allConnections_;
private EndPoint localEp_;
private EndPoint remoteEp_;
private int initialSize_;
private int growthFactor_;
private int maxSize_;
private long lastTimeUsed_;
private boolean isShut_;
private int inUse_;
TcpConnectionManager(int initialSize, int growthFactor, int maxSize, EndPoint localEp, EndPoint remoteEp)
{
initialSize_ = initialSize;
growthFactor_ = growthFactor;
maxSize_ = maxSize;
localEp_ = localEp;
remoteEp_ = remoteEp;
isShut_ = false;
lastTimeUsed_ = System.currentTimeMillis();
allConnections_ = new Vector<TcpConnection>();
}
TcpConnection getConnection() throws IOException
{
lock_.lock();
try
{
if (allConnections_.isEmpty())
{
TcpConnection conn = new TcpConnection(this, localEp_, remoteEp_);
addToPool(conn);
conn.inUse_ = true;
incUsed();
return conn;
}
TcpConnection least = getLeastLoaded();
if ( (least != null && least.pending() == 0) || allConnections_.size() == maxSize_) {
least.inUse_ = true;
incUsed();
return least;
}
TcpConnection connection = new TcpConnection(this, localEp_, remoteEp_);
if ( connection != null && !contains(connection) )
{
addToPool(connection);
connection.inUse_ = true;
incUsed();
return connection;
}
else
{
if ( connection != null )
{
connection.closeSocket();
}
return getLeastLoaded();
}
}
finally
{
lock_.unlock();
}
}
protected TcpConnection getLeastLoaded()
{
TcpConnection connection = null;
lock_.lock();
try
{
Collections.sort(allConnections_);
connection = (allConnections_.size() > 0 ) ? allConnections_.get(0) : null;
}
finally
{
lock_.unlock();
}
return connection;
}
void removeConnection(TcpConnection connection)
{
allConnections_.remove(connection);
}
void incUsed()
{
inUse_++;
}
void decUsed()
{
inUse_--;
}
int getConnectionsInUse()
{
return inUse_;
}
void addToPool(TcpConnection connection)
{
if ( contains(connection) )
return;
lock_.lock();
try
{
if ( allConnections_.size() < maxSize_ )
{
allConnections_.add(connection);
}
else
{
connection.closeSocket();
}
}
finally
{
lock_.unlock();
}
}
void shutdown()
{
lock_.lock();
try
{
while ( allConnections_.size() > 0 )
{
TcpConnection connection = allConnections_.remove(0);
connection.closeSocket();
}
}
finally
{
lock_.unlock();
}
isShut_ = true;
}
int getPoolSize()
{
return allConnections_.size();
}
EndPoint getLocalEndPoint()
{
return localEp_;
}
EndPoint getRemoteEndPoint()
{
return remoteEp_;
}
int getPendingWrites()
{
int total = 0;
lock_.lock();
try
{
for ( TcpConnection connection : allConnections_ )
{
total += connection.pending();
}
}
finally
{
lock_.unlock();
}
return total;
}
boolean contains(TcpConnection connection)
{
return allConnections_.contains(connection);
}
}