corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) 2006-2014, openmetaverse.org
3 * All rights reserved.
4 *
5 * - Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the openmetaverse.org nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26  
27 using System;
28  
29 namespace OpenMetaverse
30 {
31 /// <summary>
32 /// A hierarchical token bucket for bandwidth throttling. See
33 /// http://en.wikipedia.org/wiki/Token_bucket for more information
34 /// </summary>
35 public class TokenBucket
36 {
37 /// <summary>Parent bucket to this bucket, or null if this is a root
38 /// bucket</summary>
39 TokenBucket parent;
40 /// <summary>Size of the bucket in bytes. If zero, the bucket has
41 /// infinite capacity</summary>
42 int maxBurst;
43 /// <summary>Rate that the bucket fills, in bytes per millisecond. If
44 /// zero, the bucket always remains full</summary>
45 int tokensPerMS;
46 /// <summary>Number of tokens currently in the bucket</summary>
47 int content;
48 /// <summary>Time of the last drip, in system ticks</summary>
49 int lastDrip;
50  
51 #region Properties
52  
53 /// <summary>
54 /// The parent bucket of this bucket, or null if this bucket has no
55 /// parent. The parent bucket will limit the aggregate bandwidth of all
56 /// of its children buckets
57 /// </summary>
58 public TokenBucket Parent
59 {
60 get { return parent; }
61 }
62  
63 /// <summary>
64 /// Maximum burst rate in bytes per second. This is the maximum number
65 /// of tokens that can accumulate in the bucket at any one time
66 /// </summary>
67 public int MaxBurst
68 {
69 get { return maxBurst; }
70 set { maxBurst = (value >= 0 ? value : 0); }
71 }
72  
73 /// <summary>
74 /// The speed limit of this bucket in bytes per second. This is the
75 /// number of tokens that are added to the bucket per second
76 /// </summary>
77 /// <remarks>Tokens are added to the bucket any time
78 /// <seealso cref="RemoveTokens"/> is called, at the granularity of
79 /// the system tick interval (typically around 15-22ms)</remarks>
80 public int DripRate
81 {
82 get { return tokensPerMS * 1000; }
83 set
84 {
85 if (value == 0)
86 tokensPerMS = 0;
87 else if (value / 1000 <= 0)
88 tokensPerMS = 1; // 1 byte/ms is the minimum granularity
89 else
90 tokensPerMS = value / 1000;
91 }
92 }
93  
94 /// <summary>
95 /// The number of bytes that can be sent at this moment. This is the
96 /// current number of tokens in the bucket
97 /// <remarks>If this bucket has a parent bucket that does not have
98 /// enough tokens for a request, <seealso cref="RemoveTokens"/> will
99 /// return false regardless of the content of this bucket</remarks>
100 /// </summary>
101 public int Content
102 {
103 get { return content; }
104 }
105  
106 #endregion Properties
107  
108 /// <summary>
109 /// Default constructor
110 /// </summary>
111 /// <param name="parent">Parent bucket if this is a child bucket, or
112 /// null if this is a root bucket</param>
113 /// <param name="maxBurst">Maximum size of the bucket in bytes, or
114 /// zero if this bucket has no maximum capacity</param>
115 /// <param name="dripRate">Rate that the bucket fills, in bytes per
116 /// second. If zero, the bucket always remains full</param>
117 public TokenBucket(TokenBucket parent, int maxBurst, int dripRate)
118 {
119 this.parent = parent;
120 MaxBurst = maxBurst;
121 DripRate = dripRate;
122 lastDrip = Environment.TickCount & Int32.MaxValue;
123 }
124  
125 /// <summary>
126 /// Remove a given number of tokens from the bucket
127 /// </summary>
128 /// <param name="amount">Number of tokens to remove from the bucket</param>
129 /// <returns>True if the requested number of tokens were removed from
130 /// the bucket, otherwise false</returns>
131 public bool RemoveTokens(int amount)
132 {
133 bool dummy;
134 return RemoveTokens(amount, out dummy);
135 }
136  
137 /// <summary>
138 /// Remove a given number of tokens from the bucket
139 /// </summary>
140 /// <param name="amount">Number of tokens to remove from the bucket</param>
141 /// <param name="dripSucceeded">True if tokens were added to the bucket
142 /// during this call, otherwise false</param>
143 /// <returns>True if the requested number of tokens were removed from
144 /// the bucket, otherwise false</returns>
145 public bool RemoveTokens(int amount, out bool dripSucceeded)
146 {
147 if (maxBurst == 0)
148 {
149 dripSucceeded = true;
150 return true;
151 }
152  
153 dripSucceeded = Drip();
154  
155 if (content - amount >= 0)
156 {
157 if (parent != null && !parent.RemoveTokens(amount))
158 return false;
159  
160 content -= amount;
161 return true;
162 }
163 else
164 {
165 return false;
166 }
167 }
168  
169 /// <summary>
170 /// Add tokens to the bucket over time. The number of tokens added each
171 /// call depends on the length of time that has passed since the last
172 /// call to Drip
173 /// </summary>
174 /// <returns>True if tokens were added to the bucket, otherwise false</returns>
175 private bool Drip()
176 {
177 if (tokensPerMS == 0)
178 {
179 content = maxBurst;
180 return true;
181 }
182 else
183 {
184 int now = Environment.TickCount & Int32.MaxValue;
185 int deltaMS = now - lastDrip;
186  
187 if (deltaMS <= 0)
188 {
189 if (deltaMS < 0)
190 lastDrip = now;
191 return false;
192 }
193  
194 int dripAmount = deltaMS * tokensPerMS;
195  
196 content = Math.Min(content + dripAmount, maxBurst);
197 lastDrip = now;
198  
199 return true;
200 }
201 }
202 }
203 }