/* * Copyright 2004 - 2008 Christian Sprajc, Dennis Waldherr. All rights reserved. * * This file is part of PowerFolder. * * PowerFolder is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation. * * PowerFolder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with PowerFolder. If not, see <http://www.gnu.org/licenses/>. * * $Id$ */ package de.dal33t.powerfolder.transfer; import java.util.Date; /** * Convenient class to limit bandwidth (for example for streams). A * BandwidthLimiter starts out with 0 available and doesn't increase that. So it * needs some kind of "provider" which sets the amount of available bandwidth. * The BandwidthProvider class is an example of such. Instances start with no * limit. $Id$ * * @author Dennis "Dante" Waldherr * @version $Revision: 1.3 $ */ public class BandwidthLimiter { public static final long UNLIMITED = -1; public static final BandwidthLimiter WAN_OUTPUT_BANDWIDTH_LIMITER = new BandwidthLimiter(BandwidthLimiterInfo.WAN_OUTPUT); public static final BandwidthLimiter WAN_INPUT_BANDWIDTH_LIMITER = new BandwidthLimiter(BandwidthLimiterInfo.WAN_INPUT); public static final BandwidthLimiter LAN_OUTPUT_BANDWIDTH_LIMITER = new BandwidthLimiter(BandwidthLimiterInfo.LAN_OUTPUT); public static final BandwidthLimiter LAN_INPUT_BANDWIDTH_LIMITER = new BandwidthLimiter(BandwidthLimiterInfo.LAN_INPUT); /** * The amount of bandwidth initially set by setAvailable(). * This is used to create stats and is NOT modified by bandwidth requests. */ private long initialAvailable = UNLIMITED; /** * The amount of bandwidth remaining. */ private long available = UNLIMITED; private final Object monitor = new Object(); private final BandwidthLimiterInfo id; private BandwidthLimiter(BandwidthLimiterInfo id) { this.id = id; } public BandwidthLimiterInfo getId() { return id; } /** * Requests bandwidth on a medium. Blocks until bandwidth is available. * * @param size * the amount requested * @return the amount of bandwidth granted. */ public long requestBandwidth(long size) throws InterruptedException { synchronized (monitor) { while (available == 0) { monitor.wait(); } long amount = available < 0 ? size : Math.min(available, size); if (available >= 0) { available -= amount; } return amount; } } /** * Sets the amount of available "bandwidth". As a side-effect this call will * wake Threads waiting in requestBandwidth(). * * @param amount * the amount to set available. An amount < 0 states that there * is no limit. * @return a stat record of how much bandwidth there was initially * and how much was left over. */ public BandwidthStat setAvailable(long amount) { BandwidthStat bandwidthStat; synchronized (monitor) { // Create a stat of how much bandwidth there was initially // and how much there is now. bandwidthStat = new BandwidthStat(new Date(), id, initialAvailable, available); // Set the new amount initialAvailable = amount; available = amount; // Let everyone know. if (available != 0) { monitor.notifyAll(); } } return bandwidthStat; } /** * Returns the amount of "bandwidth" available * * @return the "bandwidth" */ public long getAvailable() { synchronized (monitor) { return available; } } /** * Returns an amount of "bandwidth" back to the limiter. Called after an * invocation of requestBandwidth which didn't use all of the requested * bandwidth. * * @param amount */ public void returnAvailable(int amount) { synchronized (monitor) { if (available >= 0) { available += amount; } } } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } BandwidthLimiter that = (BandwidthLimiter) obj; if (id != that.id) { return false; } return true; } @Override public int hashCode() { return id != null ? id.hashCode() : 0; } @Override public String toString() { return "BandwidthLimiter{" + "id=" + id + '}'; } }