// internal methods internal void Connect(TimeSpan timeout, ConnectWaitFor waitFor) { _timeoutAt = DateTime.UtcNow + timeout; // connect to all server instances in parallel (they will report responses back through the responseQueue) // the set of Instances initially comes from the seed list, but is adjusted to the official set once connected foreach (var serverInstance in _server.Instances) { QueueConnect(serverInstance); } // process the responses as they come back and return as soon as we have connected to the primary // any remaining responses after the primary will be processed in the background while (_responses.Count < _connects.Count) { var timeRemaining = _timeoutAt - DateTime.UtcNow; var response = _responseQueue.Dequeue(timeRemaining); if (response == null) { break; // we timed out } ProcessResponse(response); // return as soon as we can (according to the waitFor mode specified) bool exitEarly = false; switch (waitFor) { case ConnectWaitFor.All: if (_server.Instances.All(i => i.State == MongoServerState.Connected)) { exitEarly = true; } break; case ConnectWaitFor.AnySlaveOk: if (_server.Instances.Any(i => (i.IsPrimary || i.IsSecondary || i.IsPassive) && i.State == MongoServerState.Connected)) { exitEarly = true; } break; case ConnectWaitFor.Primary: var primary = _server.Primary; if (primary != null && primary.State == MongoServerState.Connected) { exitEarly = true; } break; default: throw new ArgumentException("Invalid ConnectWaitFor value."); } if (exitEarly) { if (_responses.Count < _connects.Count) { // process any additional responses in the background ThreadPool.QueueUserWorkItem(ProcessAdditionalResponsesWorkItem); } return; } } string waitForString; switch (waitFor) { case ConnectWaitFor.All: waitForString = "all members"; break; case ConnectWaitFor.AnySlaveOk: waitForString = "any slaveOk member"; break; case ConnectWaitFor.Primary: waitForString = "the primary member"; break; default: throw new ArgumentException("Invalid ConnectWaitFor value."); } var exceptions = _responses.Select(r => r.ServerInstance.ConnectException).Where(e => e != null).ToArray(); var firstException = exceptions.FirstOrDefault(); string message; if (firstException == null) { message = string.Format("Unable to connect to {0} of the replica set.", waitForString); } else { message = string.Format("Unable to connect to {0} of the replica set: {1}.", waitForString, firstException.Message); } var connectionException = new MongoConnectionException(message, firstException); connectionException.Data.Add("InnerExceptions", exceptions); // useful when there is more than one throw connectionException; }
public void Connect(ConnectWaitFor waitFor) { _mongoServer.Connect(waitFor); }
public void Connect(TimeSpan timeout, ConnectWaitFor waitFor) { _mongoServer.Connect(timeout, waitFor); }
// internal methods internal void Connect(TimeSpan timeout, ConnectWaitFor waitFor) { _timeoutAt = DateTime.UtcNow + timeout; // connect to all server instances in parallel (they will report responses back through the responseQueue) // the set of Instances initially comes from the seed list, but is adjusted to the official set once connected foreach (var serverInstance in _server.Instances) { QueueConnect(serverInstance); } // process the responses as they come back and return as soon as we have connected to the primary // any remaining responses after the primary will be processed in the background while (_responses.Count < _connects.Count) { var timeRemaining = _timeoutAt - DateTime.UtcNow; var response = _responseQueue.Dequeue(timeRemaining); if (response == null) { break; // we timed out } ProcessResponse(response); // return as soon as we can (according to the waitFor mode specified) bool exitEarly = false; switch (waitFor) { case ConnectWaitFor.All: if (_server.Instances.All(i => i.State == MongoServerState.Connected)) { exitEarly = true; } break; case ConnectWaitFor.AnySlaveOk: // don't check for IsPassive because IsSecondary is also true for passives (and only true if not in recovery mode) if (_server.Instances.Any(i => (i.IsPrimary || i.IsSecondary) && i.State == MongoServerState.Connected)) { exitEarly = true; } break; case ConnectWaitFor.Primary: var primary = _server.Primary; if (primary != null && primary.State == MongoServerState.Connected) { exitEarly = true; } break; default: throw new ArgumentException("Invalid ConnectWaitFor value."); } if (exitEarly) { if (_responses.Count < _connects.Count) { // process any additional responses in the background ThreadPool.QueueUserWorkItem(ProcessAdditionalResponsesWorkItem); } return; } } string waitForString; switch (waitFor) { case ConnectWaitFor.All: waitForString = "all members"; break; case ConnectWaitFor.AnySlaveOk: waitForString = "any slaveOk member"; break; case ConnectWaitFor.Primary: waitForString = "the primary member"; break; default: throw new ArgumentException("Invalid ConnectWaitFor value."); } var exceptions = _responses.Select(r => r.ServerInstance.ConnectException).Where(e => e != null).ToArray(); var firstException = exceptions.FirstOrDefault(); string message; if (firstException == null) { message = string.Format("Unable to connect to {0} of the replica set.", waitForString); } else { message = string.Format("Unable to connect to {0} of the replica set: {1}.", waitForString, firstException.Message); } var connectionException = new MongoConnectionException(message, firstException); connectionException.Data.Add("InnerExceptions", exceptions); // useful when there is more than one throw connectionException; }