Description:
Hi,
In an attempt to add more robustness to an application, before using again a Connection object opened some time before, I hoped I could do the following:
If Not Connection.Ping() Then
Connection.Close
Connection.Open
EndIf
... then do some job ...
This will check whether the connection is still alive (e.g. not closed by server after 8 hours inactivity timeout or broken socket) before I use it.
This sequence will actually fail on Connection.Open with a NullReference exception, if the connection is actually broken.
Please note that if Ping is not called, the sequence will perform correctly (e.g. calling just Connection.Close+Open) and correct operation will be restored (but I expect performance to be worse).
How to repeat:
1. open a connection to a server, even on localhost
2. stop MySQL server service and restart it
3. try the 4 code lines above
Suggested fix:
Looking at the client source I tried to figure out why, and I did a quick-and-dirty fix, as I urgently needed it.
After ping has reported failure, Connection.Close will simply do nothing, as the connection state is already closed.
When re-opening the same connection instance, the null reference exception is given by the following piece of code:
NativeDriver.cs:
public override void Configure(MySqlConnection conn)
{
base.Configure(conn);
stream.MaxPacketSize = (ulong) maxPacketSize;
stream.Encoding = Encoding;
}
as 'stream' is null.
To improve the behaviour, I did the following:
1. I touched Connection.cs Ping function:
public bool Ping()
{
bool result = driver.Ping();
if (!result)
//SetState(ConnectionState.Closed, true);
Close(); //I call the public close method instead of just setting its state
return result;
}
2. This won't work unless a second fix is performed in MySqlPool.cs
I added the try/catch block at the bottom, around poolGate.Release();
public void ReleaseConnection(Driver driver)
{
lock (lockObject)
{
if (inUsePool.Contains(driver))
inUsePool.Remove(driver);
if (driver.IsTooOld())
{
driver.Close();
Debug.Assert(!idlePool.Contains(driver));
}
else
idlePool.Enqueue(driver);
// we now either have a connection available or have room to make
// one so we release one slot in our semaphore
//added try-catch
try
{
poolGate.Release();
}
catch
{} //might need something else here??
}
}
}