private void ProcessGLEReplyMessage(CommandState state, ReplyMessage <RawBsonDocument> replyMessage, ConnectionId connectionId) { var reply = replyMessage.Documents[0]; BsonValue ok; if (!reply.TryGetValue("ok", out ok)) { // this is a degenerate case with the server and // we don't really know what to do here... } else if (!ok.ToBoolean()) { if (_failedEvent != null) { _failedEvent(new CommandFailedEvent( state.CommandName, new MongoCommandException( connectionId, string.Format("{0} command failed", state.CommandName), null, reply), state.OperationId, replyMessage.ResponseTo, connectionId, state.Stopwatch.Elapsed)); } } else if (_succeededEvent != null) { var fakeReply = new BsonDocument("ok", 1); BsonValue n; if (reply.TryGetValue("n", out n)) { fakeReply["n"] = n; } BsonValue err; if (reply.TryGetValue("err", out err) && err != BsonNull.Value) { var code = reply.GetValue("code", -1); var errmsg = err.ToString(); var isWriteConcernError = __writeConcernIndicators.Any(x => errmsg.Contains(x)); if (isWriteConcernError) { fakeReply["writeConcernError"] = new BsonDocument { { "code", code }, { "errmsg", err } }; } else { fakeReply["writeErrors"] = new BsonArray(new[] { new BsonDocument { { "index", 0 }, { "code", code }, { "errmsg", err } } }); } } else if (state.CommandName == "insert") { fakeReply["n"] = state.NumberOfInsertedDocuments; } else if (state.CommandName == "update") { // Unfortunately v2.4 GLE does not include the upserted field when // the upserted _id is non-OID type. We can detect this by the // updatedExisting field + an n of 1 BsonValue upsertedValue; var upserted = reply.TryGetValue("upserted", out upsertedValue) || (n == 1 && !reply.GetValue("updatedExisting", false).ToBoolean()); if (upserted) { fakeReply["upserted"] = new BsonArray(new[] { new BsonDocument { { "index", 0 }, { "_id", upsertedValue ?? state.UpsertedId ?? BsonUndefined.Value } } }); } } _succeededEvent(new CommandSucceededEvent( state.CommandName, fakeReply, state.OperationId, replyMessage.ResponseTo, connectionId, state.Stopwatch.Elapsed)); } }
private void ProcessQueryReplyMessage(CommandState state, ReplyMessage <RawBsonDocument> replyMessage, ConnectionId connectionId) { if (_succeededEvent != null) { BsonDocument reply; if (state.CommandName == "explain") { reply = new BsonDocument("ok", 1); reply.Merge(replyMessage.Documents[0]); } else { var batchName = state.CommandName == "find" ? "firstBatch" : "nextBatch"; reply = new BsonDocument { { "cursor", new BsonDocument { { "id", replyMessage.CursorId }, { "ns", state.QueryNamespace.FullName }, { batchName, new BsonArray(replyMessage.Documents) } } }, { "ok", 1 } }; } _succeededEvent(new CommandSucceededEvent( state.CommandName, reply, state.OperationId, replyMessage.ResponseTo, connectionId, state.Stopwatch.Elapsed)); } }
private void ProcessReplyMessage(CommandState state, ResponseMessage message, IByteBuffer buffer, ConnectionId connectionId, MessageEncoderSettings encoderSettings) { state.Stopwatch.Stop(); bool disposeOfDocuments = false; var replyMessage = message as ReplyMessage <RawBsonDocument>; if (replyMessage == null) { // ReplyMessage is generic, which means that we can't use it here, so, we need to use a different one... using (var stream = new ByteBufferStream(buffer, ownsBuffer: false)) { var encoderFactory = new BinaryMessageEncoderFactory(stream, encoderSettings); replyMessage = (ReplyMessage <RawBsonDocument>)encoderFactory .GetReplyMessageEncoder(RawBsonDocumentSerializer.Instance) .ReadMessage(); disposeOfDocuments = true; } } try { if (replyMessage.CursorNotFound || replyMessage.QueryFailure || (state.ExpectedResponseType != ExpectedResponseType.Query && replyMessage.Documents.Count == 0)) { var queryFailureDocument = replyMessage.QueryFailureDocument; if (__securitySensitiveCommands.Contains(state.CommandName)) { queryFailureDocument = new BsonDocument(); } if (_failedEvent != null) { _failedEvent(new CommandFailedEvent( state.CommandName, new MongoCommandException( connectionId, string.Format("{0} command failed", state.CommandName), null, queryFailureDocument), state.OperationId, replyMessage.ResponseTo, connectionId, state.Stopwatch.Elapsed)); } } else { switch (state.ExpectedResponseType) { case ExpectedResponseType.Command: ProcessCommandReplyMessage(state, replyMessage, connectionId); break; case ExpectedResponseType.GLE: ProcessGLEReplyMessage(state, replyMessage, connectionId); break; case ExpectedResponseType.Query: ProcessQueryReplyMessage(state, replyMessage, connectionId); break; } } } finally { if (disposeOfDocuments && replyMessage.Documents != null) { replyMessage.Documents.ForEach(d => d.Dispose()); } } }
private void ProcessCommandReplyMessage(CommandState state, ReplyMessage <RawBsonDocument> replyMessage, ConnectionId connectionId) { BsonDocument reply = replyMessage.Documents[0]; BsonValue ok; if (!reply.TryGetValue("ok", out ok)) { // this is a degenerate case with the server and // we don't really know what to do here... return; } if (__securitySensitiveCommands.Contains(state.CommandName)) { reply = new BsonDocument(); } if (!ok.ToBoolean()) { if (_failedEvent != null) { _failedEvent(new CommandFailedEvent( state.CommandName, new MongoCommandException( connectionId, string.Format("{0} command failed", state.CommandName), null, reply), state.OperationId, replyMessage.ResponseTo, connectionId, state.Stopwatch.Elapsed)); } } else if (_succeededEvent != null) { _succeededEvent(new CommandSucceededEvent( state.CommandName, reply, state.OperationId, replyMessage.ResponseTo, connectionId, state.Stopwatch.Elapsed)); } }
private void ProcessInsertMessage(RequestMessage message, Queue <RequestMessage> messageQueue, ConnectionId connectionId, InsertMessageBinaryEncoder <RawBsonDocument> encoder, Stopwatch stopwatch) { var commandName = "insert"; var operationId = EventContext.OperationId; var requestId = message.RequestId; var expectedResponseType = ExpectedResponseType.None; int numberOfDocuments = 0; int gleRequestId; WriteConcern writeConcern; if (TryGetWriteConcernFromGLE(messageQueue, out gleRequestId, out writeConcern)) { requestId = gleRequestId; expectedResponseType = ExpectedResponseType.GLE; } if (_startedEvent != null) { // InsertMessage is generic, and we don't know the generic type... // Plus, for this we really want BsonDocuments, not whatever the generic type is. var decodedMessage = encoder.ReadMessage(); var documents = decodedMessage.DocumentSource.GetBatchItems(); numberOfDocuments = documents.Count; try { var command = new BsonDocument { { commandName, decodedMessage.CollectionNamespace.CollectionName }, { "documents", new BsonArray(documents) }, { "ordered", !decodedMessage.ContinueOnError } }; if (writeConcern == null) { command["writeConcern"] = WriteConcern.Unacknowledged.ToBsonDocument(); } else if (!writeConcern.IsServerDefault) { command["writeConcern"] = writeConcern.ToBsonDocument(); } var @event = new CommandStartedEvent( commandName, command, decodedMessage.CollectionNamespace.DatabaseNamespace, operationId, requestId, connectionId); _startedEvent(@event); } finally { foreach (var document in documents) { document.Dispose(); } } } if (_shouldTrackState) { _state.TryAdd(requestId, new CommandState { CommandName = commandName, OperationId = operationId, Stopwatch = stopwatch, ExpectedResponseType = expectedResponseType, NumberOfInsertedDocuments = numberOfDocuments }); } }
private void ProcessQueryMessage(QueryMessage originalMessage, ConnectionId connectionId, QueryMessageBinaryEncoder encoder, Stopwatch stopwatch) { var requestId = originalMessage.RequestId; var operationId = EventContext.OperationId; var decodedMessage = encoder.ReadMessage(RawBsonDocumentSerializer.Instance); try { var isCommand = IsCommand(decodedMessage.CollectionNamespace); string commandName; BsonDocument command; if (isCommand) { command = decodedMessage.Query; var firstElement = command.GetElement(0); commandName = firstElement.Name; if (__securitySensitiveCommands.Contains(commandName)) { command = new BsonDocument(); } } else { commandName = "find"; command = BuildFindCommandFromQuery(decodedMessage); if (decodedMessage.Query.GetValue("$explain", false).ToBoolean()) { commandName = "explain"; command = new BsonDocument("explain", command); } } if (_startedEvent != null) { var @event = new CommandStartedEvent( commandName, command, decodedMessage.CollectionNamespace.DatabaseNamespace, operationId, requestId, connectionId); _startedEvent(@event); } if (_shouldTrackState) { _state.TryAdd(requestId, new CommandState { CommandName = commandName, OperationId = operationId, Stopwatch = stopwatch, QueryNamespace = decodedMessage.CollectionNamespace, ExpectedResponseType = isCommand ? ExpectedResponseType.Command : ExpectedResponseType.Query }); } } finally { var disposable = decodedMessage.Query as IDisposable; if (disposable != null) { disposable.Dispose(); } disposable = decodedMessage.Fields as IDisposable; if (disposable != null) { disposable.Dispose(); } } }
/// <summary> /// Returns a new instance of ConnectionDescription with a different connection identifier. /// </summary> /// <param name="value">The value.</param> /// <returns>A connection description.</returns> public ConnectionDescription WithConnectionId(ConnectionId value) { return(_connectionId.StructurallyEquals(value) ? this : new ConnectionDescription(value, _helloResult)); }
private void ProcessDeleteMessage(DeleteMessage originalMessage, Queue <RequestMessage> messageQueue, ConnectionId connectionId, DeleteMessageBinaryEncoder encoder, Stopwatch stopwatch) { var commandName = "delete"; var operationId = EventContext.OperationId; int requestId = originalMessage.RequestId; var expectedResponseType = ExpectedResponseType.None; int gleRequestId; WriteConcern writeConcern; if (TryGetWriteConcernFromGLE(messageQueue, out gleRequestId, out writeConcern)) { requestId = gleRequestId; expectedResponseType = ExpectedResponseType.GLE; } if (_startedEvent != null) { var decodedMessage = encoder.ReadMessage(RawBsonDocumentSerializer.Instance); try { var entry = new BsonDocument { { "q", decodedMessage.Query }, { "limit", decodedMessage.IsMulti ? 0 : 1 } }; var command = new BsonDocument { { commandName, decodedMessage.CollectionNamespace.CollectionName }, { "deletes", new BsonArray(new [] { entry }) } }; if (writeConcern == null) { command["writeConcern"] = WriteConcern.Unacknowledged.ToBsonDocument(); } else if (!writeConcern.IsServerDefault) { command["writeConcern"] = writeConcern.ToBsonDocument(); } var @event = new CommandStartedEvent( commandName, command, decodedMessage.CollectionNamespace.DatabaseNamespace, operationId, requestId, connectionId); _startedEvent(@event); } finally { var disposable = decodedMessage.Query as IDisposable; if (disposable != null) { disposable.Dispose(); } } } if (_shouldTrackState) { _state.TryAdd(requestId, new CommandState { CommandName = commandName, OperationId = operationId, Stopwatch = stopwatch, ExpectedResponseType = expectedResponseType }); } }
private void ProcessCommandResponseMessage(CommandState state, CommandResponseMessage message, IByteBuffer buffer, ConnectionId connectionId, ObjectId?serviceId, MessageEncoderSettings encoderSettings) { var wrappedMessage = message.WrappedMessage; var type0Section = wrappedMessage.Sections.OfType <Type0CommandMessageSection <RawBsonDocument> >().Single(); var reply = (BsonDocument)type0Section.Document; BsonValue ok; if (!reply.TryGetValue("ok", out ok)) { // this is a degenerate case with the server and // we don't really know what to do here... return; } if (state.ShouldRedactReply) { reply = new BsonDocument(); } if (ok.ToBoolean()) { if (_succeededEvent != null) { _succeededEvent(new CommandSucceededEvent( state.CommandName, reply, state.OperationId, message.ResponseTo, connectionId, serviceId, state.Stopwatch.Elapsed)); } } else { if (_failedEvent != null) { _failedEvent(new CommandFailedEvent( state.CommandName, new MongoCommandException( connectionId, string.Format("{0} command failed", state.CommandName), null, reply), state.OperationId, message.ResponseTo, connectionId, serviceId, state.Stopwatch.Elapsed)); } } }
private void ProcessUpdateMessage(UpdateMessage originalMessage, Queue <RequestMessage> messageQueue, ConnectionId connectionId, UpdateMessageBinaryEncoder encoder, Stopwatch stopwatch) { var commandName = "update"; int requestId = originalMessage.RequestId; var operationId = EventContext.OperationId; var expectedResponseType = ExpectedResponseType.None; BsonValue upsertedId = null; int gleRequestId; WriteConcern writeConcern; if (TryGetWriteConcernFromGLE(messageQueue, out gleRequestId, out writeConcern)) { requestId = gleRequestId; expectedResponseType = ExpectedResponseType.GLE; } if (_startedEvent != null) { var decodedMessage = encoder.ReadMessage(RawBsonDocumentSerializer.Instance); try { if (_shouldTrackState) { // GLE result on older versions of the server didn't return // the upserted id when it wasn't an object id, so we'll // attempt to get it from the messages. if (!decodedMessage.Update.TryGetValue("_id", out upsertedId)) { decodedMessage.Query.TryGetValue("_id", out upsertedId); } } var entry = new BsonDocument { { "q", decodedMessage.Query }, { "u", decodedMessage.Update }, { "upsert", decodedMessage.IsUpsert }, { "multi", decodedMessage.IsMulti } }; var command = new BsonDocument { { commandName, decodedMessage.CollectionNamespace.CollectionName }, { "updates", new BsonArray(new [] { entry }) } }; if (writeConcern == null) { command["writeConcern"] = WriteConcern.Unacknowledged.ToBsonDocument(); } else if (!writeConcern.IsServerDefault) { command["writeConcern"] = writeConcern.ToBsonDocument(); } var @event = new CommandStartedEvent( commandName, command, decodedMessage.CollectionNamespace.DatabaseNamespace, operationId, requestId, connectionId); _startedEvent(@event); } finally { var disposable = decodedMessage.Query as IDisposable; if (disposable != null) { disposable.Dispose(); } disposable = decodedMessage.Update as IDisposable; if (disposable != null) { disposable.Dispose(); } } } if (_shouldTrackState) { _state.TryAdd(requestId, new CommandState { CommandName = commandName, OperationId = operationId, Stopwatch = Stopwatch.StartNew(), ExpectedResponseType = expectedResponseType, UpsertedId = upsertedId }); } }
private void ProcessCommandRequestMessage(CommandRequestMessage originalMessage, Queue <RequestMessage> messageQueue, ConnectionId connectionId, ObjectId?serviceId, CommandMessageBinaryEncoder encoder, Stopwatch stopwatch) { var requestId = originalMessage.RequestId; var operationId = EventContext.OperationId; var decodedMessage = encoder.ReadMessage(); using (new CommandMessageDisposer(decodedMessage)) { var type0Section = decodedMessage.Sections.OfType <Type0CommandMessageSection>().Single(); var command = (BsonDocument)type0Section.Document; var type1Sections = decodedMessage.Sections.OfType <Type1CommandMessageSection>().ToList(); if (type1Sections.Count > 0) { command = new BsonDocument(command); // materialize the top level of the command RawBsonDocument foreach (var type1Section in type1Sections) { var name = type1Section.Identifier; var items = new BsonArray(type1Section.Documents.GetBatchItems().Cast <RawBsonDocument>()); command[name] = items; } } var commandName = command.GetElement(0).Name; var databaseName = command["$db"].AsString; var databaseNamespace = new DatabaseNamespace(databaseName); var shouldRedactCommand = ShouldRedactCommand(command); if (shouldRedactCommand) { command = new BsonDocument(); } if (_startedEvent != null) { var @event = new CommandStartedEvent( commandName, command, databaseNamespace, operationId, requestId, connectionId, serviceId); _startedEvent(@event); } if (_shouldTrackState) { _state.TryAdd(requestId, new CommandState { CommandName = commandName, OperationId = operationId, Stopwatch = stopwatch, QueryNamespace = new CollectionNamespace(databaseNamespace, "$cmd"), ExpectedResponseType = decodedMessage.MoreToCome ? ExpectedResponseType.None : ExpectedResponseType.Command, ShouldRedactReply = shouldRedactCommand }); } } }
public void LocalValue_should_be_what_was_specified_in_the_constructor() { var subject = new ConnectionId(__serverId, 10); subject.LocalValue.Should().Be(10); }
/// <summary> /// Returns a new instance of ConnectionDescription with a different connection identifier. /// </summary> /// <param name="value">The value.</param> /// <returns>A connection description.</returns> public ConnectionDescription WithConnectionId(ConnectionId value) { return(_connectionId.StructurallyEquals(value) ? this : new ConnectionDescription(value, _isMasterResult, _buildInfoResult)); }
public async Task <ConnectionDescription> InitializeConnectionAsync(IConnection connection, ConnectionId connectionId, TimeSpan timeout, CancellationToken cancellationToken) { Ensure.IsNotNull(connection, "connection"); Ensure.IsNotNull(connectionId, "connectionId"); Ensure.IsInfiniteOrGreaterThanOrEqualToZero(timeout, "timeout"); var slidingTimeout = new SlidingTimeout(timeout); var isMasterCommand = new BsonDocument("isMaster", 1); var isMasterProtocol = new CommandWireProtocol(DatabaseNamespace.Admin, isMasterCommand, true, null); var isMasterResult = new IsMasterResult(await isMasterProtocol.ExecuteAsync(connection, slidingTimeout, cancellationToken).ConfigureAwait(false)); // authentication is currently broken on arbiters if (!isMasterResult.IsArbiter) { foreach (var authenticator in connection.Settings.Authenticators) { await authenticator.AuthenticateAsync(connection, slidingTimeout, cancellationToken).ConfigureAwait(false); } } var buildInfoCommand = new BsonDocument("buildInfo", 1); var buildInfoProtocol = new CommandWireProtocol(DatabaseNamespace.Admin, buildInfoCommand, true, null); var buildInfoResult = new BuildInfoResult(await buildInfoProtocol.ExecuteAsync(connection, slidingTimeout, cancellationToken).ConfigureAwait(false)); var getLastErrorCommand = new BsonDocument("getLastError", 1); var getLastErrorProtocol = new CommandWireProtocol(DatabaseNamespace.Admin, getLastErrorCommand, true, null); var getLastErrorResult = await getLastErrorProtocol.ExecuteAsync(connection, slidingTimeout, cancellationToken).ConfigureAwait(false); BsonValue connectionIdBsonValue; if (getLastErrorResult.TryGetValue("connectionId", out connectionIdBsonValue)) { connectionId = connectionId.WithServerValue(connectionIdBsonValue.ToInt32()); } return(new ConnectionDescription(connectionId, isMasterResult, buildInfoResult)); }
private void ProcessCommandRequestMessage(CommandRequestMessage originalMessage, Queue <RequestMessage> messageQueue, ConnectionId connectionId, CommandMessageBinaryEncoder encoder, Stopwatch stopwatch) { var requestId = originalMessage.RequestId; var operationId = EventContext.OperationId; var decodedMessage = encoder.ReadMessage(); using (new CommandMessageDisposer(decodedMessage)) { var type0Section = decodedMessage.Sections.OfType <Type0CommandMessageSection>().Single(); var command = (BsonDocument)type0Section.Document; var commandName = command.GetElement(0).Name; var databaseName = command["$db"].AsString; var databaseNamespace = new DatabaseNamespace(databaseName); if (__securitySensitiveCommands.Contains(commandName)) { command = new BsonDocument(); } if (_startedEvent != null) { var @event = new CommandStartedEvent( commandName, command, databaseNamespace, operationId, requestId, connectionId); _startedEvent(@event); } if (_shouldTrackState) { _state.TryAdd(requestId, new CommandState { CommandName = commandName, OperationId = operationId, Stopwatch = stopwatch, QueryNamespace = new CollectionNamespace(databaseNamespace, "$cmd"), ExpectedResponseType = ExpectedResponseType.Command }); } } }