1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //-----------------------------------------------------------------------------
5 namespace System.ServiceModel.Dispatcher
9 using System.ServiceModel;
10 using System.ServiceModel.Diagnostics;
11 using System.ServiceModel.Diagnostics.Application;
13 interface ISessionThrottleNotification
15 void ThrottleAcquired();
18 public sealed class ServiceThrottle
20 internal const int DefaultMaxConcurrentCalls = 16;
21 internal const int DefaultMaxConcurrentSessions = 100;
22 internal static int DefaultMaxConcurrentCallsCpuCount = DefaultMaxConcurrentCalls * OSEnvironmentHelper.ProcessorCount;
23 internal static int DefaultMaxConcurrentSessionsCpuCount = DefaultMaxConcurrentSessions * OSEnvironmentHelper.ProcessorCount;
26 FlowThrottle sessions;
27 QuotaThrottle dynamic;
28 FlowThrottle instanceContexts;
31 ServicePerformanceCountersBase servicePerformanceCounters;
33 object thisLock = new object();
35 internal ServiceThrottle(ServiceHostBase host)
37 if (!((host != null)))
39 Fx.Assert("ServiceThrottle.ServiceThrottle: (host != null)");
40 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("host");
43 this.MaxConcurrentCalls = ServiceThrottle.DefaultMaxConcurrentCallsCpuCount;
44 this.MaxConcurrentSessions = ServiceThrottle.DefaultMaxConcurrentSessionsCpuCount;
55 if (this.calls == null)
57 this.calls = new FlowThrottle(this.GotCall, ServiceThrottle.DefaultMaxConcurrentCallsCpuCount,
58 ServiceThrottle.MaxConcurrentCallsPropertyName, ServiceThrottle.MaxConcurrentCallsConfigName);
59 this.calls.SetRatio(this.RatioCallsToken);
72 if (this.sessions == null)
74 this.sessions = new FlowThrottle(this.GotSession, ServiceThrottle.DefaultMaxConcurrentSessionsCpuCount,
75 ServiceThrottle.MaxConcurrentSessionsPropertyName, ServiceThrottle.MaxConcurrentSessionsConfigName);
76 this.sessions.SetRatio(this.RatioSessionsToken);
89 if (this.dynamic == null)
91 this.dynamic = new QuotaThrottle(this.GotDynamic, new object());
92 this.dynamic.Owner = "ServiceHost";
94 this.UpdateIsActive();
100 internal int ManualFlowControlLimit
102 get { return this.Dynamic.Limit; }
103 set { this.Dynamic.SetLimit(value); }
106 const string MaxConcurrentCallsPropertyName = "MaxConcurrentCalls";
107 const string MaxConcurrentCallsConfigName = "maxConcurrentCalls";
108 public int MaxConcurrentCalls
110 get { return this.Calls.Capacity; }
113 this.ThrowIfClosedOrOpened(MaxConcurrentCallsPropertyName);
114 this.Calls.Capacity = value;
115 this.UpdateIsActive();
116 if (null != this.servicePerformanceCounters)
118 this.servicePerformanceCounters.SetThrottleBase((int)ServicePerformanceCounters.PerfCounters.CallsPercentMaxCallsBase, this.Calls.Capacity);
123 const string MaxConcurrentSessionsPropertyName = "MaxConcurrentSessions";
124 const string MaxConcurrentSessionsConfigName = "maxConcurrentSessions";
125 public int MaxConcurrentSessions
127 get { return this.Sessions.Capacity; }
130 this.ThrowIfClosedOrOpened(MaxConcurrentSessionsPropertyName);
131 this.Sessions.Capacity = value;
132 this.UpdateIsActive();
133 if (null != this.servicePerformanceCounters)
135 this.servicePerformanceCounters.SetThrottleBase((int)ServicePerformanceCounters.PerfCounters.SessionsPercentMaxSessionsBase, this.Sessions.Capacity);
140 const string MaxConcurrentInstancesPropertyName = "MaxConcurrentInstances";
141 const string MaxConcurrentInstancesConfigName = "maxConcurrentInstances";
142 public int MaxConcurrentInstances
144 get { return this.InstanceContexts.Capacity; }
147 this.ThrowIfClosedOrOpened(MaxConcurrentInstancesPropertyName);
148 this.InstanceContexts.Capacity = value;
149 this.UpdateIsActive();
150 if (null != this.servicePerformanceCounters)
152 this.servicePerformanceCounters.SetThrottleBase((int)ServicePerformanceCounters.PerfCounters.InstancesPercentMaxInstancesBase, this.InstanceContexts.Capacity);
157 FlowThrottle InstanceContexts
163 if (this.instanceContexts == null)
165 this.instanceContexts = new FlowThrottle(this.GotInstanceContext, Int32.MaxValue,
166 ServiceThrottle.MaxConcurrentInstancesPropertyName, ServiceThrottle.MaxConcurrentInstancesConfigName);
167 this.instanceContexts.SetRatio(this.RatioInstancesToken);
168 if (this.servicePerformanceCounters != null)
170 InitializeInstancePerfCounterSettings();
173 return this.instanceContexts;
178 internal bool IsActive
180 get { return this.isActive; }
183 internal object ThisLock
185 get { return this.thisLock; }
188 internal void SetServicePerformanceCounters(ServicePerformanceCountersBase counters)
190 this.servicePerformanceCounters = counters;
191 //instance throttle is created through the behavior, set the perf counter callbacks if initialized
192 if (this.instanceContexts != null)
194 InitializeInstancePerfCounterSettings();
197 //this.calls and this.sessions throttles are created by the constructor. Set the perf counter callbacks
198 InitializeCallsPerfCounterSettings();
199 InitializeSessionsPerfCounterSettings();
202 void InitializeInstancePerfCounterSettings()
204 Fx.Assert(this.instanceContexts != null, "Expect instanceContext to be initialized");
205 Fx.Assert(this.servicePerformanceCounters != null, "expect servicePerformanceCounters to be set");
206 this.instanceContexts.SetAcquired(this.AcquiredInstancesToken);
207 this.instanceContexts.SetReleased(this.ReleasedInstancesToken);
208 this.instanceContexts.SetRatio(this.RatioInstancesToken);
209 this.servicePerformanceCounters.SetThrottleBase((int)ServicePerformanceCounters.PerfCounters.InstancesPercentMaxInstancesBase, this.instanceContexts.Capacity);
212 void InitializeCallsPerfCounterSettings()
214 Fx.Assert(this.calls != null, "Expect calls to be initialized");
215 Fx.Assert(this.servicePerformanceCounters != null, "expect servicePerformanceCounters to be set");
216 this.calls.SetAcquired(this.AcquiredCallsToken);
217 this.calls.SetReleased(this.ReleasedCallsToken);
218 this.calls.SetRatio(this.RatioCallsToken);
219 this.servicePerformanceCounters.SetThrottleBase((int)ServicePerformanceCounters.PerfCounters.CallsPercentMaxCallsBase, this.calls.Capacity);
222 void InitializeSessionsPerfCounterSettings()
224 Fx.Assert(this.sessions != null, "Expect sessions to be initialized");
225 Fx.Assert(this.servicePerformanceCounters != null, "expect servicePerformanceCounters to be set");
226 this.sessions.SetAcquired(this.AcquiredSessionsToken);
227 this.sessions.SetReleased(this.ReleasedSessionsToken);
228 this.sessions.SetRatio(this.RatioSessionsToken);
229 this.servicePerformanceCounters.SetThrottleBase((int)ServicePerformanceCounters.PerfCounters.SessionsPercentMaxSessionsBase, this.sessions.Capacity);
232 bool PrivateAcquireCall(ChannelHandler channel)
234 return (this.calls == null) || this.calls.Acquire(channel);
237 bool PrivateAcquireSessionListenerHandler(ListenerHandler listener)
239 if ((this.sessions != null) && (listener.Channel != null) && (listener.Channel.Throttle == null))
241 listener.Channel.Throttle = this;
242 return this.sessions.Acquire(listener);
250 bool PrivateAcquireSession(ISessionThrottleNotification source)
252 return (this.sessions == null || this.sessions.Acquire(source));
255 bool PrivateAcquireDynamic(ChannelHandler channel)
257 return (this.dynamic == null) || this.dynamic.Acquire(channel);
260 bool PrivateAcquireInstanceContext(ChannelHandler channel)
262 if ((this.instanceContexts != null) && (channel.InstanceContext == null))
264 channel.InstanceContextServiceThrottle = this;
265 return this.instanceContexts.Acquire(channel);
273 internal bool AcquireCall(ChannelHandler channel)
277 return (this.PrivateAcquireCall(channel));
281 internal bool AcquireInstanceContextAndDynamic(ChannelHandler channel, bool acquireInstanceContextThrottle)
285 if (!acquireInstanceContextThrottle)
287 return this.PrivateAcquireDynamic(channel);
291 return (this.PrivateAcquireInstanceContext(channel) &&
292 this.PrivateAcquireDynamic(channel));
297 internal bool AcquireSession(ISessionThrottleNotification source)
301 return this.PrivateAcquireSession(source);
305 internal bool AcquireSession(ListenerHandler listener)
309 return this.PrivateAcquireSessionListenerHandler(listener);
313 void GotCall(object state)
315 ChannelHandler channel = (ChannelHandler)state;
319 channel.ThrottleAcquiredForCall();
323 void GotDynamic(object state)
325 ((ChannelHandler)state).ThrottleAcquired();
328 void GotInstanceContext(object state)
330 ChannelHandler channel = (ChannelHandler)state;
334 if (this.PrivateAcquireDynamic(channel))
335 channel.ThrottleAcquired();
339 void GotSession(object state)
341 ((ISessionThrottleNotification)state).ThrottleAcquired();
344 internal void DeactivateChannel()
348 if (this.sessions != null)
349 this.sessions.Release();
353 internal void DeactivateCall()
357 if (this.calls != null)
358 this.calls.Release();
362 internal void DeactivateInstanceContext()
366 if (this.instanceContexts != null)
368 this.instanceContexts.Release();
373 internal int IncrementManualFlowControlLimit(int incrementBy)
375 return this.Dynamic.IncrementLimit(incrementBy);
378 void ThrowIfClosedOrOpened(string memberName)
380 if (this.host.State == CommunicationState.Opened)
382 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxImmutableThrottle1, memberName)));
386 this.host.ThrowIfClosedOrOpened();
390 void UpdateIsActive()
392 this.isActive = ((this.dynamic != null) ||
393 ((this.calls != null) && (this.calls.Capacity != Int32.MaxValue)) ||
394 ((this.sessions != null) && (this.sessions.Capacity != Int32.MaxValue)) ||
395 ((this.instanceContexts != null) && (this.instanceContexts.Capacity != Int32.MaxValue)));
398 internal void AcquiredCallsToken()
400 this.servicePerformanceCounters.IncrementThrottlePercent((int)ServicePerformanceCounters.PerfCounters.CallsPercentMaxCalls);
403 internal void ReleasedCallsToken()
405 this.servicePerformanceCounters.DecrementThrottlePercent((int)ServicePerformanceCounters.PerfCounters.CallsPercentMaxCalls);
408 internal void RatioCallsToken(int count)
410 if (TD.ConcurrentCallsRatioIsEnabled())
412 TD.ConcurrentCallsRatio(count, this.MaxConcurrentCalls);
416 internal void AcquiredInstancesToken()
418 this.servicePerformanceCounters.IncrementThrottlePercent((int)ServicePerformanceCounters.PerfCounters.InstancesPercentMaxInstances);
421 internal void ReleasedInstancesToken()
423 this.servicePerformanceCounters.DecrementThrottlePercent((int)ServicePerformanceCounters.PerfCounters.InstancesPercentMaxInstances);
426 internal void RatioInstancesToken(int count)
428 if (TD.ConcurrentInstancesRatioIsEnabled())
430 TD.ConcurrentInstancesRatio(count, this.MaxConcurrentInstances);
434 internal void AcquiredSessionsToken()
436 this.servicePerformanceCounters.IncrementThrottlePercent((int)ServicePerformanceCounters.PerfCounters.SessionsPercentMaxSessions);
439 internal void ReleasedSessionsToken()
441 this.servicePerformanceCounters.DecrementThrottlePercent((int)ServicePerformanceCounters.PerfCounters.SessionsPercentMaxSessions);
444 internal void RatioSessionsToken(int count)
446 if (TD.ConcurrentSessionsRatioIsEnabled())
448 TD.ConcurrentSessionsRatio(count, this.MaxConcurrentSessions);