Browse Source

Partial fix for CSHARP-302. The default action now when there is an exception on a connection is to discard only that connection instead of the whole connection pool, preventing a Connect/Disconnect storm. Also made Disconnect synchronous so it should no longer be possible to open new connections faster than old ones are being closed.

pull/66/merge
rstam 14 years ago
parent
commit
72ee5e8c79
  1. 40
      Driver/Internal/MongoConnection.cs
  2. 20
      Driver/Internal/MongoConnectionPool.cs

40
Driver/Internal/MongoConnection.cs

@ -460,21 +460,45 @@ namespace MongoDB.Driver.Internal {
private void HandleException(
Exception ex
) {
// TODO: figure out which exceptions are more serious than others
// there are three possible situations:
// 1. we can keep using the connection
// 2. just this one connection needs to be discarded
// 3. the whole connection pool needs to be discarded
// for now the only exception we know affects only one connection is FileFormatException
// and there are no cases where the connection can continue to be used
state = MongoConnectionState.Damaged;
if (!(ex is FileFormatException)) {
try {
serverInstance.Disconnect();
} catch { } // ignore any further exceptions
switch (DetermineAction(ex)) {
case HandleExceptionAction.KeepConnection:
break;
case HandleExceptionAction.DiscardConnection:
state = MongoConnectionState.Damaged;
break;
case HandleExceptionAction.DiscardConnectionPool:
state = MongoConnectionState.Damaged;
try {
serverInstance.Disconnect();
} catch { } // ignore exceptions
break;
default:
throw new MongoInternalException("Invalid HandleExceptionAction");
}
}
private enum HandleExceptionAction {
KeepConnection,
DiscardConnection,
DiscardConnectionPool
}
private HandleExceptionAction DetermineAction(
Exception ex
) {
// TODO: figure out when to return KeepConnection or DiscardConnectionPool (if ever)
// don't return DiscardConnectionPool unless you are *sure* it is the right action
// definitely don't make DiscardConnectionPool the default action
// returning DiscardConnectionPool frequently can result in Connect/Disconnect storms
return HandleExceptionAction.DiscardConnection; // this should always be the default action
}
#endregion
#region private nested classes

20
Driver/Internal/MongoConnectionPool.cs

@ -114,7 +114,7 @@ namespace MongoDB.Driver.Internal {
// otherwise replace the least recently used connection with a brand new one
// if this happens a lot the connection pool size should be increased
ThreadPool.QueueUserWorkItem(CloseConnectionWorkItem, availableConnections[0]);
availableConnections[0].Close();
availableConnections.RemoveAt(0);
return new MongoConnection(this);
}
@ -145,7 +145,7 @@ namespace MongoDB.Driver.Internal {
lock (connectionPoolLock) {
if (!closed) {
foreach (var connection in availableConnections) {
ThreadPool.QueueUserWorkItem(CloseConnectionWorkItem, connection);
connection.Close();
}
availableConnections = null;
closed = true;
@ -206,9 +206,9 @@ namespace MongoDB.Driver.Internal {
}
lock (connectionPoolLock) {
// if connection pool is closed just close connection on worker thread
// if connection pool is closed just close connection
if (closed) {
ThreadPool.QueueUserWorkItem(CloseConnectionWorkItem, connection);
connection.Close();
return;
}
@ -235,23 +235,13 @@ namespace MongoDB.Driver.Internal {
#endregion
#region private methods
// note: this method runs on a thread from the ThreadPool
private void CloseConnectionWorkItem(
object parameters
) {
try {
var connection = (MongoConnection) parameters;
connection.Close();
} catch { } // ignore exceptions
}
private void RemoveConnection(
MongoConnection connection
) {
availableConnections.Remove(connection); // it might or might not be in availableConnections (but remove it if it is)
poolSize -= 1;
connectionsRemovedSinceLastTimerTick += 1;
ThreadPool.QueueUserWorkItem(CloseConnectionWorkItem, connection);
connection.Close();
Monitor.Pulse(connectionPoolLock);
}

Loading…
Cancel
Save