Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / System.Data / System / Data / ProviderBase / DbConnectionPoolCounters.cs
blobe0484c2f89be75de62e69eec362697bce7da40d3
1 //------------------------------------------------------------------------------
2 // <copyright file="DbConnectionPoolCounters.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
8 namespace System.Data.ProviderBase {
10 using System;
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) {
101 try {
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;
131 _instance = null;
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
136 //instance.Close();
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();
219 if (name != null) {
220 result = name.Name; // MDAC 73469
223 return result;
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
248 // prevent problems.
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),
264 insertString,
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));
271 return result;
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) {
296 counter.Dispose();
300 [PrePrepareMethod]
301 void ExceptionEventHandler (object sender, UnhandledExceptionEventArgs e) {
302 if ((null != e) && e.IsTerminating) {
303 Dispose();
307 [PrePrepareMethod]
308 void ExitEventHandler (object sender, EventArgs e) {
309 Dispose();
312 [PrePrepareMethod]
313 void UnloadEventHandler (object sender, EventArgs e) {
314 Dispose();
318 sealed internal class DbConnectionPoolCountersNoCounters : DbConnectionPoolCounters {
320 public static readonly DbConnectionPoolCountersNoCounters SingletonInstance = new DbConnectionPoolCountersNoCounters();
322 private DbConnectionPoolCountersNoCounters() : base () {