/** * Process a new session : - initialize it - create its chain - fire the CREATED listeners if any * * @param session The session to create * @return true if the session has been registered */ private boolean addNow(S session) { boolean registered = false; try { init(session); registered = true; // Build the filter chain of this session. IoFilterChainBuilder chainBuilder = session.getService().getFilterChainBuilder(); chainBuilder.buildFilterChain(session.getFilterChain()); // DefaultIoFilterChain.CONNECT_FUTURE is cleared inside here // in AbstractIoFilterChain.fireSessionOpened(). // Propagate the SESSION_CREATED event up to the chain IoServiceListenerSupport listeners = ((AbstractIoService) session.getService()).getListeners(); listeners.fireSessionCreated(session); } catch (Throwable e) { ExceptionMonitor.getInstance().exceptionCaught(e); try { destroy(session); } catch (Exception e1) { ExceptionMonitor.getInstance().exceptionCaught(e1); } finally { registered = false; } } return registered; }
/** {@inheritDoc} */ public void updateTrafficControl(S session) { // try { setInterestedInRead(session, !session.isReadSuspended()); } catch (Exception e) { IoFilterChain filterChain = session.getFilterChain(); filterChain.fireExceptionCaught(e); } try { setInterestedInWrite( session, !session.getWriteRequestQueue().isEmpty(session) && !session.isWriteSuspended()); } catch (Exception e) { IoFilterChain filterChain = session.getFilterChain(); filterChain.fireExceptionCaught(e); } }
private void clearWriteRequestQueue(S session) { WriteRequestQueue writeRequestQueue = session.getWriteRequestQueue(); WriteRequest req; List<WriteRequest> failedRequests = new ArrayList<WriteRequest>(); if ((req = writeRequestQueue.poll(session)) != null) { Object message = req.getMessage(); if (message instanceof IoBuffer) { IoBuffer buf = (IoBuffer) message; // The first unwritten empty buffer must be // forwarded to the filter chain. if (buf.hasRemaining()) { buf.reset(); failedRequests.add(req); } else { IoFilterChain filterChain = session.getFilterChain(); filterChain.fireMessageSent(req); } } else { failedRequests.add(req); } // Discard others. while ((req = writeRequestQueue.poll(session)) != null) { failedRequests.add(req); } } // Create an exception and notify. if (!failedRequests.isEmpty()) { WriteToClosedSessionException cause = new WriteToClosedSessionException(failedRequests); for (WriteRequest r : failedRequests) { session.decreaseScheduledBytesAndMessages(r); r.getFuture().setException(cause); } IoFilterChain filterChain = session.getFilterChain(); filterChain.fireExceptionCaught(cause); } }
/** Write all the pending messages */ private void flush(long currentTime) { if (flushingSessions.isEmpty()) { return; } do { S session = flushingSessions.poll(); // the same one with firstSession if (session == null) { // Just in case ... It should not happen. break; } // Reset the Schedule for flush flag for this session, // as we are flushing it now session.unscheduledForFlush(); SessionState state = getState(session); switch (state) { case OPENED: try { boolean flushedAll = flushNow(session, currentTime); if (flushedAll && !session.getWriteRequestQueue().isEmpty(session) && !session.isScheduledForFlush()) { scheduleFlush(session); } } catch (Exception e) { scheduleRemove(session); IoFilterChain filterChain = session.getFilterChain(); filterChain.fireExceptionCaught(e); } break; case CLOSING: // Skip if the channel is already closed. break; case OPENING: // Retry later if session is not yet fully initialized. // (In case that Session.write() is called before addSession() // is processed) scheduleFlush(session); return; default: throw new IllegalStateException(String.valueOf(state)); } } while (!flushingSessions.isEmpty()); }
private boolean removeNow(S session) { clearWriteRequestQueue(session); try { destroy(session); return true; } catch (Exception e) { IoFilterChain filterChain = session.getFilterChain(); filterChain.fireExceptionCaught(e); } finally { clearWriteRequestQueue(session); ((AbstractIoService) session.getService()).getListeners().fireSessionDestroyed(session); } return false; }
private void fireMessageSent(S session, WriteRequest req) { session.setCurrentWriteRequest(null); IoFilterChain filterChain = session.getFilterChain(); filterChain.fireMessageSent(req); }
private boolean flushNow(S session, long currentTime) { if (!session.isConnected()) { scheduleRemove(session); return false; } final boolean hasFragmentation = session.getTransportMetadata().hasFragmentation(); final WriteRequestQueue writeRequestQueue = session.getWriteRequestQueue(); // Set limitation for the number of written bytes for read-write // fairness. I used maxReadBufferSize * 3 / 2, which yields best // performance in my experience while not breaking fairness much. final int maxWrittenBytes = session.getConfig().getMaxReadBufferSize() + (session.getConfig().getMaxReadBufferSize() >>> 1); int writtenBytes = 0; WriteRequest req = null; try { // Clear OP_WRITE setInterestedInWrite(session, false); do { // Check for pending writes. req = session.getCurrentWriteRequest(); if (req == null) { req = writeRequestQueue.poll(session); if (req == null) { break; } session.setCurrentWriteRequest(req); } int localWrittenBytes = 0; Object message = req.getMessage(); if (message instanceof IoBuffer) { localWrittenBytes = writeBuffer( session, req, hasFragmentation, maxWrittenBytes - writtenBytes, currentTime); if ((localWrittenBytes > 0) && ((IoBuffer) message).hasRemaining()) { // the buffer isn't empty, we re-interest it in writing writtenBytes += localWrittenBytes; setInterestedInWrite(session, true); return false; } } else if (message instanceof FileRegion) { localWrittenBytes = writeFile( session, req, hasFragmentation, maxWrittenBytes - writtenBytes, currentTime); // Fix for Java bug on Linux // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5103988 // If there's still data to be written in the FileRegion, // return 0 indicating that we need // to pause until writing may resume. if ((localWrittenBytes > 0) && (((FileRegion) message).getRemainingBytes() > 0)) { writtenBytes += localWrittenBytes; setInterestedInWrite(session, true); return false; } } else { throw new IllegalStateException( "Don't know how to handle message of type '" + message.getClass().getName() + "'. Are you missing a protocol encoder?"); } if (localWrittenBytes == 0) { // Kernel buffer is full. setInterestedInWrite(session, true); return false; } writtenBytes += localWrittenBytes; if (writtenBytes >= maxWrittenBytes) { // Wrote too much scheduleFlush(session); return false; } } while (writtenBytes < maxWrittenBytes); } catch (Exception e) { if (req != null) { req.getFuture().setException(e); } IoFilterChain filterChain = session.getFilterChain(); filterChain.fireExceptionCaught(e); return false; } return true; }
private void read(S session) { IoSessionConfig config = session.getConfig(); int bufferSize = config.getReadBufferSize(); IoBuffer buf = IoBuffer.allocate(bufferSize); final boolean hasFragmentation = session.getTransportMetadata().hasFragmentation(); try { int readBytes = 0; int ret; try { if (hasFragmentation) { while ((ret = read(session, buf)) > 0) { readBytes += ret; if (!buf.hasRemaining()) { break; } } } else { ret = read(session, buf); if (ret > 0) { readBytes = ret; } } } finally { buf.flip(); } if (readBytes > 0) { IoFilterChain filterChain = session.getFilterChain(); filterChain.fireMessageReceived(buf); buf = null; if (hasFragmentation) { if (readBytes << 1 < config.getReadBufferSize()) { session.decreaseReadBufferSize(); } else if (readBytes == config.getReadBufferSize()) { session.increaseReadBufferSize(); } } } if (ret < 0) { scheduleRemove(session); } } catch (Throwable e) { if (e instanceof IOException) { if (!(e instanceof PortUnreachableException) || !AbstractDatagramSessionConfig.class.isAssignableFrom(config.getClass()) || ((AbstractDatagramSessionConfig) config).isCloseOnPortUnreachable()) { scheduleRemove(session); } } IoFilterChain filterChain = session.getFilterChain(); filterChain.fireExceptionCaught(e); } }