FileDocCategorySizeDatePackage
NioSelectorPool.javaAPI DocApache Tomcat 6.0.1411874Fri Jul 20 04:20:32 BST 2007org.apache.tomcat.util.net

NioSelectorPool

public class NioSelectorPool extends Object
Thread safe non blocking selector pool
author
Filip Hanik
version
1.0
since
6.0

Fields Summary
protected static org.apache.juli.logging.Log
log
protected static final boolean
SHARED
protected static Selector
SHARED_SELECTOR
protected int
maxSelectors
protected int
maxSpareSelectors
protected boolean
enabled
protected AtomicInteger
active
protected AtomicInteger
spare
protected ConcurrentLinkedQueue
selectors
Constructors Summary
Methods Summary
public voidclose()

        enabled = false;
        Selector s;
        while ( (s = selectors.poll()) != null ) s.close();
        spare.set(0);
        active.set(0);
        if ( SHARED && getSharedSelector()!=null ) {
            getSharedSelector().close();
            SHARED_SELECTOR = null;
        }
    
public java.nio.channels.Selectorget()

        if ( SHARED ) {
            return getSharedSelector();
        }
        if ( (!enabled) || active.incrementAndGet() >= maxSelectors ) {
            if ( enabled ) active.decrementAndGet();
            return null;
        }
        Selector s = null;
        try {
            s = selectors.size()>0?selectors.poll():null;
            if (s == null) s = Selector.open();
            else spare.decrementAndGet();

        }catch (NoSuchElementException x ) {
            try {s = Selector.open();}catch (IOException iox){}
        } finally {
            if ( s == null ) active.decrementAndGet();//we were unable to find a selector
        }
        return s;
    
public intgetMaxSelectors()

        return maxSelectors;
    
public intgetMaxSpareSelectors()

        return maxSpareSelectors;
    
protected static java.nio.channels.SelectorgetSharedSelector()


          
        if (SHARED && SHARED_SELECTOR == null) {
            synchronized ( NioSelectorPool.class ) {
                if ( SHARED_SELECTOR == null )  {
                    SHARED_SELECTOR = Selector.open();
                    log.info("Using a shared selector for servlet write/read");
                }
            }
        }
        return  SHARED_SELECTOR;
    
public booleanisEnabled()

        return enabled;
    
public voidopen()

        enabled = true;
        getSharedSelector();
    
public voidput(java.nio.channels.Selector s)

        if ( SHARED ) return;
        if ( enabled ) active.decrementAndGet();
        if ( enabled && (maxSpareSelectors==-1 || spare.get() < Math.min(maxSpareSelectors,maxSelectors)) ) {
            spare.incrementAndGet();
            selectors.offer(s);
        }
        else s.close();
    
public intread(java.nio.ByteBuffer buf, NioChannel socket, java.nio.channels.Selector selector, long readTimeout)
Performs a blocking read using the bytebuffer for data to be read and a selector to block. If the selector parameter is null, then it will perform a busy read that could take up a lot of CPU cycles.

param
buf ByteBuffer - the buffer containing the data, we will read as until we have read at least one byte or we timed out
param
socket SocketChannel - the socket to write data to
param
selector Selector - the selector to use for blocking, if null then a busy read will be initiated
param
readTimeout long - the timeout for this read operation in milliseconds, -1 means no timeout
return
int - returns the number of bytes read
throws
EOFException if read returns -1
throws
SocketTimeoutException if the read times out
throws
IOException if an IO Exception occurs in the underlying socket logic

        return read(buf,socket,selector,readTimeout,true);
    
public intread(java.nio.ByteBuffer buf, NioChannel socket, java.nio.channels.Selector selector, long readTimeout, boolean block)
Performs a read using the bytebuffer for data to be read and a selector to register for events should you have the block=true. If the selector parameter is null, then it will perform a busy read that could take up a lot of CPU cycles.

