package org.kne.cloud.network.congestion; import java.io.Closeable; import java.io.IOException; import java.net.SocketException; import java.net.SocketTimeoutException; import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.UUID; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.LongAdder; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.function.Consumer; import org.kne.cloud.network.NetworkPacket; import org.kne.cloud.network.ThreadTool; import org.kne.cloud.network.ipv6.IPv6Packet; import org.kne.cloud.network.klalb.DATATPacket; import org.kne.cloud.network.klalb.SendItem; import org.kne.cloud.network.kltp.KLTPPacket; import org.kne.concurrent.ThreadParker; public class ReceivePacketSlidingWindow implements Closeable, AutoCloseable{ private ThreadParker tp=new ThreadParker(); private Map> recvMap = new ConcurrentHashMap>(); private AtomicLong recvWindowUsed=new AtomicLong(0); //private LongAdder recvWindowUsed=new LongAdder(); private long recvWindowSize; private int headerCalibrate = 0; private volatile boolean closed = false; public ReceivePacketSlidingWindow(long recvWindowSize) { super(); this.recvWindowSize = recvWindowSize; } public ReceivePacketSlidingWindow(long recvWindowSize, int headerCalibrate) { super(); this.recvWindowSize = recvWindowSize; this.headerCalibrate = headerCalibrate; } public void setHeaderCalibrate(int headerCalibrate) { this.headerCalibrate = headerCalibrate; } public int getHeaderCalibrate() { return headerCalibrate; } public void put(K sequence, V packet) { SendItem newitem = new SendItem(packet,headerCalibrate); SendItem old = recvMap.putIfAbsent(sequence, newitem); long dx=0; if (old != null) { dx=-old.getPacketLength() ; } recvWindowUsed.addAndGet(newitem.getPacketLength() +dx); tp.unpark(); } public V poll(K key) { SendItem dtp2 = recvMap.remove(key); if (dtp2 != null) { recvWindowUsed.addAndGet(-dtp2.getPacketLength()); return dtp2.getPacket(); }else { return null; } } public V take(K key) throws SocketException { while(true) { V val=poll(key); if(val!=null) { return val; } if(isClosed()) { throw new SocketException("Receive window closed!"); }tp.parkNanos(1000000L); } } public V take(K key,long timeoutNanos) throws SocketException, SocketTimeoutException { long start=System.nanoTime(); while(true) { if(System.nanoTime()-start>timeoutNanos) { throw new SocketTimeoutException("Receive time out:"+(System.nanoTime()-start)+">"+timeoutNanos); } V val=poll(key); if(val!=null) { return val; } if(isClosed()) { throw new SocketException("Receive window closed!"); }tp.parkNanos(1000000L); } } public long getRecvWindowUsed() { return recvWindowUsed.get(); } public long getRecvWindowAvaliable() { return Math.max(0, recvWindowSize-recvWindowUsed.get()); } public Map> getRecvMap() { return recvMap; } public int getWindowPacketCount() { return recvMap.size(); } public boolean isEmpty() { return recvMap.isEmpty(); } public boolean isClosed() { return closed; } @Override public void close() { closed = true; } @Override public String toString() { return "ReceivePacketSlidingWindow [recvWindowUsed=" + recvWindowUsed + ", recvWindowSize=" + recvWindowSize + ", closed=" + closed + "]"; } }