VB6 ADO Connection Pooling - vb6

We have a bunch of VB6 apps at our company. We are trying to debug a random SQL timeout error and did a trace with SQL Server Profiler on the Audit Login event. We noticed that the connections were coming in as nonpooled. We use the SQLOLEDB provider with SQL Server 2000 & 2005. I searched the internet and everything I come across says that connections are pooled by default in the SQLOLEDB provider, but we are not seeing this. Below is the code we use to connect to the database. We really need to have these connections pooled because we think this may be the problem with our random timeout error. Could any one shine some light on why connection pooling isn't working and any way to make it work? Thanks.
Dim cnn As New ADODB.Connection
cnn.ConnectionString = "Provider=SQLOLEDB;Data Source=xxx;Catalog=xxx;User ID=xxx Password=xxx;"
Call cnn.Open
Dim cmd As New ADODB.Command
Set cmd.ActiveConnection = cnn
cmd.CommandText = "SELECT * FROM [Table]"
Dim rs As New ADODB.RecordSet
Call rs.Open(cmd, , adOpenStatic, adLockOptimistic)
While Not rs.eof
'Do stuff
Call rs.MoveNext
Wend
'Close and Dispose connection here

Disposing the connection on every call could prevent pooling
...at least one instance of a Connection
object instantiated for each unique
user—at all times. Otherwise, the pool
will be destroyed when the last
Connection object for that string is
closed.
http://msdn.microsoft.com/en-us/library/ms810829.aspx

I messed around and opened a connection at app startup and kept it open through the entire time the app was running. Connection pooling did start after the second opened and closed connection.

You mentioned that you were trying to track down a random timeout problem. I've had the same, generally when I was doing a SELECT that returned a lot of rows. Two things:
Cnn.CursorLocation=ADODB.adUseServer
(The other option is adUseClient) - I believe adUseServer gave me faster queries, which reduced the likelihood of timeouts. You do this before you open the connection, I believe.
Cnn.CommandTimeout=0
Also before the open(), tells it that you want an infinite timeout. I think the default timeout is something like 30s, which was way too short for some queries. The CommandTimeout will be used for Recordset queries. If you use a Command object, it has it's own CommandTimeout member, which doesn't appear to inherit from the Connection (ie, I set it before I Execute a command).
Sorry if the syntax isn't quite right, I'm cutting from some C++ code.

Related

Does a connection instance need to be created in ObjectContext?

We have old VB6 code in our production system that everyone is afraid to touch. But, occasionally, a bug is large enough that someone needs to fix it. We are in the process of rewriting the system, but in the meantime, we still have customers using the existing VB6 code.
My biggest issue right now is my lack of understanding about ObjectContext. I've been reading documentation about it, and the more I read, the less I understand. I see code where sometimes, we have a block that looks like this:
Set CtxObject = GetObjectContext
If Not CtxObject Is Nothing Then
Set objSomeObject = CtxObject.CreateInstance("SomePackage.SomeObject")
Else
Set objSomeObject = CreateObject("SomePackage.SomeObject")
End If
but, ADODB.Connection objects are never created like this. Should connection objects be created like this? If the objContext is aborted, will any updates through that connection be rolled back? Or not since they were not created within the same object context?
Example of how we do create connection objects:
Dim oConn As New ADODB.Connection
Dim oRS As New ADODB.RecordSet
On Error GoTo ErrorHandler
Dim CtxObject As ObjectContext
Set CtxObject = GetObjectContext
oConn.Open *ConnectionString*
oRS.Open *SQL*, oConn, adOpenKeyset, adLockBatchOptimistic
...
Here, the connection object is created before the object context is grabbed, so I don't see how the connection is tied to that. If the RecordSet is updated, and then the ObjectContext is aborted, will the RecordSet updates be rolled back?

Do I need to close connection before response.end?

In classic asp I have the file open.asp and close.asp included at top and bottom of every page. Somewhere I have response.end in my codes. Do I need to close connection before response.end or the server translates the page to the end of page after response.end?
Content of open.asp:
Set objcon = Server.CreateObject("ADODB.Connection")
objcon.connectionString="DSN=something"
objcon.Open
content of close.asp:
objcon.close
set objcon=nothing
Please note that I have no problem with multiple connections and memory leak. My exact question is about behavior of of server against "Response.End"
Response.End stops further execution of the page. From the docs: "The remaining contents of the file are not processed." So, no, the connection object won't get cleaned up in this scenario.
It's better to go ahead and create connection objects at a more granular level and destroy/release them as soon as possible back to the ADO connection pool, which is what manages the actual connections to the database. Reusing a connection object leaves it more vulnerable to not getting cleaned up properly.

VB6 Winsock multiple TCP connections > problems with DoEvents

