How to use an external file that lists URLs - Singleton
Hi,
In my quest to make my ANTS load testing a bit better, I'm trying to use a list of URLs from a currently-live webserver. Here's what I've done:
-Looked at our clients web stats and found a busy day
-parsed the resultant web logs from IIS and extracted all resources, one line each
-put this list of resources into an external file of >1,000,000 lines
-tried to implement a Singleton class to read the file and sequentially feed the resource URLs one-by-one to ANTS virtual clients. The singleton is supposed to be instantiated ONCE and reused by each of the threads - so that I only have to read the big URL file once, and then it's in memory for subsequent reads.
Here's the problem:
I can't get the Singleton to work as expected. I'm not very experienced with VB (but I'm a whiz with C#), but in looking at tutorials and examples, I'm pretty sure I'm *close* to doing what I want. The problem is that I seem to be getting thousands of Instances of the Singleton created, instead of just one. Because I am getting multiple instances, I am having the URL source file read thousands of times (concurrently!), and am getting the following error messages:
Exception message: The process cannot access the file "C:\tmp\test.txt" because it is being used by another process. - 3782 times
Exception message: Object reference not set to an instance of an object. - 182 times
(and these messages are only from a 15 second run!)
So, does anyone have any idea where I can go from here?
Code for my quasi-singleton:
===================
Imports System
Imports System.Collections
Imports System.IO
Imports System.Runtime.CompilerServices
Imports System.Threading
Public Class FileReader
Dim logfile As String = "C:\tmp\antslog.txt"
Dim sourceFile As String = "C:\tmp\test.txt"
Private _alURLs As ArrayList ''holds a list of URLs
Private _URL_counter As Int32 = 0 ''counter to increment through the array
Private Shared ReadOnly padlock As Object = New Object
Private Shared FInstance As FileReader = Nothing
Private Sub New()
End Sub
Public Shared ReadOnly Property Instance() As FileReader
Get
SyncLock padlock
If (FInstance Is Nothing) Then
FInstance = New FileReader
End If
FInstance.WriteLog("getting Instance")
Return FInstance
End SyncLock
End Get
End Property
Private Sub ReadList()
WriteLog("ReadList")
''first test to make sure that the URL list has info in it
If (_alURLs Is Nothing) Then
''populate the array
Dim din As StreamReader = New StreamReader(File.Open(sourceFile, FileMode.Open))
Dim str As String
' loop through all the rows, stopping when we reach the end of file
Do
str = din.ReadLine()
If str <> Nothing Then
_alURLs.Add(str)
End If
Loop Until str = Nothing
End If
End Sub
Public Function GetURL() As String
WriteLog("Getting URL")
ReadList()
''return the next URL in the list, but if we are at
''the end of the array, move to the beginning
If (_URL_counter = _alURLs.Count) Then
_URL_counter = 0
End If
Return _alURLs(_URL_counter).ToString()
End Function
Public Sub WriteLog(ByVal text As String)
SyncLock padlock
Dim objReader As StreamWriter
objReader = New StreamWriter(logfile, True)
objReader.Write(DateTime.Now & " - " & text & System.Environment.NewLine)
objReader.Close()
End SyncLock
End Sub
End Class
In my quest to make my ANTS load testing a bit better, I'm trying to use a list of URLs from a currently-live webserver. Here's what I've done:
-Looked at our clients web stats and found a busy day
-parsed the resultant web logs from IIS and extracted all resources, one line each
-put this list of resources into an external file of >1,000,000 lines
-tried to implement a Singleton class to read the file and sequentially feed the resource URLs one-by-one to ANTS virtual clients. The singleton is supposed to be instantiated ONCE and reused by each of the threads - so that I only have to read the big URL file once, and then it's in memory for subsequent reads.
Here's the problem:
I can't get the Singleton to work as expected. I'm not very experienced with VB (but I'm a whiz with C#), but in looking at tutorials and examples, I'm pretty sure I'm *close* to doing what I want. The problem is that I seem to be getting thousands of Instances of the Singleton created, instead of just one. Because I am getting multiple instances, I am having the URL source file read thousands of times (concurrently!), and am getting the following error messages:
Exception message: The process cannot access the file "C:\tmp\test.txt" because it is being used by another process. - 3782 times
Exception message: Object reference not set to an instance of an object. - 182 times
(and these messages are only from a 15 second run!)
So, does anyone have any idea where I can go from here?
Code for my quasi-singleton:
===================
Imports System
Imports System.Collections
Imports System.IO
Imports System.Runtime.CompilerServices
Imports System.Threading
Public Class FileReader
Dim logfile As String = "C:\tmp\antslog.txt"
Dim sourceFile As String = "C:\tmp\test.txt"
Private _alURLs As ArrayList ''holds a list of URLs
Private _URL_counter As Int32 = 0 ''counter to increment through the array
Private Shared ReadOnly padlock As Object = New Object
Private Shared FInstance As FileReader = Nothing
Private Sub New()
End Sub
Public Shared ReadOnly Property Instance() As FileReader
Get
SyncLock padlock
If (FInstance Is Nothing) Then
FInstance = New FileReader
End If
FInstance.WriteLog("getting Instance")
Return FInstance
End SyncLock
End Get
End Property
Private Sub ReadList()
WriteLog("ReadList")
''first test to make sure that the URL list has info in it
If (_alURLs Is Nothing) Then
''populate the array
Dim din As StreamReader = New StreamReader(File.Open(sourceFile, FileMode.Open))
Dim str As String
' loop through all the rows, stopping when we reach the end of file
Do
str = din.ReadLine()
If str <> Nothing Then
_alURLs.Add(str)
End If
Loop Until str = Nothing
End If
End Sub
Public Function GetURL() As String
WriteLog("Getting URL")
ReadList()
''return the next URL in the list, but if we are at
''the end of the array, move to the beginning
If (_URL_counter = _alURLs.Count) Then
_URL_counter = 0
End If
Return _alURLs(_URL_counter).ToString()
End Function
Public Sub WriteLog(ByVal text As String)
SyncLock padlock
Dim objReader As StreamWriter
objReader = New StreamWriter(logfile, True)
objReader.Write(DateTime.Now & " - " & text & System.Environment.NewLine)
objReader.Close()
End SyncLock
End Sub
End Class
Comments
Sorry we haven't been terribly helpful. I haven't tried this myself, but the basic idea of a singleton class is to put a wrapper around a class and prevent more than one instance from being created when the class constructor is called more than once. I have located some sample code here:
http://searchvb.techtarget.com/tip/0,28 ... 28,00.html
Hopefully that implementation would rid you of the other script exceptions, mainly the 'locked file' issue.
Yes, that's why I'm trying to use a Singleton - I only want to build up ONE list of URLS, that all the threads of ANTS Load will share and contribute to, so in effect I can have the one list sequentially loaded by the multiple clients, without any overlap.
Thanks for the link - Googling for Singleton and VB gave pretty slim pickings.
I think my unfamiliararity with VB is making this harder than it should be!
And in a related note:
I find troubleshooting the scripts in ANTS Load a bit of a pain. It would be nice to just hit the play button in visual studio and see one thread, and be able to BREAKPOINT (!!!) the code. Instead I have to resort to putting print statements everywhere to see variable output - oldskool, and it works, but is clunky. To get around this, I tried to create a C# solution and import the ANTS resources, but I couldn't get that to play correctly.
a) Am I going about debugging in an incorrect fashion? Should I be able to troubleshoot the scripts inside of Visual Studio inside of ANTS?
b) Does anyone have an example C# ANTS solution that I can look at to see how to run ANTS externally - yet still get the results into the ANTS GUI?
c) I am using try and catch blocks to catch the exceptions - not to do anything useful, but just to print them to an external log file, as the errors displayed in ANTS are not verbose enough. I need to see the full exception text and the contents of any inner exceptions! Can this be turned on via a settings menu or config file somewhere (so i can see the output in the ants results report)?
Cheers,
Lance
You're correct in that there is currently no way to run and debug a script from inside the program. We may improve this for a future version.
Getting ANTS to use external assemblies is a bit more challenging -- but possible. The first restriction is that your assembly needs to exist in the ANTS Load program folder in order to be able to reference it from the VSA development environment.
The second trick is that the assembly needs to inherit from Control.VirtualClient. This limits you to one external assembly or module. In reality, you could have as many code modules as you want -- but you can only have one that uses any of the methods in the ANTS.Engine namespace, such as WebClient.Get and WebClient.Post.
Here is some information from another customer who is doing this:
http://www.red-gate.com/messageboard/vi ... .php?t=542