@Override public void write(final ChannelHandlerContext ctx, final Object msg, final ChannelPromise promise) throws Exception { long curtime = System.currentTimeMillis(); long size = calculateSize(msg); if (size > -1 && trafficCounter != null) { trafficCounter.bytesWriteFlowControl(size); if (writeLimit == 0) { ctx.write(msg, promise); return; } // compute the number of ms to wait before continue with the // channel long wait = getTimeToWait( writeLimit, trafficCounter.currentWrittenBytes(), trafficCounter.lastTime(), curtime); if (wait >= MINIMAL_WAIT) { ctx.executor() .schedule( new Runnable() { @Override public void run() { ctx.write(msg, promise); } }, wait, TimeUnit.MILLISECONDS); return; } } ctx.write(msg, promise); }
@Override public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception { long size = calculateSize(msg); long curtime = System.currentTimeMillis(); if (trafficCounter != null) { trafficCounter.bytesRecvFlowControl(size); if (readLimit == 0) { // no action ctx.fireChannelRead(msg); return; } // compute the number of ms to wait before reopening the channel long wait = getTimeToWait( readLimit, trafficCounter.currentReadBytes(), trafficCounter.lastTime(), curtime); if (wait >= MINIMAL_WAIT) { // At least 10ms seems a minimal // time in order to // try to limit the traffic if (!isSuspended(ctx)) { ctx.attr(READ_SUSPENDED).set(true); // Create a Runnable to reactive the read if needed. If one was create before it will just // be // reused to limit object creation Attribute<Runnable> attr = ctx.attr(REOPEN_TASK); Runnable reopenTask = attr.get(); if (reopenTask == null) { reopenTask = new ReopenReadTimerTask(ctx); attr.set(reopenTask); } ctx.executor().schedule(reopenTask, wait, TimeUnit.MILLISECONDS); } else { // Create a Runnable to update the next handler in the chain. If one was create before it // will // just be reused to limit object creation Runnable bufferUpdateTask = new Runnable() { @Override public void run() { ctx.fireChannelRead(msg); } }; ctx.executor().schedule(bufferUpdateTask, wait, TimeUnit.MILLISECONDS); return; } } } ctx.fireChannelRead(msg); }
/** * Change the underlying limitations. * * @param newWriteLimit The new write limit (in bytes) * @param newReadLimit The new read limit (in bytes) */ public void configure(long newWriteLimit, long newReadLimit) { writeLimit = newWriteLimit; readLimit = newReadLimit; if (trafficCounter != null) { trafficCounter.resetAccounting(System.currentTimeMillis() + 1); } }
@Override public String toString() { return "TrafficShaping with Write Limit: " + writeLimit + " Read Limit: " + readLimit + " and Counter: " + (trafficCounter != null ? trafficCounter.toString() : "none"); }
/** * Change the check interval. * * @param newCheckInterval The new check interval (in milliseconds) */ public void configure(long newCheckInterval) { checkInterval = newCheckInterval; if (trafficCounter != null) { trafficCounter.configure(checkInterval); } }