I made a software couple years ago using VB6 that works as a TCP server, receives multiple connections from clients.
The basic Idea of the software is to listen on a specific port, accept connections from different clients and pass each connection to a separate winsock which analyzes the data, looks in DB, replies with the proper message, and then closes the connection.
Here's some code:
Initializing the sockets when the application starts:
For i = 1 To MaxCon
Load sckAccept(i)
Next i
sckListen.Listen
Accepting connections:
Private Sub sckListen_ConnectionRequest(ByVal requestID As Long)
Dim aFreeSocket As Integer
aFreeSocket = GetFreeSocket
If aFreeSocket = 0 Then
sckAccept(0).Accept requestID
sckAccept(0).SendData "Server is full!"
sckAccept(0).Close
Else
sckAccept(aFreeSocket).Accept requestID
End Sub
Receiving data, analyzing it, and reply:
Private Sub sckAccept_DataArrival(Index As Integer, ByVal bytesTotal As Long)
Dim sData As String
sckAccept(Index).GetData sData
'Do lots of analyizing and search in DB
'
'
sckAccept(Index).SendData "Message"
'
'
DoEvents
sckAccept(Index).Close
End Sub
Everything was working fine, but now the number of connections has increased (couple dozens per second), so the software started getting Out of stack space exception (because of DoEvents).
I know that in many cases DoEvents is evil, but if I remove it, the application UI won't respond (because of the over load on the thread) and some data might not be delivered.
So, my question is: does anyone have an idea of how to get around this problem with/without using DoEvents?
Note: I know that VB6 doesn't really support multi-threading and might be a PITA for such situations. I'm actually planning to upgrade the software and re-create it using .Net, but that will take some time. That's why I need to fix this problem in VB6 since the software is written in VB6 for now.
Well, I managed to figure out the problem, and have solved it.
The short answer
Do NOT use DoEvents.. Some data won't be delivered? Well, close the connection ONLY in the SendComplete event.
The long answer
First thing first:
Why I used DoEvents in the first place? because some of the sent messages were not being delivered. A lot of articles/questions on the internet suggest using DoEvents after Socket.SendData in order to guarantee the data arrival to the receiver.
I digged deeper into this trying to figure out why the messages aren't delivered. I found out that this problem only occurs when closing the connection after sending the message:
Socket.SendData "Message"
'
'
Socket.Close
So, I simply moved the line that closes the connection to the SendComplete event, removed the DoEvents sentence -since I don't need it anymore-, and the problem is gone :)
Private Sub sckAccept_SendComplete(Index As Integer)
sckAccept_Close (Index)
End Sub
I hope this could help someone who has the same problem.

VB6 ADODB.Connection Execute() Retry until successful

I'm trying to fix a little utility which seems to be losing connection to the database after some idle time. I already set the timeout to 0 but that didn't seem to work.
Instead of simply crashing and displaying a couple of error messages I would like to try to re-establish the connection and execute the query until successful (I realize this is probably a bad use of resources) but even then that's what I'm trying to accomplish here. Or if possible display a Message Box saying that connection was lost which will then be closed once connection is established.
Any suggestions would be greatly appreciated.
Public connMain As ADODB.Connection
Public rsMain As ADODB.Recordset
......
Function Picture_Exists() As Boolean
On Error Resume Next
sqlstr = "select * .... "
Set rsMain = connMain.Execute(sqlstr)
Your connection is probably being dropped at the database end due to non-use. It isn't good practice to maintain a connection when it isn't being used; connections are expensive in terms of resources so any such practice wouldn't scale well. Dbadmins aren't likely to leave unused connections open for very long.
Your potential solution says to try to connect and if you can't ignore the error. We don't say "never" in this business very often, but you should never use "On Error Resume Next" without also evaluating Err.Number to see whether it equals 0 (if it does, there's no error). This is called "inline error handling."
In any case, I wouldn't use this method. I would evaluate the Connection object's State Property, and if it's closed (cn.State = adoStateClosed) then I would reopen it.
You can try the following:
On Error Resume ''''instead of On Error Resume Next
Dim rsMain As New ADODB.Recordset
sqlstr = "select * .... "
If rsMain.State = adStateOpen Then rsMain.Close
rsMain.Open sqlstr, sProvider, adOpenKeyset, adLockOptimistic

VB.net Windows service response time

I have a windows service that utilizes an infinite loop and thread.sleep. The sleep time for the thread is 10 seconds.
When the service is initially started AND has work to do (data exist in SQL), it immediately does it's processes. It continues to be responsive and process tasks every 10 seconds as long as it has work to do. If no data is present in SQL for an extended period (i.e. 15-20 minutes) then the service starts responding very slowly. It will eventually pick the data up and process it, but it takes more like 10 minutes instead of 10 seconds.
There's no logic in the code telling the service to sleep. Any ideas?
Without seeing your code, it is impossible to give a definitive answer; It could be the case that you aren't tidying up your database connections quickly enough.
If you've something like:
While( True )
Dim con as new SqlConnection(connectionString)
con.Open()
Dim cmd as New SqlCommand("usp_getJob", con)
cmd.CommandType = CommandType.StoredProcedure
Dim dr as SqlDataReader = cmd.ExecuteReader(CommandBehavior.SingleResult Or CommandBehavior.SingleRow Or CommandBehavior.CloseConnection)
If( dr.Read() )
DoSomething(dr)
Else
Thread.Sleep(10)
End If
End While
...then it will open connections faster than they will go away by themselves.
There are several alternates, and I'd advocate using Using blocks to allow the connection to be returned to the connection pool as fast as possible:
While( True )
Using con as new SqlConnection(connectionString)
con.Open()
Using cmd as New SqlCommand("usp_getJob", con)
cmd.CommandType = CommandType.StoredProcedure
Using dr as SqlDataReader = cmd.ExecuteReader(CommandBehavior.SingleResult Or CommandBehavior.SingleRow Or CommandBehavior.CloseConnection)
If( dr.Read() )
DoSomething(dr)
dr.Close()
Else
Thread.Sleep(10)
End If
End Using
End Using
End Using
End While
These will then call Dispose() on the SqlDataReader, SqlConnection and SqlCommand - either of the first two will cause the connection to be released to the connection pool (given we've asked the SqlDataReader to CloseConnection on its close)
Totally agree with Rowland on this one. Without seeing the code it would hard to determine but most likely culprit is your db code.

Resources