package io.craft.atom.nio;
import io.craft.atom.io.ChannelEventType;
import io.craft.atom.io.IoHandler;
import io.craft.atom.nio.spi.NioChannelEventDispatcher;
import io.craft.atom.util.schedule.ExpirationListener;
import io.craft.atom.util.schedule.TimingWheel;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import lombok.ToString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Nio channel idle timer
*
* @author mindwind
* @version 1.0, Feb 27, 2013
*/
@ToString(of = { "timingWheel", "timeoutInMillis" })
public class NioChannelIdleTimer {
private static final Logger LOG = LoggerFactory.getLogger(NioChannelIdleTimer.class);
private TimingWheel<NioByteChannel> timingWheel ;
private NioChannelEventDispatcher dispatcher ;
private IoHandler handler ;
private int timeoutInMillis;
// ~ -------------------------------------------------------------------------------------------------------------
NioChannelIdleTimer(NioChannelEventDispatcher dispatcher, IoHandler handler, int timeoutInMillis) {
this.dispatcher = dispatcher;
this.handler = handler;
this.timeoutInMillis = timeoutInMillis;
if (timeoutInMillis > 0) {
int tickDuration = (timeoutInMillis / 100 == 0 ? 10 : timeoutInMillis / 100 );
this.timingWheel = new TimingWheel<NioByteChannel>(tickDuration, 100, TimeUnit.MILLISECONDS);
this.timingWheel.addExpirationListener(new NioChannelIdleListener());
this.timingWheel.start();
}
}
void add(NioByteChannel channel) {
timingWheel.add(channel);
}
void remove(NioByteChannel channel) {
timingWheel.remove(channel);
}
Set<NioByteChannel> aliveChannels() {
return timingWheel.elements();
}
private void fireChannelIdle(NioByteChannel channel) {
dispatcher.dispatch(new NioByteChannelEvent(ChannelEventType.CHANNEL_IDLE, channel, handler));
}
// ~ -------------------------------------------------------------------------------------------------------------
private class NioChannelIdleListener implements ExpirationListener<NioByteChannel> {
@Override
public void expired(NioByteChannel channel) {
long now = System.currentTimeMillis();
long elapse = now - channel.getLastIoTime();
if (elapse > timeoutInMillis) {
fireChannelIdle(channel);
}
if (channel.isValid()) {
timingWheel.add(channel);
}
LOG.info("[CRAFT-ATOM-NIO] Nio active channel count is |{}|", timingWheel.size());
}
}
}