forked from KNEMC/KLALB
KLALB V3.6.0 写了一半
This commit is contained in:
@@ -7,6 +7,7 @@ import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.concurrent.atomic.LongAdder;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
@@ -14,447 +15,500 @@ import org.kne.cloud.clock.HighAccuracyClock;
|
||||
import org.kne.cloud.network.klalb.KLALBUtils;
|
||||
import org.kne.math.Long128;
|
||||
|
||||
public class ArrayListTimestampMonitor<K> implements TimestampMonitor<K>{
|
||||
|
||||
|
||||
public class ArrayListTimestampMonitor<K> implements TimestampMonitor<K> {
|
||||
|
||||
private HighAccuracyClock clock;
|
||||
private String name;
|
||||
|
||||
// 使用LongAdder替代AtomicLong,在高并发下性能更好
|
||||
private final LongAdder totalDataSize = new LongAdder();
|
||||
private final LongAdder totalPackets = new LongAdder();
|
||||
|
||||
// 配置参数
|
||||
private final int maxRetry;
|
||||
private final long cleanupThreshold;
|
||||
|
||||
// 使用ArrayList存储数据
|
||||
private final List<TimestampMonitorValue> entries = new ArrayList<>();
|
||||
|
||||
// 读写锁用于保护ArrayList的并发访问
|
||||
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
|
||||
|
||||
// 时间戳验证容差(纳秒),考虑到网络延迟和时钟同步
|
||||
private static final long TIMESTAMP_TOLERANCE_NS = 10_000_000L; // 10毫秒
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public HighAccuracyClock getClock() {
|
||||
private String name;
|
||||
|
||||
// 使用LongAdder替代AtomicLong,在高并发下性能更好
|
||||
private final LongAdder totalDataSize = new LongAdder();
|
||||
private final LongAdder totalPackets = new LongAdder();
|
||||
|
||||
// 配置参数
|
||||
private final int maxRetry;
|
||||
private final long cleanupThreshold;
|
||||
|
||||
// 使用ArrayList存储数据
|
||||
private final List<TimestampMonitorValue> entries = new ArrayList<>();
|
||||
|
||||
// 读写锁用于保护ArrayList的并发访问
|
||||
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
|
||||
|
||||
// 时间戳验证容差(纳秒),考虑到网络延迟和时钟同步
|
||||
private static final long TIMESTAMP_TOLERANCE_NS = 10_000_000L; // 10毫秒
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public HighAccuracyClock getClock() {
|
||||
return clock;
|
||||
}
|
||||
protected ArrayListTimestampMonitor(HighAccuracyClock clock, String name, int maxRetry, long cleanupThreshold) {
|
||||
super();
|
||||
this.clock = clock;
|
||||
this.name = name;
|
||||
this.maxRetry = maxRetry;
|
||||
this.cleanupThreshold = cleanupThreshold;
|
||||
}
|
||||
|
||||
public ArrayListTimestampMonitor() {
|
||||
this(new HighAccuracyClock(), "TimestampMonitor", 100, 1000000000L);
|
||||
}
|
||||
|
||||
public ArrayListTimestampMonitor(HighAccuracyClock clock, String name) {
|
||||
this(clock, name, 100, 1000000000L);
|
||||
}
|
||||
|
||||
private volatile long prev = System.nanoTime();
|
||||
|
||||
public boolean recordPacket(K key, int length) {
|
||||
return recordPacket(key, clock.getCurrentTimeNanos(), length);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录数据包 - 使用插入排序保持列表有序,添加时间戳验证
|
||||
*/
|
||||
public boolean recordPacket(K key, Long128 timestamp, int length) {
|
||||
// 验证时间戳的合理性
|
||||
validateTimestamp(timestamp);
|
||||
|
||||
// 快速路径:尝试sequence=0
|
||||
TimestampMonitorKey<K> monitorKey = new TimestampMonitorKey<>(key, 0);
|
||||
TimestampMonitorValue monitorValue = new TimestampMonitorValue(monitorKey, timestamp, length);
|
||||
autoCleanup(cleanupThreshold);
|
||||
|
||||
rwLock.writeLock().lock();
|
||||
try {
|
||||
// 使用二分查找插入排序,保持列表有序
|
||||
insertSorted(monitorValue);
|
||||
totalDataSize.add(length);
|
||||
totalPackets.increment();
|
||||
return true;
|
||||
} finally {
|
||||
rwLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证时间戳的合理性
|
||||
*/
|
||||
private void validateTimestamp(Long128 timestamp) {
|
||||
/* BigInteger currentTime = clock.getCurrentTimeNanos();
|
||||
BigInteger maxAllowedTime = currentTime.add(BigInteger.valueOf(TIMESTAMP_TOLERANCE_NS));
|
||||
|
||||
if (timestamp.compareTo(maxAllowedTime) > 0) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Timestamp %s is in the future (current time: %s, tolerance: %d ns)",
|
||||
timestamp, currentTime, TIMESTAMP_TOLERANCE_NS));
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用二分查找进行插入排序,保持列表有序
|
||||
*/
|
||||
private void insertSorted(TimestampMonitorValue newValue) {
|
||||
if (entries.isEmpty()) {
|
||||
entries.add(newValue);
|
||||
return;
|
||||
}
|
||||
|
||||
// 优化:检查是否可以快速添加到末尾(大部分数据包是按时间顺序到达的)
|
||||
TimestampMonitorValue lastValue = entries.get(entries.size() - 1);
|
||||
if (newValue.getTimestamp().compareTo(lastValue.getTimestamp()) >= 0) {
|
||||
entries.add(newValue);
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用二分查找找到插入位置
|
||||
int insertIndex = findInsertIndex(newValue.getTimestamp());
|
||||
entries.add(insertIndex, newValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用二分查找找到插入位置
|
||||
*/
|
||||
private int findInsertIndex(Long128 timestamp) {
|
||||
int low = 0;
|
||||
int high = entries.size() - 1;
|
||||
|
||||
while (low <= high) {
|
||||
int mid = (low + high) >>> 1;
|
||||
Long128 midTimestamp = entries.get(mid).getTimestamp();
|
||||
int cmp = timestamp.compareTo(midTimestamp);
|
||||
|
||||
if (cmp < 0) {
|
||||
high = mid - 1;
|
||||
} else if (cmp > 0) {
|
||||
low = mid + 1;
|
||||
} else {
|
||||
// 时间戳相等,插入到相同时间戳的后面
|
||||
return findLastEqualIndex(mid, timestamp) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return low;
|
||||
}
|
||||
|
||||
/**
|
||||
* 找到相同时间戳的最后一个元素的索引
|
||||
*/
|
||||
private int findLastEqualIndex(int startIndex, Long128 timestamp) {
|
||||
int index = startIndex;
|
||||
while (index < entries.size() - 1 &&
|
||||
entries.get(index + 1).getTimestamp().equals(timestamp)) {
|
||||
index++;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
private void autoCleanup(long th) {
|
||||
long curr = System.nanoTime();
|
||||
if (curr - prev > th) {
|
||||
prev = curr;
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
cleanup(clock.getCurrentTimeNanos(), cleanupThreshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理旧记录 - 由于列表已排序,直接使用二分查找
|
||||
*/
|
||||
public void cleanup(Long128 currentTime, long timeWindowNs) {
|
||||
Long128 startTime = currentTime.subtract(Long128.valueOf(timeWindowNs));
|
||||
|
||||
rwLock.writeLock().lock();
|
||||
try {
|
||||
// 使用二分查找找到第一个不过期的元素位置
|
||||
int firstValidIndex = findFirstValidIndex(startTime);
|
||||
|
||||
if (firstValidIndex > 0) {
|
||||
// 删除所有过期的元素
|
||||
entries.subList(0, firstValidIndex).clear();
|
||||
}
|
||||
} finally {
|
||||
rwLock.writeLock().unlock();
|
||||
}
|
||||
prev=System.nanoTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用二分查找找到第一个时间戳 >= startTime 的元素索引
|
||||
*/
|
||||
private int findFirstValidIndex(Long128 startTime) {
|
||||
int low = 0;
|
||||
int high = entries.size();
|
||||
|
||||
while (low < high) {
|
||||
int mid = (low + high) >>> 1;
|
||||
Long128 midTimestamp = entries.get(mid).getTimestamp();
|
||||
|
||||
if (midTimestamp.compareTo(startTime) < 0) {
|
||||
low = mid + 1;
|
||||
} else {
|
||||
high = mid;
|
||||
}
|
||||
}
|
||||
|
||||
return low;
|
||||
}
|
||||
|
||||
public long calculateDataVolume(long timeWindowNs) {
|
||||
return calculateDataVolume(clock.getCurrentTimeNanos(), timeWindowNs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 高性能数据量计算 - 优化:由于数据包不会来自未来,只需要查找startTime
|
||||
*/
|
||||
public long calculateDataVolume(Long128 currentTime, long timeWindowNs) {
|
||||
Long128 startTime = currentTime.subtract(Long128.valueOf(timeWindowNs));
|
||||
|
||||
rwLock.readLock().lock();
|
||||
try {
|
||||
return calculateDataVolumeFromSortedList(entries, startTime);
|
||||
} finally {
|
||||
rwLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从已排序的列表中计算数据量 - 优化版本,只需要startTime
|
||||
*/
|
||||
private long calculateDataVolumeFromSortedList(List<TimestampMonitorValue> sortedList,
|
||||
Long128 startTime) {
|
||||
if (sortedList.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 使用二分查找找到第一个 >= startTime 的元素位置
|
||||
int startIndex = findFirstValidIndexFromSorted(sortedList, startTime);
|
||||
|
||||
if (startIndex >= sortedList.size()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 计算从startIndex到末尾的所有数据量(因为数据包不会来自未来)
|
||||
long sum = 0;
|
||||
for (int i = startIndex; i < sortedList.size(); i++) {
|
||||
sum += sortedList.get(i).getLength();
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在已排序列表中找到第一个时间戳 >= startTime 的索引
|
||||
*/
|
||||
private int findFirstValidIndexFromSorted(List<TimestampMonitorValue> sortedList, Long128 startTime) {
|
||||
int low = 0;
|
||||
int high = sortedList.size();
|
||||
|
||||
while (low < high) {
|
||||
int mid = (low + high) >>> 1;
|
||||
Long128 midTimestamp = sortedList.get(mid).getTimestamp();
|
||||
|
||||
if (midTimestamp.compareTo(startTime) < 0) {
|
||||
low = mid + 1;
|
||||
} else {
|
||||
high = mid;
|
||||
}
|
||||
}
|
||||
|
||||
return low;
|
||||
}
|
||||
|
||||
public long calculatePacketCount(long timeWindowNs) {
|
||||
return calculatePacketCount(clock.getCurrentTimeNanos(), timeWindowNs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 高性能包数计算 - 优化:由于数据包不会来自未来,只需要查找startTime
|
||||
*/
|
||||
public long calculatePacketCount(Long128 currentTime, long timeWindowNs) {
|
||||
Long128 startTime = currentTime.subtract(Long128.valueOf(timeWindowNs));
|
||||
|
||||
rwLock.readLock().lock();
|
||||
try {
|
||||
return calculatePacketCountFromSortedList(entries, startTime);
|
||||
} finally {
|
||||
rwLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从已排序的列表中计算包数 - 优化版本,只需要startTime
|
||||
*/
|
||||
private long calculatePacketCountFromSortedList(List<TimestampMonitorValue> sortedList,
|
||||
Long128 startTime) {
|
||||
if (sortedList.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int startIndex = findFirstValidIndexFromSorted(sortedList, startTime);
|
||||
|
||||
if (startIndex >= sortedList.size()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 计算从startIndex到末尾的所有包数(因为数据包不会来自未来)
|
||||
return sortedList.size() - startIndex;
|
||||
}
|
||||
|
||||
public long calculateBandwidth(long timeWindowNs) {
|
||||
return calculateBandwidth(clock.getCurrentTimeNanos(), timeWindowNs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算带宽
|
||||
*/
|
||||
public long calculateBandwidth(Long128 currentTime, long timeWindowNs) {
|
||||
if (timeWindowNs <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
long dataVolume = calculateDataVolume(currentTime, timeWindowNs);
|
||||
return (long) (dataVolume * 1000000000.0 / timeWindowNs);
|
||||
}
|
||||
|
||||
public TrafficStats calculateTrafficStats(long timeWindowNs) {
|
||||
return calculateTrafficStats(clock.getCurrentTimeNanos(), timeWindowNs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算流量统计信息 - 优化:由于数据包不会来自未来,只需要查找startTime
|
||||
*/
|
||||
public TrafficStats calculateTrafficStats(Long128 currentTime, long timeWindowNs) {
|
||||
Long128 startTime = currentTime.subtract(Long128.valueOf(timeWindowNs));
|
||||
|
||||
rwLock.readLock().lock();
|
||||
try {
|
||||
return calculateTrafficStatsFromSortedList(entries, startTime, currentTime, timeWindowNs);
|
||||
} finally {
|
||||
rwLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从已排序的列表中计算流量统计 - 优化版本
|
||||
*/
|
||||
private TrafficStats calculateTrafficStatsFromSortedList(List<TimestampMonitorValue> sortedList,
|
||||
Long128 startTime, Long128 currentTime,
|
||||
long timeWindowNs) {
|
||||
TrafficStats stats = new TrafficStats();
|
||||
stats.timeWindowNs = timeWindowNs;
|
||||
stats.currentTime = currentTime;
|
||||
|
||||
if (sortedList.isEmpty()) {
|
||||
return stats;
|
||||
}
|
||||
|
||||
int startIndex = findFirstValidIndexFromSorted(sortedList, startTime);
|
||||
|
||||
if (startIndex >= sortedList.size()) {
|
||||
return stats;
|
||||
}
|
||||
|
||||
// 计算从startIndex到末尾的所有数据(因为数据包不会来自未来)
|
||||
for (int i = startIndex; i < sortedList.size(); i++) {
|
||||
TimestampMonitorValue value = sortedList.get(i);
|
||||
stats.packetCount++;
|
||||
stats.totalBytes += value.getLength();
|
||||
|
||||
if (stats.earliestTimestamp.equals(BigInteger.ZERO) ||
|
||||
value.getTimestamp().compareTo(stats.earliestTimestamp) < 0) {
|
||||
stats.earliestTimestamp = value.getTimestamp();
|
||||
}
|
||||
if (value.getTimestamp().compareTo(stats.latestTimestamp) > 0) {
|
||||
stats.latestTimestamp = value.getTimestamp();
|
||||
}
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
|
||||
// Getters
|
||||
public long getTotalDataSize() { return totalDataSize.sum(); }
|
||||
public long getTotalPackets() { return totalPackets.sum(); }
|
||||
public int getEntryCount() {
|
||||
rwLock.readLock().lock();
|
||||
try {
|
||||
return entries.size();
|
||||
} finally {
|
||||
rwLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
rwLock.writeLock().lock();
|
||||
try {
|
||||
totalDataSize.reset();
|
||||
totalPackets.reset();
|
||||
entries.clear();
|
||||
} finally {
|
||||
rwLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
protected ArrayListTimestampMonitor(HighAccuracyClock clock, String name, int maxRetry, long cleanupThreshold) {
|
||||
super();
|
||||
this.clock = clock;
|
||||
this.name = name;
|
||||
this.maxRetry = maxRetry;
|
||||
this.cleanupThreshold = cleanupThreshold;
|
||||
}
|
||||
|
||||
public ArrayListTimestampMonitor(HighAccuracyClock clock, String name) {
|
||||
this(clock, name, 100, 1000000000L);
|
||||
}
|
||||
|
||||
private volatile long prev = System.nanoTime();
|
||||
|
||||
public boolean recordPacket(K key, int length) {
|
||||
return recordPacket(key, clock.getCurrentTimeNanos(), length, Long.MAX_VALUE / 1024);
|
||||
}
|
||||
|
||||
public boolean recordPacket(K key, int length, long delay) {
|
||||
return recordPacket(key, clock.getCurrentTimeNanos(), length, delay);
|
||||
}
|
||||
|
||||
public boolean recordPacket(K key, Long128 timestamp, int length) {
|
||||
return recordPacket(key, timestamp, length, Long.MAX_VALUE / 1024);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录数据包 - 使用插入排序保持列表有序,添加时间戳验证
|
||||
*/
|
||||
public boolean recordPacket(K key, Long128 timestamp, int length, long delay) {
|
||||
// 验证时间戳的合理性
|
||||
validateTimestamp(timestamp);
|
||||
|
||||
// 快速路径:尝试sequence=0
|
||||
TimestampMonitorKey<K> monitorKey = new TimestampMonitorKey<>(key, 0);
|
||||
TimestampMonitorValue monitorValue = new TimestampMonitorValue(monitorKey, timestamp, length, delay);
|
||||
autoCleanup(cleanupThreshold);
|
||||
|
||||
rwLock.writeLock().lock();
|
||||
try {
|
||||
// 使用二分查找插入排序,保持列表有序
|
||||
insertSorted(monitorValue);
|
||||
totalDataSize.add(length);
|
||||
totalPackets.increment();
|
||||
} finally {
|
||||
rwLock.writeLock().unlock();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证时间戳的合理性
|
||||
*/
|
||||
private void validateTimestamp(Long128 timestamp) {
|
||||
/*Long128 currentTime = clock.getCurrentTimeNanos();
|
||||
Long128 maxAllowedTime = currentTime.add(Long128.valueOf(TIMESTAMP_TOLERANCE_NS));
|
||||
|
||||
if (timestamp.compareTo(maxAllowedTime) > 0) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Timestamp %s is in the future (current time: %s, tolerance: %d ns)", timestamp,
|
||||
currentTime, TIMESTAMP_TOLERANCE_NS));
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用二分查找进行插入排序,保持列表有序
|
||||
*/
|
||||
private void insertSorted(TimestampMonitorValue newValue) {
|
||||
if(newValue.getDelay()<Long.MAX_VALUE/1024) {
|
||||
if(recent==null||recent.getTimestamp().compareTo( newValue.getTimestamp())<0) {
|
||||
recent=newValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (entries.isEmpty()) {
|
||||
entries.add(newValue);
|
||||
return;
|
||||
}
|
||||
|
||||
// 优化:检查是否可以快速添加到末尾(大部分数据包是按时间顺序到达的)
|
||||
TimestampMonitorValue lastValue = entries.get(entries.size() - 1);
|
||||
if (newValue.getTimestamp().compareTo(lastValue.getTimestamp()) >= 0) {
|
||||
entries.add(newValue);
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用二分查找找到插入位置
|
||||
int insertIndex = findInsertIndex(newValue.getTimestamp());
|
||||
entries.add(insertIndex, newValue);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用二分查找找到插入位置
|
||||
*/
|
||||
private int findInsertIndex(Long128 timestamp) {
|
||||
int low = 0;
|
||||
int high = entries.size() - 1;
|
||||
|
||||
while (low <= high) {
|
||||
int mid = (low + high) >>> 1;
|
||||
Long128 midTimestamp = entries.get(mid).getTimestamp();
|
||||
int cmp = timestamp.compareTo(midTimestamp);
|
||||
|
||||
if (cmp < 0) {
|
||||
high = mid - 1;
|
||||
} else if (cmp > 0) {
|
||||
low = mid + 1;
|
||||
} else {
|
||||
// 时间戳相等,插入到相同时间戳的后面
|
||||
return findLastEqualIndex(mid, timestamp) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return low;
|
||||
}
|
||||
|
||||
/**
|
||||
* 找到相同时间戳的最后一个元素的索引
|
||||
*/
|
||||
private int findLastEqualIndex(int startIndex, Long128 timestamp) {
|
||||
int index = startIndex;
|
||||
while (index < entries.size() - 1 && entries.get(index + 1).getTimestamp().equals(timestamp)) {
|
||||
index++;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
private void autoCleanup(long th) {
|
||||
long curr = System.nanoTime();
|
||||
if (curr - prev > th) {
|
||||
prev = curr;
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
cleanup(clock.getCurrentTimeNanos(), cleanupThreshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理旧记录 - 由于列表已排序,直接使用二分查找
|
||||
*/
|
||||
private Long128 prevTime;
|
||||
|
||||
public void cleanup(Long128 currentTime, long timeWindowNs) {
|
||||
Long128 startTime = currentTime.subtract(Long128.valueOf(timeWindowNs));
|
||||
Long128 maxAllowedTime = currentTime.add(Long128.valueOf(TIMESTAMP_TOLERANCE_NS));
|
||||
rwLock.writeLock().lock();
|
||||
try {
|
||||
if (prevTime != null && prevTime.compareTo(maxAllowedTime) > 0) {
|
||||
|
||||
//System.out.println("Time change detected!");
|
||||
entries.clear();
|
||||
} else {
|
||||
// 使用二分查找找到第一个不过期的元素位置
|
||||
int firstValidIndex = findFirstValidIndex(startTime);
|
||||
|
||||
if (firstValidIndex > 0) {
|
||||
// 删除所有过期的元素
|
||||
entries.subList(0, firstValidIndex).clear();
|
||||
}
|
||||
}
|
||||
prevTime = currentTime;
|
||||
} finally {
|
||||
rwLock.writeLock().unlock();
|
||||
}
|
||||
prev = System.nanoTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用二分查找找到第一个时间戳 >= startTime 的元素索引
|
||||
*/
|
||||
private int findFirstValidIndex(Long128 startTime) {
|
||||
int low = 0;
|
||||
int high = entries.size();
|
||||
|
||||
while (low < high) {
|
||||
int mid = (low + high) >>> 1;
|
||||
Long128 midTimestamp = entries.get(mid).getTimestamp();
|
||||
|
||||
if (midTimestamp.compareTo(startTime) < 0) {
|
||||
low = mid + 1;
|
||||
} else {
|
||||
high = mid;
|
||||
}
|
||||
}
|
||||
|
||||
return low;
|
||||
}
|
||||
|
||||
public long calculateDataVolume(long timeWindowNs) {
|
||||
return calculateDataVolume(clock.getCurrentTimeNanos(), timeWindowNs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 高性能数据量计算 - 优化:由于数据包不会来自未来,只需要查找startTime
|
||||
*/
|
||||
public long calculateDataVolume(Long128 currentTime, long timeWindowNs) {
|
||||
Long128 startTime = currentTime.subtract(Long128.valueOf(timeWindowNs));
|
||||
|
||||
rwLock.readLock().lock();
|
||||
try {
|
||||
return calculateDataVolumeFromSortedList(entries, startTime);
|
||||
} finally {
|
||||
rwLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从已排序的列表中计算数据量 - 优化版本,只需要startTime
|
||||
*/
|
||||
private long calculateDataVolumeFromSortedList(List<TimestampMonitorValue> sortedList, Long128 startTime) {
|
||||
if (sortedList.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 使用二分查找找到第一个 >= startTime 的元素位置
|
||||
int startIndex = findFirstValidIndexFromSorted(sortedList, startTime);
|
||||
|
||||
if (startIndex >= sortedList.size()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 计算从startIndex到末尾的所有数据量(因为数据包不会来自未来)
|
||||
long sum = 0;
|
||||
for (int i = startIndex; i < sortedList.size(); i++) {
|
||||
sum += sortedList.get(i).getLength();
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在已排序列表中找到第一个时间戳 >= startTime 的索引
|
||||
*/
|
||||
private int findFirstValidIndexFromSorted(List<TimestampMonitorValue> sortedList, Long128 startTime) {
|
||||
int low = 0;
|
||||
int high = sortedList.size();
|
||||
//int x=0;
|
||||
while (low < high) {
|
||||
int mid = (low + high) >>> 1;
|
||||
Long128 midTimestamp = sortedList.get(mid).getTimestamp();
|
||||
|
||||
if (midTimestamp.compareTo(startTime) < 0) {
|
||||
low = mid + 1;
|
||||
} else {
|
||||
high = mid;
|
||||
}
|
||||
//x++;
|
||||
}
|
||||
//System.out.println(x+" "+sortedList.size());
|
||||
return low;
|
||||
}
|
||||
|
||||
public long calculatePacketCount(long timeWindowNs) {
|
||||
return calculatePacketCount(clock.getCurrentTimeNanos(), timeWindowNs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 高性能包数计算 - 优化:由于数据包不会来自未来,只需要查找startTime
|
||||
*/
|
||||
public long calculatePacketCount(Long128 currentTime, long timeWindowNs) {
|
||||
Long128 startTime = currentTime.subtract(Long128.valueOf(timeWindowNs));
|
||||
|
||||
rwLock.readLock().lock();
|
||||
try {
|
||||
return calculatePacketCountFromSortedList(entries, startTime);
|
||||
} finally {
|
||||
rwLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从已排序的列表中计算包数 - 优化版本,只需要startTime
|
||||
*/
|
||||
private long calculatePacketCountFromSortedList(List<TimestampMonitorValue> sortedList, Long128 startTime) {
|
||||
if (sortedList.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int startIndex = findFirstValidIndexFromSorted(sortedList, startTime);
|
||||
|
||||
if (startIndex >= sortedList.size()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 计算从startIndex到末尾的所有包数(因为数据包不会来自未来)
|
||||
return sortedList.size() - startIndex;
|
||||
}
|
||||
|
||||
public long calculateBandwidth(long timeWindowNs) {
|
||||
return calculateBandwidth(clock.getCurrentTimeNanos(), timeWindowNs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算带宽
|
||||
*/
|
||||
public long calculateBandwidth(Long128 currentTime, long timeWindowNs) {
|
||||
if (timeWindowNs <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
long dataVolume = calculateDataVolume(currentTime, timeWindowNs);
|
||||
return (long) (dataVolume * 1000000000.0 / timeWindowNs);
|
||||
}
|
||||
|
||||
public TrafficStats calculateTrafficStats(long timeWindowNs) {
|
||||
return calculateTrafficStats(clock.getCurrentTimeNanos(), timeWindowNs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long calculatePacketRate(long timeWindowNs) {
|
||||
return calculatePacketRate(clock.getCurrentTimeNanos(), timeWindowNs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long calculatePacketRate(Long128 currentTime, long timeWindowNs) {
|
||||
if (timeWindowNs <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
long dataVolume = calculatePacketCount(currentTime, timeWindowNs);
|
||||
return (long) (dataVolume * 1000000000.0 / timeWindowNs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算流量统计信息 - 优化:由于数据包不会来自未来,只需要查找startTime
|
||||
*/
|
||||
public TrafficStats calculateTrafficStats(Long128 currentTime, long timeWindowNs) {
|
||||
Long128 startTime = currentTime.subtract(Long128.valueOf(timeWindowNs));
|
||||
|
||||
rwLock.readLock().lock();
|
||||
try {
|
||||
return calculateTrafficStatsFromSortedList(entries, startTime, currentTime, timeWindowNs);
|
||||
} finally {
|
||||
rwLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从已排序的列表中计算流量统计 - 优化版本
|
||||
*/
|
||||
private TrafficStats calculateTrafficStatsFromSortedList(List<TimestampMonitorValue> sortedList, Long128 startTime,
|
||||
Long128 currentTime, long timeWindowNs) {
|
||||
TrafficStats stats = new TrafficStats();
|
||||
stats.timeWindowNs = timeWindowNs;
|
||||
stats.currentTime = currentTime;
|
||||
|
||||
if (sortedList.isEmpty()) {
|
||||
return stats;
|
||||
}
|
||||
|
||||
int startIndex = findFirstValidIndexFromSorted(sortedList, startTime);
|
||||
|
||||
if (startIndex >= sortedList.size()) {
|
||||
return stats;
|
||||
}
|
||||
|
||||
// 计算从startIndex到末尾的所有数据(因为数据包不会来自未来)
|
||||
for (int i = startIndex; i < sortedList.size(); i++) {
|
||||
TimestampMonitorValue value = sortedList.get(i);
|
||||
stats.packetCount++;
|
||||
stats.totalBytes += value.getLength();
|
||||
|
||||
if (stats.earliestTimestamp.equals(Long128.ZERO)
|
||||
|| value.getTimestamp().compareTo(stats.earliestTimestamp) < 0) {
|
||||
stats.earliestTimestamp = value.getTimestamp();
|
||||
}
|
||||
if (value.getTimestamp().compareTo(stats.latestTimestamp) > 0) {
|
||||
stats.latestTimestamp = value.getTimestamp();
|
||||
}
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRecentDelay() {
|
||||
TimestampMonitorValue val= getRecentDelayEntry();
|
||||
if(val!=null) {
|
||||
return val.getDelay();
|
||||
}else {
|
||||
return Long.MAX_VALUE / 1024;
|
||||
}
|
||||
}
|
||||
|
||||
private volatile TimestampMonitorValue recent=null;
|
||||
@Override
|
||||
public TimestampMonitorValue getRecentDelayEntry() {
|
||||
return recent;
|
||||
}
|
||||
|
||||
// Getters
|
||||
public long getTotalDataSize() {
|
||||
return totalDataSize.sum();
|
||||
}
|
||||
|
||||
public long getTotalPackets() {
|
||||
return totalPackets.sum();
|
||||
}
|
||||
|
||||
public int getEntryCount() {
|
||||
rwLock.readLock().lock();
|
||||
try {
|
||||
return entries.size();
|
||||
} finally {
|
||||
rwLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
rwLock.writeLock().lock();
|
||||
try {
|
||||
totalDataSize.reset();
|
||||
totalPackets.reset();
|
||||
entries.clear();
|
||||
} finally {
|
||||
rwLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(name);
|
||||
sb.append('\n');
|
||||
sb.append(KLALBUtils.convertIBUint(totalDataSize.sum())).append("\t")
|
||||
.append(KLALBUtils.convertIBUint(calculateBandwidth(Math.min(cleanupThreshold, 1000000000L))))
|
||||
.append("/s\t");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
AtomicLong along = new AtomicLong(0);
|
||||
ArrayListTimestampMonitor<Long> monitor = new ArrayListTimestampMonitor<>(new HighAccuracyClock(), "Monitor",
|
||||
100, 200000000L);
|
||||
Thread t = new Thread(() -> {
|
||||
while (true) {
|
||||
monitor.recordPacket(along.getAndIncrement(), 1000);
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
Timer tx = new Timer();
|
||||
tx.scheduleAtFixedRate(new TimerTask() {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(name);
|
||||
sb.append('\n');
|
||||
sb.append(KLALBUtils.convertIBUint(totalDataSize.sum())).append("\t")
|
||||
.append(KLALBUtils.convertIBUint(calculateBandwidth(Math.min(cleanupThreshold,1000000000L)))).append("/s\t");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
AtomicLong along=new AtomicLong(0);
|
||||
ArrayListTimestampMonitor<Long> monitor = new ArrayListTimestampMonitor<>(new HighAccuracyClock(),"Monitor",100,200000000L);
|
||||
Thread t=new Thread(()->{
|
||||
while(true) {
|
||||
monitor.recordPacket(along.getAndIncrement(), 1000);
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
Timer tx=new Timer();
|
||||
tx.scheduleAtFixedRate(new TimerTask() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// 计算带宽
|
||||
long testEndTime = System.nanoTime();
|
||||
monitor.cleanup();
|
||||
// 计算统计信息
|
||||
// TrafficStats stats = monitor.calculateTrafficStats(1000000000L);
|
||||
System.out.println(monitor);
|
||||
System.out.println(KLALBUtils.convertUintNanoDefalut( System.nanoTime()-testEndTime));
|
||||
// 计算带宽
|
||||
long testEndTime = System.nanoTime();
|
||||
monitor.cleanup();
|
||||
// 计算统计信息
|
||||
// TrafficStats stats = monitor.calculateTrafficStats(1000000000L);
|
||||
System.out.println(monitor);
|
||||
System.out.println(KLALBUtils.convertUintNanoDefalut(System.nanoTime() - testEndTime));
|
||||
}
|
||||
}, 100, 100);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,14 +2,9 @@ package org.kne.cloud.network.monitor;
|
||||
|
||||
public interface DelayMonitorData extends MonitorData {
|
||||
public long getOutDelay();
|
||||
public void setOutDelay(long delay);
|
||||
public long getOutJitter();
|
||||
|
||||
public long getInDelay();
|
||||
public void setInDelay(long delay);
|
||||
public long getInJitter();
|
||||
|
||||
public long getLatency();
|
||||
public void setLatency(long latency);
|
||||
public long getTotalJitter();
|
||||
}
|
||||
|
||||
@@ -42,16 +42,17 @@ private String name;
|
||||
public HighAccuracyClock getClock() {
|
||||
return clock;
|
||||
}
|
||||
protected HashMapTimestampMonitor(HighAccuracyClock clock,String name, int maxRetry, long cleanupThreshold) {
|
||||
public HashMapTimestampMonitor(HighAccuracyClock clock,String name, int maxRetry, long cleanupThreshold) {
|
||||
super();
|
||||
this.clock=clock;
|
||||
this.name = name;
|
||||
this.maxRetry = maxRetry;
|
||||
this.cleanupThreshold = cleanupThreshold;
|
||||
}
|
||||
public HashMapTimestampMonitor() {
|
||||
this(new HighAccuracyClock(),"TimestampMonitor",100, 1000000000L); // 默认最大重试100次,清理阈值1秒
|
||||
}
|
||||
|
||||
public HashMapTimestampMonitor(HighAccuracyClock clock) {
|
||||
this(clock,"HashMapTimestampMonitor");
|
||||
}
|
||||
|
||||
public HashMapTimestampMonitor(HighAccuracyClock clock,String name) {
|
||||
this(clock,name,100, 1000000000L); // 默认最大重试100次,清理阈值1秒
|
||||
@@ -62,17 +63,29 @@ public HashMapTimestampMonitor() {
|
||||
private volatile long prev=System.nanoTime();
|
||||
|
||||
|
||||
|
||||
|
||||
public boolean recordPacket(K key, int length) {
|
||||
return recordPacket(key,clock.getCurrentTimeNanos(),length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean recordPacket(K key, Long128 timestamp, int length) {
|
||||
return recordPacket(key, timestamp, length, Long.MAX_VALUE/1024);
|
||||
}
|
||||
@Override
|
||||
public boolean recordPacket(K key, int length, long delay) {
|
||||
return recordPacket(key,clock.getCurrentTimeNanos(),length,delay);
|
||||
}
|
||||
|
||||
/**
|
||||
* 超高性能记录数据包 - 针对路由器优化
|
||||
*/
|
||||
public boolean recordPacket(K key, Long128 timestamp, int length) {
|
||||
public boolean recordPacket(K key, Long128 timestamp, int length, long delay) {
|
||||
autoCleanup(cleanupThreshold);
|
||||
// 快速路径:尝试sequence=0
|
||||
TimestampMonitorKey<K> monitorKey = new TimestampMonitorKey<>(key, 0);
|
||||
TimestampMonitorValue monitorValue = new TimestampMonitorValue(monitorKey,timestamp, length);
|
||||
TimestampMonitorValue monitorValue = new TimestampMonitorValue(monitorKey,timestamp, length,delay);
|
||||
|
||||
if (entries.putIfAbsent(monitorKey, monitorValue) == null) {
|
||||
totalDataSize.add(length);
|
||||
@@ -159,7 +172,7 @@ public HashMapTimestampMonitor() {
|
||||
public long calculatePacketCount(Long128 currentTime, long timeWindowNs) {
|
||||
Long128 startTime = currentTime .subtract(Long128.valueOf( timeWindowNs));
|
||||
|
||||
return entries.values().parallelStream()
|
||||
return entries.values().stream()
|
||||
.filter(value -> (value.getTimestamp() .compareTo( startTime )>=0)&&
|
||||
(value.getTimestamp().compareTo( currentTime) <=0) )
|
||||
.count();
|
||||
@@ -182,6 +195,22 @@ public HashMapTimestampMonitor() {
|
||||
return (long) (dataVolume*1000000000.0/timeWindowNs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long calculatePacketRate(long timeWindowNs) {
|
||||
return calculatePacketRate(clock.getCurrentTimeNanos(),timeWindowNs);
|
||||
}
|
||||
@Override
|
||||
public long calculatePacketRate(Long128 currentTime, long timeWindowNs) {
|
||||
if (timeWindowNs <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
long dataVolume = calculatePacketCount(currentTime, timeWindowNs);
|
||||
// System.out.println(dataVolume);
|
||||
return (long) (dataVolume*1000000000.0/timeWindowNs);
|
||||
}
|
||||
|
||||
|
||||
public TrafficStats calculateTrafficStats(long timeWindowNs) {
|
||||
return calculateTrafficStats(clock.getCurrentTimeNanos(),timeWindowNs);
|
||||
}
|
||||
@@ -270,6 +299,19 @@ public HashMapTimestampMonitor() {
|
||||
|
||||
|
||||
}
|
||||
@Override
|
||||
public long getRecentDelay() {
|
||||
// TODO 自动生成的方法存根
|
||||
return 0;
|
||||
}
|
||||
@Override
|
||||
public TimestampMonitorValue getRecentDelayEntry() {
|
||||
// TODO 自动生成的方法存根
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -3,9 +3,9 @@ package org.kne.cloud.network.monitor;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public interface MonitorData extends Cloneable {
|
||||
public static final int OFFLINE=0;
|
||||
public static final int CONNECTING=1;
|
||||
public static final int ONLINE=2;
|
||||
public static final int DOWN=0;
|
||||
public static final int UNSTABLE=1;
|
||||
public static final int UP=2;
|
||||
public Consumer<MonitorData> getChangeListener();
|
||||
public void setChangeListener(Consumer<MonitorData> changeListener);
|
||||
public String getName();
|
||||
@@ -20,11 +20,11 @@ public double getReliability();
|
||||
|
||||
public static String parseStateToString(int state) {
|
||||
switch (state) {
|
||||
case OFFLINE:
|
||||
case DOWN:
|
||||
return "offline";
|
||||
case CONNECTING:
|
||||
return "connecting";
|
||||
case ONLINE:
|
||||
case UNSTABLE:
|
||||
return "unstable";
|
||||
case UP:
|
||||
return "online";
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown state:"+state);
|
||||
|
||||
@@ -26,7 +26,7 @@ private TimerTask ptt=new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
reliability=(reliability*999+(state==ONLINE?1:0))/1000;
|
||||
reliability=(reliability*999+(state==UP?1:0))/1000;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -58,11 +58,11 @@ private TimerTask ptt=new TimerTask() {
|
||||
}
|
||||
private String getDsc() {
|
||||
switch(state) {
|
||||
case OFFLINE:
|
||||
case DOWN:
|
||||
return "○离线";
|
||||
case CONNECTING:
|
||||
return "◐连接中";
|
||||
case ONLINE:
|
||||
case UNSTABLE:
|
||||
return "◐不稳定";
|
||||
case UP:
|
||||
return "●在线";
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
package org.kne.cloud.network.monitor;
|
||||
|
||||
public class QueueingMonitorDataImpl extends SpeedAndTrafficAndDelayMonitorDataImpl {
|
||||
private long queueingDelay;
|
||||
|
||||
public long getQueueingDelay() {
|
||||
return queueingDelay;
|
||||
}
|
||||
|
||||
public void setQueueingDelay(long queueingDelay) {
|
||||
this.queueingDelay = queueingDelay;
|
||||
}
|
||||
}
|
||||
@@ -1,181 +1,79 @@
|
||||
package org.kne.cloud.network.monitor;
|
||||
|
||||
import java.util.TimerTask;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.kne.cloud.clock.HighAccuracyClock;
|
||||
import org.kne.cloud.network.ipv6.PacketID;
|
||||
import org.kne.cloud.network.klalb.KLALBUtils;
|
||||
|
||||
public class SpeedAndTrafficAndDelayMonitorDataImpl extends SpeedAndTrafficMonitorDataImpl implements SpeedAndTrafficMonitorData,DelayMonitorData{
|
||||
|
||||
private long timewindowmax=500000000L;
|
||||
|
||||
|
||||
private volatile long outDelay=Long.MAX_VALUE/1024;
|
||||
private volatile long outDelayMin=Long.MAX_VALUE;
|
||||
private volatile long outDelayAvg=Long.MAX_VALUE;
|
||||
private long outDelayOld;
|
||||
private volatile long outJitter;
|
||||
|
||||
|
||||
private volatile long inDelay=Long.MAX_VALUE/1024;
|
||||
private volatile long inDelayMin=Long.MAX_VALUE;
|
||||
private volatile long inDelayAvg=Long.MAX_VALUE;
|
||||
private long inDelayOld;
|
||||
private volatile long inJitter;
|
||||
|
||||
|
||||
private volatile long latency=Long.MAX_VALUE/1024;
|
||||
private volatile long latencyMin=Long.MAX_VALUE;
|
||||
private volatile long latencyAvg=Long.MAX_VALUE;
|
||||
private long latencyOld;
|
||||
private volatile long totalJitter;
|
||||
|
||||
private volatile long outDelayPredicted;
|
||||
private volatile long inDelayPredicted;
|
||||
|
||||
private volatile long recentPingNanoTime;
|
||||
|
||||
|
||||
|
||||
public long getOutDelayAvg() {
|
||||
return outDelayAvg;
|
||||
}
|
||||
public long getInDelayAvg() {
|
||||
return inDelayAvg;
|
||||
}
|
||||
public long getLatencyAvg() {
|
||||
return latencyAvg;
|
||||
}
|
||||
|
||||
|
||||
public long getRecentPingNanoTime() {
|
||||
return recentPingNanoTime;
|
||||
}
|
||||
public void setRecentPingNanoTime(long recentPingNanoTime) {
|
||||
this.recentPingNanoTime = recentPingNanoTime;
|
||||
}
|
||||
@Override
|
||||
public long getOutDelay() {
|
||||
return outDelay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOutDelay(long delay) {
|
||||
this.outDelay=delay;
|
||||
if(outDelayAvg==Long.MAX_VALUE) {
|
||||
outDelayAvg=delay;
|
||||
}else {
|
||||
outDelayAvg=(outDelayAvg*9999+delay)/10000;
|
||||
}
|
||||
if(outDelayMin==Long.MAX_VALUE||delay<=outDelayMin) {
|
||||
outDelayMin=delay;
|
||||
}else{
|
||||
outDelayMin=(outDelayMin*9999+delay)/10000;
|
||||
}
|
||||
this.latency=outDelay+inDelay;
|
||||
|
||||
if(latencyAvg==Long.MAX_VALUE) {
|
||||
latencyAvg=latency;
|
||||
}else {
|
||||
latencyAvg=(latencyAvg*9999+latency)/10000;
|
||||
}
|
||||
if(latencyMin==Long.MAX_VALUE||latency<= latencyMin) {
|
||||
latencyMin=latency;
|
||||
}else {
|
||||
latencyMin=(latencyMin*9999+latency)/10000;
|
||||
}
|
||||
outDelayPredicted=outDelay;
|
||||
updateOutJitter();
|
||||
updateTotalJitter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getInDelay() {
|
||||
return inDelay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInDelay(long delay) {
|
||||
this.inDelay=delay;
|
||||
if(inDelayAvg==Long.MAX_VALUE) {
|
||||
inDelayAvg=latency;
|
||||
}else {
|
||||
inDelayAvg=(inDelayAvg*9999+delay)/10000;
|
||||
}
|
||||
if(inDelayMin==Long.MAX_VALUE||delay<=inDelayMin) {
|
||||
inDelayMin=delay;
|
||||
}else{
|
||||
inDelayMin=(inDelayMin*9999+delay)/10000;
|
||||
}
|
||||
this.latency=outDelay+inDelay;
|
||||
if(latencyAvg==Long.MAX_VALUE) {
|
||||
latencyAvg=latency;
|
||||
}else {
|
||||
latencyAvg=(latencyAvg*9999+latency)/10000;
|
||||
}
|
||||
if(latencyMin==Long.MAX_VALUE||latency<= latencyMin) {
|
||||
latencyMin=latency;
|
||||
}else {
|
||||
latencyMin=(latencyMin*9999+latency)/10000;
|
||||
}
|
||||
inDelayPredicted=inDelay;
|
||||
updateInJitter();
|
||||
updateTotalJitter();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public long getLatency() {
|
||||
return latency;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLatency(long latency) {
|
||||
this.latency=latency;
|
||||
if(latencyAvg==Long.MAX_VALUE) {
|
||||
latencyAvg=latency;
|
||||
}else {
|
||||
latencyAvg=(latencyAvg*9999+latency)/10000;
|
||||
}
|
||||
if(latencyMin==Long.MAX_VALUE||latency<= latencyMin) {
|
||||
latencyMin=latency;
|
||||
}else {
|
||||
latencyMin=(latencyMin*9999+latency)/10000;
|
||||
}
|
||||
long tmp= latency>>1;
|
||||
this.inDelay=tmp;
|
||||
if(inDelayAvg==Long.MAX_VALUE) {
|
||||
inDelayAvg=latency;
|
||||
}else {
|
||||
inDelayAvg=(inDelayAvg*9999+tmp)/10000;
|
||||
}
|
||||
if(inDelayMin==Long.MAX_VALUE||tmp<=inDelayMin) {
|
||||
inDelayMin=tmp;
|
||||
}else{
|
||||
inDelayMin=(inDelayMin*9999+tmp)/10000;
|
||||
}
|
||||
private TimerTask pttxr=new TimerTask() {
|
||||
|
||||
this.outDelay=tmp;
|
||||
if(outDelayAvg==Long.MAX_VALUE) {
|
||||
outDelayAvg=latency;
|
||||
}else {
|
||||
outDelayAvg=(outDelayAvg*9999+tmp)/10000;
|
||||
@Override
|
||||
public void run() {
|
||||
long idelay=getInDelay();
|
||||
if(inDelayMin==Long.MAX_VALUE||idelay<=inDelayMin) {
|
||||
inDelayMin=idelay;
|
||||
}else{
|
||||
inDelayMin=(inDelayMin*9999+idelay)/10000;
|
||||
}
|
||||
long odelay=getOutDelay();
|
||||
if(outDelayMin==Long.MAX_VALUE||odelay<=outDelayMin) {
|
||||
outDelayMin=odelay;
|
||||
}else{
|
||||
outDelayMin=(outDelayMin*9999+odelay)/10000;
|
||||
}
|
||||
}
|
||||
if(outDelayMin==Long.MAX_VALUE||tmp<=outDelayMin) {
|
||||
outDelayMin=tmp;
|
||||
}else{
|
||||
outDelayMin=(outDelayMin*9999+tmp)/10000;
|
||||
}
|
||||
outDelayPredicted=outDelay;
|
||||
inDelayPredicted=inDelay;
|
||||
updateOutJitter();
|
||||
updateInJitter();
|
||||
updateTotalJitter();
|
||||
};
|
||||
{
|
||||
getTimer().scheduleAtFixedRate(pttxr, timewindowmax/1000000, timewindowmax/1000000);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
pttxr.cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb=new StringBuilder(super.toString());
|
||||
sb.append(KLALBUtils.convertUintNanoDefalut( outDelay) ).append("s").append("\t").append(KLALBUtils.convertUintNanoDefalut( inDelay) ).append("s").append("\t").append(KLALBUtils.convertUintNanoDefalut( outJitter) ).append("s\t").append(KLALBUtils.convertUintNanoDefalut( inJitter) ).append("s\t");
|
||||
sb.append(KLALBUtils.convertUintNanoDefalut( getOutDelay()) ).append("s").append("\t").append(KLALBUtils.convertUintNanoDefalut( getInDelay()) ).append("s").append("\t").append(KLALBUtils.convertUintNanoDefalut( getOutJitter()) ).append("s\t").append(KLALBUtils.convertUintNanoDefalut( getInJitter()) ).append("s\t");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public SpeedAndTrafficAndDelayMonitorDataImpl(HighAccuracyClock clock) {
|
||||
super(clock);
|
||||
// TODO 自动生成的构造函数存根
|
||||
}
|
||||
|
||||
public SpeedAndTrafficAndDelayMonitorDataImpl(TimestampMonitor<UUID> uploadBandwidth,
|
||||
TimestampMonitor<UUID> downloadBandwidth) {
|
||||
super(uploadBandwidth, downloadBandwidth);
|
||||
// TODO 自动生成的构造函数存根
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getOutDelay() {
|
||||
return super.getUploadBandwidth().getRecentDelay();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public long getInDelay() {
|
||||
return super.getDownloadBandwidth().getRecentDelay();
|
||||
}
|
||||
|
||||
private volatile long outDelayMin=Long.MAX_VALUE;
|
||||
private volatile long outJitter;
|
||||
private volatile long inDelayMin=Long.MAX_VALUE;
|
||||
private volatile long inJitter;
|
||||
|
||||
@Override
|
||||
public long getOutJitter() {
|
||||
return outJitter;
|
||||
@@ -185,11 +83,7 @@ public class SpeedAndTrafficAndDelayMonitorDataImpl extends SpeedAndTrafficMonit
|
||||
public long getInJitter() {
|
||||
return inJitter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTotalJitter() {
|
||||
return totalJitter;
|
||||
}
|
||||
|
||||
public long getOutDelayMin() {
|
||||
return outDelayMin;
|
||||
}
|
||||
@@ -198,35 +92,6 @@ public class SpeedAndTrafficAndDelayMonitorDataImpl extends SpeedAndTrafficMonit
|
||||
return inDelayMin;
|
||||
}
|
||||
|
||||
public long getLatencyMin() {
|
||||
return latencyMin;
|
||||
}
|
||||
|
||||
private void updateOutJitter() {
|
||||
|
||||
long vj=Math.abs( outDelay-outDelayOld);
|
||||
outJitter=(outJitter*9+vj)/10;
|
||||
outDelayOld =outDelay;
|
||||
}
|
||||
private void updateInJitter() {
|
||||
long vj=Math.abs( inDelay-inDelayOld);
|
||||
inJitter=(inJitter*9+vj)/10;
|
||||
inDelayOld =inDelay;
|
||||
}
|
||||
private void updateTotalJitter() {
|
||||
long vj=Math.abs( latency-latencyOld);
|
||||
totalJitter=(totalJitter*9+vj)/10;
|
||||
latencyOld =latency;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public long getOutDelayPredicted() {
|
||||
return outDelayPredicted;
|
||||
}
|
||||
|
||||
public long getInDelayPredicted() {
|
||||
return inDelayPredicted;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,35 +1,27 @@
|
||||
package org.kne.cloud.network.monitor;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.LongAdder;
|
||||
|
||||
import org.kne.cloud.network.ipv6.PacketID;
|
||||
|
||||
public interface SpeedAndTrafficMonitorData extends MonitorData{
|
||||
public long getInTraffic();
|
||||
|
||||
public long getOutTraffic();
|
||||
|
||||
public LongAdder getInTrafficAL();
|
||||
|
||||
public LongAdder getOutTrafficAL();
|
||||
|
||||
public long getInSpeed();
|
||||
public TimestampMonitor<UUID> getUploadBandwidth();
|
||||
|
||||
|
||||
public long getOutSpeed();
|
||||
|
||||
|
||||
public long getInPPS();
|
||||
|
||||
public long getOutPPS();
|
||||
|
||||
public LongAdder getInPacketCounterAL();
|
||||
|
||||
public LongAdder getOutPacketCounterAL();
|
||||
|
||||
public long getInPacketCounter();
|
||||
|
||||
|
||||
public long getOutPacketCounter();
|
||||
|
||||
public TimestampMonitor<UUID> getDownloadBandwidth();
|
||||
|
||||
public long getOutSpeed();
|
||||
public long getInSpeed();
|
||||
public long getOutTraffic();
|
||||
public long getInTraffic();
|
||||
public long getOutPPS() ;
|
||||
public long getInPPS() ;
|
||||
|
||||
public long getOutSpeedMax();
|
||||
public long getInSpeedMax();
|
||||
public long getOutPPSMax();
|
||||
public long getInPPSMax();
|
||||
}
|
||||
|
||||
@@ -1,294 +1,78 @@
|
||||
package org.kne.cloud.network.monitor;
|
||||
|
||||
import java.util.TimerTask;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.LongAdder;
|
||||
|
||||
import org.kne.cloud.clock.HighAccuracyClock;
|
||||
import org.kne.cloud.network.ipv6.PacketID;
|
||||
import org.kne.cloud.network.klalb.KLALBUtils;
|
||||
|
||||
public class SpeedAndTrafficMonitorDataImpl extends MonitorDataImpl implements SpeedAndTrafficMonitorData {
|
||||
|
||||
private long updatetime=System.nanoTime();
|
||||
private long updatetime1=System.nanoTime();
|
||||
private long updatetime2=System.nanoTime();
|
||||
private TimestampMonitor<UUID>uploadBandwidth;
|
||||
private TimestampMonitor<UUID>downloadBandwidth;
|
||||
private long timewindow=200000000L;
|
||||
private long timewindowmax=200000000L;
|
||||
|
||||
private volatile LongAdder inTraffic=new LongAdder();
|
||||
private volatile LongAdder outTraffic=new LongAdder();
|
||||
private static final long CALC_TIMEOUT=50000000;
|
||||
|
||||
|
||||
private long inTrafficOld=0;
|
||||
private long outTrafficOld=0;
|
||||
private long inTrafficOld1=0;
|
||||
private long outTrafficOld1=0;
|
||||
private long inTrafficOld2=0;
|
||||
private long outTrafficOld2=0;
|
||||
|
||||
private volatile long inSpeed;
|
||||
private volatile long outSpeed;
|
||||
|
||||
private volatile long inSpeedAvg;
|
||||
private volatile long outSpeedAvg;
|
||||
private volatile long inSpeedAvg2;
|
||||
private volatile long outSpeedAvg2;
|
||||
|
||||
private volatile long inSpeedMax;
|
||||
private volatile long outSpeedMax;
|
||||
private volatile long inSpeedMax2;
|
||||
private volatile long outSpeedMax2;
|
||||
|
||||
public SpeedAndTrafficMonitorDataImpl() {
|
||||
public SpeedAndTrafficMonitorDataImpl(HighAccuracyClock clock) {
|
||||
super();
|
||||
createTask();
|
||||
createTask1();
|
||||
createTask2();
|
||||
this.clock=clock;
|
||||
uploadBandwidth=new ArrayListTimestampMonitor<UUID>(clock,"UploadMonitor", 100, 500000000L);
|
||||
downloadBandwidth=new ArrayListTimestampMonitor<UUID>(clock,"DownloadMonitor", 100, 500000000L);
|
||||
|
||||
getTimer().scheduleAtFixedRate(pttx, timewindowmax/1000000, timewindowmax/1000000);
|
||||
}
|
||||
|
||||
protected void createTask() {
|
||||
getTimer().scheduleAtFixedRate(tmt, 0, 20);
|
||||
private HighAccuracyClock clock;
|
||||
public HighAccuracyClock getClock() {
|
||||
return clock;
|
||||
}
|
||||
|
||||
protected void createTask1() {
|
||||
getTimer().scheduleAtFixedRate(tmt1, 0, 500);
|
||||
}
|
||||
protected void createTask2() {
|
||||
getTimer().scheduleAtFixedRate(tmt2, 0, 5000);
|
||||
}
|
||||
public long getInSpeedAvg2() {
|
||||
return inSpeedAvg2;
|
||||
}
|
||||
|
||||
public long getOutSpeedAvg2() {
|
||||
return outSpeedAvg2;
|
||||
}
|
||||
|
||||
public long getInTraffic() {
|
||||
return inTraffic.sum();
|
||||
}
|
||||
|
||||
public long getOutTraffic() {
|
||||
return outTraffic.sum();
|
||||
}
|
||||
|
||||
public LongAdder getInTrafficAL() {
|
||||
return inTraffic;
|
||||
}
|
||||
|
||||
public LongAdder getOutTrafficAL() {
|
||||
return outTraffic;
|
||||
}
|
||||
|
||||
public long getInSpeed() {
|
||||
return inSpeed;
|
||||
}
|
||||
|
||||
|
||||
public long getOutSpeed() {
|
||||
return outSpeed;
|
||||
}
|
||||
|
||||
public long getInSpeedAvg() {
|
||||
return inSpeedAvg;
|
||||
}
|
||||
|
||||
|
||||
public long getOutSpeedAvg() {
|
||||
return outSpeedAvg;
|
||||
}
|
||||
|
||||
public long getInSpeedMax() {
|
||||
return inSpeedMax;
|
||||
}
|
||||
|
||||
|
||||
public long getOutSpeedMax() {
|
||||
return outSpeedMax;
|
||||
}
|
||||
|
||||
|
||||
public long getInSpeedMax2() {
|
||||
return inSpeedMax2;
|
||||
|
||||
|
||||
public SpeedAndTrafficMonitorDataImpl(TimestampMonitor<UUID> uploadBandwidth,
|
||||
TimestampMonitor<UUID> downloadBandwidth) {
|
||||
super();
|
||||
this.uploadBandwidth = uploadBandwidth;
|
||||
this.downloadBandwidth = downloadBandwidth;
|
||||
|
||||
getTimer().scheduleAtFixedRate(pttx, timewindowmax/1000000, timewindowmax/1000000);
|
||||
}
|
||||
|
||||
|
||||
public long getOutSpeedMax2() {
|
||||
return outSpeedMax2;
|
||||
|
||||
|
||||
|
||||
|
||||
public TimestampMonitor<UUID> getUploadBandwidth() {
|
||||
return uploadBandwidth;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public TimestampMonitor<UUID> getDownloadBandwidth() {
|
||||
return downloadBandwidth;
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected TimerTask tmt=new TimerTask() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
long d=System.nanoTime()-updatetime;
|
||||
if(d!=0) {
|
||||
if(inTraffic!=null) {
|
||||
long inTrafficSum=inTraffic.sum();
|
||||
long i=inTrafficSum-inTrafficOld;
|
||||
inTrafficOld =inTrafficSum;
|
||||
inSpeed= (long) (i*1000000000.0/d);
|
||||
}
|
||||
|
||||
if(outTraffic!=null) {
|
||||
long outTrafficSum=outTraffic.sum();
|
||||
long o=outTrafficSum-outTrafficOld;
|
||||
outTrafficOld =outTrafficSum;
|
||||
outSpeed= (long) (o*1000000000.0/d);
|
||||
}
|
||||
|
||||
if(inCounter!=null) {
|
||||
long inCounterSum=inCounter.sum();
|
||||
long i=inCounterSum-inCounterOld;
|
||||
inCounterOld =inCounterSum;
|
||||
inPPS= (long) (i*1000000000.0/d);
|
||||
}
|
||||
if(outCounter!=null) {
|
||||
long outCounterSum=outCounter.sum();
|
||||
long i=outCounterSum-outCounterOld;
|
||||
outCounterOld =outCounterSum;
|
||||
outPPS= (long) (i*1000000000.0/d);
|
||||
}
|
||||
}
|
||||
if(outSpeed>=outSpeedMax) {
|
||||
outSpeedMax=outSpeed;
|
||||
}else {
|
||||
outSpeedMax=(outSpeedMax*99+outSpeed)/100;
|
||||
}
|
||||
|
||||
if(inSpeed>=inSpeedMax) {
|
||||
inSpeedMax=inSpeed;
|
||||
}else {
|
||||
inSpeedMax=(inSpeedMax*99+inSpeed)/100;
|
||||
}
|
||||
|
||||
|
||||
if(outPPS>=outPPSMax) {
|
||||
outPPSMax=outPPS;
|
||||
}else {
|
||||
outPPSMax=(outPPSMax*99+outPPS)/100;
|
||||
}
|
||||
|
||||
if(inPPS>=inPPSMax) {
|
||||
inPPSMax=inPPS;
|
||||
}else {
|
||||
inPPSMax=(inPPSMax*99+inPPS)/100;
|
||||
}
|
||||
|
||||
updatetime=System.nanoTime();
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
protected TimerTask tmt1=new TimerTask() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
long d=System.nanoTime()-updatetime1;
|
||||
if(d!=0) {
|
||||
if(inTraffic!=null) {
|
||||
long inTrafficSum=inTraffic.sum();
|
||||
long i=inTrafficSum-inTrafficOld1;
|
||||
inTrafficOld1 =inTrafficSum;
|
||||
inSpeedAvg= (long) (i*1000000000.0/d);
|
||||
}
|
||||
|
||||
if(outTraffic!=null) {
|
||||
long outTrafficSum=outTraffic.sum();
|
||||
long o=outTrafficSum-outTrafficOld1;
|
||||
outTrafficOld1 =outTrafficSum;
|
||||
outSpeedAvg= (long) (o*1000000000.0/d);
|
||||
}
|
||||
|
||||
if(inCounter!=null) {
|
||||
long inCounterSum=inCounter.sum();
|
||||
long i=inCounterSum-inCounterOld1;
|
||||
inCounterOld1 =inCounterSum;
|
||||
inPPSAvg= (long) (i*1000000000.0/d);
|
||||
}
|
||||
|
||||
if(outCounter!=null) {
|
||||
long outCounterSum=outCounter.sum();
|
||||
long o=outCounterSum-outCounterOld1;
|
||||
outCounterOld1 =outCounterSum;
|
||||
outPPSAvg= (long) (o*1000000000.0/d);
|
||||
}
|
||||
}
|
||||
|
||||
updatetime1=System.nanoTime();
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
protected TimerTask tmt2=new TimerTask() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
long d=System.nanoTime()-updatetime2;
|
||||
if(d!=0) {
|
||||
if(inTraffic!=null) {
|
||||
long inTrafficSum=inTraffic.sum();
|
||||
long i=inTrafficSum-inTrafficOld2;
|
||||
inTrafficOld2 =inTrafficSum;
|
||||
inSpeedAvg2= (long) (i*1000000000.0/d);
|
||||
}
|
||||
|
||||
if(outTraffic!=null) {
|
||||
long outTrafficSum=outTraffic.sum();
|
||||
long o=outTrafficSum-outTrafficOld2;
|
||||
outTrafficOld2 =outTrafficSum;
|
||||
outSpeedAvg2= (long) (o*1000000000.0/d);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(inCounter!=null) {
|
||||
long inCounterSum=inCounter.sum();
|
||||
long i=inCounterSum-inCounterOld2;
|
||||
inCounterOld2 =inCounterSum;
|
||||
inPPSAvg2= (long) (i*1000000000.0/d);
|
||||
}
|
||||
|
||||
if(outCounter!=null) {
|
||||
long outCounterSum=outCounter.sum();
|
||||
long o=outCounterSum-outCounterOld2;
|
||||
outCounterOld2 =outCounterSum;
|
||||
outPPSAvg2= (long) (o*1000000000.0/d);
|
||||
}
|
||||
}
|
||||
|
||||
if(outSpeedAvg2>=outSpeedMax2) {
|
||||
outSpeedMax2=outSpeedAvg2;
|
||||
}else {
|
||||
outSpeedMax2=(outSpeedMax2*999+outSpeedAvg2)/1000;
|
||||
}
|
||||
|
||||
if(inSpeedAvg2>=inSpeedMax2) {
|
||||
inSpeedMax2=inSpeedAvg2;
|
||||
}else {
|
||||
inSpeedMax2=(inSpeedMax2*999+inSpeedAvg2)/1000;
|
||||
}
|
||||
|
||||
|
||||
if(outPPSAvg2>=outPPSMax2) {
|
||||
outPPSMax2=outPPSAvg2;
|
||||
}else {
|
||||
outPPSMax2=(outPPSMax2*999+outPPSAvg2)/1000;
|
||||
}
|
||||
|
||||
if(inPPSAvg2>=inPPSMax2) {
|
||||
inPPSMax2=inPPSAvg2;
|
||||
}else {
|
||||
inPPSMax2=(inPPSMax2*999+inPPSAvg2)/1000;
|
||||
}
|
||||
|
||||
updatetime2=System.nanoTime();
|
||||
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb=new StringBuilder(super.toString());
|
||||
sb.append('\t');
|
||||
sb.append(KLALBUtils. convertIBUint(outTraffic.sum())).append("\t").append(KLALBUtils.convertIBUint(inTraffic.sum())).append("\t").append(KLALBUtils.convertIBUint(outSpeed)).append("/s\t").append(KLALBUtils.convertIBUint(inSpeed)).append("/s\t");
|
||||
sb.append(KLALBUtils. convertIBUint(uploadBandwidth.getTotalDataSize())).append("\t").append(KLALBUtils.convertIBUint(downloadBandwidth.getTotalDataSize())).append("\t").append(KLALBUtils.convertIBUint(uploadBandwidth.calculateBandwidth(timewindow))).append("/s\t").append(KLALBUtils.convertIBUint(downloadBandwidth.calculateBandwidth(timewindow))).append("/s\t");
|
||||
|
||||
/*if(getState()==OFFLINE) {
|
||||
sb.append((coolingTime-(System.currentTimeMillis()-mls))/1000L);
|
||||
@@ -301,84 +85,116 @@ public class SpeedAndTrafficMonitorDataImpl extends MonitorDataImpl implements S
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private volatile long outspeedTimeout=System.nanoTime();
|
||||
public long getOutSpeed() {
|
||||
long curr=System.nanoTime();
|
||||
if(curr-outspeedTimeout>CALC_TIMEOUT) {
|
||||
outspeedTimeout=curr;
|
||||
outSpeed=uploadBandwidth.calculateBandwidth(timewindow);
|
||||
}
|
||||
return outSpeed;
|
||||
}
|
||||
private volatile long inspeedTimeout=System.nanoTime();
|
||||
public long getInSpeed() {
|
||||
long curr=System.nanoTime();
|
||||
if(curr-inspeedTimeout>CALC_TIMEOUT) {
|
||||
inspeedTimeout=curr;
|
||||
inSpeed=downloadBandwidth.calculateBandwidth(timewindow);
|
||||
}
|
||||
return inSpeed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public long getOutTraffic() {
|
||||
return uploadBandwidth.getTotalDataSize();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public long getInTraffic() {
|
||||
return downloadBandwidth.getTotalDataSize();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public long getOutPPS() {
|
||||
return uploadBandwidth.calculatePacketRate(timewindow);
|
||||
}
|
||||
|
||||
|
||||
public long getInPPS() {
|
||||
return downloadBandwidth.calculatePacketRate(timewindow);
|
||||
}
|
||||
private long inSpeed;
|
||||
private long outSpeed;
|
||||
|
||||
private long outSpeeedMax=0;
|
||||
private long inSpeedMax=0;
|
||||
private long outPPSMax=0;
|
||||
private long inPPSMax=0;
|
||||
|
||||
public long getOutSpeedMax() {
|
||||
return outSpeeedMax;
|
||||
}
|
||||
public long getInSpeedMax() {
|
||||
return inSpeedMax;
|
||||
}
|
||||
public long getOutPPSMax() {
|
||||
return outPPSMax;
|
||||
}
|
||||
public long getInPPSMax() {
|
||||
return inPPSMax;
|
||||
}
|
||||
|
||||
private TimerTask pttx=new TimerTask() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
long os=uploadBandwidth.calculateBandwidth(timewindowmax);
|
||||
long is=downloadBandwidth.calculateBandwidth(timewindowmax);
|
||||
long op=uploadBandwidth.calculatePacketRate(timewindowmax);
|
||||
long ip=uploadBandwidth.calculatePacketRate(timewindowmax);
|
||||
if(os>outSpeeedMax) {
|
||||
outSpeeedMax=(outSpeeedMax+os)/2;
|
||||
}else {
|
||||
outSpeeedMax=(outSpeeedMax*999+os)/1000;
|
||||
}
|
||||
if(is>inSpeedMax) {
|
||||
inSpeedMax=(inSpeedMax+is)/2;
|
||||
}else {
|
||||
inSpeedMax=(inSpeedMax*999+is)/1000;
|
||||
}
|
||||
if(op>outPPSMax) {
|
||||
outPPSMax=(outPPSMax+op)/2;
|
||||
}else {
|
||||
outPPSMax=(outPPSMax*999+op)/1000;
|
||||
}
|
||||
if(ip>inPPSMax) {
|
||||
inPPSMax=(inPPSMax+ip)/2;
|
||||
}else {
|
||||
inPPSMax=(inPPSMax*999+ip)/1000;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
tmt.cancel();
|
||||
tmt1.cancel();
|
||||
tmt2.cancel();
|
||||
pttx.cancel();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private volatile LongAdder inCounter=new LongAdder();
|
||||
private volatile LongAdder outCounter=new LongAdder();
|
||||
|
||||
private long inCounterOld;
|
||||
private long outCounterOld;
|
||||
private long inCounterOld1;
|
||||
private long outCounterOld1;
|
||||
private long inCounterOld2;
|
||||
private long outCounterOld2;
|
||||
|
||||
private volatile long inPPS;
|
||||
private volatile long outPPS;
|
||||
|
||||
|
||||
private volatile long inPPSMax;
|
||||
private volatile long outPPSMax;
|
||||
private volatile long inPPSMax2;
|
||||
private volatile long outPPSMax2;
|
||||
|
||||
private volatile long inPPSAvg;
|
||||
private volatile long outPPSAvg;
|
||||
private volatile long inPPSAvg2;
|
||||
private volatile long outPPSAvg2;
|
||||
|
||||
@Override
|
||||
public long getInPPS() {
|
||||
return inPPS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getOutPPS() {
|
||||
return outPPS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LongAdder getInPacketCounterAL() {
|
||||
return inCounter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LongAdder getOutPacketCounterAL() {
|
||||
return outCounter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getInPacketCounter() {
|
||||
return inCounter.sum();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getOutPacketCounter() {
|
||||
return outCounter.sum();
|
||||
}
|
||||
|
||||
public double getOutPPSMax2() {
|
||||
return outPPSMax2;
|
||||
}
|
||||
|
||||
public double getInPPSMax2() {
|
||||
return inPPSMax2;
|
||||
}
|
||||
|
||||
public long getOutPPSAvg() {
|
||||
return outPPSAvg;
|
||||
}
|
||||
|
||||
public long getInPPSAvg() {
|
||||
return inPPSAvg;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.kne.cloud.network.monitor;
|
||||
|
||||
import org.kne.cloud.clock.HighAccuracyClock;
|
||||
import org.kne.cloud.network.ipv6.PacketID;
|
||||
import org.kne.math.Long128;
|
||||
|
||||
/**
|
||||
@@ -45,6 +46,11 @@ public interface TimestampMonitor<K> {
|
||||
*/
|
||||
boolean recordPacket(K key, Long128 timestamp, int length);
|
||||
|
||||
|
||||
boolean recordPacket(K key, Long128 timestamp, int length, long dsndDelay);
|
||||
|
||||
boolean recordPacket(K key, int length, long dsndDelay);
|
||||
|
||||
// ==================== 清理维护方法 ====================
|
||||
|
||||
/**
|
||||
@@ -106,6 +112,22 @@ public interface TimestampMonitor<K> {
|
||||
*/
|
||||
long calculateBandwidth(Long128 currentTime, long timeWindowNs);
|
||||
|
||||
/**
|
||||
* 计算转发率(使用当前时间)
|
||||
* @param timeWindowNs 时间窗口(纳秒)
|
||||
* @return 转发率(包/秒)
|
||||
*/
|
||||
long calculatePacketRate(long timeWindowNs);
|
||||
|
||||
/**
|
||||
* 计算转发率(使用指定时间)
|
||||
* @param currentTime 当前时间
|
||||
* @param timeWindowNs 时间窗口(纳秒)
|
||||
* @return 转发率(包/秒)
|
||||
*/
|
||||
long calculatePacketRate(Long128 currentTime, long timeWindowNs);
|
||||
|
||||
|
||||
/**
|
||||
* 计算流量统计信息(使用当前时间)
|
||||
* @param timeWindowNs 时间窗口(纳秒)
|
||||
@@ -121,6 +143,12 @@ public interface TimestampMonitor<K> {
|
||||
*/
|
||||
TrafficStats calculateTrafficStats(Long128 currentTime, long timeWindowNs);
|
||||
|
||||
long getRecentDelay();
|
||||
|
||||
|
||||
TimestampMonitorValue getRecentDelayEntry();
|
||||
|
||||
|
||||
// ==================== 全局统计方法 ====================
|
||||
|
||||
/**
|
||||
@@ -153,4 +181,6 @@ public interface TimestampMonitor<K> {
|
||||
* @return 监控器状态字符串
|
||||
*/
|
||||
String toString();
|
||||
|
||||
|
||||
}
|
||||
@@ -8,51 +8,68 @@ public class TimestampMonitorValue implements Comparable<TimestampMonitorValue>
|
||||
private final Long128 timestamp;
|
||||
private final int length;
|
||||
private final TimestampMonitorKey<?> key;
|
||||
|
||||
private long delay;
|
||||
public TimestampMonitorValue(TimestampMonitorKey<?> key, Long128 timestamp, int length) {
|
||||
this(key,timestamp,length,Long.MAX_VALUE/1024);
|
||||
}
|
||||
public TimestampMonitorValue(TimestampMonitorKey<?> key, Long128 timestamp, int length,long delay) {
|
||||
this.key = key;
|
||||
this.timestamp = timestamp;
|
||||
this.length = length;
|
||||
this.delay=delay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + length;
|
||||
result = prime * result + ((timestamp == null) ? 0 : timestamp.hashCode());
|
||||
return result;
|
||||
}
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + (int) (delay ^ (delay >>> 32));
|
||||
result = prime * result + length;
|
||||
result = prime * result + ((timestamp == null) ? 0 : timestamp.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
TimestampMonitorValue other = (TimestampMonitorValue) obj;
|
||||
if (length != other.length)
|
||||
return false;
|
||||
if (timestamp == null) {
|
||||
if (other.timestamp != null)
|
||||
return false;
|
||||
} else if (!timestamp.equals(other.timestamp))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
TimestampMonitorValue other = (TimestampMonitorValue) obj;
|
||||
if (delay != other.delay)
|
||||
return false;
|
||||
if (length != other.length)
|
||||
return false;
|
||||
if (timestamp == null) {
|
||||
if (other.timestamp != null)
|
||||
return false;
|
||||
} else if (!timestamp.equals(other.timestamp))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TimestampMonitorValue [timestamp=" + timestamp + ", length=" + length + "]";
|
||||
}
|
||||
public String toString() {
|
||||
return "TimestampMonitorValue [timestamp=" + timestamp + ", length=" + length + ", key=" + key + ", delay="
|
||||
+ delay + "]";
|
||||
}
|
||||
|
||||
public Long128 getTimestamp() { return timestamp; }
|
||||
public int getLength() { return length; }
|
||||
public TimestampMonitorKey<?> getKey() { return key; }
|
||||
|
||||
@Override
|
||||
|
||||
public long getDelay() {
|
||||
return delay;
|
||||
}
|
||||
|
||||
public void setDelay(long delay) {
|
||||
this.delay = delay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(TimestampMonitorValue other) {
|
||||
return this.timestamp.compareTo(other.timestamp);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user