This scheduled agent is bring the server down to its' knees

This scheduled agent runs on person docs.

For each person doc, it looks at the user activity log of that person’s mail file and writes the date that that person (s’ user id) accessed their mail file to a specified filename on the servers’ hard drive.

It will go through anywhere between 100 and 200 person docs (depending on server, I’ve run this on more than one) and then bring down the server leaving no “last words” in the log.nsf

anyone mind giving this a once-over in case you see something that can be corrected?

thks,

-MC

Option Public

Option Explicit

Use “CLASSUserActivity”

Sub Initialize

Dim ua As NotesUserActivity

Dim uae As NotesUserActivityEntry

Dim iCounter As Long

Dim filenum As Integer, test As Integer, lenname As Integer



Dim hwnd As Long

Dim i As Long

Dim j As Long

Dim dbsize As Notesdatabase

'Dim uiw As New NotesUIWorkspace 

'Dim uidoc As NotesUIDocument

Dim sess As New NotesSession, session As New NotesSession, s As New NotesSession

Dim coll As notesdocumentcollection

Dim db As New notesdatabase("", "") 

Dim newDoc As Notesdocument, doc1 As Notesdocument, doc2 As Notesdocument, docA As Notesdocument, docB As Notesdocument

Dim names As NotesDatabase

Dim longname As String

Dim db1 As New notesdatabase("","")    

fileNum% = Freefile()



Set db = sess.currentdatabase

Set coll = db.unprocesseddocuments

Set docA = coll.getfirstdocument

Set docB = docA

’ Dim boxType As Long, answer As Integer

’ boxType& = 36

’ answer% = Messagebox(“Do you want to continue?”, boxType&, _

’ “Continue?”)

’ If (answer%=7) Then

’ Exit Sub

’ End If

Open "d:\export\WhenMailFileLastAccessed.xls" For Output As fileNum%

While Not (docB Is Nothing)

	test=0

	'Print  #filenum%, + Now()+ " Mail Activity for :"+ docB.MailFile(0) + ".nsf : " + docB.MailServer(0)

	

	'On Error Goto Errortrap          

	On Error Resume Next

	Set db1 = s.GetDatabase(docB.MailServer(0),docB.MailFile(0) )

	If Not db1.IsOpen Then 

		'Call docB.replaceitemvalue ("LastAccess", "No DB")     

		'Call docB.save(True,True)

		Print  #filenum%, + Now()+ " Error opening file :"+ docB.MailServer(0) + docB.MailFile(0) + ".nsf : "

		Goto ResumeNext

	End If

	If Not db1 Is Nothing Then

		Set ua = New NotesUserActivity(db1)

		If docB.MiddleInitial(0)="" Then 

			longname=docB.Firstname(0) +" " + docB.LastName(0)

		Else

			longname=docB.Firstname(0) + " " + docB.MiddleInitial(0) + " " + docB.Lastname(0)

		End If

		If docB.Firstname(0)="" Then

			longname=docB.LastName(0)

		End If

		For iCounter = 1 To ua.UserActivityCount

			Set uae = ua.GetNthUserActivityEntry(iCounter)

			lenname=Len(longname)

			If (Left$( uae.Username, lenname)=Left$(longname$,lenname) )Then  

				If test=0 Then

					Print #filenum%, uae.Time  + " " + uae.Username + " Last Accessed"

					test=1

’ Call docB.replaceitemvalue (“FirstAccess”, ua.First)

’ Call docB.replaceitemvalue (“LastAccess”, uae.Time)

’ Call docB.replaceitemvalue (“DSTProc”, “Yes”)

’ Call docB.save(True,True)

				End If 

			End If

			If  (Mid$( uae.Username, 4,lenname)=Left$(longname$,lenname) )Then  

				If test=0 Then

					'Print #filenum%, "Last Accessed:"+ uae.Time +"  " + uae.Username      + " "    

					Print #filenum%, uae.Time  + " " + uae.Username + " Last Accessed"

					test=1

’ Call docB.replaceitemvalue (“FirstAccess”, ua.First)

’ Call docB.replaceitemvalue (“LastAccess”, uae.Time)

’ Call docB.replaceitemvalue (“DSTProc”, “Yes”)

’ Call docB.save(True,True)

				End If 

			End If

			

			

               ' Print #filenum%,"(" + Cstr(iCounter) + ") " + uae.Time + " " + uae.UserName + " " + "Reads:" + Cstr(uae.Reads) + " Writes:" + Cstr(uae.Writes)

			

		Next iCounter

		If test=0 Then

			Print #filenum%, ua.First +"  " + uae.Username + " for person: "  + longname + "(No Activity since)"

’ Call docB.replaceitemvalue (“FirstAccess”, ua.First)

