FlowThrottle.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.ServiceModel.Dispatcher
  5. {
  6. using System;
  7. using System.Diagnostics;
  8. using System.ServiceModel.Channels;
  9. using System.ServiceModel.Diagnostics;
  10. using System.Collections.Generic;
  11. using System.Threading;
  12. using System.ServiceModel.Diagnostics.Application;
  13. sealed class FlowThrottle
  14. {
  15. int capacity;
  16. int count;
  17. bool warningIssued;
  18. int warningRestoreLimit;
  19. object mutex;
  20. WaitCallback release;
  21. Queue<object> waiters;
  22. String propertyName;
  23. String configName;
  24. Action acquired;
  25. Action released;
  26. Action<int> ratio;
  27. internal FlowThrottle(WaitCallback release, int capacity, String propertyName, String configName)
  28. {
  29. if (capacity <= 0)
  30. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxThrottleLimitMustBeGreaterThanZero0)));
  31. this.count = 0;
  32. this.capacity = capacity;
  33. this.mutex = new object();
  34. this.release = release;
  35. this.waiters = new Queue<object>();
  36. this.propertyName = propertyName;
  37. this.configName = configName;
  38. this.warningRestoreLimit = (int)Math.Floor(0.7 * (double)capacity);
  39. }
  40. internal int Capacity
  41. {
  42. get { return this.capacity; }
  43. set
  44. {
  45. if (value <= 0)
  46. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxThrottleLimitMustBeGreaterThanZero0)));
  47. this.capacity = value;
  48. }
  49. }
  50. internal bool Acquire(object o)
  51. {
  52. bool acquiredThrottle = true;
  53. lock (this.mutex)
  54. {
  55. if (this.count < this.capacity)
  56. {
  57. this.count++;
  58. }
  59. else
  60. {
  61. if (this.waiters.Count == 0)
  62. {
  63. if (TD.MessageThrottleExceededIsEnabled())
  64. {
  65. if (!this.warningIssued)
  66. {
  67. TD.MessageThrottleExceeded(this.propertyName, this.capacity);
  68. this.warningIssued = true;
  69. }
  70. }
  71. if (DiagnosticUtility.ShouldTraceWarning)
  72. {
  73. string traceMessage;
  74. if (this.propertyName != null)
  75. {
  76. traceMessage = SR.GetString(SR.TraceCodeServiceThrottleLimitReached,
  77. this.propertyName, this.capacity, this.configName);
  78. }
  79. else
  80. {
  81. traceMessage = SR.GetString(SR.TraceCodeServiceThrottleLimitReachedInternal,
  82. this.capacity);
  83. }
  84. TraceUtility.TraceEvent(
  85. TraceEventType.Warning, TraceCode.ServiceThrottleLimitReached, traceMessage);
  86. }
  87. }
  88. this.waiters.Enqueue(o);
  89. acquiredThrottle = false;
  90. }
  91. if (this.acquired != null)
  92. {
  93. this.acquired();
  94. }
  95. if (this.ratio != null)
  96. {
  97. this.ratio(this.count);
  98. }
  99. return acquiredThrottle;
  100. }
  101. }
  102. internal void Release()
  103. {
  104. object next = null;
  105. lock (this.mutex)
  106. {
  107. if (this.waiters.Count > 0)
  108. {
  109. next = this.waiters.Dequeue();
  110. if (this.waiters.Count == 0)
  111. this.waiters.TrimExcess();
  112. }
  113. else
  114. {
  115. this.count--;
  116. if (this.count < this.warningRestoreLimit)
  117. {
  118. if (TD.MessageThrottleAtSeventyPercentIsEnabled() && this.warningIssued)
  119. {
  120. TD.MessageThrottleAtSeventyPercent(this.propertyName, this.capacity);
  121. }
  122. this.warningIssued = false;
  123. }
  124. }
  125. }
  126. if (next != null)
  127. this.release(next);
  128. if (this.released != null)
  129. {
  130. this.released();
  131. }
  132. if (this.ratio != null)
  133. {
  134. this.ratio(this.count);
  135. }
  136. }
  137. internal void SetReleased(Action action)
  138. {
  139. this.released = action;
  140. }
  141. internal void SetAcquired(Action action)
  142. {
  143. this.acquired = action;
  144. }
  145. internal void SetRatio(Action<int> action)
  146. {
  147. this.ratio = action;
  148. }
  149. }
  150. }