1 //------------------------------------------------------------------------------
2 // <copyright file="DbConnectionPoolCounters.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
8 namespace System
.Data
.ProviderBase
{
11 using System
.Collections
;
12 using System
.Data
.Common
;
13 using System
.Diagnostics
;
14 using System
.Globalization
;
15 using System
.Reflection
;
16 using System
.Runtime
.ConstrainedExecution
;
17 using System
.Security
;
18 using System
.Security
.Permissions
;
19 using System
.Security
.Principal
;
20 using System
.Runtime
.Versioning
;
22 internal abstract class DbConnectionPoolCounters
{
23 private static class CreationData
{
25 static internal readonly CounterCreationData HardConnectsPerSecond
= new CounterCreationData(
26 "HardConnectsPerSecond",
27 "The number of actual connections per second that are being made to servers",
28 PerformanceCounterType
.RateOfCountsPerSecond32
);
30 static internal readonly CounterCreationData HardDisconnectsPerSecond
= new CounterCreationData(
31 "HardDisconnectsPerSecond",
32 "The number of actual disconnects per second that are being made to servers",
33 PerformanceCounterType
.RateOfCountsPerSecond32
);
35 static internal readonly CounterCreationData SoftConnectsPerSecond
= new CounterCreationData(
36 "SoftConnectsPerSecond",
37 "The number of connections we get from the pool per second",
38 PerformanceCounterType
.RateOfCountsPerSecond32
);
40 static internal readonly CounterCreationData SoftDisconnectsPerSecond
= new CounterCreationData(
41 "SoftDisconnectsPerSecond",
42 "The number of connections we return to the pool per second",
43 PerformanceCounterType
.RateOfCountsPerSecond32
);
45 static internal readonly CounterCreationData NumberOfNonPooledConnections
= new CounterCreationData(
46 "NumberOfNonPooledConnections",
47 "The number of connections that are not using connection pooling",
48 PerformanceCounterType
.NumberOfItems32
);
50 static internal readonly CounterCreationData NumberOfPooledConnections
= new CounterCreationData(
51 "NumberOfPooledConnections",
52 "The number of connections that are managed by the connection pooler",
53 PerformanceCounterType
.NumberOfItems32
);
55 static internal readonly CounterCreationData NumberOfActiveConnectionPoolGroups
= new CounterCreationData(
56 "NumberOfActiveConnectionPoolGroups",
57 "The number of unique connection strings",
58 PerformanceCounterType
.NumberOfItems32
);
60 static internal readonly CounterCreationData NumberOfInactiveConnectionPoolGroups
= new CounterCreationData(
61 "NumberOfInactiveConnectionPoolGroups",
62 "The number of unique connection strings waiting for pruning",
63 PerformanceCounterType
.NumberOfItems32
);
65 static internal readonly CounterCreationData NumberOfActiveConnectionPools
= new CounterCreationData(
66 "NumberOfActiveConnectionPools",
67 "The number of connection pools",
68 PerformanceCounterType
.NumberOfItems32
);
70 static internal readonly CounterCreationData NumberOfInactiveConnectionPools
= new CounterCreationData(
71 "NumberOfInactiveConnectionPools",
72 "The number of connection pools",
73 PerformanceCounterType
.NumberOfItems32
);
75 static internal readonly CounterCreationData NumberOfActiveConnections
= new CounterCreationData(
76 "NumberOfActiveConnections",
77 "The number of connections currently in-use",
78 PerformanceCounterType
.NumberOfItems32
);
80 static internal readonly CounterCreationData NumberOfFreeConnections
= new CounterCreationData(
81 "NumberOfFreeConnections",
82 "The number of connections currently available for use",
83 PerformanceCounterType
.NumberOfItems32
);
85 static internal readonly CounterCreationData NumberOfStasisConnections
= new CounterCreationData(
86 "NumberOfStasisConnections",
87 "The number of connections currently waiting to be made ready for use",
88 PerformanceCounterType
.NumberOfItems32
);
90 static internal readonly CounterCreationData NumberOfReclaimedConnections
= new CounterCreationData(
91 "NumberOfReclaimedConnections",
92 "The number of connections we reclaim from GC'd external connections",
93 PerformanceCounterType
.NumberOfItems32
);
96 sealed internal class Counter
{
97 private PerformanceCounter _instance
;
99 internal Counter (string categoryName
, string instanceName
, string counterName
, PerformanceCounterType counterType
) {
100 if (ADP
.IsPlatformNT5
) {
102 if (!ADP
.IsEmpty(categoryName
) && !ADP
.IsEmpty(instanceName
)) {
103 PerformanceCounter instance
= new PerformanceCounter();
104 instance
.CategoryName
= categoryName
;
105 instance
.CounterName
= counterName
;
106 instance
.InstanceName
= instanceName
;
107 instance
.InstanceLifetime
= PerformanceCounterInstanceLifetime
.Process
;
108 instance
.ReadOnly
= false;
109 instance
.RawValue
= 0; // make sure we start out at zero
110 _instance
= instance
;
113 catch (InvalidOperationException e
) {
114 ADP
.TraceExceptionWithoutRethrow(e
);
121 internal void Decrement() {
122 PerformanceCounter instance
= _instance
;
123 if (null != instance
) {
124 instance
.Decrement();
128 [ReliabilityContract(Consistency
.WillNotCorruptState
, Cer
.MayFail
)]
129 internal void Dispose () { //
130 PerformanceCounter instance
= _instance
;
132 if (null != instance
) {
133 instance
.RemoveInstance();
134 // should we be calling instance.Close?
135 // if we do will it exacerbate the Dispose vs. Decrement race condition
140 internal void Increment() {
141 PerformanceCounter instance
= _instance
;
142 if (null != instance
) {
143 instance
.Increment();
148 const int CounterInstanceNameMaxLength
= 127;
150 internal readonly Counter HardConnectsPerSecond
;
151 internal readonly Counter HardDisconnectsPerSecond
;
152 internal readonly Counter SoftConnectsPerSecond
;
153 internal readonly Counter SoftDisconnectsPerSecond
;
154 internal readonly Counter NumberOfNonPooledConnections
;
155 internal readonly Counter NumberOfPooledConnections
;
156 internal readonly Counter NumberOfActiveConnectionPoolGroups
;
157 internal readonly Counter NumberOfInactiveConnectionPoolGroups
;
158 internal readonly Counter NumberOfActiveConnectionPools
;
159 internal readonly Counter NumberOfInactiveConnectionPools
;
160 internal readonly Counter NumberOfActiveConnections
;
161 internal readonly Counter NumberOfFreeConnections
;
162 internal readonly Counter NumberOfStasisConnections
;
163 internal readonly Counter NumberOfReclaimedConnections
;
165 protected DbConnectionPoolCounters() : this(null, null) {
168 protected DbConnectionPoolCounters(string categoryName
, string categoryHelp
) {
169 AppDomain
.CurrentDomain
.DomainUnload
+= new EventHandler(this.UnloadEventHandler
);
170 AppDomain
.CurrentDomain
.ProcessExit
+= new EventHandler(this.ExitEventHandler
);
171 AppDomain
.CurrentDomain
.UnhandledException
+= new UnhandledExceptionEventHandler(this.ExceptionEventHandler
);
173 string instanceName
= null;
175 if (!ADP
.IsEmpty(categoryName
)) {
176 if (ADP
.IsPlatformNT5
) {
177 instanceName
= GetInstanceName();
181 // level 0-3: hard connects/disconnects, plus basic pool/pool entry statistics
182 string basicCategoryName
= categoryName
;
183 HardConnectsPerSecond
= new Counter(basicCategoryName
, instanceName
, CreationData
.HardConnectsPerSecond
.CounterName
, CreationData
.HardConnectsPerSecond
.CounterType
);
184 HardDisconnectsPerSecond
= new Counter(basicCategoryName
, instanceName
, CreationData
.HardDisconnectsPerSecond
.CounterName
, CreationData
.HardDisconnectsPerSecond
.CounterType
);
185 NumberOfNonPooledConnections
= new Counter(basicCategoryName
, instanceName
, CreationData
.NumberOfNonPooledConnections
.CounterName
, CreationData
.NumberOfNonPooledConnections
.CounterType
);
186 NumberOfPooledConnections
= new Counter(basicCategoryName
, instanceName
, CreationData
.NumberOfPooledConnections
.CounterName
, CreationData
.NumberOfPooledConnections
.CounterType
);
187 NumberOfActiveConnectionPoolGroups
= new Counter(basicCategoryName
, instanceName
, CreationData
.NumberOfActiveConnectionPoolGroups
.CounterName
, CreationData
.NumberOfActiveConnectionPoolGroups
.CounterType
);
188 NumberOfInactiveConnectionPoolGroups
= new Counter(basicCategoryName
, instanceName
, CreationData
.NumberOfInactiveConnectionPoolGroups
.CounterName
, CreationData
.NumberOfInactiveConnectionPoolGroups
.CounterType
);
189 NumberOfActiveConnectionPools
= new Counter(basicCategoryName
, instanceName
, CreationData
.NumberOfActiveConnectionPools
.CounterName
, CreationData
.NumberOfActiveConnectionPools
.CounterType
);
190 NumberOfInactiveConnectionPools
= new Counter(basicCategoryName
, instanceName
, CreationData
.NumberOfInactiveConnectionPools
.CounterName
, CreationData
.NumberOfInactiveConnectionPools
.CounterType
);
191 NumberOfStasisConnections
= new Counter(basicCategoryName
, instanceName
, CreationData
.NumberOfStasisConnections
.CounterName
, CreationData
.NumberOfStasisConnections
.CounterType
);
192 NumberOfReclaimedConnections
= new Counter(basicCategoryName
, instanceName
, CreationData
.NumberOfReclaimedConnections
.CounterName
, CreationData
.NumberOfReclaimedConnections
.CounterType
);
194 // level 4: expensive stuff
195 string verboseCategoryName
= null;
196 if (!ADP
.IsEmpty(categoryName
)) {
197 // don't load TraceSwitch if no categoryName so that Odbc/OleDb have a chance of not loading TraceSwitch
198 // which are also used by System.Diagnostics.PerformanceCounter.ctor & System.Transactions.get_Current
199 TraceSwitch perfCtrSwitch
= new TraceSwitch("ConnectionPoolPerformanceCounterDetail", "level of detail to track with connection pool performance counters");
200 if (TraceLevel
.Verbose
== perfCtrSwitch
.Level
) {
201 verboseCategoryName
= categoryName
;
204 SoftConnectsPerSecond
= new Counter(verboseCategoryName
, instanceName
, CreationData
.SoftConnectsPerSecond
.CounterName
, CreationData
.SoftConnectsPerSecond
.CounterType
);
205 SoftDisconnectsPerSecond
= new Counter(verboseCategoryName
, instanceName
, CreationData
.SoftDisconnectsPerSecond
.CounterName
, CreationData
.SoftDisconnectsPerSecond
.CounterType
);
206 NumberOfActiveConnections
= new Counter(verboseCategoryName
, instanceName
, CreationData
.NumberOfActiveConnections
.CounterName
, CreationData
.NumberOfActiveConnections
.CounterType
);
207 NumberOfFreeConnections
= new Counter(verboseCategoryName
, instanceName
, CreationData
.NumberOfFreeConnections
.CounterName
, CreationData
.NumberOfFreeConnections
.CounterType
);
210 [FileIOPermission(SecurityAction
.Assert
, Unrestricted
=true)]
211 private string GetAssemblyName() {
212 string result
= null;
214 // First try GetEntryAssembly name, then AppDomain.FriendlyName.
215 Assembly assembly
= Assembly
.GetEntryAssembly();
217 if (null != assembly
) {
218 AssemblyName name
= assembly
.GetName();
220 result
= name
.Name
; // MDAC 73469
226 // SxS: this method uses GetCurrentProcessId to construct the instance name.
228 [ResourceExposure(ResourceScope
.None
)]
229 [ResourceConsumption(ResourceScope
.Process
, ResourceScope
.Process
)]
230 private string GetInstanceName() {
231 string result
= null;
233 string instanceName
= GetAssemblyName(); // instance perfcounter name
235 if (ADP
.IsEmpty(instanceName
)) {
236 AppDomain appDomain
= AppDomain
.CurrentDomain
;
237 if (null != appDomain
) {
238 instanceName
= appDomain
.FriendlyName
;
243 int pid
= SafeNativeMethods
.GetCurrentProcessId();
246 // SQLBUDT #366157 -there are several characters which have special meaning
247 // to PERFMON. They recommend that we translate them as shown below, to
250 result
= String
.Format((IFormatProvider
)null, "{0}[{1}]", instanceName
, pid
);
251 result
= result
.Replace('(','[').Replace(')',']').Replace('#','_').Replace('/','_').Replace('\\','_');
253 // SQLBUVSTS #94625 - counter instance name cannot be greater than 127
254 if (result
.Length
> CounterInstanceNameMaxLength
) {
255 // Replacing the middle part with "[...]"
256 // For example: if path is c:\long_path\very_(Ax200)_long__path\perftest.exe and process ID is 1234 than the resulted instance name will be:
257 // c:\long_path\very_(AxM)[...](AxN)_long__path\perftest.exe[1234]
258 // while M and N are adjusted to make each part before and after the [...] = 61 (making the total = 61 + 5 + 61 = 127)
259 const string insertString
= "[...]";
260 int firstPartLength
= (CounterInstanceNameMaxLength
- insertString
.Length
) / 2;
261 int lastPartLength
= CounterInstanceNameMaxLength
- firstPartLength
- insertString
.Length
;
262 result
= string.Format((IFormatProvider
)null, "{0}{1}{2}",
263 result
.Substring(0, firstPartLength
),
265 result
.Substring(result
.Length
- lastPartLength
, lastPartLength
));
267 Debug
.Assert(result
.Length
== CounterInstanceNameMaxLength
,
268 string.Format((IFormatProvider
)null, "wrong calculation of the instance name: expected {0}, actual: {1}", CounterInstanceNameMaxLength
, result
.Length
));
274 [ReliabilityContract(Consistency
.WillNotCorruptState
, Cer
.MayFail
)]
275 public void Dispose() {
276 // ExceptionEventHandler with IsTerminiating may be called before
277 // the Connection Close is called or the variables are initialized
278 SafeDispose(HardConnectsPerSecond
);
279 SafeDispose(HardDisconnectsPerSecond
);
280 SafeDispose(SoftConnectsPerSecond
);
281 SafeDispose(SoftDisconnectsPerSecond
);
282 SafeDispose(NumberOfNonPooledConnections
);
283 SafeDispose(NumberOfPooledConnections
);
284 SafeDispose(NumberOfActiveConnectionPoolGroups
);
285 SafeDispose(NumberOfInactiveConnectionPoolGroups
);
286 SafeDispose(NumberOfActiveConnectionPools
);
287 SafeDispose(NumberOfActiveConnections
);
288 SafeDispose(NumberOfFreeConnections
);
289 SafeDispose(NumberOfStasisConnections
);
290 SafeDispose(NumberOfReclaimedConnections
);
293 [ReliabilityContract(Consistency
.WillNotCorruptState
, Cer
.MayFail
)]
294 private void SafeDispose(Counter counter
) { // WebData 103603
295 if (null != counter
) {
301 void ExceptionEventHandler (object sender
, UnhandledExceptionEventArgs e
) {
302 if ((null != e
) && e
.IsTerminating
) {
308 void ExitEventHandler (object sender
, EventArgs e
) {
313 void UnloadEventHandler (object sender
, EventArgs e
) {
318 sealed internal class DbConnectionPoolCountersNoCounters
: DbConnectionPoolCounters
{
320 public static readonly DbConnectionPoolCountersNoCounters SingletonInstance
= new DbConnectionPoolCountersNoCounters();
322 private DbConnectionPoolCountersNoCounters() : base () {