param
buf ByteBuffer - the buffer containing the data, we will read as until we have read at least one byte or we timed out
param
socket SocketChannel - the socket to write data to
param
selector Selector - the selector to use for blocking, if null then a busy read will be initiated
param
readTimeout long - the timeout for this read operation in milliseconds, -1 means no timeout
param
block - true if you want to block until data becomes available or timeout time has been reached
return
int - returns the number of bytes read
throws
EOFException if read returns -1
throws
SocketTimeoutException if the read times out
throws
IOException if an IO Exception occurs in the underlying socket logic

        if ( SHARED && block) {
            return NioBlockingSelector.read(buf,socket,readTimeout);
        }
        SelectionKey key = null;
        int read = 0;
        boolean timedout = false;
        int keycount = 1; //assume we can write
        long time = System.currentTimeMillis(); //start the timeout timer
        try {
            while ( (!timedout) ) {
                int cnt = 0;
                if ( keycount > 0 ) { //only read if we were registered for a read
                    cnt = socket.read(buf);
                    if (cnt == -1) throw new EOFException();
                    read += cnt;
                    if (cnt > 0) continue; //read some more
                    if (cnt==0 && (read>0 || (!block) ) ) break; //we are done reading
                } 
                if ( selector != null ) {//perform a blocking read
                    //register OP_WRITE to the selector
                    if (key==null) key = socket.getIOChannel().register(selector, SelectionKey.OP_READ);
                    else key.interestOps(SelectionKey.OP_READ);
                    keycount = selector.select(readTimeout);
                }
                if (readTimeout > 0 && (selector == null || keycount == 0) ) timedout = (System.currentTimeMillis()-time)>=readTimeout;
            }//while
            if ( timedout ) throw new SocketTimeoutException();
        } finally {
            if (key != null) {
                key.cancel();
                if (selector != null) selector.selectNow();//removes the key from this selector
            }
        }
        return read;
    
public voidsetEnabled(boolean enabled)

        this.enabled = enabled;
    
public voidsetMaxSelectors(int maxSelectors)

        this.maxSelectors = maxSelectors;
    
public voidsetMaxSpareSelectors(int maxSpareSelectors)

        this.maxSpareSelectors = maxSpareSelectors;
    
public intwrite(java.nio.ByteBuffer buf, NioChannel socket, java.nio.channels.Selector selector, long writeTimeout)
Performs a blocking write using the bytebuffer for data to be written and a selector to block. If the selector parameter is null, then it will perform a busy write that could take up a lot of CPU cycles.

param
buf ByteBuffer - the buffer containing the data, we will write as long as (buf.hasRemaining()==true)
param
socket SocketChannel - the socket to write data to
param
selector Selector - the selector to use for blocking, if null then a busy write will be initiated
param
writeTimeout long - the timeout for this write operation in milliseconds, -1 means no timeout
return
int - returns the number of bytes written
throws
EOFException if write returns -1
throws
SocketTimeoutException if the write times out
throws
IOException if an IO Exception occurs in the underlying socket logic

        return write(buf,socket,selector,writeTimeout,true);
    
public intwrite(java.nio.ByteBuffer buf, NioChannel socket, java.nio.channels.Selector selector, long writeTimeout, boolean block)

        if ( SHARED && block) {
            return NioBlockingSelector.write(buf,socket,writeTimeout);
        }
        SelectionKey key = null;
        int written = 0;
        boolean timedout = false;
        int keycount = 1; //assume we can write
        long time = System.currentTimeMillis(); //start the timeout timer
        if ( socket.getBufHandler().getWriteBuffer()!= buf ) {
            socket.getBufHandler().getWriteBuffer().put(buf);
            buf = socket.getBufHandler().getWriteBuffer();
        }
        try {
            while ( (!timedout) && buf.hasRemaining() ) {
                int cnt = 0;
                if ( keycount > 0 ) { //only write if we were registered for a write
                    cnt = socket.write(buf); //write the data
                    if (cnt == -1) throw new EOFException();
                    written += cnt;
                    if (cnt > 0) {
                        time = System.currentTimeMillis(); //reset our timeout timer
                        continue; //we successfully wrote, try again without a selector
                    }
                    if (cnt==0 && (!block)) break; //don't block
                }
                if ( selector != null ) {
                    //register OP_WRITE to the selector
                    if (key==null) key = socket.getIOChannel().register(selector, SelectionKey.OP_WRITE);
                    else key.interestOps(SelectionKey.OP_WRITE);
                    keycount = selector.select(writeTimeout);
                }
                if (writeTimeout > 0 && (selector == null || keycount == 0) ) timedout = (System.currentTimeMillis()-time)>=writeTimeout;
            }//while
            if ( timedout ) throw new SocketTimeoutException();
        } finally {
            if (key != null) {
                key.cancel();
                if (selector != null) selector.selectNow();//removes the key from this selector
            }
        }
        return written;