PerformanceCountersBase.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.ServiceModel.Diagnostics
  5. {
  6. using System.Collections.Generic;
  7. using System.Diagnostics;
  8. using System.Diagnostics.PerformanceData;
  9. using System.Globalization;
  10. using System.Runtime;
  11. using System.Threading;
  12. using System.Linq;
  13. abstract class PerformanceCountersBase : IDisposable
  14. {
  15. internal abstract string InstanceName
  16. {
  17. get;
  18. }
  19. internal abstract string[] CounterNames
  20. {
  21. get;
  22. }
  23. internal abstract int PerfCounterStart
  24. {
  25. get;
  26. }
  27. internal abstract int PerfCounterEnd
  28. {
  29. get;
  30. }
  31. // remove count chars from string and add a 2 char hash code to beginning or end, as specified.
  32. protected static string GetHashedString(string str, int startIndex, int count, bool hashAtEnd)
  33. {
  34. string returnVal = str.Remove(startIndex, count);
  35. string hash = ((uint)str.GetHashCode() % 99).ToString("00", CultureInfo.InvariantCulture);
  36. return hashAtEnd ? returnVal + hash : hash + returnVal;
  37. }
  38. internal abstract bool Initialized { get; }
  39. protected int disposed = 0;
  40. public void Dispose()
  41. {
  42. if (Interlocked.Exchange(ref disposed, 1) == 0)
  43. {
  44. Dispose(true);
  45. }
  46. }
  47. protected virtual void Dispose(bool disposing)
  48. {
  49. }
  50. // A CounterSetInstance is not disposed immediately when a service, endpoint or operation perf counter is disposed. Because messages
  51. // can be processed while a ServiceHost is being closed, and such messages can try to update perf counters data, resulting in AVs or
  52. // corruptions (see bug 249132 @ CSDMain). So instead of disposing a CounterSetInstance, we hold a WeakReference to it, until either
  53. // GC reclaims it or a new service/endpoint/operation perf counter is started with the same name (and re-uses the CounterSetInstance).
  54. // The CounterSetInstance finalizer will free up the perf counters memory, so we don't have a leak.
  55. protected class CounterSetInstanceCache
  56. {
  57. // instance name -> WeakReference of CounterSetInstance
  58. private readonly Dictionary<string, WeakReference> cache = new Dictionary<string, WeakReference>();
  59. /// <summary>
  60. /// Returns and removes the CounterSetInstance with the specified name from the cache. Returns null if not found.
  61. /// </summary>
  62. internal CounterSetInstance Get(string instanceName)
  63. {
  64. Fx.Assert(instanceName != null, "Invalid argument.");
  65. lock (this.cache)
  66. {
  67. WeakReference wr;
  68. if (this.cache.TryGetValue(instanceName, out wr))
  69. {
  70. Fx.Assert(wr != null, "The values in 'availableCounterSetInstances' should not be null.");
  71. this.cache.Remove(instanceName);
  72. return (CounterSetInstance)wr.Target;
  73. }
  74. else
  75. {
  76. return null;
  77. }
  78. }
  79. }
  80. /// <summary>
  81. /// Adds a CounterSetInstance to the cache, from where it will be garbage collected or re-used by another performance counter (whichever occurs first).
  82. /// </summary>
  83. internal void Add(string instanceName, CounterSetInstance instance)
  84. {
  85. Fx.Assert(instanceName != null, "Invalid argument.");
  86. Fx.Assert(instance != null, "Invalid argument.");
  87. lock (this.cache)
  88. {
  89. this.cache[instanceName] = new WeakReference(instance);
  90. }
  91. }
  92. /// <summary>
  93. /// Clear the entries for CounterSetInstances that were garbage collected.
  94. /// </summary>
  95. internal void Cleanup()
  96. {
  97. lock (this.cache)
  98. {
  99. foreach (var entry in this.cache.Where(pair => !pair.Value.IsAlive).ToList())
  100. {
  101. this.cache.Remove(entry.Key);
  102. }
  103. }
  104. }
  105. }
  106. }
  107. }