1 /* 2 * Created on Dec 1, 2008 3 * Created by Paul Gardner 4 * 5 * Copyright (C) Azureus Software, Inc, All Rights Reserved. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 */ 19 20 21 package com.aelitis.azureus.core.networkmanager.impl; 22 23 import org.gudy.azureus2.core3.util.Debug; 24 import org.gudy.azureus2.core3.util.SystemTime; 25 26 import com.aelitis.azureus.core.networkmanager.NetworkManager; 27 28 public class 29 ByteBucketMT 30 implements ByteBucket 31 { 32 private int rate; 33 private int burst_rate; 34 private volatile long avail_bytes; 35 private volatile long prev_update_time; 36 37 private volatile boolean frozen; 38 39 /** 40 * Create a new byte-bucket with the given byte fill (guaranteed) rate. 41 * Burst rate is set to default 1.2X of given fill rate. 42 * @param rate_bytes_per_sec fill rate 43 */ ByteBucketMT( int rate_bytes_per_sec )44 public ByteBucketMT( int rate_bytes_per_sec ) { 45 this( rate_bytes_per_sec, rate_bytes_per_sec + (rate_bytes_per_sec/5) ); 46 } 47 48 /** 49 * Create a new byte-bucket with the given byte fill (guaranteed) rate 50 * and the given burst rate. 51 * @param rate_bytes_per_sec fill rate 52 * @param burst_rate max rate 53 */ ByteBucketMT( int rate_bytes_per_sec, int burst_rate )54 private ByteBucketMT( int rate_bytes_per_sec, int burst_rate ) { 55 this.rate = rate_bytes_per_sec; 56 this.burst_rate = burst_rate; 57 avail_bytes = 0; //start bucket empty 58 prev_update_time = SystemTime.getMonotonousTime(); 59 ensureByteBucketMinBurstRate(); 60 } 61 62 63 /** 64 * Get the number of bytes currently available for use. 65 * @return number of free bytes 66 */ getAvailableByteCount()67 public int getAvailableByteCount() { 68 if ( avail_bytes < NetworkManager.UNLIMITED_RATE ){ 69 update_avail_byte_count(); 70 } 71 72 int res = (int)avail_bytes; 73 74 if ( res < 0 ){ 75 res = 0; 76 } 77 return( res ); 78 } 79 80 81 /** 82 * Update the bucket with the number of bytes just used. 83 * @param bytes_used 84 */ setBytesUsed( int bytes_used )85 public void setBytesUsed( int bytes_used ) { 86 if ( avail_bytes >= NetworkManager.UNLIMITED_RATE ){ 87 return; 88 } 89 90 avail_bytes -= bytes_used; 91 //if( avail_bytes < 0 ) Debug.out( "avail_bytes < 0: " + avail_bytes); 92 } 93 94 95 /** 96 * Get the configured fill rate. 97 * @return guaranteed rate in bytes per sec 98 */ getRate()99 public int getRate() { return rate; } 100 101 102 /** 103 * Get the configured burst rate. 104 * @return burst rate in bytes per sec 105 */ getBurstRate()106 public int getBurstRate() { return burst_rate; } 107 108 109 /** 110 * Set the current fill/guaranteed rate, with a burst rate of 1.2X the given rate. 111 * @param rate_bytes_per_sec 112 */ setRate( int rate_bytes_per_sec )113 public void setRate( int rate_bytes_per_sec ) { 114 setRate( rate_bytes_per_sec, rate_bytes_per_sec + (rate_bytes_per_sec/5)); 115 } 116 117 public void setFrozen( boolean f )118 setFrozen( 119 boolean f ) 120 { 121 frozen = f; 122 } 123 124 /** 125 * Set the current fill/guaranteed rate, along with the burst rate. 126 * @param rate_bytes_per_sec 127 * @param burst_rate 128 */ setRate( int rate_bytes_per_sec, int burst_rate )129 public void setRate( int rate_bytes_per_sec, int burst_rate ) { 130 if( rate_bytes_per_sec < 0 ) { 131 Debug.out("rate_bytes_per_sec [" +rate_bytes_per_sec+ "] < 0"); 132 rate_bytes_per_sec = 0; 133 } 134 if( burst_rate < rate_bytes_per_sec ) { 135 Debug.out("burst_rate [" +burst_rate+ "] < rate_bytes_per_sec [" +rate_bytes_per_sec+ "]"); 136 burst_rate = rate_bytes_per_sec; 137 } 138 this.rate = rate_bytes_per_sec; 139 this.burst_rate = burst_rate; 140 if ( avail_bytes > burst_rate ){ 141 avail_bytes = burst_rate; 142 } 143 ensureByteBucketMinBurstRate(); 144 } 145 146 update_avail_byte_count()147 private void update_avail_byte_count() { 148 if ( frozen ){ 149 return; 150 } 151 synchronized( this ){ 152 final long now =SystemTime.getMonotonousTime(); 153 if (prev_update_time <now) { 154 avail_bytes +=((now -prev_update_time) * rate) / 1000; 155 prev_update_time =now; 156 if( avail_bytes > burst_rate ) avail_bytes = burst_rate; 157 else if( avail_bytes < 0 ){ 158 //Debug.out("ERROR: avail_bytes < 0: " + avail_bytes); 159 } 160 } 161 } 162 } 163 164 165 /** 166 * Make sure the bucket's burst rate is at least MSS-sized, 167 * otherwise it will never allow a full packet's worth of data. 168 */ ensureByteBucketMinBurstRate()169 private void ensureByteBucketMinBurstRate() { 170 int mss = NetworkManager.getMinMssSize(); 171 if( burst_rate < mss ) { //oops, this won't ever allow a full packet 172 burst_rate = mss; //so increase the max byte size 173 } 174 } 175 176 } 177