/// <summary> /// Attempt to consume a specified number of tokens from the bucket. If the tokens were consumed then <code>true</code> /// is returned, otherwise <code>false</code> is returned. /// </summary> /// <param name="numTokens">The number of tokens to consume from the bucket, must be a positive number.</param> /// <returns><code>true</code> if the tokens were consumed, <code>false</code> otherwise.</returns> public bool TryConsume(long numTokens) { if (numTokens <= 0) { throw new ArgumentOutOfRangeException("numTokens", "Number of tokens to consume must be positive"); } if (numTokens > _capacity) { throw new ArgumentOutOfRangeException("numTokens", "Number of tokens to consume must be less than the capacity of the bucket."); } lock (_syncRoot) { // Give the refill strategy a chance to add tokens if it needs to, but beware of overflow var newTokens = Math.Min(_capacity, Math.Max(0, _refillStrategy.Refill())); _size = Math.Max(0, Math.Min(_size + newTokens, _capacity)); if (numTokens > _size) { return(false); } // Now try to consume some tokens _size -= numTokens; return(true); } }
/// <summary> /// Attempts to consume the specified number of tokens from the bucket. If the /// requested number of tokens are not immediately available, then this method /// will return false to indicate that zero tokens have been consumed. /// </summary> public bool TryConsume(long tokens) { if (tokens <= 0) { throw new ArgumentOutOfRangeException(nameof(tokens), "Number of tokens to consume must be positive" ); } if (tokens > Capacity) { throw new ArgumentOutOfRangeException(nameof(tokens), "Number of tokens to consume must be less than or equal to the capacity" ); } lock (_sync) { // determine how many units have become available since last invocation var refilled = Math.Max(0, _refill.Refill()); // the number of tokens to add, the max of which is the difference between capacity and currently available var deltaTokens = Math.Min(Capacity - _available, refilled); // update the available number of units with the new tokens _available += deltaTokens; if (tokens > _available) { // we don't have enough tokens yet Logging.Log.Trace($"LeakyBucket.TryConsume({tokens}): Failed to consumed tokens. Available: {_available}"); return(false); } // subtract the number of tokens consumed _available = _available - tokens; Logging.Log.Trace($"LeakyBucket.TryConsume({tokens}): Successfully consumed tokens. Available: {_available}"); return(true); } }
/// <summary> /// Sometimes the bucket is half-used before we start counting. This allows us /// to account for this in the beginning. /// </summary> public void SetRemainingTokens(long numTokens) { lock (_syncRoot) _refillStrategy.Refill(); _size = numTokens; }