View Javadoc

1   /*
2    *  XNap - A P2P framework and client.
3    *
4    *  See the file AUTHORS for copyright information.
5    *
6    *  This program is free software; you can redistribute it and/or modify
7    *  it under the terms of the GNU General Public License as published by
8    *  the Free Software Foundation.
9    *
10   *  This program is distributed in the hope that it will be useful,
11   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   *  GNU General Public License for more details.
14   *
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  package org.xnap.io;
21  
22  
23  /***
24   * Provides a throttle implementation based on time ticks. Clients can
25   * allocate a limited amount of bytes for each tick. If all bandwidth
26   * has been allocated clients are stalled until the next tick.
27   */
28  public class ThrottleSupport
29  {
30  
31      //--- Constant(s) ---
32  
33      /***
34       * The default length of a tick.
35       */
36      public static final long TICK_LENGTH = 250;
37  
38      //--- Data field(s) ---
39  
40      //private static Logger logger = Logger.getLogger(ThrottleSupport.class);
41  
42      /***
43       * bytes per tick
44       */
45      protected long bandwidth = 0;
46      protected long allocated = 0;
47      protected long tickStart = 0;
48      protected Object lock = new Object();
49  
50      //--- Constructor(s) ---
51  
52      public ThrottleSupport()
53      {
54      }
55  
56      //--- Method(s) ---
57  
58      /***
59       * Returns the preferred block size each client should try to
60       * allocate at a time. This makes sure each client gets a fair
61       * share of the bandwidth.
62       *
63       * @see #allocate(int) 
64       */
65      public int getPreferredBlocksize()
66      {
67  		synchronized (lock) {
68  			long bs = bandwidth / 4;
69  			return bs == 0 ? 512 : bs < 64 ? 64 : bs > 512 ? 512 : (int)bs;
70  		}
71      }
72  
73      /***
74       * Sets the maximum bandwidth.
75       *
76       * @param bandwidth byte / s
77       */
78      public void setBandwidth(long bandwidth)
79      {
80  		synchronized (lock) {
81  			this.bandwidth = (bandwidth * TICK_LENGTH) / 1000;
82  		}
83      }
84  
85      /***
86       * Returns the number of bytes that the calling thread is allowed to 
87       * send. Blocks until at least one byte could be allocated.
88       *
89       * @return -1, if interrupted;
90       */
91      public int allocate(int bytes)
92      {
93  		synchronized (lock) {
94  			while (true) {
95  				if (System.currentTimeMillis() - tickStart >= TICK_LENGTH) {
96  					//logger.warn("* new tick: " + bandwidth + " to allocate *");
97  					tickStart = System.currentTimeMillis();
98  					allocated = 0;
99  					//lock.notifyAll();
100 				}
101 
102 				if (bandwidth == 0) {
103 					// no limit
104 					return bytes;
105 				}
106 				else if (bytes < bandwidth - allocated) {
107 					// we still have some bandwidth left
108 					allocated += bytes;
109 					//logger.warn("returning " + bytes);
110 					return bytes;
111 				}
112 				else if (bandwidth - allocated > 0) {
113 					// don't have enough, but return all we have left
114 					bytes = (int)(bandwidth - allocated);
115 					allocated = bandwidth;
116 					//logger.warn("returning " + bytes);
117 					return bytes;
118 				}
119 		
120 				// we could not allocate any bandwidth, wait until the next
121 				// tick is started
122 
123 				// this is a bit too long
124 				long t
125 					= (TICK_LENGTH - (System.currentTimeMillis() - tickStart));
126 				if (t > 0) {
127 					try {
128 						//logger.warn("waiting for " + t);
129 						lock.wait(t);
130 					}
131 					catch (InterruptedException e) {
132 						return -1;
133 					}
134 				}
135 			}
136 		}
137     }	    
138 
139 }