/******************************************************************************* * Copyright (c) 2006-2008, Cloudsmith Inc. * The code, documentation and other materials contained herein have been * licensed under the Eclipse Public License - v 1.0 by the copyright holder * listed above, as the Initial Contributor under such license. The text or * such license is available at www.eclipse.org. ******************************************************************************/ package org.eclipse.equinox.p2.authoring.internal; import java.util.Locale; import java.util.SortedMap; import java.util.TreeMap; import java.util.Map.Entry; public class ProgressStatistics { private static final int DEFAULT_REPORT_INTERVAL = 1000; private static final int SPEED_INTERVAL = 5000; private static final int SPEED_RESOLUTION = 1000; private final StringBuilder m_reportBuilder; private final long m_total; private final long m_startTime; private final int m_leadInLength; private long m_current; private long m_lastReportTime; private int m_reportInterval; private SortedMap<Long, Long> m_recentSpeedMap; private long m_recentSpeedMapKey; public ProgressStatistics(String fileName, long total) { m_startTime = System.currentTimeMillis(); m_reportBuilder = new StringBuilder(fileName.length() + 30); m_reportBuilder.append("Fetching "); m_reportBuilder.append(fileName); m_reportBuilder.append(" ("); m_leadInLength = m_reportBuilder.length(); m_total = total; m_current = 0; m_lastReportTime = 0; m_reportInterval = DEFAULT_REPORT_INTERVAL; m_recentSpeedMap = new TreeMap<Long, Long>(); m_recentSpeedMapKey = 0L; } public void increase(long inc) { registerRecentSpeed(getDuration() / SPEED_RESOLUTION, inc); m_current += inc; } public long getDuration() { return System.currentTimeMillis() - m_startTime; } public long getAverageSpeed() { long dur = getDuration(); if(dur >= 1000) return m_current / (dur / 1000); return 0L; } synchronized public long getRecentSpeed() { removeObsoleteRecentSpeedData(getDuration() / SPEED_RESOLUTION); long dur = 0L; long amount = 0L; SortedMap<Long, Long> relevantData = m_recentSpeedMap.headMap(Long.valueOf(m_recentSpeedMapKey)); for(Entry<Long, Long> entry : relevantData.entrySet()) { dur += SPEED_RESOLUTION; amount += entry.getValue().longValue(); } if(dur >= 1000) return amount / (dur / 1000); return 0L; } public double getPercentage() { if(m_total > 0) return ((double)m_current) / ((double)m_total); return 0.0; } public int getReportInterval() { return m_reportInterval; } public long getTotal() { return m_total; } public void setReportInterval(int reportInterval) { m_reportInterval = reportInterval; } public boolean shouldReport() { long currentTime = System.currentTimeMillis(); if(m_lastReportTime == 0 || currentTime - m_lastReportTime >= m_reportInterval) { m_lastReportTime = currentTime; return true; } return false; } public synchronized String report() { m_reportBuilder.setLength(m_leadInLength); m_reportBuilder.append(convert(m_current)); if(m_total != -1) { m_reportBuilder.append(" of "); m_reportBuilder.append(convert(m_total)); } m_reportBuilder.append(" at "); m_reportBuilder.append(convert(getRecentSpeed())); m_reportBuilder.append("/s)"); return m_reportBuilder.toString(); } @Override public String toString() { return report(); } synchronized private void registerRecentSpeed(long key, long inc) { Long keyL = Long.valueOf(key); Long currentValueL = m_recentSpeedMap.get(keyL); long currentValue = 0L; if(currentValueL != null) currentValue = currentValueL.longValue(); m_recentSpeedMap.put(keyL, Long.valueOf(inc + currentValue)); if(m_recentSpeedMapKey != key) { m_recentSpeedMapKey = key; removeObsoleteRecentSpeedData(key); } } synchronized private void removeObsoleteRecentSpeedData(long lastKey) { long threshold = lastKey - SPEED_INTERVAL / SPEED_RESOLUTION; m_recentSpeedMap.headMap(Long.valueOf(threshold)).clear(); } private static String convert(long amount) { if(amount < 1024) return String.format(Locale.US, "%dB", Long.valueOf(amount)); if(amount < 1024 * 1024) return String.format(Locale.US, "%.2fkB", Double.valueOf(((double)amount) / 1024)); return String.format(Locale.US, "%.2fMB", Double.valueOf(((double)amount) / (1024 * 1024))); } }