package org.ovirt.engine.core.vdsbroker; import org.ovirt.engine.core.common.businessentities.network.NetworkInterface; import org.ovirt.engine.core.common.businessentities.network.NetworkStatistics; public class NetworkStatisticsBuilder { private static final int BITS_IN_BYTE = 8; private static final int BITS_IN_MEGABIT = 1000000; private Integer speed; private Double currentTime; private Double previousTime; public NetworkStatisticsBuilder() { } /** * Updates an existing NetworkInterface entity with recent statistics stored in a new NetworkInterface entity. * * @param existingIface * the existing NetworkInterface entity, whose Statistics and Speed members are to be modified. * @param reportedIface * the NetworkInterface entity storing recently-reported values, which will not be modified. */ public void updateExistingInterfaceStatistics(NetworkInterface<?> existingIface, NetworkInterface<?> reportedIface) { NetworkStatistics existingStats = existingIface.getStatistics(); NetworkStatistics reportedStats = reportedIface.getStatistics(); speed = reportedIface.getSpeed(); currentTime = reportedStats.getSampleTime(); previousTime = existingStats.getSampleTime(); existingIface.setSpeed(speed); existingStats.setReceiveDropRate(reportedStats.getReceiveDropRate()); existingStats.setTransmitDropRate(reportedStats.getTransmitDropRate()); EffectiveStats rxResult = computeEffectiveStats(reportedStats.getReceivedBytes(), existingStats.getReceivedBytes(), existingStats.getReceivedBytesOffset()); EffectiveStats txResult = computeEffectiveStats(reportedStats.getTransmittedBytes(), existingStats.getTransmittedBytes(), existingStats.getTransmittedBytesOffset()); existingStats.setReceivedBytes(rxResult.current); existingStats.setReceivedBytesOffset(rxResult.offset); existingStats.setReceiveRate(rxResult.rate); existingStats.setTransmittedBytes(txResult.current); existingStats.setTransmittedBytesOffset(txResult.offset); existingStats.setTransmitRate(txResult.rate); existingStats.setSampleTime(currentTime); } private EffectiveStats computeEffectiveStats(Long reported, Long previous, Long offset) { EffectiveStats stats = new EffectiveStats(); if (reported == null) { // the value wasn't reported - clear it, keep the previous offset, and rate can't be computed stats.current = null; stats.offset = offset; stats.rate = null; } else if (offset == null) { // statistic reported for the first time - set to zero, set offset accordingly, and rate can't be computed stats.current = 0L; stats.offset = -reported; stats.rate = null; } else { stats.offset = offset; stats.current = offset + reported; if (previous == null) { // for some reason there's no previous sample - the rate can't be computed stats.rate = null; } else { if (stats.current < previous) { // if value wrapped around, it means counter had reset - compensate in offset, and update value stats.offset = previous; stats.current = previous + reported; } // current and previous sampled values are up-to-date - try to compute rate stats.rate = computeRatePercentage(stats.current - previous); } } return stats; } private static double truncatePercentage(double value) { return Math.min(100, value); } private Double computeRatePercentage(long byteDiff) { if (currentTime == null || previousTime == null || currentTime <= previousTime || speed == null || speed.equals(0)) { return null; } long megabitDiff = BITS_IN_BYTE * byteDiff / BITS_IN_MEGABIT; double timeDiffInSeconds = currentTime - previousTime; double rateInMbps = megabitDiff / timeDiffInSeconds; return truncatePercentage(100 * rateInMbps / speed); } private static class EffectiveStats { private Long current; private Long offset; private Double rate; } }