// leaking bucket implementation public virtual T Start() { T stopWatch = null; IList <T> toBeLogged = null; lock (this) { while (LeakyBucket.First != null && LeakyBucket.First.Value.StartTime < BottomOfBucket.Value.StartTime && (int)(DateTime.Now - LeakyBucket.First.Value.StartTime).TotalSeconds > Configue.TimeOutInSecond) { LeakyBucket.First.Value.Timeout(); OnTimeOut(); LeakyBucketHash.Remove(LeakyBucket.First.Value.StartTime); LeakyBucket.RemoveFirst(); LastLogTime = DateTime.Now; } // before tracking current request, process existing requests already in bucket no more than QPS allowed int leakingSize = 0; if (BottomOfBucket != null) { //Logger.LogInfo("bottom at " + BottomOfBucket.Value.RequestDetail["index"]); leakingSize = GetLeakingSince(LastLogTime); } for (var i = 0; i < leakingSize; i++) // leaking limited number of items out of bucket according to QPS { if (BottomOfBucket == null) // bucket is empty; { break; } if (BottomOfBucket.Value.IsFinished()) // if it's already stopped/received when being leaked { var prev = BottomOfBucket; BottomOfBucket = BottomOfBucket.Next; // leak //directly remove and log LeakyBucket.Remove(prev); Logger.LogInfo(">> Logging the already finishsed when leaking, " + "sent at " + prev.Value.StartTime.Ticks); if (toBeLogged == null) { toBeLogged = new List <T>(); } toBeLogged.Add(prev.Value); LastLogTime = DateTime.Now; } else { BottomOfBucket = BottomOfBucket.Next; // leak only } nItemsInBucket -= 1; } // if bucket is full, ignore current request to realize down sampling if (nItemsInBucket >= Configue.BucketSize) { Logger.LogInfo("Ignored, too frequent, nItemsInBucket as " + nItemsInBucket); } else { // enqueue and track this request stopWatch = CreateStopWatch(Configue); var node = new LinkedListNode <T>(stopWatch); LeakyBucket.AddLast(node); LeakyBucketHash[stopWatch.StartTime] = node; // so to locate the stopWatch with O(1) when its response received and finish method invoked. nItemsInBucket += 1; Logger.LogInfo("Enqueued" + stopWatch.StartTime.Ticks + ", nItemsInBucket become " + nItemsInBucket); if (BottomOfBucket == null) { BottomOfBucket = node; } } } // move watcher's Log logic out of locked critical section in case any lengthy operation defined if (toBeLogged != null) { foreach (var watcher in toBeLogged) { watcher.Log(); } } return(stopWatch); }