|
dev
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Problem of refresh with PerformanceCounter and failover.This service checks nearly 250 another servers to log statisticals data acquired via WMI, SNMP, PerformanceCounter... We use XOsoft for the fail over of our SQL Server databases (active, passive but the clients are always using the same name to connect to the elected active server) but we always have problems when the active server change because the PerformanceCounter objects use a cache located to the class PerformanceCounterLib internal to the .NET framework. This cache contains the categories available for each server name. Because the servers are not identical, the categories of a server cannot be reused for the other one and we catch these exceptions after a fail over. [2006/06/21 13:05:16.1935] Pdh Failed for xxx..bvdep.net System.InvalidOperationException: Could not Read Category Index: 3616. at System.Diagnostics.CategorySample..ctor(Byte[] data, CategoryEntry entry, PerformanceCounterLib library) at System.Diagnostics.PerformanceCounterLib.GetCategorySample(String category) at System.Diagnostics.PerformanceCounterLib.GetCategorySample(String machine, String category) at System.Diagnostics.PerformanceCounter.NextSample() at ServerPatrol.Agent.Components.Specialized.Pdh.Invoke(ResultPipeline results, TargetDTO target, String& resultDescription) It exists the method PerformanceCounter.CloseSharedResources() that clears the cache but for all servers which is not interesting for us because we have all the time between 1.000 and 3.000 open performance counters dispatched to ~250 servers. I'm not even sure it's possible because the service is always running between 10 and 60 threads at the same time and the implementation of CloseSharedResources doesn't seem to be thread safe. Is there any tricks to correct this kind of problem? I have two solutions but I prefer not to use them until a better one. 1. Put the PerformanceCounters associated to a server in a dedicated application domain. That way, I can call CloseSharedResources without loosing the data of the other servers. I don't like this solution because: - I don't want to manage the lifetime of my objects between the application domain - I don't want an application with ~250 application domains. - Debugging is harder. 2. Directly removing the concerned cached entries via reflection (because the class is internal). I used Reflector to write the following code but I don't like this solution because the internal implementation could change between different version of the .NET Framework. System.Reflection.Assembly assembly = System.Reflection.Assembly.GetAssembly(typeof(PerformanceCounter)); Type type = assembly.GetType("System.Diagnostics.PerformanceCounterLib"); System.Reflection.FieldInfo fi = type.GetField( "libraryTable", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic); Hashtable dictionary = fi.GetValue(null) as Hashtable; if (null == dictionary) return; System.Globalization.CultureInfo culture = new System.Globalization.CultureInfo(9); string key = server.ToLower(System.Globalization.CultureInfo.InvariantCulture) + ":" + culture.LCID.ToString("X3", System.Globalization.CultureInfo.InvariantCulture); object o = dictionary[key]; if (null != o) { System.Reflection.MethodInfo mi = o.GetType().GetMethod("Close", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); mi.Invoke(o, new object[0]); dictionary.Remove(key); } Thanks in advance. Lionel Schiepers (ls at bvdep.com), Bureau van Dijk Electronic Publishing Belgium. I forgot to mention that I recreate the performance counter when I catch an
exception. Lionel Schiepers Show quote "Lionel Schiepers" <l*@bvdep.com> wrote in message news:u6mAobSlGHA.1664@TK2MSFTNGP03.phx.gbl... > We have a multithreaded service written in .NET 2.0 that is running > 24h/24. This service checks nearly 250 another servers to log statisticals > data acquired via WMI, SNMP, PerformanceCounter... > > We use XOsoft for the fail over of our SQL Server databases (active, > passive but the clients are always using the same name to connect to the > elected active server) but we always have problems when the active server > change because the PerformanceCounter objects use a cache located to the > class PerformanceCounterLib internal to the .NET framework. This cache > contains the categories available for each server name. Because the > servers are not identical, the categories of a server cannot be reused for > the other one and we catch these exceptions after a fail over. > > [2006/06/21 13:05:16.1935] Pdh Failed for xxx..bvdep.net > System.InvalidOperationException: Could not Read Category Index: 3616. > at System.Diagnostics.CategorySample..ctor(Byte[] data, CategoryEntry > entry, PerformanceCounterLib library) > at System.Diagnostics.PerformanceCounterLib.GetCategorySample(String > category) > at System.Diagnostics.PerformanceCounterLib.GetCategorySample(String > machine, String category) > at System.Diagnostics.PerformanceCounter.NextSample() > at ServerPatrol.Agent.Components.Specialized.Pdh.Invoke(ResultPipeline > results, TargetDTO target, String& resultDescription) > > > It exists the method PerformanceCounter.CloseSharedResources() that clears > the cache but for all servers which is not interesting for us because we > have all the time between 1.000 and 3.000 open performance counters > dispatched to ~250 servers. I'm not even sure it's possible because the > service is always running between 10 and 60 threads at the same time and > the implementation of CloseSharedResources doesn't seem to be thread safe. > > Is there any tricks to correct this kind of problem? > > I have two solutions but I prefer not to use them until a better one. > > > 1. Put the PerformanceCounters associated to a server in a dedicated > application domain. That way, I can call CloseSharedResources without > loosing the data of the other servers. I don't like this solution because: > - I don't want to manage the lifetime of my objects between the > application domain > - I don't want an application with ~250 application domains. > - Debugging is harder. > > 2. Directly removing the concerned cached entries via reflection (because > the class is internal). I used Reflector to write the following code but I > don't like this solution because the internal implementation could change > between different version of the .NET Framework. > > System.Reflection.Assembly assembly = > System.Reflection.Assembly.GetAssembly(typeof(PerformanceCounter)); > Type type = > assembly.GetType("System.Diagnostics.PerformanceCounterLib"); > System.Reflection.FieldInfo fi = type.GetField( > "libraryTable", > System.Reflection.BindingFlags.Static | > System.Reflection.BindingFlags.NonPublic); > > Hashtable dictionary = fi.GetValue(null) as Hashtable; > if (null == dictionary) > return; > System.Globalization.CultureInfo culture = new > System.Globalization.CultureInfo(9); > string key = > server.ToLower(System.Globalization.CultureInfo.InvariantCulture) + ":" + > culture.LCID.ToString("X3", > System.Globalization.CultureInfo.InvariantCulture); > object o = dictionary[key]; > if (null != o) > { > System.Reflection.MethodInfo mi = o.GetType().GetMethod("Close", > System.Reflection.BindingFlags.Instance | > System.Reflection.BindingFlags.NonPublic); > mi.Invoke(o, new object[0]); > dictionary.Remove(key); > } > > Thanks in advance. > > Lionel Schiepers (ls at bvdep.com), > Bureau van Dijk Electronic Publishing > Belgium. > > |
|||||||||||||||||||||||