org.eclipse.jetty.io.nio.SelectorManager Maven / Gradle / Ivy
Show all versions of testatoo-container-jetty-full Show documentation
// ========================================================================
// Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.io.nio;
import java.io.IOException;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.io.ConnectedEndPoint;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.thread.Timeout;
import org.eclipse.jetty.util.thread.Timeout.Task;
/* ------------------------------------------------------------ */
/**
* The Selector Manager manages and number of SelectSets to allow
* NIO scheduling to scale to large numbers of connections.
*
* This class works around a number of know JVM bugs. For details
* see http://wiki.eclipse.org/Jetty/Feature/JVM_NIO_Bug
*/
public abstract class SelectorManager extends AbstractLifeCycle
{
// TODO Tune these by approx system speed.
private static final int __JVMBUG_THRESHHOLD=Integer.getInteger("org.eclipse.jetty.io.nio.JVMBUG_THRESHHOLD",512).intValue();
private static final int __MONITOR_PERIOD=Integer.getInteger("org.eclipse.jetty.io.nio.MONITOR_PERIOD",1000).intValue();
private static final int __MAX_SELECTS=Integer.getInteger("org.eclipse.jetty.io.nio.MAX_SELECTS",25000).intValue();
private static final int __BUSY_PAUSE=Integer.getInteger("org.eclipse.jetty.io.nio.BUSY_PAUSE",50).intValue();
private static final int __BUSY_KEY=Integer.getInteger("org.eclipse.jetty.io.nio.BUSY_KEY",-1).intValue();
private static final int __IDLE_TICK=Integer.getInteger("org.eclipse.jetty.io.nio.IDLE_TICK",400).intValue();
private int _maxIdleTime;
private int _lowResourcesMaxIdleTime;
private long _lowResourcesConnections;
private SelectSet[] _selectSet;
private int _selectSets=1;
private volatile int _set;
/* ------------------------------------------------------------ */
/**
* @param maxIdleTime The maximum period in milli seconds that a connection may be idle before it is closed.
* @see #setLowResourcesMaxIdleTime(long)
*/
public void setMaxIdleTime(long maxIdleTime)
{
_maxIdleTime=(int)maxIdleTime;
}
/* ------------------------------------------------------------ */
/**
* @param selectSets number of select sets to create
*/
public void setSelectSets(int selectSets)
{
long lrc = _lowResourcesConnections * _selectSets;
_selectSets=selectSets;
_lowResourcesConnections=lrc/_selectSets;
}
/* ------------------------------------------------------------ */
/**
* @return the max idle time
*/
public long getMaxIdleTime()
{
return _maxIdleTime;
}
/* ------------------------------------------------------------ */
/**
* @return the number of select sets in use
*/
public int getSelectSets()
{
return _selectSets;
}
/* ------------------------------------------------------------ */
/**
* @param i
* @return The select set
*/
public SelectSet getSelectSet(int i)
{
return _selectSet[i];
}
/* ------------------------------------------------------------ */
/** Register a channel
* @param channel
* @param att Attached Object
*/
public void register(SocketChannel channel, Object att)
{
// The ++ increment here is not atomic, but it does not matter.
// so long as the value changes sometimes, then connections will
// be distributed over the available sets.
int s=_set++;
s=s%_selectSets;
SelectSet[] sets=_selectSet;
if (sets!=null)
{
SelectSet set=sets[s];
set.addChange(channel,att);
set.wakeup();
}
}
/* ------------------------------------------------------------ */
/** Register a channel
* @param channel
* @param att Attached Object
*/
public void register(SocketChannel channel)
{
// The ++ increment here is not atomic, but it does not matter.
// so long as the value changes sometimes, then connections will
// be distributed over the available sets.
int s=_set++;
s=s%_selectSets;
SelectSet[] sets=_selectSet;
if (sets!=null)
{
SelectSet set=sets[s];
set.addChange(channel);
set.wakeup();
}
}
/* ------------------------------------------------------------ */
/** Register a {@link ServerSocketChannel}
* @param acceptChannel
*/
public void register(ServerSocketChannel acceptChannel)
{
int s=_set++;
s=s%_selectSets;
SelectSet set=_selectSet[s];
set.addChange(acceptChannel);
set.wakeup();
}
/* ------------------------------------------------------------ */
/**
* @return the lowResourcesConnections
*/
public long getLowResourcesConnections()
{
return _lowResourcesConnections*_selectSets;
}
/* ------------------------------------------------------------ */
/**
* Set the number of connections, which if exceeded places this manager in low resources state.
* This is not an exact measure as the connection count is averaged over the select sets.
* @param lowResourcesConnections the number of connections
* @see #setLowResourcesMaxIdleTime(long)
*/
public void setLowResourcesConnections(long lowResourcesConnections)
{
_lowResourcesConnections=(lowResourcesConnections+_selectSets-1)/_selectSets;
}
/* ------------------------------------------------------------ */
/**
* @return the lowResourcesMaxIdleTime
*/
public long getLowResourcesMaxIdleTime()
{
return _lowResourcesMaxIdleTime;
}
/* ------------------------------------------------------------ */
/**
* @param lowResourcesMaxIdleTime the period in ms that a connection is allowed to be idle when this SelectSet has more connections than {@link #getLowResourcesConnections()}
* @see #setMaxIdleTime(long)
*/
public void setLowResourcesMaxIdleTime(long lowResourcesMaxIdleTime)
{
_lowResourcesMaxIdleTime=(int)lowResourcesMaxIdleTime;
}
/* ------------------------------------------------------------ */
/**
* @param acceptorID
* @throws IOException
*/
public void doSelect(int acceptorID) throws IOException
{
SelectSet[] sets= _selectSet;
if (sets!=null && sets.length>acceptorID && sets[acceptorID]!=null)
sets[acceptorID].doSelect();
}
/* ------------------------------------------------------------------------------- */
public abstract boolean dispatch(Runnable task);
/* ------------------------------------------------------------ */
/* (non-Javadoc)
* @see org.eclipse.component.AbstractLifeCycle#doStart()
*/
@Override
protected void doStart() throws Exception
{
_selectSet = new SelectSet[_selectSets];
for (int i=0;i<_selectSet.length;i++)
_selectSet[i]= new SelectSet(i);
super.doStart();
}
/* ------------------------------------------------------------------------------- */
@Override
protected void doStop() throws Exception
{
SelectSet[] sets= _selectSet;
_selectSet=null;
if (sets!=null)
{
for (SelectSet set : sets)
{
if (set!=null)
set.stop();
}
}
super.doStop();
}
/* ------------------------------------------------------------ */
/**
* @param endpoint
*/
protected abstract void endPointClosed(SelectChannelEndPoint endpoint);
/* ------------------------------------------------------------ */
/**
* @param endpoint
*/
protected abstract void endPointOpened(SelectChannelEndPoint endpoint);
/* ------------------------------------------------------------ */
protected abstract void endPointUpgraded(ConnectedEndPoint endpoint,Connection oldConnection);
/* ------------------------------------------------------------------------------- */
protected abstract Connection newConnection(SocketChannel channel, SelectChannelEndPoint endpoint);
/* ------------------------------------------------------------ */
/**
* Create a new end point
* @param channel
* @param selectSet
* @param sKey the selection key
* @return the new endpoint {@link SelectChannelEndPoint}
* @throws IOException
*/
protected abstract SelectChannelEndPoint newEndPoint(SocketChannel channel, SelectorManager.SelectSet selectSet, SelectionKey sKey) throws IOException;
/* ------------------------------------------------------------------------------- */
public void dump()
{
for (final SelectSet set :_selectSet)
{
Thread selecting = set._selecting;
Log.info("SelectSet "+set._setID+" : "+selecting);
if (selecting!=null)
{
StackTraceElement[] trace =selecting.getStackTrace();
if (trace!=null)
{
for (StackTraceElement e : trace)
{
Log.info("\tat "+e.toString());
}
}
}
set.addChange(new Runnable(){
public void run()
{
set.dump();
}
});
}
}
/* ------------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------------- */
public class SelectSet
{
private final int _setID;
private final Timeout _timeout;
private final ConcurrentLinkedQueue