KLALB V3.4
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
package org.kne.cloud.network.congress;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class BBRCongressAlgorithm implements CongressAlgorithm {
|
||||
|
||||
private static final long BURST_TIME = 2000000L;
|
||||
private static final long BIAS = 2000000L;
|
||||
private static long MIN_SPEED = 128 * 1024L;
|
||||
private static long MIN_WINDOW = 16384;
|
||||
|
||||
private Consumer<Long> windowControlConsumer;
|
||||
private BiConsumer<Long, Long> speedControlConsumer;
|
||||
|
||||
private AtomicBoolean firstUpdate = new AtomicBoolean(true);
|
||||
private long MIN_RTTVAR = 50000000L;
|
||||
private volatile long RTTMin = 1000000000L;
|
||||
private volatile long RTTVar = 1000000000L;
|
||||
private volatile long RTTAvg = 1000000000L;
|
||||
private volatile long RTTAvg2 = 1000000000L;
|
||||
private volatile long RTTTotal = 0;
|
||||
private volatile long RTTCount = 0;
|
||||
private volatile long RTO = 1000000000L;
|
||||
|
||||
|
||||
private volatile long window=MIN_WINDOW;
|
||||
private volatile long speed=MIN_SPEED;
|
||||
private volatile long maxwindow=99999999999L;
|
||||
private long congressSpeed=MIN_SPEED;
|
||||
private double MAX_GAIN=1.02;//2.8853900817779
|
||||
private double MIN_GAIN=0.9;
|
||||
private double windowGain=MAX_GAIN;
|
||||
private double speedGain=MAX_GAIN;
|
||||
@Override
|
||||
public void reset() {
|
||||
window = MIN_WINDOW;
|
||||
if (windowControlConsumer != null) {
|
||||
windowControlConsumer.accept(window);
|
||||
}
|
||||
speed = MIN_SPEED;
|
||||
if (speedControlConsumer != null) {
|
||||
speedControlConsumer.accept(speed, BURST_TIME);
|
||||
}
|
||||
windowGain=MAX_GAIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWindowControlConsumer(Consumer<Long> windowControlConsumer) {
|
||||
this.windowControlConsumer = windowControlConsumer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSpeedControlConsumer(BiConsumer<Long, Long> speedControlConsumer) {
|
||||
this.speedControlConsumer = speedControlConsumer;
|
||||
}
|
||||
|
||||
private long RTTstartTime = System.nanoTime();
|
||||
private long bandwidth;
|
||||
@Override
|
||||
public synchronized void putAck(long packetSize, long latencyns, boolean ecn) {
|
||||
if (latencyns <= RTTMin) {
|
||||
RTTMin = latencyns;
|
||||
} else {
|
||||
RTTMin = (RTTMin * 99999 + latencyns) / 100000;
|
||||
}
|
||||
if (firstUpdate.compareAndSet(true, false)) {
|
||||
RTTAvg = latencyns;
|
||||
RTTVar = latencyns / 2;
|
||||
RTTAvg2 = latencyns;
|
||||
} else {
|
||||
RTTVar = (RTTVar * 3 + Math.abs(RTTAvg - latencyns)) / 4;
|
||||
RTTAvg = (RTTAvg * 7 + latencyns) / 8;
|
||||
}
|
||||
RTO = RTTAvg + Math.max(MIN_RTTVAR, RTTVar * 4);// RTTVar*4
|
||||
|
||||
RTTTotal += latencyns;
|
||||
RTTCount++;
|
||||
long curr=System.nanoTime();
|
||||
if(curr-RTTstartTime>RTTAvg2) {
|
||||
if(RTTCount>0) {
|
||||
RTTAvg2=(RTTAvg2+RTTTotal/RTTCount)/2;
|
||||
RTTTotal=0;
|
||||
RTTCount=0;
|
||||
}
|
||||
|
||||
RTTstartTime=curr;
|
||||
|
||||
if (bandwidth >= congressSpeed) {
|
||||
congressSpeed = bandwidth;
|
||||
//congressSpeed = (congressSpeed + bandwidth) / 2;
|
||||
} else {
|
||||
congressSpeed = (congressSpeed * 199 + bandwidth) / 200;
|
||||
}
|
||||
speed=MIN_SPEED+(long) (congressSpeed * speedGain) ;
|
||||
window= (Math.max(MIN_SPEED,(long) (congressSpeed*windowGain ))*(RTTMin+1000000L)/1000000000L)+MIN_WINDOW;
|
||||
if (windowControlConsumer != null) {
|
||||
windowControlConsumer.accept(window);
|
||||
}
|
||||
if (speedControlConsumer != null) {
|
||||
speedControlConsumer.accept(speed, BURST_TIME);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putLoss(long packetSize, long lossns, int losscounter) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRTO() {
|
||||
return RTO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentWindowUsed(long used) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentBandwidth(long bandwidth) {
|
||||
this.bandwidth=bandwidth;
|
||||
|
||||
//System.out.println(gain);
|
||||
//System.out.println(bandwidth+" "+congressSpeed+" "+window);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package org.kne.cloud.network.congress;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class BBRVegasCongressAlgorithm implements CongressAlgorithm {
|
||||
|
||||
private static final long BURST_TIME = 2000000L;
|
||||
private static final long BIAS = 2000000L;
|
||||
private static long MIN_SPEED = 128 * 1024L;
|
||||
private static long MIN_WINDOW = 8192;
|
||||
|
||||
private Consumer<Long> windowControlConsumer;
|
||||
private BiConsumer<Long, Long> speedControlConsumer;
|
||||
|
||||
private AtomicBoolean firstUpdate = new AtomicBoolean(true);
|
||||
private long MIN_RTTVAR = 50000000L;
|
||||
private volatile long RTTMin = 1000000000L;
|
||||
private volatile long RTTVar = 1000000000L;
|
||||
private volatile long RTTAvg = 1000000000L;
|
||||
private volatile long RTTAvg2 = 1000000000L;
|
||||
private volatile long RTTTotal = 0;
|
||||
private volatile long RTTCount = 0;
|
||||
private volatile long RTO = 1000000000L;
|
||||
|
||||
|
||||
private volatile long window=MIN_WINDOW;
|
||||
private volatile long speed=MIN_SPEED;
|
||||
private volatile long maxwindow=99999999999L;
|
||||
private long congressSpeed=MIN_SPEED;
|
||||
private double MAX_GAIN=2.8853900817779;//2.8853900817779
|
||||
private double MIN_GAIN=1.1;
|
||||
private double gain=MAX_GAIN;
|
||||
@Override
|
||||
public void reset() {
|
||||
window = MIN_WINDOW;
|
||||
if (windowControlConsumer != null) {
|
||||
windowControlConsumer.accept(window);
|
||||
}
|
||||
speed = MIN_SPEED;
|
||||
if (speedControlConsumer != null) {
|
||||
speedControlConsumer.accept(speed, BURST_TIME);
|
||||
}
|
||||
gain=MAX_GAIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWindowControlConsumer(Consumer<Long> windowControlConsumer) {
|
||||
this.windowControlConsumer = windowControlConsumer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSpeedControlConsumer(BiConsumer<Long, Long> speedControlConsumer) {
|
||||
this.speedControlConsumer = speedControlConsumer;
|
||||
}
|
||||
|
||||
private long RTTstartTime = System.nanoTime();
|
||||
@Override
|
||||
public synchronized void putAck(long packetSize, long latencyns, boolean ecn) {
|
||||
if (latencyns <= RTTMin) {
|
||||
RTTMin = latencyns;
|
||||
} else {
|
||||
RTTMin = (RTTMin * 99999 + latencyns) / 100000;
|
||||
}
|
||||
if (firstUpdate.compareAndSet(true, false)) {
|
||||
RTTAvg = latencyns;
|
||||
RTTVar = latencyns / 2;
|
||||
RTTAvg2 = latencyns;
|
||||
} else {
|
||||
RTTVar = (RTTVar * 3 + Math.abs(RTTAvg - latencyns)) / 4;
|
||||
RTTAvg = (RTTAvg * 7 + latencyns) / 8;
|
||||
}
|
||||
RTO = RTTAvg + Math.max(MIN_RTTVAR, RTTVar * 4);// RTTVar*4
|
||||
|
||||
RTTTotal += latencyns;
|
||||
RTTCount++;
|
||||
long curr=System.nanoTime();
|
||||
if(curr-RTTstartTime>RTTMin) {
|
||||
if(RTTCount>0) {
|
||||
RTTAvg2=(RTTAvg2+RTTTotal/RTTCount)/2;
|
||||
RTTTotal=0;
|
||||
RTTCount=0;
|
||||
}
|
||||
long RTTAvg2x=Math.max(RTTAvg2-BIAS,RTTMin);
|
||||
double excepted=window/(double)RTTMin;
|
||||
double actual=window/(double)RTTAvg2x;
|
||||
double diff=(excepted-actual)*RTTMin;
|
||||
if(diff>65536*3+3) {
|
||||
gain-=0.0005;
|
||||
}
|
||||
if(diff<65536*3+1) {
|
||||
gain+=0.0005;
|
||||
}
|
||||
if(gain>=MAX_GAIN){
|
||||
gain=MAX_GAIN;
|
||||
//System.out.println("window:"+window);
|
||||
}
|
||||
if(gain<MIN_GAIN) {
|
||||
gain=MIN_GAIN;
|
||||
//System.out.println("window:"+window);
|
||||
}
|
||||
RTTstartTime=curr;
|
||||
|
||||
}
|
||||
//System.out.println(speed+" "+window);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putLoss(long packetSize, long lossns, int losscounter) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRTO() {
|
||||
return RTO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentWindowUsed(long used) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentBandwidth(long bandwidth) {
|
||||
/*if (bandwidth >= congressSpeed) {
|
||||
congressSpeed = (congressSpeed * 49 + bandwidth) / 50;
|
||||
} else {
|
||||
congressSpeed = (congressSpeed *2 + bandwidth) / 3;
|
||||
}*/
|
||||
if (bandwidth >= congressSpeed) {
|
||||
//congressSpeed = bandwidth;
|
||||
congressSpeed = (congressSpeed + bandwidth) / 2;
|
||||
} else {
|
||||
congressSpeed = (congressSpeed * 49 + bandwidth) / 50;
|
||||
}
|
||||
speed=Math.max(MIN_SPEED,(long) (congressSpeed * gain)) ;
|
||||
window=Math.max( (Math.max(MIN_SPEED,(long) (congressSpeed*gain ))*Math.max(2000000L,RTTMin)/1000000000L),MIN_WINDOW);
|
||||
if (windowControlConsumer != null) {
|
||||
windowControlConsumer.accept(window);
|
||||
}
|
||||
if (speedControlConsumer != null) {
|
||||
speedControlConsumer.accept(speed, BURST_TIME);
|
||||
}
|
||||
//System.out.println(gain);
|
||||
//System.out.println(bandwidth+" "+congressSpeed+" "+window);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.kne.cloud.network.congress;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public interface CongressAlgorithm {
|
||||
public void reset();
|
||||
public void setWindowControlConsumer(Consumer<Long>windowControlConsumer);
|
||||
public void setSpeedControlConsumer(BiConsumer<Long,Long>speedControlConsumer);
|
||||
public void putAck(long packetSize,long latencyns,boolean ecn);
|
||||
public void putLoss(long packetSize,long lossns,int losscounter);
|
||||
public void setCurrentWindowUsed(long maxwindow);
|
||||
public void setCurrentBandwidth(long bandwidth);
|
||||
public long getRTO();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
package org.kne.cloud.network.congress;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class ECNCongressAlgorithm implements CongressAlgorithm {
|
||||
|
||||
private static final long BURST_TIME = 2000000L;
|
||||
private static final long BIAS = 2000000L;
|
||||
private static long MIN_SPEED = 64 * 1024L;
|
||||
private static long MIN_WINDOW = 16384;
|
||||
|
||||
private Consumer<Long> windowControlConsumer;
|
||||
private BiConsumer<Long, Long> speedControlConsumer;
|
||||
|
||||
private AtomicBoolean firstUpdate = new AtomicBoolean(true);
|
||||
private long MIN_RTTVAR = 50000000L;
|
||||
private volatile long RTTMin = 1000000000L;
|
||||
private volatile long RTTVar = 1000000000L;
|
||||
private volatile long RTTAvg = 1000000000L;
|
||||
private volatile long RTTAvg2 = 1000000000L;
|
||||
private double ECNAvg2 = 0L;
|
||||
private double alpha=0;
|
||||
private volatile AtomicLong RTTTotal = new AtomicLong(0);
|
||||
private volatile AtomicLong ECNSize = new AtomicLong(0);
|
||||
private volatile AtomicLong TotalSize = new AtomicLong(0);
|
||||
private volatile AtomicLong RTTCount = new AtomicLong(0);
|
||||
private volatile long RTO = 1000000000L;
|
||||
|
||||
|
||||
private volatile long window=MIN_WINDOW;
|
||||
private volatile long windowUsed=MIN_WINDOW;
|
||||
private volatile long congressWindowSize=MIN_WINDOW;
|
||||
private volatile long speed=MIN_SPEED;
|
||||
private long congressSpeed=MIN_SPEED;
|
||||
|
||||
private long RTTstartTime = System.nanoTime();
|
||||
private long bandwidth=MIN_SPEED;
|
||||
private double MAX_GAIN=1.2;//2.8853900817779
|
||||
private double MIN_GAIN=1.2;
|
||||
private double gain=MAX_GAIN;
|
||||
|
||||
private ReentrantLock lock=new ReentrantLock();
|
||||
@Override
|
||||
public void reset() {
|
||||
window = MIN_WINDOW;
|
||||
if (windowControlConsumer != null) {
|
||||
windowControlConsumer.accept(window);
|
||||
}
|
||||
speed = MIN_SPEED;
|
||||
if (speedControlConsumer != null) {
|
||||
speedControlConsumer.accept(speed, BURST_TIME);
|
||||
}
|
||||
gain=MAX_GAIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWindowControlConsumer(Consumer<Long> windowControlConsumer) {
|
||||
this.windowControlConsumer = windowControlConsumer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSpeedControlConsumer(BiConsumer<Long, Long> speedControlConsumer) {
|
||||
this.speedControlConsumer = speedControlConsumer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void putAck(long packetSize, long latencyns, boolean ecn) {
|
||||
if (latencyns <= RTTMin) {
|
||||
RTTMin = latencyns;
|
||||
} else {
|
||||
RTTMin = (RTTMin * 99999 + latencyns) / 100000;
|
||||
}
|
||||
if (firstUpdate.compareAndSet(true, false)) {
|
||||
RTTAvg = latencyns;
|
||||
RTTVar = latencyns / 2;
|
||||
RTTAvg2 = latencyns;
|
||||
} else {
|
||||
RTTVar = (RTTVar * 3 + Math.abs(RTTAvg - latencyns)) / 4;
|
||||
RTTAvg = (RTTAvg * 7 + latencyns) / 8;
|
||||
}
|
||||
RTO = RTTAvg + Math.max(MIN_RTTVAR, RTTVar * 4);// RTTVar*4
|
||||
|
||||
RTTTotal .addAndGet( latencyns);
|
||||
if(ecn) {
|
||||
ECNSize.addAndGet(packetSize);
|
||||
}
|
||||
TotalSize.addAndGet(packetSize);
|
||||
RTTCount.incrementAndGet();
|
||||
|
||||
|
||||
long curr=System.nanoTime();
|
||||
if(curr-RTTstartTime>RTTAvg2) {
|
||||
RTTstartTime=curr;
|
||||
lock.lock();
|
||||
try {
|
||||
if(RTTCount.get()>0) {
|
||||
long count=RTTCount.getAndSet(0);
|
||||
RTTAvg2=RTTTotal.getAndSet(0)/count;
|
||||
ECNAvg2=ECNSize.getAndSet(0)/(double)TotalSize.getAndSet(0);
|
||||
alpha=(alpha*15+ECNAvg2)/16;
|
||||
//System.out.println(alpha);
|
||||
}
|
||||
if(ECNAvg2>0.5) {
|
||||
gain=MIN_GAIN;
|
||||
if(congressWindowSize>MIN_WINDOW) {
|
||||
congressWindowSize=Math.max(MIN_WINDOW,(long) (congressWindowSize*(1-alpha/5)));
|
||||
updateWindowSize();
|
||||
}
|
||||
}else if(ECNAvg2>0.05){
|
||||
if(windowUsed*3L>=congressWindowSize) {
|
||||
congressWindowSize+=100;
|
||||
updateWindowSize();
|
||||
}
|
||||
}else {
|
||||
if(windowUsed*3L>=congressWindowSize) {
|
||||
congressWindowSize+=4000;
|
||||
updateWindowSize();
|
||||
}
|
||||
}
|
||||
|
||||
if (bandwidth >= congressSpeed) {
|
||||
congressSpeed = bandwidth;
|
||||
} else {
|
||||
congressSpeed = (congressSpeed * 99 + bandwidth) / 100;
|
||||
}
|
||||
speed=Math.max(MIN_SPEED,(long) (congressSpeed * gain)) ;
|
||||
|
||||
if (speedControlConsumer != null) {
|
||||
speedControlConsumer.accept(speed, BURST_TIME);
|
||||
}
|
||||
}finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
//System.out.println(speed+" "+window);
|
||||
|
||||
}
|
||||
|
||||
private void updateWindowSize() {
|
||||
window=Math.max( congressWindowSize,MIN_WINDOW);
|
||||
if (windowControlConsumer != null) {
|
||||
windowControlConsumer.accept(window);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putLoss(long packetSize, long lossns, int losscounter) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRTO() {
|
||||
return RTO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentWindowUsed(long used) {
|
||||
this.windowUsed=used;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentBandwidth(long bandwidth) {
|
||||
this.bandwidth=bandwidth;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package org.kne.cloud.network.congress;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class EmptyCongressAlgorithm implements CongressAlgorithm{
|
||||
|
||||
private long timeout;
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
// TODO 自动生成的方法存根
|
||||
|
||||
}
|
||||
|
||||
public long getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWindowControlConsumer(Consumer<Long> windowControlConsumer) {
|
||||
// TODO 自动生成的方法存根
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSpeedControlConsumer(BiConsumer<Long, Long> speedControlConsumer) {
|
||||
// TODO 自动生成的方法存根
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAck(long packetSize, long latencyns, boolean ecn) {
|
||||
// TODO 自动生成的方法存根
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putLoss(long packetSize, long lossns, int losscounter) {
|
||||
// TODO 自动生成的方法存根
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentWindowUsed(long maxwindow) {
|
||||
// TODO 自动生成的方法存根
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentBandwidth(long bandwidth) {
|
||||
// TODO 自动生成的方法存根
|
||||
|
||||
}
|
||||
|
||||
public EmptyCongressAlgorithm(long timeout) {
|
||||
super();
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRTO() {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package org.kne.cloud.network.congress;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class LARCCongressAlgorithm implements CongressAlgorithm {
|
||||
|
||||
private static final long BURST_TIME = 1000000L;
|
||||
private static final long BIAS = 1000000L;
|
||||
private static long MIN_SPEED = 64 * 1024L;
|
||||
private static long MIN_WINDOW = 16384;
|
||||
|
||||
private Consumer<Long> windowControlConsumer;
|
||||
private BiConsumer<Long, Long> speedControlConsumer;
|
||||
|
||||
private AtomicBoolean firstUpdate = new AtomicBoolean(true);
|
||||
private long MIN_RTTVAR = 10000000L;
|
||||
private volatile long RTTMin = 1000000000L;
|
||||
private volatile long RTTVar = 1000000000L;
|
||||
private volatile long RTTAvg = 1000000000L;
|
||||
private volatile long RTTAvg2 = 1000000000L;
|
||||
private volatile long RTTTotal = 0;
|
||||
private volatile long RTTCount = 0;
|
||||
private volatile long RTO = 1000000000L;
|
||||
|
||||
|
||||
private volatile long window=MIN_WINDOW;
|
||||
private volatile long speed=MIN_SPEED;
|
||||
private volatile long maxwindow=99999999999L;
|
||||
private long congressSpeed=MIN_SPEED;
|
||||
private double MAX_GAIN=1.1;//2.8853900817779
|
||||
private double MIN_GAIN=0.95;
|
||||
private double windowGain=1.5;
|
||||
private double speedGain=4;//MAX_GAIN
|
||||
@Override
|
||||
public void reset() {
|
||||
window = MIN_WINDOW;
|
||||
if (windowControlConsumer != null) {
|
||||
windowControlConsumer.accept(window);
|
||||
}
|
||||
speed = MIN_SPEED;
|
||||
if (speedControlConsumer != null) {
|
||||
speedControlConsumer.accept(speed, BURST_TIME);
|
||||
}
|
||||
windowGain=MAX_GAIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWindowControlConsumer(Consumer<Long> windowControlConsumer) {
|
||||
this.windowControlConsumer = windowControlConsumer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSpeedControlConsumer(BiConsumer<Long, Long> speedControlConsumer) {
|
||||
this.speedControlConsumer = speedControlConsumer;
|
||||
}
|
||||
|
||||
private long RTTstartTime = System.nanoTime();
|
||||
private long bandwidth;
|
||||
@Override
|
||||
public synchronized void putAck(long packetSize, long latencyns, boolean ecn) {
|
||||
if (latencyns <= RTTMin) {
|
||||
RTTMin = latencyns;
|
||||
} else {
|
||||
RTTMin = (RTTMin * 99999 + latencyns) / 100000;
|
||||
}
|
||||
if (firstUpdate.compareAndSet(true, false)) {
|
||||
RTTAvg = latencyns;
|
||||
RTTVar = latencyns / 2;
|
||||
RTTAvg2 = latencyns;
|
||||
} else {
|
||||
RTTVar = (RTTVar * 3 + Math.abs(RTTAvg - latencyns)) / 4;
|
||||
RTTAvg = (RTTAvg * 7 + latencyns) / 8;
|
||||
}
|
||||
RTO = RTTAvg + Math.max(MIN_RTTVAR, RTTVar * 4);// RTTVar*4
|
||||
|
||||
RTTTotal += latencyns;
|
||||
RTTCount++;
|
||||
/*double rate=latencyns/(double)(RTTMin+BIAS);
|
||||
if(rate>2) {
|
||||
windowGain=MIN_GAIN;
|
||||
}else if(rate<1.2){
|
||||
windowGain=MAX_GAIN;
|
||||
|
||||
}*/
|
||||
long curr=System.nanoTime();
|
||||
if(curr-RTTstartTime>RTTAvg2) {
|
||||
if(RTTCount>0) {
|
||||
RTTAvg2=(RTTAvg2+RTTTotal/RTTCount)/2;
|
||||
RTTTotal=0;
|
||||
RTTCount=0;
|
||||
}
|
||||
|
||||
RTTstartTime=curr;
|
||||
|
||||
if (bandwidth >= congressSpeed) {
|
||||
congressSpeed = bandwidth;
|
||||
//congressSpeed = (congressSpeed + bandwidth) / 2;
|
||||
} else {
|
||||
congressSpeed = (congressSpeed * 199 + bandwidth) / 200;
|
||||
}
|
||||
speed=(long) (congressSpeed * speedGain)+MIN_SPEED ;
|
||||
window= ((long) (congressSpeed*windowGain )*(RTTMin+BIAS)/1000000000L)+MIN_WINDOW;
|
||||
if (windowControlConsumer != null) {
|
||||
windowControlConsumer.accept(window);
|
||||
}
|
||||
if (speedControlConsumer != null) {
|
||||
speedControlConsumer.accept(speed, BURST_TIME);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putLoss(long packetSize, long lossns, int losscounter) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRTO() {
|
||||
return RTO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentWindowUsed(long used) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentBandwidth(long bandwidth) {
|
||||
this.bandwidth=bandwidth;
|
||||
|
||||
//System.out.println(gain);
|
||||
//System.out.println(bandwidth+" "+congressSpeed+" "+window);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
package org.kne.cloud.network.congress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* 网络消息批量发送器,用于减少小包数量,降低网络性能开销
|
||||
* @param <T> 消息类型
|
||||
*/
|
||||
public class MessageBatcher<T> implements Runnable{
|
||||
private ArrayList<T> messageList;
|
||||
private ReentrantLock lock=new ReentrantLock();
|
||||
private final int batchSize;
|
||||
private final long maxDelay;
|
||||
private Consumer<List<T>> consumer;
|
||||
private final Thread batchThread;
|
||||
private final AtomicBoolean running;
|
||||
private long firstTime;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @param batchSize 批量大小,当消息达到此数量时触发发送
|
||||
* @param maxDelayMillis 最大延迟时间(毫秒),即使消息数量不足也会触发发送
|
||||
*/
|
||||
public MessageBatcher(int batchSize, long maxDelay) {
|
||||
this.batchSize = batchSize;
|
||||
this.maxDelay = maxDelay;
|
||||
this.running = new AtomicBoolean(true);
|
||||
|
||||
// 创建并启动批量处理线程
|
||||
this.batchThread = new Thread(this);
|
||||
this.batchThread.setDaemon(true);
|
||||
this.batchThread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置消息消费者回调函数
|
||||
* @param consumer 消费者回调
|
||||
*/
|
||||
public void setConsumer(Consumer<List<T>> consumer) {
|
||||
this.consumer = consumer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加消息到批量处理器
|
||||
* @param message 消息对象
|
||||
*/
|
||||
public void putMessage(T message) {
|
||||
if (message != null) {
|
||||
lock.lock();
|
||||
try {
|
||||
if(messageList==null) {
|
||||
messageList=new ArrayList<T>(batchSize);
|
||||
firstTime=System.nanoTime();
|
||||
}
|
||||
messageList.add(message);
|
||||
check(false);
|
||||
}finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 批量添加消息
|
||||
* @param messages 消息列表
|
||||
*/
|
||||
public void putMessages(List<T> messages) {
|
||||
for(T message :messages) {
|
||||
putMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void check(boolean force) {
|
||||
if(messageList==null)
|
||||
return;
|
||||
long currTime=System.nanoTime();
|
||||
if(messageList.size()>=batchSize||(currTime-firstTime)>maxDelay||force) {
|
||||
if(consumer!=null) {
|
||||
try {
|
||||
consumer.accept(messageList);
|
||||
}catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
messageList=null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止批量处理器
|
||||
*/
|
||||
public void close() {
|
||||
running.set(false);
|
||||
LockSupport.unpark(batchThread);
|
||||
// 确保所有消息都被发送
|
||||
flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量处理消息的核心方法
|
||||
*/
|
||||
public void run() {
|
||||
while(running.get()) {
|
||||
lock.lock();
|
||||
try {
|
||||
check(false);
|
||||
}finally {
|
||||
lock.unlock();
|
||||
}
|
||||
// 更精确的等待策略
|
||||
long sleepTimeNanos = calculateSleepTime();
|
||||
if (sleepTimeNanos > 0) {
|
||||
LockSupport.parkNanos(sleepTimeNanos);
|
||||
} else {
|
||||
// 避免忙等待
|
||||
LockSupport.parkNanos(1_000_000L); // 1ms
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算需要等待的时间
|
||||
* @return 等待时间(纳秒)
|
||||
*/
|
||||
private long calculateSleepTime() {
|
||||
lock.lock();
|
||||
try {
|
||||
if (messageList == null || messageList.isEmpty()) {
|
||||
return 10_000_000L; // 10ms
|
||||
}
|
||||
|
||||
long elapsed = System.nanoTime() - firstTime;
|
||||
long remaining = maxDelay - elapsed;
|
||||
|
||||
if (remaining <= 0) {
|
||||
return 0; // 立即处理
|
||||
}
|
||||
|
||||
// 返回剩余时间或10ms中的较小值
|
||||
return Math.min(remaining, 10_000_000L);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public int getBatchSize() {
|
||||
return batchSize;
|
||||
}
|
||||
|
||||
public long getMaxDelay() {
|
||||
return maxDelay;
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
lock.lock();
|
||||
try {
|
||||
check(true);
|
||||
}finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public int getQueueSize() {
|
||||
List<T> cmessageList =messageList;
|
||||
if(cmessageList==null)
|
||||
return 0;
|
||||
return cmessageList.size();
|
||||
}
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
MessageBatcher<Integer>mes=new MessageBatcher<>(10, 1000000L);
|
||||
mes.setConsumer((x)->{System.out.println(x);});
|
||||
int n=0;
|
||||
for(;;){
|
||||
mes.putMessage(n++);
|
||||
mes.putMessage(n++);
|
||||
mes.putMessage(n++);
|
||||
mes.putMessage(n++);
|
||||
Thread.sleep(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package org.kne.cloud.network.congress;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||
|
||||
public class ReceiveByteSlidingWindow<E> {
|
||||
private AtomicReferenceArray<E> array;
|
||||
private AtomicInteger windowSize =new AtomicInteger();
|
||||
private AtomicLong windowPosition=new AtomicLong();
|
||||
|
||||
public int getWindowSize() {
|
||||
return windowSize.get();
|
||||
}
|
||||
|
||||
public void setWindowSize(int windowSize) {
|
||||
this.windowSize.set(windowSize);
|
||||
}
|
||||
|
||||
public long getWindowPosition() {
|
||||
return windowPosition.get();
|
||||
}
|
||||
|
||||
public void setWindowPosition(long windowPosition) {
|
||||
this.windowPosition.set(windowPosition);
|
||||
}
|
||||
|
||||
public ReceiveByteSlidingWindow(int capacity){
|
||||
array=new AtomicReferenceArray<E>(capacity);
|
||||
}
|
||||
|
||||
public boolean push(E object) {
|
||||
Objects.requireNonNull(object);
|
||||
if(array.get((int) ((windowPosition.get()-windowSize.get())%array.length()))==null ) {
|
||||
array.set((int) (windowPosition.getAndIncrement()%array.length()), object);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public E pull(long number) {
|
||||
return array.getAndSet((int) (number%array.length()), null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package org.kne.cloud.network.congress;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||
|
||||
public class SendByteSlidingWindow<E> implements Iterable<E>{
|
||||
private Object[] array;
|
||||
private volatile int windowSize ;
|
||||
private volatile long windowPosition;
|
||||
|
||||
public int getWindowSize() {
|
||||
return windowSize;
|
||||
}
|
||||
|
||||
public void setWindowSize(int windowSize) {
|
||||
this.windowSize=windowSize;
|
||||
}
|
||||
|
||||
public long getWindowPosition() {
|
||||
return windowPosition;
|
||||
}
|
||||
|
||||
public void setWindowPosition(long windowPosition) {
|
||||
this.windowPosition=windowPosition;
|
||||
}
|
||||
|
||||
public SendByteSlidingWindow(int capacity,int windowSize){
|
||||
if(windowSize>capacity) {
|
||||
throw new IllegalArgumentException("windowSize>capacity!");
|
||||
}
|
||||
array= new Object[capacity];
|
||||
this.windowSize=windowSize;
|
||||
}
|
||||
|
||||
public boolean checkPush() {
|
||||
if(array[calcPosition(windowPosition-windowSize)]==null ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void push(E object) {
|
||||
|
||||
array[calcPosition(windowPosition)]= object;
|
||||
}
|
||||
|
||||
public E remove(long number) {
|
||||
if(number<windowPosition&&number>=windowPosition-windowSize) {
|
||||
int indp=calcPosition(number);
|
||||
E old=(E) array[indp];
|
||||
array[indp]=null;
|
||||
return old;
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
for (long i = windowPosition-windowSize; i < windowPosition; i++) {
|
||||
if(array[calcPosition(i)]!=null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public E get(long number) {
|
||||
if(number<windowPosition&&number>=windowPosition-windowSize) {
|
||||
return (E) array[calcPosition(number)];
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return new Iterator<E>() {
|
||||
private long pointer=windowPosition-windowSize;
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return pointer<windowPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E next() {
|
||||
return (E) array[calcPosition(pointer++)];
|
||||
}
|
||||
};
|
||||
}
|
||||
private int calcPosition(long number) {
|
||||
return (int) ((number+array.length)%array.length);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
package org.kne.cloud.network.congress;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.net.SocketException;
|
||||
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.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.ipv6.IPv6Packet;
|
||||
import org.kne.cloud.network.klalb.SendItem;
|
||||
|
||||
public class SendPacketSlidingWindow <K,V extends NetworkPacket> implements Closeable,AutoCloseable{
|
||||
private Map<K,SendItem<V>> sendMap= new ConcurrentHashMap<>(1024,0.2f);
|
||||
//private AtomicInteger sendmapWindowUsed=new AtomicInteger(0);
|
||||
private LongAdder sendmapWindowUsed=new LongAdder();
|
||||
|
||||
private int headerCalibrate=0;
|
||||
public void setHeaderCalibrate(int headerCalibrate) {
|
||||
this.headerCalibrate = headerCalibrate;
|
||||
}
|
||||
|
||||
private CongressAlgorithm algorithm;
|
||||
|
||||
private Consumer<V> resendConsumer;
|
||||
private Consumer<V> closingConsumer;
|
||||
private volatile boolean closed=false;
|
||||
private ResendChecker checker=new ResendChecker();
|
||||
private AtomicLong windowSize = new AtomicLong();
|
||||
|
||||
|
||||
private Lock lock;
|
||||
|
||||
private Condition condition;
|
||||
|
||||
public SendPacketSlidingWindow(CongressAlgorithm algorithm, long windowSize) {
|
||||
super();
|
||||
this.algorithm = algorithm;
|
||||
this.windowSize .set( windowSize);
|
||||
Thread t=new Thread(checker);
|
||||
t.start();
|
||||
}
|
||||
|
||||
public SendPacketSlidingWindow(CongressAlgorithm algorithm, long windowSize,int headerCalibrate) {
|
||||
this(algorithm,windowSize);
|
||||
this.headerCalibrate=headerCalibrate;
|
||||
}
|
||||
|
||||
public long getWindowSize() {
|
||||
return windowSize.get();
|
||||
}
|
||||
|
||||
public void setWindowSize(long windowSize) {
|
||||
this.windowSize.set(windowSize);
|
||||
}
|
||||
|
||||
public Consumer<V> getResendConsumer() {
|
||||
return resendConsumer;
|
||||
}
|
||||
|
||||
public void setResendConsumer(Consumer<V> resendConsumer) {
|
||||
this.resendConsumer = resendConsumer;
|
||||
}
|
||||
|
||||
public Consumer<V> getClosingConsumer() {
|
||||
return closingConsumer;
|
||||
}
|
||||
|
||||
public void setClosingConsumer(Consumer<V> closingConsumer) {
|
||||
this.closingConsumer = closingConsumer;
|
||||
}
|
||||
|
||||
public long getSendmapWindowUsed() {
|
||||
return sendmapWindowUsed.sum();
|
||||
}
|
||||
|
||||
public int getHeaderCalibrate() {
|
||||
return headerCalibrate;
|
||||
}
|
||||
|
||||
public CongressAlgorithm getAlgorithm() {
|
||||
return algorithm;
|
||||
}
|
||||
|
||||
|
||||
public boolean isCongress(IPv6Packet iPv6Packet,double scale) {
|
||||
boolean congress=sendmapWindowUsed.sum()>windowSize.get()*scale;
|
||||
return congress;
|
||||
|
||||
}
|
||||
|
||||
public void put(K sequence,V packet) throws SocketException {
|
||||
if(closed) {
|
||||
throw new SocketException("sliding window closed!");
|
||||
}
|
||||
SendItem<V> newitem=new SendItem<V>( packet);
|
||||
SendItem<V> old= sendMap.put(sequence,newitem);
|
||||
if(old!=null) {
|
||||
sendmapWindowUsed.add( -(old.getPacketLength()+headerCalibrate));
|
||||
}
|
||||
sendmapWindowUsed.add( (newitem.getPacketLength()+headerCalibrate));
|
||||
long newWindow=sendmapWindowUsed.sum();
|
||||
algorithm.setCurrentWindowUsed(newWindow);
|
||||
}
|
||||
|
||||
public V ack(K sequence) {
|
||||
SendItem<V> ipv6;
|
||||
if((ipv6=sendMap.remove(sequence))!=null) {
|
||||
sendmapWindowUsed.add( -(ipv6.getPacketLength()+headerCalibrate));
|
||||
long newWindow= sendmapWindowUsed.sum();
|
||||
algorithm.setCurrentWindowUsed(newWindow);
|
||||
long RTTC=System.nanoTime()-ipv6.getSendtime();
|
||||
algorithm.putAck(ipv6.getPacketLength(), RTTC, false);
|
||||
//System.out.println("remove:"+aseq.getSequence()+" "+sendMap.size());
|
||||
Lock lockx=lock;
|
||||
if(lockx!=null) {
|
||||
lockx.lock();
|
||||
try {
|
||||
Condition cds=condition;
|
||||
if(cds!=null) {
|
||||
cds.signalAll();
|
||||
}
|
||||
}finally {
|
||||
lockx.unlock();
|
||||
}
|
||||
}
|
||||
return ipv6.getPacket();
|
||||
}else {
|
||||
// System.out.println("miss:"+aseq.getSequence()+" "+sendMap.size());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private class ResendChecker implements Runnable{
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while(!closed) {
|
||||
|
||||
Collection<SendItem<V>>vals= sendMap.values();
|
||||
for (Iterator<SendItem<V>> iterator = vals.iterator(); iterator.hasNext();) {
|
||||
SendItem<V> sitm = (SendItem<V>) iterator.next();
|
||||
if(System.nanoTime() -sitm.getSendtime()>algorithm.getRTO()) {
|
||||
iterator.remove();
|
||||
sendmapWindowUsed.add((int) -(sitm.getPacketLength()+headerCalibrate));
|
||||
long newWindow=sendmapWindowUsed.sum();
|
||||
algorithm.setCurrentWindowUsed(newWindow);
|
||||
//if(!kplink.isStream())
|
||||
V pktr=sitm.getPacket();
|
||||
pktr.setPriority(pktr.getPriority()-1);
|
||||
if(resendConsumer!=null)
|
||||
resendConsumer.accept(pktr);
|
||||
//System.out.println("reroute");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
try {
|
||||
Thread.sleep(2);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
// 清理资源
|
||||
if (closingConsumer != null) {
|
||||
for (SendItem<V> item : sendMap.values()) {
|
||||
closingConsumer.accept(item.getPacket());
|
||||
}
|
||||
}
|
||||
sendMap.clear();
|
||||
sendmapWindowUsed.reset();
|
||||
}
|
||||
}
|
||||
public boolean isClosed() {
|
||||
return closed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
closed=true;
|
||||
}
|
||||
|
||||
public void setCongressCondition(Lock lock2, Condition condition2) {
|
||||
this.lock=lock2;
|
||||
this.condition=condition2;
|
||||
}
|
||||
|
||||
public Map<K, SendItem<V>> getSendmap() {
|
||||
return sendMap;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package org.kne.cloud.network.congress;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class VegasCongressAlgorithm implements CongressAlgorithm {
|
||||
|
||||
private static final long BURST_TIME = 1000000L;
|
||||
private static final long BIAS = 1000000L;
|
||||
private static long MIN_SPEED=256*1024L;
|
||||
private static long MIN_WINDOW=4096L;
|
||||
|
||||
private Consumer<Long> windowControlConsumer;
|
||||
private BiConsumer<Long, Long> speedControlConsumer;
|
||||
|
||||
private AtomicBoolean firstUpdate=new AtomicBoolean(true);
|
||||
private long MIN_RTTVAR=30000000L;
|
||||
private volatile long RTTMin=1000000000L;
|
||||
private volatile long RTTVar=1000000000L;
|
||||
private volatile long RTTAvg=1000000000L;
|
||||
private volatile long RTTAvg2=1000000000L;
|
||||
private volatile long RTTTotal=0;
|
||||
private volatile long RTTCount=0;
|
||||
private volatile long RTO=1000000000L;
|
||||
|
||||
private volatile long window=MIN_WINDOW;
|
||||
private volatile long speed=MIN_SPEED;
|
||||
private volatile long maxwindow=99999999999L;
|
||||
@Override
|
||||
public void reset() {
|
||||
window=MIN_WINDOW;
|
||||
if(windowControlConsumer!=null) {
|
||||
windowControlConsumer.accept(window);
|
||||
}
|
||||
speed=MIN_SPEED;
|
||||
if(speedControlConsumer!=null) {
|
||||
speedControlConsumer.accept(speed, BURST_TIME);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWindowControlConsumer(Consumer<Long> windowControlConsumer) {
|
||||
this.windowControlConsumer=windowControlConsumer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSpeedControlConsumer(BiConsumer<Long, Long> speedControlConsumer) {
|
||||
this.speedControlConsumer=speedControlConsumer;
|
||||
}
|
||||
private long RTTstartTime=System.nanoTime();
|
||||
@Override
|
||||
public synchronized void putAck(long packetSize, long latencyns, boolean ecn) {
|
||||
if(latencyns<=RTTMin) {
|
||||
RTTMin=latencyns;
|
||||
}else {
|
||||
RTTMin= (RTTMin*9999+latencyns)/10000;
|
||||
}
|
||||
if(firstUpdate.compareAndSet(true, false)) {
|
||||
RTTAvg=latencyns;
|
||||
RTTVar=latencyns/2;
|
||||
RTTAvg2=latencyns;
|
||||
}else {
|
||||
RTTVar=(RTTVar*3+Math.abs(RTTAvg-latencyns))/4;
|
||||
RTTAvg= (RTTAvg*7+latencyns)/8;
|
||||
}
|
||||
RTO=RTTAvg+Math.max(MIN_RTTVAR, RTTVar*4);//RTTVar*4
|
||||
|
||||
RTTTotal+=latencyns;
|
||||
RTTCount++;
|
||||
|
||||
long curr=System.nanoTime();
|
||||
if(curr-RTTstartTime>RTTMin) {
|
||||
if(RTTCount>0) {
|
||||
RTTAvg2=(RTTAvg2+RTTTotal/RTTCount)/2;
|
||||
RTTTotal=0;
|
||||
RTTCount=0;
|
||||
}
|
||||
double excepted=window/(double)(Math.max( BIAS,RTTMin));
|
||||
double actual=window/(double)(RTTAvg2);
|
||||
double diff=(excepted-actual)*(Math.max( BIAS,RTTMin));
|
||||
//System.out.println("diff:"+diff);
|
||||
if(diff>65536*3) {
|
||||
window-=512;
|
||||
}
|
||||
if(diff<65536*2) {
|
||||
window+=512;
|
||||
}
|
||||
if(window>=maxwindow){
|
||||
window=maxwindow;
|
||||
//System.out.println("window:"+window);
|
||||
}
|
||||
if(window<MIN_WINDOW) {
|
||||
window=MIN_WINDOW;
|
||||
//System.out.println("window:"+window);
|
||||
}
|
||||
RTTstartTime=curr;
|
||||
if(windowControlConsumer!=null) {
|
||||
windowControlConsumer.accept(window);
|
||||
}
|
||||
speed=Math.max(MIN_SPEED, (long) (window/(double)(RTTAvg2)*1000000000.0*1.2));
|
||||
if(speedControlConsumer!=null) {
|
||||
speedControlConsumer.accept(speed, BURST_TIME);
|
||||
}
|
||||
//System.out.println(speed+" "+window);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putLoss(long packetSize, long lossns, int losscounter) {
|
||||
// TODO 自动生成的方法存根
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRTO() {
|
||||
return RTO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentWindowUsed(long used) {
|
||||
this.maxwindow=used*16+65536;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentBandwidth(long bandwidth) {
|
||||
// TODO 自动生成的方法存根
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user