’ Call docB.replaceitemvalue (“LastAccess”, “No Activity”)

’ Call docB.save(True,True)

		End If

	End If

ResumeNext:

	Call db1.close

	

	Set docB = coll.getnextdocument(docA) 

	Set docA = docB

	

Wend

Close filenum%

Exit Sub

'Errortrap:

’ Print #filenum%,“Error opening mail file: " + docB.Firstname(0) +” " + docB.LastName(0) +“:” + + docB.MailFile(0) + ".nsf : " + docB.MailServer(0)

End Sub

CLASSUserActivity - Script Library


Option Public

Option Explicit

Const MAXALPHATIMEDATE = 80

Type TIMEDATE

Innard1 As Long

Innard2 As Long

End Type

Type DBACTIVITY

First As TIMEDATE

Last As TIMEDATE

Uses As Long

Reads As Long

Writes As Long

PrevDayUses As Long

PrevDayReads As Long

PrevDayWrites As Long

PrevWeekUses As Long

PrevWeekReads As Long

PrevWeekWrites As Long

PrevMonthUses As Long

PrevMonthReads As Long

PrevMonthWrites As Long

End Type

Type DBACTIVITY_ENTRY

Time As TIMEDATE

Reads As Integer

Writes As Integer

UserNameOffset As Long

End Type

Declare Function W32_NSFDbOpen Lib “nnotes.dll” Alias “NSFDbOpen” ( Byval dbName As String, hDb As Long) As Integer

Declare Function W32_NSFDbClose Lib “nnotes.dll” Alias “NSFDbClose” ( Byval hDb As Long) As Integer

Declare Function W32_NSFDbGetUserActivity Lib “nnotes.dll” Alias “NSFDbGetUserActivity” ( Byval hDB As Long, Byval flags As Long, retDbActivity As DBActivity, rethUserInfo As Long, retUserCount As Long) As Integer

Declare Function W32_OSLockObject Lib “nnotes.dll” Alias “OSLockObject” ( Byval handle) As Long

Declare Sub OSUnlockObject Lib “NNOTES.DLL” Alias “OSUnlockObject” (Byval handle)

Declare Sub W32_OSMemFree Lib “NNOTES.DLL” Alias “OSMemFree” (Byval handle)

Declare Sub CopyMemory Lib “KERNEL32” Alias “RtlMoveMemory” ( hpvDest As Any, Byval hpvSource As Long, Byval cbCopy As Long)

Declare Sub CopyMemoryString Lib “KERNEL32” Alias “RtlMoveMemory” ( Byval hpvDest As String, Byval hpvSource As Long, Byval cbCopy As Long)

Declare Sub ConvertTIMEDATEToText Lib “NNOTES.DLL” Alias “ConvertTIMEDATEToText” (Byval IntlFormat As Long,Byval TextFormat As Long, actTIMEDATE As TIMEDATE, Byval retTextBuffer As String,Byval TextBufferLength As Integer,retTextLength As Integer)

Class NotesUserActivityEntry

Public UserName As String

Public Reads As Long

Public Writes As Long

Public Time As String

End Class

Class NotesUserActivity

Private hDb As Long

Private pDbActivity As DBACTIVITY

Private rethUserInfo As Long

Private retUserCount As Long

Private prvdb As NotesDatabase

Private flgHasActivity As Integer



Sub Delete

	If Me.flgHasActivity Then Call W32_OSMemFree(rethUserInfo)

	If hDb <> 0 Then Call W32_NSFDbClose(hDb)   

End Sub



Sub New (inpNotesDatabase As NotesDatabase)

	

	Dim sDatabase As String

	Dim rc As Integer     

	

	Me.flgHasActivity = False

	

      'Get a valid NotesDatabase to the specified database         

	If inpNotesDatabase Is Nothing Then 

		Error 14101, "NotesUserActivity: Database Object is invalid"

		Exit Sub

	End If

	

	Set prvdb = New NotesDatabase(inpNotesDatabase.Server, inpNotesDatabase.FilePath)

	

	If prvdb.Server = "" Then

		sdatabase = prvdb.filepath

	Else

		sdatabase = prvdb.server + "!!" + prvdb.filepath

	End If

	

      'Open the target database

	rc = W32_NSFDbOpen(sDatabase,Me.hDb)

	If rc <> 0 Then

		Me.flgHasActivity = False

	End If

	

      'Get the Summary User information

	rc = W32_NSFDbGetUserActivity(Me.hDb, &h0, Me.pDbActivity, Me.rethUserInfo, Me.retUserCount)

	If rc <> 0 Then

		Me.flgHasActivity = False

	End If      

	Me.flgHasActivity = True

End Sub 



 'Global Times

