J
J
Hi,
I've written a multi threaded application which scans about 2000
servers event logs to check for disk errors.
The problem with it is due to the fact that it just keeps eating
memory. In the end it's used up the best part of 100Mb, which I think
is excessive.
For each server it checks, it creates a new EventHelper object and
then executes a method which collects the data via a new thread. The
CheckEventLogs method rasies an event when it's completed and that
calls another method in the original code which writes the data to a
temp file.
Can anyone point me in the direction of what I'm doing wrong here and
the correct method for doing this?
Module1.vb #####################################################
Imports System.Threading
Module Module1
Dim RunningThreads As Integer = 0
Dim MaxThreads As Integer = 30
Sub Main()
RunProcess()
End Sub
Private Sub RunProcess()
If ServerList.Count = 0 Then End
Thread.CurrentThread.Name = "Main Thread"
Dim EventChecks(ServerList.Count - 1) As EventHelper
Dim t As Thread
For i As Integer = 0 To ServerList.Count - 1
EventChecks(i) = New EventHelper
EventChecks(i).ID = i
EventChecks(i).ServerName = ServerList(i)
AddHandler EventChecks(i).TaskCompleted, AddressOf
ProcessResults
t = New Thread(New ThreadStart(AddressOf
EventChecks(i).CheckEventLogs))
t.Name = String.Format("{0}", EventChecks(i).ID)
t.IsBackground = True
t.Start()
RunningThreads += 1
Do While RunningThreads >= MaxThreads + 1
Thread.Sleep(10000)
Loop
Next
Do Until RunningThreads = 0
Thread.Sleep(200)
Loop
End Sub
Private Function GetServerList() As ArrayList
Dim myList As New ArrayList
' Attains server list from source ....
Return myList
End Function
Private Sub ProcessResults(ByVal sender As Object)
RunningThreads -= 1
Dim Results As EventHelper = DirectCast(sender, EventHelper)
Dim id As String = Results.ID
Console.WriteLine("ThreadID {0} complete (Server: {1}).
Running processes: {2}. {3}", id, Results.ServerName, RunningThreads,
Results.ErrorMessage)
TempFileWriter.WriteTempFile(DirectCast(sender, EventHelper))
Results.Dispose()
Results = Nothing
sender = Nothing
End Sub
End Module
###############################################################
EventHelper.vb
Imports System.Management
Public Class EventHelper
Implements IDisposable
Event TaskCompleted(ByVal sender As Object)
Public ID As Integer = 0
Public ServerName As String = String.Empty
Public DaysToCheck As Double = 1.0
Public PhysicalDiskFail As Boolean = False
Public PredictiveDiskFail As Boolean = False
Public LogicalFail As Boolean = False
Public SANPathIssue As Boolean = False
Public BadBlock As Boolean = False
Public CorruptFilesystem As Boolean = False
Public BattteryFailure As Boolean = False
Public ErrorMessage As String = String.Empty
Public Sub New()
End Sub
Public Sub CheckEventLogs()
If Not ServerOnline(Me.ServerName) Then
ErrorMessage = String.Format("{0} - Server offline",
Me.ServerName)
RaiseEvent TaskCompleted(Me)
Exit Sub
End If
Me.ServerName = Me.ServerName.ToUpper.Trim
Dim EndDate As DateTime = Now
Dim StartDate As DateTime = DateAdd(DateInterval.Day, -
DaysToCheck, EndDate)
' Convert to WMI dates
Dim strEndDate As String = Year(EndDate) & Right("00" &
Month(EndDate), 2) & Right("00" & Day(EndDate), 2) & Right("00" &
Hour(Now), 2) & Right("00" & Minute(Now), 2) & "00.000000+060"
Dim strStartDate As String = Year(StartDate) & Right("00" &
Month(StartDate), 2) & Right("00" & Day(StartDate), 2) &
"000000.000000+060"
Dim SelectStatement As String = String.Format("Select * from
Win32_NTLogEvent Where TimeWritten >= '{0}' and TimeWritten < '{1}'
AND LogFile = 'system' and (SourceName = 'storage agents' OR
SourceName = 'CPQCISSE' OR SourceName = 'ntfs' OR SourceName =
'EmcpBase' OR SourceName = 'Disk') AND (EventType =1 OR EventType =
2)", strStartDate, strEndDate)
Dim Scope As ManagementScope
Dim Options As ConnectionOptions
Dim Query As ObjectQuery
Dim WMIInfo As ManagementObjectSearcher
Try
Scope = New ManagementScope
Options = New ConnectionOptions
Query = New ObjectQuery(SelectStatement)
WMIInfo = New ManagementObjectSearcher
With Options
.Impersonation = ImpersonationLevel.Impersonate
.Authentication = AuthenticationLevel.Packet
End With
Scope = New ManagementScope("\\" & Me.ServerName & "\root
\cimv2", Options)
Scope.Connect()
If Scope.IsConnected = False Then
Exit Sub
End If
WMIInfo.Scope = Scope
WMIInfo.Query = Query
For Each Info As ManagementObject In WMIInfo.Get
CheckForErrors(Info)
Next
Catch ex As Exception
ErrorMessage = String.Format("EventHelper: {0}",
ex.Message)
ErrorLogHelper.WriteError(String.Format("EventHelper:
{0}", ex.Message), Me.ServerName)
Finally
If Not IsNothing(WMIInfo) Then WMIInfo.Dispose()
RaiseEvent TaskCompleted(Me)
End Try
End Sub
Private Sub CheckForErrors(ByVal EventInfo As ManagementObject)
Dim EventCode As Int16 =
Convert.ToInt16(EventInfo("EventCode"))
Dim EventMsg As String = CStr(EventInfo("Message"))
Select Case EventCode
' Code removed for brevity
End Select
End Sub
Private Function ServerOnline(ByVal Server As String) As Boolean
Dim objStatus As ManagementObject
Dim objPing As New SelectQuery("Select StatusCode from
Win32_PingStatus WHERE Address = '" & Server & "' and statuscode = 0")
Dim Search As New ManagementObjectSearcher(objPing)
ServerOnline = (Search.Get.Count = 1)
objPing = Nothing
objStatus = Nothing
Search = Nothing
End Function
Public Overloads Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub ' Dispose
Protected Overridable Overloads Sub Dispose(ByVal disposing As
Boolean)
If disposing Then
ID = Nothing
ServerName = Nothing
DaysToCheck = Nothing
PhysicalDiskFail = Nothing
PredictiveDiskFail = Nothing
LogicalFail = Nothing
SANPathIssue = Nothing
BadBlock = Nothing
CorruptFilesystem = Nothing
BattteryFailure = Nothing
ErrorMessage = Nothing
End If
End Sub ' Dispose
End Class
I've written a multi threaded application which scans about 2000
servers event logs to check for disk errors.
The problem with it is due to the fact that it just keeps eating
memory. In the end it's used up the best part of 100Mb, which I think
is excessive.
For each server it checks, it creates a new EventHelper object and
then executes a method which collects the data via a new thread. The
CheckEventLogs method rasies an event when it's completed and that
calls another method in the original code which writes the data to a
temp file.
Can anyone point me in the direction of what I'm doing wrong here and
the correct method for doing this?
Module1.vb #####################################################
Imports System.Threading
Module Module1
Dim RunningThreads As Integer = 0
Dim MaxThreads As Integer = 30
Sub Main()
RunProcess()
End Sub
Private Sub RunProcess()
If ServerList.Count = 0 Then End
Thread.CurrentThread.Name = "Main Thread"
Dim EventChecks(ServerList.Count - 1) As EventHelper
Dim t As Thread
For i As Integer = 0 To ServerList.Count - 1
EventChecks(i) = New EventHelper
EventChecks(i).ID = i
EventChecks(i).ServerName = ServerList(i)
AddHandler EventChecks(i).TaskCompleted, AddressOf
ProcessResults
t = New Thread(New ThreadStart(AddressOf
EventChecks(i).CheckEventLogs))
t.Name = String.Format("{0}", EventChecks(i).ID)
t.IsBackground = True
t.Start()
RunningThreads += 1
Do While RunningThreads >= MaxThreads + 1
Thread.Sleep(10000)
Loop
Next
Do Until RunningThreads = 0
Thread.Sleep(200)
Loop
End Sub
Private Function GetServerList() As ArrayList
Dim myList As New ArrayList
' Attains server list from source ....
Return myList
End Function
Private Sub ProcessResults(ByVal sender As Object)
RunningThreads -= 1
Dim Results As EventHelper = DirectCast(sender, EventHelper)
Dim id As String = Results.ID
Console.WriteLine("ThreadID {0} complete (Server: {1}).
Running processes: {2}. {3}", id, Results.ServerName, RunningThreads,
Results.ErrorMessage)
TempFileWriter.WriteTempFile(DirectCast(sender, EventHelper))
Results.Dispose()
Results = Nothing
sender = Nothing
End Sub
End Module
###############################################################
EventHelper.vb
Imports System.Management
Public Class EventHelper
Implements IDisposable
Event TaskCompleted(ByVal sender As Object)
Public ID As Integer = 0
Public ServerName As String = String.Empty
Public DaysToCheck As Double = 1.0
Public PhysicalDiskFail As Boolean = False
Public PredictiveDiskFail As Boolean = False
Public LogicalFail As Boolean = False
Public SANPathIssue As Boolean = False
Public BadBlock As Boolean = False
Public CorruptFilesystem As Boolean = False
Public BattteryFailure As Boolean = False
Public ErrorMessage As String = String.Empty
Public Sub New()
End Sub
Public Sub CheckEventLogs()
If Not ServerOnline(Me.ServerName) Then
ErrorMessage = String.Format("{0} - Server offline",
Me.ServerName)
RaiseEvent TaskCompleted(Me)
Exit Sub
End If
Me.ServerName = Me.ServerName.ToUpper.Trim
Dim EndDate As DateTime = Now
Dim StartDate As DateTime = DateAdd(DateInterval.Day, -
DaysToCheck, EndDate)
' Convert to WMI dates
Dim strEndDate As String = Year(EndDate) & Right("00" &
Month(EndDate), 2) & Right("00" & Day(EndDate), 2) & Right("00" &
Hour(Now), 2) & Right("00" & Minute(Now), 2) & "00.000000+060"
Dim strStartDate As String = Year(StartDate) & Right("00" &
Month(StartDate), 2) & Right("00" & Day(StartDate), 2) &
"000000.000000+060"
Dim SelectStatement As String = String.Format("Select * from
Win32_NTLogEvent Where TimeWritten >= '{0}' and TimeWritten < '{1}'
AND LogFile = 'system' and (SourceName = 'storage agents' OR
SourceName = 'CPQCISSE' OR SourceName = 'ntfs' OR SourceName =
'EmcpBase' OR SourceName = 'Disk') AND (EventType =1 OR EventType =
2)", strStartDate, strEndDate)
Dim Scope As ManagementScope
Dim Options As ConnectionOptions
Dim Query As ObjectQuery
Dim WMIInfo As ManagementObjectSearcher
Try
Scope = New ManagementScope
Options = New ConnectionOptions
Query = New ObjectQuery(SelectStatement)
WMIInfo = New ManagementObjectSearcher
With Options
.Impersonation = ImpersonationLevel.Impersonate
.Authentication = AuthenticationLevel.Packet
End With
Scope = New ManagementScope("\\" & Me.ServerName & "\root
\cimv2", Options)
Scope.Connect()
If Scope.IsConnected = False Then
Exit Sub
End If
WMIInfo.Scope = Scope
WMIInfo.Query = Query
For Each Info As ManagementObject In WMIInfo.Get
CheckForErrors(Info)
Next
Catch ex As Exception
ErrorMessage = String.Format("EventHelper: {0}",
ex.Message)
ErrorLogHelper.WriteError(String.Format("EventHelper:
{0}", ex.Message), Me.ServerName)
Finally
If Not IsNothing(WMIInfo) Then WMIInfo.Dispose()
RaiseEvent TaskCompleted(Me)
End Try
End Sub
Private Sub CheckForErrors(ByVal EventInfo As ManagementObject)
Dim EventCode As Int16 =
Convert.ToInt16(EventInfo("EventCode"))
Dim EventMsg As String = CStr(EventInfo("Message"))
Select Case EventCode
' Code removed for brevity
End Select
End Sub
Private Function ServerOnline(ByVal Server As String) As Boolean
Dim objStatus As ManagementObject
Dim objPing As New SelectQuery("Select StatusCode from
Win32_PingStatus WHERE Address = '" & Server & "' and statuscode = 0")
Dim Search As New ManagementObjectSearcher(objPing)
ServerOnline = (Search.Get.Count = 1)
objPing = Nothing
objStatus = Nothing
Search = Nothing
End Function
Public Overloads Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub ' Dispose
Protected Overridable Overloads Sub Dispose(ByVal disposing As
Boolean)
If disposing Then
ID = Nothing
ServerName = Nothing
DaysToCheck = Nothing
PhysicalDiskFail = Nothing
PredictiveDiskFail = Nothing
LogicalFail = Nothing
SANPathIssue = Nothing
BadBlock = Nothing
CorruptFilesystem = Nothing
BattteryFailure = Nothing
ErrorMessage = Nothing
End If
End Sub ' Dispose
End Class