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
                });
            }
        }
Пример #2
0
 private void VerifyCommandStartedEvent(CommandStartedEvent actual, BsonDocument expected, string databaseName, string collectionName)
 {
     actual.CommandName.Should().Be(expected["command_name"].ToString());
     actual.DatabaseNamespace.Should().Be(new DatabaseNamespace(databaseName));
     var command = MassageCommand(actual.CommandName, actual.Command);
     command.Should().BeEquivalentTo((BsonDocument)expected["command"]);
 }
        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();
                }
            }
        }
        private void ProcessKillCursorsMessages(KillCursorsMessage originalMessage, ConnectionId connectionId, Stopwatch stopwatch)
        {
            const string commandName = "killCursors";
            var operationId = EventContext.OperationId;

            if (_startedEvent != null)
            {
                var collectionNamespace = EventContext.KillCursorsCollectionNamespace ?? DatabaseNamespace.Admin.CommandCollection;
                var command = new BsonDocument
                {
                    { commandName, collectionNamespace.CollectionName },
                    { "cursors", new BsonArray(originalMessage.CursorIds) }
                };

                var @event = new CommandStartedEvent(
                    commandName,
                    command,
                    collectionNamespace.DatabaseNamespace,
                    operationId,
                    originalMessage.RequestId,
                    connectionId);

                _startedEvent(@event);
            }

            if (_shouldTrackState)
            {
                _state.TryAdd(originalMessage.RequestId, new CommandState
                {
                    CommandName = commandName,
                    OperationId = operationId,
                    Stopwatch = stopwatch,
                    ExpectedResponseType = ExpectedResponseType.None,
                    NoResponseResponse = new BsonDocument
                    {
                        { "ok", 1 },
                        { "cursorsUnknown", new BsonArray(originalMessage.CursorIds) }
                    }
                });
            }
        }
        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.GetRemainingItems().ToList();
                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
                {
                    documents.ForEach(d => d.Dispose());
                }
            }

            if (_shouldTrackState)
            {
                _state.TryAdd(requestId, new CommandState
                {
                    CommandName = commandName,
                    OperationId = operationId,
                    Stopwatch = stopwatch,
                    ExpectedResponseType = expectedResponseType,
                    NumberOfInsertedDocuments = numberOfDocuments
                });
            }
        }
        private void ProcessGetMoreMessage(GetMoreMessage originalMessage, ConnectionId connectionId, Stopwatch stopwatch)
        {
            var commandName = "getMore";
            var operationId = EventContext.OperationId;
            if (_startedEvent != null)
            {
                var command = new BsonDocument
                {
                    { commandName, originalMessage.CursorId },
                    { "collection",  originalMessage.CollectionNamespace.CollectionName },
                    { "batchSize", originalMessage.BatchSize, originalMessage.BatchSize > 0 }
                };

                var @event = new CommandStartedEvent(
                    "getMore",
                    command,
                    originalMessage.CollectionNamespace.DatabaseNamespace,
                    operationId,
                    originalMessage.RequestId,
                    connectionId);

                _startedEvent(@event);
            }

            if (_shouldTrackState)
            {
                _state.TryAdd(originalMessage.RequestId, new CommandState
                {
                    CommandName = commandName,
                    OperationId = operationId,
                    Stopwatch = stopwatch,
                    QueryNamespace = originalMessage.CollectionNamespace,
                    ExpectedResponseType = ExpectedResponseType.Query
                });
            }
        }
        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
                });
            }
        }