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