/projects/tomcat-7.0.2/java/org/apache/tomcat/util/net/NioSelectorPool.java
https://gitlab.com/essere.lab.public/qualitas.class-corpus · Java · 304 lines · 204 code · 34 blank · 66 comment · 75 complexity · 34403a38ca894dd1735a2ee400208259 MD5 · raw file
- /*
- * 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 org.apache.tomcat.util.net;
- import java.io.EOFException;
- import java.io.IOException;
- import java.net.SocketTimeoutException;
- import java.nio.ByteBuffer;
- import java.nio.channels.SelectionKey;
- import java.nio.channels.Selector;
- import java.util.NoSuchElementException;
- import java.util.concurrent.ConcurrentLinkedQueue;
- import java.util.concurrent.atomic.AtomicInteger;
- import org.apache.juli.logging.Log;
- import org.apache.juli.logging.LogFactory;
- import org.apache.tomcat.util.MutableInteger;
- /**
- *
- * Thread safe non blocking selector pool
- * @author Filip Hanik
- * @version 1.0
- * @since 6.0
- */
- public class NioSelectorPool {
-
- public NioSelectorPool() {
- }
-
- protected static int threadCount = 0;
-
- private static final Log log = LogFactory.getLog(NioSelectorPool.class);
- protected final static boolean SHARED =
- Boolean.valueOf(System.getProperty("org.apache.tomcat.util.net.NioSelectorShared", "true")).booleanValue();
-
- protected NioBlockingSelector blockingSelector;
-
- protected Selector SHARED_SELECTOR;
-
- protected int maxSelectors = 200;
- protected long sharedSelectorTimeout = 30000;
- protected int maxSpareSelectors = -1;
- protected boolean enabled = true;
- protected AtomicInteger active = new AtomicInteger(0);
- protected AtomicInteger spare = new AtomicInteger(0);
- protected ConcurrentLinkedQueue<Selector> selectors =
- new ConcurrentLinkedQueue<Selector>();
- protected Selector getSharedSelector() throws IOException {
- 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 Selector get() throws IOException{
- 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 void put(Selector s) throws IOException {
- 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 void close() throws IOException {
- enabled = false;
- Selector s;
- while ( (s = selectors.poll()) != null ) s.close();
- spare.set(0);
- active.set(0);
- if (blockingSelector!=null) {
- blockingSelector.close();
- }
- if ( SHARED && getSharedSelector()!=null ) {
- getSharedSelector().close();
- SHARED_SELECTOR = null;
- }
- }
- public void open() throws IOException {
- enabled = true;
- getSharedSelector();
- if (SHARED) {
- blockingSelector = new NioBlockingSelector();
- blockingSelector.open(getSharedSelector());
- }
- }
- /**
- * Performs a blocking write using the bytebuffer for data to be written and a selector to block.
- * If the <code>selector</code> 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 <code>(buf.hasRemaining()==true)</code>
- * @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
- */
- public int write(ByteBuffer buf, NioChannel socket, Selector selector, long writeTimeout) throws IOException {
- return write(buf,socket,selector,writeTimeout,true,null);
- }
-
- public int write(ByteBuffer buf, NioChannel socket, Selector selector,
- long writeTimeout, boolean block,MutableInteger lastWrite) throws IOException {
- if ( SHARED && block ) {
- return blockingSelector.write(buf,socket,writeTimeout,lastWrite);
- }
- SelectionKey key = null;
- int written = 0;
- boolean timedout = false;
- int keycount = 1; //assume we can write
- long time = System.currentTimeMillis(); //start the timeout timer
- 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 (lastWrite!=null) lastWrite.set(cnt);
- 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;
- }
- /**
- * Performs a blocking read using the bytebuffer for data to be read and a selector to block.
- * If the <code>selector</code> 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
- */
- public int read(ByteBuffer buf, NioChannel socket, Selector selector, long readTimeout) throws IOException {
- return read(buf,socket,selector,readTimeout,true);
- }
- /**
- * 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 <code>selector</code> 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
- */
- public int read(ByteBuffer buf, NioChannel socket, Selector selector, long readTimeout, boolean block) throws IOException {
- if ( SHARED && block ) {
- return blockingSelector.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 void setMaxSelectors(int maxSelectors) {
- this.maxSelectors = maxSelectors;
- }
- public void setMaxSpareSelectors(int maxSpareSelectors) {
- this.maxSpareSelectors = maxSpareSelectors;
- }
- public void setEnabled(boolean enabled) {
- this.enabled = enabled;
- }
- public void setSharedSelectorTimeout(long sharedSelectorTimeout) {
- this.sharedSelectorTimeout = sharedSelectorTimeout;
- }
- public int getMaxSelectors() {
- return maxSelectors;
- }
- public int getMaxSpareSelectors() {
- return maxSpareSelectors;
- }
- public boolean isEnabled() {
- return enabled;
- }
- public long getSharedSelectorTimeout() {
- return sharedSelectorTimeout;
- }
- public ConcurrentLinkedQueue<Selector> getSelectors() {
- return selectors;
- }
- public AtomicInteger getSpare() {
- return spare;
- }
- }