Public Function First As String

	First = ConvertTIMEtoText(pDbActivity.First)     

End Function

Public Function Last As String

	Last = ConvertTIMEtoText(pDbActivity.Last)     

End Function



 'Total summary

Public Function Uses As Long

	Uses = pDbActivity.Uses  

End Function

Public Function Reads As Long

	Reads = pDbActivity.Reads          

End Function

Public Function Writes As Long

	Writes = pDbActivity.Writes

End Function



 'Day summary

Public Function PrevDayUses As Long

	PrevDayUses = pDbActivity.PrevDayUses     

End Function

Public Function PrevDayReads As Long

	PrevDayReads = pDbActivity.PrevDayReads     

End Function

Public Function PrevDayWrites As Long

	PrevDayWrites = pDbActivity.PrevDayReads

End Function



 'Week summary

Public Function PrevWeekUses As Long

	PrevWeekUses = pDbActivity.PrevWeekUses          

End Function

Public Function PrevWeekReads As Long

	PrevWeekReads = pDbActivity.PrevWeekReads

End Function

Public Function PrevWeekWrites As Long

	PrevWeekWrites= pDbActivity.PrevWeekWrites

End Function



 'Month summary

Public Function PrevMonthUses As Long

	PrevMonthUses = pDbActivity.PrevMonthUses               

End Function

Public Function PrevMonthReads As Long

	PrevMonthReads = pDbActivity.PrevMonthReads     

End Function

Public Function PrevMonthWrites As Long

	PrevMonthWrites = pDbActivity.PrevMonthWrites

End Function



Public Function UserActivityCount As Long

	UserActivityCount = retUserCount

End Function



Public Function HasUserActivity As Integer

	HasUserActivity = Me.flgHasActivity

End Function



Public Function Parent As NotesDatabase

	Set Parent = prvdb

End Function



Public Function GetNthUserActivityEntry(inpEntry As Long) As NotesUserActivityEntry

	Dim puActivity As Long

	Dim lEntry As Long

	Dim puActivityEntry As DBACTIVITY_ENTRY

	Dim StructureOffset As Long

	Dim UsernameOffset As Long

	Dim spUsername As String * 256

	Dim sUsername As String

	Dim nuae As New NotesUserActivityEntry

	

	lEntry = inpEntry - 1

	

	If Not Me.flgHasActivity Then Error 14104, "NotesUserActivity: No activity available"

	

	If lEntry > Me.retUserCount Or lEntry < 0 Then

		Error 14103, "NotesUserActivity: Subscript out of range."

	End If

	

      'Lock the structure get the required entry

	puActivity = W32_OSLockObject(Me.rethUserInfo)

	StructureOffset = puActivity + (Lenb(puActivityEntry) * lEntry)

	Call CopyMemory (puActivityEntry, StructureOffset, Len(puActivityEntry))

	

      'Load the User name for the Activity Structure

	UsernameOffset = puActivity + puActivityEntry.UserNameOffset

	spUsername = Space(256)

	Call CopyMemoryString(spUsername, UsernameOffset,Lenb(spUsername))

	sUserName = Left(spUsername, Instr(spUsername, Chr(0)) - 1)

	

	With nuae

		.UserName = sUserName

		.Reads = puActivityEntry.Reads

		.Writes = puActivityEntry.Writes

		.Time = ConvertTIMEtoText(puActivityEntry.Time)

	End With

	

	Call OSUnlockObject(rethUserInfo)

	

	Set GetNthUserActivityEntry = nuae

	

End Function

End Class

Function ConvertTIMEtoText(TIMESTRUCT As TIMEDATE) As String

Dim spTime As String * MAXALPHATIMEDATE

Dim retLength As Integer



spTime = Space(MAXALPHATIMEDATE)

Call ConvertTIMEDATEToText (&h0,&h0, TIMESTRUCT, spTime,MAXALPHATIMEDATE,retLength)

ConvertTIMEtoText = Left(spTime,retLength)

End Function

Subject: this scheduled agent is bring the server down to its’ knees

Michael,

First thing is to get rid of those multiple Notessession variables, you only need one.

Also as a matter of tidy up I would remove all of those if test=0 and use elseifs instead. Also were you use have your first If to test if db1 is open, remove the goto resumenext, istead wrap everything down to the label into the else statement of the if.

I have not had a chance to read your custom class fully yet but the Session var stuff might be enough.

Danny

Subject: this scheduled agent is bring the server down to its’ knees

Running out of memory on your server?JYR

Subject: RE: this scheduled agent is bring the server down to its’ knees

Yes.

If I run it from he client (a manual/selected version) the machine produces the “virtual memory too low” error.

So I converted this to a scheduled agent on the server and maybe we are having the same problem.

thks,

-MC