From 4ca75413b391a35284e134a7fe5196ebc0795b91 Mon Sep 17 00:00:00 2001 From: Oleksandr Poliakov Date: Wed, 23 Apr 2025 17:07:45 -0700 Subject: [PATCH 01/14] CSHARP-5560: CSOT: Refactor IOperationExecutor to use operation context --- .editorconfig | 8 +- src/MongoDB.Driver/AggregateHelper.cs | 96 ++ src/MongoDB.Driver/IOperationExecutor.cs | 34 +- src/MongoDB.Driver/MongoClient.cs | 527 +++---- src/MongoDB.Driver/MongoCollectionImpl.cs | 1361 +++++++---------- src/MongoDB.Driver/MongoDatabase.cs | 727 ++++----- src/MongoDB.Driver/OperationExecutor.cs | 158 +- src/MongoDB.Driver/ReadOperationOptions.cs | 42 + src/MongoDB.Driver/ReadPreferenceResolver.cs | 42 - src/MongoDB.Driver/WriteOperationOptions.cs | 20 + .../MockOperationExecutor.cs | 52 +- .../MongoDB.Driver.Tests/MongoClientTests.cs | 11 +- ...oDatabasTests.cs => MongoDatabaseTests.cs} | 20 +- .../OperationExecutorTests.cs | 117 ++ .../ReadOperationOptionsTests.cs | 70 + 15 files changed, 1605 insertions(+), 1680 deletions(-) create mode 100644 src/MongoDB.Driver/AggregateHelper.cs create mode 100644 src/MongoDB.Driver/ReadOperationOptions.cs delete mode 100644 src/MongoDB.Driver/ReadPreferenceResolver.cs create mode 100644 src/MongoDB.Driver/WriteOperationOptions.cs rename tests/MongoDB.Driver.Tests/{MongoDatabasTests.cs => MongoDatabaseTests.cs} (98%) create mode 100644 tests/MongoDB.Driver.Tests/OperationExecutorTests.cs create mode 100644 tests/MongoDB.Driver.Tests/ReadOperationOptionsTests.cs diff --git a/.editorconfig b/.editorconfig index 1ab98bee463..482cea58e85 100644 --- a/.editorconfig +++ b/.editorconfig @@ -47,10 +47,10 @@ dotnet_style_qualification_for_property = false:suggestion dotnet_style_qualification_for_method = false:suggestion dotnet_style_qualification_for_event = false:suggestion -# Types: use keywords instead of BCL types, and permit var only when the type is clear -csharp_style_var_for_built_in_types = false:suggestion -csharp_style_var_when_type_is_apparent = false:none -csharp_style_var_elsewhere = false:suggestion +# Types: use keywords instead of BCL types, and prefer var instead of the explicit type +csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_when_type_is_apparent = true:suggestion +csharp_style_var_elsewhere = true:suggestion dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion dotnet_style_predefined_type_for_member_access = true:suggestion diff --git a/src/MongoDB.Driver/AggregateHelper.cs b/src/MongoDB.Driver/AggregateHelper.cs new file mode 100644 index 00000000000..c61628b5330 --- /dev/null +++ b/src/MongoDB.Driver/AggregateHelper.cs @@ -0,0 +1,96 @@ +/* Copyright 2010-present MongoDB Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Linq; +using MongoDB.Bson; + +namespace MongoDB.Driver +{ + internal static class AggregateHelper + { + public static RenderedPipelineDefinition RenderAggregatePipeline(PipelineDefinition pipeline, RenderArgs renderArgs, out bool isAggregateToCollection) + { + var renderedPipeline = pipeline.Render(renderArgs); + + var lastStage = renderedPipeline.Documents.LastOrDefault(); + var lastStageName = lastStage?.GetElement(0).Name; + isAggregateToCollection = lastStageName == "$out" || lastStageName == "$merge"; + + return renderedPipeline; + } + + public static CollectionNamespace GetOutCollection(BsonDocument outStage, DatabaseNamespace defaultDatabaseNamespace) + { + var stageName = outStage.GetElement(0).Name; + switch (stageName) + { + case "$out": + { + var outValue = outStage[0]; + DatabaseNamespace outputDatabaseNamespace; + string outputCollectionName; + if (outValue.IsString) + { + outputDatabaseNamespace = defaultDatabaseNamespace; + outputCollectionName = outValue.AsString; + } + else + { + outputDatabaseNamespace = new DatabaseNamespace(outValue["db"].AsString); + outputCollectionName = outValue["coll"].AsString; + } + return new CollectionNamespace(outputDatabaseNamespace, outputCollectionName); + } + case "$merge": + { + var mergeArguments = outStage[0]; + DatabaseNamespace outputDatabaseNamespace; + string outputCollectionName; + if (mergeArguments.IsString) + { + outputDatabaseNamespace = defaultDatabaseNamespace; + outputCollectionName = mergeArguments.AsString; + } + else + { + var into = mergeArguments.AsBsonDocument["into"]; + if (into.IsString) + { + outputDatabaseNamespace = defaultDatabaseNamespace; + outputCollectionName = into.AsString; + } + else + { + if (into.AsBsonDocument.Contains("db")) + { + outputDatabaseNamespace = new DatabaseNamespace(into["db"].AsString); + } + else + { + outputDatabaseNamespace = defaultDatabaseNamespace; + } + outputCollectionName = into["coll"].AsString; + } + } + return new CollectionNamespace(outputDatabaseNamespace, outputCollectionName); + } + default: + throw new ArgumentException($"Unexpected stage name: {stageName}."); + } + } + } +} + diff --git a/src/MongoDB.Driver/IOperationExecutor.cs b/src/MongoDB.Driver/IOperationExecutor.cs index 1af86d6ff62..556017387a5 100644 --- a/src/MongoDB.Driver/IOperationExecutor.cs +++ b/src/MongoDB.Driver/IOperationExecutor.cs @@ -16,20 +16,42 @@ using System; using System.Threading; using System.Threading.Tasks; -using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Operations; namespace MongoDB.Driver { - internal interface IOperationExecutor + internal interface IOperationExecutor : IDisposable { - TResult ExecuteReadOperation(IReadBinding binding, IReadOperation operation, CancellationToken cancellationToken); - Task ExecuteReadOperationAsync(IReadBinding binding, IReadOperation operation, CancellationToken cancellationToken); + TResult ExecuteReadOperation( + IReadOperation operation, + ReadOperationOptions options, + IClientSessionHandle session = null, + bool disableChannelPinning = false, + CancellationToken cancellationToken = default); - TResult ExecuteWriteOperation(IWriteBinding binding, IWriteOperation operation, CancellationToken cancellationToken); - Task ExecuteWriteOperationAsync(IWriteBinding binding, IWriteOperation operation, CancellationToken cancellationToken); + Task ExecuteReadOperationAsync( + IReadOperation operation, + ReadOperationOptions options, + IClientSessionHandle session = null, + bool disableChannelPinning = false, + CancellationToken cancellationToken = default); + + TResult ExecuteWriteOperation( + IWriteOperation operation, + WriteOperationOptions options, + IClientSessionHandle session = null, + bool disableChannelPinning = false, + CancellationToken cancellationToken = default); + + Task ExecuteWriteOperationAsync( + IWriteOperation operation, + WriteOperationOptions options, + IClientSessionHandle session = null, + bool disableChannelPinning = false, + CancellationToken cancellationToken = default); IClientSessionHandle StartImplicitSession(CancellationToken cancellationToken); + Task StartImplicitSessionAsync(CancellationToken cancellationToken); } } diff --git a/src/MongoDB.Driver/MongoClient.cs b/src/MongoDB.Driver/MongoClient.cs index 0fa1b4eb8d2..33f6753c49e 100644 --- a/src/MongoDB.Driver/MongoClient.cs +++ b/src/MongoDB.Driver/MongoClient.cs @@ -23,7 +23,6 @@ using MongoDB.Bson.IO; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; -using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Clusters; using MongoDB.Driver.Core.Logging; using MongoDB.Driver.Core.Misc; @@ -42,9 +41,12 @@ public sealed class MongoClient : IMongoClient private readonly IClusterInternal _cluster; #pragma warning restore CA2213 // Disposable fields should be disposed private readonly IAutoEncryptionLibMongoCryptController _libMongoCryptController; + private readonly Func _operationExecutorFactory; private readonly IOperationExecutor _operationExecutor; private readonly MongoClientSettings _settings; private readonly ILogger _logger; + private readonly ReadOperationOptions _readOperationOptions; + private readonly WriteOperationOptions _writeOperationOptions; // constructors /// @@ -60,23 +62,9 @@ public MongoClient() /// /// The settings. public MongoClient(MongoClientSettings settings) + : this(client => new OperationExecutor(client), settings) { - _settings = Ensure.IsNotNull(settings, nameof(settings)).FrozenCopy(); - _logger = _settings.LoggingSettings?.CreateLogger(); - - _cluster = _settings.ClusterSource.Get(_settings.ToClusterKey()); - _operationExecutor = new OperationExecutor(this); - if (settings.AutoEncryptionOptions != null) - { - _libMongoCryptController = - MongoClientSettings.Extensions.AutoEncryptionProvider.CreateAutoCryptClientController(this, settings.AutoEncryptionOptions); - _settings.LoggingSettings?.CreateLogger()?.LogTrace( - StructuredLogTemplateProviders.TopologyId_Message_SharedLibraryVersion, - _cluster.ClusterId, - "CryptClient created. Configured shared library version: ", - _libMongoCryptController.CryptSharedLibraryVersion() ?? "None"); - } } /// @@ -97,10 +85,27 @@ public MongoClient(string connectionString) { } - internal MongoClient(IOperationExecutor operationExecutor, MongoClientSettings settings) - : this(settings) + internal MongoClient(Func operationExecutorFactory, MongoClientSettings settings) { - _operationExecutor = operationExecutor; + _operationExecutorFactory = Ensure.IsNotNull(operationExecutorFactory, nameof(operationExecutorFactory)); + _settings = Ensure.IsNotNull(settings, nameof(settings)).FrozenCopy(); + _logger = _settings.LoggingSettings?.CreateLogger(); + _cluster = _settings.ClusterSource.Get(_settings.ToClusterKey()); + _operationExecutor = _operationExecutorFactory(this); + _readOperationOptions = new(DefaultReadPreference: _settings.ReadPreference); + _writeOperationOptions = new(); + + if (settings.AutoEncryptionOptions != null) + { + _libMongoCryptController = + MongoClientSettings.Extensions.AutoEncryptionProvider.CreateAutoCryptClientController(this, settings.AutoEncryptionOptions); + + _settings.LoggingSettings?.CreateLogger()?.LogTrace( + StructuredLogTemplateProviders.TopologyId_Message_SharedLibraryVersion, + _cluster.ClusterId, + "CryptClient created. Configured shared library version: ", + _libMongoCryptController.CryptSharedLibraryVersion() ?? "None"); + } } // public properties @@ -112,13 +117,11 @@ internal MongoClient(IOperationExecutor operationExecutor, MongoClientSettings s // internal properties internal IAutoEncryptionLibMongoCryptController LibMongoCryptController => ThrowIfDisposed(_libMongoCryptController); - internal IOperationExecutor OperationExecutor => ThrowIfDisposed(_operationExecutor); // internal methods internal void ConfigureAutoEncryptionMessageEncoderSettings(MessageEncoderSettings messageEncoderSettings) { ThrowIfDisposed(); - var autoEncryptionOptions = _settings.AutoEncryptionOptions; if (autoEncryptionOptions != null) { @@ -133,33 +136,36 @@ internal void ConfigureAutoEncryptionMessageEncoderSettings(MessageEncoderSettin // public methods /// public ClientBulkWriteResult BulkWrite(IReadOnlyList models, ClientBulkWriteOptions options = null, CancellationToken cancellationToken = default) - => UsingImplicitSession(session => BulkWrite(session, models, options, cancellationToken), cancellationToken); + => _operationExecutor.ExecuteWriteOperation( + CreateClientBulkWriteOperation(models, options), + _writeOperationOptions, + disableChannelPinning: true, + cancellationToken: cancellationToken); /// public ClientBulkWriteResult BulkWrite(IClientSessionHandle session, IReadOnlyList models, ClientBulkWriteOptions options = null, CancellationToken cancellationToken = default) - { - var operation = CreateClientBulkWriteOperation(models, options); - return ExecuteWriteOperation(session, operation, cancellationToken); - } + => _operationExecutor.ExecuteWriteOperation( + CreateClientBulkWriteOperation(models, options), + _writeOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + disableChannelPinning: true, + cancellationToken: cancellationToken); /// public Task BulkWriteAsync(IReadOnlyList models, ClientBulkWriteOptions options = null, CancellationToken cancellationToken = default) - => UsingImplicitSession(session => BulkWriteAsync(session, models, options, cancellationToken), cancellationToken); + => _operationExecutor.ExecuteWriteOperationAsync( + CreateClientBulkWriteOperation(models, options), + _writeOperationOptions, + cancellationToken: cancellationToken); /// public Task BulkWriteAsync(IClientSessionHandle session, IReadOnlyList models, ClientBulkWriteOptions options = null, CancellationToken cancellationToken = default) - { - var operation = CreateClientBulkWriteOperation(models, options); - return ExecuteWriteOperationAsync(session, operation, cancellationToken); - } - - /// - public void DropDatabase(string name, CancellationToken cancellationToken = default(CancellationToken)) - { - ThrowIfDisposed(); - - UsingImplicitSession(session => DropDatabase(session, name, cancellationToken), cancellationToken); - } + => _operationExecutor.ExecuteWriteOperationAsync( + CreateClientBulkWriteOperation(models, options), + _writeOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + disableChannelPinning: true, + cancellationToken: cancellationToken); /// public void Dispose() @@ -180,6 +186,7 @@ public void Dispose(bool disposing) { _logger?.LogDebug(_cluster.ClusterId, "MongoClient disposing"); + _operationExecutor.Dispose(); _settings.ClusterSource.Return(_cluster); _libMongoCryptController?.Dispose(); @@ -191,40 +198,38 @@ public void Dispose(bool disposing) } /// - public void DropDatabase(IClientSessionHandle session, string name, CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - ThrowIfDisposed(); - - var messageEncoderSettings = GetMessageEncoderSettings(); - var operation = new DropDatabaseOperation(new DatabaseNamespace(name), messageEncoderSettings) - { - WriteConcern = _settings.WriteConcern - }; - ExecuteWriteOperation(session, operation, cancellationToken); - } + public void DropDatabase(string name, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteWriteOperation( + CreateDropDatabaseOperation(name), + _writeOperationOptions, + disableChannelPinning: true, + cancellationToken: cancellationToken); /// - public Task DropDatabaseAsync(string name, CancellationToken cancellationToken = default(CancellationToken)) - { - ThrowIfDisposed(); - - return UsingImplicitSessionAsync(session => DropDatabaseAsync(session, name, cancellationToken), cancellationToken); - } + public void DropDatabase(IClientSessionHandle session, string name, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteWriteOperation( + CreateDropDatabaseOperation(name), + _writeOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + disableChannelPinning: true, + cancellationToken: cancellationToken); /// - public Task DropDatabaseAsync(IClientSessionHandle session, string name, CancellationToken cancellationToken = default(CancellationToken)) - { - ThrowIfDisposed(); + public Task DropDatabaseAsync(string name, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteWriteOperationAsync( + CreateDropDatabaseOperation(name), + _writeOperationOptions, + disableChannelPinning: true, + cancellationToken: cancellationToken); - Ensure.IsNotNull(session, nameof(session)); - var messageEncoderSettings = GetMessageEncoderSettings(); - var operation = new DropDatabaseOperation(new DatabaseNamespace(name), messageEncoderSettings) - { - WriteConcern = _settings.WriteConcern - }; - return ExecuteWriteOperationAsync(session, operation, cancellationToken); - } + /// + public Task DropDatabaseAsync(IClientSessionHandle session, string name, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteWriteOperationAsync( + CreateDropDatabaseOperation(name), + _writeOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + disableChannelPinning: true, + cancellationToken: cancellationToken); /// public IMongoDatabase GetDatabase(string name, MongoDatabaseSettings settings = null) @@ -241,205 +246,151 @@ public IMongoDatabase GetDatabase(string name, MongoDatabaseSettings settings = } /// - public IAsyncCursor ListDatabaseNames( - CancellationToken cancellationToken = default(CancellationToken)) - { - ThrowIfDisposed(); - - return ListDatabaseNames(options: null, cancellationToken); - } + public IAsyncCursor ListDatabaseNames(CancellationToken cancellationToken = default) + => ListDatabaseNames(options: null, cancellationToken); /// public IAsyncCursor ListDatabaseNames( ListDatabaseNamesOptions options, - CancellationToken cancellationToken = default(CancellationToken)) + CancellationToken cancellationToken = default) { - ThrowIfDisposed(); - - return UsingImplicitSession(session => ListDatabaseNames(session, options, cancellationToken), cancellationToken); + var listDatabasesOptions = CreateListDatabasesOptionsFromListDatabaseNamesOptions(options); + var databases = ListDatabases(listDatabasesOptions, cancellationToken); + return CreateDatabaseNamesCursor(databases); } /// public IAsyncCursor ListDatabaseNames( IClientSessionHandle session, - CancellationToken cancellationToken = default(CancellationToken)) - { - ThrowIfDisposed(); - - return ListDatabaseNames(session, options: null, cancellationToken); - } + CancellationToken cancellationToken = default) + => ListDatabaseNames(session, options: null, cancellationToken); /// public IAsyncCursor ListDatabaseNames( IClientSessionHandle session, ListDatabaseNamesOptions options, - CancellationToken cancellationToken = default(CancellationToken)) + CancellationToken cancellationToken = default) { - ThrowIfDisposed(); - var listDatabasesOptions = CreateListDatabasesOptionsFromListDatabaseNamesOptions(options); var databases = ListDatabases(session, listDatabasesOptions, cancellationToken); - return CreateDatabaseNamesCursor(databases); } /// - public Task> ListDatabaseNamesAsync( - CancellationToken cancellationToken = default(CancellationToken)) - { - ThrowIfDisposed(); - - return ListDatabaseNamesAsync(options: null, cancellationToken); - } + public Task> ListDatabaseNamesAsync(CancellationToken cancellationToken = default) + => ListDatabaseNamesAsync(options: null, cancellationToken); /// - public Task> ListDatabaseNamesAsync( + public async Task> ListDatabaseNamesAsync( ListDatabaseNamesOptions options, - CancellationToken cancellationToken = default(CancellationToken)) + CancellationToken cancellationToken = default) { - ThrowIfDisposed(); - - return UsingImplicitSessionAsync(session => ListDatabaseNamesAsync(session, options, cancellationToken), cancellationToken); + var listDatabasesOptions = CreateListDatabasesOptionsFromListDatabaseNamesOptions(options); + var databases = await ListDatabasesAsync(listDatabasesOptions, cancellationToken).ConfigureAwait(false); + return CreateDatabaseNamesCursor(databases); } /// public Task> ListDatabaseNamesAsync( IClientSessionHandle session, - CancellationToken cancellationToken = default(CancellationToken)) - { - ThrowIfDisposed(); - - return ListDatabaseNamesAsync(session, options: null, cancellationToken); - } + CancellationToken cancellationToken = default) + => ListDatabaseNamesAsync(session, options: null, cancellationToken); /// public async Task> ListDatabaseNamesAsync( IClientSessionHandle session, ListDatabaseNamesOptions options, - CancellationToken cancellationToken = default(CancellationToken)) + CancellationToken cancellationToken = default) { - ThrowIfDisposed(); - var listDatabasesOptions = CreateListDatabasesOptionsFromListDatabaseNamesOptions(options); var databases = await ListDatabasesAsync(session, listDatabasesOptions, cancellationToken).ConfigureAwait(false); - return CreateDatabaseNamesCursor(databases); } /// - public IAsyncCursor ListDatabases( - CancellationToken cancellationToken = default(CancellationToken)) - { - ThrowIfDisposed(); - - return UsingImplicitSession(session => ListDatabases(session, cancellationToken), cancellationToken); - } + public IAsyncCursor ListDatabases(CancellationToken cancellationToken) + => _operationExecutor.ExecuteReadOperation( + CreateListDatabaseOperation(null), + _readOperationOptions, + disableChannelPinning: true, + cancellationToken: cancellationToken); /// public IAsyncCursor ListDatabases( ListDatabasesOptions options, - CancellationToken cancellationToken = default(CancellationToken)) - { - ThrowIfDisposed(); - - return UsingImplicitSession(session => ListDatabases(session, options, cancellationToken), cancellationToken); - } + CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperation( + CreateListDatabaseOperation(options), + _readOperationOptions, + disableChannelPinning: true, + cancellationToken: cancellationToken); /// public IAsyncCursor ListDatabases( IClientSessionHandle session, - CancellationToken cancellationToken = default(CancellationToken)) - { - ThrowIfDisposed(); - - return ListDatabases(session, null, cancellationToken); - } + CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperation( + CreateListDatabaseOperation(null), + _readOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + disableChannelPinning: true, + cancellationToken: cancellationToken); /// public IAsyncCursor ListDatabases( IClientSessionHandle session, ListDatabasesOptions options, - CancellationToken cancellationToken = default(CancellationToken)) - { - ThrowIfDisposed(); - - Ensure.IsNotNull(session, nameof(session)); - options = options ?? new ListDatabasesOptions(); - var messageEncoderSettings = GetMessageEncoderSettings(); - var translationOptions = _settings.TranslationOptions; - var operation = CreateListDatabaseOperation(options, messageEncoderSettings, translationOptions); - return ExecuteReadOperation(session, operation, cancellationToken); - } + CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperation( + CreateListDatabaseOperation(options), + _readOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + disableChannelPinning: true, + cancellationToken: cancellationToken); /// - public Task> ListDatabasesAsync( - CancellationToken cancellationToken = default(CancellationToken)) - { - ThrowIfDisposed(); - - return UsingImplicitSessionAsync(session => ListDatabasesAsync(session, null, cancellationToken), cancellationToken); - } + public Task> ListDatabasesAsync(CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperationAsync( + CreateListDatabaseOperation(null), + _readOperationOptions, + disableChannelPinning: true, + cancellationToken: cancellationToken); /// public Task> ListDatabasesAsync( ListDatabasesOptions options, - CancellationToken cancellationToken = default(CancellationToken)) - { - ThrowIfDisposed(); - - return UsingImplicitSessionAsync(session => ListDatabasesAsync(session, options, cancellationToken), cancellationToken); - } + CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperationAsync( + CreateListDatabaseOperation(options), + _readOperationOptions, + disableChannelPinning: true, + cancellationToken: cancellationToken); /// public Task> ListDatabasesAsync( IClientSessionHandle session, - CancellationToken cancellationToken = default(CancellationToken)) - { - ThrowIfDisposed(); - - return ListDatabasesAsync(session, null, cancellationToken); - } + CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperationAsync( + CreateListDatabaseOperation(null), + _readOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + disableChannelPinning: true, + cancellationToken: cancellationToken); /// public Task> ListDatabasesAsync( IClientSessionHandle session, ListDatabasesOptions options, - CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - ThrowIfDisposed(); - - options = options ?? new ListDatabasesOptions(); - var messageEncoderSettings = GetMessageEncoderSettings(); - var translationOptions = _settings.TranslationOptions; - var operation = CreateListDatabaseOperation(options, messageEncoderSettings, translationOptions); - return ExecuteReadOperationAsync(session, operation, cancellationToken); - } - - /// - /// Starts an implicit session. - /// - /// A session. - internal IClientSessionHandle StartImplicitSession(CancellationToken cancellationToken) - { - ThrowIfDisposed(); - - return StartImplicitSession(); - } - - /// - /// Starts an implicit session. - /// - /// A Task whose result is a session. - internal Task StartImplicitSessionAsync(CancellationToken cancellationToken) - { - ThrowIfDisposed(); - - return Task.FromResult(StartImplicitSession()); - } + CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperationAsync( + CreateListDatabaseOperation(options), + _readOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + disableChannelPinning: true, + cancellationToken: cancellationToken); /// - public IClientSessionHandle StartSession(ClientSessionOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) + public IClientSessionHandle StartSession(ClientSessionOptions options = null, CancellationToken cancellationToken = default) { ThrowIfDisposed(); @@ -447,7 +398,7 @@ internal Task StartImplicitSessionAsync(CancellationToken } /// - public Task StartSessionAsync(ClientSessionOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) + public Task StartSessionAsync(ClientSessionOptions options = null, CancellationToken cancellationToken = default) { ThrowIfDisposed(); @@ -458,56 +409,49 @@ internal Task StartImplicitSessionAsync(CancellationToken public IChangeStreamCursor Watch( PipelineDefinition, TResult> pipeline, ChangeStreamOptions options = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - ThrowIfDisposed(); - - return UsingImplicitSession(session => Watch(session, pipeline, options, cancellationToken), cancellationToken); - } + CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperation( + CreateChangeStreamOperation(pipeline, options), + _readOperationOptions, + disableChannelPinning: true, + cancellationToken: cancellationToken); /// public IChangeStreamCursor Watch( IClientSessionHandle session, PipelineDefinition, TResult> pipeline, ChangeStreamOptions options = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(pipeline, nameof(pipeline)); - ThrowIfDisposed(); - - var translationOptions = _settings.TranslationOptions; - var operation = CreateChangeStreamOperation(pipeline, options, translationOptions); - return ExecuteReadOperation(session, operation, cancellationToken); - } + CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperation( + CreateChangeStreamOperation(pipeline, options), + _readOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + disableChannelPinning: true, + cancellationToken: cancellationToken); /// public Task> WatchAsync( PipelineDefinition, TResult> pipeline, ChangeStreamOptions options = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - ThrowIfDisposed(); - - return UsingImplicitSessionAsync(session => WatchAsync(session, pipeline, options, cancellationToken), cancellationToken); - } + CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperationAsync( + CreateChangeStreamOperation(pipeline, options), + _readOperationOptions, + disableChannelPinning: true, + cancellationToken: cancellationToken); /// public Task> WatchAsync( IClientSessionHandle session, PipelineDefinition, TResult> pipeline, ChangeStreamOptions options = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(pipeline, nameof(pipeline)); - - ThrowIfDisposed(); - - var translationOptions = _settings.TranslationOptions; - var operation = CreateChangeStreamOperation(pipeline, options, translationOptions); - return ExecuteReadOperationAsync(session, operation, cancellationToken); - } + CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperationAsync( + CreateChangeStreamOperation(pipeline, options), + _readOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + disableChannelPinning: true, + cancellationToken: cancellationToken); /// public IMongoClient WithReadConcern(ReadConcern readConcern) @@ -518,7 +462,7 @@ public IMongoClient WithReadConcern(ReadConcern readConcern) var newSettings = Settings.Clone(); newSettings.ReadConcern = readConcern; - return new MongoClient(_operationExecutor, newSettings); + return new MongoClient(_operationExecutorFactory, newSettings); } /// @@ -530,7 +474,7 @@ public IMongoClient WithReadPreference(ReadPreference readPreference) var newSettings = Settings.Clone(); newSettings.ReadPreference = readPreference; - return new MongoClient(_operationExecutor, newSettings); + return new MongoClient(_operationExecutorFactory, newSettings); } /// @@ -542,11 +486,11 @@ public IMongoClient WithWriteConcern(WriteConcern writeConcern) var newSettings = Settings.Clone(); newSettings.WriteConcern = writeConcern; - return new MongoClient(_operationExecutor, newSettings); + return new MongoClient(_operationExecutorFactory, newSettings); } // private methods - private ClientBulkWriteOperation CreateClientBulkWriteOperation(IReadOnlyList models, ClientBulkWriteOptions options = null) + private ClientBulkWriteOperation CreateClientBulkWriteOperation(IReadOnlyList models, ClientBulkWriteOptions options) { if (_settings.AutoEncryptionOptions != null) { @@ -578,17 +522,22 @@ private ClientBulkWriteOperation CreateClientBulkWriteOperation(IReadOnlyList CreateDatabaseNamesCursor(IAsyncCursor cursor) - { - return new BatchTransformingAsyncCursor( + => new BatchTransformingAsyncCursor( cursor, databases => databases.Select(database => database["name"].AsString)); - } - private ListDatabasesOperation CreateListDatabaseOperation( - ListDatabasesOptions options, - MessageEncoderSettings messageEncoderSettings, - ExpressionTranslationOptions translationOptions) + private DropDatabaseOperation CreateDropDatabaseOperation(string name) + => new(new DatabaseNamespace(name), GetMessageEncoderSettings()) + { + WriteConcern = _settings.WriteConcern + }; + + private ListDatabasesOperation CreateListDatabaseOperation(ListDatabasesOptions options) { + options ??= new ListDatabasesOptions(); + var messageEncoderSettings = GetMessageEncoderSettings(); + var translationOptions = _settings.TranslationOptions; + return new ListDatabasesOperation(messageEncoderSettings) { AuthorizedDatabases = options.AuthorizedDatabases, @@ -612,69 +561,16 @@ private ListDatabasesOptions CreateListDatabasesOptionsFromListDatabaseNamesOpti return listDatabasesOptions; } - private IReadBindingHandle CreateReadBinding(IClientSessionHandle session) - { - var readPreference = _settings.ReadPreference; - if (session.IsInTransaction && readPreference.ReadPreferenceMode != ReadPreferenceMode.Primary) - { - throw new InvalidOperationException("Read preference in a transaction must be primary."); - } - - var binding = new ReadPreferenceBinding(_cluster, readPreference, session.WrappedCoreSession.Fork()); - return new ReadBindingHandle(binding); - } - - private IReadWriteBindingHandle CreateReadWriteBinding(IClientSessionHandle session) - { - var binding = new WritableServerBinding(_cluster, session.WrappedCoreSession.Fork()); - return new ReadWriteBindingHandle(binding); - } - private ChangeStreamOperation CreateChangeStreamOperation( PipelineDefinition, TResult> pipeline, - ChangeStreamOptions options, - ExpressionTranslationOptions translationOptions) - { - return ChangeStreamHelper.CreateChangeStreamOperation( - pipeline, + ChangeStreamOptions options) + => ChangeStreamHelper.CreateChangeStreamOperation( + Ensure.IsNotNull(pipeline, nameof(pipeline)), options, _settings.ReadConcern, GetMessageEncoderSettings(), _settings.RetryReads, - translationOptions); - } - - private TResult ExecuteReadOperation(IClientSessionHandle session, IReadOperation operation, CancellationToken cancellationToken = default(CancellationToken)) - { - using (var binding = CreateReadBinding(session)) - { - return _operationExecutor.ExecuteReadOperation(binding, operation, cancellationToken); - } - } - - private async Task ExecuteReadOperationAsync(IClientSessionHandle session, IReadOperation operation, CancellationToken cancellationToken = default(CancellationToken)) - { - using (var binding = CreateReadBinding(session)) - { - return await _operationExecutor.ExecuteReadOperationAsync(binding, operation, cancellationToken).ConfigureAwait(false); - } - } - - private TResult ExecuteWriteOperation(IClientSessionHandle session, IWriteOperation operation, CancellationToken cancellationToken = default(CancellationToken)) - { - using (var binding = CreateReadWriteBinding(session)) - { - return _operationExecutor.ExecuteWriteOperation(binding, operation, cancellationToken); - } - } - - private async Task ExecuteWriteOperationAsync(IClientSessionHandle session, IWriteOperation operation, CancellationToken cancellationToken = default(CancellationToken)) - { - using (var binding = CreateReadWriteBinding(session)) - { - return await _operationExecutor.ExecuteWriteOperationAsync(binding, operation, cancellationToken).ConfigureAwait(false); - } - } + _settings.TranslationOptions); private MessageEncoderSettings GetMessageEncoderSettings() { @@ -696,13 +592,6 @@ private RenderArgs GetRenderArgs() return new RenderArgs(BsonDocumentSerializer.Instance, serializerRegistry, translationOptions: translationOptions); } - private IClientSessionHandle StartImplicitSession() - { - var options = new ClientSessionOptions { CausalConsistency = false, Snapshot = false }; - ICoreSessionHandle coreSession = _cluster.StartSession(options.ToCore(isImplicit: true)); - return new ClientSessionHandle(this, options, coreSession); - } - private IClientSessionHandle StartSession(ClientSessionOptions options) { if (options != null && options.Snapshot && options.CausalConsistency == true) @@ -718,37 +607,5 @@ private IClientSessionHandle StartSession(ClientSessionOptions options) private void ThrowIfDisposed() => ThrowIfDisposed(string.Empty); private T ThrowIfDisposed(T value) => _disposed ? throw new ObjectDisposedException(GetType().Name) : value; - - private void UsingImplicitSession(Action func, CancellationToken cancellationToken) - { - using (var session = StartImplicitSession(cancellationToken)) - { - func(session); - } - } - - private TResult UsingImplicitSession(Func func, CancellationToken cancellationToken) - { - using (var session = StartImplicitSession(cancellationToken)) - { - return func(session); - } - } - - private async Task UsingImplicitSessionAsync(Func funcAsync, CancellationToken cancellationToken) - { - using (var session = await StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false)) - { - await funcAsync(session).ConfigureAwait(false); - } - } - - private async Task UsingImplicitSessionAsync(Func> funcAsync, CancellationToken cancellationToken) - { - using (var session = await StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false)) - { - return await funcAsync(session).ConfigureAwait(false); - } - } } } diff --git a/src/MongoDB.Driver/MongoCollectionImpl.cs b/src/MongoDB.Driver/MongoCollectionImpl.cs index 51f03dc0a04..33796933e30 100644 --- a/src/MongoDB.Driver/MongoCollectionImpl.cs +++ b/src/MongoDB.Driver/MongoCollectionImpl.cs @@ -21,8 +21,6 @@ using MongoDB.Bson; using MongoDB.Bson.IO; using MongoDB.Bson.Serialization; -using MongoDB.Driver.Core; -using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Clusters; using MongoDB.Driver.Core.Misc; using MongoDB.Driver.Core.Operations; @@ -41,6 +39,8 @@ internal sealed class MongoCollectionImpl : MongoCollectionBase _documentSerializer; private readonly MongoCollectionSettings _settings; + private readonly ReadOperationOptions _readOperationOptions; + private readonly WriteOperationOptions _writeOperationOptions; // constructors public MongoCollectionImpl(IMongoDatabase database, CollectionNamespace collectionNamespace, MongoCollectionSettings settings, IClusterInternal cluster, IOperationExecutor operationExecutor) @@ -58,6 +58,8 @@ private MongoCollectionImpl(IMongoDatabase database, CollectionNamespace collect _documentSerializer = Ensure.IsNotNull(documentSerializer, nameof(documentSerializer)); _messageEncoderSettings = GetMessageEncoderSettings(); + _readOperationOptions = new(DefaultReadPreference: _settings.ReadPreference); + _writeOperationOptions = new(); } // properties @@ -94,160 +96,121 @@ public override MongoCollectionSettings Settings } // public methods - public override IAsyncCursor Aggregate(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default(CancellationToken)) + public override IAsyncCursor Aggregate(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { - return UsingImplicitSession(session => Aggregate(session, pipeline, options, cancellationToken), cancellationToken); + using var session = _operationExecutor.StartImplicitSession(cancellationToken: cancellationToken); + return Aggregate(session, pipeline, options, cancellationToken: cancellationToken); } - public override IAsyncCursor Aggregate(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default(CancellationToken)) + public override IAsyncCursor Aggregate(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); Ensure.IsNotNull(pipeline, nameof(pipeline)); - options = options ?? new AggregateOptions(); + options ??= new AggregateOptions(); var renderArgs = GetRenderArgs(options.TranslationOptions); - var renderedPipeline = pipeline.Render(renderArgs); - - var lastStage = renderedPipeline.Documents.LastOrDefault(); - var lastStageName = lastStage?.GetElement(0).Name; - if (lastStage != null && (lastStageName == "$out" || lastStageName == "$merge")) + var renderedPipeline = AggregateHelper.RenderAggregatePipeline(pipeline, renderArgs, out bool isAggregateToCollection); + if (isAggregateToCollection) { var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - ExecuteWriteOperation(session, aggregateOperation, cancellationToken); - - // we want to delay execution of the find because the user may - // not want to iterate the results at all... - var findOperation = CreateAggregateToCollectionFindOperation(lastStage, renderedPipeline.OutputSerializer, options); - var forkedSession = session.Fork(); - var deferredCursor = new DeferredAsyncCursor( - () => forkedSession.Dispose(), - ct => ExecuteReadOperation(forkedSession, findOperation, ReadPreference.Primary, ct), - ct => ExecuteReadOperationAsync(forkedSession, findOperation, ReadPreference.Primary, ct)); - return deferredCursor; + _operationExecutor.ExecuteWriteOperation(aggregateOperation, _writeOperationOptions, session, cancellationToken: cancellationToken); + return CreateAggregateToCollectionResultCursor(session, renderedPipeline, options); } else { var aggregateOperation = CreateAggregateOperation(renderedPipeline, options); - return ExecuteReadOperation(session, aggregateOperation, cancellationToken); + return _operationExecutor.ExecuteReadOperation(aggregateOperation, _readOperationOptions, session, cancellationToken: cancellationToken); } } - public override Task> AggregateAsync(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default(CancellationToken)) + public override async Task> AggregateAsync(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { - return UsingImplicitSessionAsync(session => AggregateAsync(session, pipeline, options, cancellationToken), cancellationToken); + using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false); + return await AggregateAsync(session, pipeline, options, cancellationToken: cancellationToken).ConfigureAwait(false); } - public override async Task> AggregateAsync(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default(CancellationToken)) + public override async Task> AggregateAsync(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); Ensure.IsNotNull(pipeline, nameof(pipeline)); - options = options ?? new AggregateOptions(); + options ??= new AggregateOptions(); var renderArgs = GetRenderArgs(options.TranslationOptions); - var renderedPipeline = pipeline.Render(renderArgs); - - var lastStage = renderedPipeline.Documents.LastOrDefault(); - var lastStageName = lastStage?.GetElement(0).Name; - if (lastStage != null && (lastStageName == "$out" || lastStageName == "$merge")) + var renderedPipeline = AggregateHelper.RenderAggregatePipeline(pipeline, renderArgs, out bool isAggregateToCollection); + if (isAggregateToCollection) { var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - await ExecuteWriteOperationAsync(session, aggregateOperation, cancellationToken).ConfigureAwait(false); - - // we want to delay execution of the find because the user may - // not want to iterate the results at all... - var findOperation = CreateAggregateToCollectionFindOperation(lastStage, renderedPipeline.OutputSerializer, options); - var forkedSession = session.Fork(); - var deferredCursor = new DeferredAsyncCursor( - () => forkedSession.Dispose(), - ct => ExecuteReadOperation(forkedSession, findOperation, ReadPreference.Primary, ct), - ct => ExecuteReadOperationAsync(forkedSession, findOperation, ReadPreference.Primary, ct)); - return await Task.FromResult>(deferredCursor).ConfigureAwait(false); + await _operationExecutor.ExecuteWriteOperationAsync(aggregateOperation, _writeOperationOptions, session, cancellationToken: cancellationToken).ConfigureAwait(false); + return CreateAggregateToCollectionResultCursor(session, renderedPipeline, options); } else { var aggregateOperation = CreateAggregateOperation(renderedPipeline, options); - return await ExecuteReadOperationAsync(session, aggregateOperation, cancellationToken).ConfigureAwait(false); + return await _operationExecutor.ExecuteReadOperationAsync(aggregateOperation, _readOperationOptions, session, cancellationToken: cancellationToken).ConfigureAwait(false); } } - public override void AggregateToCollection(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default(CancellationToken)) + public override void AggregateToCollection(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { - UsingImplicitSession(session => AggregateToCollection(session, pipeline, options, cancellationToken), cancellationToken); + using var session = _operationExecutor.StartImplicitSession(cancellationToken: cancellationToken); + AggregateToCollection(session, pipeline, options, cancellationToken: cancellationToken); } - public override void AggregateToCollection(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default(CancellationToken)) + public override void AggregateToCollection(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); Ensure.IsNotNull(pipeline, nameof(pipeline)); - options = options ?? new AggregateOptions(); + options ??= new AggregateOptions(); var renderArgs = GetRenderArgs(options.TranslationOptions); - var renderedPipeline = pipeline.Render(renderArgs); - - var lastStage = renderedPipeline.Documents.LastOrDefault(); - var lastStageName = lastStage?.GetElement(0).Name; - if (lastStage == null || (lastStageName != "$out" && lastStageName != "$merge")) + var renderedPipeline = AggregateHelper.RenderAggregatePipeline(pipeline, renderArgs, out bool isAggregateToCollection); + if (renderedPipeline.Documents.Count == 0 || !isAggregateToCollection) { throw new InvalidOperationException("AggregateToCollection requires that the last stage be $out or $merge."); } var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - ExecuteWriteOperation(session, aggregateOperation, cancellationToken); + _operationExecutor.ExecuteWriteOperation(aggregateOperation, _writeOperationOptions, session, cancellationToken: cancellationToken); } - public override Task AggregateToCollectionAsync(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default(CancellationToken)) + public override async Task AggregateToCollectionAsync(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { - return UsingImplicitSessionAsync(session => AggregateToCollectionAsync(session, pipeline, options, cancellationToken), cancellationToken); + using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false); + await AggregateToCollectionAsync(session, pipeline, options, cancellationToken: cancellationToken).ConfigureAwait(false); } - public override async Task AggregateToCollectionAsync(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default(CancellationToken)) + public override async Task AggregateToCollectionAsync(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); Ensure.IsNotNull(pipeline, nameof(pipeline)); - options = options ?? new AggregateOptions(); + options ??= new AggregateOptions(); var renderArgs = GetRenderArgs(options.TranslationOptions); - var renderedPipeline = pipeline.Render(renderArgs); - - var lastStage = renderedPipeline.Documents.LastOrDefault(); - var lastStageName = lastStage?.GetElement(0).Name; - if (lastStage == null || (lastStageName != "$out" && lastStageName != "$merge")) + var renderedPipeline = AggregateHelper.RenderAggregatePipeline(pipeline, renderArgs, out bool isAggregateToCollection); + if (renderedPipeline.Documents.Count == 0 || !isAggregateToCollection) { throw new InvalidOperationException("AggregateToCollectionAsync requires that the last stage be $out or $merge."); } var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - await ExecuteWriteOperationAsync(session, aggregateOperation, cancellationToken).ConfigureAwait(false); + await _operationExecutor.ExecuteWriteOperationAsync(aggregateOperation, _writeOperationOptions, session, cancellationToken: cancellationToken).ConfigureAwait(false); } - public override BulkWriteResult BulkWrite(IEnumerable> requests, BulkWriteOptions options, CancellationToken cancellationToken = default(CancellationToken)) + public override BulkWriteResult BulkWrite(IEnumerable> requests, BulkWriteOptions options, CancellationToken cancellationToken = default) { - return UsingImplicitSession(session => BulkWrite(session, requests, options, cancellationToken), cancellationToken); + using var session = _operationExecutor.StartImplicitSession(cancellationToken: cancellationToken); + return BulkWrite(session, requests, options, cancellationToken: cancellationToken); } - public override BulkWriteResult BulkWrite(IClientSessionHandle session, IEnumerable> requests, BulkWriteOptions options, CancellationToken cancellationToken = default(CancellationToken)) + public override BulkWriteResult BulkWrite(IClientSessionHandle session, IEnumerable> requests, BulkWriteOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull((object)requests, nameof(requests)); - var requestsArray = requests.ToArray(); - if (requestsArray.Length == 0) - { - throw new ArgumentException("Must contain at least 1 request.", nameof(requests)); - } - foreach (var request in requestsArray) - { - request.ThrowIfNotValid(); - } - - options = options ?? new BulkWriteOptions(); - - var renderArgs = GetRenderArgs(); - var operation = CreateBulkWriteOperation(session, requestsArray, options, renderArgs); + var operation = CreateBulkWriteOperation(session, requestsArray, options); try { - var result = ExecuteWriteOperation(session, operation, cancellationToken); + var result = _operationExecutor.ExecuteWriteOperation(operation, _writeOperationOptions, session, cancellationToken: cancellationToken); return BulkWriteResult.FromCore(result, requestsArray); } catch (MongoBulkWriteOperationException ex) @@ -256,34 +219,21 @@ public override MongoCollectionSettings Settings } } - public override Task> BulkWriteAsync(IEnumerable> requests, BulkWriteOptions options, CancellationToken cancellationToken = default(CancellationToken)) + public override async Task> BulkWriteAsync(IEnumerable> requests, BulkWriteOptions options, CancellationToken cancellationToken = default) { - return UsingImplicitSessionAsync(session => BulkWriteAsync(session, requests, options, cancellationToken), cancellationToken); + using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false); + return await BulkWriteAsync(session, requests, options, cancellationToken: cancellationToken).ConfigureAwait(false); } - public override async Task> BulkWriteAsync(IClientSessionHandle session, IEnumerable> requests, BulkWriteOptions options, CancellationToken cancellationToken = default(CancellationToken)) + public override async Task> BulkWriteAsync(IClientSessionHandle session, IEnumerable> requests, BulkWriteOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull((object)requests, nameof(requests)); - var requestsArray = requests.ToArray(); - if (requestsArray.Length == 0) - { - throw new ArgumentException("Must contain at least 1 request.", nameof(requests)); - } - - foreach (var request in requestsArray) - { - request.ThrowIfNotValid(); - } - - options = options ?? new BulkWriteOptions(); - var renderArgs = GetRenderArgs(); - var operation = CreateBulkWriteOperation(session, requestsArray, options, renderArgs); + var operation = CreateBulkWriteOperation(session, requestsArray, options); try { - var result = await ExecuteWriteOperationAsync(session, operation, cancellationToken).ConfigureAwait(false); + var result = await _operationExecutor.ExecuteWriteOperationAsync(operation, _writeOperationOptions, session, cancellationToken: cancellationToken).ConfigureAwait(false); return BulkWriteResult.FromCore(result, requestsArray); } catch (MongoBulkWriteOperationException ex) @@ -293,314 +243,243 @@ public override MongoCollectionSettings Settings } [Obsolete("Use CountDocuments or EstimatedDocumentCount instead.")] - public override long Count(FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - return UsingImplicitSession(session => Count(session, filter, options, cancellationToken), cancellationToken); - } + public override long Count(FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperation( + CreateCountOperation(filter, options), + _readOperationOptions, + cancellationToken: cancellationToken); [Obsolete("Use CountDocuments or EstimatedDocumentCount instead.")] - public override long Count(IClientSessionHandle session, FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(filter, nameof(filter)); - options = options ?? new CountOptions(); - - var renderArgs = GetRenderArgs(); - var operation = CreateCountOperation(filter, options, renderArgs); - return ExecuteReadOperation(session, operation, cancellationToken); - } + public override long Count(IClientSessionHandle session, FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperation( + CreateCountOperation(filter, options), + _readOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); [Obsolete("Use CountDocumentsAsync or EstimatedDocumentCountAsync instead.")] - public override Task CountAsync(FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - return UsingImplicitSessionAsync(session => CountAsync(session, filter, options, cancellationToken), cancellationToken); - } + public override Task CountAsync(FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperationAsync( + CreateCountOperation(filter, options), + _readOperationOptions, + cancellationToken: cancellationToken); [Obsolete("Use CountDocumentsAsync or EstimatedDocumentCountAsync instead.")] - public override Task CountAsync(IClientSessionHandle session, FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(filter, nameof(filter)); - options = options ?? new CountOptions(); - - var renderArgs = GetRenderArgs(); - var operation = CreateCountOperation(filter, options, renderArgs); - return ExecuteReadOperationAsync(session, operation, cancellationToken); - } - - public override long CountDocuments(FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - return UsingImplicitSession(session => CountDocuments(session, filter, options, cancellationToken), cancellationToken); - } - - public override long CountDocuments(IClientSessionHandle session, FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(filter, nameof(filter)); - options = options ?? new CountOptions(); - - var renderArgs = GetRenderArgs(); - var operation = CreateCountDocumentsOperation(filter, options, renderArgs); - return ExecuteReadOperation(session, operation, cancellationToken); - } - - public override Task CountDocumentsAsync(FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - return UsingImplicitSessionAsync(session => CountDocumentsAsync(session, filter, options, cancellationToken), cancellationToken); - } - - public override Task CountDocumentsAsync(IClientSessionHandle session, FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(filter, nameof(filter)); - options = options ?? new CountOptions(); - - var renderArgs = GetRenderArgs(); - var operation = CreateCountDocumentsOperation(filter, options, renderArgs); - return ExecuteReadOperationAsync(session, operation, cancellationToken); - } - - public override IAsyncCursor Distinct(FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - return UsingImplicitSession(session => Distinct(session, field, filter, options, cancellationToken), cancellationToken); - } - - public override IAsyncCursor Distinct(IClientSessionHandle session, FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(field, nameof(field)); - Ensure.IsNotNull(filter, nameof(filter)); - options = options ?? new DistinctOptions(); - - var renderArgs = GetRenderArgs(); - var operation = CreateDistinctOperation(field, filter, options, renderArgs); - return ExecuteReadOperation(session, operation, cancellationToken); - } - - public override Task> DistinctAsync(FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - return UsingImplicitSessionAsync(session => DistinctAsync(session, field, filter, options, cancellationToken), cancellationToken); - } - - public override Task> DistinctAsync(IClientSessionHandle session, FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(field, nameof(field)); - Ensure.IsNotNull(filter, nameof(filter)); - options = options ?? new DistinctOptions(); - - var renderArgs = GetRenderArgs(); - var operation = CreateDistinctOperation(field, filter, options, renderArgs); - return ExecuteReadOperationAsync(session, operation, cancellationToken); - } - - public override IAsyncCursor DistinctMany(FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - return UsingImplicitSession(session => DistinctMany(session, field, filter, options, cancellationToken), cancellationToken); - } - - public override IAsyncCursor DistinctMany(IClientSessionHandle session, FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(field, nameof(field)); - Ensure.IsNotNull(filter, nameof(filter)); - options = options ?? new DistinctOptions(); - - var renderArgs = GetRenderArgs(); - var operation = CreateDistinctManyOperation(field, filter, options, renderArgs); - return ExecuteReadOperation(session, operation, cancellationToken); - } - - public override Task> DistinctManyAsync(FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - return UsingImplicitSessionAsync(session => DistinctManyAsync(session, field, filter, options, cancellationToken), cancellationToken); - } - - public override Task> DistinctManyAsync(IClientSessionHandle session, FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(field, nameof(field)); - Ensure.IsNotNull(filter, nameof(filter)); - options = options ?? new DistinctOptions(); - - var renderArgs = GetRenderArgs(); - var operation = CreateDistinctManyOperation(field, filter, options, renderArgs); - return ExecuteReadOperationAsync(session, operation, cancellationToken); - } - - public override long EstimatedDocumentCount(EstimatedDocumentCountOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - return UsingImplicitSession(session => - { - var operation = CreateEstimatedDocumentCountOperation(options); - return ExecuteReadOperation(session, operation, cancellationToken); - }); - } - - public override Task EstimatedDocumentCountAsync(EstimatedDocumentCountOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - return UsingImplicitSessionAsync(session => - { - var operation = CreateEstimatedDocumentCountOperation(options); - return ExecuteReadOperationAsync(session, operation, cancellationToken); - }); - } - - public override IAsyncCursor FindSync(FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - return UsingImplicitSession(session => FindSync(session, filter, options, cancellationToken), cancellationToken); - } - - public override IAsyncCursor FindSync(IClientSessionHandle session, FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(filter, nameof(filter)); - options = options ?? new FindOptions(); - - var renderArgs = GetRenderArgs(options.TranslationOptions); - var operation = CreateFindOperation(filter, options, renderArgs); - return ExecuteReadOperation(session, operation, cancellationToken); - } - - public override Task> FindAsync(FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - return UsingImplicitSessionAsync(session => FindAsync(session, filter, options, cancellationToken), cancellationToken); - } - - public override Task> FindAsync(IClientSessionHandle session, FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(filter, nameof(filter)); - options = options ?? new FindOptions(); - - var renderArgs = GetRenderArgs(options.TranslationOptions); - var operation = CreateFindOperation(filter, options, renderArgs); - return ExecuteReadOperationAsync(session, operation, cancellationToken); - } - - public override TProjection FindOneAndDelete(FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - return UsingImplicitSession(session => FindOneAndDelete(session, filter, options, cancellationToken), cancellationToken); - } - - public override TProjection FindOneAndDelete(IClientSessionHandle session, FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(filter, nameof(filter)); - options = options ?? new FindOneAndDeleteOptions(); - - var renderArgs = GetRenderArgs(); - var operation = CreateFindOneAndDeleteOperation(filter, options, renderArgs); - return ExecuteWriteOperation(session, operation, cancellationToken); - } - - public override Task FindOneAndDeleteAsync(FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - return UsingImplicitSessionAsync(session => FindOneAndDeleteAsync(session, filter, options, cancellationToken), cancellationToken); - } - - public override Task FindOneAndDeleteAsync(IClientSessionHandle session, FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(filter, nameof(filter)); - options = options ?? new FindOneAndDeleteOptions(); - - var renderArgs = GetRenderArgs(); - var operation = CreateFindOneAndDeleteOperation(filter, options, renderArgs); - return ExecuteWriteOperationAsync(session, operation, cancellationToken); - } - - public override TProjection FindOneAndReplace(FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - return UsingImplicitSession(session => FindOneAndReplace(session, filter, replacement, options, cancellationToken), cancellationToken); - } - - public override TProjection FindOneAndReplace(IClientSessionHandle session, FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(filter, nameof(filter)); - var replacementObject = Ensure.IsNotNull((object)replacement, nameof(replacement)); // only box once if it's a struct - options = options ?? new FindOneAndReplaceOptions(); - - var renderArgs = GetRenderArgs(); - var operation = CreateFindOneAndReplaceOperation(filter, replacementObject, options, renderArgs); - return ExecuteWriteOperation(session, operation, cancellationToken); - } - - public override Task FindOneAndReplaceAsync(FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - return UsingImplicitSessionAsync(session => FindOneAndReplaceAsync(session, filter, replacement, options, cancellationToken), cancellationToken); - } - - public override Task FindOneAndReplaceAsync(IClientSessionHandle session, FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(filter, nameof(filter)); - var replacementObject = Ensure.IsNotNull((object)replacement, nameof(replacement)); // only box once if it's a struct - options = options ?? new FindOneAndReplaceOptions(); - - var renderArgs = GetRenderArgs(); - var operation = CreateFindOneAndReplaceOperation(filter, replacementObject, options, renderArgs); - return ExecuteWriteOperationAsync(session, operation, cancellationToken); - } - - public override TProjection FindOneAndUpdate(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - return UsingImplicitSession(session => FindOneAndUpdate(session, filter, update, options, cancellationToken), cancellationToken); - } - - public override TProjection FindOneAndUpdate(IClientSessionHandle session, FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(filter, nameof(filter)); - Ensure.IsNotNull(update, nameof(update)); - options = options ?? new FindOneAndUpdateOptions(); - - if (update is PipelineUpdateDefinition && (options.ArrayFilters != null && options.ArrayFilters.Any())) - { - throw new NotSupportedException("An arrayfilter is not supported in the pipeline-style update."); - } - - var renderArgs = GetRenderArgs(); - var operation = CreateFindOneAndUpdateOperation(filter, update, options, renderArgs); - return ExecuteWriteOperation(session, operation, cancellationToken); - } - - public override Task FindOneAndUpdateAsync(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - return UsingImplicitSessionAsync(session => FindOneAndUpdateAsync(session, filter, update, options, cancellationToken), cancellationToken); - } - - public override Task FindOneAndUpdateAsync(IClientSessionHandle session, FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(filter, nameof(filter)); - Ensure.IsNotNull(update, nameof(update)); - options = options ?? new FindOneAndUpdateOptions(); - - if (update is PipelineUpdateDefinition && (options.ArrayFilters != null && options.ArrayFilters.Any())) - { - throw new NotSupportedException("An arrayfilter is not supported in the pipeline-style update."); - } - - var renderArgs = GetRenderArgs(); - var operation = CreateFindOneAndUpdateOperation(filter, update, options, renderArgs); - return ExecuteWriteOperationAsync(session, operation, cancellationToken); - } + public override Task CountAsync(IClientSessionHandle session, FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperationAsync( + CreateCountOperation(filter, options), + _readOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); + + public override long CountDocuments(FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperation( + CreateCountDocumentsOperation(filter, options), + _readOperationOptions, + cancellationToken: cancellationToken); + + public override long CountDocuments(IClientSessionHandle session, FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperation( + CreateCountDocumentsOperation(filter, options), + _readOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); + + public override Task CountDocumentsAsync(FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperationAsync( + CreateCountDocumentsOperation(filter, options), + _readOperationOptions, + cancellationToken: cancellationToken); + + public override Task CountDocumentsAsync(IClientSessionHandle session, FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperationAsync( + CreateCountDocumentsOperation(filter, options), + _readOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); + + public override IAsyncCursor Distinct(FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperation( + CreateDistinctOperation(field, filter, options), + _readOperationOptions, + cancellationToken: cancellationToken); + + public override IAsyncCursor Distinct(IClientSessionHandle session, FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperation( + CreateDistinctOperation(field, filter, options), + _readOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); + + public override Task> DistinctAsync(FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperationAsync( + CreateDistinctOperation(field, filter, options), + _readOperationOptions, + cancellationToken: cancellationToken); + + public override Task> DistinctAsync(IClientSessionHandle session, FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperationAsync( + CreateDistinctOperation(field, filter, options), + _readOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); + + public override IAsyncCursor DistinctMany(FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperation( + CreateDistinctManyOperation(field, filter, options), + _readOperationOptions, + cancellationToken: cancellationToken); + + public override IAsyncCursor DistinctMany(IClientSessionHandle session, FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperation( + CreateDistinctManyOperation(field, filter, options), + _readOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); + + public override Task> DistinctManyAsync(FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperationAsync( + CreateDistinctManyOperation(field, filter, options), + _readOperationOptions, + cancellationToken: cancellationToken); + + public override Task> DistinctManyAsync(IClientSessionHandle session, FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperationAsync( + CreateDistinctManyOperation(field, filter, options), + _readOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); + + public override long EstimatedDocumentCount(EstimatedDocumentCountOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperation( + CreateEstimatedDocumentCountOperation(options), + _readOperationOptions, + cancellationToken: cancellationToken); + + public override Task EstimatedDocumentCountAsync(EstimatedDocumentCountOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperationAsync( + CreateEstimatedDocumentCountOperation(options), + _readOperationOptions, + cancellationToken: cancellationToken); + + public override IAsyncCursor FindSync(FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperation( + CreateFindOperation(filter, options), + _readOperationOptions, + cancellationToken: cancellationToken); + + public override IAsyncCursor FindSync(IClientSessionHandle session, FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperation( + CreateFindOperation(filter, options), + _readOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); + + public override Task> FindAsync(FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperationAsync( + CreateFindOperation(filter, options), + _readOperationOptions, + cancellationToken: cancellationToken); + + public override Task> FindAsync(IClientSessionHandle session, FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperationAsync( + CreateFindOperation(filter, options), + _readOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); + + public override TProjection FindOneAndDelete(FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteWriteOperation( + CreateFindOneAndDeleteOperation(filter, options), + _writeOperationOptions, + cancellationToken: cancellationToken); + + public override TProjection FindOneAndDelete(IClientSessionHandle session, FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteWriteOperation( + CreateFindOneAndDeleteOperation(filter, options), + _writeOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); + + public override Task FindOneAndDeleteAsync(FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteWriteOperationAsync( + CreateFindOneAndDeleteOperation(filter, options), + _writeOperationOptions, + cancellationToken: cancellationToken); + + public override Task FindOneAndDeleteAsync(IClientSessionHandle session, FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteWriteOperationAsync( + CreateFindOneAndDeleteOperation(filter, options), + _writeOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); + + public override TProjection FindOneAndReplace(FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteWriteOperation( + CreateFindOneAndReplaceOperation(filter, replacement, options), + _writeOperationOptions, + cancellationToken: cancellationToken); + + public override TProjection FindOneAndReplace(IClientSessionHandle session, FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteWriteOperation( + CreateFindOneAndReplaceOperation(filter, replacement, options), + _writeOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); + + public override Task FindOneAndReplaceAsync(FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteWriteOperationAsync( + CreateFindOneAndReplaceOperation(filter, replacement, options), + _writeOperationOptions, + cancellationToken: cancellationToken); + + public override Task FindOneAndReplaceAsync(IClientSessionHandle session, FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteWriteOperationAsync( + CreateFindOneAndReplaceOperation(filter, replacement, options), + _writeOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); + + public override TProjection FindOneAndUpdate(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteWriteOperation( + CreateFindOneAndUpdateOperation(filter, update, options), + _writeOperationOptions, + cancellationToken: cancellationToken); + + public override TProjection FindOneAndUpdate(IClientSessionHandle session, FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteWriteOperation( + CreateFindOneAndUpdateOperation(filter, update, options), + _writeOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); + + public override Task FindOneAndUpdateAsync(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteWriteOperationAsync( + CreateFindOneAndUpdateOperation(filter, update, options), + _writeOperationOptions, + cancellationToken: cancellationToken); + + public override Task FindOneAndUpdateAsync(IClientSessionHandle session, FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteWriteOperationAsync( + CreateFindOneAndUpdateOperation(filter, update, options), + _writeOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); [Obsolete("Use Aggregation pipeline instead.")] - public override IAsyncCursor MapReduce(BsonJavaScript map, BsonJavaScript reduce, MapReduceOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) + public override IAsyncCursor MapReduce(BsonJavaScript map, BsonJavaScript reduce, MapReduceOptions options = null, CancellationToken cancellationToken = default) { - return UsingImplicitSession(session => MapReduce(session, map, reduce, options, cancellationToken), cancellationToken); + using var session = _operationExecutor.StartImplicitSession(cancellationToken: cancellationToken); + return MapReduce(session, map, reduce, options, cancellationToken: cancellationToken); } [Obsolete("Use Aggregation pipeline instead.")] - public override IAsyncCursor MapReduce(IClientSessionHandle session, BsonJavaScript map, BsonJavaScript reduce, MapReduceOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) + public override IAsyncCursor MapReduce(IClientSessionHandle session, BsonJavaScript map, BsonJavaScript reduce, MapReduceOptions options = null, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); Ensure.IsNotNull(map, nameof(map)); Ensure.IsNotNull(reduce, nameof(reduce)); - options = options ?? new MapReduceOptions(); + options ??= new MapReduceOptions(); var outputOptions = options.OutputOptions ?? MapReduceOutputOptions.Inline; var resultSerializer = ResolveResultSerializer(options.ResultSerializer); @@ -609,38 +488,30 @@ public override MongoCollectionSettings Settings if (outputOptions == MapReduceOutputOptions.Inline) { var operation = CreateMapReduceOperation(map, reduce, options, resultSerializer, renderArgs); - return ExecuteReadOperation(session, operation, cancellationToken); + return _operationExecutor.ExecuteReadOperation(operation, _readOperationOptions, session, cancellationToken: cancellationToken); } else { var mapReduceOperation = CreateMapReduceOutputToCollectionOperation(map, reduce, options, outputOptions, renderArgs); - ExecuteWriteOperation(session, mapReduceOperation, cancellationToken); - - // we want to delay execution of the find because the user may - // not want to iterate the results at all... - var findOperation = CreateMapReduceOutputToCollectionFindOperation(options, mapReduceOperation.OutputCollectionNamespace, resultSerializer); - var forkedSession = session.Fork(); - var deferredCursor = new DeferredAsyncCursor( - () => forkedSession.Dispose(), - ct => ExecuteReadOperation(forkedSession, findOperation, ReadPreference.Primary, ct), - ct => ExecuteReadOperationAsync(forkedSession, findOperation, ReadPreference.Primary, ct)); - return deferredCursor; + _operationExecutor.ExecuteWriteOperation(mapReduceOperation, _writeOperationOptions, session, cancellationToken: cancellationToken); + return CreateMapReduceOutputToCollectionResultCursor(session, options, mapReduceOperation.OutputCollectionNamespace, resultSerializer); } } [Obsolete("Use Aggregation pipeline instead.")] - public override Task> MapReduceAsync(BsonJavaScript map, BsonJavaScript reduce, MapReduceOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) + public override async Task> MapReduceAsync(BsonJavaScript map, BsonJavaScript reduce, MapReduceOptions options = null, CancellationToken cancellationToken = default) { - return UsingImplicitSessionAsync(session => MapReduceAsync(session, map, reduce, options, cancellationToken), cancellationToken); + using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false); + return await MapReduceAsync(session, map, reduce, options, cancellationToken: cancellationToken).ConfigureAwait(false); } [Obsolete("Use Aggregation pipeline instead.")] - public override async Task> MapReduceAsync(IClientSessionHandle session, BsonJavaScript map, BsonJavaScript reduce, MapReduceOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) + public override async Task> MapReduceAsync(IClientSessionHandle session, BsonJavaScript map, BsonJavaScript reduce, MapReduceOptions options = null, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); Ensure.IsNotNull(map, nameof(map)); Ensure.IsNotNull(reduce, nameof(reduce)); - options = options ?? new MapReduceOptions(); + options ??= new MapReduceOptions(); var outputOptions = options.OutputOptions ?? MapReduceOutputOptions.Inline; var resultSerializer = ResolveResultSerializer(options.ResultSerializer); @@ -649,22 +520,13 @@ public override MongoCollectionSettings Settings if (outputOptions == MapReduceOutputOptions.Inline) { var operation = CreateMapReduceOperation(map, reduce, options, resultSerializer, renderArgs); - return await ExecuteReadOperationAsync(session, operation, cancellationToken).ConfigureAwait(false); + return await _operationExecutor.ExecuteReadOperationAsync(operation, _readOperationOptions, session, cancellationToken: cancellationToken).ConfigureAwait(false); } else { var mapReduceOperation = CreateMapReduceOutputToCollectionOperation(map, reduce, options, outputOptions, renderArgs); - await ExecuteWriteOperationAsync(session, mapReduceOperation, cancellationToken).ConfigureAwait(false); - - // we want to delay execution of the find because the user may - // not want to iterate the results at all... - var findOperation = CreateMapReduceOutputToCollectionFindOperation(options, mapReduceOperation.OutputCollectionNamespace, resultSerializer); - var forkedSession = session.Fork(); - var deferredCursor = new DeferredAsyncCursor( - () => forkedSession.Dispose(), - ct => ExecuteReadOperation(forkedSession, findOperation, ReadPreference.Primary, ct), - ct => ExecuteReadOperationAsync(forkedSession, findOperation, ReadPreference.Primary, ct)); - return await Task.FromResult(deferredCursor).ConfigureAwait(false); + await _operationExecutor.ExecuteWriteOperationAsync(mapReduceOperation, _writeOperationOptions, session, cancellationToken: cancellationToken).ConfigureAwait(false); + return CreateMapReduceOutputToCollectionResultCursor(session, options, mapReduceOperation.OutputCollectionNamespace, resultSerializer); } } @@ -685,44 +547,42 @@ public override IFilteredMongoCollection OfType Watch( PipelineDefinition, TResult> pipeline, ChangeStreamOptions options = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - return UsingImplicitSession(session => Watch(session, pipeline, options, cancellationToken), cancellationToken); - } + CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperation( + CreateChangeStreamOperation(pipeline, options), + _readOperationOptions, + cancellationToken: cancellationToken); public override IChangeStreamCursor Watch( IClientSessionHandle session, PipelineDefinition, TResult> pipeline, ChangeStreamOptions options = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(pipeline, nameof(pipeline)); - var translationOptions = _database.Client.Settings.TranslationOptions; - var operation = CreateChangeStreamOperation(pipeline, options, translationOptions); - return ExecuteReadOperation(session, operation, cancellationToken); - } + CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperation( + CreateChangeStreamOperation(pipeline, options), + _readOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); public override Task> WatchAsync( PipelineDefinition, TResult> pipeline, ChangeStreamOptions options = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - return UsingImplicitSessionAsync(session => WatchAsync(session, pipeline, options, cancellationToken), cancellationToken); - } + CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperationAsync( + CreateChangeStreamOperation(pipeline, options), + _readOperationOptions, + cancellationToken: cancellationToken); public override Task> WatchAsync( IClientSessionHandle session, PipelineDefinition, TResult> pipeline, ChangeStreamOptions options = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(pipeline, nameof(pipeline)); - var translationOptions = _database.Client.Settings.TranslationOptions; - var operation = CreateChangeStreamOperation(pipeline, options, translationOptions); - return ExecuteReadOperationAsync(session, operation, cancellationToken); - } + CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperationAsync( + CreateChangeStreamOperation(pipeline, options), + _readOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); public override IMongoCollection WithReadConcern(ReadConcern readConcern) { @@ -850,72 +710,11 @@ private AggregateOperation CreateAggregateOperation(RenderedPi }; } - private FindOperation CreateAggregateToCollectionFindOperation(BsonDocument outStage, IBsonSerializer resultSerializer, AggregateOptions options) + private IAsyncCursor CreateAggregateToCollectionResultCursor(IClientSessionHandle session, RenderedPipelineDefinition pipeline, AggregateOptions options) { - CollectionNamespace outputCollectionNamespace; - var stageName = outStage.GetElement(0).Name; - switch (stageName) - { - case "$out": - { - var outValue = outStage[0]; - DatabaseNamespace outputDatabaseNamespace; - string outputCollectionName; - if (outValue.IsString) - { - outputDatabaseNamespace = _collectionNamespace.DatabaseNamespace; - outputCollectionName = outValue.AsString; - } - else - { - outputDatabaseNamespace = new DatabaseNamespace(outValue["db"].AsString); - outputCollectionName = outValue["coll"].AsString; - } - outputCollectionNamespace = new CollectionNamespace(outputDatabaseNamespace, outputCollectionName); - } - break; - case "$merge": - { - var mergeArguments = outStage[0]; - DatabaseNamespace outputDatabaseNamespace; - string outputCollectionName; - if (mergeArguments.IsString) - { - outputDatabaseNamespace = _collectionNamespace.DatabaseNamespace; - outputCollectionName = mergeArguments.AsString; - } - else - { - var into = mergeArguments.AsBsonDocument["into"]; - if (into.IsString) - { - outputDatabaseNamespace = _collectionNamespace.DatabaseNamespace; - outputCollectionName = into.AsString; - } - else - { - if (into.AsBsonDocument.Contains("db")) - { - outputDatabaseNamespace = new DatabaseNamespace(into["db"].AsString); - } - else - { - outputDatabaseNamespace = _collectionNamespace.DatabaseNamespace; - } - outputCollectionName = into["coll"].AsString; - } - } - outputCollectionNamespace = new CollectionNamespace(outputDatabaseNamespace, outputCollectionName); - } - break; - default: - throw new ArgumentException($"Unexpected stage name: {stageName}."); - } + var outputCollectionNamespace = AggregateHelper.GetOutCollection(pipeline.Documents.Last(), _collectionNamespace.DatabaseNamespace); - return new FindOperation( - outputCollectionNamespace, - resultSerializer, - _messageEncoderSettings) + var findOperation = new FindOperation(outputCollectionNamespace, pipeline.OutputSerializer, _messageEncoderSettings) { BatchSize = options.BatchSize, Collation = options.Collation, @@ -923,6 +722,16 @@ private FindOperation CreateAggregateToCollectionFindOperation ReadConcern = _settings.ReadConcern, RetryRequested = _database.Client.Settings.RetryReads }; + + // we want to delay execution of the find because the user may + // not want to iterate the results at all... + var forkedSession = session.Fork(); + var readOperationOptions = _readOperationOptions with { ExplicitReadPreference = ReadPreference.Primary }; + var deferredCursor = new DeferredAsyncCursor( + () => forkedSession.Dispose(), + ct => _operationExecutor.ExecuteReadOperation(findOperation, readOperationOptions, forkedSession, cancellationToken: ct), + ct => _operationExecutor.ExecuteReadOperationAsync(findOperation, readOperationOptions, forkedSession, cancellationToken: ct)); + return deferredCursor; } private AggregateToCollectionOperation CreateAggregateToCollectionOperation(RenderedPipelineDefinition renderedPipeline, AggregateOptions options) @@ -947,15 +756,28 @@ private AggregateToCollectionOperation CreateAggregateToCollectionOperation> requests, - BulkWriteOptions options, - RenderArgs renderArgs) + IReadOnlyList> requests, + BulkWriteOptions options) { + Ensure.IsNotNull((object)requests, nameof(requests)); + if (requests.Count == 0) + { + throw new ArgumentException("Must contain at least 1 request.", nameof(requests)); + } + + options ??= new BulkWriteOptions(); + var renderArgs = GetRenderArgs(); var effectiveWriteConcern = session.IsInTransaction ? WriteConcern.Acknowledged : _settings.WriteConcern; + var writeModels = requests.Select((model, index) => + { + model.ThrowIfNotValid(); + return ConvertWriteModelToWriteRequest(model, index, renderArgs); + }).ToArray(); + return new BulkMixedWriteOperation( _collectionNamespace, - requests.Select((model, index) => ConvertWriteModelToWriteRequest(model, index, renderArgs)), + writeModels, _messageEncoderSettings) { BypassDocumentValidation = options.BypassDocumentValidation, @@ -969,9 +791,11 @@ private BulkMixedWriteOperation CreateBulkWriteOperation( private ChangeStreamOperation CreateChangeStreamOperation( PipelineDefinition, TResult> pipeline, - ChangeStreamOptions options, - ExpressionTranslationOptions translationOptions) + ChangeStreamOptions options) { + Ensure.IsNotNull(pipeline, nameof(pipeline)); + var translationOptions = _database.Client.Settings.TranslationOptions; + return ChangeStreamHelper.CreateChangeStreamOperation( this, pipeline, @@ -984,9 +808,12 @@ private ChangeStreamOperation CreateChangeStreamOperation( private CountDocumentsOperation CreateCountDocumentsOperation( FilterDefinition filter, - CountOptions options, - RenderArgs renderArgs) + CountOptions options) { + Ensure.IsNotNull(filter, nameof(filter)); + options ??= new CountOptions(); + var renderArgs = GetRenderArgs(); + return new CountDocumentsOperation(_collectionNamespace, _messageEncoderSettings) { Collation = options.Collation, @@ -1003,9 +830,12 @@ private CountDocumentsOperation CreateCountDocumentsOperation( private CountOperation CreateCountOperation( FilterDefinition filter, - CountOptions options, - RenderArgs renderArgs) + CountOptions options) { + Ensure.IsNotNull(filter, nameof(filter)); + options ??= new CountOptions(); + var renderArgs = GetRenderArgs(); + return new CountOperation(_collectionNamespace, _messageEncoderSettings) { Collation = options.Collation, @@ -1023,9 +853,12 @@ private CountOperation CreateCountOperation( private DistinctOperation CreateDistinctOperation( FieldDefinition field, FilterDefinition filter, - DistinctOptions options, - RenderArgs renderArgs) + DistinctOptions options) { + Ensure.IsNotNull(field, nameof(field)); + Ensure.IsNotNull(filter, nameof(filter)); + options ??= new DistinctOptions(); + var renderArgs = GetRenderArgs(); var renderedField = field.Render(renderArgs); var valueSerializer = GetValueSerializerForDistinct(renderedField, _settings.SerializerRegistry); @@ -1047,9 +880,12 @@ private DistinctOperation CreateDistinctOperation( private DistinctOperation CreateDistinctManyOperation( FieldDefinition> field, FilterDefinition filter, - DistinctOptions options, - RenderArgs renderArgs) + DistinctOptions options) { + Ensure.IsNotNull(field, nameof(field)); + Ensure.IsNotNull(filter, nameof(filter)); + options ??= new DistinctOptions(); + var renderArgs = GetRenderArgs(); var renderedField = field.Render(renderArgs); var itemSerializer = GetItemSerializerForDistinctMany(renderedField, _settings.SerializerRegistry); @@ -1080,9 +916,11 @@ private EstimatedDocumentCountOperation CreateEstimatedDocumentCountOperation(Es private FindOneAndDeleteOperation CreateFindOneAndDeleteOperation( FilterDefinition filter, - FindOneAndDeleteOptions options, - RenderArgs renderArgs) + FindOneAndDeleteOptions options) { + Ensure.IsNotNull(filter, nameof(filter)); + options ??= new FindOneAndDeleteOptions(); + var renderArgs = GetRenderArgs(); var projection = options.Projection ?? new ClientSideDeserializationProjectionDefinition(); var renderedProjection = projection.Render(renderArgs with { RenderForFind = true }); @@ -1106,17 +944,21 @@ private FindOneAndDeleteOperation CreateFindOneAndDeleteOperation CreateFindOneAndReplaceOperation( FilterDefinition filter, - object replacementObject, - FindOneAndReplaceOptions options, - RenderArgs renderArgs) + object replacement, + FindOneAndReplaceOptions options) { + Ensure.IsNotNull(filter, nameof(filter)); + Ensure.IsNotNull(replacement, nameof(replacement)); + options ??= new FindOneAndReplaceOptions(); + + var renderArgs = GetRenderArgs(); var projection = options.Projection ?? new ClientSideDeserializationProjectionDefinition(); var renderedProjection = projection.Render(renderArgs with { RenderForFind = true }); return new FindOneAndReplaceOperation( _collectionNamespace, filter.Render(renderArgs), - new BsonDocumentWrapper(replacementObject, _documentSerializer), + new BsonDocumentWrapper(replacement, _documentSerializer), new FindAndModifyValueDeserializer(renderedProjection.ProjectionSerializer), _messageEncoderSettings) { @@ -1138,9 +980,18 @@ private FindOneAndReplaceOperation CreateFindOneAndReplaceOperation private FindOneAndUpdateOperation CreateFindOneAndUpdateOperation( FilterDefinition filter, UpdateDefinition update, - FindOneAndUpdateOptions options, - RenderArgs renderArgs) + FindOneAndUpdateOptions options) { + Ensure.IsNotNull(filter, nameof(filter)); + Ensure.IsNotNull(update, nameof(update)); + options = options ?? new FindOneAndUpdateOptions(); + + if (update is PipelineUpdateDefinition && (options.ArrayFilters != null && options.ArrayFilters.Any())) + { + throw new NotSupportedException("An arrayfilter is not supported in the pipeline-style update."); + } + + var renderArgs = GetRenderArgs(); var projection = options.Projection ?? new ClientSideDeserializationProjectionDefinition(); var renderedProjection = projection.Render(renderArgs with { RenderForFind = true }); @@ -1169,9 +1020,12 @@ private FindOneAndUpdateOperation CreateFindOneAndUpdateOperation CreateFindOperation( FilterDefinition filter, - FindOptions options, - RenderArgs renderArgs) + FindOptions options) { + Ensure.IsNotNull(filter, nameof(filter)); + options ??= new FindOptions(); + + var renderArgs = GetRenderArgs(options.TranslationOptions); var projection = options.Projection ?? new ClientSideDeserializationProjectionDefinition(); var renderedProjection = projection.Render(renderArgs with { RenderForFind = true }); @@ -1285,10 +1139,10 @@ private MapReduceOutputToCollectionOperation CreateMapReduceOutputToCollectionOp } #pragma warning disable CS0618 // Type or member is obsolete - private FindOperation CreateMapReduceOutputToCollectionFindOperation(MapReduceOptions options, CollectionNamespace outputCollectionNamespace, IBsonSerializer resultSerializer) + private IAsyncCursor CreateMapReduceOutputToCollectionResultCursor(IClientSessionHandle session, MapReduceOptions options, CollectionNamespace outputCollectionNamespace, IBsonSerializer resultSerializer) #pragma warning restore CS0618 // Type or member is obsolete { - return new FindOperation( + var findOperation = new FindOperation( outputCollectionNamespace, resultSerializer, _messageEncoderSettings) @@ -1298,21 +1152,16 @@ private FindOperation CreateMapReduceOutputToCollectionFindOperation( + () => forkedSession.Dispose(), + ct => _operationExecutor.ExecuteReadOperation(findOperation, readOperationOptions, forkedSession, cancellationToken: ct), + ct => _operationExecutor.ExecuteReadOperationAsync(findOperation, readOperationOptions, forkedSession, cancellationToken: ct)); + return deferredCursor; } private MessageEncoderSettings GetMessageEncoderSettings() @@ -1389,50 +1238,6 @@ private RenderArgs GetRenderArgs(ExpressionTranslationOptions transla return new RenderArgs(_documentSerializer, _settings.SerializerRegistry, translationOptions: translationOptions); } - private TResult ExecuteReadOperation(IClientSessionHandle session, IReadOperation operation, CancellationToken cancellationToken = default(CancellationToken)) - { - var effectiveReadPreference = ReadPreferenceResolver.GetEffectiveReadPreference(session, null, _settings.ReadPreference); - return ExecuteReadOperation(session, operation, effectiveReadPreference, cancellationToken); - } - - private TResult ExecuteReadOperation(IClientSessionHandle session, IReadOperation operation, ReadPreference readPreference, CancellationToken cancellationToken = default(CancellationToken)) - { - using (var binding = CreateReadBinding(session, readPreference)) - { - return _operationExecutor.ExecuteReadOperation(binding, operation, cancellationToken); - } - } - - private Task ExecuteReadOperationAsync(IClientSessionHandle session, IReadOperation operation, CancellationToken cancellationToken = default(CancellationToken)) - { - var effectiveReadPreference = ReadPreferenceResolver.GetEffectiveReadPreference(session, null, _settings.ReadPreference); - return ExecuteReadOperationAsync(session, operation, effectiveReadPreference, cancellationToken); - } - - private async Task ExecuteReadOperationAsync(IClientSessionHandle session, IReadOperation operation, ReadPreference readPreference, CancellationToken cancellationToken = default(CancellationToken)) - { - using (var binding = CreateReadBinding(session, readPreference)) - { - return await _operationExecutor.ExecuteReadOperationAsync(binding, operation, cancellationToken).ConfigureAwait(false); - } - } - - private TResult ExecuteWriteOperation(IClientSessionHandle session, IWriteOperation operation, CancellationToken cancellationToken = default(CancellationToken)) - { - using (var binding = CreateReadWriteBinding(session)) - { - return _operationExecutor.ExecuteWriteOperation(binding, operation, cancellationToken); - } - } - - private async Task ExecuteWriteOperationAsync(IClientSessionHandle session, IWriteOperation operation, CancellationToken cancellationToken = default(CancellationToken)) - { - using (var binding = CreateReadWriteBinding(session)) - { - return await _operationExecutor.ExecuteWriteOperationAsync(binding, operation, cancellationToken).ConfigureAwait(false); - } - } - private IEnumerable RenderArrayFilters(IEnumerable arrayFilters) { if (arrayFilters == null) @@ -1465,38 +1270,6 @@ private IBsonSerializer ResolveResultSerializer(IBsonSerialize return _settings.SerializerRegistry.GetSerializer(); } - private void UsingImplicitSession(Action func, CancellationToken cancellationToken = default(CancellationToken)) - { - using (var session = _operationExecutor.StartImplicitSession(cancellationToken)) - { - func(session); - } - } - - private TResult UsingImplicitSession(Func func, CancellationToken cancellationToken = default(CancellationToken)) - { - using (var session = _operationExecutor.StartImplicitSession(cancellationToken)) - { - return func(session); - } - } - - private async Task UsingImplicitSessionAsync(Func funcAsync, CancellationToken cancellationToken = default(CancellationToken)) - { - using (var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false)) - { - await funcAsync(session).ConfigureAwait(false); - } - } - - private async Task UsingImplicitSessionAsync(Func> funcAsync, CancellationToken cancellationToken = default(CancellationToken)) - { - using (var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false)) - { - return await funcAsync(session).ConfigureAwait(false); - } - } - // nested types private class MongoIndexManager : MongoIndexManagerBase { @@ -1526,231 +1299,192 @@ public override MongoCollectionSettings Settings } // public methods - public override IEnumerable CreateMany(IEnumerable> models, CancellationToken cancellationToken = default(CancellationToken)) - { - return CreateMany(models, null, cancellationToken); - } + public override IEnumerable CreateMany(IEnumerable> models, CancellationToken cancellationToken = default) + => CreateMany(models, null, cancellationToken: cancellationToken); public override IEnumerable CreateMany( IEnumerable> models, CreateManyIndexesOptions options, - CancellationToken cancellationToken = default(CancellationToken)) + CancellationToken cancellationToken = default) { - return _collection.UsingImplicitSession(session => CreateMany(session, models, options, cancellationToken), cancellationToken); + var operation = CreateCreateIndexesOperation(models, options); + _collection._operationExecutor.ExecuteWriteOperation(operation, _collection._writeOperationOptions, null, cancellationToken: cancellationToken); + return operation.Requests.Select(x => x.GetIndexName()); } - public override IEnumerable CreateMany(IClientSessionHandle session, IEnumerable> models, CancellationToken cancellationToken = default(CancellationToken)) - { - return CreateMany(session, models, null, cancellationToken); - } + public override IEnumerable CreateMany(IClientSessionHandle session, IEnumerable> models, CancellationToken cancellationToken = default) + => CreateMany(session, models, null, cancellationToken: cancellationToken); public override IEnumerable CreateMany( IClientSessionHandle session, IEnumerable> models, CreateManyIndexesOptions options, - CancellationToken cancellationToken = default(CancellationToken)) + CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(models, nameof(models)); - var renderArgs = _collection.GetRenderArgs(); - var requests = CreateCreateIndexRequests(models, renderArgs); - var operation = CreateCreateIndexesOperation(requests, options); - _collection.ExecuteWriteOperation(session, operation, cancellationToken); - - return requests.Select(x => x.GetIndexName()); + var operation = CreateCreateIndexesOperation(models, options); + _collection._operationExecutor.ExecuteWriteOperation(operation, _collection._writeOperationOptions, session, cancellationToken: cancellationToken); + return operation.Requests.Select(x => x.GetIndexName()); } - public override Task> CreateManyAsync(IEnumerable> models, CancellationToken cancellationToken = default(CancellationToken)) - { - return CreateManyAsync(models, null, cancellationToken); - } + public override Task> CreateManyAsync(IEnumerable> models, CancellationToken cancellationToken = default) + => CreateManyAsync(models, null, cancellationToken: cancellationToken); - public override Task> CreateManyAsync( + public override async Task> CreateManyAsync( IEnumerable> models, CreateManyIndexesOptions options, - CancellationToken cancellationToken = default(CancellationToken)) + CancellationToken cancellationToken = default) { - return _collection.UsingImplicitSessionAsync(session => CreateManyAsync(session, models, options, cancellationToken), cancellationToken); + var operation = CreateCreateIndexesOperation(models, options); + await _collection._operationExecutor.ExecuteWriteOperationAsync(operation, _collection._writeOperationOptions, null, cancellationToken: cancellationToken).ConfigureAwait(false); + return operation.Requests.Select(x => x.GetIndexName()); } - public override Task> CreateManyAsync(IClientSessionHandle session, IEnumerable> models, CancellationToken cancellationToken = default(CancellationToken)) - { - return CreateManyAsync(session, models, null, cancellationToken); - } + public override Task> CreateManyAsync(IClientSessionHandle session, IEnumerable> models, CancellationToken cancellationToken = default) + => CreateManyAsync(session, models, null, cancellationToken: cancellationToken); public override async Task> CreateManyAsync( IClientSessionHandle session, IEnumerable> models, CreateManyIndexesOptions options, - CancellationToken cancellationToken = default(CancellationToken)) + CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(models, nameof(models)); - var renderArgs = _collection.GetRenderArgs(); - var requests = CreateCreateIndexRequests(models, renderArgs); - var operation = CreateCreateIndexesOperation(requests, options); - await _collection.ExecuteWriteOperationAsync(session, operation, cancellationToken).ConfigureAwait(false); - - return requests.Select(x => x.GetIndexName()); + var operation = CreateCreateIndexesOperation(models, options); + await _collection._operationExecutor.ExecuteWriteOperationAsync(operation, _collection._writeOperationOptions, session, cancellationToken: cancellationToken).ConfigureAwait(false); + return operation.Requests.Select(x => x.GetIndexName()); } public override void DropAll(CancellationToken cancellationToken) - { - _collection.UsingImplicitSession(session => DropAll(session, cancellationToken), cancellationToken); - } + => DropAll(options: null, cancellationToken: cancellationToken); - public override void DropAll(DropIndexOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - _collection.UsingImplicitSession(session => DropAll(session, options, cancellationToken), cancellationToken); - } + public override void DropAll(DropIndexOptions options, CancellationToken cancellationToken = default) + => _collection._operationExecutor.ExecuteWriteOperation( + CreateDropAllOperation(options), + _collection._writeOperationOptions, + cancellationToken: cancellationToken); - public override void DropAll(IClientSessionHandle session, CancellationToken cancellationToken = default(CancellationToken)) - { - DropAll(session, null, cancellationToken); - } + public override void DropAll(IClientSessionHandle session, CancellationToken cancellationToken = default) + => DropAll(session, null, cancellationToken: cancellationToken); - public override void DropAll(IClientSessionHandle session, DropIndexOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - var operation = CreateDropAllOperation(options); - _collection.ExecuteWriteOperation(session, operation, cancellationToken); - } + public override void DropAll(IClientSessionHandle session, DropIndexOptions options, CancellationToken cancellationToken = default) + => _collection._operationExecutor.ExecuteWriteOperation( + CreateDropAllOperation(options), + _collection._writeOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); public override Task DropAllAsync(CancellationToken cancellationToken) - { - return _collection.UsingImplicitSessionAsync(session => DropAllAsync(session, cancellationToken), cancellationToken); - } + => DropAllAsync(options: null, cancellationToken: cancellationToken); - public override Task DropAllAsync(DropIndexOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - return _collection.UsingImplicitSessionAsync(session => DropAllAsync(session, options, cancellationToken), cancellationToken); - } + public override Task DropAllAsync(DropIndexOptions options, CancellationToken cancellationToken = default) + => _collection._operationExecutor.ExecuteWriteOperationAsync( + CreateDropAllOperation(options), + _collection._writeOperationOptions, + cancellationToken: cancellationToken); - public override Task DropAllAsync(IClientSessionHandle session, CancellationToken cancellationToken = default(CancellationToken)) - { - return DropAllAsync(session, null, cancellationToken); - } + public override Task DropAllAsync(IClientSessionHandle session, CancellationToken cancellationToken = default) + => DropAllAsync(session, null, cancellationToken: cancellationToken); - public override Task DropAllAsync(IClientSessionHandle session, DropIndexOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - var operation = CreateDropAllOperation(options); - return _collection.ExecuteWriteOperationAsync(session, operation, cancellationToken); - } + public override Task DropAllAsync(IClientSessionHandle session, DropIndexOptions options, CancellationToken cancellationToken = default) + => _collection._operationExecutor.ExecuteWriteOperationAsync( + CreateDropAllOperation(options), + _collection._writeOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); - public override void DropOne(string name, CancellationToken cancellationToken = default(CancellationToken)) - { - _collection.UsingImplicitSession(session => DropOne(session, name, cancellationToken), cancellationToken); - } + public override void DropOne(string name, CancellationToken cancellationToken = default) + => DropOne(name, null, cancellationToken: cancellationToken); - public override void DropOne(string name, DropIndexOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - _collection.UsingImplicitSession(session => DropOne(session, name, options, cancellationToken), cancellationToken); - } + public override void DropOne(string name, DropIndexOptions options, CancellationToken cancellationToken = default) + => _collection._operationExecutor.ExecuteWriteOperation( + CreateDropOneOperation(name, options), + _collection._writeOperationOptions, + cancellationToken: cancellationToken); - public override void DropOne(IClientSessionHandle session, string name, CancellationToken cancellationToken = default(CancellationToken)) - { - DropOne(session, name, null, cancellationToken); - } + public override void DropOne(IClientSessionHandle session, string name, CancellationToken cancellationToken = default) + => DropOne(session, name, null, cancellationToken: cancellationToken); public override void DropOne( IClientSessionHandle session, string name, DropIndexOptions options, CancellationToken cancellationToken) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNullOrEmpty(name, nameof(name)); - if (name == "*") - { - throw new ArgumentException("Cannot specify '*' for the index name. Use DropAllAsync to drop all indexes.", "name"); - } + => _collection._operationExecutor.ExecuteWriteOperation( + CreateDropOneOperation(name, options), + _collection._writeOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); - var operation = CreateDropOneOperation(name, options); - _collection.ExecuteWriteOperation(session, operation, cancellationToken); - } + public override Task DropOneAsync(string name, CancellationToken cancellationToken = default) + => DropOneAsync(name, null, cancellationToken: cancellationToken); - public override Task DropOneAsync(string name, CancellationToken cancellationToken = default(CancellationToken)) - { - return _collection.UsingImplicitSessionAsync(session => DropOneAsync(session, name, cancellationToken), cancellationToken); - } - - public override Task DropOneAsync(string name, DropIndexOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - return _collection.UsingImplicitSessionAsync(session => DropOneAsync(session, name, options, cancellationToken), cancellationToken); - } + public override Task DropOneAsync(string name, DropIndexOptions options, CancellationToken cancellationToken = default) + => _collection._operationExecutor.ExecuteWriteOperationAsync( + CreateDropOneOperation(name, options), + _collection._writeOperationOptions, + cancellationToken: cancellationToken); - public override Task DropOneAsync(IClientSessionHandle session, string name, CancellationToken cancellationToken = default(CancellationToken)) - { - return DropOneAsync(session, name, null, cancellationToken); - } + public override Task DropOneAsync(IClientSessionHandle session, string name, CancellationToken cancellationToken = default) + => DropOneAsync(session, name, null, cancellationToken: cancellationToken); public override Task DropOneAsync( IClientSessionHandle session, string name, DropIndexOptions options, CancellationToken cancellationToken) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNullOrEmpty(name, nameof(name)); - if (name == "*") - { - throw new ArgumentException("Cannot specify '*' for the index name. Use DropAllAsync to drop all indexes.", "name"); - } + => _collection._operationExecutor.ExecuteWriteOperationAsync( + CreateDropOneOperation(name, options), + _collection._writeOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); - var operation = CreateDropOneOperation(name, options); - return _collection.ExecuteWriteOperationAsync(session, operation, cancellationToken); - } + public override IAsyncCursor List(CancellationToken cancellationToken = default) + => List(options: null, cancellationToken: cancellationToken); - public override IAsyncCursor List(CancellationToken cancellationToken = default(CancellationToken)) - { - return List(options: null, cancellationToken); - } - - public override IAsyncCursor List(ListIndexesOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - return _collection.UsingImplicitSession(session => List(session, options, cancellationToken), cancellationToken); - } + public override IAsyncCursor List(ListIndexesOptions options, CancellationToken cancellationToken = default) + => _collection._operationExecutor.ExecuteReadOperation( + CreateListIndexesOperation(options), + _collection._readOperationOptions, + cancellationToken: cancellationToken); public override IAsyncCursor List(IClientSessionHandle session, CancellationToken cancellationToken = default) - { - return List(session, options: null, cancellationToken); - } + => List(session, options: null, cancellationToken: cancellationToken); - public override IAsyncCursor List(IClientSessionHandle session, ListIndexesOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - var operation = CreateListIndexesOperation(options); - return _collection.ExecuteReadOperation(session, operation, ReadPreference.Primary, cancellationToken); - } + public override IAsyncCursor List(IClientSessionHandle session, ListIndexesOptions options, CancellationToken cancellationToken = default) + => _collection._operationExecutor.ExecuteReadOperation( + CreateListIndexesOperation(options), + _collection._readOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); - public override Task> ListAsync(CancellationToken cancellationToken = default(CancellationToken)) - { - return ListAsync(options: null, cancellationToken); - } + public override Task> ListAsync(CancellationToken cancellationToken = default) + => ListAsync(options: null, cancellationToken: cancellationToken); - public override Task> ListAsync(ListIndexesOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - return _collection.UsingImplicitSessionAsync(session => ListAsync(session, options, cancellationToken), cancellationToken); - } + public override Task> ListAsync(ListIndexesOptions options, CancellationToken cancellationToken = default) + => _collection._operationExecutor.ExecuteReadOperationAsync( + CreateListIndexesOperation(options), + _collection._readOperationOptions, + cancellationToken: cancellationToken); public override Task> ListAsync(IClientSessionHandle session, CancellationToken cancellationToken = default) - { - return ListAsync(session, options: null, cancellationToken); - } + => ListAsync(session, options: null, cancellationToken: cancellationToken); - public override Task> ListAsync(IClientSessionHandle session, ListIndexesOptions options, CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - var operation = CreateListIndexesOperation(options); - return _collection.ExecuteReadOperationAsync(session, operation, ReadPreference.Primary, cancellationToken); - } + public override Task> ListAsync(IClientSessionHandle session, ListIndexesOptions options, CancellationToken cancellationToken = default) + => _collection._operationExecutor.ExecuteReadOperationAsync( + CreateListIndexesOperation(options), + _collection._readOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); // private methods - private CreateIndexesOperation CreateCreateIndexesOperation(IEnumerable requests, CreateManyIndexesOptions options) + private CreateIndexesOperation CreateCreateIndexesOperation(IEnumerable> models, CreateManyIndexesOptions options) { + Ensure.IsNotNull((object)models, nameof(models)); + var requests = CreateCreateIndexRequests(models); + return new CreateIndexesOperation(_collection._collectionNamespace, requests, _collection._messageEncoderSettings) { Comment = options?.Comment, @@ -1760,8 +1494,9 @@ private CreateIndexesOperation CreateCreateIndexesOperation(IEnumerable CreateCreateIndexRequests(IEnumerable> models, RenderArgs renderArgs) + private IEnumerable CreateCreateIndexRequests(IEnumerable> models) { + var renderArgs = _collection.GetRenderArgs(); return models.Select(m => { var options = m.Options ?? new CreateIndexOptions(); @@ -1809,6 +1544,12 @@ private DropIndexOperation CreateDropAllOperation(DropIndexOptions options) private DropIndexOperation CreateDropOneOperation(string name, DropIndexOptions options) { + Ensure.IsNotNullOrEmpty(name, nameof(name)); + if (name == "*") + { + throw new ArgumentException("Cannot specify '*' for the index name. Use DropAll and DropAllAsync to drop all indexes.", "name"); + } + return new DropIndexOperation(_collection._collectionNamespace, name, _collection._messageEncoderSettings) { Comment = options?.Comment, @@ -1842,74 +1583,68 @@ public MongoSearchIndexManager(MongoCollectionImpl collection) public IEnumerable CreateMany(IEnumerable models, CancellationToken cancellationToken = default) { var operation = CreateCreateIndexesOperation(models); - var result = _collection.UsingImplicitSession(session => _collection.ExecuteWriteOperation(session, operation, cancellationToken), cancellationToken); - var indexNames = GetIndexNames(result); - - return indexNames; + var result = _collection._operationExecutor.ExecuteWriteOperation(operation, _collection._writeOperationOptions, cancellationToken: cancellationToken); + return GetIndexNames(result); } public async Task> CreateManyAsync(IEnumerable models, CancellationToken cancellationToken = default) { var operation = CreateCreateIndexesOperation(models); - var result = await _collection.UsingImplicitSessionAsync(session => _collection.ExecuteWriteOperationAsync(session, operation, cancellationToken), cancellationToken).ConfigureAwait(false); - var indexNames = GetIndexNames(result); - - return indexNames; + var result = await _collection._operationExecutor.ExecuteWriteOperationAsync(operation, _collection._writeOperationOptions, cancellationToken: cancellationToken).ConfigureAwait(false); + return GetIndexNames(result); } public string CreateOne(BsonDocument definition, string name = null, CancellationToken cancellationToken = default) => - CreateOne(new CreateSearchIndexModel(name, definition), cancellationToken); + CreateOne(new CreateSearchIndexModel(name, definition), cancellationToken: cancellationToken); public string CreateOne(CreateSearchIndexModel model, CancellationToken cancellationToken = default) { - var result = CreateMany(new[] { model }, cancellationToken); + var result = CreateMany(new[] { model }, cancellationToken: cancellationToken); return result.Single(); } public Task CreateOneAsync(BsonDocument definition, string name = null, CancellationToken cancellationToken = default) => - CreateOneAsync(new CreateSearchIndexModel(name, definition), cancellationToken); + CreateOneAsync(new CreateSearchIndexModel(name, definition), cancellationToken: cancellationToken); public async Task CreateOneAsync(CreateSearchIndexModel model, CancellationToken cancellationToken = default) { - var result = await CreateManyAsync(new[] { model }, cancellationToken).ConfigureAwait(false); + var result = await CreateManyAsync(new[] { model }, cancellationToken: cancellationToken).ConfigureAwait(false); return result.Single(); } public void DropOne(string indexName, CancellationToken cancellationToken = default) - { - var operation = new DropSearchIndexOperation(_collection.CollectionNamespace, indexName, _collection._messageEncoderSettings); - _collection.UsingImplicitSession(session => _collection.ExecuteWriteOperation(session, operation, cancellationToken), cancellationToken); - } + => _collection._operationExecutor.ExecuteWriteOperation( + new DropSearchIndexOperation(_collection.CollectionNamespace, indexName, _collection._messageEncoderSettings), + _collection._writeOperationOptions, + cancellationToken: cancellationToken); public Task DropOneAsync(string indexName, CancellationToken cancellationToken = default) - { - var operation = new DropSearchIndexOperation(_collection.CollectionNamespace, indexName, _collection._messageEncoderSettings); - return _collection.UsingImplicitSessionAsync(session => _collection.ExecuteWriteOperationAsync(session, operation, cancellationToken), cancellationToken); - } + => _collection._operationExecutor.ExecuteWriteOperationAsync( + new DropSearchIndexOperation(_collection.CollectionNamespace, indexName, _collection._messageEncoderSettings), + _collection._writeOperationOptions, + cancellationToken: cancellationToken); public IAsyncCursor List(string indexName, AggregateOptions aggregateOptions = null, CancellationToken cancellationToken = default) { - return _collection.WithReadConcern(ReadConcern.Default).Aggregate(CreateListIndexesStage(indexName), aggregateOptions, cancellationToken); + return _collection.WithReadConcern(ReadConcern.Default).Aggregate(CreateListIndexesStage(indexName), aggregateOptions, cancellationToken: cancellationToken); } public Task> ListAsync(string indexName, AggregateOptions aggregateOptions = null, CancellationToken cancellationToken = default) { - return _collection.WithReadConcern(ReadConcern.Default).AggregateAsync(CreateListIndexesStage(indexName), aggregateOptions, cancellationToken); + return _collection.WithReadConcern(ReadConcern.Default).AggregateAsync(CreateListIndexesStage(indexName), aggregateOptions, cancellationToken: cancellationToken); } public void Update(string indexName, BsonDocument definition, CancellationToken cancellationToken = default) - { - var operation = new UpdateSearchIndexOperation(_collection.CollectionNamespace, indexName, definition, _collection._messageEncoderSettings); - - _collection.UsingImplicitSession(session => _collection.ExecuteWriteOperation(session, operation, cancellationToken), cancellationToken); - } - - public async Task UpdateAsync(string indexName, BsonDocument definition, CancellationToken cancellationToken = default) - { - var operation = new UpdateSearchIndexOperation(_collection.CollectionNamespace, indexName, definition, _collection._messageEncoderSettings); - - await _collection.UsingImplicitSessionAsync(session => _collection.ExecuteWriteOperationAsync(session, operation, cancellationToken), cancellationToken).ConfigureAwait(false); - } + => _collection._operationExecutor.ExecuteWriteOperation( + new UpdateSearchIndexOperation(_collection.CollectionNamespace, indexName, definition, _collection._messageEncoderSettings), + _collection._writeOperationOptions, + cancellationToken: cancellationToken); + + public Task UpdateAsync(string indexName, BsonDocument definition, CancellationToken cancellationToken = default) + => _collection._operationExecutor.ExecuteWriteOperationAsync( + new UpdateSearchIndexOperation(_collection.CollectionNamespace, indexName, definition, _collection._messageEncoderSettings), + _collection._writeOperationOptions, + cancellationToken: cancellationToken); // private methods private PipelineDefinition CreateListIndexesStage(string indexName) diff --git a/src/MongoDB.Driver/MongoDatabase.cs b/src/MongoDB.Driver/MongoDatabase.cs index a57eec55d94..1d433dcec44 100644 --- a/src/MongoDB.Driver/MongoDatabase.cs +++ b/src/MongoDB.Driver/MongoDatabase.cs @@ -23,8 +23,6 @@ using MongoDB.Bson.IO; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; -using MongoDB.Driver.Core; -using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Clusters; using MongoDB.Driver.Core.Misc; using MongoDB.Driver.Core.Operations; @@ -41,6 +39,8 @@ internal sealed class MongoDatabase : IMongoDatabase private readonly DatabaseNamespace _databaseNamespace; private readonly IOperationExecutor _operationExecutor; private readonly MongoDatabaseSettings _settings; + private readonly ReadOperationOptions _readOperationOptions; + private readonly WriteOperationOptions _writeOperationOptions; // constructors public MongoDatabase(IMongoClient client, DatabaseNamespace databaseNamespace, MongoDatabaseSettings settings, IClusterInternal cluster, IOperationExecutor operationExecutor) @@ -50,6 +50,9 @@ public MongoDatabase(IMongoClient client, DatabaseNamespace databaseNamespace, M _settings = Ensure.IsNotNull(settings, nameof(settings)).Freeze(); _cluster = Ensure.IsNotNull(cluster, nameof(cluster)); _operationExecutor = Ensure.IsNotNull(operationExecutor, nameof(operationExecutor)); + + _readOperationOptions = new(DefaultReadPreference: _settings.ReadPreference); + _writeOperationOptions = new(); } // public properties @@ -58,131 +61,110 @@ public MongoDatabase(IMongoClient client, DatabaseNamespace databaseNamespace, M public MongoDatabaseSettings Settings => _settings; // public methods - public IAsyncCursor Aggregate(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default(CancellationToken)) + public IAsyncCursor Aggregate(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { - return UsingImplicitSession(session => Aggregate(session, pipeline, options, cancellationToken), cancellationToken); + using var session = _operationExecutor.StartImplicitSession(cancellationToken); + return Aggregate(session, pipeline, options, cancellationToken: cancellationToken); } - public IAsyncCursor Aggregate(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default(CancellationToken)) + public IAsyncCursor Aggregate(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); - var renderArgs = GetRenderArgs(NoPipelineInputSerializer.Instance, options?.TranslationOptions); - var renderedPipeline = Ensure.IsNotNull(pipeline, nameof(pipeline)).Render(renderArgs); - options = options ?? new AggregateOptions(); + Ensure.IsNotNull(pipeline, nameof(pipeline)); + options ??= new AggregateOptions(); - var lastStage = renderedPipeline.Documents.LastOrDefault(); - var lastStageName = lastStage?.GetElement(0).Name; - if (lastStage != null && (lastStageName == "$out" || lastStageName == "$merge")) + var renderArgs = GetRenderArgs(NoPipelineInputSerializer.Instance, options.TranslationOptions); + var renderedPipeline = AggregateHelper.RenderAggregatePipeline(pipeline, renderArgs, out bool isAggregateToCollection); + if (isAggregateToCollection) { var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - ExecuteWriteOperation(session, aggregateOperation, cancellationToken); - - // we want to delay execution of the find because the user may - // not want to iterate the results at all... - var findOperation = CreateAggregateToCollectionFindOperation(lastStage, renderedPipeline.OutputSerializer, options); - var forkedSession = session.Fork(); - var deferredCursor = new DeferredAsyncCursor( - () => forkedSession.Dispose(), - ct => ExecuteReadOperation(forkedSession, findOperation, ReadPreference.Primary, ct), - ct => ExecuteReadOperationAsync(forkedSession, findOperation, ReadPreference.Primary, ct)); - return deferredCursor; + _operationExecutor.ExecuteWriteOperation(aggregateOperation, _writeOperationOptions, session, cancellationToken: cancellationToken); + return CreateAggregateToCollectionResultCursor(session, renderedPipeline, options); } else { var aggregateOperation = CreateAggregateOperation(renderedPipeline, options); - return ExecuteReadOperation(session, aggregateOperation, cancellationToken); + return _operationExecutor.ExecuteReadOperation(aggregateOperation, _readOperationOptions, session, cancellationToken: cancellationToken); } } - public Task> AggregateAsync(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default(CancellationToken)) + public async Task> AggregateAsync(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { - return UsingImplicitSessionAsync(session => AggregateAsync(session, pipeline, options, cancellationToken), cancellationToken); + using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken: cancellationToken).ConfigureAwait(false); + return await AggregateAsync(session, pipeline, options, cancellationToken: cancellationToken).ConfigureAwait(false); } - public async Task> AggregateAsync(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default(CancellationToken)) + public async Task> AggregateAsync(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); - var renderArgs = GetRenderArgs(NoPipelineInputSerializer.Instance, options?.TranslationOptions); - var renderedPipeline = Ensure.IsNotNull(pipeline, nameof(pipeline)).Render(renderArgs); - options = options ?? new AggregateOptions(); + Ensure.IsNotNull(pipeline, nameof(pipeline)); + options ??= new AggregateOptions(); - var lastStage = renderedPipeline.Documents.LastOrDefault(); - var lastStageName = lastStage?.GetElement(0).Name; - if (lastStage != null && (lastStageName == "$out" || lastStageName == "$merge")) + var renderArgs = GetRenderArgs(NoPipelineInputSerializer.Instance, options.TranslationOptions); + var renderedPipeline = AggregateHelper.RenderAggregatePipeline(pipeline, renderArgs, out bool isAggregateToCollection); + if (isAggregateToCollection) { var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - await ExecuteWriteOperationAsync(session, aggregateOperation, cancellationToken).ConfigureAwait(false); - - // we want to delay execution of the find because the user may - // not want to iterate the results at all... - var findOperation = CreateAggregateToCollectionFindOperation(lastStage, renderedPipeline.OutputSerializer, options); - var forkedSession = session.Fork(); - var deferredCursor = new DeferredAsyncCursor( - () => forkedSession.Dispose(), - ct => ExecuteReadOperation(forkedSession, findOperation, ReadPreference.Primary, ct), - ct => ExecuteReadOperationAsync(forkedSession, findOperation, ReadPreference.Primary, ct)); - return await Task.FromResult>(deferredCursor).ConfigureAwait(false); + await _operationExecutor.ExecuteWriteOperationAsync(aggregateOperation, _writeOperationOptions, session, cancellationToken: cancellationToken).ConfigureAwait(false); + return CreateAggregateToCollectionResultCursor(session, renderedPipeline, options); } else { var aggregateOperation = CreateAggregateOperation(renderedPipeline, options); - return await ExecuteReadOperationAsync(session, aggregateOperation, cancellationToken).ConfigureAwait(false); + return await _operationExecutor.ExecuteReadOperationAsync(aggregateOperation, _readOperationOptions, session, cancellationToken: cancellationToken).ConfigureAwait(false); } } - public void AggregateToCollection(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default(CancellationToken)) + public void AggregateToCollection(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { - UsingImplicitSession(session => AggregateToCollection(session, pipeline, options, cancellationToken), cancellationToken); + using var session = _operationExecutor.StartImplicitSession(cancellationToken); + AggregateToCollection(session, pipeline, options, cancellationToken: cancellationToken); } - public void AggregateToCollection(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default(CancellationToken)) + public void AggregateToCollection(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); - var renderArgs = GetRenderArgs(NoPipelineInputSerializer.Instance, options?.TranslationOptions); - var renderedPipeline = Ensure.IsNotNull(pipeline, nameof(pipeline)).Render(renderArgs); - options = options ?? new AggregateOptions(); + Ensure.IsNotNull(pipeline, nameof(pipeline)); + options ??= new AggregateOptions(); - var lastStage = renderedPipeline.Documents.LastOrDefault(); - var lastStageName = lastStage?.GetElement(0).Name; - if (lastStage == null || (lastStageName != "$out" && lastStageName != "$merge")) + var renderArgs = GetRenderArgs(NoPipelineInputSerializer.Instance, options.TranslationOptions); + var renderedPipeline = AggregateHelper.RenderAggregatePipeline(pipeline, renderArgs, out bool isAggregateToCollection); + if (!isAggregateToCollection) { throw new InvalidOperationException("AggregateToCollection requires that the last stage be $out or $merge."); } - else - { - var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - ExecuteWriteOperation(session, aggregateOperation, cancellationToken); - } + + var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); + _operationExecutor.ExecuteWriteOperation(aggregateOperation, _writeOperationOptions, session, cancellationToken: cancellationToken); } - public Task AggregateToCollectionAsync(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default(CancellationToken)) + public async Task AggregateToCollectionAsync(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { - return UsingImplicitSessionAsync(session => AggregateToCollectionAsync(session, pipeline, options, cancellationToken), cancellationToken); + using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken: cancellationToken).ConfigureAwait(false); + await AggregateToCollectionAsync(session, pipeline, options, cancellationToken: cancellationToken).ConfigureAwait(false); } - public async Task AggregateToCollectionAsync(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default(CancellationToken)) + public async Task AggregateToCollectionAsync(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); - var renderArgs = GetRenderArgs(NoPipelineInputSerializer.Instance, options?.TranslationOptions); - var renderedPipeline = Ensure.IsNotNull(pipeline, nameof(pipeline)).Render(renderArgs); - options = options ?? new AggregateOptions(); + Ensure.IsNotNull(pipeline, nameof(pipeline)); + options ??= new AggregateOptions(); - var lastStage = renderedPipeline.Documents.LastOrDefault(); - var lastStageName = lastStage?.GetElement(0).Name; - if (lastStage == null || (lastStageName != "$out" && lastStageName != "$merge")) + var renderArgs = GetRenderArgs(NoPipelineInputSerializer.Instance, options.TranslationOptions); + var renderedPipeline = AggregateHelper.RenderAggregatePipeline(pipeline, renderArgs, out bool isAggregateToCollection); + if (!isAggregateToCollection) { throw new InvalidOperationException("AggregateToCollectionAsync requires that the last stage be $out or $merge."); } - else - { - var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - await ExecuteWriteOperationAsync(session, aggregateOperation, cancellationToken).ConfigureAwait(false); - } + + var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); + await _operationExecutor.ExecuteWriteOperationAsync(aggregateOperation, _writeOperationOptions, session, cancellationToken: cancellationToken).ConfigureAwait(false); } public void CreateCollection(string name, CreateCollectionOptions options, CancellationToken cancellationToken) { - UsingImplicitSession(session => CreateCollection(session, name, options, cancellationToken), cancellationToken); + using var session = _operationExecutor.StartImplicitSession(cancellationToken); + CreateCollection(session, name, options, cancellationToken: cancellationToken); } public void CreateCollection(IClientSessionHandle session, string name, CreateCollectionOptions options, CancellationToken cancellationToken) @@ -192,18 +174,18 @@ public void CreateCollection(IClientSessionHandle session, string name, CreateCo if (options == null) { - CreateCollectionHelper(session, name, null, cancellationToken); + CreateCollectionHelper(session, name, null, cancellationToken: cancellationToken); return; } if (options.GetType() == typeof(CreateCollectionOptions)) { var genericOptions = CreateCollectionOptions.CoercedFrom(options); - CreateCollectionHelper(session, name, genericOptions, cancellationToken); + CreateCollectionHelper(session, name, genericOptions, cancellationToken: cancellationToken); return; } - var genericMethodDefinition = typeof(MongoDatabase).GetTypeInfo().GetMethod("CreateCollectionHelper", BindingFlags.NonPublic | BindingFlags.Instance); + var genericMethodDefinition = typeof(MongoDatabase).GetTypeInfo().GetMethod(nameof(CreateCollectionHelper), BindingFlags.NonPublic | BindingFlags.Instance); var documentType = options.GetType().GetTypeInfo().GetGenericArguments()[0]; var methodInfo = genericMethodDefinition.MakeGenericMethod(documentType); try @@ -216,9 +198,10 @@ public void CreateCollection(IClientSessionHandle session, string name, CreateCo } } - public Task CreateCollectionAsync(string name, CreateCollectionOptions options, CancellationToken cancellationToken) + public async Task CreateCollectionAsync(string name, CreateCollectionOptions options, CancellationToken cancellationToken) { - return UsingImplicitSessionAsync(session => CreateCollectionAsync(session, name, options, cancellationToken), cancellationToken); + using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken: cancellationToken).ConfigureAwait(false); + await CreateCollectionAsync(session, name, options, cancellationToken: cancellationToken).ConfigureAwait(false); } public async Task CreateCollectionAsync(IClientSessionHandle session, string name, CreateCollectionOptions options, CancellationToken cancellationToken) @@ -228,18 +211,18 @@ public async Task CreateCollectionAsync(IClientSessionHandle session, string nam if (options == null) { - await CreateCollectionHelperAsync(session, name, null, cancellationToken).ConfigureAwait(false); + await CreateCollectionHelperAsync(session, name, null, cancellationToken: cancellationToken).ConfigureAwait(false); return; } if (options.GetType() == typeof(CreateCollectionOptions)) { var genericOptions = CreateCollectionOptions.CoercedFrom(options); - await CreateCollectionHelperAsync(session, name, genericOptions, cancellationToken).ConfigureAwait(false); + await CreateCollectionHelperAsync(session, name, genericOptions, cancellationToken: cancellationToken).ConfigureAwait(false); return; } - var genericMethodDefinition = typeof(MongoDatabase).GetTypeInfo().GetMethod("CreateCollectionHelperAsync", BindingFlags.NonPublic | BindingFlags.Instance); + var genericMethodDefinition = typeof(MongoDatabase).GetTypeInfo().GetMethod(nameof(CreateCollectionHelperAsync), BindingFlags.NonPublic | BindingFlags.Instance); var documentType = options.GetType().GetTypeInfo().GetGenericArguments()[0]; var methodInfo = genericMethodDefinition.MakeGenericMethod(documentType); try @@ -252,84 +235,84 @@ public async Task CreateCollectionAsync(IClientSessionHandle session, string nam } } - public void CreateView(string viewName, string viewOn, PipelineDefinition pipeline, CreateViewOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) - { - UsingImplicitSession(session => CreateView(session, viewName, viewOn, pipeline, options, cancellationToken), cancellationToken); - } - - public void CreateView(IClientSessionHandle session, string viewName, string viewOn, PipelineDefinition pipeline, CreateViewOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(viewName, nameof(viewName)); - Ensure.IsNotNull(viewOn, nameof(viewOn)); - Ensure.IsNotNull(pipeline, nameof(pipeline)); - options = options ?? new CreateViewOptions(); - var translationOptions = _client.Settings.TranslationOptions; - var operation = CreateCreateViewOperation(viewName, viewOn, pipeline, options, translationOptions); - ExecuteWriteOperation(session, operation, cancellationToken); - } - - public Task CreateViewAsync(string viewName, string viewOn, PipelineDefinition pipeline, CreateViewOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) - { - return UsingImplicitSessionAsync(session => CreateViewAsync(session, viewName, viewOn, pipeline, options, cancellationToken), cancellationToken); - } - - public Task CreateViewAsync(IClientSessionHandle session, string viewName, string viewOn, PipelineDefinition pipeline, CreateViewOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(viewName, nameof(viewName)); - Ensure.IsNotNull(viewOn, nameof(viewOn)); - Ensure.IsNotNull(pipeline, nameof(pipeline)); - options = options ?? new CreateViewOptions(); - var translationOptions = _client.Settings.TranslationOptions; - var operation = CreateCreateViewOperation(viewName, viewOn, pipeline, options, translationOptions); - return ExecuteWriteOperationAsync(session, operation, cancellationToken); - } + public void CreateView(string viewName, string viewOn, PipelineDefinition pipeline, CreateViewOptions options = null, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteWriteOperation( + CreateCreateViewOperation(viewName, viewOn, pipeline, options), + _writeOperationOptions, + cancellationToken: cancellationToken); + + public void CreateView(IClientSessionHandle session, string viewName, string viewOn, PipelineDefinition pipeline, CreateViewOptions options = null, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteWriteOperation( + CreateCreateViewOperation(viewName, viewOn, pipeline, options), + _writeOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); + + public Task CreateViewAsync(string viewName, string viewOn, PipelineDefinition pipeline, CreateViewOptions options = null, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteWriteOperationAsync( + CreateCreateViewOperation(viewName, viewOn, pipeline, options), + _writeOperationOptions, + cancellationToken: cancellationToken); + + public Task CreateViewAsync(IClientSessionHandle session, string viewName, string viewOn, PipelineDefinition pipeline, CreateViewOptions options = null, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteWriteOperationAsync( + CreateCreateViewOperation(viewName, viewOn, pipeline, options), + _writeOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); public void DropCollection(string name, CancellationToken cancellationToken) { - DropCollection(name, options: null, cancellationToken); + DropCollection(name, options: null, cancellationToken: cancellationToken); } public void DropCollection(string name, DropCollectionOptions options, CancellationToken cancellationToken = default) { - UsingImplicitSession(session => DropCollection(session, name, options, cancellationToken), cancellationToken); + using var session = _operationExecutor.StartImplicitSession(cancellationToken); + DropCollection(session, name, options, cancellationToken: cancellationToken); } public void DropCollection(IClientSessionHandle session, string name, CancellationToken cancellationToken) { - DropCollection(session, name, options: null, cancellationToken); + DropCollection(session, name, options: null, cancellationToken: cancellationToken); } public void DropCollection(IClientSessionHandle session, string name, DropCollectionOptions options, CancellationToken cancellationToken) { Ensure.IsNotNull(session, nameof(session)); Ensure.IsNotNullOrEmpty(name, nameof(name)); - var operation = CreateDropCollectionOperation(name, options, session, cancellationToken); - ExecuteWriteOperation(session, operation, cancellationToken); + + var collectionNamespace = new CollectionNamespace(_databaseNamespace, name); + var encryptedFields = GetEncryptedFields(session, collectionNamespace, options, cancellationToken: cancellationToken); + var operation = CreateDropCollectionOperation(collectionNamespace, encryptedFields); + _operationExecutor.ExecuteWriteOperation(operation, _writeOperationOptions, session, cancellationToken: cancellationToken); } public Task DropCollectionAsync(string name, CancellationToken cancellationToken) { - return DropCollectionAsync(name, options: null, cancellationToken); + return DropCollectionAsync(name, options: null, cancellationToken: cancellationToken); } - public Task DropCollectionAsync(string name, DropCollectionOptions options, CancellationToken cancellationToken) + public async Task DropCollectionAsync(string name, DropCollectionOptions options, CancellationToken cancellationToken) { - return UsingImplicitSessionAsync(session => DropCollectionAsync(session, name, options, cancellationToken), cancellationToken); + using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken: cancellationToken).ConfigureAwait(false); + await DropCollectionAsync(session, name, options, cancellationToken: cancellationToken).ConfigureAwait(false); } public Task DropCollectionAsync(IClientSessionHandle session, string name, CancellationToken cancellationToken) { - return DropCollectionAsync(session, name, options: null, cancellationToken); + return DropCollectionAsync(session, name, options: null, cancellationToken: cancellationToken); } public async Task DropCollectionAsync(IClientSessionHandle session, string name, DropCollectionOptions options, CancellationToken cancellationToken) { Ensure.IsNotNull(session, nameof(session)); Ensure.IsNotNullOrEmpty(name, nameof(name)); - var operation = await CreateDropCollectionOperationAsync(name, options, session, cancellationToken).ConfigureAwait(false); - await ExecuteWriteOperationAsync(session, operation, cancellationToken).ConfigureAwait(false); + + var collectionNamespace = new CollectionNamespace(_databaseNamespace, name); + var encryptedFields = await GetEncryptedFieldsAsync(session, collectionNamespace, options, cancellationToken: cancellationToken).ConfigureAwait(false); + var operation = CreateDropCollectionOperation(collectionNamespace, encryptedFields); + await _operationExecutor.ExecuteWriteOperationAsync(operation, _writeOperationOptions, session, cancellationToken: cancellationToken).ConfigureAwait(false); } public IMongoCollection GetCollection(string name, MongoCollectionSettings settings) @@ -345,167 +328,162 @@ public IMongoCollection GetCollection(string name, MongoCo return new MongoCollectionImpl(this, new CollectionNamespace(_databaseNamespace, name), settings, _cluster, _operationExecutor); } - public IAsyncCursor ListCollectionNames(ListCollectionNamesOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) + public IAsyncCursor ListCollectionNames(ListCollectionNamesOptions options = null, CancellationToken cancellationToken = default) { - return UsingImplicitSession(session => ListCollectionNames(session, options, cancellationToken), cancellationToken); + var cursor = _operationExecutor.ExecuteReadOperation( + CreateListCollectionNamesOperation(options), + _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, + null, + cancellationToken: cancellationToken); + return new BatchTransformingAsyncCursor(cursor, ExtractCollectionNames); } - public IAsyncCursor ListCollectionNames(IClientSessionHandle session, ListCollectionNamesOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) + public IAsyncCursor ListCollectionNames(IClientSessionHandle session, ListCollectionNamesOptions options = null, CancellationToken cancellationToken = default) { - Ensure.IsNotNull(session, nameof(session)); - var renderArgs = GetRenderArgs(BsonDocumentSerializer.Instance); - var operation = CreateListCollectionNamesOperation(options, renderArgs); - var effectiveReadPreference = ReadPreferenceResolver.GetEffectiveReadPreference(session, null, ReadPreference.Primary); - var cursor = ExecuteReadOperation(session, operation, effectiveReadPreference, cancellationToken); + var cursor = _operationExecutor.ExecuteReadOperation( + CreateListCollectionNamesOperation(options), + _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); return new BatchTransformingAsyncCursor(cursor, ExtractCollectionNames); } - public Task> ListCollectionNamesAsync(ListCollectionNamesOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) + public async Task> ListCollectionNamesAsync(ListCollectionNamesOptions options = null, CancellationToken cancellationToken = default) { - return UsingImplicitSessionAsync(session => ListCollectionNamesAsync(session, options, cancellationToken), cancellationToken); + var cursor = await _operationExecutor.ExecuteReadOperationAsync( + CreateListCollectionNamesOperation(options), + _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, + cancellationToken: cancellationToken).ConfigureAwait(false); + return new BatchTransformingAsyncCursor(cursor, ExtractCollectionNames); } - public async Task> ListCollectionNamesAsync(IClientSessionHandle session, ListCollectionNamesOptions options = null, CancellationToken cancellationToken = default(CancellationToken)) + public async Task> ListCollectionNamesAsync(IClientSessionHandle session, ListCollectionNamesOptions options = null, CancellationToken cancellationToken = default) { - Ensure.IsNotNull(session, nameof(session)); - var renderArgs = GetRenderArgs(BsonDocumentSerializer.Instance); - var operation = CreateListCollectionNamesOperation(options, renderArgs); - var effectiveReadPreference = ReadPreferenceResolver.GetEffectiveReadPreference(session, null, ReadPreference.Primary); - var cursor = await ExecuteReadOperationAsync(session, operation, effectiveReadPreference, cancellationToken).ConfigureAwait(false); + var cursor = await _operationExecutor.ExecuteReadOperationAsync( + CreateListCollectionNamesOperation(options), + _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken).ConfigureAwait(false); return new BatchTransformingAsyncCursor(cursor, ExtractCollectionNames); } public IAsyncCursor ListCollections(ListCollectionsOptions options, CancellationToken cancellationToken) - { - return UsingImplicitSession(session => ListCollections(session, options, cancellationToken), cancellationToken); - } + => _operationExecutor.ExecuteReadOperation( + CreateListCollectionsOperation(options), + _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, + cancellationToken: cancellationToken); public IAsyncCursor ListCollections(IClientSessionHandle session, ListCollectionsOptions options, CancellationToken cancellationToken) - { - Ensure.IsNotNull(session, nameof(session)); - var renderArgs = GetRenderArgs(BsonDocumentSerializer.Instance); - var operation = CreateListCollectionsOperation(options, renderArgs); - var effectiveReadPreference = ReadPreferenceResolver.GetEffectiveReadPreference(session, null, ReadPreference.Primary); - return ExecuteReadOperation(session, operation, effectiveReadPreference, cancellationToken); - } + => _operationExecutor.ExecuteReadOperation( + CreateListCollectionsOperation(options), + _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); public Task> ListCollectionsAsync(ListCollectionsOptions options, CancellationToken cancellationToken) - { - return UsingImplicitSessionAsync(session => ListCollectionsAsync(session, options, cancellationToken), cancellationToken); - } + => _operationExecutor.ExecuteReadOperationAsync( + CreateListCollectionsOperation(options), + _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, + cancellationToken: cancellationToken); public Task> ListCollectionsAsync(IClientSessionHandle session, ListCollectionsOptions options, CancellationToken cancellationToken) - { - Ensure.IsNotNull(session, nameof(session)); - var renderArgs = GetRenderArgs(BsonDocumentSerializer.Instance); - var operation = CreateListCollectionsOperation(options, renderArgs); - var effectiveReadPreference = ReadPreferenceResolver.GetEffectiveReadPreference(session, null, ReadPreference.Primary); - return ExecuteReadOperationAsync(session, operation, effectiveReadPreference, cancellationToken); - } + => _operationExecutor.ExecuteReadOperationAsync( + CreateListCollectionsOperation(options), + _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); public void RenameCollection(string oldName, string newName, RenameCollectionOptions options, CancellationToken cancellationToken) - { - UsingImplicitSession(session => RenameCollection(session, oldName, newName, options, cancellationToken), cancellationToken); - } + => _operationExecutor.ExecuteWriteOperation( + CreateRenameCollectionOperation(oldName, newName, options), + _writeOperationOptions, + cancellationToken: cancellationToken); public void RenameCollection(IClientSessionHandle session, string oldName, string newName, RenameCollectionOptions options, CancellationToken cancellationToken) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNullOrEmpty(oldName, nameof(oldName)); - Ensure.IsNotNullOrEmpty(newName, nameof(newName)); - options = options ?? new RenameCollectionOptions(); - - var operation = CreateRenameCollectionOperation(oldName, newName, options); - ExecuteWriteOperation(session, operation, cancellationToken); - } + => _operationExecutor.ExecuteWriteOperation( + CreateRenameCollectionOperation(oldName, newName, options), + _writeOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); public Task RenameCollectionAsync(string oldName, string newName, RenameCollectionOptions options, CancellationToken cancellationToken) - { - return UsingImplicitSessionAsync(session => RenameCollectionAsync(session, oldName, newName, options, cancellationToken), cancellationToken); - } + => _operationExecutor.ExecuteWriteOperationAsync( + CreateRenameCollectionOperation(oldName, newName, options), + _writeOperationOptions, + cancellationToken: cancellationToken); public Task RenameCollectionAsync(IClientSessionHandle session, string oldName, string newName, RenameCollectionOptions options, CancellationToken cancellationToken) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNullOrEmpty(oldName, nameof(oldName)); - Ensure.IsNotNullOrEmpty(newName, nameof(newName)); - options = options ?? new RenameCollectionOptions(); - - var operation = CreateRenameCollectionOperation(oldName, newName, options); - return ExecuteWriteOperationAsync(session, operation, cancellationToken); - } - - public TResult RunCommand(Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default(CancellationToken)) - { - return UsingImplicitSession(session => RunCommand(session, command, readPreference, cancellationToken), cancellationToken); - } - - public TResult RunCommand(IClientSessionHandle session, Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(command, nameof(command)); - - var operation = CreateRunCommandOperation(command); - var effectiveReadPreference = ReadPreferenceResolver.GetEffectiveReadPreference(session, readPreference, ReadPreference.Primary); - return ExecuteReadOperation(session, operation, effectiveReadPreference, cancellationToken); - } - - public Task RunCommandAsync(Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default(CancellationToken)) - { - return UsingImplicitSessionAsync(session => RunCommandAsync(session, command, readPreference, cancellationToken), cancellationToken); - } - - public Task RunCommandAsync(IClientSessionHandle session, Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(command, nameof(command)); - - var operation = CreateRunCommandOperation(command); - var effectiveReadPreference = ReadPreferenceResolver.GetEffectiveReadPreference(session, readPreference, ReadPreference.Primary); - return ExecuteReadOperationAsync(session, operation, effectiveReadPreference, cancellationToken); - } + => _operationExecutor.ExecuteWriteOperationAsync( + CreateRenameCollectionOperation(oldName, newName, options), + _writeOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); + + public TResult RunCommand(Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperation( + CreateRunCommandOperation(command), + _readOperationOptions with { ExplicitReadPreference = readPreference, DefaultReadPreference = ReadPreference.Primary}, + cancellationToken: cancellationToken); + + public TResult RunCommand(IClientSessionHandle session, Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperation( + CreateRunCommandOperation(command), + _readOperationOptions with { ExplicitReadPreference = readPreference, DefaultReadPreference = ReadPreference.Primary}, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); + + public Task RunCommandAsync(Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperationAsync( + CreateRunCommandOperation(command), + _readOperationOptions with { ExplicitReadPreference = readPreference, DefaultReadPreference = ReadPreference.Primary}, + cancellationToken: cancellationToken); + + public Task RunCommandAsync(IClientSessionHandle session, Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperationAsync( + CreateRunCommandOperation(command), + _readOperationOptions with { ExplicitReadPreference = readPreference, DefaultReadPreference = ReadPreference.Primary}, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); public IChangeStreamCursor Watch( PipelineDefinition, TResult> pipeline, ChangeStreamOptions options = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - return UsingImplicitSession(session => Watch(session, pipeline, options, cancellationToken), cancellationToken); - } + CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperation( + CreateChangeStreamOperation(pipeline, options), + _readOperationOptions, + cancellationToken: cancellationToken); public IChangeStreamCursor Watch( IClientSessionHandle session, PipelineDefinition, TResult> pipeline, ChangeStreamOptions options = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(pipeline, nameof(pipeline)); - var translationOptions = _client.Settings.TranslationOptions; - var operation = CreateChangeStreamOperation(pipeline, options, translationOptions); - return ExecuteReadOperation(session, operation, cancellationToken); - } + CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperation( + CreateChangeStreamOperation(pipeline, options), + _readOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); public Task> WatchAsync( PipelineDefinition, TResult> pipeline, ChangeStreamOptions options = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - return UsingImplicitSessionAsync(session => WatchAsync(session, pipeline, options, cancellationToken), cancellationToken); - } + CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperationAsync( + CreateChangeStreamOperation(pipeline, options), + _readOperationOptions, + cancellationToken: cancellationToken); public Task> WatchAsync( IClientSessionHandle session, PipelineDefinition, TResult> pipeline, ChangeStreamOptions options = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull(pipeline, nameof(pipeline)); - var translationOptions = _client.Settings.TranslationOptions; - var operation = CreateChangeStreamOperation(pipeline, options, translationOptions); - return ExecuteReadOperationAsync(session, operation, cancellationToken); - } + CancellationToken cancellationToken = default) + => _operationExecutor.ExecuteReadOperationAsync( + CreateChangeStreamOperation(pipeline, options), + _readOperationOptions, + Ensure.IsNotNull(session, nameof(session)), + cancellationToken: cancellationToken); public IMongoDatabase WithReadConcern(ReadConcern readConcern) { @@ -532,6 +510,7 @@ public IMongoDatabase WithWriteConcern(WriteConcern writeConcern) } // private methods + private AggregateOperation CreateAggregateOperation(RenderedPipelineDefinition renderedPipeline, AggregateOptions options) { var messageEncoderSettings = GetMessageEncoderSettings(); @@ -557,59 +536,16 @@ private AggregateOperation CreateAggregateOperation(RenderedPi }; } - private FindOperation CreateAggregateToCollectionFindOperation(BsonDocument outStage, IBsonSerializer resultSerializer, AggregateOptions options) + private IAsyncCursor CreateAggregateToCollectionResultCursor(IClientSessionHandle session, RenderedPipelineDefinition pipeline, AggregateOptions options) { - CollectionNamespace outputCollectionNamespace; - var stageName = outStage.GetElement(0).Name; - switch (stageName) - { - case "$out": - { - var outValue = outStage[0]; - DatabaseNamespace outputDatabaseNamespace; - string outputCollectionName; - if (outValue.IsString) - { - outputDatabaseNamespace = _databaseNamespace; - outputCollectionName = outValue.AsString; - } - else - { - outputDatabaseNamespace = new DatabaseNamespace(outValue["db"].AsString); - outputCollectionName = outValue["coll"].AsString; - } - outputCollectionNamespace = new CollectionNamespace(outputDatabaseNamespace, outputCollectionName); - } - break; - case "$merge": - { - var mergeArguments = outStage[0].AsBsonDocument; - DatabaseNamespace outputDatabaseNamespace; - string outputCollectionName; - var into = mergeArguments["into"]; - if (into.IsString) - { - outputDatabaseNamespace = _databaseNamespace; - outputCollectionName = into.AsString; - } - else - { - outputDatabaseNamespace = new DatabaseNamespace(into["db"].AsString); - outputCollectionName = into["coll"].AsString; - } - outputCollectionNamespace = new CollectionNamespace(outputDatabaseNamespace, outputCollectionName); - } - break; - default: - throw new ArgumentException($"Unexpected stage name: {stageName}."); - } + var outputCollectionNamespace = AggregateHelper.GetOutCollection(pipeline.Documents.Last(), _databaseNamespace); // because auto encryption is not supported for non-collection commands. // So, an error will be thrown in the previous CreateAggregateToCollectionOperation step. // However, since we've added encryption configuration for CreateAggregateToCollectionOperation operation, // it's not superfluous to also add it here var messageEncoderSettings = GetMessageEncoderSettings(); - return new FindOperation(outputCollectionNamespace, resultSerializer, messageEncoderSettings) + var findOperation = new FindOperation(outputCollectionNamespace, pipeline.OutputSerializer, messageEncoderSettings) { BatchSize = options.BatchSize, Collation = options.Collation, @@ -617,6 +553,16 @@ private FindOperation CreateAggregateToCollectionFindOperation ReadConcern = _settings.ReadConcern, RetryRequested = _client.Settings.RetryReads }; + + // we want to delay execution of the find because the user may + // not want to iterate the results at all... + var forkedSession = session.Fork(); + var readOperationOptions = _readOperationOptions with { ExplicitReadPreference = ReadPreference.Primary }; + var deferredCursor = new DeferredAsyncCursor( + () => forkedSession.Dispose(), + ct => _operationExecutor.ExecuteReadOperation(findOperation, readOperationOptions, forkedSession, cancellationToken: ct), + ct => _operationExecutor.ExecuteReadOperationAsync(findOperation, readOperationOptions, forkedSession, cancellationToken: ct)); + return deferredCursor; } private AggregateToCollectionOperation CreateAggregateToCollectionOperation(RenderedPipelineDefinition renderedPipeline, AggregateOptions options) @@ -641,25 +587,19 @@ private AggregateToCollectionOperation CreateAggregateToCollectionOperation(IClientSessionHandle session, string name, CreateCollectionOptions options, CancellationToken cancellationToken) - { - options = options ?? new CreateCollectionOptions(); - - var translationOptions = _client.Settings.TranslationOptions; - var operation = CreateCreateCollectionOperation(name, options, translationOptions); - ExecuteWriteOperation(session, operation, cancellationToken); - } + => _operationExecutor.ExecuteWriteOperation(CreateCreateCollectionOperation(name, options), + _writeOperationOptions, + session, cancellationToken: cancellationToken); private Task CreateCollectionHelperAsync(IClientSessionHandle session, string name, CreateCollectionOptions options, CancellationToken cancellationToken) - { - options = options ?? new CreateCollectionOptions(); + => _operationExecutor.ExecuteWriteOperationAsync(CreateCreateCollectionOperation(name, options), + _writeOperationOptions, + session, cancellationToken: cancellationToken); - var translationOptions = _client.Settings.TranslationOptions; - var operation = CreateCreateCollectionOperation(name, options, translationOptions); - return ExecuteWriteOperationAsync(session, operation, cancellationToken); - } - - private IWriteOperation CreateCreateCollectionOperation(string name, CreateCollectionOptions options, ExpressionTranslationOptions translationOptions) + private IWriteOperation CreateCreateCollectionOperation(string name, CreateCollectionOptions options) { + options ??= new CreateCollectionOptions(); + var translationOptions = _client.Settings.TranslationOptions; var serializerRegistry = options.SerializerRegistry ?? BsonSerializer.SerializerRegistry; var documentSerializer = options.DocumentSerializer ?? serializerRegistry.GetSerializer(); @@ -700,9 +640,14 @@ private CreateViewOperation CreateCreateViewOperation( string viewName, string viewOn, PipelineDefinition pipeline, - CreateViewOptions options, - ExpressionTranslationOptions translationOptions) + CreateViewOptions options) { + Ensure.IsNotNull(viewName, nameof(viewName)); + Ensure.IsNotNull(viewOn, nameof(viewOn)); + Ensure.IsNotNull(pipeline, nameof(pipeline)); + options ??= new CreateViewOptions(); + + var translationOptions = _client.Settings.TranslationOptions; var serializerRegistry = options.SerializerRegistry ?? BsonSerializer.SerializerRegistry; var documentSerializer = options.DocumentSerializer ?? serializerRegistry.GetSerializer(); var pipelineDocuments = pipeline.Render(new (documentSerializer, serializerRegistry, translationOptions: translationOptions)).Documents; @@ -713,60 +658,8 @@ private CreateViewOperation CreateCreateViewOperation( }; } - private IWriteOperation CreateDropCollectionOperation(string name, DropCollectionOptions options, IClientSessionHandle session, CancellationToken cancellationToken) - { - var collectionNamespace = new CollectionNamespace(_databaseNamespace, name); - - options = options ?? new DropCollectionOptions(); - - var encryptedFieldsMap = _client.Settings?.AutoEncryptionOptions?.EncryptedFieldsMap; - if (!EncryptedCollectionHelper.TryGetEffectiveEncryptedFields(collectionNamespace, options.EncryptedFields, encryptedFieldsMap, out var effectiveEncryptedFields)) - { - if (encryptedFieldsMap != null) - { - var listCollectionOptions = new ListCollectionsOptions() { Filter = $"{{ name : '{collectionNamespace.CollectionName}' }}" }; - var currrentCollectionInfo = ListCollections(session, listCollectionOptions, cancellationToken).FirstOrDefault(); - effectiveEncryptedFields = currrentCollectionInfo - ?.GetValue("options", defaultValue: null) - ?.AsBsonDocument - ?.GetValue("encryptedFields", defaultValue: null) - ?.ToBsonDocument(); - } - } - - var messageEncoderSettings = GetMessageEncoderSettings(); - return DropCollectionOperation.CreateEncryptedDropCollectionOperationIfConfigured( - collectionNamespace, - effectiveEncryptedFields, - messageEncoderSettings, - (dco) => - { - dco.WriteConcern = _settings.WriteConcern; - }); - } - - private async Task> CreateDropCollectionOperationAsync(string name, DropCollectionOptions options, IClientSessionHandle session, CancellationToken cancellationToken) + private IWriteOperation CreateDropCollectionOperation(CollectionNamespace collectionNamespace, BsonDocument effectiveEncryptedFields) { - var collectionNamespace = new CollectionNamespace(_databaseNamespace, name); - - options = options ?? new DropCollectionOptions(); - - var encryptedFieldsMap = _client.Settings?.AutoEncryptionOptions?.EncryptedFieldsMap; - if (!EncryptedCollectionHelper.TryGetEffectiveEncryptedFields(collectionNamespace, options.EncryptedFields, encryptedFieldsMap, out var effectiveEncryptedFields)) - { - if (encryptedFieldsMap != null) - { - var listCollectionOptions = new ListCollectionsOptions() { Filter = $"{{ name : '{collectionNamespace.CollectionName}' }}" }; - var currentCollectionsInfo = await ListCollectionsAsync(session, listCollectionOptions, cancellationToken).ConfigureAwait(false); - var currentCollectionInfo = await currentCollectionsInfo.FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); - effectiveEncryptedFields = currentCollectionInfo - ?.GetValue("options", defaultValue: null) - ?.AsBsonDocument - ?.GetValue("encryptedFields", defaultValue: null) - ?.ToBsonDocument(); - } - } - var messageEncoderSettings = GetMessageEncoderSettings(); return DropCollectionOperation.CreateEncryptedDropCollectionOperationIfConfigured( collectionNamespace, @@ -778,9 +671,10 @@ private async Task> CreateDropCollectionOperationA }); } - private ListCollectionsOperation CreateListCollectionNamesOperation(ListCollectionNamesOptions options, RenderArgs renderArgs) + private ListCollectionsOperation CreateListCollectionNamesOperation(ListCollectionNamesOptions options) { var messageEncoderSettings = GetMessageEncoderSettings(); + var renderArgs = GetRenderArgs(BsonDocumentSerializer.Instance); return new ListCollectionsOperation(_databaseNamespace, messageEncoderSettings) { AuthorizedCollections = options?.AuthorizedCollections, @@ -791,8 +685,9 @@ private ListCollectionsOperation CreateListCollectionNamesOperation(ListCollecti }; } - private ListCollectionsOperation CreateListCollectionsOperation(ListCollectionsOptions options, RenderArgs renderArgs) + private ListCollectionsOperation CreateListCollectionsOperation(ListCollectionsOptions options) { + var renderArgs = GetRenderArgs(BsonDocumentSerializer.Instance); var messageEncoderSettings = GetMessageEncoderSettings(); return new ListCollectionsOperation(_databaseNamespace, messageEncoderSettings) { @@ -803,23 +698,12 @@ private ListCollectionsOperation CreateListCollectionsOperation(ListCollectionsO }; } - private IReadBinding CreateReadBinding(IClientSessionHandle session, ReadPreference readPreference) - { - if (session.IsInTransaction && readPreference.ReadPreferenceMode != ReadPreferenceMode.Primary) - { - throw new InvalidOperationException("Read preference in a transaction must be primary."); - } - - return ChannelPinningHelper.CreateReadBinding(_cluster, session.WrappedCoreSession.Fork(), readPreference); - } - - private IWriteBindingHandle CreateReadWriteBinding(IClientSessionHandle session) - { - return ChannelPinningHelper.CreateReadWriteBinding(_cluster, session.WrappedCoreSession.Fork()); - } - private RenameCollectionOperation CreateRenameCollectionOperation(string oldName, string newName, RenameCollectionOptions options) { + Ensure.IsNotNullOrEmpty(oldName, nameof(oldName)); + Ensure.IsNotNullOrEmpty(newName, nameof(newName)); + options ??= new RenameCollectionOptions(); + var messageEncoderSettings = GetMessageEncoderSettings(); return new RenameCollectionOperation( new CollectionNamespace(_databaseNamespace, oldName), @@ -833,6 +717,7 @@ private RenameCollectionOperation CreateRenameCollectionOperation(string oldName private ReadCommandOperation CreateRunCommandOperation(Command command) { + Ensure.IsNotNull(command, nameof(command)); var renderedCommand = command.Render(_settings.SerializerRegistry); var messageEncoderSettings = GetMessageEncoderSettings(); return new ReadCommandOperation(_databaseNamespace, renderedCommand.Document, renderedCommand.ResultSerializer, messageEncoderSettings) @@ -843,9 +728,11 @@ private ReadCommandOperation CreateRunCommandOperation(Command private ChangeStreamOperation CreateChangeStreamOperation( PipelineDefinition, TResult> pipeline, - ChangeStreamOptions options, - ExpressionTranslationOptions translationOptions) + ChangeStreamOptions options) { + Ensure.IsNotNull(pipeline, nameof(pipeline)); + var translationOptions = _client.Settings.TranslationOptions; + return ChangeStreamHelper.CreateChangeStreamOperation( this, pipeline, @@ -861,48 +748,46 @@ private IEnumerable ExtractCollectionNames(IEnumerable col return collections.Select(collection => collection["name"].AsString); } - private T ExecuteReadOperation(IClientSessionHandle session, IReadOperation operation, CancellationToken cancellationToken) - { - var readPreference = ReadPreferenceResolver.GetEffectiveReadPreference(session, null, _settings.ReadPreference); - return ExecuteReadOperation(session, operation, readPreference, cancellationToken); - } - private T ExecuteReadOperation(IClientSessionHandle session, IReadOperation operation, ReadPreference readPreference, CancellationToken cancellationToken) + private BsonDocument GetEncryptedFields(IClientSessionHandle session, CollectionNamespace collectionNamespace, DropCollectionOptions options, CancellationToken cancellationToken) { - using (var binding = CreateReadBinding(session, readPreference)) + var encryptedFieldsMap = _client.Settings?.AutoEncryptionOptions?.EncryptedFieldsMap; + if (!EncryptedCollectionHelper.TryGetEffectiveEncryptedFields(collectionNamespace, options?.EncryptedFields, encryptedFieldsMap, out var effectiveEncryptedFields)) { - return _operationExecutor.ExecuteReadOperation(binding, operation, cancellationToken); + if (encryptedFieldsMap != null) + { + var listCollectionOptions = new ListCollectionsOptions() { Filter = $"{{ name : '{collectionNamespace.CollectionName}' }}" }; + var currentCollectionInfo = ListCollections(session, listCollectionOptions, cancellationToken: cancellationToken).FirstOrDefault(); + effectiveEncryptedFields = currentCollectionInfo + ?.GetValue("options", defaultValue: null) + ?.AsBsonDocument + ?.GetValue("encryptedFields", defaultValue: null) + ?.ToBsonDocument(); + } } - } - private Task ExecuteReadOperationAsync(IClientSessionHandle session, IReadOperation operation, CancellationToken cancellationToken) - { - var readPreference = ReadPreferenceResolver.GetEffectiveReadPreference(session, null, _settings.ReadPreference); - return ExecuteReadOperationAsync(session, operation, readPreference, cancellationToken); + return effectiveEncryptedFields; } - private async Task ExecuteReadOperationAsync(IClientSessionHandle session, IReadOperation operation, ReadPreference readPreference, CancellationToken cancellationToken) + private async Task GetEncryptedFieldsAsync(IClientSessionHandle session, CollectionNamespace collectionNamespace, DropCollectionOptions options, CancellationToken cancellationToken) { - using (var binding = CreateReadBinding(session, readPreference)) - { - return await _operationExecutor.ExecuteReadOperationAsync(binding, operation, cancellationToken).ConfigureAwait(false); - } - } - - private T ExecuteWriteOperation(IClientSessionHandle session, IWriteOperation operation, CancellationToken cancellationToken) - { - using (var binding = CreateReadWriteBinding(session)) + var encryptedFieldsMap = _client.Settings?.AutoEncryptionOptions?.EncryptedFieldsMap; + if (!EncryptedCollectionHelper.TryGetEffectiveEncryptedFields(collectionNamespace, options?.EncryptedFields, encryptedFieldsMap, out var effectiveEncryptedFields)) { - return _operationExecutor.ExecuteWriteOperation(binding, operation, cancellationToken); + if (encryptedFieldsMap != null) + { + var listCollectionOptions = new ListCollectionsOptions() { Filter = $"{{ name : '{collectionNamespace.CollectionName}' }}" }; + var currentCollectionsInfo = await ListCollectionsAsync(session, listCollectionOptions, cancellationToken: cancellationToken).ConfigureAwait(false); + var currentCollectionInfo = await currentCollectionsInfo.FirstOrDefaultAsync(cancellationToken: cancellationToken).ConfigureAwait(false); + effectiveEncryptedFields = currentCollectionInfo + ?.GetValue("options", defaultValue: null) + ?.AsBsonDocument + ?.GetValue("encryptedFields", defaultValue: null) + ?.ToBsonDocument(); + } } - } - private async Task ExecuteWriteOperationAsync(IClientSessionHandle session, IWriteOperation operation, CancellationToken cancellationToken) - { - using (var binding = CreateReadWriteBinding(session)) - { - return await _operationExecutor.ExecuteWriteOperationAsync(binding, operation, cancellationToken).ConfigureAwait(false); - } + return effectiveEncryptedFields; } private MessageEncoderSettings GetMessageEncoderSettings() @@ -932,37 +817,5 @@ private RenderArgs GetRenderArgs(IBsonSerializer(documentSerializer, _settings.SerializerRegistry, translationOptions: translationOptions); } - - private void UsingImplicitSession(Action func, CancellationToken cancellationToken) - { - using (var session = _operationExecutor.StartImplicitSession(cancellationToken)) - { - func(session); - } - } - - private TResult UsingImplicitSession(Func func, CancellationToken cancellationToken) - { - using (var session = _operationExecutor.StartImplicitSession(cancellationToken)) - { - return func(session); - } - } - - private async Task UsingImplicitSessionAsync(Func funcAsync, CancellationToken cancellationToken) - { - using (var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false)) - { - await funcAsync(session).ConfigureAwait(false); - } - } - - private async Task UsingImplicitSessionAsync(Func> funcAsync, CancellationToken cancellationToken) - { - using (var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false)) - { - return await funcAsync(session).ConfigureAwait(false); - } - } } } diff --git a/src/MongoDB.Driver/OperationExecutor.cs b/src/MongoDB.Driver/OperationExecutor.cs index cc521cdf762..764369d5ce8 100644 --- a/src/MongoDB.Driver/OperationExecutor.cs +++ b/src/MongoDB.Driver/OperationExecutor.cs @@ -13,8 +13,10 @@ * limitations under the License. */ +using System; using System.Threading; using System.Threading.Tasks; +using MongoDB.Driver.Core; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Operations; @@ -22,41 +24,173 @@ namespace MongoDB.Driver { internal sealed class OperationExecutor : IOperationExecutor { - private readonly MongoClient _client; + private readonly IMongoClient _client; + private bool _isDisposed; - public OperationExecutor(MongoClient client) + public OperationExecutor(IMongoClient client) { _client = client; } - public TResult ExecuteReadOperation(IReadBinding binding, IReadOperation operation, CancellationToken cancellationToken) + public void Dispose() { - return operation.Execute(binding, cancellationToken); + _isDisposed = true; } - public async Task ExecuteReadOperationAsync(IReadBinding binding, IReadOperation operation, CancellationToken cancellationToken) + public TResult ExecuteReadOperation( + IReadOperation operation, + ReadOperationOptions options, + IClientSessionHandle session = null, + bool disableChannelPinning = false, + CancellationToken cancellationToken = default) { - return await operation.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false); + ThrowIfDisposed(); + var isOwnSession = session == null; + session ??= StartImplicitSession(cancellationToken); + + try + { + var readPreference = options.GetEffectiveReadPreference(session); + using var binding = CreateReadBinding(session, readPreference, disableChannelPinning); + return operation.Execute(binding, cancellationToken); + } + finally + { + if (isOwnSession) + { + session.Dispose(); + } + } } - public TResult ExecuteWriteOperation(IWriteBinding binding, IWriteOperation operation, CancellationToken cancellationToken) + public async Task ExecuteReadOperationAsync( + IReadOperation operation, + ReadOperationOptions options, + IClientSessionHandle session = null, + bool disableChannelPinning = false, + CancellationToken cancellationToken = default) { - return operation.Execute(binding, cancellationToken); + ThrowIfDisposed(); + var isOwnSession = session == null; + session ??= await StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false); + + try + { + var readPreference = options.GetEffectiveReadPreference(session); + using var binding = CreateReadBinding(session, readPreference, disableChannelPinning); + return await operation.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false); + } + finally + { + if (isOwnSession) + { + session.Dispose(); + } + } } - public async Task ExecuteWriteOperationAsync(IWriteBinding binding, IWriteOperation operation, CancellationToken cancellationToken) + public TResult ExecuteWriteOperation( + IWriteOperation operation, + WriteOperationOptions options, + IClientSessionHandle session = null, + bool disableChannelPinning = false, + CancellationToken cancellationToken = default) { - return await operation.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false); + ThrowIfDisposed(); + var isOwnSession = session == null; + session ??= StartImplicitSession(cancellationToken); + + try + { + using var binding = CreateReadWriteBinding(session, disableChannelPinning); + return operation.Execute(binding, cancellationToken); + } + finally + { + if (isOwnSession) + { + session.Dispose(); + } + } + } + + public async Task ExecuteWriteOperationAsync( + IWriteOperation operation, + WriteOperationOptions options, + IClientSessionHandle session = null, + bool disableChannelPinning = false, + CancellationToken cancellationToken = default) + { + ThrowIfDisposed(); + var isOwnSession = session == null; + session ??= await StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false); + + try + { + using var binding = CreateReadWriteBinding(session, disableChannelPinning); + return await operation.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false); + } + finally + { + if (isOwnSession) + { + session.Dispose(); + } + } } public IClientSessionHandle StartImplicitSession(CancellationToken cancellationToken) { - return _client.StartImplicitSession(cancellationToken); + ThrowIfDisposed(); + return StartImplicitSession(); } public Task StartImplicitSessionAsync(CancellationToken cancellationToken) { - return _client.StartImplicitSessionAsync(cancellationToken); + ThrowIfDisposed(); + return Task.FromResult(StartImplicitSession()); + } + + private IReadBindingHandle CreateReadBinding(IClientSessionHandle session, ReadPreference readPreference, bool disableChannelPinning) + { + if (session.IsInTransaction && readPreference.ReadPreferenceMode != ReadPreferenceMode.Primary) + { + throw new InvalidOperationException("Read preference in a transaction must be primary."); + } + + if (disableChannelPinning) + { + var binding = new ReadPreferenceBinding(_client.GetClusterInternal(), readPreference, session.WrappedCoreSession.Fork()); + return new ReadBindingHandle(binding); + } + + return ChannelPinningHelper.CreateReadBinding(_client.GetClusterInternal(), session.WrappedCoreSession.Fork(), readPreference); + } + + private IReadWriteBindingHandle CreateReadWriteBinding(IClientSessionHandle session, bool disableChannelPinning) + { + if (disableChannelPinning) + { + var binding = new WritableServerBinding(_client.GetClusterInternal(), session.WrappedCoreSession.Fork()); + return new ReadWriteBindingHandle(binding); + } + + return ChannelPinningHelper.CreateReadWriteBinding(_client.GetClusterInternal(), session.WrappedCoreSession.Fork()); + } + + private IClientSessionHandle StartImplicitSession() + { + var options = new ClientSessionOptions { CausalConsistency = false, Snapshot = false }; + var coreSession = _client.GetClusterInternal().StartSession(options.ToCore(isImplicit: true)); + return new ClientSessionHandle(_client, options, coreSession); + } + + private void ThrowIfDisposed() + { + if (_isDisposed) + { + throw new ObjectDisposedException(nameof(OperationExecutor)); + } } } } diff --git a/src/MongoDB.Driver/ReadOperationOptions.cs b/src/MongoDB.Driver/ReadOperationOptions.cs new file mode 100644 index 00000000000..2473d5dc045 --- /dev/null +++ b/src/MongoDB.Driver/ReadOperationOptions.cs @@ -0,0 +1,42 @@ +/* Copyright 2010-present MongoDB Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace MongoDB.Driver +{ + internal record ReadOperationOptions(ReadPreference ExplicitReadPreference = null, ReadPreference DefaultReadPreference = null); + + internal static class ReadOperationOptionsExtensions + { + public static ReadPreference GetEffectiveReadPreference(this ReadOperationOptions options, IClientSessionHandle session) + { + if (options.ExplicitReadPreference != null) + { + return options.ExplicitReadPreference; + } + + if (session.IsInTransaction) + { + var transactionReadPreference = session.WrappedCoreSession.CurrentTransaction.TransactionOptions.ReadPreference; + if (transactionReadPreference != null) + { + return transactionReadPreference; + } + } + + return options.DefaultReadPreference ?? ReadPreference.Primary; + } + } +} + diff --git a/src/MongoDB.Driver/ReadPreferenceResolver.cs b/src/MongoDB.Driver/ReadPreferenceResolver.cs deleted file mode 100644 index 6fbc9ed27f8..00000000000 --- a/src/MongoDB.Driver/ReadPreferenceResolver.cs +++ /dev/null @@ -1,42 +0,0 @@ -/* Copyright 2018-present MongoDB Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -namespace MongoDB.Driver -{ - internal static class ReadPreferenceResolver - { - public static ReadPreference GetEffectiveReadPreference( - IClientSessionHandle session, - ReadPreference explicitReadPreference, - ReadPreference defaultReadPreference) - { - if (explicitReadPreference != null) - { - return explicitReadPreference; - } - - if (session.IsInTransaction) - { - var transactionReadPreference = session.WrappedCoreSession.CurrentTransaction.TransactionOptions.ReadPreference; - if (transactionReadPreference != null) - { - return transactionReadPreference; - } - } - - return defaultReadPreference ?? ReadPreference.Primary; - } - } -} diff --git a/src/MongoDB.Driver/WriteOperationOptions.cs b/src/MongoDB.Driver/WriteOperationOptions.cs new file mode 100644 index 00000000000..fd56dc0fa78 --- /dev/null +++ b/src/MongoDB.Driver/WriteOperationOptions.cs @@ -0,0 +1,20 @@ +/* Copyright 2010-present MongoDB Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace MongoDB.Driver +{ + internal record WriteOperationOptions(); +} + diff --git a/tests/MongoDB.Driver.Tests/MockOperationExecutor.cs b/tests/MongoDB.Driver.Tests/MockOperationExecutor.cs index 6c9c18b6410..76a746d96f7 100644 --- a/tests/MongoDB.Driver.Tests/MockOperationExecutor.cs +++ b/tests/MongoDB.Driver.Tests/MockOperationExecutor.cs @@ -48,6 +48,10 @@ public int QueuedCallCount get { return _calls.Count; } } + public void Dispose() + { + } + public void EnqueueResult(TResult result) { _results.Enqueue(result); @@ -58,15 +62,20 @@ public void EnqueueException(Exception exception) _results.Enqueue(exception); } - public TResult ExecuteReadOperation(IReadBinding binding, IReadOperation operation, CancellationToken cancellationToken) + public TResult ExecuteReadOperation( + IReadOperation operation, + ReadOperationOptions readOperationOptions, + IClientSessionHandle session = null, + bool disableChannelPinning = false, + CancellationToken cancellationToken = default) { _calls.Enqueue(new ReadCall { - Binding = binding, Operation = operation, CancellationToken = cancellationToken, - SessionId = binding.Session.Id, - UsedImplicitSession = binding.Session.IsImplicit + Options = readOperationOptions, + SessionId = session?.WrappedCoreSession.Id, + UsedImplicitSession = session == null || session.IsImplicit }); if (_results.Count > 0) @@ -85,11 +94,16 @@ public TResult ExecuteReadOperation(IReadBinding binding, IReadOperatio return default(TResult); } - public Task ExecuteReadOperationAsync(IReadBinding binding, IReadOperation operation, CancellationToken cancellationToken) + public Task ExecuteReadOperationAsync( + IReadOperation operation, + ReadOperationOptions readOperationOptions, + IClientSessionHandle session = null, + bool disableChannelPinning = false, + CancellationToken cancellationToken = default) { try { - var result = ExecuteReadOperation(binding, operation, cancellationToken); + var result = ExecuteReadOperation(operation, readOperationOptions, session, disableChannelPinning, cancellationToken); return Task.FromResult(result); } catch (Exception ex) @@ -100,15 +114,20 @@ public Task ExecuteReadOperationAsync(IReadBinding binding, IR } } - public TResult ExecuteWriteOperation(IWriteBinding binding, IWriteOperation operation, CancellationToken cancellationToken) + public TResult ExecuteWriteOperation( + IWriteOperation operation, + WriteOperationOptions writeOperationOptions, + IClientSessionHandle session = null, + bool disableChannelPinning = false, + CancellationToken cancellationToken = default) { _calls.Enqueue(new WriteCall { - Binding = binding, Operation = operation, CancellationToken = cancellationToken, - SessionId = binding.Session.Id, - UsedImplicitSession = binding.Session.IsImplicit + Options = writeOperationOptions, + SessionId = session?.WrappedCoreSession.Id, + UsedImplicitSession = session == null || session.IsImplicit }); if (_results.Count > 0) @@ -127,11 +146,16 @@ public TResult ExecuteWriteOperation(IWriteBinding binding, IWriteOpera return default(TResult); } - public Task ExecuteWriteOperationAsync(IWriteBinding binding, IWriteOperation operation, CancellationToken cancellationToken) + public Task ExecuteWriteOperationAsync( + IWriteOperation operation, + WriteOperationOptions writeOperationOptions, + IClientSessionHandle session = null, + bool disableChannelPinning = false, + CancellationToken cancellationToken = default) { try { - var result = ExecuteWriteOperation(binding, operation, cancellationToken); + var result = ExecuteWriteOperation(operation, writeOperationOptions, session, disableChannelPinning, cancellationToken); return Task.FromResult(result); } catch (Exception ex) @@ -193,18 +217,18 @@ public Task StartImplicitSessionAsync(CancellationToken ca public class ReadCall { - public IReadBinding Binding { get; set; } public IReadOperation Operation { get; set; } public CancellationToken CancellationToken { get; set; } + public ReadOperationOptions Options { get; set; } public BsonDocument SessionId { get; set; } public bool UsedImplicitSession { get; set; } } public class WriteCall { - public IWriteBinding Binding { get; set; } public IWriteOperation Operation { get; set; } public CancellationToken CancellationToken { get; set; } + public WriteOperationOptions Options { get; set; } public BsonDocument SessionId { get; set; } public bool UsedImplicitSession { get; set; } } diff --git a/tests/MongoDB.Driver.Tests/MongoClientTests.cs b/tests/MongoDB.Driver.Tests/MongoClientTests.cs index 36d6bca9231..111c62ffd56 100644 --- a/tests/MongoDB.Driver.Tests/MongoClientTests.cs +++ b/tests/MongoDB.Driver.Tests/MongoClientTests.cs @@ -119,9 +119,6 @@ public void Disposed_client_should_throw_on_member_access() var exception = Record.Exception(() => client.Cluster); exception.Should().BeOfType(); - - exception = Record.Exception(() => client.StartImplicitSession(default)); - exception.Should().BeOfType(); } [Theory] @@ -132,7 +129,7 @@ public void DropDatabase_should_invoke_the_correct_operation( { var operationExecutor = new MockOperationExecutor(); var writeConcern = new WriteConcern(1); - var subject = new MongoClient(operationExecutor, DriverTestConfiguration.GetClientSettings()).WithWriteConcern(writeConcern); + var subject = new MongoClient(_ => operationExecutor, DriverTestConfiguration.GetClientSettings()).WithWriteConcern(writeConcern); var session = CreateClientSession(); using var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; @@ -183,7 +180,7 @@ public void ListDatabaseNames_should_invoke_the_correct_operation( [Values(false, true)] bool async) { var operationExecutor = new MockOperationExecutor(); - var subject = new MongoClient(operationExecutor, DriverTestConfiguration.GetClientSettings()); + var subject = new MongoClient(_ => operationExecutor, DriverTestConfiguration.GetClientSettings()); var session = CreateClientSession(); using var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; @@ -277,7 +274,7 @@ public void ListDatabases_should_invoke_the_correct_operation( [Values(false, true)] bool async) { var operationExecutor = new MockOperationExecutor(); - var subject = new MongoClient(operationExecutor, DriverTestConfiguration.GetClientSettings()); + var subject = new MongoClient(_ => operationExecutor, DriverTestConfiguration.GetClientSettings()); var session = CreateClientSession(); using var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; @@ -337,7 +334,7 @@ public void Watch_should_invoke_the_correct_operation( { var operationExecutor = new MockOperationExecutor(); var clientSettings = DriverTestConfiguration.GetClientSettings(); - var subject = new MongoClient(operationExecutor, clientSettings); + var subject = new MongoClient(_ => operationExecutor, clientSettings); var session = usingSession ? CreateClientSession() : null; var pipeline = new EmptyPipelineDefinition>().Limit(1); var options = new ChangeStreamOptions diff --git a/tests/MongoDB.Driver.Tests/MongoDatabasTests.cs b/tests/MongoDB.Driver.Tests/MongoDatabaseTests.cs similarity index 98% rename from tests/MongoDB.Driver.Tests/MongoDatabasTests.cs rename to tests/MongoDB.Driver.Tests/MongoDatabaseTests.cs index 68cb5526beb..c2fc8f9166b 100644 --- a/tests/MongoDB.Driver.Tests/MongoDatabasTests.cs +++ b/tests/MongoDB.Driver.Tests/MongoDatabaseTests.cs @@ -1097,8 +1097,8 @@ public void RunCommand_should_default_to_ReadPreference_primary( var call = _operationExecutor.GetReadCall(); VerifySessionAndCancellationToken(call, session, cancellationToken); - var binding = call.Binding.Should().BeOfType().Subject; - binding.ReadPreference.Should().Be(ReadPreference.Primary); + call.Options.ExplicitReadPreference.Should().BeNull(); + call.Options.DefaultReadPreference.Should().Be(ReadPreference.Primary); var op = call.Operation.Should().BeOfType>().Subject; op.DatabaseNamespace.Should().Be(_subject.DatabaseNamespace); @@ -1144,8 +1144,8 @@ public void RunCommand_should_use_the_provided_ReadPreference( var call = _operationExecutor.GetReadCall(); VerifySessionAndCancellationToken(call, session, cancellationToken); - var binding = call.Binding.Should().BeOfType().Subject; - binding.ReadPreference.Should().Be(readPreference); + call.Options.ExplicitReadPreference.Should().Be(readPreference); + call.Options.DefaultReadPreference.Should().Be(ReadPreference.Primary); var op = call.Operation.Should().BeOfType>().Subject; op.DatabaseNamespace.Should().Be(_subject.DatabaseNamespace); @@ -1190,8 +1190,8 @@ public void RunCommand_should_run_a_non_read_command( var call = _operationExecutor.GetReadCall(); VerifySessionAndCancellationToken(call, session, cancellationToken); - var binding = call.Binding.Should().BeOfType().Subject; - binding.ReadPreference.Should().Be(ReadPreference.Primary); + call.Options.ExplicitReadPreference.Should().BeNull(); + call.Options.DefaultReadPreference.Should().Be(ReadPreference.Primary); var op = call.Operation.Should().BeOfType>().Subject; op.DatabaseNamespace.Should().Be(_subject.DatabaseNamespace); @@ -1236,8 +1236,8 @@ public void RunCommand_should_run_a_json_command( var call = _operationExecutor.GetReadCall(); VerifySessionAndCancellationToken(call, session, cancellationToken); - var binding = call.Binding.Should().BeOfType().Subject; - binding.ReadPreference.Should().Be(ReadPreference.Primary); + call.Options.ExplicitReadPreference.Should().BeNull(); + call.Options.DefaultReadPreference.Should().Be(ReadPreference.Primary); var op = call.Operation.Should().BeOfType>().Subject; op.DatabaseNamespace.Should().Be(_subject.DatabaseNamespace); @@ -1282,8 +1282,8 @@ public void RunCommand_should_run_a_serialized_command( var call = _operationExecutor.GetReadCall(); VerifySessionAndCancellationToken(call, session, cancellationToken); - var binding = call.Binding.Should().BeOfType().Subject; - binding.ReadPreference.Should().Be(ReadPreference.Primary); + call.Options.ExplicitReadPreference.Should().BeNull(); + call.Options.DefaultReadPreference.Should().Be(ReadPreference.Primary); var op = call.Operation.Should().BeOfType>().Subject; op.DatabaseNamespace.Should().Be(_subject.DatabaseNamespace); diff --git a/tests/MongoDB.Driver.Tests/OperationExecutorTests.cs b/tests/MongoDB.Driver.Tests/OperationExecutorTests.cs new file mode 100644 index 00000000000..37f911f2b36 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/OperationExecutorTests.cs @@ -0,0 +1,117 @@ +/* Copyright 2010-present MongoDB Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using MongoDB.Driver.Core.Bindings; +using MongoDB.Driver.Core.Clusters; +using MongoDB.Driver.Core.Operations; +using MongoDB.TestHelpers.XunitExtensions; +using Moq; +using Xunit; + +namespace MongoDB.Driver.Tests +{ + public class OperationExecutorTests + { + [Theory] + [ParameterAttributeData] + public async Task StartImplicitSession_should_call_cluster_StartSession([Values(true, false)]bool isAsync) + { + var subject = CreateSubject(out var clusterMock, out _); + if (isAsync) + { + await subject.StartImplicitSessionAsync(CancellationToken.None); + } + else + { + subject.StartImplicitSession(CancellationToken.None); + } + + clusterMock.Verify(c => c.StartSession(It.Is(v => v.IsImplicit && v.IsCausallyConsistent == false && v.IsSnapshot == false))); + } + + [Theory] + [MemberData(nameof(ImplicitSessionTestCases))] + public async Task ExecuteReadOperation_should_start_and_dispose_implicit_session_if_needed(bool shouldCreateSession, bool isAsync, IClientSessionHandle session) + { + var subject = CreateSubject(out var clusterMock, out var implicitSessionMock); + var readOperation = Mock.Of>(); + var readOperationOptions = new ReadOperationOptions(); + + _ = isAsync ? + await subject.ExecuteReadOperationAsync(readOperation, readOperationOptions, session, cancellationToken: CancellationToken.None) : + subject.ExecuteReadOperation(readOperation, readOperationOptions, session, cancellationToken: CancellationToken.None); + + var times = shouldCreateSession ? Times.Once() : Times.Never(); + clusterMock.Verify(c => c.StartSession(It.Is(v => v.IsImplicit && v.IsCausallyConsistent == false && v.IsSnapshot == false)), times); + implicitSessionMock.Verify(s => s.Dispose(), times); + } + + [Theory] + [MemberData(nameof(ImplicitSessionTestCases))] + public async Task ExecuteWriteOperation_should_start_and_dispose_implicit_session_if_needed(bool shouldCreateSession, bool isAsync, IClientSessionHandle session) + { + var subject = CreateSubject(out var clusterMock, out var implicitSessionMock); + var writeOperation = Mock.Of>(); + var writeOperationOptions = new WriteOperationOptions(); + + _ = isAsync ? + await subject.ExecuteWriteOperationAsync(writeOperation, writeOperationOptions, session, cancellationToken: CancellationToken.None) : + subject.ExecuteWriteOperation(writeOperation, writeOperationOptions, session, cancellationToken: CancellationToken.None); + + var times = shouldCreateSession ? Times.Once() : Times.Never(); + clusterMock.Verify(c => c.StartSession(It.Is(v => v.IsImplicit && v.IsCausallyConsistent == false && v.IsSnapshot == false)), times); + implicitSessionMock.Verify(s => s.Dispose(), times); + } + + private static IEnumerable ImplicitSessionTestCases() + { + yield return [ true, false, null ]; + yield return [ true, true, null ]; + + var implicitSession = new Mock(); + implicitSession.SetupGet(s => s.IsImplicit).Returns(true); + implicitSession.SetupGet(s => s.WrappedCoreSession).Returns(CreateCoreSessionMock(true).Object); + yield return [ false, false, implicitSession.Object ]; + yield return [ false, true, implicitSession.Object ]; + + var regularSession = new Mock(); + regularSession.SetupGet(s => s.WrappedCoreSession).Returns(CreateCoreSessionMock(false).Object); + yield return [ false, false, regularSession.Object ]; + yield return [ false, true, regularSession.Object ]; + } + + private OperationExecutor CreateSubject(out Mock clusterMock, out Mock implicitSessionMock) + { + implicitSessionMock = CreateCoreSessionMock(true); + clusterMock = new Mock(); + clusterMock.Setup(c => c.StartSession(It.IsAny())).Returns(implicitSessionMock.Object); + var clientMock = new Mock(); + clientMock.SetupGet(c => c.Cluster).Returns(clusterMock.Object); + return new OperationExecutor(clientMock.Object); + } + + private static Mock CreateCoreSessionMock(bool isImplicit) + { + var sessionMock = new Mock(); + sessionMock.SetupGet(s => s.IsImplicit).Returns(isImplicit); + sessionMock.Setup(s => s.Fork()).Returns(() => CreateCoreSessionMock(isImplicit).Object); + return sessionMock; + } + } +} + diff --git a/tests/MongoDB.Driver.Tests/ReadOperationOptionsTests.cs b/tests/MongoDB.Driver.Tests/ReadOperationOptionsTests.cs new file mode 100644 index 00000000000..585b2e442ff --- /dev/null +++ b/tests/MongoDB.Driver.Tests/ReadOperationOptionsTests.cs @@ -0,0 +1,70 @@ +/* Copyright 2010-present MongoDB Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System.Collections.Generic; +using FluentAssertions; +using MongoDB.Driver.Core.Bindings; +using Moq; +using Xunit; + +namespace MongoDB.Driver.Tests +{ + public class ReadOperationOptionsTests + { + [Theory] + [MemberData(nameof(GetEffectiveReadPreferenceTestCases))] + public void GetEffectiveReadPreferenceTests( + ReadPreference expectedReadPreference, + ReadPreference explicitReadPreference, + ReadPreference defaultReadPreference, + IClientSessionHandle session) + { + var readOperationOptions = new ReadOperationOptions(explicitReadPreference, defaultReadPreference); + var result = readOperationOptions.GetEffectiveReadPreference(session); + + result.Should().Be(expectedReadPreference); + } + + public static IEnumerable GetEffectiveReadPreferenceTestCases() + { + var noTransactionSession = CreateSessionMock(null); + var inTransactionSession = CreateSessionMock(new TransactionOptions(readPreference: ReadPreference.Nearest)); + var inTransactionNoPreferenceSession = CreateSessionMock(new TransactionOptions()); + + yield return [ReadPreference.Primary, null, null, noTransactionSession]; + yield return [ReadPreference.Secondary, ReadPreference.Secondary, ReadPreference.SecondaryPreferred, noTransactionSession]; + yield return [ReadPreference.Secondary, ReadPreference.Secondary, ReadPreference.SecondaryPreferred, inTransactionSession]; + yield return [ReadPreference.SecondaryPreferred, null, ReadPreference.SecondaryPreferred, noTransactionSession]; + yield return [ReadPreference.Nearest, null, ReadPreference.SecondaryPreferred, inTransactionSession]; + yield return [ReadPreference.Primary, null, null, inTransactionNoPreferenceSession]; + yield return [ReadPreference.SecondaryPreferred, null, ReadPreference.SecondaryPreferred, inTransactionNoPreferenceSession]; + } + + private static IClientSessionHandle CreateSessionMock(TransactionOptions transactionOptions) + { + var sessionMock = new Mock(); + if (transactionOptions != null) + { + sessionMock.SetupGet(s => s.IsInTransaction).Returns(true); + var coreSessionMock = new Mock(); + coreSessionMock.SetupGet(s => s.CurrentTransaction).Returns(new CoreTransaction(0, transactionOptions)); + sessionMock.SetupGet(s => s.WrappedCoreSession).Returns(coreSessionMock.Object); + } + + return sessionMock.Object; + } + } +} + From 5ba15fe0fa13599510e4d3f07893cdf2f346de3b Mon Sep 17 00:00:00 2001 From: Oleksandr Poliakov Date: Fri, 30 May 2025 13:55:10 -0700 Subject: [PATCH 02/14] PR --- src/MongoDB.Driver/MongoClient.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/MongoDB.Driver/MongoClient.cs b/src/MongoDB.Driver/MongoClient.cs index 33f6753c49e..dacf9645c7e 100644 --- a/src/MongoDB.Driver/MongoClient.cs +++ b/src/MongoDB.Driver/MongoClient.cs @@ -156,6 +156,7 @@ public Task BulkWriteAsync(IReadOnlyList => _operationExecutor.ExecuteWriteOperationAsync( CreateClientBulkWriteOperation(models, options), _writeOperationOptions, + disableChannelPinning: true, cancellationToken: cancellationToken); /// From 95ca4e0febc2fb4935b9bd1fc542c589b6e0e54e Mon Sep 17 00:00:00 2001 From: Oleksandr Poliakov Date: Mon, 2 Jun 2025 14:04:08 -0700 Subject: [PATCH 03/14] PR --- src/MongoDB.Driver/IOperationExecutor.cs | 8 ++--- src/MongoDB.Driver/MongoClient.cs | 10 ++++++ src/MongoDB.Driver/MongoCollectionImpl.cs | 34 +++++++++++++++++-- src/MongoDB.Driver/MongoDatabase.cs | 11 ++++++ src/MongoDB.Driver/OperationExecutor.cs | 8 ++--- .../MockOperationExecutor.cs | 8 ++--- 6 files changed, 65 insertions(+), 14 deletions(-) diff --git a/src/MongoDB.Driver/IOperationExecutor.cs b/src/MongoDB.Driver/IOperationExecutor.cs index 556017387a5..dc3f20f8689 100644 --- a/src/MongoDB.Driver/IOperationExecutor.cs +++ b/src/MongoDB.Driver/IOperationExecutor.cs @@ -25,28 +25,28 @@ internal interface IOperationExecutor : IDisposable TResult ExecuteReadOperation( IReadOperation operation, ReadOperationOptions options, - IClientSessionHandle session = null, + IClientSessionHandle session, bool disableChannelPinning = false, CancellationToken cancellationToken = default); Task ExecuteReadOperationAsync( IReadOperation operation, ReadOperationOptions options, - IClientSessionHandle session = null, + IClientSessionHandle session, bool disableChannelPinning = false, CancellationToken cancellationToken = default); TResult ExecuteWriteOperation( IWriteOperation operation, WriteOperationOptions options, - IClientSessionHandle session = null, + IClientSessionHandle session, bool disableChannelPinning = false, CancellationToken cancellationToken = default); Task ExecuteWriteOperationAsync( IWriteOperation operation, WriteOperationOptions options, - IClientSessionHandle session = null, + IClientSessionHandle session, bool disableChannelPinning = false, CancellationToken cancellationToken = default); diff --git a/src/MongoDB.Driver/MongoClient.cs b/src/MongoDB.Driver/MongoClient.cs index dacf9645c7e..3b942569f3c 100644 --- a/src/MongoDB.Driver/MongoClient.cs +++ b/src/MongoDB.Driver/MongoClient.cs @@ -139,6 +139,7 @@ public ClientBulkWriteResult BulkWrite(IReadOnlyList models, Cli => _operationExecutor.ExecuteWriteOperation( CreateClientBulkWriteOperation(models, options), _writeOperationOptions, + session: null, disableChannelPinning: true, cancellationToken: cancellationToken); @@ -156,6 +157,7 @@ public Task BulkWriteAsync(IReadOnlyList => _operationExecutor.ExecuteWriteOperationAsync( CreateClientBulkWriteOperation(models, options), _writeOperationOptions, + session: null, disableChannelPinning: true, cancellationToken: cancellationToken); @@ -203,6 +205,7 @@ public void DropDatabase(string name, CancellationToken cancellationToken = defa => _operationExecutor.ExecuteWriteOperation( CreateDropDatabaseOperation(name), _writeOperationOptions, + session: null, disableChannelPinning: true, cancellationToken: cancellationToken); @@ -220,6 +223,7 @@ public Task DropDatabaseAsync(string name, CancellationToken cancellationToken = => _operationExecutor.ExecuteWriteOperationAsync( CreateDropDatabaseOperation(name), _writeOperationOptions, + session: null, disableChannelPinning: true, cancellationToken: cancellationToken); @@ -313,6 +317,7 @@ public IAsyncCursor ListDatabases(CancellationToken cancellationTo => _operationExecutor.ExecuteReadOperation( CreateListDatabaseOperation(null), _readOperationOptions, + session: null, disableChannelPinning: true, cancellationToken: cancellationToken); @@ -323,6 +328,7 @@ public IAsyncCursor ListDatabases( => _operationExecutor.ExecuteReadOperation( CreateListDatabaseOperation(options), _readOperationOptions, + session: null, disableChannelPinning: true, cancellationToken: cancellationToken); @@ -354,6 +360,7 @@ public Task> ListDatabasesAsync(CancellationToken can => _operationExecutor.ExecuteReadOperationAsync( CreateListDatabaseOperation(null), _readOperationOptions, + session: null, disableChannelPinning: true, cancellationToken: cancellationToken); @@ -364,6 +371,7 @@ public Task> ListDatabasesAsync( => _operationExecutor.ExecuteReadOperationAsync( CreateListDatabaseOperation(options), _readOperationOptions, + session: null, disableChannelPinning: true, cancellationToken: cancellationToken); @@ -414,6 +422,7 @@ public IChangeStreamCursor Watch( => _operationExecutor.ExecuteReadOperation( CreateChangeStreamOperation(pipeline, options), _readOperationOptions, + session: null, disableChannelPinning: true, cancellationToken: cancellationToken); @@ -438,6 +447,7 @@ public Task> WatchAsync( => _operationExecutor.ExecuteReadOperationAsync( CreateChangeStreamOperation(pipeline, options), _readOperationOptions, + session: null, disableChannelPinning: true, cancellationToken: cancellationToken); diff --git a/src/MongoDB.Driver/MongoCollectionImpl.cs b/src/MongoDB.Driver/MongoCollectionImpl.cs index 33796933e30..0a9673ca626 100644 --- a/src/MongoDB.Driver/MongoCollectionImpl.cs +++ b/src/MongoDB.Driver/MongoCollectionImpl.cs @@ -247,6 +247,7 @@ public override long Count(FilterDefinition filter, CountOptions opti => _operationExecutor.ExecuteReadOperation( CreateCountOperation(filter, options), _readOperationOptions, + session: null, cancellationToken: cancellationToken); [Obsolete("Use CountDocuments or EstimatedDocumentCount instead.")] @@ -262,6 +263,7 @@ public override Task CountAsync(FilterDefinition filter, CountO => _operationExecutor.ExecuteReadOperationAsync( CreateCountOperation(filter, options), _readOperationOptions, + session: null, cancellationToken: cancellationToken); [Obsolete("Use CountDocumentsAsync or EstimatedDocumentCountAsync instead.")] @@ -276,6 +278,7 @@ public override long CountDocuments(FilterDefinition filter, CountOpt => _operationExecutor.ExecuteReadOperation( CreateCountDocumentsOperation(filter, options), _readOperationOptions, + session: null, cancellationToken: cancellationToken); public override long CountDocuments(IClientSessionHandle session, FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) @@ -289,6 +292,7 @@ public override Task CountDocumentsAsync(FilterDefinition filte => _operationExecutor.ExecuteReadOperationAsync( CreateCountDocumentsOperation(filter, options), _readOperationOptions, + session: null, cancellationToken: cancellationToken); public override Task CountDocumentsAsync(IClientSessionHandle session, FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) @@ -302,6 +306,7 @@ public override IAsyncCursor Distinct(FieldDefinition _operationExecutor.ExecuteReadOperation( CreateDistinctOperation(field, filter, options), _readOperationOptions, + session: null, cancellationToken: cancellationToken); public override IAsyncCursor Distinct(IClientSessionHandle session, FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) @@ -315,6 +320,7 @@ public override Task> DistinctAsync(FieldDefinition => _operationExecutor.ExecuteReadOperationAsync( CreateDistinctOperation(field, filter, options), _readOperationOptions, + session: null, cancellationToken: cancellationToken); public override Task> DistinctAsync(IClientSessionHandle session, FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) @@ -328,6 +334,7 @@ public override IAsyncCursor DistinctMany(FieldDefinition _operationExecutor.ExecuteReadOperation( CreateDistinctManyOperation(field, filter, options), _readOperationOptions, + session: null, cancellationToken: cancellationToken); public override IAsyncCursor DistinctMany(IClientSessionHandle session, FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) @@ -341,6 +348,7 @@ public override Task> DistinctManyAsync(FieldDefiniti => _operationExecutor.ExecuteReadOperationAsync( CreateDistinctManyOperation(field, filter, options), _readOperationOptions, + session: null, cancellationToken: cancellationToken); public override Task> DistinctManyAsync(IClientSessionHandle session, FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) @@ -354,18 +362,21 @@ public override long EstimatedDocumentCount(EstimatedDocumentCountOptions option => _operationExecutor.ExecuteReadOperation( CreateEstimatedDocumentCountOperation(options), _readOperationOptions, + session: null, cancellationToken: cancellationToken); public override Task EstimatedDocumentCountAsync(EstimatedDocumentCountOptions options, CancellationToken cancellationToken = default) => _operationExecutor.ExecuteReadOperationAsync( CreateEstimatedDocumentCountOperation(options), _readOperationOptions, + session: null, cancellationToken: cancellationToken); public override IAsyncCursor FindSync(FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default) => _operationExecutor.ExecuteReadOperation( CreateFindOperation(filter, options), _readOperationOptions, + session: null, cancellationToken: cancellationToken); public override IAsyncCursor FindSync(IClientSessionHandle session, FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default) @@ -379,6 +390,7 @@ public override Task> FindAsync(FilterDef => _operationExecutor.ExecuteReadOperationAsync( CreateFindOperation(filter, options), _readOperationOptions, + session: null, cancellationToken: cancellationToken); public override Task> FindAsync(IClientSessionHandle session, FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default) @@ -392,6 +404,7 @@ public override TProjection FindOneAndDelete(FilterDefinition _operationExecutor.ExecuteWriteOperation( CreateFindOneAndDeleteOperation(filter, options), _writeOperationOptions, + session: null, cancellationToken: cancellationToken); public override TProjection FindOneAndDelete(IClientSessionHandle session, FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default) @@ -405,6 +418,7 @@ public override Task FindOneAndDeleteAsync(FilterDefin => _operationExecutor.ExecuteWriteOperationAsync( CreateFindOneAndDeleteOperation(filter, options), _writeOperationOptions, + session: null, cancellationToken: cancellationToken); public override Task FindOneAndDeleteAsync(IClientSessionHandle session, FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default) @@ -418,6 +432,7 @@ public override TProjection FindOneAndReplace(FilterDefinition _operationExecutor.ExecuteWriteOperation( CreateFindOneAndReplaceOperation(filter, replacement, options), _writeOperationOptions, + session: null, cancellationToken: cancellationToken); public override TProjection FindOneAndReplace(IClientSessionHandle session, FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default) @@ -431,6 +446,7 @@ public override Task FindOneAndReplaceAsync(FilterDefi => _operationExecutor.ExecuteWriteOperationAsync( CreateFindOneAndReplaceOperation(filter, replacement, options), _writeOperationOptions, + session: null, cancellationToken: cancellationToken); public override Task FindOneAndReplaceAsync(IClientSessionHandle session, FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default) @@ -444,6 +460,7 @@ public override TProjection FindOneAndUpdate(FilterDefinition _operationExecutor.ExecuteWriteOperation( CreateFindOneAndUpdateOperation(filter, update, options), _writeOperationOptions, + session: null, cancellationToken: cancellationToken); public override TProjection FindOneAndUpdate(IClientSessionHandle session, FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default) @@ -457,6 +474,7 @@ public override Task FindOneAndUpdateAsync(FilterDefin => _operationExecutor.ExecuteWriteOperationAsync( CreateFindOneAndUpdateOperation(filter, update, options), _writeOperationOptions, + session: null, cancellationToken: cancellationToken); public override Task FindOneAndUpdateAsync(IClientSessionHandle session, FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default) @@ -551,6 +569,7 @@ public override IChangeStreamCursor Watch( => _operationExecutor.ExecuteReadOperation( CreateChangeStreamOperation(pipeline, options), _readOperationOptions, + session: null, cancellationToken: cancellationToken); public override IChangeStreamCursor Watch( @@ -571,6 +590,7 @@ public override Task> WatchAsync( => _operationExecutor.ExecuteReadOperationAsync( CreateChangeStreamOperation(pipeline, options), _readOperationOptions, + session: null, cancellationToken: cancellationToken); public override Task> WatchAsync( @@ -1364,6 +1384,7 @@ public override void DropAll(DropIndexOptions options, CancellationToken cancell => _collection._operationExecutor.ExecuteWriteOperation( CreateDropAllOperation(options), _collection._writeOperationOptions, + session: null, cancellationToken: cancellationToken); public override void DropAll(IClientSessionHandle session, CancellationToken cancellationToken = default) @@ -1383,6 +1404,7 @@ public override Task DropAllAsync(DropIndexOptions options, CancellationToken ca => _collection._operationExecutor.ExecuteWriteOperationAsync( CreateDropAllOperation(options), _collection._writeOperationOptions, + session: null, cancellationToken: cancellationToken); public override Task DropAllAsync(IClientSessionHandle session, CancellationToken cancellationToken = default) @@ -1402,6 +1424,7 @@ public override void DropOne(string name, DropIndexOptions options, Cancellation => _collection._operationExecutor.ExecuteWriteOperation( CreateDropOneOperation(name, options), _collection._writeOperationOptions, + session: null, cancellationToken: cancellationToken); public override void DropOne(IClientSessionHandle session, string name, CancellationToken cancellationToken = default) @@ -1425,6 +1448,7 @@ public override Task DropOneAsync(string name, DropIndexOptions options, Cancell => _collection._operationExecutor.ExecuteWriteOperationAsync( CreateDropOneOperation(name, options), _collection._writeOperationOptions, + session: null, cancellationToken: cancellationToken); public override Task DropOneAsync(IClientSessionHandle session, string name, CancellationToken cancellationToken = default) @@ -1448,6 +1472,7 @@ public override IAsyncCursor List(ListIndexesOptions options, Canc => _collection._operationExecutor.ExecuteReadOperation( CreateListIndexesOperation(options), _collection._readOperationOptions, + session: null, cancellationToken: cancellationToken); public override IAsyncCursor List(IClientSessionHandle session, CancellationToken cancellationToken = default) @@ -1467,6 +1492,7 @@ public override Task> ListAsync(ListIndexesOptions op => _collection._operationExecutor.ExecuteReadOperationAsync( CreateListIndexesOperation(options), _collection._readOperationOptions, + session: null, cancellationToken: cancellationToken); public override Task> ListAsync(IClientSessionHandle session, CancellationToken cancellationToken = default) @@ -1583,14 +1609,14 @@ public MongoSearchIndexManager(MongoCollectionImpl collection) public IEnumerable CreateMany(IEnumerable models, CancellationToken cancellationToken = default) { var operation = CreateCreateIndexesOperation(models); - var result = _collection._operationExecutor.ExecuteWriteOperation(operation, _collection._writeOperationOptions, cancellationToken: cancellationToken); + var result = _collection._operationExecutor.ExecuteWriteOperation(operation, _collection._writeOperationOptions, session: null, cancellationToken: cancellationToken); return GetIndexNames(result); } public async Task> CreateManyAsync(IEnumerable models, CancellationToken cancellationToken = default) { var operation = CreateCreateIndexesOperation(models); - var result = await _collection._operationExecutor.ExecuteWriteOperationAsync(operation, _collection._writeOperationOptions, cancellationToken: cancellationToken).ConfigureAwait(false); + var result = await _collection._operationExecutor.ExecuteWriteOperationAsync(operation, _collection._writeOperationOptions, session: null, cancellationToken: cancellationToken).ConfigureAwait(false); return GetIndexNames(result); } @@ -1616,12 +1642,14 @@ public void DropOne(string indexName, CancellationToken cancellationToken = defa => _collection._operationExecutor.ExecuteWriteOperation( new DropSearchIndexOperation(_collection.CollectionNamespace, indexName, _collection._messageEncoderSettings), _collection._writeOperationOptions, + session: null, cancellationToken: cancellationToken); public Task DropOneAsync(string indexName, CancellationToken cancellationToken = default) => _collection._operationExecutor.ExecuteWriteOperationAsync( new DropSearchIndexOperation(_collection.CollectionNamespace, indexName, _collection._messageEncoderSettings), _collection._writeOperationOptions, + session: null, cancellationToken: cancellationToken); public IAsyncCursor List(string indexName, AggregateOptions aggregateOptions = null, CancellationToken cancellationToken = default) @@ -1638,12 +1666,14 @@ public void Update(string indexName, BsonDocument definition, CancellationToken => _collection._operationExecutor.ExecuteWriteOperation( new UpdateSearchIndexOperation(_collection.CollectionNamespace, indexName, definition, _collection._messageEncoderSettings), _collection._writeOperationOptions, + session: null, cancellationToken: cancellationToken); public Task UpdateAsync(string indexName, BsonDocument definition, CancellationToken cancellationToken = default) => _collection._operationExecutor.ExecuteWriteOperationAsync( new UpdateSearchIndexOperation(_collection.CollectionNamespace, indexName, definition, _collection._messageEncoderSettings), _collection._writeOperationOptions, + session: null, cancellationToken: cancellationToken); // private methods diff --git a/src/MongoDB.Driver/MongoDatabase.cs b/src/MongoDB.Driver/MongoDatabase.cs index 1d433dcec44..877faa560d2 100644 --- a/src/MongoDB.Driver/MongoDatabase.cs +++ b/src/MongoDB.Driver/MongoDatabase.cs @@ -239,6 +239,7 @@ public void CreateView(string viewName, string viewOn, Pipel => _operationExecutor.ExecuteWriteOperation( CreateCreateViewOperation(viewName, viewOn, pipeline, options), _writeOperationOptions, + session: null, cancellationToken: cancellationToken); public void CreateView(IClientSessionHandle session, string viewName, string viewOn, PipelineDefinition pipeline, CreateViewOptions options = null, CancellationToken cancellationToken = default) @@ -252,6 +253,7 @@ public Task CreateViewAsync(string viewName, string viewOn, => _operationExecutor.ExecuteWriteOperationAsync( CreateCreateViewOperation(viewName, viewOn, pipeline, options), _writeOperationOptions, + session: null, cancellationToken: cancellationToken); public Task CreateViewAsync(IClientSessionHandle session, string viewName, string viewOn, PipelineDefinition pipeline, CreateViewOptions options = null, CancellationToken cancellationToken = default) @@ -353,6 +355,7 @@ public async Task> ListCollectionNamesAsync(ListCollectionN var cursor = await _operationExecutor.ExecuteReadOperationAsync( CreateListCollectionNamesOperation(options), _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, + session: null, cancellationToken: cancellationToken).ConfigureAwait(false); return new BatchTransformingAsyncCursor(cursor, ExtractCollectionNames); } @@ -371,6 +374,7 @@ public IAsyncCursor ListCollections(ListCollectionsOptions options => _operationExecutor.ExecuteReadOperation( CreateListCollectionsOperation(options), _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, + session: null, cancellationToken: cancellationToken); public IAsyncCursor ListCollections(IClientSessionHandle session, ListCollectionsOptions options, CancellationToken cancellationToken) @@ -384,6 +388,7 @@ public Task> ListCollectionsAsync(ListCollectionsOpti => _operationExecutor.ExecuteReadOperationAsync( CreateListCollectionsOperation(options), _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, + session: null, cancellationToken: cancellationToken); public Task> ListCollectionsAsync(IClientSessionHandle session, ListCollectionsOptions options, CancellationToken cancellationToken) @@ -397,6 +402,7 @@ public void RenameCollection(string oldName, string newName, RenameCollectionOpt => _operationExecutor.ExecuteWriteOperation( CreateRenameCollectionOperation(oldName, newName, options), _writeOperationOptions, + session: null, cancellationToken: cancellationToken); public void RenameCollection(IClientSessionHandle session, string oldName, string newName, RenameCollectionOptions options, CancellationToken cancellationToken) @@ -410,6 +416,7 @@ public Task RenameCollectionAsync(string oldName, string newName, RenameCollecti => _operationExecutor.ExecuteWriteOperationAsync( CreateRenameCollectionOperation(oldName, newName, options), _writeOperationOptions, + session: null, cancellationToken: cancellationToken); public Task RenameCollectionAsync(IClientSessionHandle session, string oldName, string newName, RenameCollectionOptions options, CancellationToken cancellationToken) @@ -423,6 +430,7 @@ public TResult RunCommand(Command command, ReadPreference read => _operationExecutor.ExecuteReadOperation( CreateRunCommandOperation(command), _readOperationOptions with { ExplicitReadPreference = readPreference, DefaultReadPreference = ReadPreference.Primary}, + session: null, cancellationToken: cancellationToken); public TResult RunCommand(IClientSessionHandle session, Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default) @@ -436,6 +444,7 @@ public Task RunCommandAsync(Command command, ReadPref => _operationExecutor.ExecuteReadOperationAsync( CreateRunCommandOperation(command), _readOperationOptions with { ExplicitReadPreference = readPreference, DefaultReadPreference = ReadPreference.Primary}, + session: null, cancellationToken: cancellationToken); public Task RunCommandAsync(IClientSessionHandle session, Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default) @@ -452,6 +461,7 @@ public IChangeStreamCursor Watch( => _operationExecutor.ExecuteReadOperation( CreateChangeStreamOperation(pipeline, options), _readOperationOptions, + session: null, cancellationToken: cancellationToken); public IChangeStreamCursor Watch( @@ -472,6 +482,7 @@ public Task> WatchAsync( => _operationExecutor.ExecuteReadOperationAsync( CreateChangeStreamOperation(pipeline, options), _readOperationOptions, + session: null, cancellationToken: cancellationToken); public Task> WatchAsync( diff --git a/src/MongoDB.Driver/OperationExecutor.cs b/src/MongoDB.Driver/OperationExecutor.cs index 764369d5ce8..ffb49457705 100644 --- a/src/MongoDB.Driver/OperationExecutor.cs +++ b/src/MongoDB.Driver/OperationExecutor.cs @@ -40,7 +40,7 @@ public void Dispose() public TResult ExecuteReadOperation( IReadOperation operation, ReadOperationOptions options, - IClientSessionHandle session = null, + IClientSessionHandle session, bool disableChannelPinning = false, CancellationToken cancellationToken = default) { @@ -66,7 +66,7 @@ public TResult ExecuteReadOperation( public async Task ExecuteReadOperationAsync( IReadOperation operation, ReadOperationOptions options, - IClientSessionHandle session = null, + IClientSessionHandle session, bool disableChannelPinning = false, CancellationToken cancellationToken = default) { @@ -92,7 +92,7 @@ public async Task ExecuteReadOperationAsync( public TResult ExecuteWriteOperation( IWriteOperation operation, WriteOperationOptions options, - IClientSessionHandle session = null, + IClientSessionHandle session, bool disableChannelPinning = false, CancellationToken cancellationToken = default) { @@ -117,7 +117,7 @@ public TResult ExecuteWriteOperation( public async Task ExecuteWriteOperationAsync( IWriteOperation operation, WriteOperationOptions options, - IClientSessionHandle session = null, + IClientSessionHandle session, bool disableChannelPinning = false, CancellationToken cancellationToken = default) { diff --git a/tests/MongoDB.Driver.Tests/MockOperationExecutor.cs b/tests/MongoDB.Driver.Tests/MockOperationExecutor.cs index 76a746d96f7..f719d472c3e 100644 --- a/tests/MongoDB.Driver.Tests/MockOperationExecutor.cs +++ b/tests/MongoDB.Driver.Tests/MockOperationExecutor.cs @@ -65,7 +65,7 @@ public void EnqueueException(Exception exception) public TResult ExecuteReadOperation( IReadOperation operation, ReadOperationOptions readOperationOptions, - IClientSessionHandle session = null, + IClientSessionHandle session, bool disableChannelPinning = false, CancellationToken cancellationToken = default) { @@ -97,7 +97,7 @@ public TResult ExecuteReadOperation( public Task ExecuteReadOperationAsync( IReadOperation operation, ReadOperationOptions readOperationOptions, - IClientSessionHandle session = null, + IClientSessionHandle session, bool disableChannelPinning = false, CancellationToken cancellationToken = default) { @@ -117,7 +117,7 @@ public Task ExecuteReadOperationAsync( public TResult ExecuteWriteOperation( IWriteOperation operation, WriteOperationOptions writeOperationOptions, - IClientSessionHandle session = null, + IClientSessionHandle session, bool disableChannelPinning = false, CancellationToken cancellationToken = default) { @@ -149,7 +149,7 @@ public TResult ExecuteWriteOperation( public Task ExecuteWriteOperationAsync( IWriteOperation operation, WriteOperationOptions writeOperationOptions, - IClientSessionHandle session = null, + IClientSessionHandle session, bool disableChannelPinning = false, CancellationToken cancellationToken = default) { From 9155e463154928e7dd4b0aa08864760ba1c783c5 Mon Sep 17 00:00:00 2001 From: Oleksandr Poliakov Date: Mon, 2 Jun 2025 18:38:17 -0700 Subject: [PATCH 04/14] Pr --- src/MongoDB.Driver/IOperationExecutor.cs | 28 ++- src/MongoDB.Driver/MongoClient.cs | 50 +++--- src/MongoDB.Driver/MongoCollectionImpl.cs | 159 +++++++++++------- src/MongoDB.Driver/MongoDatabase.cs | 100 +++++++---- src/MongoDB.Driver/OperationExecutor.cs | 46 +++-- .../MockOperationExecutor.cs | 32 ++-- .../OperationExecutorTests.cs | 8 +- 7 files changed, 243 insertions(+), 180 deletions(-) diff --git a/src/MongoDB.Driver/IOperationExecutor.cs b/src/MongoDB.Driver/IOperationExecutor.cs index dc3f20f8689..b2086e24c78 100644 --- a/src/MongoDB.Driver/IOperationExecutor.cs +++ b/src/MongoDB.Driver/IOperationExecutor.cs @@ -22,33 +22,29 @@ namespace MongoDB.Driver { internal interface IOperationExecutor : IDisposable { - TResult ExecuteReadOperation( - IReadOperation operation, + TResult ExecuteReadOperation(IReadOperation operation, ReadOperationOptions options, IClientSessionHandle session, - bool disableChannelPinning = false, - CancellationToken cancellationToken = default); + bool allowChannelPinning, + CancellationToken cancellationToken); - Task ExecuteReadOperationAsync( - IReadOperation operation, + Task ExecuteReadOperationAsync(IReadOperation operation, ReadOperationOptions options, IClientSessionHandle session, - bool disableChannelPinning = false, - CancellationToken cancellationToken = default); + bool allowChannelPinning, + CancellationToken cancellationToken); - TResult ExecuteWriteOperation( - IWriteOperation operation, + TResult ExecuteWriteOperation(IWriteOperation operation, WriteOperationOptions options, IClientSessionHandle session, - bool disableChannelPinning = false, - CancellationToken cancellationToken = default); + bool allowChannelPinning, + CancellationToken cancellationToken); - Task ExecuteWriteOperationAsync( - IWriteOperation operation, + Task ExecuteWriteOperationAsync(IWriteOperation operation, WriteOperationOptions options, IClientSessionHandle session, - bool disableChannelPinning = false, - CancellationToken cancellationToken = default); + bool allowChannelPinning, + CancellationToken cancellationToken); IClientSessionHandle StartImplicitSession(CancellationToken cancellationToken); diff --git a/src/MongoDB.Driver/MongoClient.cs b/src/MongoDB.Driver/MongoClient.cs index 3b942569f3c..76af45ea2bb 100644 --- a/src/MongoDB.Driver/MongoClient.cs +++ b/src/MongoDB.Driver/MongoClient.cs @@ -62,7 +62,7 @@ public MongoClient() /// /// The settings. public MongoClient(MongoClientSettings settings) - : this(client => new OperationExecutor(client), settings) + : this(settings, client => new OperationExecutor(client)) { } @@ -85,7 +85,7 @@ public MongoClient(string connectionString) { } - internal MongoClient(Func operationExecutorFactory, MongoClientSettings settings) + internal MongoClient(MongoClientSettings settings, Func operationExecutorFactory) { _operationExecutorFactory = Ensure.IsNotNull(operationExecutorFactory, nameof(operationExecutorFactory)); _settings = Ensure.IsNotNull(settings, nameof(settings)).FrozenCopy(); @@ -140,7 +140,7 @@ public ClientBulkWriteResult BulkWrite(IReadOnlyList models, Cli CreateClientBulkWriteOperation(models, options), _writeOperationOptions, session: null, - disableChannelPinning: true, + allowChannelPinning: false, cancellationToken: cancellationToken); /// @@ -149,7 +149,7 @@ public ClientBulkWriteResult BulkWrite(IClientSessionHandle session, IReadOnlyLi CreateClientBulkWriteOperation(models, options), _writeOperationOptions, Ensure.IsNotNull(session, nameof(session)), - disableChannelPinning: true, + allowChannelPinning: false, cancellationToken: cancellationToken); /// @@ -158,7 +158,7 @@ public Task BulkWriteAsync(IReadOnlyList CreateClientBulkWriteOperation(models, options), _writeOperationOptions, session: null, - disableChannelPinning: true, + allowChannelPinning: false, cancellationToken: cancellationToken); /// @@ -167,7 +167,7 @@ public Task BulkWriteAsync(IClientSessionHandle session, CreateClientBulkWriteOperation(models, options), _writeOperationOptions, Ensure.IsNotNull(session, nameof(session)), - disableChannelPinning: true, + allowChannelPinning: false, cancellationToken: cancellationToken); /// @@ -206,7 +206,7 @@ public void DropDatabase(string name, CancellationToken cancellationToken = defa CreateDropDatabaseOperation(name), _writeOperationOptions, session: null, - disableChannelPinning: true, + allowChannelPinning: false, cancellationToken: cancellationToken); /// @@ -215,7 +215,7 @@ public void DropDatabase(IClientSessionHandle session, string name, Cancellation CreateDropDatabaseOperation(name), _writeOperationOptions, Ensure.IsNotNull(session, nameof(session)), - disableChannelPinning: true, + allowChannelPinning: false, cancellationToken: cancellationToken); /// @@ -224,7 +224,7 @@ public Task DropDatabaseAsync(string name, CancellationToken cancellationToken = CreateDropDatabaseOperation(name), _writeOperationOptions, session: null, - disableChannelPinning: true, + allowChannelPinning: false, cancellationToken: cancellationToken); /// @@ -233,7 +233,7 @@ public Task DropDatabaseAsync(IClientSessionHandle session, string name, Cancell CreateDropDatabaseOperation(name), _writeOperationOptions, Ensure.IsNotNull(session, nameof(session)), - disableChannelPinning: true, + allowChannelPinning: false, cancellationToken: cancellationToken); /// @@ -318,7 +318,7 @@ public IAsyncCursor ListDatabases(CancellationToken cancellationTo CreateListDatabaseOperation(null), _readOperationOptions, session: null, - disableChannelPinning: true, + allowChannelPinning: false, cancellationToken: cancellationToken); /// @@ -329,7 +329,7 @@ public IAsyncCursor ListDatabases( CreateListDatabaseOperation(options), _readOperationOptions, session: null, - disableChannelPinning: true, + allowChannelPinning: false, cancellationToken: cancellationToken); /// @@ -340,7 +340,7 @@ public IAsyncCursor ListDatabases( CreateListDatabaseOperation(null), _readOperationOptions, Ensure.IsNotNull(session, nameof(session)), - disableChannelPinning: true, + allowChannelPinning: false, cancellationToken: cancellationToken); /// @@ -352,7 +352,7 @@ public IAsyncCursor ListDatabases( CreateListDatabaseOperation(options), _readOperationOptions, Ensure.IsNotNull(session, nameof(session)), - disableChannelPinning: true, + allowChannelPinning: false, cancellationToken: cancellationToken); /// @@ -361,7 +361,7 @@ public Task> ListDatabasesAsync(CancellationToken can CreateListDatabaseOperation(null), _readOperationOptions, session: null, - disableChannelPinning: true, + allowChannelPinning: false, cancellationToken: cancellationToken); /// @@ -372,7 +372,7 @@ public Task> ListDatabasesAsync( CreateListDatabaseOperation(options), _readOperationOptions, session: null, - disableChannelPinning: true, + allowChannelPinning: false, cancellationToken: cancellationToken); /// @@ -383,7 +383,7 @@ public Task> ListDatabasesAsync( CreateListDatabaseOperation(null), _readOperationOptions, Ensure.IsNotNull(session, nameof(session)), - disableChannelPinning: true, + allowChannelPinning: false, cancellationToken: cancellationToken); /// @@ -395,7 +395,7 @@ public Task> ListDatabasesAsync( CreateListDatabaseOperation(options), _readOperationOptions, Ensure.IsNotNull(session, nameof(session)), - disableChannelPinning: true, + allowChannelPinning: false, cancellationToken: cancellationToken); /// @@ -423,7 +423,7 @@ public IChangeStreamCursor Watch( CreateChangeStreamOperation(pipeline, options), _readOperationOptions, session: null, - disableChannelPinning: true, + allowChannelPinning: false, cancellationToken: cancellationToken); /// @@ -436,7 +436,7 @@ public IChangeStreamCursor Watch( CreateChangeStreamOperation(pipeline, options), _readOperationOptions, Ensure.IsNotNull(session, nameof(session)), - disableChannelPinning: true, + allowChannelPinning: false, cancellationToken: cancellationToken); /// @@ -448,7 +448,7 @@ public Task> WatchAsync( CreateChangeStreamOperation(pipeline, options), _readOperationOptions, session: null, - disableChannelPinning: true, + allowChannelPinning: false, cancellationToken: cancellationToken); /// @@ -461,7 +461,7 @@ public Task> WatchAsync( CreateChangeStreamOperation(pipeline, options), _readOperationOptions, Ensure.IsNotNull(session, nameof(session)), - disableChannelPinning: true, + allowChannelPinning: false, cancellationToken: cancellationToken); /// @@ -473,7 +473,7 @@ public IMongoClient WithReadConcern(ReadConcern readConcern) var newSettings = Settings.Clone(); newSettings.ReadConcern = readConcern; - return new MongoClient(_operationExecutorFactory, newSettings); + return new MongoClient(newSettings, _operationExecutorFactory); } /// @@ -485,7 +485,7 @@ public IMongoClient WithReadPreference(ReadPreference readPreference) var newSettings = Settings.Clone(); newSettings.ReadPreference = readPreference; - return new MongoClient(_operationExecutorFactory, newSettings); + return new MongoClient(newSettings, _operationExecutorFactory); } /// @@ -497,7 +497,7 @@ public IMongoClient WithWriteConcern(WriteConcern writeConcern) var newSettings = Settings.Clone(); newSettings.WriteConcern = writeConcern; - return new MongoClient(_operationExecutorFactory, newSettings); + return new MongoClient(newSettings, _operationExecutorFactory); } // private methods diff --git a/src/MongoDB.Driver/MongoCollectionImpl.cs b/src/MongoDB.Driver/MongoCollectionImpl.cs index 0a9673ca626..d5684cd38dd 100644 --- a/src/MongoDB.Driver/MongoCollectionImpl.cs +++ b/src/MongoDB.Driver/MongoCollectionImpl.cs @@ -113,20 +113,20 @@ public override IAsyncCursor Aggregate(IClientSessionHandle se if (isAggregateToCollection) { var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - _operationExecutor.ExecuteWriteOperation(aggregateOperation, _writeOperationOptions, session, cancellationToken: cancellationToken); + _operationExecutor.ExecuteWriteOperation(aggregateOperation, _writeOperationOptions, session, true, cancellationToken); return CreateAggregateToCollectionResultCursor(session, renderedPipeline, options); } else { var aggregateOperation = CreateAggregateOperation(renderedPipeline, options); - return _operationExecutor.ExecuteReadOperation(aggregateOperation, _readOperationOptions, session, cancellationToken: cancellationToken); + return _operationExecutor.ExecuteReadOperation(aggregateOperation, _readOperationOptions, session, true, cancellationToken); } } public override async Task> AggregateAsync(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false); - return await AggregateAsync(session, pipeline, options, cancellationToken: cancellationToken).ConfigureAwait(false); + return await AggregateAsync(session, pipeline, options, cancellationToken).ConfigureAwait(false); } public override async Task> AggregateAsync(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) @@ -140,20 +140,20 @@ public override async Task> AggregateAsync(IClien if (isAggregateToCollection) { var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - await _operationExecutor.ExecuteWriteOperationAsync(aggregateOperation, _writeOperationOptions, session, cancellationToken: cancellationToken).ConfigureAwait(false); + await _operationExecutor.ExecuteWriteOperationAsync(aggregateOperation, _writeOperationOptions, session, true, cancellationToken).ConfigureAwait(false); return CreateAggregateToCollectionResultCursor(session, renderedPipeline, options); } else { var aggregateOperation = CreateAggregateOperation(renderedPipeline, options); - return await _operationExecutor.ExecuteReadOperationAsync(aggregateOperation, _readOperationOptions, session, cancellationToken: cancellationToken).ConfigureAwait(false); + return await _operationExecutor.ExecuteReadOperationAsync(aggregateOperation, _readOperationOptions, session, true, cancellationToken: cancellationToken).ConfigureAwait(false); } } public override void AggregateToCollection(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { - using var session = _operationExecutor.StartImplicitSession(cancellationToken: cancellationToken); - AggregateToCollection(session, pipeline, options, cancellationToken: cancellationToken); + using var session = _operationExecutor.StartImplicitSession(cancellationToken); + AggregateToCollection(session, pipeline, options, cancellationToken); } public override void AggregateToCollection(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) @@ -170,13 +170,13 @@ public override void AggregateToCollection(IClientSessionHandle session } var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - _operationExecutor.ExecuteWriteOperation(aggregateOperation, _writeOperationOptions, session, cancellationToken: cancellationToken); + _operationExecutor.ExecuteWriteOperation(aggregateOperation, _writeOperationOptions, session, true, cancellationToken); } public override async Task AggregateToCollectionAsync(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false); - await AggregateToCollectionAsync(session, pipeline, options, cancellationToken: cancellationToken).ConfigureAwait(false); + await AggregateToCollectionAsync(session, pipeline, options, cancellationToken).ConfigureAwait(false); } public override async Task AggregateToCollectionAsync(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) @@ -193,13 +193,13 @@ public override async Task AggregateToCollectionAsync(IClientSessionHan } var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - await _operationExecutor.ExecuteWriteOperationAsync(aggregateOperation, _writeOperationOptions, session, cancellationToken: cancellationToken).ConfigureAwait(false); + await _operationExecutor.ExecuteWriteOperationAsync(aggregateOperation, _writeOperationOptions, session, true, cancellationToken).ConfigureAwait(false); } public override BulkWriteResult BulkWrite(IEnumerable> requests, BulkWriteOptions options, CancellationToken cancellationToken = default) { using var session = _operationExecutor.StartImplicitSession(cancellationToken: cancellationToken); - return BulkWrite(session, requests, options, cancellationToken: cancellationToken); + return BulkWrite(session, requests, options, cancellationToken); } public override BulkWriteResult BulkWrite(IClientSessionHandle session, IEnumerable> requests, BulkWriteOptions options, CancellationToken cancellationToken = default) @@ -210,7 +210,7 @@ public override BulkWriteResult BulkWrite(IClientSessionHandle sessio var operation = CreateBulkWriteOperation(session, requestsArray, options); try { - var result = _operationExecutor.ExecuteWriteOperation(operation, _writeOperationOptions, session, cancellationToken: cancellationToken); + var result = _operationExecutor.ExecuteWriteOperation(operation, _writeOperationOptions, session, true, cancellationToken); return BulkWriteResult.FromCore(result, requestsArray); } catch (MongoBulkWriteOperationException ex) @@ -222,7 +222,7 @@ public override BulkWriteResult BulkWrite(IClientSessionHandle sessio public override async Task> BulkWriteAsync(IEnumerable> requests, BulkWriteOptions options, CancellationToken cancellationToken = default) { using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false); - return await BulkWriteAsync(session, requests, options, cancellationToken: cancellationToken).ConfigureAwait(false); + return await BulkWriteAsync(session, requests, options, cancellationToken).ConfigureAwait(false); } public override async Task> BulkWriteAsync(IClientSessionHandle session, IEnumerable> requests, BulkWriteOptions options, CancellationToken cancellationToken = default) @@ -233,7 +233,7 @@ public override async Task> BulkWriteAsync(IClientSes var operation = CreateBulkWriteOperation(session, requestsArray, options); try { - var result = await _operationExecutor.ExecuteWriteOperationAsync(operation, _writeOperationOptions, session, cancellationToken: cancellationToken).ConfigureAwait(false); + var result = await _operationExecutor.ExecuteWriteOperationAsync(operation, _writeOperationOptions, session, true, cancellationToken).ConfigureAwait(false); return BulkWriteResult.FromCore(result, requestsArray); } catch (MongoBulkWriteOperationException ex) @@ -248,6 +248,7 @@ public override long Count(FilterDefinition filter, CountOptions opti CreateCountOperation(filter, options), _readOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); [Obsolete("Use CountDocuments or EstimatedDocumentCount instead.")] @@ -256,6 +257,7 @@ public override long Count(IClientSessionHandle session, FilterDefinition CountAsync(FilterDefinition filter, CountO CreateCountOperation(filter, options), _readOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); [Obsolete("Use CountDocumentsAsync or EstimatedDocumentCountAsync instead.")] @@ -272,6 +275,7 @@ public override Task CountAsync(IClientSessionHandle session, FilterDefini CreateCountOperation(filter, options), _readOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public override long CountDocuments(FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) @@ -279,6 +283,7 @@ public override long CountDocuments(FilterDefinition filter, CountOpt CreateCountDocumentsOperation(filter, options), _readOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public override long CountDocuments(IClientSessionHandle session, FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) @@ -286,6 +291,7 @@ public override long CountDocuments(IClientSessionHandle session, FilterDefiniti CreateCountDocumentsOperation(filter, options), _readOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public override Task CountDocumentsAsync(FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) @@ -293,6 +299,7 @@ public override Task CountDocumentsAsync(FilterDefinition filte CreateCountDocumentsOperation(filter, options), _readOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public override Task CountDocumentsAsync(IClientSessionHandle session, FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) @@ -300,6 +307,7 @@ public override Task CountDocumentsAsync(IClientSessionHandle session, Fil CreateCountDocumentsOperation(filter, options), _readOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public override IAsyncCursor Distinct(FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) @@ -307,6 +315,7 @@ public override IAsyncCursor Distinct(FieldDefinition Distinct(IClientSessionHandle session, FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) @@ -314,6 +323,7 @@ public override IAsyncCursor Distinct(IClientSessionHandle sessi CreateDistinctOperation(field, filter, options), _readOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public override Task> DistinctAsync(FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) @@ -321,6 +331,7 @@ public override Task> DistinctAsync(FieldDefinition CreateDistinctOperation(field, filter, options), _readOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public override Task> DistinctAsync(IClientSessionHandle session, FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) @@ -328,6 +339,7 @@ public override Task> DistinctAsync(IClientSessionH CreateDistinctOperation(field, filter, options), _readOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public override IAsyncCursor DistinctMany(FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) @@ -335,6 +347,7 @@ public override IAsyncCursor DistinctMany(FieldDefinition DistinctMany(IClientSessionHandle session, FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) @@ -342,6 +355,7 @@ public override IAsyncCursor DistinctMany(IClientSessionHandle ses CreateDistinctManyOperation(field, filter, options), _readOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public override Task> DistinctManyAsync(FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) @@ -349,6 +363,7 @@ public override Task> DistinctManyAsync(FieldDefiniti CreateDistinctManyOperation(field, filter, options), _readOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public override Task> DistinctManyAsync(IClientSessionHandle session, FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) @@ -356,13 +371,14 @@ public override Task> DistinctManyAsync(IClientSessio CreateDistinctManyOperation(field, filter, options), _readOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public override long EstimatedDocumentCount(EstimatedDocumentCountOptions options, CancellationToken cancellationToken = default) => _operationExecutor.ExecuteReadOperation( CreateEstimatedDocumentCountOperation(options), _readOperationOptions, - session: null, + session: null, allowChannelPinning: true, cancellationToken: cancellationToken); public override Task EstimatedDocumentCountAsync(EstimatedDocumentCountOptions options, CancellationToken cancellationToken = default) @@ -370,6 +386,7 @@ public override Task EstimatedDocumentCountAsync(EstimatedDocumentCountOpt CreateEstimatedDocumentCountOperation(options), _readOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public override IAsyncCursor FindSync(FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default) @@ -377,6 +394,7 @@ public override IAsyncCursor FindSync(FilterDefinition CreateFindOperation(filter, options), _readOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public override IAsyncCursor FindSync(IClientSessionHandle session, FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default) @@ -384,6 +402,7 @@ public override IAsyncCursor FindSync(IClientSessionHa CreateFindOperation(filter, options), _readOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public override Task> FindAsync(FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default) @@ -391,6 +410,7 @@ public override Task> FindAsync(FilterDef CreateFindOperation(filter, options), _readOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public override Task> FindAsync(IClientSessionHandle session, FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default) @@ -398,6 +418,7 @@ public override Task> FindAsync(IClientSe CreateFindOperation(filter, options), _readOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public override TProjection FindOneAndDelete(FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default) @@ -405,6 +426,7 @@ public override TProjection FindOneAndDelete(FilterDefinition(IClientSessionHandle session, FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default) @@ -412,6 +434,7 @@ public override TProjection FindOneAndDelete(IClientSessionHandle s CreateFindOneAndDeleteOperation(filter, options), _writeOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public override Task FindOneAndDeleteAsync(FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default) @@ -419,6 +442,7 @@ public override Task FindOneAndDeleteAsync(FilterDefin CreateFindOneAndDeleteOperation(filter, options), _writeOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public override Task FindOneAndDeleteAsync(IClientSessionHandle session, FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default) @@ -426,6 +450,7 @@ public override Task FindOneAndDeleteAsync(IClientSess CreateFindOneAndDeleteOperation(filter, options), _writeOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public override TProjection FindOneAndReplace(FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default) @@ -433,6 +458,7 @@ public override TProjection FindOneAndReplace(FilterDefinition(IClientSessionHandle session, FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default) @@ -440,6 +466,7 @@ public override TProjection FindOneAndReplace(IClientSessionHandle CreateFindOneAndReplaceOperation(filter, replacement, options), _writeOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public override Task FindOneAndReplaceAsync(FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default) @@ -447,6 +474,7 @@ public override Task FindOneAndReplaceAsync(FilterDefi CreateFindOneAndReplaceOperation(filter, replacement, options), _writeOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public override Task FindOneAndReplaceAsync(IClientSessionHandle session, FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default) @@ -454,6 +482,7 @@ public override Task FindOneAndReplaceAsync(IClientSes CreateFindOneAndReplaceOperation(filter, replacement, options), _writeOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public override TProjection FindOneAndUpdate(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default) @@ -461,6 +490,7 @@ public override TProjection FindOneAndUpdate(FilterDefinition(IClientSessionHandle session, FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default) @@ -468,6 +498,7 @@ public override TProjection FindOneAndUpdate(IClientSessionHandle s CreateFindOneAndUpdateOperation(filter, update, options), _writeOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public override Task FindOneAndUpdateAsync(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default) @@ -475,6 +506,7 @@ public override Task FindOneAndUpdateAsync(FilterDefin CreateFindOneAndUpdateOperation(filter, update, options), _writeOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public override Task FindOneAndUpdateAsync(IClientSessionHandle session, FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default) @@ -482,6 +514,7 @@ public override Task FindOneAndUpdateAsync(IClientSess CreateFindOneAndUpdateOperation(filter, update, options), _writeOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); [Obsolete("Use Aggregation pipeline instead.")] @@ -506,12 +539,12 @@ public override IAsyncCursor MapReduce(IClientSessionHandle se if (outputOptions == MapReduceOutputOptions.Inline) { var operation = CreateMapReduceOperation(map, reduce, options, resultSerializer, renderArgs); - return _operationExecutor.ExecuteReadOperation(operation, _readOperationOptions, session, cancellationToken: cancellationToken); + return _operationExecutor.ExecuteReadOperation(operation, _readOperationOptions, session, true, cancellationToken); } else { var mapReduceOperation = CreateMapReduceOutputToCollectionOperation(map, reduce, options, outputOptions, renderArgs); - _operationExecutor.ExecuteWriteOperation(mapReduceOperation, _writeOperationOptions, session, cancellationToken: cancellationToken); + _operationExecutor.ExecuteWriteOperation(mapReduceOperation, _writeOperationOptions, session, true, cancellationToken); return CreateMapReduceOutputToCollectionResultCursor(session, options, mapReduceOperation.OutputCollectionNamespace, resultSerializer); } } @@ -520,7 +553,7 @@ public override IAsyncCursor MapReduce(IClientSessionHandle se public override async Task> MapReduceAsync(BsonJavaScript map, BsonJavaScript reduce, MapReduceOptions options = null, CancellationToken cancellationToken = default) { using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false); - return await MapReduceAsync(session, map, reduce, options, cancellationToken: cancellationToken).ConfigureAwait(false); + return await MapReduceAsync(session, map, reduce, options, cancellationToken).ConfigureAwait(false); } [Obsolete("Use Aggregation pipeline instead.")] @@ -538,12 +571,12 @@ public override async Task> MapReduceAsync(IClien if (outputOptions == MapReduceOutputOptions.Inline) { var operation = CreateMapReduceOperation(map, reduce, options, resultSerializer, renderArgs); - return await _operationExecutor.ExecuteReadOperationAsync(operation, _readOperationOptions, session, cancellationToken: cancellationToken).ConfigureAwait(false); + return await _operationExecutor.ExecuteReadOperationAsync(operation, _readOperationOptions, session, true, cancellationToken).ConfigureAwait(false); } else { var mapReduceOperation = CreateMapReduceOutputToCollectionOperation(map, reduce, options, outputOptions, renderArgs); - await _operationExecutor.ExecuteWriteOperationAsync(mapReduceOperation, _writeOperationOptions, session, cancellationToken: cancellationToken).ConfigureAwait(false); + await _operationExecutor.ExecuteWriteOperationAsync(mapReduceOperation, _writeOperationOptions, session, true, cancellationToken).ConfigureAwait(false); return CreateMapReduceOutputToCollectionResultCursor(session, options, mapReduceOperation.OutputCollectionNamespace, resultSerializer); } } @@ -570,6 +603,7 @@ public override IChangeStreamCursor Watch( CreateChangeStreamOperation(pipeline, options), _readOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public override IChangeStreamCursor Watch( @@ -581,6 +615,7 @@ public override IChangeStreamCursor Watch( CreateChangeStreamOperation(pipeline, options), _readOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public override Task> WatchAsync( @@ -591,6 +626,7 @@ public override Task> WatchAsync( CreateChangeStreamOperation(pipeline, options), _readOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public override Task> WatchAsync( @@ -602,6 +638,7 @@ public override Task> WatchAsync( CreateChangeStreamOperation(pipeline, options), _readOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public override IMongoCollection WithReadConcern(ReadConcern readConcern) @@ -749,8 +786,8 @@ private IAsyncCursor CreateAggregateToCollectionResultCursor(I var readOperationOptions = _readOperationOptions with { ExplicitReadPreference = ReadPreference.Primary }; var deferredCursor = new DeferredAsyncCursor( () => forkedSession.Dispose(), - ct => _operationExecutor.ExecuteReadOperation(findOperation, readOperationOptions, forkedSession, cancellationToken: ct), - ct => _operationExecutor.ExecuteReadOperationAsync(findOperation, readOperationOptions, forkedSession, cancellationToken: ct)); + ct => _operationExecutor.ExecuteReadOperation(findOperation, readOperationOptions, forkedSession, true, ct), + ct => _operationExecutor.ExecuteReadOperationAsync(findOperation, readOperationOptions, forkedSession, true, ct)); return deferredCursor; } @@ -1179,8 +1216,8 @@ private IAsyncCursor CreateMapReduceOutputToCollectionResultCursor( () => forkedSession.Dispose(), - ct => _operationExecutor.ExecuteReadOperation(findOperation, readOperationOptions, forkedSession, cancellationToken: ct), - ct => _operationExecutor.ExecuteReadOperationAsync(findOperation, readOperationOptions, forkedSession, cancellationToken: ct)); + ct => _operationExecutor.ExecuteReadOperation(findOperation, readOperationOptions, forkedSession, true, ct), + ct => _operationExecutor.ExecuteReadOperationAsync(findOperation, readOperationOptions, forkedSession, true, ct)); return deferredCursor; } @@ -1328,7 +1365,7 @@ public override IEnumerable CreateMany( CancellationToken cancellationToken = default) { var operation = CreateCreateIndexesOperation(models, options); - _collection._operationExecutor.ExecuteWriteOperation(operation, _collection._writeOperationOptions, null, cancellationToken: cancellationToken); + _collection._operationExecutor.ExecuteWriteOperation(operation, _collection._writeOperationOptions, null, true, cancellationToken); return operation.Requests.Select(x => x.GetIndexName()); } @@ -1344,7 +1381,7 @@ public override IEnumerable CreateMany( Ensure.IsNotNull(session, nameof(session)); var operation = CreateCreateIndexesOperation(models, options); - _collection._operationExecutor.ExecuteWriteOperation(operation, _collection._writeOperationOptions, session, cancellationToken: cancellationToken); + _collection._operationExecutor.ExecuteWriteOperation(operation, _collection._writeOperationOptions, session, true, cancellationToken); return operation.Requests.Select(x => x.GetIndexName()); } @@ -1357,7 +1394,7 @@ public override async Task> CreateManyAsync( CancellationToken cancellationToken = default) { var operation = CreateCreateIndexesOperation(models, options); - await _collection._operationExecutor.ExecuteWriteOperationAsync(operation, _collection._writeOperationOptions, null, cancellationToken: cancellationToken).ConfigureAwait(false); + await _collection._operationExecutor.ExecuteWriteOperationAsync(operation, _collection._writeOperationOptions, null, true, cancellationToken).ConfigureAwait(false); return operation.Requests.Select(x => x.GetIndexName()); } @@ -1373,7 +1410,7 @@ public override async Task> CreateManyAsync( Ensure.IsNotNull(session, nameof(session)); var operation = CreateCreateIndexesOperation(models, options); - await _collection._operationExecutor.ExecuteWriteOperationAsync(operation, _collection._writeOperationOptions, session, cancellationToken: cancellationToken).ConfigureAwait(false); + await _collection._operationExecutor.ExecuteWriteOperationAsync(operation, _collection._writeOperationOptions, session, true, cancellationToken).ConfigureAwait(false); return operation.Requests.Select(x => x.GetIndexName()); } @@ -1385,124 +1422,128 @@ public override void DropAll(DropIndexOptions options, CancellationToken cancell CreateDropAllOperation(options), _collection._writeOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public override void DropAll(IClientSessionHandle session, CancellationToken cancellationToken = default) - => DropAll(session, null, cancellationToken: cancellationToken); + => DropAll(session, null, cancellationToken); public override void DropAll(IClientSessionHandle session, DropIndexOptions options, CancellationToken cancellationToken = default) => _collection._operationExecutor.ExecuteWriteOperation( CreateDropAllOperation(options), _collection._writeOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public override Task DropAllAsync(CancellationToken cancellationToken) - => DropAllAsync(options: null, cancellationToken: cancellationToken); + => DropAllAsync(options: null, cancellationToken); public override Task DropAllAsync(DropIndexOptions options, CancellationToken cancellationToken = default) => _collection._operationExecutor.ExecuteWriteOperationAsync( CreateDropAllOperation(options), _collection._writeOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public override Task DropAllAsync(IClientSessionHandle session, CancellationToken cancellationToken = default) - => DropAllAsync(session, null, cancellationToken: cancellationToken); + => DropAllAsync(session, null, cancellationToken); public override Task DropAllAsync(IClientSessionHandle session, DropIndexOptions options, CancellationToken cancellationToken = default) => _collection._operationExecutor.ExecuteWriteOperationAsync( CreateDropAllOperation(options), _collection._writeOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public override void DropOne(string name, CancellationToken cancellationToken = default) - => DropOne(name, null, cancellationToken: cancellationToken); + => DropOne(name, null, cancellationToken); public override void DropOne(string name, DropIndexOptions options, CancellationToken cancellationToken = default) => _collection._operationExecutor.ExecuteWriteOperation( CreateDropOneOperation(name, options), _collection._writeOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public override void DropOne(IClientSessionHandle session, string name, CancellationToken cancellationToken = default) - => DropOne(session, name, null, cancellationToken: cancellationToken); + => DropOne(session, name, null, cancellationToken); - public override void DropOne( - IClientSessionHandle session, - string name, - DropIndexOptions options, - CancellationToken cancellationToken) + public override void DropOne(IClientSessionHandle session, string name, DropIndexOptions options, CancellationToken cancellationToken) => _collection._operationExecutor.ExecuteWriteOperation( CreateDropOneOperation(name, options), _collection._writeOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public override Task DropOneAsync(string name, CancellationToken cancellationToken = default) - => DropOneAsync(name, null, cancellationToken: cancellationToken); + => DropOneAsync(name, null, cancellationToken); public override Task DropOneAsync(string name, DropIndexOptions options, CancellationToken cancellationToken = default) => _collection._operationExecutor.ExecuteWriteOperationAsync( CreateDropOneOperation(name, options), _collection._writeOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public override Task DropOneAsync(IClientSessionHandle session, string name, CancellationToken cancellationToken = default) - => DropOneAsync(session, name, null, cancellationToken: cancellationToken); + => DropOneAsync(session, name, null, cancellationToken); - public override Task DropOneAsync( - IClientSessionHandle session, - string name, - DropIndexOptions options, - CancellationToken cancellationToken) + public override Task DropOneAsync(IClientSessionHandle session, string name, DropIndexOptions options, CancellationToken cancellationToken) => _collection._operationExecutor.ExecuteWriteOperationAsync( CreateDropOneOperation(name, options), _collection._writeOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public override IAsyncCursor List(CancellationToken cancellationToken = default) - => List(options: null, cancellationToken: cancellationToken); + => List(options: null, cancellationToken); public override IAsyncCursor List(ListIndexesOptions options, CancellationToken cancellationToken = default) => _collection._operationExecutor.ExecuteReadOperation( CreateListIndexesOperation(options), _collection._readOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public override IAsyncCursor List(IClientSessionHandle session, CancellationToken cancellationToken = default) - => List(session, options: null, cancellationToken: cancellationToken); + => List(session, options: null, cancellationToken); public override IAsyncCursor List(IClientSessionHandle session, ListIndexesOptions options, CancellationToken cancellationToken = default) => _collection._operationExecutor.ExecuteReadOperation( CreateListIndexesOperation(options), _collection._readOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public override Task> ListAsync(CancellationToken cancellationToken = default) - => ListAsync(options: null, cancellationToken: cancellationToken); + => ListAsync(options: null, cancellationToken); public override Task> ListAsync(ListIndexesOptions options, CancellationToken cancellationToken = default) => _collection._operationExecutor.ExecuteReadOperationAsync( CreateListIndexesOperation(options), _collection._readOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public override Task> ListAsync(IClientSessionHandle session, CancellationToken cancellationToken = default) - => ListAsync(session, options: null, cancellationToken: cancellationToken); + => ListAsync(session, options: null, cancellationToken); public override Task> ListAsync(IClientSessionHandle session, ListIndexesOptions options, CancellationToken cancellationToken = default) => _collection._operationExecutor.ExecuteReadOperationAsync( CreateListIndexesOperation(options), _collection._readOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); // private methods @@ -1609,32 +1650,32 @@ public MongoSearchIndexManager(MongoCollectionImpl collection) public IEnumerable CreateMany(IEnumerable models, CancellationToken cancellationToken = default) { var operation = CreateCreateIndexesOperation(models); - var result = _collection._operationExecutor.ExecuteWriteOperation(operation, _collection._writeOperationOptions, session: null, cancellationToken: cancellationToken); + var result = _collection._operationExecutor.ExecuteWriteOperation(operation, _collection._writeOperationOptions, null, true, cancellationToken); return GetIndexNames(result); } public async Task> CreateManyAsync(IEnumerable models, CancellationToken cancellationToken = default) { var operation = CreateCreateIndexesOperation(models); - var result = await _collection._operationExecutor.ExecuteWriteOperationAsync(operation, _collection._writeOperationOptions, session: null, cancellationToken: cancellationToken).ConfigureAwait(false); + var result = await _collection._operationExecutor.ExecuteWriteOperationAsync(operation, _collection._writeOperationOptions, null, true, cancellationToken).ConfigureAwait(false); return GetIndexNames(result); } public string CreateOne(BsonDocument definition, string name = null, CancellationToken cancellationToken = default) => - CreateOne(new CreateSearchIndexModel(name, definition), cancellationToken: cancellationToken); + CreateOne(new CreateSearchIndexModel(name, definition), cancellationToken); public string CreateOne(CreateSearchIndexModel model, CancellationToken cancellationToken = default) { - var result = CreateMany(new[] { model }, cancellationToken: cancellationToken); + var result = CreateMany(new[] { model }, cancellationToken); return result.Single(); } public Task CreateOneAsync(BsonDocument definition, string name = null, CancellationToken cancellationToken = default) => - CreateOneAsync(new CreateSearchIndexModel(name, definition), cancellationToken: cancellationToken); + CreateOneAsync(new CreateSearchIndexModel(name, definition), cancellationToken); public async Task CreateOneAsync(CreateSearchIndexModel model, CancellationToken cancellationToken = default) { - var result = await CreateManyAsync(new[] { model }, cancellationToken: cancellationToken).ConfigureAwait(false); + var result = await CreateManyAsync(new[] { model }, cancellationToken).ConfigureAwait(false); return result.Single(); } @@ -1643,6 +1684,7 @@ public void DropOne(string indexName, CancellationToken cancellationToken = defa new DropSearchIndexOperation(_collection.CollectionNamespace, indexName, _collection._messageEncoderSettings), _collection._writeOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public Task DropOneAsync(string indexName, CancellationToken cancellationToken = default) @@ -1650,16 +1692,17 @@ public Task DropOneAsync(string indexName, CancellationToken cancellationToken = new DropSearchIndexOperation(_collection.CollectionNamespace, indexName, _collection._messageEncoderSettings), _collection._writeOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public IAsyncCursor List(string indexName, AggregateOptions aggregateOptions = null, CancellationToken cancellationToken = default) { - return _collection.WithReadConcern(ReadConcern.Default).Aggregate(CreateListIndexesStage(indexName), aggregateOptions, cancellationToken: cancellationToken); + return _collection.WithReadConcern(ReadConcern.Default).Aggregate(CreateListIndexesStage(indexName), aggregateOptions, cancellationToken); } public Task> ListAsync(string indexName, AggregateOptions aggregateOptions = null, CancellationToken cancellationToken = default) { - return _collection.WithReadConcern(ReadConcern.Default).AggregateAsync(CreateListIndexesStage(indexName), aggregateOptions, cancellationToken: cancellationToken); + return _collection.WithReadConcern(ReadConcern.Default).AggregateAsync(CreateListIndexesStage(indexName), aggregateOptions, cancellationToken); } public void Update(string indexName, BsonDocument definition, CancellationToken cancellationToken = default) @@ -1667,6 +1710,7 @@ public void Update(string indexName, BsonDocument definition, CancellationToken new UpdateSearchIndexOperation(_collection.CollectionNamespace, indexName, definition, _collection._messageEncoderSettings), _collection._writeOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public Task UpdateAsync(string indexName, BsonDocument definition, CancellationToken cancellationToken = default) @@ -1674,6 +1718,7 @@ public Task UpdateAsync(string indexName, BsonDocument definition, CancellationT new UpdateSearchIndexOperation(_collection.CollectionNamespace, indexName, definition, _collection._messageEncoderSettings), _collection._writeOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); // private methods diff --git a/src/MongoDB.Driver/MongoDatabase.cs b/src/MongoDB.Driver/MongoDatabase.cs index 877faa560d2..8480542415b 100644 --- a/src/MongoDB.Driver/MongoDatabase.cs +++ b/src/MongoDB.Driver/MongoDatabase.cs @@ -78,20 +78,20 @@ public IAsyncCursor Aggregate(IClientSessionHandle session, Pi if (isAggregateToCollection) { var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - _operationExecutor.ExecuteWriteOperation(aggregateOperation, _writeOperationOptions, session, cancellationToken: cancellationToken); + _operationExecutor.ExecuteWriteOperation(aggregateOperation, _writeOperationOptions, session, true, cancellationToken); return CreateAggregateToCollectionResultCursor(session, renderedPipeline, options); } else { var aggregateOperation = CreateAggregateOperation(renderedPipeline, options); - return _operationExecutor.ExecuteReadOperation(aggregateOperation, _readOperationOptions, session, cancellationToken: cancellationToken); + return _operationExecutor.ExecuteReadOperation(aggregateOperation, _readOperationOptions, session, true, cancellationToken); } } public async Task> AggregateAsync(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { - using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken: cancellationToken).ConfigureAwait(false); - return await AggregateAsync(session, pipeline, options, cancellationToken: cancellationToken).ConfigureAwait(false); + using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false); + return await AggregateAsync(session, pipeline, options, cancellationToken).ConfigureAwait(false); } public async Task> AggregateAsync(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) @@ -105,20 +105,20 @@ public async Task> AggregateAsync(IClientSessionH if (isAggregateToCollection) { var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - await _operationExecutor.ExecuteWriteOperationAsync(aggregateOperation, _writeOperationOptions, session, cancellationToken: cancellationToken).ConfigureAwait(false); + await _operationExecutor.ExecuteWriteOperationAsync(aggregateOperation, _writeOperationOptions, session, true, cancellationToken).ConfigureAwait(false); return CreateAggregateToCollectionResultCursor(session, renderedPipeline, options); } else { var aggregateOperation = CreateAggregateOperation(renderedPipeline, options); - return await _operationExecutor.ExecuteReadOperationAsync(aggregateOperation, _readOperationOptions, session, cancellationToken: cancellationToken).ConfigureAwait(false); + return await _operationExecutor.ExecuteReadOperationAsync(aggregateOperation, _readOperationOptions, session, true, cancellationToken).ConfigureAwait(false); } } public void AggregateToCollection(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { using var session = _operationExecutor.StartImplicitSession(cancellationToken); - AggregateToCollection(session, pipeline, options, cancellationToken: cancellationToken); + AggregateToCollection(session, pipeline, options, cancellationToken); } public void AggregateToCollection(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) @@ -135,13 +135,13 @@ public void AggregateToCollection(IClientSessionHandle session, Pipelin } var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - _operationExecutor.ExecuteWriteOperation(aggregateOperation, _writeOperationOptions, session, cancellationToken: cancellationToken); + _operationExecutor.ExecuteWriteOperation(aggregateOperation, _writeOperationOptions, session, true, cancellationToken); } public async Task AggregateToCollectionAsync(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { - using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken: cancellationToken).ConfigureAwait(false); - await AggregateToCollectionAsync(session, pipeline, options, cancellationToken: cancellationToken).ConfigureAwait(false); + using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false); + await AggregateToCollectionAsync(session, pipeline, options, cancellationToken).ConfigureAwait(false); } public async Task AggregateToCollectionAsync(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) @@ -158,13 +158,13 @@ public async Task AggregateToCollectionAsync(IClientSessionHandle sessi } var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - await _operationExecutor.ExecuteWriteOperationAsync(aggregateOperation, _writeOperationOptions, session, cancellationToken: cancellationToken).ConfigureAwait(false); + await _operationExecutor.ExecuteWriteOperationAsync(aggregateOperation, _writeOperationOptions, session, true, cancellationToken).ConfigureAwait(false); } public void CreateCollection(string name, CreateCollectionOptions options, CancellationToken cancellationToken) { using var session = _operationExecutor.StartImplicitSession(cancellationToken); - CreateCollection(session, name, options, cancellationToken: cancellationToken); + CreateCollection(session, name, options, cancellationToken); } public void CreateCollection(IClientSessionHandle session, string name, CreateCollectionOptions options, CancellationToken cancellationToken) @@ -174,14 +174,14 @@ public void CreateCollection(IClientSessionHandle session, string name, CreateCo if (options == null) { - CreateCollectionHelper(session, name, null, cancellationToken: cancellationToken); + CreateCollectionHelper(session, name, null, cancellationToken); return; } if (options.GetType() == typeof(CreateCollectionOptions)) { var genericOptions = CreateCollectionOptions.CoercedFrom(options); - CreateCollectionHelper(session, name, genericOptions, cancellationToken: cancellationToken); + CreateCollectionHelper(session, name, genericOptions, cancellationToken); return; } @@ -200,8 +200,8 @@ public void CreateCollection(IClientSessionHandle session, string name, CreateCo public async Task CreateCollectionAsync(string name, CreateCollectionOptions options, CancellationToken cancellationToken) { - using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken: cancellationToken).ConfigureAwait(false); - await CreateCollectionAsync(session, name, options, cancellationToken: cancellationToken).ConfigureAwait(false); + using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false); + await CreateCollectionAsync(session, name, options, cancellationToken).ConfigureAwait(false); } public async Task CreateCollectionAsync(IClientSessionHandle session, string name, CreateCollectionOptions options, CancellationToken cancellationToken) @@ -211,14 +211,14 @@ public async Task CreateCollectionAsync(IClientSessionHandle session, string nam if (options == null) { - await CreateCollectionHelperAsync(session, name, null, cancellationToken: cancellationToken).ConfigureAwait(false); + await CreateCollectionHelperAsync(session, name, null, cancellationToken).ConfigureAwait(false); return; } if (options.GetType() == typeof(CreateCollectionOptions)) { var genericOptions = CreateCollectionOptions.CoercedFrom(options); - await CreateCollectionHelperAsync(session, name, genericOptions, cancellationToken: cancellationToken).ConfigureAwait(false); + await CreateCollectionHelperAsync(session, name, genericOptions, cancellationToken).ConfigureAwait(false); return; } @@ -240,6 +240,7 @@ public void CreateView(string viewName, string viewOn, Pipel CreateCreateViewOperation(viewName, viewOn, pipeline, options), _writeOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public void CreateView(IClientSessionHandle session, string viewName, string viewOn, PipelineDefinition pipeline, CreateViewOptions options = null, CancellationToken cancellationToken = default) @@ -247,6 +248,7 @@ public void CreateView(IClientSessionHandle session, string CreateCreateViewOperation(viewName, viewOn, pipeline, options), _writeOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public Task CreateViewAsync(string viewName, string viewOn, PipelineDefinition pipeline, CreateViewOptions options = null, CancellationToken cancellationToken = default) @@ -254,6 +256,7 @@ public Task CreateViewAsync(string viewName, string viewOn, CreateCreateViewOperation(viewName, viewOn, pipeline, options), _writeOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public Task CreateViewAsync(IClientSessionHandle session, string viewName, string viewOn, PipelineDefinition pipeline, CreateViewOptions options = null, CancellationToken cancellationToken = default) @@ -261,22 +264,23 @@ public Task CreateViewAsync(IClientSessionHandle session, st CreateCreateViewOperation(viewName, viewOn, pipeline, options), _writeOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public void DropCollection(string name, CancellationToken cancellationToken) { - DropCollection(name, options: null, cancellationToken: cancellationToken); + DropCollection(name, options: null, cancellationToken); } public void DropCollection(string name, DropCollectionOptions options, CancellationToken cancellationToken = default) { using var session = _operationExecutor.StartImplicitSession(cancellationToken); - DropCollection(session, name, options, cancellationToken: cancellationToken); + DropCollection(session, name, options, cancellationToken); } public void DropCollection(IClientSessionHandle session, string name, CancellationToken cancellationToken) { - DropCollection(session, name, options: null, cancellationToken: cancellationToken); + DropCollection(session, name, options: null, cancellationToken); } public void DropCollection(IClientSessionHandle session, string name, DropCollectionOptions options, CancellationToken cancellationToken) @@ -285,25 +289,25 @@ public void DropCollection(IClientSessionHandle session, string name, DropCollec Ensure.IsNotNullOrEmpty(name, nameof(name)); var collectionNamespace = new CollectionNamespace(_databaseNamespace, name); - var encryptedFields = GetEncryptedFields(session, collectionNamespace, options, cancellationToken: cancellationToken); + var encryptedFields = GetEncryptedFields(session, collectionNamespace, options, cancellationToken); var operation = CreateDropCollectionOperation(collectionNamespace, encryptedFields); - _operationExecutor.ExecuteWriteOperation(operation, _writeOperationOptions, session, cancellationToken: cancellationToken); + _operationExecutor.ExecuteWriteOperation(operation, _writeOperationOptions, session, true, cancellationToken); } public Task DropCollectionAsync(string name, CancellationToken cancellationToken) { - return DropCollectionAsync(name, options: null, cancellationToken: cancellationToken); + return DropCollectionAsync(name, options: null, cancellationToken); } public async Task DropCollectionAsync(string name, DropCollectionOptions options, CancellationToken cancellationToken) { - using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken: cancellationToken).ConfigureAwait(false); - await DropCollectionAsync(session, name, options, cancellationToken: cancellationToken).ConfigureAwait(false); + using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false); + await DropCollectionAsync(session, name, options, cancellationToken).ConfigureAwait(false); } public Task DropCollectionAsync(IClientSessionHandle session, string name, CancellationToken cancellationToken) { - return DropCollectionAsync(session, name, options: null, cancellationToken: cancellationToken); + return DropCollectionAsync(session, name, options: null, cancellationToken); } public async Task DropCollectionAsync(IClientSessionHandle session, string name, DropCollectionOptions options, CancellationToken cancellationToken) @@ -312,9 +316,9 @@ public async Task DropCollectionAsync(IClientSessionHandle session, string name, Ensure.IsNotNullOrEmpty(name, nameof(name)); var collectionNamespace = new CollectionNamespace(_databaseNamespace, name); - var encryptedFields = await GetEncryptedFieldsAsync(session, collectionNamespace, options, cancellationToken: cancellationToken).ConfigureAwait(false); + var encryptedFields = await GetEncryptedFieldsAsync(session, collectionNamespace, options, cancellationToken).ConfigureAwait(false); var operation = CreateDropCollectionOperation(collectionNamespace, encryptedFields); - await _operationExecutor.ExecuteWriteOperationAsync(operation, _writeOperationOptions, session, cancellationToken: cancellationToken).ConfigureAwait(false); + await _operationExecutor.ExecuteWriteOperationAsync(operation, _writeOperationOptions, session, true, cancellationToken).ConfigureAwait(false); } public IMongoCollection GetCollection(string name, MongoCollectionSettings settings) @@ -336,6 +340,7 @@ public IAsyncCursor ListCollectionNames(ListCollectionNamesOptions optio CreateListCollectionNamesOperation(options), _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, null, + allowChannelPinning: true, cancellationToken: cancellationToken); return new BatchTransformingAsyncCursor(cursor, ExtractCollectionNames); } @@ -346,6 +351,7 @@ public IAsyncCursor ListCollectionNames(IClientSessionHandle session, Li CreateListCollectionNamesOperation(options), _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); return new BatchTransformingAsyncCursor(cursor, ExtractCollectionNames); } @@ -356,6 +362,7 @@ public async Task> ListCollectionNamesAsync(ListCollectionN CreateListCollectionNamesOperation(options), _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken).ConfigureAwait(false); return new BatchTransformingAsyncCursor(cursor, ExtractCollectionNames); } @@ -366,6 +373,7 @@ public async Task> ListCollectionNamesAsync(IClientSessionH CreateListCollectionNamesOperation(options), _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken).ConfigureAwait(false); return new BatchTransformingAsyncCursor(cursor, ExtractCollectionNames); } @@ -375,6 +383,7 @@ public IAsyncCursor ListCollections(ListCollectionsOptions options CreateListCollectionsOperation(options), _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public IAsyncCursor ListCollections(IClientSessionHandle session, ListCollectionsOptions options, CancellationToken cancellationToken) @@ -382,6 +391,7 @@ public IAsyncCursor ListCollections(IClientSessionHandle session, CreateListCollectionsOperation(options), _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public Task> ListCollectionsAsync(ListCollectionsOptions options, CancellationToken cancellationToken) @@ -389,6 +399,7 @@ public Task> ListCollectionsAsync(ListCollectionsOpti CreateListCollectionsOperation(options), _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public Task> ListCollectionsAsync(IClientSessionHandle session, ListCollectionsOptions options, CancellationToken cancellationToken) @@ -396,6 +407,7 @@ public Task> ListCollectionsAsync(IClientSessionHandl CreateListCollectionsOperation(options), _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public void RenameCollection(string oldName, string newName, RenameCollectionOptions options, CancellationToken cancellationToken) @@ -403,6 +415,7 @@ public void RenameCollection(string oldName, string newName, RenameCollectionOpt CreateRenameCollectionOperation(oldName, newName, options), _writeOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public void RenameCollection(IClientSessionHandle session, string oldName, string newName, RenameCollectionOptions options, CancellationToken cancellationToken) @@ -410,6 +423,7 @@ public void RenameCollection(IClientSessionHandle session, string oldName, strin CreateRenameCollectionOperation(oldName, newName, options), _writeOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public Task RenameCollectionAsync(string oldName, string newName, RenameCollectionOptions options, CancellationToken cancellationToken) @@ -417,6 +431,7 @@ public Task RenameCollectionAsync(string oldName, string newName, RenameCollecti CreateRenameCollectionOperation(oldName, newName, options), _writeOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public Task RenameCollectionAsync(IClientSessionHandle session, string oldName, string newName, RenameCollectionOptions options, CancellationToken cancellationToken) @@ -424,6 +439,7 @@ public Task RenameCollectionAsync(IClientSessionHandle session, string oldName, CreateRenameCollectionOperation(oldName, newName, options), _writeOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public TResult RunCommand(Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default) @@ -431,6 +447,7 @@ public TResult RunCommand(Command command, ReadPreference read CreateRunCommandOperation(command), _readOperationOptions with { ExplicitReadPreference = readPreference, DefaultReadPreference = ReadPreference.Primary}, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public TResult RunCommand(IClientSessionHandle session, Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default) @@ -438,6 +455,7 @@ public TResult RunCommand(IClientSessionHandle session, Command RunCommandAsync(Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default) @@ -445,6 +463,7 @@ public Task RunCommandAsync(Command command, ReadPref CreateRunCommandOperation(command), _readOperationOptions with { ExplicitReadPreference = readPreference, DefaultReadPreference = ReadPreference.Primary}, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public Task RunCommandAsync(IClientSessionHandle session, Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default) @@ -452,6 +471,7 @@ public Task RunCommandAsync(IClientSessionHandle session, Comm CreateRunCommandOperation(command), _readOperationOptions with { ExplicitReadPreference = readPreference, DefaultReadPreference = ReadPreference.Primary}, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public IChangeStreamCursor Watch( @@ -462,6 +482,7 @@ public IChangeStreamCursor Watch( CreateChangeStreamOperation(pipeline, options), _readOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public IChangeStreamCursor Watch( @@ -473,6 +494,7 @@ public IChangeStreamCursor Watch( CreateChangeStreamOperation(pipeline, options), _readOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public Task> WatchAsync( @@ -483,6 +505,7 @@ public Task> WatchAsync( CreateChangeStreamOperation(pipeline, options), _readOperationOptions, session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public Task> WatchAsync( @@ -494,6 +517,7 @@ public Task> WatchAsync( CreateChangeStreamOperation(pipeline, options), _readOperationOptions, Ensure.IsNotNull(session, nameof(session)), + allowChannelPinning: true, cancellationToken: cancellationToken); public IMongoDatabase WithReadConcern(ReadConcern readConcern) @@ -571,8 +595,8 @@ private IAsyncCursor CreateAggregateToCollectionResultCursor(I var readOperationOptions = _readOperationOptions with { ExplicitReadPreference = ReadPreference.Primary }; var deferredCursor = new DeferredAsyncCursor( () => forkedSession.Dispose(), - ct => _operationExecutor.ExecuteReadOperation(findOperation, readOperationOptions, forkedSession, cancellationToken: ct), - ct => _operationExecutor.ExecuteReadOperationAsync(findOperation, readOperationOptions, forkedSession, cancellationToken: ct)); + ct => _operationExecutor.ExecuteReadOperation(findOperation, readOperationOptions, forkedSession, false, cancellationToken: ct), + ct => _operationExecutor.ExecuteReadOperationAsync(findOperation, readOperationOptions, forkedSession, false, cancellationToken: ct)); return deferredCursor; } @@ -598,14 +622,20 @@ private AggregateToCollectionOperation CreateAggregateToCollectionOperation(IClientSessionHandle session, string name, CreateCollectionOptions options, CancellationToken cancellationToken) - => _operationExecutor.ExecuteWriteOperation(CreateCreateCollectionOperation(name, options), + => _operationExecutor.ExecuteWriteOperation( + CreateCreateCollectionOperation(name, options), _writeOperationOptions, - session, cancellationToken: cancellationToken); + session, + allowChannelPinning: true, + cancellationToken); private Task CreateCollectionHelperAsync(IClientSessionHandle session, string name, CreateCollectionOptions options, CancellationToken cancellationToken) - => _operationExecutor.ExecuteWriteOperationAsync(CreateCreateCollectionOperation(name, options), + => _operationExecutor.ExecuteWriteOperationAsync( + CreateCreateCollectionOperation(name, options), _writeOperationOptions, - session, cancellationToken: cancellationToken); + session, + allowChannelPinning: true, + cancellationToken); private IWriteOperation CreateCreateCollectionOperation(string name, CreateCollectionOptions options) { diff --git a/src/MongoDB.Driver/OperationExecutor.cs b/src/MongoDB.Driver/OperationExecutor.cs index ffb49457705..cf0a6b32a0f 100644 --- a/src/MongoDB.Driver/OperationExecutor.cs +++ b/src/MongoDB.Driver/OperationExecutor.cs @@ -37,12 +37,11 @@ public void Dispose() _isDisposed = true; } - public TResult ExecuteReadOperation( - IReadOperation operation, + public TResult ExecuteReadOperation(IReadOperation operation, ReadOperationOptions options, IClientSessionHandle session, - bool disableChannelPinning = false, - CancellationToken cancellationToken = default) + bool allowChannelPinning, + CancellationToken cancellationToken) { ThrowIfDisposed(); var isOwnSession = session == null; @@ -51,7 +50,7 @@ public TResult ExecuteReadOperation( try { var readPreference = options.GetEffectiveReadPreference(session); - using var binding = CreateReadBinding(session, readPreference, disableChannelPinning); + using var binding = CreateReadBinding(session, readPreference, allowChannelPinning); return operation.Execute(binding, cancellationToken); } finally @@ -63,12 +62,11 @@ public TResult ExecuteReadOperation( } } - public async Task ExecuteReadOperationAsync( - IReadOperation operation, + public async Task ExecuteReadOperationAsync(IReadOperation operation, ReadOperationOptions options, IClientSessionHandle session, - bool disableChannelPinning = false, - CancellationToken cancellationToken = default) + bool allowChannelPinning, + CancellationToken cancellationToken) { ThrowIfDisposed(); var isOwnSession = session == null; @@ -77,7 +75,7 @@ public async Task ExecuteReadOperationAsync( try { var readPreference = options.GetEffectiveReadPreference(session); - using var binding = CreateReadBinding(session, readPreference, disableChannelPinning); + using var binding = CreateReadBinding(session, readPreference, allowChannelPinning); return await operation.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false); } finally @@ -89,12 +87,11 @@ public async Task ExecuteReadOperationAsync( } } - public TResult ExecuteWriteOperation( - IWriteOperation operation, + public TResult ExecuteWriteOperation(IWriteOperation operation, WriteOperationOptions options, IClientSessionHandle session, - bool disableChannelPinning = false, - CancellationToken cancellationToken = default) + bool allowChannelPinning, + CancellationToken cancellationToken) { ThrowIfDisposed(); var isOwnSession = session == null; @@ -102,7 +99,7 @@ public TResult ExecuteWriteOperation( try { - using var binding = CreateReadWriteBinding(session, disableChannelPinning); + using var binding = CreateReadWriteBinding(session, allowChannelPinning); return operation.Execute(binding, cancellationToken); } finally @@ -114,12 +111,11 @@ public TResult ExecuteWriteOperation( } } - public async Task ExecuteWriteOperationAsync( - IWriteOperation operation, + public async Task ExecuteWriteOperationAsync(IWriteOperation operation, WriteOperationOptions options, IClientSessionHandle session, - bool disableChannelPinning = false, - CancellationToken cancellationToken = default) + bool allowChannelPinning, + CancellationToken cancellationToken) { ThrowIfDisposed(); var isOwnSession = session == null; @@ -127,7 +123,7 @@ public async Task ExecuteWriteOperationAsync( try { - using var binding = CreateReadWriteBinding(session, disableChannelPinning); + using var binding = CreateReadWriteBinding(session, allowChannelPinning); return await operation.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false); } finally @@ -151,20 +147,20 @@ public Task StartImplicitSessionAsync(CancellationToken ca return Task.FromResult(StartImplicitSession()); } - private IReadBindingHandle CreateReadBinding(IClientSessionHandle session, ReadPreference readPreference, bool disableChannelPinning) + private IReadBindingHandle CreateReadBinding(IClientSessionHandle session, ReadPreference readPreference, bool allowChannelPinning) { if (session.IsInTransaction && readPreference.ReadPreferenceMode != ReadPreferenceMode.Primary) { throw new InvalidOperationException("Read preference in a transaction must be primary."); } - if (disableChannelPinning) + if (allowChannelPinning) { - var binding = new ReadPreferenceBinding(_client.GetClusterInternal(), readPreference, session.WrappedCoreSession.Fork()); - return new ReadBindingHandle(binding); + return ChannelPinningHelper.CreateReadBinding(_client.GetClusterInternal(), session.WrappedCoreSession.Fork(), readPreference); } - return ChannelPinningHelper.CreateReadBinding(_client.GetClusterInternal(), session.WrappedCoreSession.Fork(), readPreference); + var binding = new ReadPreferenceBinding(_client.GetClusterInternal(), readPreference, session.WrappedCoreSession.Fork()); + return new ReadBindingHandle(binding); } private IReadWriteBindingHandle CreateReadWriteBinding(IClientSessionHandle session, bool disableChannelPinning) diff --git a/tests/MongoDB.Driver.Tests/MockOperationExecutor.cs b/tests/MongoDB.Driver.Tests/MockOperationExecutor.cs index f719d472c3e..116310455b1 100644 --- a/tests/MongoDB.Driver.Tests/MockOperationExecutor.cs +++ b/tests/MongoDB.Driver.Tests/MockOperationExecutor.cs @@ -62,12 +62,11 @@ public void EnqueueException(Exception exception) _results.Enqueue(exception); } - public TResult ExecuteReadOperation( - IReadOperation operation, + public TResult ExecuteReadOperation(IReadOperation operation, ReadOperationOptions readOperationOptions, IClientSessionHandle session, - bool disableChannelPinning = false, - CancellationToken cancellationToken = default) + bool allowChannelPinning, + CancellationToken cancellationToken) { _calls.Enqueue(new ReadCall { @@ -94,16 +93,15 @@ public TResult ExecuteReadOperation( return default(TResult); } - public Task ExecuteReadOperationAsync( - IReadOperation operation, + public Task ExecuteReadOperationAsync(IReadOperation operation, ReadOperationOptions readOperationOptions, IClientSessionHandle session, - bool disableChannelPinning = false, - CancellationToken cancellationToken = default) + bool allowChannelPinning, + CancellationToken cancellationToken) { try { - var result = ExecuteReadOperation(operation, readOperationOptions, session, disableChannelPinning, cancellationToken); + var result = ExecuteReadOperation(operation, readOperationOptions, session, allowChannelPinning, cancellationToken); return Task.FromResult(result); } catch (Exception ex) @@ -114,12 +112,11 @@ public Task ExecuteReadOperationAsync( } } - public TResult ExecuteWriteOperation( - IWriteOperation operation, + public TResult ExecuteWriteOperation(IWriteOperation operation, WriteOperationOptions writeOperationOptions, IClientSessionHandle session, - bool disableChannelPinning = false, - CancellationToken cancellationToken = default) + bool allowChannelPinning, + CancellationToken cancellationToken) { _calls.Enqueue(new WriteCall { @@ -146,16 +143,15 @@ public TResult ExecuteWriteOperation( return default(TResult); } - public Task ExecuteWriteOperationAsync( - IWriteOperation operation, + public Task ExecuteWriteOperationAsync(IWriteOperation operation, WriteOperationOptions writeOperationOptions, IClientSessionHandle session, - bool disableChannelPinning = false, - CancellationToken cancellationToken = default) + bool allowChannelPinning, + CancellationToken cancellationToken) { try { - var result = ExecuteWriteOperation(operation, writeOperationOptions, session, disableChannelPinning, cancellationToken); + var result = ExecuteWriteOperation(operation, writeOperationOptions, session, allowChannelPinning, cancellationToken); return Task.FromResult(result); } catch (Exception ex) diff --git a/tests/MongoDB.Driver.Tests/OperationExecutorTests.cs b/tests/MongoDB.Driver.Tests/OperationExecutorTests.cs index 37f911f2b36..e3cd85cde01 100644 --- a/tests/MongoDB.Driver.Tests/OperationExecutorTests.cs +++ b/tests/MongoDB.Driver.Tests/OperationExecutorTests.cs @@ -53,8 +53,8 @@ public async Task ExecuteReadOperation_should_start_and_dispose_implicit_session var readOperationOptions = new ReadOperationOptions(); _ = isAsync ? - await subject.ExecuteReadOperationAsync(readOperation, readOperationOptions, session, cancellationToken: CancellationToken.None) : - subject.ExecuteReadOperation(readOperation, readOperationOptions, session, cancellationToken: CancellationToken.None); + await subject.ExecuteReadOperationAsync(readOperation, readOperationOptions, session, false, cancellationToken: CancellationToken.None) : + subject.ExecuteReadOperation(readOperation, readOperationOptions, session, false, cancellationToken: CancellationToken.None); var times = shouldCreateSession ? Times.Once() : Times.Never(); clusterMock.Verify(c => c.StartSession(It.Is(v => v.IsImplicit && v.IsCausallyConsistent == false && v.IsSnapshot == false)), times); @@ -70,8 +70,8 @@ public async Task ExecuteWriteOperation_should_start_and_dispose_implicit_sessio var writeOperationOptions = new WriteOperationOptions(); _ = isAsync ? - await subject.ExecuteWriteOperationAsync(writeOperation, writeOperationOptions, session, cancellationToken: CancellationToken.None) : - subject.ExecuteWriteOperation(writeOperation, writeOperationOptions, session, cancellationToken: CancellationToken.None); + await subject.ExecuteWriteOperationAsync(writeOperation, writeOperationOptions, session, false, cancellationToken: CancellationToken.None) : + subject.ExecuteWriteOperation(writeOperation, writeOperationOptions, session, false, cancellationToken: CancellationToken.None); var times = shouldCreateSession ? Times.Once() : Times.Never(); clusterMock.Verify(c => c.StartSession(It.Is(v => v.IsImplicit && v.IsCausallyConsistent == false && v.IsSnapshot == false)), times); From 5528ceffb533894c5ff5a55aa39f0afefcf5dca3 Mon Sep 17 00:00:00 2001 From: Oleksandr Poliakov Date: Mon, 2 Jun 2025 18:43:15 -0700 Subject: [PATCH 05/14] pr --- src/MongoDB.Driver/MongoCollectionImpl.cs | 3 ++- src/MongoDB.Driver/MongoDatabase.cs | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/MongoDB.Driver/MongoCollectionImpl.cs b/src/MongoDB.Driver/MongoCollectionImpl.cs index d5684cd38dd..5802a02b47b 100644 --- a/src/MongoDB.Driver/MongoCollectionImpl.cs +++ b/src/MongoDB.Driver/MongoCollectionImpl.cs @@ -378,7 +378,8 @@ public override long EstimatedDocumentCount(EstimatedDocumentCountOptions option => _operationExecutor.ExecuteReadOperation( CreateEstimatedDocumentCountOperation(options), _readOperationOptions, - session: null, allowChannelPinning: true, + session: null, + allowChannelPinning: true, cancellationToken: cancellationToken); public override Task EstimatedDocumentCountAsync(EstimatedDocumentCountOptions options, CancellationToken cancellationToken = default) diff --git a/src/MongoDB.Driver/MongoDatabase.cs b/src/MongoDB.Driver/MongoDatabase.cs index 8480542415b..2e1ee1fc080 100644 --- a/src/MongoDB.Driver/MongoDatabase.cs +++ b/src/MongoDB.Driver/MongoDatabase.cs @@ -595,8 +595,8 @@ private IAsyncCursor CreateAggregateToCollectionResultCursor(I var readOperationOptions = _readOperationOptions with { ExplicitReadPreference = ReadPreference.Primary }; var deferredCursor = new DeferredAsyncCursor( () => forkedSession.Dispose(), - ct => _operationExecutor.ExecuteReadOperation(findOperation, readOperationOptions, forkedSession, false, cancellationToken: ct), - ct => _operationExecutor.ExecuteReadOperationAsync(findOperation, readOperationOptions, forkedSession, false, cancellationToken: ct)); + ct => _operationExecutor.ExecuteReadOperation(findOperation, readOperationOptions, forkedSession, true, cancellationToken: ct), + ct => _operationExecutor.ExecuteReadOperationAsync(findOperation, readOperationOptions, forkedSession, true, cancellationToken: ct)); return deferredCursor; } From 085b0b7f351006338f11ffc8779cf76e09491709 Mon Sep 17 00:00:00 2001 From: Oleksandr Poliakov Date: Tue, 3 Jun 2025 09:05:12 -0700 Subject: [PATCH 06/14] Fix build --- tests/MongoDB.Driver.Tests/MongoClientTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/MongoDB.Driver.Tests/MongoClientTests.cs b/tests/MongoDB.Driver.Tests/MongoClientTests.cs index 111c62ffd56..026f5b83cd4 100644 --- a/tests/MongoDB.Driver.Tests/MongoClientTests.cs +++ b/tests/MongoDB.Driver.Tests/MongoClientTests.cs @@ -129,7 +129,7 @@ public void DropDatabase_should_invoke_the_correct_operation( { var operationExecutor = new MockOperationExecutor(); var writeConcern = new WriteConcern(1); - var subject = new MongoClient(_ => operationExecutor, DriverTestConfiguration.GetClientSettings()).WithWriteConcern(writeConcern); + var subject = new MongoClient(DriverTestConfiguration.GetClientSettings(), _ => operationExecutor).WithWriteConcern(writeConcern); var session = CreateClientSession(); using var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; @@ -180,7 +180,7 @@ public void ListDatabaseNames_should_invoke_the_correct_operation( [Values(false, true)] bool async) { var operationExecutor = new MockOperationExecutor(); - var subject = new MongoClient(_ => operationExecutor, DriverTestConfiguration.GetClientSettings()); + var subject = new MongoClient(DriverTestConfiguration.GetClientSettings(), _ => operationExecutor); var session = CreateClientSession(); using var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; @@ -274,7 +274,7 @@ public void ListDatabases_should_invoke_the_correct_operation( [Values(false, true)] bool async) { var operationExecutor = new MockOperationExecutor(); - var subject = new MongoClient(_ => operationExecutor, DriverTestConfiguration.GetClientSettings()); + var subject = new MongoClient(DriverTestConfiguration.GetClientSettings(), _ => operationExecutor); var session = CreateClientSession(); using var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; @@ -334,7 +334,7 @@ public void Watch_should_invoke_the_correct_operation( { var operationExecutor = new MockOperationExecutor(); var clientSettings = DriverTestConfiguration.GetClientSettings(); - var subject = new MongoClient(_ => operationExecutor, clientSettings); + var subject = new MongoClient(clientSettings, _ => operationExecutor); var session = usingSession ? CreateClientSession() : null; var pipeline = new EmptyPipelineDefinition>().Limit(1); var options = new ChangeStreamOptions From f88dc488dfd074232965e6c14e1fd61024c60b6f Mon Sep 17 00:00:00 2001 From: Oleksandr Poliakov Date: Wed, 4 Jun 2025 08:55:34 -0700 Subject: [PATCH 07/14] PR --- src/MongoDB.Driver/IOperationExecutor.cs | 4 +- src/MongoDB.Driver/MongoClient.cs | 110 +++--- src/MongoDB.Driver/MongoCollectionImpl.cs | 368 ++++++++---------- src/MongoDB.Driver/MongoDatabase.cs | 152 +++----- src/MongoDB.Driver/OperationExecutor.cs | 112 ++---- .../MockOperationExecutor.cs | 7 +- .../OperationExecutorTests.cs | 135 ++++--- 7 files changed, 385 insertions(+), 503 deletions(-) diff --git a/src/MongoDB.Driver/IOperationExecutor.cs b/src/MongoDB.Driver/IOperationExecutor.cs index b2086e24c78..66f5eba5406 100644 --- a/src/MongoDB.Driver/IOperationExecutor.cs +++ b/src/MongoDB.Driver/IOperationExecutor.cs @@ -46,8 +46,6 @@ Task ExecuteWriteOperationAsync(IWriteOperation opera bool allowChannelPinning, CancellationToken cancellationToken); - IClientSessionHandle StartImplicitSession(CancellationToken cancellationToken); - - Task StartImplicitSessionAsync(CancellationToken cancellationToken); + IClientSessionHandle StartImplicitSession(); } } diff --git a/src/MongoDB.Driver/MongoClient.cs b/src/MongoDB.Driver/MongoClient.cs index 76af45ea2bb..74b98d6b444 100644 --- a/src/MongoDB.Driver/MongoClient.cs +++ b/src/MongoDB.Driver/MongoClient.cs @@ -136,12 +136,10 @@ internal void ConfigureAutoEncryptionMessageEncoderSettings(MessageEncoderSettin // public methods /// public ClientBulkWriteResult BulkWrite(IReadOnlyList models, ClientBulkWriteOptions options = null, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteWriteOperation( - CreateClientBulkWriteOperation(models, options), - _writeOperationOptions, - session: null, - allowChannelPinning: false, - cancellationToken: cancellationToken); + { + using var session = _operationExecutor.StartImplicitSession(); + return BulkWrite(session, models, options, cancellationToken); + } /// public ClientBulkWriteResult BulkWrite(IClientSessionHandle session, IReadOnlyList models, ClientBulkWriteOptions options = null, CancellationToken cancellationToken = default) @@ -153,13 +151,11 @@ public ClientBulkWriteResult BulkWrite(IClientSessionHandle session, IReadOnlyLi cancellationToken: cancellationToken); /// - public Task BulkWriteAsync(IReadOnlyList models, ClientBulkWriteOptions options = null, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteWriteOperationAsync( - CreateClientBulkWriteOperation(models, options), - _writeOperationOptions, - session: null, - allowChannelPinning: false, - cancellationToken: cancellationToken); + public async Task BulkWriteAsync(IReadOnlyList models, ClientBulkWriteOptions options = null, CancellationToken cancellationToken = default) + { + using var session = _operationExecutor.StartImplicitSession(); + return await BulkWriteAsync(session, models, options, cancellationToken).ConfigureAwait(false); + } /// public Task BulkWriteAsync(IClientSessionHandle session, IReadOnlyList models, ClientBulkWriteOptions options = null, CancellationToken cancellationToken = default) @@ -202,12 +198,10 @@ public void Dispose(bool disposing) /// public void DropDatabase(string name, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteWriteOperation( - CreateDropDatabaseOperation(name), - _writeOperationOptions, - session: null, - allowChannelPinning: false, - cancellationToken: cancellationToken); + { + using var session = _operationExecutor.StartImplicitSession(); + DropDatabase(session, name, cancellationToken); + } /// public void DropDatabase(IClientSessionHandle session, string name, CancellationToken cancellationToken = default) @@ -219,13 +213,11 @@ public void DropDatabase(IClientSessionHandle session, string name, Cancellation cancellationToken: cancellationToken); /// - public Task DropDatabaseAsync(string name, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteWriteOperationAsync( - CreateDropDatabaseOperation(name), - _writeOperationOptions, - session: null, - allowChannelPinning: false, - cancellationToken: cancellationToken); + public async Task DropDatabaseAsync(string name, CancellationToken cancellationToken = default) + { + using var session = _operationExecutor.StartImplicitSession(); + await DropDatabaseAsync(session, name, cancellationToken).ConfigureAwait(false); + } /// public Task DropDatabaseAsync(IClientSessionHandle session, string name, CancellationToken cancellationToken = default) @@ -314,23 +306,19 @@ public async Task> ListDatabaseNamesAsync( /// public IAsyncCursor ListDatabases(CancellationToken cancellationToken) - => _operationExecutor.ExecuteReadOperation( - CreateListDatabaseOperation(null), - _readOperationOptions, - session: null, - allowChannelPinning: false, - cancellationToken: cancellationToken); + { + using var session = _operationExecutor.StartImplicitSession(); + return ListDatabases(session, cancellationToken); + } /// public IAsyncCursor ListDatabases( ListDatabasesOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperation( - CreateListDatabaseOperation(options), - _readOperationOptions, - session: null, - allowChannelPinning: false, - cancellationToken: cancellationToken); + { + using var session = _operationExecutor.StartImplicitSession(); + return ListDatabases(session, options, cancellationToken); + } /// public IAsyncCursor ListDatabases( @@ -356,24 +344,20 @@ public IAsyncCursor ListDatabases( cancellationToken: cancellationToken); /// - public Task> ListDatabasesAsync(CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperationAsync( - CreateListDatabaseOperation(null), - _readOperationOptions, - session: null, - allowChannelPinning: false, - cancellationToken: cancellationToken); + public async Task> ListDatabasesAsync(CancellationToken cancellationToken = default) + { + using var session = _operationExecutor.StartImplicitSession(); + return await ListDatabasesAsync(session, cancellationToken).ConfigureAwait(false); + } /// - public Task> ListDatabasesAsync( + public async Task> ListDatabasesAsync( ListDatabasesOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperationAsync( - CreateListDatabaseOperation(options), - _readOperationOptions, - session: null, - allowChannelPinning: false, - cancellationToken: cancellationToken); + { + using var session = _operationExecutor.StartImplicitSession(); + return await ListDatabasesAsync(session, options, cancellationToken).ConfigureAwait(false); + } /// public Task> ListDatabasesAsync( @@ -419,12 +403,10 @@ public IChangeStreamCursor Watch( PipelineDefinition, TResult> pipeline, ChangeStreamOptions options = null, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperation( - CreateChangeStreamOperation(pipeline, options), - _readOperationOptions, - session: null, - allowChannelPinning: false, - cancellationToken: cancellationToken); + { + using var session = _operationExecutor.StartImplicitSession(); + return Watch(session, pipeline, options, cancellationToken); + } /// public IChangeStreamCursor Watch( @@ -440,16 +422,14 @@ public IChangeStreamCursor Watch( cancellationToken: cancellationToken); /// - public Task> WatchAsync( + public async Task> WatchAsync( PipelineDefinition, TResult> pipeline, ChangeStreamOptions options = null, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperationAsync( - CreateChangeStreamOperation(pipeline, options), - _readOperationOptions, - session: null, - allowChannelPinning: false, - cancellationToken: cancellationToken); + { + using var session = _operationExecutor.StartImplicitSession(); + return await WatchAsync(session, pipeline, options, cancellationToken).ConfigureAwait(false); + } /// public Task> WatchAsync( diff --git a/src/MongoDB.Driver/MongoCollectionImpl.cs b/src/MongoDB.Driver/MongoCollectionImpl.cs index 5802a02b47b..4b7fb6de65e 100644 --- a/src/MongoDB.Driver/MongoCollectionImpl.cs +++ b/src/MongoDB.Driver/MongoCollectionImpl.cs @@ -98,7 +98,7 @@ public override MongoCollectionSettings Settings // public methods public override IAsyncCursor Aggregate(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { - using var session = _operationExecutor.StartImplicitSession(cancellationToken: cancellationToken); + using var session = _operationExecutor.StartImplicitSession(); return Aggregate(session, pipeline, options, cancellationToken: cancellationToken); } @@ -125,7 +125,7 @@ public override IAsyncCursor Aggregate(IClientSessionHandle se public override async Task> AggregateAsync(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { - using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false); + using var session = _operationExecutor.StartImplicitSession(); return await AggregateAsync(session, pipeline, options, cancellationToken).ConfigureAwait(false); } @@ -152,7 +152,7 @@ public override async Task> AggregateAsync(IClien public override void AggregateToCollection(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { - using var session = _operationExecutor.StartImplicitSession(cancellationToken); + using var session = _operationExecutor.StartImplicitSession(); AggregateToCollection(session, pipeline, options, cancellationToken); } @@ -175,7 +175,7 @@ public override void AggregateToCollection(IClientSessionHandle session public override async Task AggregateToCollectionAsync(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { - using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false); + using var session = _operationExecutor.StartImplicitSession(); await AggregateToCollectionAsync(session, pipeline, options, cancellationToken).ConfigureAwait(false); } @@ -198,7 +198,7 @@ public override async Task AggregateToCollectionAsync(IClientSessionHan public override BulkWriteResult BulkWrite(IEnumerable> requests, BulkWriteOptions options, CancellationToken cancellationToken = default) { - using var session = _operationExecutor.StartImplicitSession(cancellationToken: cancellationToken); + using var session = _operationExecutor.StartImplicitSession(); return BulkWrite(session, requests, options, cancellationToken); } @@ -221,7 +221,7 @@ public override BulkWriteResult BulkWrite(IClientSessionHandle sessio public override async Task> BulkWriteAsync(IEnumerable> requests, BulkWriteOptions options, CancellationToken cancellationToken = default) { - using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false); + using var session = _operationExecutor.StartImplicitSession(); return await BulkWriteAsync(session, requests, options, cancellationToken).ConfigureAwait(false); } @@ -244,12 +244,10 @@ public override async Task> BulkWriteAsync(IClientSes [Obsolete("Use CountDocuments or EstimatedDocumentCount instead.")] public override long Count(FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperation( - CreateCountOperation(filter, options), - _readOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + using var session = _operationExecutor.StartImplicitSession(); + return Count(session, filter, options, cancellationToken); + } [Obsolete("Use CountDocuments or EstimatedDocumentCount instead.")] public override long Count(IClientSessionHandle session, FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) @@ -261,13 +259,11 @@ public override long Count(IClientSessionHandle session, FilterDefinition CountAsync(FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperationAsync( - CreateCountOperation(filter, options), - _readOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + public override async Task CountAsync(FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) + { + using var session = _operationExecutor.StartImplicitSession(); + return await CountAsync(session, filter, options, cancellationToken).ConfigureAwait(false); + } [Obsolete("Use CountDocumentsAsync or EstimatedDocumentCountAsync instead.")] public override Task CountAsync(IClientSessionHandle session, FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) @@ -279,12 +275,10 @@ public override Task CountAsync(IClientSessionHandle session, FilterDefini cancellationToken: cancellationToken); public override long CountDocuments(FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperation( - CreateCountDocumentsOperation(filter, options), - _readOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + using var session = _operationExecutor.StartImplicitSession(); + return CountDocuments(session, filter, options, cancellationToken); + } public override long CountDocuments(IClientSessionHandle session, FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) => _operationExecutor.ExecuteReadOperation( @@ -294,13 +288,11 @@ public override long CountDocuments(IClientSessionHandle session, FilterDefiniti allowChannelPinning: true, cancellationToken: cancellationToken); - public override Task CountDocumentsAsync(FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperationAsync( - CreateCountDocumentsOperation(filter, options), - _readOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + public override async Task CountDocumentsAsync(FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) + { + using var session = _operationExecutor.StartImplicitSession(); + return await CountDocumentsAsync(session, filter, options, cancellationToken).ConfigureAwait(false); + } public override Task CountDocumentsAsync(IClientSessionHandle session, FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) => _operationExecutor.ExecuteReadOperationAsync( @@ -311,12 +303,10 @@ public override Task CountDocumentsAsync(IClientSessionHandle session, Fil cancellationToken: cancellationToken); public override IAsyncCursor Distinct(FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperation( - CreateDistinctOperation(field, filter, options), - _readOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + using var session = _operationExecutor.StartImplicitSession(); + return Distinct(session, field, filter, options, cancellationToken); + } public override IAsyncCursor Distinct(IClientSessionHandle session, FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) => _operationExecutor.ExecuteReadOperation( @@ -326,13 +316,11 @@ public override IAsyncCursor Distinct(IClientSessionHandle sessi allowChannelPinning: true, cancellationToken: cancellationToken); - public override Task> DistinctAsync(FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperationAsync( - CreateDistinctOperation(field, filter, options), - _readOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + public override async Task> DistinctAsync(FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) + { + using var session = _operationExecutor.StartImplicitSession(); + return await DistinctAsync(session, field, filter, options, cancellationToken).ConfigureAwait(false); + } public override Task> DistinctAsync(IClientSessionHandle session, FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) => _operationExecutor.ExecuteReadOperationAsync( @@ -343,12 +331,10 @@ public override Task> DistinctAsync(IClientSessionH cancellationToken: cancellationToken); public override IAsyncCursor DistinctMany(FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperation( - CreateDistinctManyOperation(field, filter, options), - _readOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + using var session = _operationExecutor.StartImplicitSession(); + return DistinctMany(session, field, filter, options, cancellationToken); + } public override IAsyncCursor DistinctMany(IClientSessionHandle session, FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) => _operationExecutor.ExecuteReadOperation( @@ -358,13 +344,11 @@ public override IAsyncCursor DistinctMany(IClientSessionHandle ses allowChannelPinning: true, cancellationToken: cancellationToken); - public override Task> DistinctManyAsync(FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperationAsync( - CreateDistinctManyOperation(field, filter, options), - _readOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + public override async Task> DistinctManyAsync(FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) + { + using var session = _operationExecutor.StartImplicitSession(); + return await DistinctManyAsync(session, field, filter, options, cancellationToken).ConfigureAwait(false); + } public override Task> DistinctManyAsync(IClientSessionHandle session, FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) => _operationExecutor.ExecuteReadOperationAsync( @@ -375,28 +359,24 @@ public override Task> DistinctManyAsync(IClientSessio cancellationToken: cancellationToken); public override long EstimatedDocumentCount(EstimatedDocumentCountOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperation( - CreateEstimatedDocumentCountOperation(options), - _readOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + using var session = _operationExecutor.StartImplicitSession(); + var operation = CreateEstimatedDocumentCountOperation(options); + return _operationExecutor.ExecuteReadOperation(operation, _readOperationOptions, session, true, cancellationToken); + } - public override Task EstimatedDocumentCountAsync(EstimatedDocumentCountOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperationAsync( - CreateEstimatedDocumentCountOperation(options), - _readOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + public override async Task EstimatedDocumentCountAsync(EstimatedDocumentCountOptions options, CancellationToken cancellationToken = default) + { + using var session = _operationExecutor.StartImplicitSession(); + var operation = CreateEstimatedDocumentCountOperation(options); + return await _operationExecutor.ExecuteReadOperationAsync(operation, _readOperationOptions, session, true, cancellationToken).ConfigureAwait(false); + } public override IAsyncCursor FindSync(FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperation( - CreateFindOperation(filter, options), - _readOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + using var session = _operationExecutor.StartImplicitSession(); + return FindSync(session, filter, options, cancellationToken); + } public override IAsyncCursor FindSync(IClientSessionHandle session, FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default) => _operationExecutor.ExecuteReadOperation( @@ -406,13 +386,11 @@ public override IAsyncCursor FindSync(IClientSessionHa allowChannelPinning: true, cancellationToken: cancellationToken); - public override Task> FindAsync(FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperationAsync( - CreateFindOperation(filter, options), - _readOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + public override async Task> FindAsync(FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default) + { + using var session = _operationExecutor.StartImplicitSession(); + return await FindAsync(session, filter, options, cancellationToken).ConfigureAwait(false); + } public override Task> FindAsync(IClientSessionHandle session, FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default) => _operationExecutor.ExecuteReadOperationAsync( @@ -423,12 +401,10 @@ public override Task> FindAsync(IClientSe cancellationToken: cancellationToken); public override TProjection FindOneAndDelete(FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteWriteOperation( - CreateFindOneAndDeleteOperation(filter, options), - _writeOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + using var session = _operationExecutor.StartImplicitSession(); + return FindOneAndDelete(session, filter, options, cancellationToken); + } public override TProjection FindOneAndDelete(IClientSessionHandle session, FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default) => _operationExecutor.ExecuteWriteOperation( @@ -438,13 +414,11 @@ public override TProjection FindOneAndDelete(IClientSessionHandle s allowChannelPinning: true, cancellationToken: cancellationToken); - public override Task FindOneAndDeleteAsync(FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteWriteOperationAsync( - CreateFindOneAndDeleteOperation(filter, options), - _writeOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + public override async Task FindOneAndDeleteAsync(FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default) + { + using var session = _operationExecutor.StartImplicitSession(); + return await FindOneAndDeleteAsync(session, filter, options, cancellationToken).ConfigureAwait(false); + } public override Task FindOneAndDeleteAsync(IClientSessionHandle session, FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default) => _operationExecutor.ExecuteWriteOperationAsync( @@ -455,12 +429,10 @@ public override Task FindOneAndDeleteAsync(IClientSess cancellationToken: cancellationToken); public override TProjection FindOneAndReplace(FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteWriteOperation( - CreateFindOneAndReplaceOperation(filter, replacement, options), - _writeOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + using var session = _operationExecutor.StartImplicitSession(); + return FindOneAndReplace(session, filter, replacement, options, cancellationToken); + } public override TProjection FindOneAndReplace(IClientSessionHandle session, FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default) => _operationExecutor.ExecuteWriteOperation( @@ -470,13 +442,11 @@ public override TProjection FindOneAndReplace(IClientSessionHandle allowChannelPinning: true, cancellationToken: cancellationToken); - public override Task FindOneAndReplaceAsync(FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteWriteOperationAsync( - CreateFindOneAndReplaceOperation(filter, replacement, options), - _writeOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + public override async Task FindOneAndReplaceAsync(FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default) + { + using var session = _operationExecutor.StartImplicitSession(); + return await FindOneAndReplaceAsync(session, filter, replacement, options, cancellationToken).ConfigureAwait(false); + } public override Task FindOneAndReplaceAsync(IClientSessionHandle session, FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default) => _operationExecutor.ExecuteWriteOperationAsync( @@ -487,12 +457,10 @@ public override Task FindOneAndReplaceAsync(IClientSes cancellationToken: cancellationToken); public override TProjection FindOneAndUpdate(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteWriteOperation( - CreateFindOneAndUpdateOperation(filter, update, options), - _writeOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + using var session = _operationExecutor.StartImplicitSession(); + return FindOneAndUpdate(session, filter, update, options, cancellationToken); + } public override TProjection FindOneAndUpdate(IClientSessionHandle session, FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default) => _operationExecutor.ExecuteWriteOperation( @@ -502,13 +470,11 @@ public override TProjection FindOneAndUpdate(IClientSessionHandle s allowChannelPinning: true, cancellationToken: cancellationToken); - public override Task FindOneAndUpdateAsync(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteWriteOperationAsync( - CreateFindOneAndUpdateOperation(filter, update, options), - _writeOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + public override async Task FindOneAndUpdateAsync(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default) + { + using var session = _operationExecutor.StartImplicitSession(); + return await FindOneAndUpdateAsync(session, filter, update, options, cancellationToken).ConfigureAwait(false); + } public override Task FindOneAndUpdateAsync(IClientSessionHandle session, FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default) => _operationExecutor.ExecuteWriteOperationAsync( @@ -521,7 +487,7 @@ public override Task FindOneAndUpdateAsync(IClientSess [Obsolete("Use Aggregation pipeline instead.")] public override IAsyncCursor MapReduce(BsonJavaScript map, BsonJavaScript reduce, MapReduceOptions options = null, CancellationToken cancellationToken = default) { - using var session = _operationExecutor.StartImplicitSession(cancellationToken: cancellationToken); + using var session = _operationExecutor.StartImplicitSession(); return MapReduce(session, map, reduce, options, cancellationToken: cancellationToken); } @@ -553,7 +519,7 @@ public override IAsyncCursor MapReduce(IClientSessionHandle se [Obsolete("Use Aggregation pipeline instead.")] public override async Task> MapReduceAsync(BsonJavaScript map, BsonJavaScript reduce, MapReduceOptions options = null, CancellationToken cancellationToken = default) { - using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false); + using var session = _operationExecutor.StartImplicitSession(); return await MapReduceAsync(session, map, reduce, options, cancellationToken).ConfigureAwait(false); } @@ -600,12 +566,10 @@ public override IChangeStreamCursor Watch( PipelineDefinition, TResult> pipeline, ChangeStreamOptions options = null, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperation( - CreateChangeStreamOperation(pipeline, options), - _readOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + using var session = _operationExecutor.StartImplicitSession(); + return Watch(session, pipeline, options, cancellationToken); + } public override IChangeStreamCursor Watch( IClientSessionHandle session, @@ -619,16 +583,14 @@ public override IChangeStreamCursor Watch( allowChannelPinning: true, cancellationToken: cancellationToken); - public override Task> WatchAsync( + public override async Task> WatchAsync( PipelineDefinition, TResult> pipeline, ChangeStreamOptions options = null, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperationAsync( - CreateChangeStreamOperation(pipeline, options), - _readOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + using var session = _operationExecutor.StartImplicitSession(); + return await WatchAsync(session, pipeline, options, cancellationToken).ConfigureAwait(false); + } public override Task> WatchAsync( IClientSessionHandle session, @@ -1365,9 +1327,8 @@ public override IEnumerable CreateMany( CreateManyIndexesOptions options, CancellationToken cancellationToken = default) { - var operation = CreateCreateIndexesOperation(models, options); - _collection._operationExecutor.ExecuteWriteOperation(operation, _collection._writeOperationOptions, null, true, cancellationToken); - return operation.Requests.Select(x => x.GetIndexName()); + using var session = _collection._operationExecutor.StartImplicitSession(); + return CreateMany(session, models, options, cancellationToken); } public override IEnumerable CreateMany(IClientSessionHandle session, IEnumerable> models, CancellationToken cancellationToken = default) @@ -1394,9 +1355,8 @@ public override async Task> CreateManyAsync( CreateManyIndexesOptions options, CancellationToken cancellationToken = default) { - var operation = CreateCreateIndexesOperation(models, options); - await _collection._operationExecutor.ExecuteWriteOperationAsync(operation, _collection._writeOperationOptions, null, true, cancellationToken).ConfigureAwait(false); - return operation.Requests.Select(x => x.GetIndexName()); + using var session = _collection._operationExecutor.StartImplicitSession(); + return await CreateManyAsync(session, models, options, cancellationToken).ConfigureAwait(false); } public override Task> CreateManyAsync(IClientSessionHandle session, IEnumerable> models, CancellationToken cancellationToken = default) @@ -1419,12 +1379,10 @@ public override void DropAll(CancellationToken cancellationToken) => DropAll(options: null, cancellationToken: cancellationToken); public override void DropAll(DropIndexOptions options, CancellationToken cancellationToken = default) - => _collection._operationExecutor.ExecuteWriteOperation( - CreateDropAllOperation(options), - _collection._writeOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + using var session = _collection._operationExecutor.StartImplicitSession(); + DropAll(session, options, cancellationToken); + } public override void DropAll(IClientSessionHandle session, CancellationToken cancellationToken = default) => DropAll(session, null, cancellationToken); @@ -1440,13 +1398,11 @@ public override void DropAll(IClientSessionHandle session, DropIndexOptions opti public override Task DropAllAsync(CancellationToken cancellationToken) => DropAllAsync(options: null, cancellationToken); - public override Task DropAllAsync(DropIndexOptions options, CancellationToken cancellationToken = default) - => _collection._operationExecutor.ExecuteWriteOperationAsync( - CreateDropAllOperation(options), - _collection._writeOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + public override async Task DropAllAsync(DropIndexOptions options, CancellationToken cancellationToken = default) + { + using var session = _collection._operationExecutor.StartImplicitSession(); + await DropAllAsync(session, options, cancellationToken).ConfigureAwait(false); + } public override Task DropAllAsync(IClientSessionHandle session, CancellationToken cancellationToken = default) => DropAllAsync(session, null, cancellationToken); @@ -1463,12 +1419,10 @@ public override void DropOne(string name, CancellationToken cancellationToken = => DropOne(name, null, cancellationToken); public override void DropOne(string name, DropIndexOptions options, CancellationToken cancellationToken = default) - => _collection._operationExecutor.ExecuteWriteOperation( - CreateDropOneOperation(name, options), - _collection._writeOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + using var session = _collection._operationExecutor.StartImplicitSession(); + DropOne(session, name, options, cancellationToken); + } public override void DropOne(IClientSessionHandle session, string name, CancellationToken cancellationToken = default) => DropOne(session, name, null, cancellationToken); @@ -1484,13 +1438,11 @@ public override void DropOne(IClientSessionHandle session, string name, DropInde public override Task DropOneAsync(string name, CancellationToken cancellationToken = default) => DropOneAsync(name, null, cancellationToken); - public override Task DropOneAsync(string name, DropIndexOptions options, CancellationToken cancellationToken = default) - => _collection._operationExecutor.ExecuteWriteOperationAsync( - CreateDropOneOperation(name, options), - _collection._writeOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + public override async Task DropOneAsync(string name, DropIndexOptions options, CancellationToken cancellationToken = default) + { + using var session = _collection._operationExecutor.StartImplicitSession(); + await DropOneAsync(session, name, options, cancellationToken).ConfigureAwait(false); + } public override Task DropOneAsync(IClientSessionHandle session, string name, CancellationToken cancellationToken = default) => DropOneAsync(session, name, null, cancellationToken); @@ -1507,12 +1459,10 @@ public override IAsyncCursor List(CancellationToken cancellationTo => List(options: null, cancellationToken); public override IAsyncCursor List(ListIndexesOptions options, CancellationToken cancellationToken = default) - => _collection._operationExecutor.ExecuteReadOperation( - CreateListIndexesOperation(options), - _collection._readOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + using var session = _collection._operationExecutor.StartImplicitSession(); + return List(session, options, cancellationToken); + } public override IAsyncCursor List(IClientSessionHandle session, CancellationToken cancellationToken = default) => List(session, options: null, cancellationToken); @@ -1528,13 +1478,11 @@ public override IAsyncCursor List(IClientSessionHandle session, Li public override Task> ListAsync(CancellationToken cancellationToken = default) => ListAsync(options: null, cancellationToken); - public override Task> ListAsync(ListIndexesOptions options, CancellationToken cancellationToken = default) - => _collection._operationExecutor.ExecuteReadOperationAsync( - CreateListIndexesOperation(options), - _collection._readOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + public override async Task> ListAsync(ListIndexesOptions options, CancellationToken cancellationToken = default) + { + using var session = _collection._operationExecutor.StartImplicitSession(); + return await ListAsync(session, options, cancellationToken).ConfigureAwait(false); + } public override Task> ListAsync(IClientSessionHandle session, CancellationToken cancellationToken = default) => ListAsync(session, options: null, cancellationToken); @@ -1650,15 +1598,17 @@ public MongoSearchIndexManager(MongoCollectionImpl collection) public IEnumerable CreateMany(IEnumerable models, CancellationToken cancellationToken = default) { + using var session = _collection._operationExecutor.StartImplicitSession(); var operation = CreateCreateIndexesOperation(models); - var result = _collection._operationExecutor.ExecuteWriteOperation(operation, _collection._writeOperationOptions, null, true, cancellationToken); + var result = _collection._operationExecutor.ExecuteWriteOperation(operation, _collection._writeOperationOptions, session, true, cancellationToken); return GetIndexNames(result); } public async Task> CreateManyAsync(IEnumerable models, CancellationToken cancellationToken = default) { + using var session = _collection._operationExecutor.StartImplicitSession(); var operation = CreateCreateIndexesOperation(models); - var result = await _collection._operationExecutor.ExecuteWriteOperationAsync(operation, _collection._writeOperationOptions, null, true, cancellationToken).ConfigureAwait(false); + var result = await _collection._operationExecutor.ExecuteWriteOperationAsync(operation, _collection._writeOperationOptions, session, true, cancellationToken).ConfigureAwait(false); return GetIndexNames(result); } @@ -1681,20 +1631,18 @@ public async Task CreateOneAsync(CreateSearchIndexModel model, Cancellat } public void DropOne(string indexName, CancellationToken cancellationToken = default) - => _collection._operationExecutor.ExecuteWriteOperation( - new DropSearchIndexOperation(_collection.CollectionNamespace, indexName, _collection._messageEncoderSettings), - _collection._writeOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + using var session = _collection._operationExecutor.StartImplicitSession(); + var operation = new DropSearchIndexOperation(_collection.CollectionNamespace, indexName, _collection._messageEncoderSettings); + _collection._operationExecutor.ExecuteWriteOperation(operation, _collection._writeOperationOptions, session, true, cancellationToken); + } - public Task DropOneAsync(string indexName, CancellationToken cancellationToken = default) - => _collection._operationExecutor.ExecuteWriteOperationAsync( - new DropSearchIndexOperation(_collection.CollectionNamespace, indexName, _collection._messageEncoderSettings), - _collection._writeOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + public async Task DropOneAsync(string indexName, CancellationToken cancellationToken = default) + { + using var session = _collection._operationExecutor.StartImplicitSession(); + var operation = new DropSearchIndexOperation(_collection.CollectionNamespace, indexName, _collection._messageEncoderSettings); + await _collection._operationExecutor.ExecuteWriteOperationAsync(operation, _collection._writeOperationOptions, session, true, cancellationToken).ConfigureAwait(false); + } public IAsyncCursor List(string indexName, AggregateOptions aggregateOptions = null, CancellationToken cancellationToken = default) { @@ -1707,20 +1655,18 @@ public Task> ListAsync(string indexName, AggregateOpt } public void Update(string indexName, BsonDocument definition, CancellationToken cancellationToken = default) - => _collection._operationExecutor.ExecuteWriteOperation( - new UpdateSearchIndexOperation(_collection.CollectionNamespace, indexName, definition, _collection._messageEncoderSettings), - _collection._writeOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + using var session = _collection._operationExecutor.StartImplicitSession(); + var operation = new UpdateSearchIndexOperation(_collection.CollectionNamespace, indexName, definition, _collection._messageEncoderSettings); + _collection._operationExecutor.ExecuteWriteOperation(operation, _collection._writeOperationOptions, session, true, cancellationToken); + } - public Task UpdateAsync(string indexName, BsonDocument definition, CancellationToken cancellationToken = default) - => _collection._operationExecutor.ExecuteWriteOperationAsync( - new UpdateSearchIndexOperation(_collection.CollectionNamespace, indexName, definition, _collection._messageEncoderSettings), - _collection._writeOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + public async Task UpdateAsync(string indexName, BsonDocument definition, CancellationToken cancellationToken = default) + { + using var session = _collection._operationExecutor.StartImplicitSession(); + var operation = new UpdateSearchIndexOperation(_collection.CollectionNamespace, indexName, definition, _collection._messageEncoderSettings); + await _collection._operationExecutor.ExecuteWriteOperationAsync(operation, _collection._writeOperationOptions, session, true, cancellationToken).ConfigureAwait(false); + } // private methods private PipelineDefinition CreateListIndexesStage(string indexName) diff --git a/src/MongoDB.Driver/MongoDatabase.cs b/src/MongoDB.Driver/MongoDatabase.cs index 2e1ee1fc080..6e3d6222243 100644 --- a/src/MongoDB.Driver/MongoDatabase.cs +++ b/src/MongoDB.Driver/MongoDatabase.cs @@ -63,7 +63,7 @@ public MongoDatabase(IMongoClient client, DatabaseNamespace databaseNamespace, M // public methods public IAsyncCursor Aggregate(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { - using var session = _operationExecutor.StartImplicitSession(cancellationToken); + using var session = _operationExecutor.StartImplicitSession(); return Aggregate(session, pipeline, options, cancellationToken: cancellationToken); } @@ -90,7 +90,7 @@ public IAsyncCursor Aggregate(IClientSessionHandle session, Pi public async Task> AggregateAsync(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { - using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false); + using var session = _operationExecutor.StartImplicitSession(); return await AggregateAsync(session, pipeline, options, cancellationToken).ConfigureAwait(false); } @@ -117,7 +117,7 @@ public async Task> AggregateAsync(IClientSessionH public void AggregateToCollection(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { - using var session = _operationExecutor.StartImplicitSession(cancellationToken); + using var session = _operationExecutor.StartImplicitSession(); AggregateToCollection(session, pipeline, options, cancellationToken); } @@ -140,7 +140,7 @@ public void AggregateToCollection(IClientSessionHandle session, Pipelin public async Task AggregateToCollectionAsync(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { - using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false); + using var session = _operationExecutor.StartImplicitSession(); await AggregateToCollectionAsync(session, pipeline, options, cancellationToken).ConfigureAwait(false); } @@ -163,7 +163,7 @@ public async Task AggregateToCollectionAsync(IClientSessionHandle sessi public void CreateCollection(string name, CreateCollectionOptions options, CancellationToken cancellationToken) { - using var session = _operationExecutor.StartImplicitSession(cancellationToken); + using var session = _operationExecutor.StartImplicitSession(); CreateCollection(session, name, options, cancellationToken); } @@ -200,7 +200,7 @@ public void CreateCollection(IClientSessionHandle session, string name, CreateCo public async Task CreateCollectionAsync(string name, CreateCollectionOptions options, CancellationToken cancellationToken) { - using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false); + using var session = _operationExecutor.StartImplicitSession(); await CreateCollectionAsync(session, name, options, cancellationToken).ConfigureAwait(false); } @@ -236,12 +236,10 @@ public async Task CreateCollectionAsync(IClientSessionHandle session, string nam } public void CreateView(string viewName, string viewOn, PipelineDefinition pipeline, CreateViewOptions options = null, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteWriteOperation( - CreateCreateViewOperation(viewName, viewOn, pipeline, options), - _writeOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + using var session = _operationExecutor.StartImplicitSession(); + CreateView(session, viewName, viewOn, pipeline, options, cancellationToken); + } public void CreateView(IClientSessionHandle session, string viewName, string viewOn, PipelineDefinition pipeline, CreateViewOptions options = null, CancellationToken cancellationToken = default) => _operationExecutor.ExecuteWriteOperation( @@ -251,13 +249,11 @@ public void CreateView(IClientSessionHandle session, string allowChannelPinning: true, cancellationToken: cancellationToken); - public Task CreateViewAsync(string viewName, string viewOn, PipelineDefinition pipeline, CreateViewOptions options = null, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteWriteOperationAsync( - CreateCreateViewOperation(viewName, viewOn, pipeline, options), - _writeOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + public async Task CreateViewAsync(string viewName, string viewOn, PipelineDefinition pipeline, CreateViewOptions options = null, CancellationToken cancellationToken = default) + { + using var session = _operationExecutor.StartImplicitSession(); + await CreateViewAsync(session, viewName, viewOn, pipeline, options, cancellationToken).ConfigureAwait(false); + } public Task CreateViewAsync(IClientSessionHandle session, string viewName, string viewOn, PipelineDefinition pipeline, CreateViewOptions options = null, CancellationToken cancellationToken = default) => _operationExecutor.ExecuteWriteOperationAsync( @@ -274,7 +270,7 @@ public void DropCollection(string name, CancellationToken cancellationToken) public void DropCollection(string name, DropCollectionOptions options, CancellationToken cancellationToken = default) { - using var session = _operationExecutor.StartImplicitSession(cancellationToken); + using var session = _operationExecutor.StartImplicitSession(); DropCollection(session, name, options, cancellationToken); } @@ -295,20 +291,16 @@ public void DropCollection(IClientSessionHandle session, string name, DropCollec } public Task DropCollectionAsync(string name, CancellationToken cancellationToken) - { - return DropCollectionAsync(name, options: null, cancellationToken); - } + => DropCollectionAsync(name, options: null, cancellationToken); public async Task DropCollectionAsync(string name, DropCollectionOptions options, CancellationToken cancellationToken) { - using var session = await _operationExecutor.StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false); + using var session = _operationExecutor.StartImplicitSession(); await DropCollectionAsync(session, name, options, cancellationToken).ConfigureAwait(false); } public Task DropCollectionAsync(IClientSessionHandle session, string name, CancellationToken cancellationToken) - { - return DropCollectionAsync(session, name, options: null, cancellationToken); - } + => DropCollectionAsync(session, name, options: null, cancellationToken); public async Task DropCollectionAsync(IClientSessionHandle session, string name, DropCollectionOptions options, CancellationToken cancellationToken) { @@ -336,13 +328,8 @@ public IMongoCollection GetCollection(string name, MongoCo public IAsyncCursor ListCollectionNames(ListCollectionNamesOptions options = null, CancellationToken cancellationToken = default) { - var cursor = _operationExecutor.ExecuteReadOperation( - CreateListCollectionNamesOperation(options), - _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, - null, - allowChannelPinning: true, - cancellationToken: cancellationToken); - return new BatchTransformingAsyncCursor(cursor, ExtractCollectionNames); + using var session = _operationExecutor.StartImplicitSession(); + return ListCollectionNames(session, options, cancellationToken); } public IAsyncCursor ListCollectionNames(IClientSessionHandle session, ListCollectionNamesOptions options = null, CancellationToken cancellationToken = default) @@ -358,13 +345,8 @@ public IAsyncCursor ListCollectionNames(IClientSessionHandle session, Li public async Task> ListCollectionNamesAsync(ListCollectionNamesOptions options = null, CancellationToken cancellationToken = default) { - var cursor = await _operationExecutor.ExecuteReadOperationAsync( - CreateListCollectionNamesOperation(options), - _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken).ConfigureAwait(false); - return new BatchTransformingAsyncCursor(cursor, ExtractCollectionNames); + using var session = _operationExecutor.StartImplicitSession(); + return await ListCollectionNamesAsync(session, options, cancellationToken).ConfigureAwait(false); } public async Task> ListCollectionNamesAsync(IClientSessionHandle session, ListCollectionNamesOptions options = null, CancellationToken cancellationToken = default) @@ -379,12 +361,10 @@ public async Task> ListCollectionNamesAsync(IClientSessionH } public IAsyncCursor ListCollections(ListCollectionsOptions options, CancellationToken cancellationToken) - => _operationExecutor.ExecuteReadOperation( - CreateListCollectionsOperation(options), - _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + using var session = _operationExecutor.StartImplicitSession(); + return ListCollections(session, options, cancellationToken); + } public IAsyncCursor ListCollections(IClientSessionHandle session, ListCollectionsOptions options, CancellationToken cancellationToken) => _operationExecutor.ExecuteReadOperation( @@ -394,13 +374,11 @@ public IAsyncCursor ListCollections(IClientSessionHandle session, allowChannelPinning: true, cancellationToken: cancellationToken); - public Task> ListCollectionsAsync(ListCollectionsOptions options, CancellationToken cancellationToken) - => _operationExecutor.ExecuteReadOperationAsync( - CreateListCollectionsOperation(options), - _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + public async Task> ListCollectionsAsync(ListCollectionsOptions options, CancellationToken cancellationToken) + { + using var session = _operationExecutor.StartImplicitSession(); + return await ListCollectionsAsync(session, options, cancellationToken).ConfigureAwait(false); + } public Task> ListCollectionsAsync(IClientSessionHandle session, ListCollectionsOptions options, CancellationToken cancellationToken) => _operationExecutor.ExecuteReadOperationAsync( @@ -411,12 +389,10 @@ public Task> ListCollectionsAsync(IClientSessionHandl cancellationToken: cancellationToken); public void RenameCollection(string oldName, string newName, RenameCollectionOptions options, CancellationToken cancellationToken) - => _operationExecutor.ExecuteWriteOperation( - CreateRenameCollectionOperation(oldName, newName, options), - _writeOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + using var session = _operationExecutor.StartImplicitSession(); + RenameCollection(session, oldName, newName, options, cancellationToken); + } public void RenameCollection(IClientSessionHandle session, string oldName, string newName, RenameCollectionOptions options, CancellationToken cancellationToken) => _operationExecutor.ExecuteWriteOperation( @@ -426,13 +402,11 @@ public void RenameCollection(IClientSessionHandle session, string oldName, strin allowChannelPinning: true, cancellationToken: cancellationToken); - public Task RenameCollectionAsync(string oldName, string newName, RenameCollectionOptions options, CancellationToken cancellationToken) - => _operationExecutor.ExecuteWriteOperationAsync( - CreateRenameCollectionOperation(oldName, newName, options), - _writeOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + public async Task RenameCollectionAsync(string oldName, string newName, RenameCollectionOptions options, CancellationToken cancellationToken) + { + using var session = _operationExecutor.StartImplicitSession(); + await RenameCollectionAsync(session, oldName, newName, options, cancellationToken).ConfigureAwait(false); + } public Task RenameCollectionAsync(IClientSessionHandle session, string oldName, string newName, RenameCollectionOptions options, CancellationToken cancellationToken) => _operationExecutor.ExecuteWriteOperationAsync( @@ -443,12 +417,10 @@ public Task RenameCollectionAsync(IClientSessionHandle session, string oldName, cancellationToken: cancellationToken); public TResult RunCommand(Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperation( - CreateRunCommandOperation(command), - _readOperationOptions with { ExplicitReadPreference = readPreference, DefaultReadPreference = ReadPreference.Primary}, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + using var session = _operationExecutor.StartImplicitSession(); + return RunCommand(session, command, readPreference, cancellationToken); + } public TResult RunCommand(IClientSessionHandle session, Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default) => _operationExecutor.ExecuteReadOperation( @@ -458,13 +430,11 @@ public TResult RunCommand(IClientSessionHandle session, Command RunCommandAsync(Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperationAsync( - CreateRunCommandOperation(command), - _readOperationOptions with { ExplicitReadPreference = readPreference, DefaultReadPreference = ReadPreference.Primary}, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + public async Task RunCommandAsync(Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default) + { + using var session = _operationExecutor.StartImplicitSession(); + return await RunCommandAsync(session, command, readPreference, cancellationToken).ConfigureAwait(false); + } public Task RunCommandAsync(IClientSessionHandle session, Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default) => _operationExecutor.ExecuteReadOperationAsync( @@ -478,12 +448,10 @@ public IChangeStreamCursor Watch( PipelineDefinition, TResult> pipeline, ChangeStreamOptions options = null, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperation( - CreateChangeStreamOperation(pipeline, options), - _readOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + using var session = _operationExecutor.StartImplicitSession(); + return Watch(session, pipeline, options, cancellationToken); + } public IChangeStreamCursor Watch( IClientSessionHandle session, @@ -497,16 +465,14 @@ public IChangeStreamCursor Watch( allowChannelPinning: true, cancellationToken: cancellationToken); - public Task> WatchAsync( + public async Task> WatchAsync( PipelineDefinition, TResult> pipeline, ChangeStreamOptions options = null, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperationAsync( - CreateChangeStreamOperation(pipeline, options), - _readOperationOptions, - session: null, - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + using var session = _operationExecutor.StartImplicitSession(); + return await WatchAsync(session, pipeline, options, cancellationToken).ConfigureAwait(false); + } public Task> WatchAsync( IClientSessionHandle session, diff --git a/src/MongoDB.Driver/OperationExecutor.cs b/src/MongoDB.Driver/OperationExecutor.cs index cf0a6b32a0f..eae6c39ae07 100644 --- a/src/MongoDB.Driver/OperationExecutor.cs +++ b/src/MongoDB.Driver/OperationExecutor.cs @@ -18,6 +18,7 @@ using System.Threading.Tasks; using MongoDB.Driver.Core; using MongoDB.Driver.Core.Bindings; +using MongoDB.Driver.Core.Misc; using MongoDB.Driver.Core.Operations; namespace MongoDB.Driver @@ -37,114 +38,78 @@ public void Dispose() _isDisposed = true; } - public TResult ExecuteReadOperation(IReadOperation operation, + public TResult ExecuteReadOperation( + IReadOperation operation, ReadOperationOptions options, IClientSessionHandle session, bool allowChannelPinning, CancellationToken cancellationToken) { ThrowIfDisposed(); - var isOwnSession = session == null; - session ??= StartImplicitSession(cancellationToken); + Ensure.IsNotNull(operation, nameof(operation)); + Ensure.IsNotNull(options, nameof(options)); + Ensure.IsNotNull(session, nameof(session)); - try - { - var readPreference = options.GetEffectiveReadPreference(session); - using var binding = CreateReadBinding(session, readPreference, allowChannelPinning); - return operation.Execute(binding, cancellationToken); - } - finally - { - if (isOwnSession) - { - session.Dispose(); - } - } + var readPreference = options.GetEffectiveReadPreference(session); + using var binding = CreateReadBinding(session, readPreference, allowChannelPinning); + return operation.Execute(binding, cancellationToken); } - public async Task ExecuteReadOperationAsync(IReadOperation operation, + public async Task ExecuteReadOperationAsync( + IReadOperation operation, ReadOperationOptions options, IClientSessionHandle session, bool allowChannelPinning, CancellationToken cancellationToken) { ThrowIfDisposed(); - var isOwnSession = session == null; - session ??= await StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false); + Ensure.IsNotNull(operation, nameof(operation)); + Ensure.IsNotNull(options, nameof(options)); + Ensure.IsNotNull(session, nameof(session)); - try - { - var readPreference = options.GetEffectiveReadPreference(session); - using var binding = CreateReadBinding(session, readPreference, allowChannelPinning); - return await operation.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false); - } - finally - { - if (isOwnSession) - { - session.Dispose(); - } - } + var readPreference = options.GetEffectiveReadPreference(session); + using var binding = CreateReadBinding(session, readPreference, allowChannelPinning); + return await operation.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false); } - public TResult ExecuteWriteOperation(IWriteOperation operation, + public TResult ExecuteWriteOperation( + IWriteOperation operation, WriteOperationOptions options, IClientSessionHandle session, bool allowChannelPinning, CancellationToken cancellationToken) { ThrowIfDisposed(); - var isOwnSession = session == null; - session ??= StartImplicitSession(cancellationToken); + Ensure.IsNotNull(operation, nameof(operation)); + Ensure.IsNotNull(options, nameof(options)); + Ensure.IsNotNull(session, nameof(session)); - try - { - using var binding = CreateReadWriteBinding(session, allowChannelPinning); - return operation.Execute(binding, cancellationToken); - } - finally - { - if (isOwnSession) - { - session.Dispose(); - } - } + using var binding = CreateReadWriteBinding(session, allowChannelPinning); + return operation.Execute(binding, cancellationToken); } - public async Task ExecuteWriteOperationAsync(IWriteOperation operation, + public async Task ExecuteWriteOperationAsync( + IWriteOperation operation, WriteOperationOptions options, IClientSessionHandle session, bool allowChannelPinning, CancellationToken cancellationToken) { ThrowIfDisposed(); - var isOwnSession = session == null; - session ??= await StartImplicitSessionAsync(cancellationToken).ConfigureAwait(false); + Ensure.IsNotNull(operation, nameof(operation)); + Ensure.IsNotNull(options, nameof(options)); + Ensure.IsNotNull(session, nameof(session)); - try - { - using var binding = CreateReadWriteBinding(session, allowChannelPinning); - return await operation.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false); - } - finally - { - if (isOwnSession) - { - session.Dispose(); - } - } + using var binding = CreateReadWriteBinding(session, allowChannelPinning); + return await operation.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false); } - public IClientSessionHandle StartImplicitSession(CancellationToken cancellationToken) + public IClientSessionHandle StartImplicitSession() { ThrowIfDisposed(); - return StartImplicitSession(); - } - - public Task StartImplicitSessionAsync(CancellationToken cancellationToken) - { - ThrowIfDisposed(); - return Task.FromResult(StartImplicitSession()); + var options = new ClientSessionOptions { CausalConsistency = false, Snapshot = false }; + var coreSession = _client.GetClusterInternal().StartSession(options.ToCore(isImplicit: true)); + return new ClientSessionHandle(_client, options, coreSession); } private IReadBindingHandle CreateReadBinding(IClientSessionHandle session, ReadPreference readPreference, bool allowChannelPinning) @@ -174,13 +139,6 @@ private IReadWriteBindingHandle CreateReadWriteBinding(IClientSessionHandle sess return ChannelPinningHelper.CreateReadWriteBinding(_client.GetClusterInternal(), session.WrappedCoreSession.Fork()); } - private IClientSessionHandle StartImplicitSession() - { - var options = new ClientSessionOptions { CausalConsistency = false, Snapshot = false }; - var coreSession = _client.GetClusterInternal().StartSession(options.ToCore(isImplicit: true)); - return new ClientSessionHandle(_client, options, coreSession); - } - private void ThrowIfDisposed() { if (_isDisposed) diff --git a/tests/MongoDB.Driver.Tests/MockOperationExecutor.cs b/tests/MongoDB.Driver.Tests/MockOperationExecutor.cs index 116310455b1..197b5acc0ab 100644 --- a/tests/MongoDB.Driver.Tests/MockOperationExecutor.cs +++ b/tests/MongoDB.Driver.Tests/MockOperationExecutor.cs @@ -196,7 +196,7 @@ public WriteCall GetWriteCall() return writeCall; } - public IClientSessionHandle StartImplicitSession(CancellationToken cancellationToken) + public IClientSessionHandle StartImplicitSession() { var cluster = Mock.Of(); var options = new ClientSessionOptions(); @@ -206,11 +206,6 @@ public IClientSessionHandle StartImplicitSession(CancellationToken cancellationT return new ClientSessionHandle(_client, options, coreSessionHandle); } - public Task StartImplicitSessionAsync(CancellationToken cancellationToken) - { - return Task.FromResult(StartImplicitSession(cancellationToken)); - } - public class ReadCall { public IReadOperation Operation { get; set; } diff --git a/tests/MongoDB.Driver.Tests/OperationExecutorTests.cs b/tests/MongoDB.Driver.Tests/OperationExecutorTests.cs index e3cd85cde01..b8cc379f9c3 100644 --- a/tests/MongoDB.Driver.Tests/OperationExecutorTests.cs +++ b/tests/MongoDB.Driver.Tests/OperationExecutorTests.cs @@ -13,9 +13,10 @@ * limitations under the License. */ -using System.Collections.Generic; +using System; using System.Threading; using System.Threading.Tasks; +using FluentAssertions; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Clusters; using MongoDB.Driver.Core.Operations; @@ -27,72 +28,110 @@ namespace MongoDB.Driver.Tests { public class OperationExecutorTests { - [Theory] - [ParameterAttributeData] - public async Task StartImplicitSession_should_call_cluster_StartSession([Values(true, false)]bool isAsync) + [Fact] + public void StartImplicitSession_should_call_cluster_StartSession() { var subject = CreateSubject(out var clusterMock, out _); - if (isAsync) - { - await subject.StartImplicitSessionAsync(CancellationToken.None); - } - else - { - subject.StartImplicitSession(CancellationToken.None); - } + + subject.StartImplicitSession(); clusterMock.Verify(c => c.StartSession(It.Is(v => v.IsImplicit && v.IsCausallyConsistent == false && v.IsSnapshot == false))); } [Theory] - [MemberData(nameof(ImplicitSessionTestCases))] - public async Task ExecuteReadOperation_should_start_and_dispose_implicit_session_if_needed(bool shouldCreateSession, bool isAsync, IClientSessionHandle session) + [ParameterAttributeData] + public async Task ExecuteReadOperation_throws_on_null_operation([Values(true, false)] bool async) + { + var subject = CreateSubject(out _, out _); + var options = new ReadOperationOptions(); + var session = Mock.Of(); + + var exception = async ? + await Record.ExceptionAsync(() => subject.ExecuteReadOperationAsync(null, options, session, true, CancellationToken.None)) : + Record.Exception(() => subject.ExecuteReadOperation(null, options, session, true, CancellationToken.None)); + + exception.Should().BeOfType() + .Subject.ParamName.Should().Be("operation"); + } + + [Theory] + [ParameterAttributeData] + public async Task ExecuteReadOperation_throws_on_null_options([Values(true, false)] bool async) + { + var subject = CreateSubject(out _, out _); + var operation = Mock.Of>(); + var session = Mock.Of(); + + var exception = async ? + await Record.ExceptionAsync(() => subject.ExecuteReadOperationAsync(operation, null, session, true, CancellationToken.None)) : + Record.Exception(() => subject.ExecuteReadOperation(operation, null, session, true, CancellationToken.None)); + + exception.Should().BeOfType() + .Subject.ParamName.Should().Be("options"); + } + + [Theory] + [ParameterAttributeData] + public async Task ExecuteReadOperation_throws_on_null_session([Values(true, false)] bool async) { - var subject = CreateSubject(out var clusterMock, out var implicitSessionMock); - var readOperation = Mock.Of>(); - var readOperationOptions = new ReadOperationOptions(); + var subject = CreateSubject(out _, out _); + var operation = Mock.Of>(); + var options = new ReadOperationOptions(); - _ = isAsync ? - await subject.ExecuteReadOperationAsync(readOperation, readOperationOptions, session, false, cancellationToken: CancellationToken.None) : - subject.ExecuteReadOperation(readOperation, readOperationOptions, session, false, cancellationToken: CancellationToken.None); + var exception = async ? + await Record.ExceptionAsync(() => subject.ExecuteReadOperationAsync(operation, options, null, true, CancellationToken.None)) : + Record.Exception(() => subject.ExecuteReadOperation(operation, options, null, true, CancellationToken.None)); - var times = shouldCreateSession ? Times.Once() : Times.Never(); - clusterMock.Verify(c => c.StartSession(It.Is(v => v.IsImplicit && v.IsCausallyConsistent == false && v.IsSnapshot == false)), times); - implicitSessionMock.Verify(s => s.Dispose(), times); + exception.Should().BeOfType() + .Subject.ParamName.Should().Be("session"); } [Theory] - [MemberData(nameof(ImplicitSessionTestCases))] - public async Task ExecuteWriteOperation_should_start_and_dispose_implicit_session_if_needed(bool shouldCreateSession, bool isAsync, IClientSessionHandle session) + [ParameterAttributeData] + public async Task ExecuteWriteOperation_throws_on_null_operation([Values(true, false)] bool async) { - var subject = CreateSubject(out var clusterMock, out var implicitSessionMock); - var writeOperation = Mock.Of>(); - var writeOperationOptions = new WriteOperationOptions(); + var subject = CreateSubject(out _, out _); + var options = new WriteOperationOptions(); + var session = Mock.Of(); - _ = isAsync ? - await subject.ExecuteWriteOperationAsync(writeOperation, writeOperationOptions, session, false, cancellationToken: CancellationToken.None) : - subject.ExecuteWriteOperation(writeOperation, writeOperationOptions, session, false, cancellationToken: CancellationToken.None); + var exception = async ? + await Record.ExceptionAsync(() => subject.ExecuteWriteOperationAsync(null, options, session, true, CancellationToken.None)) : + Record.Exception(() => subject.ExecuteWriteOperation(null, options, session, true, CancellationToken.None)); - var times = shouldCreateSession ? Times.Once() : Times.Never(); - clusterMock.Verify(c => c.StartSession(It.Is(v => v.IsImplicit && v.IsCausallyConsistent == false && v.IsSnapshot == false)), times); - implicitSessionMock.Verify(s => s.Dispose(), times); + exception.Should().BeOfType() + .Subject.ParamName.Should().Be("operation"); } - private static IEnumerable ImplicitSessionTestCases() + [Theory] + [ParameterAttributeData] + public async Task ExecuteWriteOperation_throws_on_null_options([Values(true, false)] bool async) { - yield return [ true, false, null ]; - yield return [ true, true, null ]; - - var implicitSession = new Mock(); - implicitSession.SetupGet(s => s.IsImplicit).Returns(true); - implicitSession.SetupGet(s => s.WrappedCoreSession).Returns(CreateCoreSessionMock(true).Object); - yield return [ false, false, implicitSession.Object ]; - yield return [ false, true, implicitSession.Object ]; - - var regularSession = new Mock(); - regularSession.SetupGet(s => s.WrappedCoreSession).Returns(CreateCoreSessionMock(false).Object); - yield return [ false, false, regularSession.Object ]; - yield return [ false, true, regularSession.Object ]; + var subject = CreateSubject(out _, out _); + var operation = Mock.Of>(); + var session = Mock.Of(); + + var exception = async ? + await Record.ExceptionAsync(() => subject.ExecuteWriteOperationAsync(operation, null, session, true, CancellationToken.None)) : + Record.Exception(() => subject.ExecuteWriteOperation(operation, null, session, true, CancellationToken.None)); + + exception.Should().BeOfType() + .Subject.ParamName.Should().Be("options"); + } + + [Theory] + [ParameterAttributeData] + public async Task ExecuteWriteOperation_throws_on_null_session([Values(true, false)] bool async) + { + var subject = CreateSubject(out _, out _); + var operation = Mock.Of>(); + var options = new WriteOperationOptions(); + + var exception = async ? + await Record.ExceptionAsync(() => subject.ExecuteWriteOperationAsync(operation, options, null, true, CancellationToken.None)) : + Record.Exception(() => subject.ExecuteWriteOperation(operation, options, null, true, CancellationToken.None)); + + exception.Should().BeOfType() + .Subject.ParamName.Should().Be("session"); } private OperationExecutor CreateSubject(out Mock clusterMock, out Mock implicitSessionMock) From 38973f2cbb7b738c2bbaee36eccd888fc874861a Mon Sep 17 00:00:00 2001 From: Oleksandr Poliakov Date: Wed, 4 Jun 2025 11:43:39 -0700 Subject: [PATCH 08/14] PR --- src/MongoDB.Driver/IOperationExecutor.cs | 20 +- src/MongoDB.Driver/MongoClient.cs | 148 ++++---- src/MongoDB.Driver/MongoCollectionImpl.cs | 329 +++++++++--------- src/MongoDB.Driver/MongoDatabase.cs | 183 +++++----- src/MongoDB.Driver/OperationExecutor.cs | 18 +- .../MockOperationExecutor.cs | 24 +- .../OperationExecutorTests.cs | 24 +- 7 files changed, 380 insertions(+), 366 deletions(-) diff --git a/src/MongoDB.Driver/IOperationExecutor.cs b/src/MongoDB.Driver/IOperationExecutor.cs index 66f5eba5406..b935561469f 100644 --- a/src/MongoDB.Driver/IOperationExecutor.cs +++ b/src/MongoDB.Driver/IOperationExecutor.cs @@ -22,27 +22,31 @@ namespace MongoDB.Driver { internal interface IOperationExecutor : IDisposable { - TResult ExecuteReadOperation(IReadOperation operation, - ReadOperationOptions options, + TResult ExecuteReadOperation( IClientSessionHandle session, + IReadOperation operation, + ReadOperationOptions options, bool allowChannelPinning, CancellationToken cancellationToken); - Task ExecuteReadOperationAsync(IReadOperation operation, - ReadOperationOptions options, + Task ExecuteReadOperationAsync( IClientSessionHandle session, + IReadOperation operation, + ReadOperationOptions options, bool allowChannelPinning, CancellationToken cancellationToken); - TResult ExecuteWriteOperation(IWriteOperation operation, - WriteOperationOptions options, + TResult ExecuteWriteOperation( IClientSessionHandle session, + IWriteOperation operation, + WriteOperationOptions options, bool allowChannelPinning, CancellationToken cancellationToken); - Task ExecuteWriteOperationAsync(IWriteOperation operation, - WriteOperationOptions options, + Task ExecuteWriteOperationAsync( IClientSessionHandle session, + IWriteOperation operation, + WriteOperationOptions options, bool allowChannelPinning, CancellationToken cancellationToken); diff --git a/src/MongoDB.Driver/MongoClient.cs b/src/MongoDB.Driver/MongoClient.cs index 74b98d6b444..48272cd8eb6 100644 --- a/src/MongoDB.Driver/MongoClient.cs +++ b/src/MongoDB.Driver/MongoClient.cs @@ -87,8 +87,8 @@ public MongoClient(string connectionString) internal MongoClient(MongoClientSettings settings, Func operationExecutorFactory) { - _operationExecutorFactory = Ensure.IsNotNull(operationExecutorFactory, nameof(operationExecutorFactory)); _settings = Ensure.IsNotNull(settings, nameof(settings)).FrozenCopy(); + _operationExecutorFactory = Ensure.IsNotNull(operationExecutorFactory, nameof(operationExecutorFactory)); _logger = _settings.LoggingSettings?.CreateLogger(); _cluster = _settings.ClusterSource.Get(_settings.ToClusterKey()); _operationExecutor = _operationExecutorFactory(this); @@ -137,34 +137,36 @@ internal void ConfigureAutoEncryptionMessageEncoderSettings(MessageEncoderSettin /// public ClientBulkWriteResult BulkWrite(IReadOnlyList models, ClientBulkWriteOptions options = null, CancellationToken cancellationToken = default) { + ThrowIfDisposed(); using var session = _operationExecutor.StartImplicitSession(); return BulkWrite(session, models, options, cancellationToken); } /// public ClientBulkWriteResult BulkWrite(IClientSessionHandle session, IReadOnlyList models, ClientBulkWriteOptions options = null, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteWriteOperation( - CreateClientBulkWriteOperation(models, options), - _writeOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: false, - cancellationToken: cancellationToken); + { + ThrowIfDisposed(); + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateClientBulkWriteOperation(models, options); + return ExecuteWriteOperation(session, operation, _writeOperationOptions, cancellationToken); + } /// public async Task BulkWriteAsync(IReadOnlyList models, ClientBulkWriteOptions options = null, CancellationToken cancellationToken = default) { + ThrowIfDisposed(); using var session = _operationExecutor.StartImplicitSession(); return await BulkWriteAsync(session, models, options, cancellationToken).ConfigureAwait(false); } /// public Task BulkWriteAsync(IClientSessionHandle session, IReadOnlyList models, ClientBulkWriteOptions options = null, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteWriteOperationAsync( - CreateClientBulkWriteOperation(models, options), - _writeOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: false, - cancellationToken: cancellationToken); + { + ThrowIfDisposed(); + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateClientBulkWriteOperation(models, options); + return ExecuteWriteOperationAsync(session, operation, _writeOperationOptions, cancellationToken); + } /// public void Dispose() @@ -199,34 +201,36 @@ public void Dispose(bool disposing) /// public void DropDatabase(string name, CancellationToken cancellationToken = default) { + ThrowIfDisposed(); using var session = _operationExecutor.StartImplicitSession(); DropDatabase(session, name, cancellationToken); } /// public void DropDatabase(IClientSessionHandle session, string name, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteWriteOperation( - CreateDropDatabaseOperation(name), - _writeOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: false, - cancellationToken: cancellationToken); + { + ThrowIfDisposed(); + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateDropDatabaseOperation(name); + ExecuteWriteOperation(session, operation, _writeOperationOptions, cancellationToken); + } /// public async Task DropDatabaseAsync(string name, CancellationToken cancellationToken = default) { + ThrowIfDisposed(); using var session = _operationExecutor.StartImplicitSession(); await DropDatabaseAsync(session, name, cancellationToken).ConfigureAwait(false); } /// public Task DropDatabaseAsync(IClientSessionHandle session, string name, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteWriteOperationAsync( - CreateDropDatabaseOperation(name), - _writeOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: false, - cancellationToken: cancellationToken); + { + ThrowIfDisposed(); + Ensure.IsNotNull(session, nameof(session)); + var opertion = CreateDropDatabaseOperation(name); + return ExecuteWriteOperationAsync(session, opertion, _writeOperationOptions, cancellationToken); + } /// public IMongoDatabase GetDatabase(string name, MongoDatabaseSettings settings = null) @@ -251,6 +255,7 @@ public IAsyncCursor ListDatabaseNames( ListDatabaseNamesOptions options, CancellationToken cancellationToken = default) { + ThrowIfDisposed(); var listDatabasesOptions = CreateListDatabasesOptionsFromListDatabaseNamesOptions(options); var databases = ListDatabases(listDatabasesOptions, cancellationToken); return CreateDatabaseNamesCursor(databases); @@ -268,6 +273,7 @@ public IAsyncCursor ListDatabaseNames( ListDatabaseNamesOptions options, CancellationToken cancellationToken = default) { + ThrowIfDisposed(); var listDatabasesOptions = CreateListDatabasesOptionsFromListDatabaseNamesOptions(options); var databases = ListDatabases(session, listDatabasesOptions, cancellationToken); return CreateDatabaseNamesCursor(databases); @@ -282,6 +288,7 @@ public async Task> ListDatabaseNamesAsync( ListDatabaseNamesOptions options, CancellationToken cancellationToken = default) { + ThrowIfDisposed(); var listDatabasesOptions = CreateListDatabasesOptionsFromListDatabaseNamesOptions(options); var databases = await ListDatabasesAsync(listDatabasesOptions, cancellationToken).ConfigureAwait(false); return CreateDatabaseNamesCursor(databases); @@ -299,6 +306,7 @@ public async Task> ListDatabaseNamesAsync( ListDatabaseNamesOptions options, CancellationToken cancellationToken = default) { + ThrowIfDisposed(); var listDatabasesOptions = CreateListDatabasesOptionsFromListDatabaseNamesOptions(options); var databases = await ListDatabasesAsync(session, listDatabasesOptions, cancellationToken).ConfigureAwait(false); return CreateDatabaseNamesCursor(databases); @@ -307,6 +315,7 @@ public async Task> ListDatabaseNamesAsync( /// public IAsyncCursor ListDatabases(CancellationToken cancellationToken) { + ThrowIfDisposed(); using var session = _operationExecutor.StartImplicitSession(); return ListDatabases(session, cancellationToken); } @@ -316,6 +325,7 @@ public IAsyncCursor ListDatabases( ListDatabasesOptions options, CancellationToken cancellationToken = default) { + ThrowIfDisposed(); using var session = _operationExecutor.StartImplicitSession(); return ListDatabases(session, options, cancellationToken); } @@ -324,28 +334,29 @@ public IAsyncCursor ListDatabases( public IAsyncCursor ListDatabases( IClientSessionHandle session, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperation( - CreateListDatabaseOperation(null), - _readOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: false, - cancellationToken: cancellationToken); + { + ThrowIfDisposed(); + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateListDatabaseOperation(null); + return ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); + } /// public IAsyncCursor ListDatabases( IClientSessionHandle session, ListDatabasesOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperation( - CreateListDatabaseOperation(options), - _readOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: false, - cancellationToken: cancellationToken); + { + ThrowIfDisposed(); + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateListDatabaseOperation(options); + return ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); + } /// public async Task> ListDatabasesAsync(CancellationToken cancellationToken = default) { + ThrowIfDisposed(); using var session = _operationExecutor.StartImplicitSession(); return await ListDatabasesAsync(session, cancellationToken).ConfigureAwait(false); } @@ -355,6 +366,7 @@ public async Task> ListDatabasesAsync( ListDatabasesOptions options, CancellationToken cancellationToken = default) { + ThrowIfDisposed(); using var session = _operationExecutor.StartImplicitSession(); return await ListDatabasesAsync(session, options, cancellationToken).ConfigureAwait(false); } @@ -363,24 +375,24 @@ public async Task> ListDatabasesAsync( public Task> ListDatabasesAsync( IClientSessionHandle session, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperationAsync( - CreateListDatabaseOperation(null), - _readOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: false, - cancellationToken: cancellationToken); + { + ThrowIfDisposed(); + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateListDatabaseOperation(null); + return ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken); + } /// public Task> ListDatabasesAsync( IClientSessionHandle session, ListDatabasesOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperationAsync( - CreateListDatabaseOperation(options), - _readOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: false, - cancellationToken: cancellationToken); + { + ThrowIfDisposed(); + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateListDatabaseOperation(options); + return ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken); + } /// public IClientSessionHandle StartSession(ClientSessionOptions options = null, CancellationToken cancellationToken = default) @@ -404,6 +416,7 @@ public IChangeStreamCursor Watch( ChangeStreamOptions options = null, CancellationToken cancellationToken = default) { + ThrowIfDisposed(); using var session = _operationExecutor.StartImplicitSession(); return Watch(session, pipeline, options, cancellationToken); } @@ -414,12 +427,12 @@ public IChangeStreamCursor Watch( PipelineDefinition, TResult> pipeline, ChangeStreamOptions options = null, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperation( - CreateChangeStreamOperation(pipeline, options), - _readOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: false, - cancellationToken: cancellationToken); + { + ThrowIfDisposed(); + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateChangeStreamOperation(pipeline, options); + return ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); + } /// public async Task> WatchAsync( @@ -427,6 +440,7 @@ public async Task> WatchAsync( ChangeStreamOptions options = null, CancellationToken cancellationToken = default) { + ThrowIfDisposed(); using var session = _operationExecutor.StartImplicitSession(); return await WatchAsync(session, pipeline, options, cancellationToken).ConfigureAwait(false); } @@ -437,12 +451,12 @@ public Task> WatchAsync( PipelineDefinition, TResult> pipeline, ChangeStreamOptions options = null, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperationAsync( - CreateChangeStreamOperation(pipeline, options), - _readOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: false, - cancellationToken: cancellationToken); + { + ThrowIfDisposed(); + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateChangeStreamOperation(pipeline, options); + return ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken); + } /// public IMongoClient WithReadConcern(ReadConcern readConcern) @@ -563,6 +577,18 @@ private ChangeStreamOperation CreateChangeStreamOperation( _settings.RetryReads, _settings.TranslationOptions); + private TResult ExecuteReadOperation(IClientSessionHandle session, IReadOperation operation, ReadOperationOptions options, CancellationToken cancellationToken) + => _operationExecutor.ExecuteReadOperation(session, operation, options, false, cancellationToken); + + private Task ExecuteReadOperationAsync(IClientSessionHandle session, IReadOperation operation, ReadOperationOptions options, CancellationToken cancellationToken) + => _operationExecutor.ExecuteReadOperationAsync(session, operation, options, false, cancellationToken); + + private TResult ExecuteWriteOperation(IClientSessionHandle session, IWriteOperation operation, WriteOperationOptions options, CancellationToken cancellationToken) + => _operationExecutor.ExecuteWriteOperation(session, operation, options, false, cancellationToken); + + private Task ExecuteWriteOperationAsync(IClientSessionHandle session, IWriteOperation operation, WriteOperationOptions options, CancellationToken cancellationToken) + => _operationExecutor.ExecuteWriteOperationAsync(session, operation, options, false, cancellationToken); + private MessageEncoderSettings GetMessageEncoderSettings() { var messageEncoderSettings = new MessageEncoderSettings diff --git a/src/MongoDB.Driver/MongoCollectionImpl.cs b/src/MongoDB.Driver/MongoCollectionImpl.cs index 4b7fb6de65e..12d9d709aad 100644 --- a/src/MongoDB.Driver/MongoCollectionImpl.cs +++ b/src/MongoDB.Driver/MongoCollectionImpl.cs @@ -113,13 +113,13 @@ public override IAsyncCursor Aggregate(IClientSessionHandle se if (isAggregateToCollection) { var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - _operationExecutor.ExecuteWriteOperation(aggregateOperation, _writeOperationOptions, session, true, cancellationToken); + ExecuteWriteOperation(session, aggregateOperation, _writeOperationOptions, cancellationToken); return CreateAggregateToCollectionResultCursor(session, renderedPipeline, options); } else { var aggregateOperation = CreateAggregateOperation(renderedPipeline, options); - return _operationExecutor.ExecuteReadOperation(aggregateOperation, _readOperationOptions, session, true, cancellationToken); + return ExecuteReadOperation(session, aggregateOperation, _readOperationOptions, cancellationToken); } } @@ -140,13 +140,13 @@ public override async Task> AggregateAsync(IClien if (isAggregateToCollection) { var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - await _operationExecutor.ExecuteWriteOperationAsync(aggregateOperation, _writeOperationOptions, session, true, cancellationToken).ConfigureAwait(false); + await ExecuteWriteOperationAsync(session, aggregateOperation, _writeOperationOptions, cancellationToken).ConfigureAwait(false); return CreateAggregateToCollectionResultCursor(session, renderedPipeline, options); } else { var aggregateOperation = CreateAggregateOperation(renderedPipeline, options); - return await _operationExecutor.ExecuteReadOperationAsync(aggregateOperation, _readOperationOptions, session, true, cancellationToken: cancellationToken).ConfigureAwait(false); + return await ExecuteReadOperationAsync(session, aggregateOperation, _readOperationOptions, cancellationToken).ConfigureAwait(false); } } @@ -170,7 +170,7 @@ public override void AggregateToCollection(IClientSessionHandle session } var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - _operationExecutor.ExecuteWriteOperation(aggregateOperation, _writeOperationOptions, session, true, cancellationToken); + ExecuteWriteOperation(session, aggregateOperation, _writeOperationOptions, cancellationToken); } public override async Task AggregateToCollectionAsync(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) @@ -193,7 +193,7 @@ public override async Task AggregateToCollectionAsync(IClientSessionHan } var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - await _operationExecutor.ExecuteWriteOperationAsync(aggregateOperation, _writeOperationOptions, session, true, cancellationToken).ConfigureAwait(false); + await ExecuteWriteOperationAsync(session, aggregateOperation, _writeOperationOptions, cancellationToken).ConfigureAwait(false); } public override BulkWriteResult BulkWrite(IEnumerable> requests, BulkWriteOptions options, CancellationToken cancellationToken = default) @@ -210,7 +210,7 @@ public override BulkWriteResult BulkWrite(IClientSessionHandle sessio var operation = CreateBulkWriteOperation(session, requestsArray, options); try { - var result = _operationExecutor.ExecuteWriteOperation(operation, _writeOperationOptions, session, true, cancellationToken); + var result = ExecuteWriteOperation(session, operation, _writeOperationOptions, cancellationToken); return BulkWriteResult.FromCore(result, requestsArray); } catch (MongoBulkWriteOperationException ex) @@ -233,7 +233,7 @@ public override async Task> BulkWriteAsync(IClientSes var operation = CreateBulkWriteOperation(session, requestsArray, options); try { - var result = await _operationExecutor.ExecuteWriteOperationAsync(operation, _writeOperationOptions, session, true, cancellationToken).ConfigureAwait(false); + var result = await ExecuteWriteOperationAsync(session, operation, _writeOperationOptions, cancellationToken).ConfigureAwait(false); return BulkWriteResult.FromCore(result, requestsArray); } catch (MongoBulkWriteOperationException ex) @@ -251,12 +251,11 @@ public override long Count(FilterDefinition filter, CountOptions opti [Obsolete("Use CountDocuments or EstimatedDocumentCount instead.")] public override long Count(IClientSessionHandle session, FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperation( - CreateCountOperation(filter, options), - _readOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateCountOperation(filter, options); + return ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); + } [Obsolete("Use CountDocumentsAsync or EstimatedDocumentCountAsync instead.")] public override async Task CountAsync(FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) @@ -267,12 +266,11 @@ public override async Task CountAsync(FilterDefinition filter, [Obsolete("Use CountDocumentsAsync or EstimatedDocumentCountAsync instead.")] public override Task CountAsync(IClientSessionHandle session, FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperationAsync( - CreateCountOperation(filter, options), - _readOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateCountOperation(filter, options); + return ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken); + } public override long CountDocuments(FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) { @@ -281,12 +279,11 @@ public override long CountDocuments(FilterDefinition filter, CountOpt } public override long CountDocuments(IClientSessionHandle session, FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperation( - CreateCountDocumentsOperation(filter, options), - _readOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateCountDocumentsOperation(filter, options); + return ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); + } public override async Task CountDocumentsAsync(FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) { @@ -295,12 +292,11 @@ public override async Task CountDocumentsAsync(FilterDefinition } public override Task CountDocumentsAsync(IClientSessionHandle session, FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperationAsync( - CreateCountDocumentsOperation(filter, options), - _readOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateCountDocumentsOperation(filter, options); + return ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken); + } public override IAsyncCursor Distinct(FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) { @@ -309,12 +305,11 @@ public override IAsyncCursor Distinct(FieldDefinition Distinct(IClientSessionHandle session, FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperation( - CreateDistinctOperation(field, filter, options), - _readOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateDistinctOperation(field, filter, options); + return ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); + } public override async Task> DistinctAsync(FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) { @@ -323,12 +318,11 @@ public override async Task> DistinctAsync(FieldDefi } public override Task> DistinctAsync(IClientSessionHandle session, FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperationAsync( - CreateDistinctOperation(field, filter, options), - _readOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateDistinctOperation(field, filter, options); + return ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken); + } public override IAsyncCursor DistinctMany(FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) { @@ -337,12 +331,11 @@ public override IAsyncCursor DistinctMany(FieldDefinition DistinctMany(IClientSessionHandle session, FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperation( - CreateDistinctManyOperation(field, filter, options), - _readOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateDistinctManyOperation(field, filter, options); + return ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); + } public override async Task> DistinctManyAsync(FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) { @@ -351,25 +344,24 @@ public override async Task> DistinctManyAsync(FieldDe } public override Task> DistinctManyAsync(IClientSessionHandle session, FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperationAsync( - CreateDistinctManyOperation(field, filter, options), - _readOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateDistinctManyOperation(field, filter, options); + return ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken); + } public override long EstimatedDocumentCount(EstimatedDocumentCountOptions options, CancellationToken cancellationToken = default) { using var session = _operationExecutor.StartImplicitSession(); var operation = CreateEstimatedDocumentCountOperation(options); - return _operationExecutor.ExecuteReadOperation(operation, _readOperationOptions, session, true, cancellationToken); + return ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); } public override async Task EstimatedDocumentCountAsync(EstimatedDocumentCountOptions options, CancellationToken cancellationToken = default) { using var session = _operationExecutor.StartImplicitSession(); var operation = CreateEstimatedDocumentCountOperation(options); - return await _operationExecutor.ExecuteReadOperationAsync(operation, _readOperationOptions, session, true, cancellationToken).ConfigureAwait(false); + return await ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken).ConfigureAwait(false); } public override IAsyncCursor FindSync(FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default) @@ -379,12 +371,11 @@ public override IAsyncCursor FindSync(FilterDefinition } public override IAsyncCursor FindSync(IClientSessionHandle session, FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperation( - CreateFindOperation(filter, options), - _readOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateFindOperation(filter, options); + return ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); + } public override async Task> FindAsync(FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default) { @@ -393,12 +384,11 @@ public override async Task> FindAsync(Fil } public override Task> FindAsync(IClientSessionHandle session, FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperationAsync( - CreateFindOperation(filter, options), - _readOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateFindOperation(filter, options); + return ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken); + } public override TProjection FindOneAndDelete(FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default) { @@ -407,12 +397,11 @@ public override TProjection FindOneAndDelete(FilterDefinition(IClientSessionHandle session, FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteWriteOperation( - CreateFindOneAndDeleteOperation(filter, options), - _writeOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateFindOneAndDeleteOperation(filter, options); + return ExecuteWriteOperation(session, operation, _writeOperationOptions, cancellationToken); + } public override async Task FindOneAndDeleteAsync(FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default) { @@ -421,12 +410,11 @@ public override async Task FindOneAndDeleteAsync(Filte } public override Task FindOneAndDeleteAsync(IClientSessionHandle session, FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteWriteOperationAsync( - CreateFindOneAndDeleteOperation(filter, options), - _writeOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateFindOneAndDeleteOperation(filter, options); + return ExecuteWriteOperationAsync(session, operation, _writeOperationOptions, cancellationToken); + } public override TProjection FindOneAndReplace(FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default) { @@ -435,12 +423,11 @@ public override TProjection FindOneAndReplace(FilterDefinition(IClientSessionHandle session, FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteWriteOperation( - CreateFindOneAndReplaceOperation(filter, replacement, options), - _writeOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateFindOneAndReplaceOperation(filter, replacement, options); + return ExecuteWriteOperation(session, operation, _writeOperationOptions, cancellationToken); + } public override async Task FindOneAndReplaceAsync(FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default) { @@ -449,12 +436,11 @@ public override async Task FindOneAndReplaceAsync(Filt } public override Task FindOneAndReplaceAsync(IClientSessionHandle session, FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteWriteOperationAsync( - CreateFindOneAndReplaceOperation(filter, replacement, options), - _writeOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateFindOneAndReplaceOperation(filter, replacement, options); + return ExecuteWriteOperationAsync(session, operation, _writeOperationOptions, cancellationToken); + } public override TProjection FindOneAndUpdate(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default) { @@ -463,12 +449,11 @@ public override TProjection FindOneAndUpdate(FilterDefinition(IClientSessionHandle session, FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteWriteOperation( - CreateFindOneAndUpdateOperation(filter, update, options), - _writeOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateFindOneAndUpdateOperation(filter, update, options); + return ExecuteWriteOperation(session, operation, _writeOperationOptions, cancellationToken); + } public override async Task FindOneAndUpdateAsync(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default) { @@ -477,12 +462,11 @@ public override async Task FindOneAndUpdateAsync(Filte } public override Task FindOneAndUpdateAsync(IClientSessionHandle session, FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteWriteOperationAsync( - CreateFindOneAndUpdateOperation(filter, update, options), - _writeOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateFindOneAndUpdateOperation(filter, update, options); + return ExecuteWriteOperationAsync(session, operation, _writeOperationOptions, cancellationToken); + } [Obsolete("Use Aggregation pipeline instead.")] public override IAsyncCursor MapReduce(BsonJavaScript map, BsonJavaScript reduce, MapReduceOptions options = null, CancellationToken cancellationToken = default) @@ -506,12 +490,12 @@ public override IAsyncCursor MapReduce(IClientSessionHandle se if (outputOptions == MapReduceOutputOptions.Inline) { var operation = CreateMapReduceOperation(map, reduce, options, resultSerializer, renderArgs); - return _operationExecutor.ExecuteReadOperation(operation, _readOperationOptions, session, true, cancellationToken); + return ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); } else { var mapReduceOperation = CreateMapReduceOutputToCollectionOperation(map, reduce, options, outputOptions, renderArgs); - _operationExecutor.ExecuteWriteOperation(mapReduceOperation, _writeOperationOptions, session, true, cancellationToken); + ExecuteWriteOperation(session, mapReduceOperation, _writeOperationOptions, cancellationToken); return CreateMapReduceOutputToCollectionResultCursor(session, options, mapReduceOperation.OutputCollectionNamespace, resultSerializer); } } @@ -538,12 +522,12 @@ public override async Task> MapReduceAsync(IClien if (outputOptions == MapReduceOutputOptions.Inline) { var operation = CreateMapReduceOperation(map, reduce, options, resultSerializer, renderArgs); - return await _operationExecutor.ExecuteReadOperationAsync(operation, _readOperationOptions, session, true, cancellationToken).ConfigureAwait(false); + return await ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken).ConfigureAwait(false); } else { var mapReduceOperation = CreateMapReduceOutputToCollectionOperation(map, reduce, options, outputOptions, renderArgs); - await _operationExecutor.ExecuteWriteOperationAsync(mapReduceOperation, _writeOperationOptions, session, true, cancellationToken).ConfigureAwait(false); + await ExecuteWriteOperationAsync(session, mapReduceOperation, _writeOperationOptions, cancellationToken).ConfigureAwait(false); return CreateMapReduceOutputToCollectionResultCursor(session, options, mapReduceOperation.OutputCollectionNamespace, resultSerializer); } } @@ -576,12 +560,11 @@ public override IChangeStreamCursor Watch( PipelineDefinition, TResult> pipeline, ChangeStreamOptions options = null, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperation( - CreateChangeStreamOperation(pipeline, options), - _readOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateChangeStreamOperation(pipeline, options); + return ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); + } public override async Task> WatchAsync( PipelineDefinition, TResult> pipeline, @@ -597,12 +580,11 @@ public override Task> WatchAsync( PipelineDefinition, TResult> pipeline, ChangeStreamOptions options = null, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperationAsync( - CreateChangeStreamOperation(pipeline, options), - _readOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateChangeStreamOperation(pipeline, options); + return ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken); + } public override IMongoCollection WithReadConcern(ReadConcern readConcern) { @@ -749,8 +731,8 @@ private IAsyncCursor CreateAggregateToCollectionResultCursor(I var readOperationOptions = _readOperationOptions with { ExplicitReadPreference = ReadPreference.Primary }; var deferredCursor = new DeferredAsyncCursor( () => forkedSession.Dispose(), - ct => _operationExecutor.ExecuteReadOperation(findOperation, readOperationOptions, forkedSession, true, ct), - ct => _operationExecutor.ExecuteReadOperationAsync(findOperation, readOperationOptions, forkedSession, true, ct)); + ct => ExecuteReadOperation(forkedSession, findOperation, readOperationOptions, ct), + ct => ExecuteReadOperationAsync(forkedSession, findOperation, readOperationOptions, ct)); return deferredCursor; } @@ -1179,11 +1161,24 @@ private IAsyncCursor CreateMapReduceOutputToCollectionResultCursor( () => forkedSession.Dispose(), - ct => _operationExecutor.ExecuteReadOperation(findOperation, readOperationOptions, forkedSession, true, ct), - ct => _operationExecutor.ExecuteReadOperationAsync(findOperation, readOperationOptions, forkedSession, true, ct)); + ct => ExecuteReadOperation(forkedSession, findOperation, readOperationOptions, ct), + ct => ExecuteReadOperationAsync(forkedSession, findOperation, readOperationOptions, ct)); return deferredCursor; } + private TResult ExecuteReadOperation(IClientSessionHandle session, IReadOperation operation, ReadOperationOptions options, CancellationToken cancellationToken) + => _operationExecutor.ExecuteReadOperation(session, operation, options, true, cancellationToken); + + private Task ExecuteReadOperationAsync(IClientSessionHandle session, IReadOperation operation, ReadOperationOptions options, CancellationToken cancellationToken) + => _operationExecutor.ExecuteReadOperationAsync(session, operation, options, true, cancellationToken); + + private TResult ExecuteWriteOperation(IClientSessionHandle session, IWriteOperation operation, WriteOperationOptions options, CancellationToken cancellationToken) + => _operationExecutor.ExecuteWriteOperation(session, operation, options, true, cancellationToken); + + private Task ExecuteWriteOperationAsync(IClientSessionHandle session, IWriteOperation operation, WriteOperationOptions options, CancellationToken cancellationToken) + => _operationExecutor.ExecuteWriteOperationAsync(session, operation, options, true, cancellationToken); + + private MessageEncoderSettings GetMessageEncoderSettings() { var messageEncoderSettings = new MessageEncoderSettings @@ -1343,7 +1338,7 @@ public override IEnumerable CreateMany( Ensure.IsNotNull(session, nameof(session)); var operation = CreateCreateIndexesOperation(models, options); - _collection._operationExecutor.ExecuteWriteOperation(operation, _collection._writeOperationOptions, session, true, cancellationToken); + _collection.ExecuteWriteOperation(session, operation, _collection._writeOperationOptions, cancellationToken); return operation.Requests.Select(x => x.GetIndexName()); } @@ -1371,7 +1366,7 @@ public override async Task> CreateManyAsync( Ensure.IsNotNull(session, nameof(session)); var operation = CreateCreateIndexesOperation(models, options); - await _collection._operationExecutor.ExecuteWriteOperationAsync(operation, _collection._writeOperationOptions, session, true, cancellationToken).ConfigureAwait(false); + await _collection.ExecuteWriteOperationAsync(session, operation, _collection._writeOperationOptions, cancellationToken).ConfigureAwait(false); return operation.Requests.Select(x => x.GetIndexName()); } @@ -1388,12 +1383,11 @@ public override void DropAll(IClientSessionHandle session, CancellationToken can => DropAll(session, null, cancellationToken); public override void DropAll(IClientSessionHandle session, DropIndexOptions options, CancellationToken cancellationToken = default) - => _collection._operationExecutor.ExecuteWriteOperation( - CreateDropAllOperation(options), - _collection._writeOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateDropAllOperation(options); + _collection.ExecuteWriteOperation(session, operation, _collection._writeOperationOptions, cancellationToken); + } public override Task DropAllAsync(CancellationToken cancellationToken) => DropAllAsync(options: null, cancellationToken); @@ -1408,12 +1402,11 @@ public override Task DropAllAsync(IClientSessionHandle session, CancellationToke => DropAllAsync(session, null, cancellationToken); public override Task DropAllAsync(IClientSessionHandle session, DropIndexOptions options, CancellationToken cancellationToken = default) - => _collection._operationExecutor.ExecuteWriteOperationAsync( - CreateDropAllOperation(options), - _collection._writeOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateDropAllOperation(options); + return _collection.ExecuteWriteOperationAsync(session, operation, _collection._writeOperationOptions, cancellationToken); + } public override void DropOne(string name, CancellationToken cancellationToken = default) => DropOne(name, null, cancellationToken); @@ -1428,12 +1421,11 @@ public override void DropOne(IClientSessionHandle session, string name, Cancella => DropOne(session, name, null, cancellationToken); public override void DropOne(IClientSessionHandle session, string name, DropIndexOptions options, CancellationToken cancellationToken) - => _collection._operationExecutor.ExecuteWriteOperation( - CreateDropOneOperation(name, options), - _collection._writeOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateDropOneOperation(name, options); + _collection.ExecuteWriteOperation(session, operation, _collection._writeOperationOptions, cancellationToken); + } public override Task DropOneAsync(string name, CancellationToken cancellationToken = default) => DropOneAsync(name, null, cancellationToken); @@ -1448,12 +1440,11 @@ public override Task DropOneAsync(IClientSessionHandle session, string name, Can => DropOneAsync(session, name, null, cancellationToken); public override Task DropOneAsync(IClientSessionHandle session, string name, DropIndexOptions options, CancellationToken cancellationToken) - => _collection._operationExecutor.ExecuteWriteOperationAsync( - CreateDropOneOperation(name, options), - _collection._writeOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateDropOneOperation(name, options); + return _collection.ExecuteWriteOperationAsync(session, operation, _collection._writeOperationOptions, cancellationToken); + } public override IAsyncCursor List(CancellationToken cancellationToken = default) => List(options: null, cancellationToken); @@ -1468,12 +1459,11 @@ public override IAsyncCursor List(IClientSessionHandle session, Ca => List(session, options: null, cancellationToken); public override IAsyncCursor List(IClientSessionHandle session, ListIndexesOptions options, CancellationToken cancellationToken = default) - => _collection._operationExecutor.ExecuteReadOperation( - CreateListIndexesOperation(options), - _collection._readOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateListIndexesOperation(options); + return _collection.ExecuteReadOperation(session, operation, _collection._readOperationOptions, cancellationToken); + } public override Task> ListAsync(CancellationToken cancellationToken = default) => ListAsync(options: null, cancellationToken); @@ -1488,12 +1478,11 @@ public override Task> ListAsync(IClientSessionHandle => ListAsync(session, options: null, cancellationToken); public override Task> ListAsync(IClientSessionHandle session, ListIndexesOptions options, CancellationToken cancellationToken = default) - => _collection._operationExecutor.ExecuteReadOperationAsync( - CreateListIndexesOperation(options), - _collection._readOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateListIndexesOperation(options); + return _collection.ExecuteReadOperationAsync(session, operation, _collection._readOperationOptions, cancellationToken); + } // private methods private CreateIndexesOperation CreateCreateIndexesOperation(IEnumerable> models, CreateManyIndexesOptions options) @@ -1600,7 +1589,7 @@ public IEnumerable CreateMany(IEnumerable models { using var session = _collection._operationExecutor.StartImplicitSession(); var operation = CreateCreateIndexesOperation(models); - var result = _collection._operationExecutor.ExecuteWriteOperation(operation, _collection._writeOperationOptions, session, true, cancellationToken); + var result = _collection.ExecuteWriteOperation(session, operation, _collection._writeOperationOptions, cancellationToken); return GetIndexNames(result); } @@ -1608,7 +1597,7 @@ public async Task> CreateManyAsync(IEnumerable List(string indexName, AggregateOptions aggregateOptions = null, CancellationToken cancellationToken = default) @@ -1658,14 +1647,14 @@ public void Update(string indexName, BsonDocument definition, CancellationToken { using var session = _collection._operationExecutor.StartImplicitSession(); var operation = new UpdateSearchIndexOperation(_collection.CollectionNamespace, indexName, definition, _collection._messageEncoderSettings); - _collection._operationExecutor.ExecuteWriteOperation(operation, _collection._writeOperationOptions, session, true, cancellationToken); + _collection.ExecuteWriteOperation(session, operation, _collection._writeOperationOptions, cancellationToken); } public async Task UpdateAsync(string indexName, BsonDocument definition, CancellationToken cancellationToken = default) { using var session = _collection._operationExecutor.StartImplicitSession(); var operation = new UpdateSearchIndexOperation(_collection.CollectionNamespace, indexName, definition, _collection._messageEncoderSettings); - await _collection._operationExecutor.ExecuteWriteOperationAsync(operation, _collection._writeOperationOptions, session, true, cancellationToken).ConfigureAwait(false); + await _collection.ExecuteWriteOperationAsync(session, operation, _collection._writeOperationOptions, cancellationToken).ConfigureAwait(false); } // private methods diff --git a/src/MongoDB.Driver/MongoDatabase.cs b/src/MongoDB.Driver/MongoDatabase.cs index 6e3d6222243..599815c9521 100644 --- a/src/MongoDB.Driver/MongoDatabase.cs +++ b/src/MongoDB.Driver/MongoDatabase.cs @@ -78,13 +78,13 @@ public IAsyncCursor Aggregate(IClientSessionHandle session, Pi if (isAggregateToCollection) { var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - _operationExecutor.ExecuteWriteOperation(aggregateOperation, _writeOperationOptions, session, true, cancellationToken); + ExecuteWriteOperation(session, aggregateOperation, _writeOperationOptions, cancellationToken); return CreateAggregateToCollectionResultCursor(session, renderedPipeline, options); } else { var aggregateOperation = CreateAggregateOperation(renderedPipeline, options); - return _operationExecutor.ExecuteReadOperation(aggregateOperation, _readOperationOptions, session, true, cancellationToken); + return ExecuteReadOperation(session, aggregateOperation, _readOperationOptions, cancellationToken); } } @@ -105,13 +105,13 @@ public async Task> AggregateAsync(IClientSessionH if (isAggregateToCollection) { var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - await _operationExecutor.ExecuteWriteOperationAsync(aggregateOperation, _writeOperationOptions, session, true, cancellationToken).ConfigureAwait(false); + await ExecuteWriteOperationAsync(session, aggregateOperation, _writeOperationOptions, cancellationToken).ConfigureAwait(false); return CreateAggregateToCollectionResultCursor(session, renderedPipeline, options); } else { var aggregateOperation = CreateAggregateOperation(renderedPipeline, options); - return await _operationExecutor.ExecuteReadOperationAsync(aggregateOperation, _readOperationOptions, session, true, cancellationToken).ConfigureAwait(false); + return await ExecuteReadOperationAsync(session, aggregateOperation, _readOperationOptions, cancellationToken).ConfigureAwait(false); } } @@ -135,7 +135,7 @@ public void AggregateToCollection(IClientSessionHandle session, Pipelin } var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - _operationExecutor.ExecuteWriteOperation(aggregateOperation, _writeOperationOptions, session, true, cancellationToken); + ExecuteWriteOperation(session, aggregateOperation, _writeOperationOptions, cancellationToken); } public async Task AggregateToCollectionAsync(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) @@ -144,7 +144,7 @@ public async Task AggregateToCollectionAsync(PipelineDefinition(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) + public Task AggregateToCollectionAsync(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); Ensure.IsNotNull(pipeline, nameof(pipeline)); @@ -158,7 +158,7 @@ public async Task AggregateToCollectionAsync(IClientSessionHandle sessi } var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - await _operationExecutor.ExecuteWriteOperationAsync(aggregateOperation, _writeOperationOptions, session, true, cancellationToken).ConfigureAwait(false); + return ExecuteWriteOperationAsync(session, aggregateOperation, _writeOperationOptions, cancellationToken); } public void CreateCollection(string name, CreateCollectionOptions options, CancellationToken cancellationToken) @@ -242,12 +242,11 @@ public void CreateView(string viewName, string viewOn, Pipel } public void CreateView(IClientSessionHandle session, string viewName, string viewOn, PipelineDefinition pipeline, CreateViewOptions options = null, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteWriteOperation( - CreateCreateViewOperation(viewName, viewOn, pipeline, options), - _writeOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateCreateViewOperation(viewName, viewOn, pipeline, options); + ExecuteWriteOperation(session, operation, _writeOperationOptions, cancellationToken); + } public async Task CreateViewAsync(string viewName, string viewOn, PipelineDefinition pipeline, CreateViewOptions options = null, CancellationToken cancellationToken = default) { @@ -256,12 +255,11 @@ public async Task CreateViewAsync(string viewName, string vi } public Task CreateViewAsync(IClientSessionHandle session, string viewName, string viewOn, PipelineDefinition pipeline, CreateViewOptions options = null, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteWriteOperationAsync( - CreateCreateViewOperation(viewName, viewOn, pipeline, options), - _writeOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateCreateViewOperation(viewName, viewOn, pipeline, options); + return ExecuteWriteOperationAsync(session, operation,_writeOperationOptions, cancellationToken); + } public void DropCollection(string name, CancellationToken cancellationToken) { @@ -287,7 +285,7 @@ public void DropCollection(IClientSessionHandle session, string name, DropCollec var collectionNamespace = new CollectionNamespace(_databaseNamespace, name); var encryptedFields = GetEncryptedFields(session, collectionNamespace, options, cancellationToken); var operation = CreateDropCollectionOperation(collectionNamespace, encryptedFields); - _operationExecutor.ExecuteWriteOperation(operation, _writeOperationOptions, session, true, cancellationToken); + ExecuteWriteOperation(session, operation, _writeOperationOptions, cancellationToken); } public Task DropCollectionAsync(string name, CancellationToken cancellationToken) @@ -310,7 +308,7 @@ public async Task DropCollectionAsync(IClientSessionHandle session, string name, var collectionNamespace = new CollectionNamespace(_databaseNamespace, name); var encryptedFields = await GetEncryptedFieldsAsync(session, collectionNamespace, options, cancellationToken).ConfigureAwait(false); var operation = CreateDropCollectionOperation(collectionNamespace, encryptedFields); - await _operationExecutor.ExecuteWriteOperationAsync(operation, _writeOperationOptions, session, true, cancellationToken).ConfigureAwait(false); + await ExecuteWriteOperationAsync(session, operation, _writeOperationOptions, cancellationToken).ConfigureAwait(false); } public IMongoCollection GetCollection(string name, MongoCollectionSettings settings) @@ -334,12 +332,9 @@ public IAsyncCursor ListCollectionNames(ListCollectionNamesOptions optio public IAsyncCursor ListCollectionNames(IClientSessionHandle session, ListCollectionNamesOptions options = null, CancellationToken cancellationToken = default) { - var cursor = _operationExecutor.ExecuteReadOperation( - CreateListCollectionNamesOperation(options), - _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateListCollectionNamesOperation(options); + var cursor = ExecuteReadOperation(session, operation, _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, cancellationToken); return new BatchTransformingAsyncCursor(cursor, ExtractCollectionNames); } @@ -351,12 +346,9 @@ public async Task> ListCollectionNamesAsync(ListCollectionN public async Task> ListCollectionNamesAsync(IClientSessionHandle session, ListCollectionNamesOptions options = null, CancellationToken cancellationToken = default) { - var cursor = await _operationExecutor.ExecuteReadOperationAsync( - CreateListCollectionNamesOperation(options), - _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken).ConfigureAwait(false); + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateListCollectionNamesOperation(options); + var cursor = await ExecuteReadOperationAsync(session, operation, _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, cancellationToken).ConfigureAwait(false); return new BatchTransformingAsyncCursor(cursor, ExtractCollectionNames); } @@ -367,12 +359,11 @@ public IAsyncCursor ListCollections(ListCollectionsOptions options } public IAsyncCursor ListCollections(IClientSessionHandle session, ListCollectionsOptions options, CancellationToken cancellationToken) - => _operationExecutor.ExecuteReadOperation( - CreateListCollectionsOperation(options), - _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateListCollectionsOperation(options); + return ExecuteReadOperation(session, operation, _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, cancellationToken); + } public async Task> ListCollectionsAsync(ListCollectionsOptions options, CancellationToken cancellationToken) { @@ -381,12 +372,11 @@ public async Task> ListCollectionsAsync(ListCollectio } public Task> ListCollectionsAsync(IClientSessionHandle session, ListCollectionsOptions options, CancellationToken cancellationToken) - => _operationExecutor.ExecuteReadOperationAsync( - CreateListCollectionsOperation(options), - _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateListCollectionsOperation(options); + return ExecuteReadOperationAsync(session, operation, _readOperationOptions with { DefaultReadPreference = ReadPreference.Primary }, cancellationToken); + } public void RenameCollection(string oldName, string newName, RenameCollectionOptions options, CancellationToken cancellationToken) { @@ -395,12 +385,11 @@ public void RenameCollection(string oldName, string newName, RenameCollectionOpt } public void RenameCollection(IClientSessionHandle session, string oldName, string newName, RenameCollectionOptions options, CancellationToken cancellationToken) - => _operationExecutor.ExecuteWriteOperation( - CreateRenameCollectionOperation(oldName, newName, options), - _writeOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateRenameCollectionOperation(oldName, newName, options); + ExecuteWriteOperation(session, operation, _writeOperationOptions, cancellationToken); + } public async Task RenameCollectionAsync(string oldName, string newName, RenameCollectionOptions options, CancellationToken cancellationToken) { @@ -409,12 +398,11 @@ public async Task RenameCollectionAsync(string oldName, string newName, RenameCo } public Task RenameCollectionAsync(IClientSessionHandle session, string oldName, string newName, RenameCollectionOptions options, CancellationToken cancellationToken) - => _operationExecutor.ExecuteWriteOperationAsync( - CreateRenameCollectionOperation(oldName, newName, options), - _writeOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateRenameCollectionOperation(oldName, newName, options); + return ExecuteWriteOperationAsync(session, operation, _writeOperationOptions, cancellationToken); + } public TResult RunCommand(Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default) { @@ -423,12 +411,11 @@ public TResult RunCommand(Command command, ReadPreference read } public TResult RunCommand(IClientSessionHandle session, Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperation( - CreateRunCommandOperation(command), - _readOperationOptions with { ExplicitReadPreference = readPreference, DefaultReadPreference = ReadPreference.Primary}, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateRunCommandOperation(command); + return ExecuteReadOperation(session, operation, _readOperationOptions with { ExplicitReadPreference = readPreference, DefaultReadPreference = ReadPreference.Primary }, cancellationToken); + } public async Task RunCommandAsync(Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default) { @@ -437,12 +424,11 @@ public async Task RunCommandAsync(Command command, Re } public Task RunCommandAsync(IClientSessionHandle session, Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperationAsync( - CreateRunCommandOperation(command), - _readOperationOptions with { ExplicitReadPreference = readPreference, DefaultReadPreference = ReadPreference.Primary}, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateRunCommandOperation(command); + return ExecuteReadOperationAsync(session, operation, _readOperationOptions with { ExplicitReadPreference = readPreference, DefaultReadPreference = ReadPreference.Primary }, cancellationToken); + } public IChangeStreamCursor Watch( PipelineDefinition, TResult> pipeline, @@ -458,12 +444,11 @@ public IChangeStreamCursor Watch( PipelineDefinition, TResult> pipeline, ChangeStreamOptions options = null, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperation( - CreateChangeStreamOperation(pipeline, options), - _readOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateChangeStreamOperation(pipeline, options); + return ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); + } public async Task> WatchAsync( PipelineDefinition, TResult> pipeline, @@ -479,12 +464,11 @@ public Task> WatchAsync( PipelineDefinition, TResult> pipeline, ChangeStreamOptions options = null, CancellationToken cancellationToken = default) - => _operationExecutor.ExecuteReadOperationAsync( - CreateChangeStreamOperation(pipeline, options), - _readOperationOptions, - Ensure.IsNotNull(session, nameof(session)), - allowChannelPinning: true, - cancellationToken: cancellationToken); + { + Ensure.IsNotNull(session, nameof(session)); + var operation = CreateChangeStreamOperation(pipeline, options); + return ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken); + } public IMongoDatabase WithReadConcern(ReadConcern readConcern) { @@ -561,8 +545,8 @@ private IAsyncCursor CreateAggregateToCollectionResultCursor(I var readOperationOptions = _readOperationOptions with { ExplicitReadPreference = ReadPreference.Primary }; var deferredCursor = new DeferredAsyncCursor( () => forkedSession.Dispose(), - ct => _operationExecutor.ExecuteReadOperation(findOperation, readOperationOptions, forkedSession, true, cancellationToken: ct), - ct => _operationExecutor.ExecuteReadOperationAsync(findOperation, readOperationOptions, forkedSession, true, cancellationToken: ct)); + ct => ExecuteReadOperation(forkedSession, findOperation, readOperationOptions, ct), + ct => ExecuteReadOperationAsync(forkedSession, findOperation, readOperationOptions, ct)); return deferredCursor; } @@ -588,20 +572,16 @@ private AggregateToCollectionOperation CreateAggregateToCollectionOperation(IClientSessionHandle session, string name, CreateCollectionOptions options, CancellationToken cancellationToken) - => _operationExecutor.ExecuteWriteOperation( - CreateCreateCollectionOperation(name, options), - _writeOperationOptions, - session, - allowChannelPinning: true, - cancellationToken); + { + var operation = CreateCreateCollectionOperation(name, options); + ExecuteWriteOperation(session, operation, _writeOperationOptions, cancellationToken); + } private Task CreateCollectionHelperAsync(IClientSessionHandle session, string name, CreateCollectionOptions options, CancellationToken cancellationToken) - => _operationExecutor.ExecuteWriteOperationAsync( - CreateCreateCollectionOperation(name, options), - _writeOperationOptions, - session, - allowChannelPinning: true, - cancellationToken); + { + var operation = CreateCreateCollectionOperation(name, options); + return ExecuteWriteOperationAsync(session, operation, _writeOperationOptions, cancellationToken); + } private IWriteOperation CreateCreateCollectionOperation(string name, CreateCollectionOptions options) { @@ -750,12 +730,23 @@ private ChangeStreamOperation CreateChangeStreamOperation( translationOptions); } + private TResult ExecuteReadOperation(IClientSessionHandle session, IReadOperation operation, ReadOperationOptions options, CancellationToken cancellationToken) + => _operationExecutor.ExecuteReadOperation(session, operation, options, true, cancellationToken); + + private Task ExecuteReadOperationAsync(IClientSessionHandle session, IReadOperation operation, ReadOperationOptions options, CancellationToken cancellationToken) + => _operationExecutor.ExecuteReadOperationAsync(session, operation, options, true, cancellationToken); + + private TResult ExecuteWriteOperation(IClientSessionHandle session, IWriteOperation operation, WriteOperationOptions options, CancellationToken cancellationToken) + => _operationExecutor.ExecuteWriteOperation(session, operation, options, true, cancellationToken); + + private Task ExecuteWriteOperationAsync(IClientSessionHandle session, IWriteOperation operation, WriteOperationOptions options, CancellationToken cancellationToken) + => _operationExecutor.ExecuteWriteOperationAsync(session, operation, options, true, cancellationToken); + private IEnumerable ExtractCollectionNames(IEnumerable collections) { return collections.Select(collection => collection["name"].AsString); } - private BsonDocument GetEncryptedFields(IClientSessionHandle session, CollectionNamespace collectionNamespace, DropCollectionOptions options, CancellationToken cancellationToken) { var encryptedFieldsMap = _client.Settings?.AutoEncryptionOptions?.EncryptedFieldsMap; diff --git a/src/MongoDB.Driver/OperationExecutor.cs b/src/MongoDB.Driver/OperationExecutor.cs index eae6c39ae07..c5d1b457ce9 100644 --- a/src/MongoDB.Driver/OperationExecutor.cs +++ b/src/MongoDB.Driver/OperationExecutor.cs @@ -39,9 +39,9 @@ public void Dispose() } public TResult ExecuteReadOperation( + IClientSessionHandle session, IReadOperation operation, ReadOperationOptions options, - IClientSessionHandle session, bool allowChannelPinning, CancellationToken cancellationToken) { @@ -56,9 +56,9 @@ public TResult ExecuteReadOperation( } public async Task ExecuteReadOperationAsync( + IClientSessionHandle session, IReadOperation operation, ReadOperationOptions options, - IClientSessionHandle session, bool allowChannelPinning, CancellationToken cancellationToken) { @@ -73,9 +73,9 @@ public async Task ExecuteReadOperationAsync( } public TResult ExecuteWriteOperation( + IClientSessionHandle session, IWriteOperation operation, WriteOperationOptions options, - IClientSessionHandle session, bool allowChannelPinning, CancellationToken cancellationToken) { @@ -89,9 +89,9 @@ public TResult ExecuteWriteOperation( } public async Task ExecuteWriteOperationAsync( + IClientSessionHandle session, IWriteOperation operation, WriteOperationOptions options, - IClientSessionHandle session, bool allowChannelPinning, CancellationToken cancellationToken) { @@ -128,15 +128,15 @@ private IReadBindingHandle CreateReadBinding(IClientSessionHandle session, ReadP return new ReadBindingHandle(binding); } - private IReadWriteBindingHandle CreateReadWriteBinding(IClientSessionHandle session, bool disableChannelPinning) + private IReadWriteBindingHandle CreateReadWriteBinding(IClientSessionHandle session, bool allowChannelPinning) { - if (disableChannelPinning) + if (allowChannelPinning) { - var binding = new WritableServerBinding(_client.GetClusterInternal(), session.WrappedCoreSession.Fork()); - return new ReadWriteBindingHandle(binding); + return ChannelPinningHelper.CreateReadWriteBinding(_client.GetClusterInternal(), session.WrappedCoreSession.Fork()); } - return ChannelPinningHelper.CreateReadWriteBinding(_client.GetClusterInternal(), session.WrappedCoreSession.Fork()); + var binding = new WritableServerBinding(_client.GetClusterInternal(), session.WrappedCoreSession.Fork()); + return new ReadWriteBindingHandle(binding); } private void ThrowIfDisposed() diff --git a/tests/MongoDB.Driver.Tests/MockOperationExecutor.cs b/tests/MongoDB.Driver.Tests/MockOperationExecutor.cs index 197b5acc0ab..6abf665a10e 100644 --- a/tests/MongoDB.Driver.Tests/MockOperationExecutor.cs +++ b/tests/MongoDB.Driver.Tests/MockOperationExecutor.cs @@ -62,9 +62,10 @@ public void EnqueueException(Exception exception) _results.Enqueue(exception); } - public TResult ExecuteReadOperation(IReadOperation operation, - ReadOperationOptions readOperationOptions, + public TResult ExecuteReadOperation( IClientSessionHandle session, + IReadOperation operation, + ReadOperationOptions readOperationOptions, bool allowChannelPinning, CancellationToken cancellationToken) { @@ -93,15 +94,16 @@ public TResult ExecuteReadOperation(IReadOperation operation, return default(TResult); } - public Task ExecuteReadOperationAsync(IReadOperation operation, - ReadOperationOptions readOperationOptions, + public Task ExecuteReadOperationAsync( IClientSessionHandle session, + IReadOperation operation, + ReadOperationOptions readOperationOptions, bool allowChannelPinning, CancellationToken cancellationToken) { try { - var result = ExecuteReadOperation(operation, readOperationOptions, session, allowChannelPinning, cancellationToken); + var result = ExecuteReadOperation(session, operation, readOperationOptions, allowChannelPinning, cancellationToken); return Task.FromResult(result); } catch (Exception ex) @@ -112,9 +114,10 @@ public Task ExecuteReadOperationAsync(IReadOperation } } - public TResult ExecuteWriteOperation(IWriteOperation operation, - WriteOperationOptions writeOperationOptions, + public TResult ExecuteWriteOperation( IClientSessionHandle session, + IWriteOperation operation, + WriteOperationOptions writeOperationOptions, bool allowChannelPinning, CancellationToken cancellationToken) { @@ -143,15 +146,16 @@ public TResult ExecuteWriteOperation(IWriteOperation operation return default(TResult); } - public Task ExecuteWriteOperationAsync(IWriteOperation operation, - WriteOperationOptions writeOperationOptions, + public Task ExecuteWriteOperationAsync( IClientSessionHandle session, + IWriteOperation operation, + WriteOperationOptions writeOperationOptions, bool allowChannelPinning, CancellationToken cancellationToken) { try { - var result = ExecuteWriteOperation(operation, writeOperationOptions, session, allowChannelPinning, cancellationToken); + var result = ExecuteWriteOperation(session, operation, writeOperationOptions, allowChannelPinning, cancellationToken); return Task.FromResult(result); } catch (Exception ex) diff --git a/tests/MongoDB.Driver.Tests/OperationExecutorTests.cs b/tests/MongoDB.Driver.Tests/OperationExecutorTests.cs index b8cc379f9c3..ef207d784f6 100644 --- a/tests/MongoDB.Driver.Tests/OperationExecutorTests.cs +++ b/tests/MongoDB.Driver.Tests/OperationExecutorTests.cs @@ -47,8 +47,8 @@ public async Task ExecuteReadOperation_throws_on_null_operation([Values(true, fa var session = Mock.Of(); var exception = async ? - await Record.ExceptionAsync(() => subject.ExecuteReadOperationAsync(null, options, session, true, CancellationToken.None)) : - Record.Exception(() => subject.ExecuteReadOperation(null, options, session, true, CancellationToken.None)); + await Record.ExceptionAsync(() => subject.ExecuteReadOperationAsync(session, null, options, true, CancellationToken.None)) : + Record.Exception(() => subject.ExecuteReadOperation(session, null, options, true, CancellationToken.None)); exception.Should().BeOfType() .Subject.ParamName.Should().Be("operation"); @@ -63,8 +63,8 @@ public async Task ExecuteReadOperation_throws_on_null_options([Values(true, fals var session = Mock.Of(); var exception = async ? - await Record.ExceptionAsync(() => subject.ExecuteReadOperationAsync(operation, null, session, true, CancellationToken.None)) : - Record.Exception(() => subject.ExecuteReadOperation(operation, null, session, true, CancellationToken.None)); + await Record.ExceptionAsync(() => subject.ExecuteReadOperationAsync(session, operation, null, true, CancellationToken.None)) : + Record.Exception(() => subject.ExecuteReadOperation(session, operation, null, true, CancellationToken.None)); exception.Should().BeOfType() .Subject.ParamName.Should().Be("options"); @@ -79,8 +79,8 @@ public async Task ExecuteReadOperation_throws_on_null_session([Values(true, fals var options = new ReadOperationOptions(); var exception = async ? - await Record.ExceptionAsync(() => subject.ExecuteReadOperationAsync(operation, options, null, true, CancellationToken.None)) : - Record.Exception(() => subject.ExecuteReadOperation(operation, options, null, true, CancellationToken.None)); + await Record.ExceptionAsync(() => subject.ExecuteReadOperationAsync(null, operation, options, true, CancellationToken.None)) : + Record.Exception(() => subject.ExecuteReadOperation(null, operation, options, true, CancellationToken.None)); exception.Should().BeOfType() .Subject.ParamName.Should().Be("session"); @@ -95,8 +95,8 @@ public async Task ExecuteWriteOperation_throws_on_null_operation([Values(true, f var session = Mock.Of(); var exception = async ? - await Record.ExceptionAsync(() => subject.ExecuteWriteOperationAsync(null, options, session, true, CancellationToken.None)) : - Record.Exception(() => subject.ExecuteWriteOperation(null, options, session, true, CancellationToken.None)); + await Record.ExceptionAsync(() => subject.ExecuteWriteOperationAsync(session, null, options, true, CancellationToken.None)) : + Record.Exception(() => subject.ExecuteWriteOperation(session, null, options, true, CancellationToken.None)); exception.Should().BeOfType() .Subject.ParamName.Should().Be("operation"); @@ -111,8 +111,8 @@ public async Task ExecuteWriteOperation_throws_on_null_options([Values(true, fal var session = Mock.Of(); var exception = async ? - await Record.ExceptionAsync(() => subject.ExecuteWriteOperationAsync(operation, null, session, true, CancellationToken.None)) : - Record.Exception(() => subject.ExecuteWriteOperation(operation, null, session, true, CancellationToken.None)); + await Record.ExceptionAsync(() => subject.ExecuteWriteOperationAsync(session, operation, null, true, CancellationToken.None)) : + Record.Exception(() => subject.ExecuteWriteOperation(session, operation, null, true, CancellationToken.None)); exception.Should().BeOfType() .Subject.ParamName.Should().Be("options"); @@ -127,8 +127,8 @@ public async Task ExecuteWriteOperation_throws_on_null_session([Values(true, fal var options = new WriteOperationOptions(); var exception = async ? - await Record.ExceptionAsync(() => subject.ExecuteWriteOperationAsync(operation, options, null, true, CancellationToken.None)) : - Record.Exception(() => subject.ExecuteWriteOperation(operation, options, null, true, CancellationToken.None)); + await Record.ExceptionAsync(() => subject.ExecuteWriteOperationAsync(null, operation, options, true, CancellationToken.None)) : + Record.Exception(() => subject.ExecuteWriteOperation(null, operation, options, true, CancellationToken.None)); exception.Should().BeOfType() .Subject.ParamName.Should().Be("session"); From b3c293f9f8f9a265eff24fd077c65113d457d798 Mon Sep 17 00:00:00 2001 From: Oleksandr Poliakov Date: Wed, 4 Jun 2025 12:07:30 -0700 Subject: [PATCH 09/14] pr --- src/MongoDB.Driver/MongoCollectionImpl.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/MongoDB.Driver/MongoCollectionImpl.cs b/src/MongoDB.Driver/MongoCollectionImpl.cs index 12d9d709aad..34d9c83e8e0 100644 --- a/src/MongoDB.Driver/MongoCollectionImpl.cs +++ b/src/MongoDB.Driver/MongoCollectionImpl.cs @@ -179,7 +179,7 @@ public override async Task AggregateToCollectionAsync(PipelineDefinitio await AggregateToCollectionAsync(session, pipeline, options, cancellationToken).ConfigureAwait(false); } - public override async Task AggregateToCollectionAsync(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) + public override Task AggregateToCollectionAsync(IClientSessionHandle session, PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); Ensure.IsNotNull(pipeline, nameof(pipeline)); @@ -193,7 +193,7 @@ public override async Task AggregateToCollectionAsync(IClientSessionHan } var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - await ExecuteWriteOperationAsync(session, aggregateOperation, _writeOperationOptions, cancellationToken).ConfigureAwait(false); + return ExecuteWriteOperationAsync(session, aggregateOperation, _writeOperationOptions, cancellationToken); } public override BulkWriteResult BulkWrite(IEnumerable> requests, BulkWriteOptions options, CancellationToken cancellationToken = default) From dce7ee318b528117ad848a275438ca7cb414ad98 Mon Sep 17 00:00:00 2001 From: Oleksandr Poliakov Date: Wed, 4 Jun 2025 14:31:20 -0700 Subject: [PATCH 10/14] PR --- src/MongoDB.Driver/MongoClient.cs | 73 ++++++++++--------------- src/MongoDB.Driver/OperationExecutor.cs | 8 +-- 2 files changed, 33 insertions(+), 48 deletions(-) diff --git a/src/MongoDB.Driver/MongoClient.cs b/src/MongoDB.Driver/MongoClient.cs index 48272cd8eb6..85ecaf7013e 100644 --- a/src/MongoDB.Driver/MongoClient.cs +++ b/src/MongoDB.Driver/MongoClient.cs @@ -145,10 +145,10 @@ public ClientBulkWriteResult BulkWrite(IReadOnlyList models, Cli /// public ClientBulkWriteResult BulkWrite(IClientSessionHandle session, IReadOnlyList models, ClientBulkWriteOptions options = null, CancellationToken cancellationToken = default) { - ThrowIfDisposed(); Ensure.IsNotNull(session, nameof(session)); + ThrowIfDisposed(); var operation = CreateClientBulkWriteOperation(models, options); - return ExecuteWriteOperation(session, operation, _writeOperationOptions, cancellationToken); + return ExecuteWriteOperation(session, operation, cancellationToken); } /// @@ -162,10 +162,10 @@ public async Task BulkWriteAsync(IReadOnlyList public Task BulkWriteAsync(IClientSessionHandle session, IReadOnlyList models, ClientBulkWriteOptions options = null, CancellationToken cancellationToken = default) { - ThrowIfDisposed(); Ensure.IsNotNull(session, nameof(session)); + ThrowIfDisposed(); var operation = CreateClientBulkWriteOperation(models, options); - return ExecuteWriteOperationAsync(session, operation, _writeOperationOptions, cancellationToken); + return ExecuteWriteOperationAsync(session, operation, cancellationToken); } /// @@ -209,10 +209,10 @@ public void DropDatabase(string name, CancellationToken cancellationToken = defa /// public void DropDatabase(IClientSessionHandle session, string name, CancellationToken cancellationToken = default) { - ThrowIfDisposed(); Ensure.IsNotNull(session, nameof(session)); + ThrowIfDisposed(); var operation = CreateDropDatabaseOperation(name); - ExecuteWriteOperation(session, operation, _writeOperationOptions, cancellationToken); + ExecuteWriteOperation(session, operation, cancellationToken); } /// @@ -226,10 +226,10 @@ public async Task DropDatabaseAsync(string name, CancellationToken cancellationT /// public Task DropDatabaseAsync(IClientSessionHandle session, string name, CancellationToken cancellationToken = default) { - ThrowIfDisposed(); Ensure.IsNotNull(session, nameof(session)); + ThrowIfDisposed(); var opertion = CreateDropDatabaseOperation(name); - return ExecuteWriteOperationAsync(session, opertion, _writeOperationOptions, cancellationToken); + return ExecuteWriteOperationAsync(session, opertion, cancellationToken); } /// @@ -256,9 +256,8 @@ public IAsyncCursor ListDatabaseNames( CancellationToken cancellationToken = default) { ThrowIfDisposed(); - var listDatabasesOptions = CreateListDatabasesOptionsFromListDatabaseNamesOptions(options); - var databases = ListDatabases(listDatabasesOptions, cancellationToken); - return CreateDatabaseNamesCursor(databases); + using var session = _operationExecutor.StartImplicitSession(); + return ListDatabaseNames(session, options, cancellationToken); } /// @@ -289,9 +288,8 @@ public async Task> ListDatabaseNamesAsync( CancellationToken cancellationToken = default) { ThrowIfDisposed(); - var listDatabasesOptions = CreateListDatabasesOptionsFromListDatabaseNamesOptions(options); - var databases = await ListDatabasesAsync(listDatabasesOptions, cancellationToken).ConfigureAwait(false); - return CreateDatabaseNamesCursor(databases); + using var session = _operationExecutor.StartImplicitSession(); + return await ListDatabaseNamesAsync(session, options, cancellationToken).ConfigureAwait(false); } /// @@ -334,12 +332,7 @@ public IAsyncCursor ListDatabases( public IAsyncCursor ListDatabases( IClientSessionHandle session, CancellationToken cancellationToken = default) - { - ThrowIfDisposed(); - Ensure.IsNotNull(session, nameof(session)); - var operation = CreateListDatabaseOperation(null); - return ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); - } + => ListDatabases(session, null, cancellationToken); /// public IAsyncCursor ListDatabases( @@ -350,7 +343,7 @@ public IAsyncCursor ListDatabases( ThrowIfDisposed(); Ensure.IsNotNull(session, nameof(session)); var operation = CreateListDatabaseOperation(options); - return ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); + return ExecuteReadOperation(session, operation, cancellationToken); } /// @@ -375,12 +368,7 @@ public async Task> ListDatabasesAsync( public Task> ListDatabasesAsync( IClientSessionHandle session, CancellationToken cancellationToken = default) - { - ThrowIfDisposed(); - Ensure.IsNotNull(session, nameof(session)); - var operation = CreateListDatabaseOperation(null); - return ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken); - } + => ListDatabasesAsync(session, null, cancellationToken); /// public Task> ListDatabasesAsync( @@ -388,10 +376,10 @@ public Task> ListDatabasesAsync( ListDatabasesOptions options, CancellationToken cancellationToken = default) { - ThrowIfDisposed(); Ensure.IsNotNull(session, nameof(session)); + ThrowIfDisposed(); var operation = CreateListDatabaseOperation(options); - return ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken); + return ExecuteReadOperationAsync(session, operation, cancellationToken); } /// @@ -428,10 +416,10 @@ public IChangeStreamCursor Watch( ChangeStreamOptions options = null, CancellationToken cancellationToken = default) { - ThrowIfDisposed(); Ensure.IsNotNull(session, nameof(session)); + ThrowIfDisposed(); var operation = CreateChangeStreamOperation(pipeline, options); - return ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); + return ExecuteReadOperation(session, operation, cancellationToken); } /// @@ -452,17 +440,16 @@ public Task> WatchAsync( ChangeStreamOptions options = null, CancellationToken cancellationToken = default) { - ThrowIfDisposed(); Ensure.IsNotNull(session, nameof(session)); + ThrowIfDisposed(); var operation = CreateChangeStreamOperation(pipeline, options); - return ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken); + return ExecuteReadOperationAsync(session, operation, cancellationToken); } /// public IMongoClient WithReadConcern(ReadConcern readConcern) { Ensure.IsNotNull(readConcern, nameof(readConcern)); - ThrowIfDisposed(); var newSettings = Settings.Clone(); @@ -474,7 +461,6 @@ public IMongoClient WithReadConcern(ReadConcern readConcern) public IMongoClient WithReadPreference(ReadPreference readPreference) { Ensure.IsNotNull(readPreference, nameof(readPreference)); - ThrowIfDisposed(); var newSettings = Settings.Clone(); @@ -486,7 +472,6 @@ public IMongoClient WithReadPreference(ReadPreference readPreference) public IMongoClient WithWriteConcern(WriteConcern writeConcern) { Ensure.IsNotNull(writeConcern, nameof(writeConcern)); - ThrowIfDisposed(); var newSettings = Settings.Clone(); @@ -577,17 +562,17 @@ private ChangeStreamOperation CreateChangeStreamOperation( _settings.RetryReads, _settings.TranslationOptions); - private TResult ExecuteReadOperation(IClientSessionHandle session, IReadOperation operation, ReadOperationOptions options, CancellationToken cancellationToken) - => _operationExecutor.ExecuteReadOperation(session, operation, options, false, cancellationToken); + private TResult ExecuteReadOperation(IClientSessionHandle session, IReadOperation operation, CancellationToken cancellationToken) + => _operationExecutor.ExecuteReadOperation(session, operation, _readOperationOptions, false, cancellationToken); - private Task ExecuteReadOperationAsync(IClientSessionHandle session, IReadOperation operation, ReadOperationOptions options, CancellationToken cancellationToken) - => _operationExecutor.ExecuteReadOperationAsync(session, operation, options, false, cancellationToken); + private Task ExecuteReadOperationAsync(IClientSessionHandle session, IReadOperation operation, CancellationToken cancellationToken) + => _operationExecutor.ExecuteReadOperationAsync(session, operation, _readOperationOptions, false, cancellationToken); - private TResult ExecuteWriteOperation(IClientSessionHandle session, IWriteOperation operation, WriteOperationOptions options, CancellationToken cancellationToken) - => _operationExecutor.ExecuteWriteOperation(session, operation, options, false, cancellationToken); + private TResult ExecuteWriteOperation(IClientSessionHandle session, IWriteOperation operation, CancellationToken cancellationToken) + => _operationExecutor.ExecuteWriteOperation(session, operation, _writeOperationOptions, false, cancellationToken); - private Task ExecuteWriteOperationAsync(IClientSessionHandle session, IWriteOperation operation, WriteOperationOptions options, CancellationToken cancellationToken) - => _operationExecutor.ExecuteWriteOperationAsync(session, operation, options, false, cancellationToken); + private Task ExecuteWriteOperationAsync(IClientSessionHandle session, IWriteOperation operation, CancellationToken cancellationToken) + => _operationExecutor.ExecuteWriteOperationAsync(session, operation, _writeOperationOptions, false, cancellationToken); private MessageEncoderSettings GetMessageEncoderSettings() { diff --git a/src/MongoDB.Driver/OperationExecutor.cs b/src/MongoDB.Driver/OperationExecutor.cs index c5d1b457ce9..295d136bd09 100644 --- a/src/MongoDB.Driver/OperationExecutor.cs +++ b/src/MongoDB.Driver/OperationExecutor.cs @@ -45,10 +45,10 @@ public TResult ExecuteReadOperation( bool allowChannelPinning, CancellationToken cancellationToken) { - ThrowIfDisposed(); Ensure.IsNotNull(operation, nameof(operation)); Ensure.IsNotNull(options, nameof(options)); Ensure.IsNotNull(session, nameof(session)); + ThrowIfDisposed(); var readPreference = options.GetEffectiveReadPreference(session); using var binding = CreateReadBinding(session, readPreference, allowChannelPinning); @@ -62,10 +62,10 @@ public async Task ExecuteReadOperationAsync( bool allowChannelPinning, CancellationToken cancellationToken) { - ThrowIfDisposed(); Ensure.IsNotNull(operation, nameof(operation)); Ensure.IsNotNull(options, nameof(options)); Ensure.IsNotNull(session, nameof(session)); + ThrowIfDisposed(); var readPreference = options.GetEffectiveReadPreference(session); using var binding = CreateReadBinding(session, readPreference, allowChannelPinning); @@ -79,10 +79,10 @@ public TResult ExecuteWriteOperation( bool allowChannelPinning, CancellationToken cancellationToken) { - ThrowIfDisposed(); Ensure.IsNotNull(operation, nameof(operation)); Ensure.IsNotNull(options, nameof(options)); Ensure.IsNotNull(session, nameof(session)); + ThrowIfDisposed(); using var binding = CreateReadWriteBinding(session, allowChannelPinning); return operation.Execute(binding, cancellationToken); @@ -95,10 +95,10 @@ public async Task ExecuteWriteOperationAsync( bool allowChannelPinning, CancellationToken cancellationToken) { - ThrowIfDisposed(); Ensure.IsNotNull(operation, nameof(operation)); Ensure.IsNotNull(options, nameof(options)); Ensure.IsNotNull(session, nameof(session)); + ThrowIfDisposed(); using var binding = CreateReadWriteBinding(session, allowChannelPinning); return await operation.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false); From 81b880623913ca8f78cc107db2e8a27cce82454d Mon Sep 17 00:00:00 2001 From: Oleksandr Poliakov Date: Wed, 4 Jun 2025 15:47:21 -0700 Subject: [PATCH 11/14] PR --- src/MongoDB.Driver/MongoClient.cs | 4 +- src/MongoDB.Driver/MongoCollectionImpl.cs | 204 +++++++++++++--------- src/MongoDB.Driver/MongoDatabase.cs | 75 +++++--- 3 files changed, 177 insertions(+), 106 deletions(-) diff --git a/src/MongoDB.Driver/MongoClient.cs b/src/MongoDB.Driver/MongoClient.cs index 85ecaf7013e..154491305d0 100644 --- a/src/MongoDB.Driver/MongoClient.cs +++ b/src/MongoDB.Driver/MongoClient.cs @@ -417,6 +417,7 @@ public IChangeStreamCursor Watch( CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull(pipeline, nameof(pipeline)); ThrowIfDisposed(); var operation = CreateChangeStreamOperation(pipeline, options); return ExecuteReadOperation(session, operation, cancellationToken); @@ -441,6 +442,7 @@ public Task> WatchAsync( CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull(pipeline, nameof(pipeline)); ThrowIfDisposed(); var operation = CreateChangeStreamOperation(pipeline, options); return ExecuteReadOperationAsync(session, operation, cancellationToken); @@ -555,7 +557,7 @@ private ChangeStreamOperation CreateChangeStreamOperation( PipelineDefinition, TResult> pipeline, ChangeStreamOptions options) => ChangeStreamHelper.CreateChangeStreamOperation( - Ensure.IsNotNull(pipeline, nameof(pipeline)), + pipeline, options, _settings.ReadConcern, GetMessageEncoderSettings(), diff --git a/src/MongoDB.Driver/MongoCollectionImpl.cs b/src/MongoDB.Driver/MongoCollectionImpl.cs index 34d9c83e8e0..a575d7849f3 100644 --- a/src/MongoDB.Driver/MongoCollectionImpl.cs +++ b/src/MongoDB.Driver/MongoCollectionImpl.cs @@ -113,13 +113,13 @@ public override IAsyncCursor Aggregate(IClientSessionHandle se if (isAggregateToCollection) { var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - ExecuteWriteOperation(session, aggregateOperation, _writeOperationOptions, cancellationToken); + ExecuteWriteOperation(session, aggregateOperation, cancellationToken); return CreateAggregateToCollectionResultCursor(session, renderedPipeline, options); } else { var aggregateOperation = CreateAggregateOperation(renderedPipeline, options); - return ExecuteReadOperation(session, aggregateOperation, _readOperationOptions, cancellationToken); + return ExecuteReadOperation(session, aggregateOperation, cancellationToken); } } @@ -140,13 +140,13 @@ public override async Task> AggregateAsync(IClien if (isAggregateToCollection) { var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - await ExecuteWriteOperationAsync(session, aggregateOperation, _writeOperationOptions, cancellationToken).ConfigureAwait(false); + await ExecuteWriteOperationAsync(session, aggregateOperation, cancellationToken).ConfigureAwait(false); return CreateAggregateToCollectionResultCursor(session, renderedPipeline, options); } else { var aggregateOperation = CreateAggregateOperation(renderedPipeline, options); - return await ExecuteReadOperationAsync(session, aggregateOperation, _readOperationOptions, cancellationToken).ConfigureAwait(false); + return await ExecuteReadOperationAsync(session, aggregateOperation, cancellationToken).ConfigureAwait(false); } } @@ -170,7 +170,7 @@ public override void AggregateToCollection(IClientSessionHandle session } var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - ExecuteWriteOperation(session, aggregateOperation, _writeOperationOptions, cancellationToken); + ExecuteWriteOperation(session, aggregateOperation, cancellationToken); } public override async Task AggregateToCollectionAsync(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) @@ -193,7 +193,7 @@ public override Task AggregateToCollectionAsync(IClientSessionHandle se } var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - return ExecuteWriteOperationAsync(session, aggregateOperation, _writeOperationOptions, cancellationToken); + return ExecuteWriteOperationAsync(session, aggregateOperation, cancellationToken); } public override BulkWriteResult BulkWrite(IEnumerable> requests, BulkWriteOptions options, CancellationToken cancellationToken = default) @@ -205,12 +205,17 @@ public override BulkWriteResult BulkWrite(IEnumerable BulkWrite(IClientSessionHandle session, IEnumerable> requests, BulkWriteOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull((object)requests, nameof(requests)); var requestsArray = requests.ToArray(); + if (requestsArray.Length == 0) + { + throw new ArgumentException("Must contain at least 1 request.", nameof(requests)); + } var operation = CreateBulkWriteOperation(session, requestsArray, options); try { - var result = ExecuteWriteOperation(session, operation, _writeOperationOptions, cancellationToken); + var result = ExecuteWriteOperation(session, operation, cancellationToken); return BulkWriteResult.FromCore(result, requestsArray); } catch (MongoBulkWriteOperationException ex) @@ -228,12 +233,17 @@ public override async Task> BulkWriteAsync(IEnumerabl public override async Task> BulkWriteAsync(IClientSessionHandle session, IEnumerable> requests, BulkWriteOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull((object)requests, nameof(requests)); var requestsArray = requests.ToArray(); + if (requestsArray.Length == 0) + { + throw new ArgumentException("Must contain at least 1 request.", nameof(requests)); + } var operation = CreateBulkWriteOperation(session, requestsArray, options); try { - var result = await ExecuteWriteOperationAsync(session, operation, _writeOperationOptions, cancellationToken).ConfigureAwait(false); + var result = await ExecuteWriteOperationAsync(session, operation, cancellationToken).ConfigureAwait(false); return BulkWriteResult.FromCore(result, requestsArray); } catch (MongoBulkWriteOperationException ex) @@ -253,8 +263,10 @@ public override long Count(FilterDefinition filter, CountOptions opti public override long Count(IClientSessionHandle session, FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull(filter, nameof(filter)); + var operation = CreateCountOperation(filter, options); - return ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); + return ExecuteReadOperation(session, operation, cancellationToken); } [Obsolete("Use CountDocumentsAsync or EstimatedDocumentCountAsync instead.")] @@ -268,8 +280,10 @@ public override async Task CountAsync(FilterDefinition filter, public override Task CountAsync(IClientSessionHandle session, FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull(filter, nameof(filter)); + var operation = CreateCountOperation(filter, options); - return ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken); + return ExecuteReadOperationAsync(session, operation, cancellationToken); } public override long CountDocuments(FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) @@ -281,8 +295,10 @@ public override long CountDocuments(FilterDefinition filter, CountOpt public override long CountDocuments(IClientSessionHandle session, FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull(filter, nameof(filter)); + var operation = CreateCountDocumentsOperation(filter, options); - return ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); + return ExecuteReadOperation(session, operation, cancellationToken); } public override async Task CountDocumentsAsync(FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) @@ -294,8 +310,10 @@ public override async Task CountDocumentsAsync(FilterDefinition public override Task CountDocumentsAsync(IClientSessionHandle session, FilterDefinition filter, CountOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull(filter, nameof(filter)); + var operation = CreateCountDocumentsOperation(filter, options); - return ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken); + return ExecuteReadOperationAsync(session, operation, cancellationToken); } public override IAsyncCursor Distinct(FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) @@ -307,8 +325,11 @@ public override IAsyncCursor Distinct(FieldDefinition Distinct(IClientSessionHandle session, FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull(field, nameof(field)); + Ensure.IsNotNull(filter, nameof(filter)); + var operation = CreateDistinctOperation(field, filter, options); - return ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); + return ExecuteReadOperation(session, operation, cancellationToken); } public override async Task> DistinctAsync(FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) @@ -320,8 +341,11 @@ public override async Task> DistinctAsync(FieldDefi public override Task> DistinctAsync(IClientSessionHandle session, FieldDefinition field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull(field, nameof(field)); + Ensure.IsNotNull(filter, nameof(filter)); + var operation = CreateDistinctOperation(field, filter, options); - return ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken); + return ExecuteReadOperationAsync(session, operation, cancellationToken); } public override IAsyncCursor DistinctMany(FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) @@ -333,8 +357,11 @@ public override IAsyncCursor DistinctMany(FieldDefinition DistinctMany(IClientSessionHandle session, FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull(field, nameof(field)); + Ensure.IsNotNull(filter, nameof(filter)); + var operation = CreateDistinctManyOperation(field, filter, options); - return ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); + return ExecuteReadOperation(session, operation, cancellationToken); } public override async Task> DistinctManyAsync(FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) @@ -346,22 +373,25 @@ public override async Task> DistinctManyAsync(FieldDe public override Task> DistinctManyAsync(IClientSessionHandle session, FieldDefinition> field, FilterDefinition filter, DistinctOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull(field, nameof(field)); + Ensure.IsNotNull(filter, nameof(filter)); + var operation = CreateDistinctManyOperation(field, filter, options); - return ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken); + return ExecuteReadOperationAsync(session, operation, cancellationToken); } public override long EstimatedDocumentCount(EstimatedDocumentCountOptions options, CancellationToken cancellationToken = default) { using var session = _operationExecutor.StartImplicitSession(); var operation = CreateEstimatedDocumentCountOperation(options); - return ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); + return ExecuteReadOperation(session, operation, cancellationToken); } public override async Task EstimatedDocumentCountAsync(EstimatedDocumentCountOptions options, CancellationToken cancellationToken = default) { using var session = _operationExecutor.StartImplicitSession(); var operation = CreateEstimatedDocumentCountOperation(options); - return await ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken).ConfigureAwait(false); + return await ExecuteReadOperationAsync(session, operation, cancellationToken).ConfigureAwait(false); } public override IAsyncCursor FindSync(FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default) @@ -373,8 +403,10 @@ public override IAsyncCursor FindSync(FilterDefinition public override IAsyncCursor FindSync(IClientSessionHandle session, FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull(filter, nameof(filter)); + var operation = CreateFindOperation(filter, options); - return ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); + return ExecuteReadOperation(session, operation, cancellationToken); } public override async Task> FindAsync(FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default) @@ -386,8 +418,10 @@ public override async Task> FindAsync(Fil public override Task> FindAsync(IClientSessionHandle session, FilterDefinition filter, FindOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull(filter, nameof(filter)); + var operation = CreateFindOperation(filter, options); - return ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken); + return ExecuteReadOperationAsync(session, operation, cancellationToken); } public override TProjection FindOneAndDelete(FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default) @@ -399,8 +433,10 @@ public override TProjection FindOneAndDelete(FilterDefinition(IClientSessionHandle session, FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull(filter, nameof(filter)); + var operation = CreateFindOneAndDeleteOperation(filter, options); - return ExecuteWriteOperation(session, operation, _writeOperationOptions, cancellationToken); + return ExecuteWriteOperation(session, operation, cancellationToken); } public override async Task FindOneAndDeleteAsync(FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default) @@ -412,8 +448,10 @@ public override async Task FindOneAndDeleteAsync(Filte public override Task FindOneAndDeleteAsync(IClientSessionHandle session, FilterDefinition filter, FindOneAndDeleteOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull(filter, nameof(filter)); + var operation = CreateFindOneAndDeleteOperation(filter, options); - return ExecuteWriteOperationAsync(session, operation, _writeOperationOptions, cancellationToken); + return ExecuteWriteOperationAsync(session, operation, cancellationToken); } public override TProjection FindOneAndReplace(FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default) @@ -425,8 +463,11 @@ public override TProjection FindOneAndReplace(FilterDefinition(IClientSessionHandle session, FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); - var operation = CreateFindOneAndReplaceOperation(filter, replacement, options); - return ExecuteWriteOperation(session, operation, _writeOperationOptions, cancellationToken); + Ensure.IsNotNull(filter, nameof(filter)); + var replacementObject = Ensure.IsNotNull((object)replacement, nameof(replacement)); // only box once if it's a struct + + var operation = CreateFindOneAndReplaceOperation(filter, replacementObject, options); + return ExecuteWriteOperation(session, operation, cancellationToken); } public override async Task FindOneAndReplaceAsync(FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default) @@ -438,8 +479,11 @@ public override async Task FindOneAndReplaceAsync(Filt public override Task FindOneAndReplaceAsync(IClientSessionHandle session, FilterDefinition filter, TDocument replacement, FindOneAndReplaceOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); - var operation = CreateFindOneAndReplaceOperation(filter, replacement, options); - return ExecuteWriteOperationAsync(session, operation, _writeOperationOptions, cancellationToken); + Ensure.IsNotNull(filter, nameof(filter)); + var replacementObject = Ensure.IsNotNull((object)replacement, nameof(replacement)); // only box once if it's a struct + + var operation = CreateFindOneAndReplaceOperation(filter, replacementObject, options); + return ExecuteWriteOperationAsync(session, operation, cancellationToken); } public override TProjection FindOneAndUpdate(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default) @@ -451,8 +495,11 @@ public override TProjection FindOneAndUpdate(FilterDefinition(IClientSessionHandle session, FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull(filter, nameof(filter)); + Ensure.IsNotNull(update, nameof(update)); + var operation = CreateFindOneAndUpdateOperation(filter, update, options); - return ExecuteWriteOperation(session, operation, _writeOperationOptions, cancellationToken); + return ExecuteWriteOperation(session, operation, cancellationToken); } public override async Task FindOneAndUpdateAsync(FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default) @@ -464,8 +511,11 @@ public override async Task FindOneAndUpdateAsync(Filte public override Task FindOneAndUpdateAsync(IClientSessionHandle session, FilterDefinition filter, UpdateDefinition update, FindOneAndUpdateOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull(filter, nameof(filter)); + Ensure.IsNotNull(update, nameof(update)); + var operation = CreateFindOneAndUpdateOperation(filter, update, options); - return ExecuteWriteOperationAsync(session, operation, _writeOperationOptions, cancellationToken); + return ExecuteWriteOperationAsync(session, operation, cancellationToken); } [Obsolete("Use Aggregation pipeline instead.")] @@ -490,12 +540,12 @@ public override IAsyncCursor MapReduce(IClientSessionHandle se if (outputOptions == MapReduceOutputOptions.Inline) { var operation = CreateMapReduceOperation(map, reduce, options, resultSerializer, renderArgs); - return ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); + return ExecuteReadOperation(session, operation, cancellationToken); } else { var mapReduceOperation = CreateMapReduceOutputToCollectionOperation(map, reduce, options, outputOptions, renderArgs); - ExecuteWriteOperation(session, mapReduceOperation, _writeOperationOptions, cancellationToken); + ExecuteWriteOperation(session, mapReduceOperation, cancellationToken); return CreateMapReduceOutputToCollectionResultCursor(session, options, mapReduceOperation.OutputCollectionNamespace, resultSerializer); } } @@ -522,12 +572,12 @@ public override async Task> MapReduceAsync(IClien if (outputOptions == MapReduceOutputOptions.Inline) { var operation = CreateMapReduceOperation(map, reduce, options, resultSerializer, renderArgs); - return await ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken).ConfigureAwait(false); + return await ExecuteReadOperationAsync(session, operation, cancellationToken).ConfigureAwait(false); } else { var mapReduceOperation = CreateMapReduceOutputToCollectionOperation(map, reduce, options, outputOptions, renderArgs); - await ExecuteWriteOperationAsync(session, mapReduceOperation, _writeOperationOptions, cancellationToken).ConfigureAwait(false); + await ExecuteWriteOperationAsync(session, mapReduceOperation, cancellationToken).ConfigureAwait(false); return CreateMapReduceOutputToCollectionResultCursor(session, options, mapReduceOperation.OutputCollectionNamespace, resultSerializer); } } @@ -562,8 +612,10 @@ public override IChangeStreamCursor Watch( CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull(pipeline, nameof(pipeline)); + var operation = CreateChangeStreamOperation(pipeline, options); - return ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); + return ExecuteReadOperation(session, operation, cancellationToken); } public override async Task> WatchAsync( @@ -582,8 +634,10 @@ public override Task> WatchAsync( CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull(pipeline, nameof(pipeline)); + var operation = CreateChangeStreamOperation(pipeline, options); - return ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken); + return ExecuteReadOperationAsync(session, operation, cancellationToken); } public override IMongoCollection WithReadConcern(ReadConcern readConcern) @@ -761,12 +815,6 @@ private BulkMixedWriteOperation CreateBulkWriteOperation( IReadOnlyList> requests, BulkWriteOptions options) { - Ensure.IsNotNull((object)requests, nameof(requests)); - if (requests.Count == 0) - { - throw new ArgumentException("Must contain at least 1 request.", nameof(requests)); - } - options ??= new BulkWriteOptions(); var renderArgs = GetRenderArgs(); var effectiveWriteConcern = session.IsInTransaction ? WriteConcern.Acknowledged : _settings.WriteConcern; @@ -795,7 +843,6 @@ private ChangeStreamOperation CreateChangeStreamOperation( PipelineDefinition, TResult> pipeline, ChangeStreamOptions options) { - Ensure.IsNotNull(pipeline, nameof(pipeline)); var translationOptions = _database.Client.Settings.TranslationOptions; return ChangeStreamHelper.CreateChangeStreamOperation( @@ -812,7 +859,6 @@ private CountDocumentsOperation CreateCountDocumentsOperation( FilterDefinition filter, CountOptions options) { - Ensure.IsNotNull(filter, nameof(filter)); options ??= new CountOptions(); var renderArgs = GetRenderArgs(); @@ -834,7 +880,6 @@ private CountOperation CreateCountOperation( FilterDefinition filter, CountOptions options) { - Ensure.IsNotNull(filter, nameof(filter)); options ??= new CountOptions(); var renderArgs = GetRenderArgs(); @@ -857,8 +902,6 @@ private DistinctOperation CreateDistinctOperation( FilterDefinition filter, DistinctOptions options) { - Ensure.IsNotNull(field, nameof(field)); - Ensure.IsNotNull(filter, nameof(filter)); options ??= new DistinctOptions(); var renderArgs = GetRenderArgs(); var renderedField = field.Render(renderArgs); @@ -884,8 +927,6 @@ private DistinctOperation CreateDistinctManyOperation( FilterDefinition filter, DistinctOptions options) { - Ensure.IsNotNull(field, nameof(field)); - Ensure.IsNotNull(filter, nameof(filter)); options ??= new DistinctOptions(); var renderArgs = GetRenderArgs(); var renderedField = field.Render(renderArgs); @@ -920,7 +961,6 @@ private FindOneAndDeleteOperation CreateFindOneAndDeleteOperation filter, FindOneAndDeleteOptions options) { - Ensure.IsNotNull(filter, nameof(filter)); options ??= new FindOneAndDeleteOptions(); var renderArgs = GetRenderArgs(); var projection = options.Projection ?? new ClientSideDeserializationProjectionDefinition(); @@ -949,8 +989,6 @@ private FindOneAndReplaceOperation CreateFindOneAndReplaceOperation object replacement, FindOneAndReplaceOptions options) { - Ensure.IsNotNull(filter, nameof(filter)); - Ensure.IsNotNull(replacement, nameof(replacement)); options ??= new FindOneAndReplaceOptions(); var renderArgs = GetRenderArgs(); @@ -984,8 +1022,6 @@ private FindOneAndUpdateOperation CreateFindOneAndUpdateOperation update, FindOneAndUpdateOptions options) { - Ensure.IsNotNull(filter, nameof(filter)); - Ensure.IsNotNull(update, nameof(update)); options = options ?? new FindOneAndUpdateOptions(); if (update is PipelineUpdateDefinition && (options.ArrayFilters != null && options.ArrayFilters.Any())) @@ -1024,7 +1060,6 @@ private FindOperation CreateFindOperation( FilterDefinition filter, FindOptions options) { - Ensure.IsNotNull(filter, nameof(filter)); options ??= new FindOptions(); var renderArgs = GetRenderArgs(options.TranslationOptions); @@ -1166,17 +1201,23 @@ private IAsyncCursor CreateMapReduceOutputToCollectionResultCursor(IClientSessionHandle session, IReadOperation operation, CancellationToken cancellationToken) + => _operationExecutor.ExecuteReadOperation(session, operation, _readOperationOptions, true, cancellationToken); + + private Task ExecuteReadOperationAsync(IClientSessionHandle session, IReadOperation operation, CancellationToken cancellationToken) + => _operationExecutor.ExecuteReadOperationAsync(session, operation, _readOperationOptions, true, cancellationToken); + private TResult ExecuteReadOperation(IClientSessionHandle session, IReadOperation operation, ReadOperationOptions options, CancellationToken cancellationToken) => _operationExecutor.ExecuteReadOperation(session, operation, options, true, cancellationToken); private Task ExecuteReadOperationAsync(IClientSessionHandle session, IReadOperation operation, ReadOperationOptions options, CancellationToken cancellationToken) => _operationExecutor.ExecuteReadOperationAsync(session, operation, options, true, cancellationToken); - private TResult ExecuteWriteOperation(IClientSessionHandle session, IWriteOperation operation, WriteOperationOptions options, CancellationToken cancellationToken) - => _operationExecutor.ExecuteWriteOperation(session, operation, options, true, cancellationToken); + private TResult ExecuteWriteOperation(IClientSessionHandle session, IWriteOperation operation, CancellationToken cancellationToken) + => _operationExecutor.ExecuteWriteOperation(session, operation, _writeOperationOptions, true, cancellationToken); - private Task ExecuteWriteOperationAsync(IClientSessionHandle session, IWriteOperation operation, WriteOperationOptions options, CancellationToken cancellationToken) - => _operationExecutor.ExecuteWriteOperationAsync(session, operation, options, true, cancellationToken); + private Task ExecuteWriteOperationAsync(IClientSessionHandle session, IWriteOperation operation, CancellationToken cancellationToken) + => _operationExecutor.ExecuteWriteOperationAsync(session, operation, _writeOperationOptions, true, cancellationToken); private MessageEncoderSettings GetMessageEncoderSettings() @@ -1336,9 +1377,10 @@ public override IEnumerable CreateMany( CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull((object)models, nameof(models)); var operation = CreateCreateIndexesOperation(models, options); - _collection.ExecuteWriteOperation(session, operation, _collection._writeOperationOptions, cancellationToken); + _collection.ExecuteWriteOperation(session, operation, cancellationToken); return operation.Requests.Select(x => x.GetIndexName()); } @@ -1364,9 +1406,10 @@ public override async Task> CreateManyAsync( CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull((object)models, nameof(models)); var operation = CreateCreateIndexesOperation(models, options); - await _collection.ExecuteWriteOperationAsync(session, operation, _collection._writeOperationOptions, cancellationToken).ConfigureAwait(false); + await _collection.ExecuteWriteOperationAsync(session, operation, cancellationToken).ConfigureAwait(false); return operation.Requests.Select(x => x.GetIndexName()); } @@ -1386,7 +1429,7 @@ public override void DropAll(IClientSessionHandle session, DropIndexOptions opti { Ensure.IsNotNull(session, nameof(session)); var operation = CreateDropAllOperation(options); - _collection.ExecuteWriteOperation(session, operation, _collection._writeOperationOptions, cancellationToken); + _collection.ExecuteWriteOperation(session, operation, cancellationToken); } public override Task DropAllAsync(CancellationToken cancellationToken) @@ -1405,7 +1448,7 @@ public override Task DropAllAsync(IClientSessionHandle session, DropIndexOptions { Ensure.IsNotNull(session, nameof(session)); var operation = CreateDropAllOperation(options); - return _collection.ExecuteWriteOperationAsync(session, operation, _collection._writeOperationOptions, cancellationToken); + return _collection.ExecuteWriteOperationAsync(session, operation, cancellationToken); } public override void DropOne(string name, CancellationToken cancellationToken = default) @@ -1423,8 +1466,14 @@ public override void DropOne(IClientSessionHandle session, string name, Cancella public override void DropOne(IClientSessionHandle session, string name, DropIndexOptions options, CancellationToken cancellationToken) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNullOrEmpty(name, nameof(name)); + if (name == "*") + { + throw new ArgumentException("Cannot specify '*' for the index name. Use DropAll and DropAllAsync to drop all indexes.", "name"); + } + var operation = CreateDropOneOperation(name, options); - _collection.ExecuteWriteOperation(session, operation, _collection._writeOperationOptions, cancellationToken); + _collection.ExecuteWriteOperation(session, operation, cancellationToken); } public override Task DropOneAsync(string name, CancellationToken cancellationToken = default) @@ -1442,8 +1491,14 @@ public override Task DropOneAsync(IClientSessionHandle session, string name, Can public override Task DropOneAsync(IClientSessionHandle session, string name, DropIndexOptions options, CancellationToken cancellationToken) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNullOrEmpty(name, nameof(name)); + if (name == "*") + { + throw new ArgumentException("Cannot specify '*' for the index name. Use DropAll and DropAllAsync to drop all indexes.", "name"); + } + var operation = CreateDropOneOperation(name, options); - return _collection.ExecuteWriteOperationAsync(session, operation, _collection._writeOperationOptions, cancellationToken); + return _collection.ExecuteWriteOperationAsync(session, operation, cancellationToken); } public override IAsyncCursor List(CancellationToken cancellationToken = default) @@ -1462,7 +1517,7 @@ public override IAsyncCursor List(IClientSessionHandle session, Li { Ensure.IsNotNull(session, nameof(session)); var operation = CreateListIndexesOperation(options); - return _collection.ExecuteReadOperation(session, operation, _collection._readOperationOptions, cancellationToken); + return _collection.ExecuteReadOperation(session, operation, cancellationToken); } public override Task> ListAsync(CancellationToken cancellationToken = default) @@ -1481,13 +1536,12 @@ public override Task> ListAsync(IClientSessionHandle { Ensure.IsNotNull(session, nameof(session)); var operation = CreateListIndexesOperation(options); - return _collection.ExecuteReadOperationAsync(session, operation, _collection._readOperationOptions, cancellationToken); + return _collection.ExecuteReadOperationAsync(session, operation, cancellationToken); } // private methods private CreateIndexesOperation CreateCreateIndexesOperation(IEnumerable> models, CreateManyIndexesOptions options) { - Ensure.IsNotNull((object)models, nameof(models)); var requests = CreateCreateIndexRequests(models); return new CreateIndexesOperation(_collection._collectionNamespace, requests, _collection._messageEncoderSettings) @@ -1549,12 +1603,6 @@ private DropIndexOperation CreateDropAllOperation(DropIndexOptions options) private DropIndexOperation CreateDropOneOperation(string name, DropIndexOptions options) { - Ensure.IsNotNullOrEmpty(name, nameof(name)); - if (name == "*") - { - throw new ArgumentException("Cannot specify '*' for the index name. Use DropAll and DropAllAsync to drop all indexes.", "name"); - } - return new DropIndexOperation(_collection._collectionNamespace, name, _collection._messageEncoderSettings) { Comment = options?.Comment, @@ -1589,7 +1637,7 @@ public IEnumerable CreateMany(IEnumerable models { using var session = _collection._operationExecutor.StartImplicitSession(); var operation = CreateCreateIndexesOperation(models); - var result = _collection.ExecuteWriteOperation(session, operation, _collection._writeOperationOptions, cancellationToken); + var result = _collection.ExecuteWriteOperation(session, operation, cancellationToken); return GetIndexNames(result); } @@ -1597,7 +1645,7 @@ public async Task> CreateManyAsync(IEnumerable List(string indexName, AggregateOptions aggregateOptions = null, CancellationToken cancellationToken = default) @@ -1647,14 +1695,14 @@ public void Update(string indexName, BsonDocument definition, CancellationToken { using var session = _collection._operationExecutor.StartImplicitSession(); var operation = new UpdateSearchIndexOperation(_collection.CollectionNamespace, indexName, definition, _collection._messageEncoderSettings); - _collection.ExecuteWriteOperation(session, operation, _collection._writeOperationOptions, cancellationToken); + _collection.ExecuteWriteOperation(session, operation, cancellationToken); } public async Task UpdateAsync(string indexName, BsonDocument definition, CancellationToken cancellationToken = default) { using var session = _collection._operationExecutor.StartImplicitSession(); var operation = new UpdateSearchIndexOperation(_collection.CollectionNamespace, indexName, definition, _collection._messageEncoderSettings); - await _collection.ExecuteWriteOperationAsync(session, operation, _collection._writeOperationOptions, cancellationToken).ConfigureAwait(false); + await _collection.ExecuteWriteOperationAsync(session, operation, cancellationToken).ConfigureAwait(false); } // private methods diff --git a/src/MongoDB.Driver/MongoDatabase.cs b/src/MongoDB.Driver/MongoDatabase.cs index 599815c9521..493f435d713 100644 --- a/src/MongoDB.Driver/MongoDatabase.cs +++ b/src/MongoDB.Driver/MongoDatabase.cs @@ -78,13 +78,13 @@ public IAsyncCursor Aggregate(IClientSessionHandle session, Pi if (isAggregateToCollection) { var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - ExecuteWriteOperation(session, aggregateOperation, _writeOperationOptions, cancellationToken); + ExecuteWriteOperation(session, aggregateOperation, cancellationToken); return CreateAggregateToCollectionResultCursor(session, renderedPipeline, options); } else { var aggregateOperation = CreateAggregateOperation(renderedPipeline, options); - return ExecuteReadOperation(session, aggregateOperation, _readOperationOptions, cancellationToken); + return ExecuteReadOperation(session, aggregateOperation, cancellationToken); } } @@ -105,13 +105,13 @@ public async Task> AggregateAsync(IClientSessionH if (isAggregateToCollection) { var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - await ExecuteWriteOperationAsync(session, aggregateOperation, _writeOperationOptions, cancellationToken).ConfigureAwait(false); + await ExecuteWriteOperationAsync(session, aggregateOperation, cancellationToken).ConfigureAwait(false); return CreateAggregateToCollectionResultCursor(session, renderedPipeline, options); } else { var aggregateOperation = CreateAggregateOperation(renderedPipeline, options); - return await ExecuteReadOperationAsync(session, aggregateOperation, _readOperationOptions, cancellationToken).ConfigureAwait(false); + return await ExecuteReadOperationAsync(session, aggregateOperation, cancellationToken).ConfigureAwait(false); } } @@ -135,7 +135,7 @@ public void AggregateToCollection(IClientSessionHandle session, Pipelin } var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - ExecuteWriteOperation(session, aggregateOperation, _writeOperationOptions, cancellationToken); + ExecuteWriteOperation(session, aggregateOperation, cancellationToken); } public async Task AggregateToCollectionAsync(PipelineDefinition pipeline, AggregateOptions options, CancellationToken cancellationToken = default) @@ -158,7 +158,7 @@ public Task AggregateToCollectionAsync(IClientSessionHandle session, Pi } var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); - return ExecuteWriteOperationAsync(session, aggregateOperation, _writeOperationOptions, cancellationToken); + return ExecuteWriteOperationAsync(session, aggregateOperation, cancellationToken); } public void CreateCollection(string name, CreateCollectionOptions options, CancellationToken cancellationToken) @@ -244,8 +244,12 @@ public void CreateView(string viewName, string viewOn, Pipel public void CreateView(IClientSessionHandle session, string viewName, string viewOn, PipelineDefinition pipeline, CreateViewOptions options = null, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull(viewName, nameof(viewName)); + Ensure.IsNotNull(viewOn, nameof(viewOn)); + Ensure.IsNotNull(pipeline, nameof(pipeline)); + var operation = CreateCreateViewOperation(viewName, viewOn, pipeline, options); - ExecuteWriteOperation(session, operation, _writeOperationOptions, cancellationToken); + ExecuteWriteOperation(session, operation, cancellationToken); } public async Task CreateViewAsync(string viewName, string viewOn, PipelineDefinition pipeline, CreateViewOptions options = null, CancellationToken cancellationToken = default) @@ -257,8 +261,12 @@ public async Task CreateViewAsync(string viewName, string vi public Task CreateViewAsync(IClientSessionHandle session, string viewName, string viewOn, PipelineDefinition pipeline, CreateViewOptions options = null, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull(viewName, nameof(viewName)); + Ensure.IsNotNull(viewOn, nameof(viewOn)); + Ensure.IsNotNull(pipeline, nameof(pipeline)); + var operation = CreateCreateViewOperation(viewName, viewOn, pipeline, options); - return ExecuteWriteOperationAsync(session, operation,_writeOperationOptions, cancellationToken); + return ExecuteWriteOperationAsync(session, operation, cancellationToken); } public void DropCollection(string name, CancellationToken cancellationToken) @@ -285,7 +293,7 @@ public void DropCollection(IClientSessionHandle session, string name, DropCollec var collectionNamespace = new CollectionNamespace(_databaseNamespace, name); var encryptedFields = GetEncryptedFields(session, collectionNamespace, options, cancellationToken); var operation = CreateDropCollectionOperation(collectionNamespace, encryptedFields); - ExecuteWriteOperation(session, operation, _writeOperationOptions, cancellationToken); + ExecuteWriteOperation(session, operation, cancellationToken); } public Task DropCollectionAsync(string name, CancellationToken cancellationToken) @@ -308,7 +316,7 @@ public async Task DropCollectionAsync(IClientSessionHandle session, string name, var collectionNamespace = new CollectionNamespace(_databaseNamespace, name); var encryptedFields = await GetEncryptedFieldsAsync(session, collectionNamespace, options, cancellationToken).ConfigureAwait(false); var operation = CreateDropCollectionOperation(collectionNamespace, encryptedFields); - await ExecuteWriteOperationAsync(session, operation, _writeOperationOptions, cancellationToken).ConfigureAwait(false); + await ExecuteWriteOperationAsync(session, operation, cancellationToken).ConfigureAwait(false); } public IMongoCollection GetCollection(string name, MongoCollectionSettings settings) @@ -387,8 +395,11 @@ public void RenameCollection(string oldName, string newName, RenameCollectionOpt public void RenameCollection(IClientSessionHandle session, string oldName, string newName, RenameCollectionOptions options, CancellationToken cancellationToken) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNullOrEmpty(oldName, nameof(oldName)); + Ensure.IsNotNullOrEmpty(newName, nameof(newName)); + var operation = CreateRenameCollectionOperation(oldName, newName, options); - ExecuteWriteOperation(session, operation, _writeOperationOptions, cancellationToken); + ExecuteWriteOperation(session, operation, cancellationToken); } public async Task RenameCollectionAsync(string oldName, string newName, RenameCollectionOptions options, CancellationToken cancellationToken) @@ -400,8 +411,11 @@ public async Task RenameCollectionAsync(string oldName, string newName, RenameCo public Task RenameCollectionAsync(IClientSessionHandle session, string oldName, string newName, RenameCollectionOptions options, CancellationToken cancellationToken) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNullOrEmpty(oldName, nameof(oldName)); + Ensure.IsNotNullOrEmpty(newName, nameof(newName)); + var operation = CreateRenameCollectionOperation(oldName, newName, options); - return ExecuteWriteOperationAsync(session, operation, _writeOperationOptions, cancellationToken); + return ExecuteWriteOperationAsync(session, operation, cancellationToken); } public TResult RunCommand(Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default) @@ -413,6 +427,8 @@ public TResult RunCommand(Command command, ReadPreference read public TResult RunCommand(IClientSessionHandle session, Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull(command, nameof(command)); + var operation = CreateRunCommandOperation(command); return ExecuteReadOperation(session, operation, _readOperationOptions with { ExplicitReadPreference = readPreference, DefaultReadPreference = ReadPreference.Primary }, cancellationToken); } @@ -426,6 +442,8 @@ public async Task RunCommandAsync(Command command, Re public Task RunCommandAsync(IClientSessionHandle session, Command command, ReadPreference readPreference = null, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull(command, nameof(command)); + var operation = CreateRunCommandOperation(command); return ExecuteReadOperationAsync(session, operation, _readOperationOptions with { ExplicitReadPreference = readPreference, DefaultReadPreference = ReadPreference.Primary }, cancellationToken); } @@ -446,8 +464,10 @@ public IChangeStreamCursor Watch( CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull(pipeline, nameof(pipeline)); + var operation = CreateChangeStreamOperation(pipeline, options); - return ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); + return ExecuteReadOperation(session, operation, cancellationToken); } public async Task> WatchAsync( @@ -466,8 +486,10 @@ public Task> WatchAsync( CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); + Ensure.IsNotNull(pipeline, nameof(pipeline)); + var operation = CreateChangeStreamOperation(pipeline, options); - return ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken); + return ExecuteReadOperationAsync(session, operation, cancellationToken); } public IMongoDatabase WithReadConcern(ReadConcern readConcern) @@ -574,13 +596,13 @@ private AggregateToCollectionOperation CreateAggregateToCollectionOperation(IClientSessionHandle session, string name, CreateCollectionOptions options, CancellationToken cancellationToken) { var operation = CreateCreateCollectionOperation(name, options); - ExecuteWriteOperation(session, operation, _writeOperationOptions, cancellationToken); + ExecuteWriteOperation(session, operation, cancellationToken); } private Task CreateCollectionHelperAsync(IClientSessionHandle session, string name, CreateCollectionOptions options, CancellationToken cancellationToken) { var operation = CreateCreateCollectionOperation(name, options); - return ExecuteWriteOperationAsync(session, operation, _writeOperationOptions, cancellationToken); + return ExecuteWriteOperationAsync(session, operation, cancellationToken); } private IWriteOperation CreateCreateCollectionOperation(string name, CreateCollectionOptions options) @@ -629,9 +651,6 @@ private CreateViewOperation CreateCreateViewOperation( PipelineDefinition pipeline, CreateViewOptions options) { - Ensure.IsNotNull(viewName, nameof(viewName)); - Ensure.IsNotNull(viewOn, nameof(viewOn)); - Ensure.IsNotNull(pipeline, nameof(pipeline)); options ??= new CreateViewOptions(); var translationOptions = _client.Settings.TranslationOptions; @@ -687,8 +706,6 @@ private ListCollectionsOperation CreateListCollectionsOperation(ListCollectionsO private RenameCollectionOperation CreateRenameCollectionOperation(string oldName, string newName, RenameCollectionOptions options) { - Ensure.IsNotNullOrEmpty(oldName, nameof(oldName)); - Ensure.IsNotNullOrEmpty(newName, nameof(newName)); options ??= new RenameCollectionOptions(); var messageEncoderSettings = GetMessageEncoderSettings(); @@ -704,7 +721,6 @@ private RenameCollectionOperation CreateRenameCollectionOperation(string oldName private ReadCommandOperation CreateRunCommandOperation(Command command) { - Ensure.IsNotNull(command, nameof(command)); var renderedCommand = command.Render(_settings.SerializerRegistry); var messageEncoderSettings = GetMessageEncoderSettings(); return new ReadCommandOperation(_databaseNamespace, renderedCommand.Document, renderedCommand.ResultSerializer, messageEncoderSettings) @@ -717,7 +733,6 @@ private ChangeStreamOperation CreateChangeStreamOperation( PipelineDefinition, TResult> pipeline, ChangeStreamOptions options) { - Ensure.IsNotNull(pipeline, nameof(pipeline)); var translationOptions = _client.Settings.TranslationOptions; return ChangeStreamHelper.CreateChangeStreamOperation( @@ -730,17 +745,23 @@ private ChangeStreamOperation CreateChangeStreamOperation( translationOptions); } + private TResult ExecuteReadOperation(IClientSessionHandle session, IReadOperation operation, CancellationToken cancellationToken) + => _operationExecutor.ExecuteReadOperation(session, operation, _readOperationOptions, true, cancellationToken); + + private Task ExecuteReadOperationAsync(IClientSessionHandle session, IReadOperation operation, CancellationToken cancellationToken) + => _operationExecutor.ExecuteReadOperationAsync(session, operation, _readOperationOptions, true, cancellationToken); + private TResult ExecuteReadOperation(IClientSessionHandle session, IReadOperation operation, ReadOperationOptions options, CancellationToken cancellationToken) => _operationExecutor.ExecuteReadOperation(session, operation, options, true, cancellationToken); private Task ExecuteReadOperationAsync(IClientSessionHandle session, IReadOperation operation, ReadOperationOptions options, CancellationToken cancellationToken) => _operationExecutor.ExecuteReadOperationAsync(session, operation, options, true, cancellationToken); - private TResult ExecuteWriteOperation(IClientSessionHandle session, IWriteOperation operation, WriteOperationOptions options, CancellationToken cancellationToken) - => _operationExecutor.ExecuteWriteOperation(session, operation, options, true, cancellationToken); + private TResult ExecuteWriteOperation(IClientSessionHandle session, IWriteOperation operation, CancellationToken cancellationToken) + => _operationExecutor.ExecuteWriteOperation(session, operation, _writeOperationOptions, true, cancellationToken); - private Task ExecuteWriteOperationAsync(IClientSessionHandle session, IWriteOperation operation, WriteOperationOptions options, CancellationToken cancellationToken) - => _operationExecutor.ExecuteWriteOperationAsync(session, operation, options, true, cancellationToken); + private Task ExecuteWriteOperationAsync(IClientSessionHandle session, IWriteOperation operation, CancellationToken cancellationToken) + => _operationExecutor.ExecuteWriteOperationAsync(session, operation, _writeOperationOptions, true, cancellationToken); private IEnumerable ExtractCollectionNames(IEnumerable collections) { From 4314f4aba498648b4d9deef223550f9140aa1c11 Mon Sep 17 00:00:00 2001 From: Oleksandr Poliakov Date: Wed, 4 Jun 2025 18:09:40 -0700 Subject: [PATCH 12/14] PR --- src/MongoDB.Driver/MongoClient.cs | 6 ++-- src/MongoDB.Driver/MongoCollectionImpl.cs | 38 ++++++++++++----------- src/MongoDB.Driver/MongoDatabase.cs | 24 +++++++------- 3 files changed, 35 insertions(+), 33 deletions(-) diff --git a/src/MongoDB.Driver/MongoClient.cs b/src/MongoDB.Driver/MongoClient.cs index 154491305d0..55d91940952 100644 --- a/src/MongoDB.Driver/MongoClient.cs +++ b/src/MongoDB.Driver/MongoClient.cs @@ -342,7 +342,7 @@ public IAsyncCursor ListDatabases( { ThrowIfDisposed(); Ensure.IsNotNull(session, nameof(session)); - var operation = CreateListDatabaseOperation(options); + var operation = CreateListDatabasesOperation(options); return ExecuteReadOperation(session, operation, cancellationToken); } @@ -378,7 +378,7 @@ public Task> ListDatabasesAsync( { Ensure.IsNotNull(session, nameof(session)); ThrowIfDisposed(); - var operation = CreateListDatabaseOperation(options); + var operation = CreateListDatabasesOperation(options); return ExecuteReadOperationAsync(session, operation, cancellationToken); } @@ -524,7 +524,7 @@ private DropDatabaseOperation CreateDropDatabaseOperation(string name) WriteConcern = _settings.WriteConcern }; - private ListDatabasesOperation CreateListDatabaseOperation(ListDatabasesOptions options) + private ListDatabasesOperation CreateListDatabasesOperation(ListDatabasesOptions options) { options ??= new ListDatabasesOptions(); var messageEncoderSettings = GetMessageEncoderSettings(); diff --git a/src/MongoDB.Driver/MongoCollectionImpl.cs b/src/MongoDB.Driver/MongoCollectionImpl.cs index a575d7849f3..5bb176a049c 100644 --- a/src/MongoDB.Driver/MongoCollectionImpl.cs +++ b/src/MongoDB.Driver/MongoCollectionImpl.cs @@ -109,7 +109,7 @@ public override IAsyncCursor Aggregate(IClientSessionHandle se options ??= new AggregateOptions(); var renderArgs = GetRenderArgs(options.TranslationOptions); - var renderedPipeline = AggregateHelper.RenderAggregatePipeline(pipeline, renderArgs, out bool isAggregateToCollection); + var renderedPipeline = AggregateHelper.RenderAggregatePipeline(pipeline, renderArgs, out var isAggregateToCollection); if (isAggregateToCollection) { var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); @@ -136,7 +136,7 @@ public override async Task> AggregateAsync(IClien options ??= new AggregateOptions(); var renderArgs = GetRenderArgs(options.TranslationOptions); - var renderedPipeline = AggregateHelper.RenderAggregatePipeline(pipeline, renderArgs, out bool isAggregateToCollection); + var renderedPipeline = AggregateHelper.RenderAggregatePipeline(pipeline, renderArgs, out var isAggregateToCollection); if (isAggregateToCollection) { var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); @@ -163,7 +163,7 @@ public override void AggregateToCollection(IClientSessionHandle session options ??= new AggregateOptions(); var renderArgs = GetRenderArgs(options.TranslationOptions); - var renderedPipeline = AggregateHelper.RenderAggregatePipeline(pipeline, renderArgs, out bool isAggregateToCollection); + var renderedPipeline = AggregateHelper.RenderAggregatePipeline(pipeline, renderArgs, out var isAggregateToCollection); if (renderedPipeline.Documents.Count == 0 || !isAggregateToCollection) { throw new InvalidOperationException("AggregateToCollection requires that the last stage be $out or $merge."); @@ -186,7 +186,7 @@ public override Task AggregateToCollectionAsync(IClientSessionHandle se options ??= new AggregateOptions(); var renderArgs = GetRenderArgs(options.TranslationOptions); - var renderedPipeline = AggregateHelper.RenderAggregatePipeline(pipeline, renderArgs, out bool isAggregateToCollection); + var renderedPipeline = AggregateHelper.RenderAggregatePipeline(pipeline, renderArgs, out var isAggregateToCollection); if (renderedPipeline.Documents.Count == 0 || !isAggregateToCollection) { throw new InvalidOperationException("AggregateToCollectionAsync requires that the last stage be $out or $merge."); @@ -205,7 +205,7 @@ public override BulkWriteResult BulkWrite(IEnumerable BulkWrite(IClientSessionHandle session, IEnumerable> requests, BulkWriteOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull((object)requests, nameof(requests)); + Ensure.IsNotNull(requests, nameof(requests)); var requestsArray = requests.ToArray(); if (requestsArray.Length == 0) { @@ -233,7 +233,7 @@ public override async Task> BulkWriteAsync(IEnumerabl public override async Task> BulkWriteAsync(IClientSessionHandle session, IEnumerable> requests, BulkWriteOptions options, CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull((object)requests, nameof(requests)); + Ensure.IsNotNull(requests, nameof(requests)); var requestsArray = requests.ToArray(); if (requestsArray.Length == 0) { @@ -497,6 +497,10 @@ public override TProjection FindOneAndUpdate(IClientSessionHandle s Ensure.IsNotNull(session, nameof(session)); Ensure.IsNotNull(filter, nameof(filter)); Ensure.IsNotNull(update, nameof(update)); + if (update is PipelineUpdateDefinition && (options.ArrayFilters != null && options.ArrayFilters.Any())) + { + throw new NotSupportedException("An arrayfilter is not supported in the pipeline-style update."); + } var operation = CreateFindOneAndUpdateOperation(filter, update, options); return ExecuteWriteOperation(session, operation, cancellationToken); @@ -513,6 +517,10 @@ public override Task FindOneAndUpdateAsync(IClientSess Ensure.IsNotNull(session, nameof(session)); Ensure.IsNotNull(filter, nameof(filter)); Ensure.IsNotNull(update, nameof(update)); + if (update is PipelineUpdateDefinition && (options.ArrayFilters != null && options.ArrayFilters.Any())) + { + throw new NotSupportedException("An arrayfilter is not supported in the pipeline-style update."); + } var operation = CreateFindOneAndUpdateOperation(filter, update, options); return ExecuteWriteOperationAsync(session, operation, cancellationToken); @@ -1023,12 +1031,6 @@ private FindOneAndUpdateOperation CreateFindOneAndUpdateOperation options) { options = options ?? new FindOneAndUpdateOptions(); - - if (update is PipelineUpdateDefinition && (options.ArrayFilters != null && options.ArrayFilters.Any())) - { - throw new NotSupportedException("An arrayfilter is not supported in the pipeline-style update."); - } - var renderArgs = GetRenderArgs(); var projection = options.Projection ?? new ClientSideDeserializationProjectionDefinition(); var renderedProjection = projection.Render(renderArgs with { RenderForFind = true }); @@ -1202,14 +1204,14 @@ private IAsyncCursor CreateMapReduceOutputToCollectionResultCursor(IClientSessionHandle session, IReadOperation operation, CancellationToken cancellationToken) - => _operationExecutor.ExecuteReadOperation(session, operation, _readOperationOptions, true, cancellationToken); - - private Task ExecuteReadOperationAsync(IClientSessionHandle session, IReadOperation operation, CancellationToken cancellationToken) - => _operationExecutor.ExecuteReadOperationAsync(session, operation, _readOperationOptions, true, cancellationToken); + => ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); private TResult ExecuteReadOperation(IClientSessionHandle session, IReadOperation operation, ReadOperationOptions options, CancellationToken cancellationToken) => _operationExecutor.ExecuteReadOperation(session, operation, options, true, cancellationToken); + private Task ExecuteReadOperationAsync(IClientSessionHandle session, IReadOperation operation, CancellationToken cancellationToken) + => ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken); + private Task ExecuteReadOperationAsync(IClientSessionHandle session, IReadOperation operation, ReadOperationOptions options, CancellationToken cancellationToken) => _operationExecutor.ExecuteReadOperationAsync(session, operation, options, true, cancellationToken); @@ -1377,7 +1379,7 @@ public override IEnumerable CreateMany( CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull((object)models, nameof(models)); + Ensure.IsNotNull(models, nameof(models)); var operation = CreateCreateIndexesOperation(models, options); _collection.ExecuteWriteOperation(session, operation, cancellationToken); @@ -1406,7 +1408,7 @@ public override async Task> CreateManyAsync( CancellationToken cancellationToken = default) { Ensure.IsNotNull(session, nameof(session)); - Ensure.IsNotNull((object)models, nameof(models)); + Ensure.IsNotNull(models, nameof(models)); var operation = CreateCreateIndexesOperation(models, options); await _collection.ExecuteWriteOperationAsync(session, operation, cancellationToken).ConfigureAwait(false); diff --git a/src/MongoDB.Driver/MongoDatabase.cs b/src/MongoDB.Driver/MongoDatabase.cs index 493f435d713..cb1e0820dff 100644 --- a/src/MongoDB.Driver/MongoDatabase.cs +++ b/src/MongoDB.Driver/MongoDatabase.cs @@ -74,7 +74,7 @@ public IAsyncCursor Aggregate(IClientSessionHandle session, Pi options ??= new AggregateOptions(); var renderArgs = GetRenderArgs(NoPipelineInputSerializer.Instance, options.TranslationOptions); - var renderedPipeline = AggregateHelper.RenderAggregatePipeline(pipeline, renderArgs, out bool isAggregateToCollection); + var renderedPipeline = AggregateHelper.RenderAggregatePipeline(pipeline, renderArgs, out var isAggregateToCollection); if (isAggregateToCollection) { var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); @@ -101,7 +101,7 @@ public async Task> AggregateAsync(IClientSessionH options ??= new AggregateOptions(); var renderArgs = GetRenderArgs(NoPipelineInputSerializer.Instance, options.TranslationOptions); - var renderedPipeline = AggregateHelper.RenderAggregatePipeline(pipeline, renderArgs, out bool isAggregateToCollection); + var renderedPipeline = AggregateHelper.RenderAggregatePipeline(pipeline, renderArgs, out var isAggregateToCollection); if (isAggregateToCollection) { var aggregateOperation = CreateAggregateToCollectionOperation(renderedPipeline, options); @@ -128,7 +128,7 @@ public void AggregateToCollection(IClientSessionHandle session, Pipelin options ??= new AggregateOptions(); var renderArgs = GetRenderArgs(NoPipelineInputSerializer.Instance, options.TranslationOptions); - var renderedPipeline = AggregateHelper.RenderAggregatePipeline(pipeline, renderArgs, out bool isAggregateToCollection); + var renderedPipeline = AggregateHelper.RenderAggregatePipeline(pipeline, renderArgs, out var isAggregateToCollection); if (!isAggregateToCollection) { throw new InvalidOperationException("AggregateToCollection requires that the last stage be $out or $merge."); @@ -151,7 +151,7 @@ public Task AggregateToCollectionAsync(IClientSessionHandle session, Pi options ??= new AggregateOptions(); var renderArgs = GetRenderArgs(NoPipelineInputSerializer.Instance, options.TranslationOptions); - var renderedPipeline = AggregateHelper.RenderAggregatePipeline(pipeline, renderArgs, out bool isAggregateToCollection); + var renderedPipeline = AggregateHelper.RenderAggregatePipeline(pipeline, renderArgs, out var isAggregateToCollection); if (!isAggregateToCollection) { throw new InvalidOperationException("AggregateToCollectionAsync requires that the last stage be $out or $merge."); @@ -291,7 +291,7 @@ public void DropCollection(IClientSessionHandle session, string name, DropCollec Ensure.IsNotNullOrEmpty(name, nameof(name)); var collectionNamespace = new CollectionNamespace(_databaseNamespace, name); - var encryptedFields = GetEncryptedFields(session, collectionNamespace, options, cancellationToken); + var encryptedFields = GetEffectiveEncryptedFields(session, collectionNamespace, options, cancellationToken); var operation = CreateDropCollectionOperation(collectionNamespace, encryptedFields); ExecuteWriteOperation(session, operation, cancellationToken); } @@ -314,7 +314,7 @@ public async Task DropCollectionAsync(IClientSessionHandle session, string name, Ensure.IsNotNullOrEmpty(name, nameof(name)); var collectionNamespace = new CollectionNamespace(_databaseNamespace, name); - var encryptedFields = await GetEncryptedFieldsAsync(session, collectionNamespace, options, cancellationToken).ConfigureAwait(false); + var encryptedFields = await GetEffectiveEncryptedFieldsAsync(session, collectionNamespace, options, cancellationToken).ConfigureAwait(false); var operation = CreateDropCollectionOperation(collectionNamespace, encryptedFields); await ExecuteWriteOperationAsync(session, operation, cancellationToken).ConfigureAwait(false); } @@ -746,14 +746,14 @@ private ChangeStreamOperation CreateChangeStreamOperation( } private TResult ExecuteReadOperation(IClientSessionHandle session, IReadOperation operation, CancellationToken cancellationToken) - => _operationExecutor.ExecuteReadOperation(session, operation, _readOperationOptions, true, cancellationToken); - - private Task ExecuteReadOperationAsync(IClientSessionHandle session, IReadOperation operation, CancellationToken cancellationToken) - => _operationExecutor.ExecuteReadOperationAsync(session, operation, _readOperationOptions, true, cancellationToken); + => ExecuteReadOperation(session, operation, _readOperationOptions, cancellationToken); private TResult ExecuteReadOperation(IClientSessionHandle session, IReadOperation operation, ReadOperationOptions options, CancellationToken cancellationToken) => _operationExecutor.ExecuteReadOperation(session, operation, options, true, cancellationToken); + private Task ExecuteReadOperationAsync(IClientSessionHandle session, IReadOperation operation, CancellationToken cancellationToken) + => ExecuteReadOperationAsync(session, operation, _readOperationOptions, cancellationToken); + private Task ExecuteReadOperationAsync(IClientSessionHandle session, IReadOperation operation, ReadOperationOptions options, CancellationToken cancellationToken) => _operationExecutor.ExecuteReadOperationAsync(session, operation, options, true, cancellationToken); @@ -768,7 +768,7 @@ private IEnumerable ExtractCollectionNames(IEnumerable col return collections.Select(collection => collection["name"].AsString); } - private BsonDocument GetEncryptedFields(IClientSessionHandle session, CollectionNamespace collectionNamespace, DropCollectionOptions options, CancellationToken cancellationToken) + private BsonDocument GetEffectiveEncryptedFields(IClientSessionHandle session, CollectionNamespace collectionNamespace, DropCollectionOptions options, CancellationToken cancellationToken) { var encryptedFieldsMap = _client.Settings?.AutoEncryptionOptions?.EncryptedFieldsMap; if (!EncryptedCollectionHelper.TryGetEffectiveEncryptedFields(collectionNamespace, options?.EncryptedFields, encryptedFieldsMap, out var effectiveEncryptedFields)) @@ -788,7 +788,7 @@ private BsonDocument GetEncryptedFields(IClientSessionHandle session, Collection return effectiveEncryptedFields; } - private async Task GetEncryptedFieldsAsync(IClientSessionHandle session, CollectionNamespace collectionNamespace, DropCollectionOptions options, CancellationToken cancellationToken) + private async Task GetEffectiveEncryptedFieldsAsync(IClientSessionHandle session, CollectionNamespace collectionNamespace, DropCollectionOptions options, CancellationToken cancellationToken) { var encryptedFieldsMap = _client.Settings?.AutoEncryptionOptions?.EncryptedFieldsMap; if (!EncryptedCollectionHelper.TryGetEffectiveEncryptedFields(collectionNamespace, options?.EncryptedFields, encryptedFieldsMap, out var effectiveEncryptedFields)) From 1e830cf123f867cc4f78718c40dfe20673761180 Mon Sep 17 00:00:00 2001 From: Oleksandr Poliakov Date: Wed, 4 Jun 2025 18:56:58 -0700 Subject: [PATCH 13/14] Fix nullreference exception. --- src/MongoDB.Driver/MongoCollectionImpl.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/MongoDB.Driver/MongoCollectionImpl.cs b/src/MongoDB.Driver/MongoCollectionImpl.cs index 5bb176a049c..60347fb231c 100644 --- a/src/MongoDB.Driver/MongoCollectionImpl.cs +++ b/src/MongoDB.Driver/MongoCollectionImpl.cs @@ -497,6 +497,8 @@ public override TProjection FindOneAndUpdate(IClientSessionHandle s Ensure.IsNotNull(session, nameof(session)); Ensure.IsNotNull(filter, nameof(filter)); Ensure.IsNotNull(update, nameof(update)); + + options ??= new FindOneAndUpdateOptions(); if (update is PipelineUpdateDefinition && (options.ArrayFilters != null && options.ArrayFilters.Any())) { throw new NotSupportedException("An arrayfilter is not supported in the pipeline-style update."); @@ -517,6 +519,7 @@ public override Task FindOneAndUpdateAsync(IClientSess Ensure.IsNotNull(session, nameof(session)); Ensure.IsNotNull(filter, nameof(filter)); Ensure.IsNotNull(update, nameof(update)); + options ??= new FindOneAndUpdateOptions(); if (update is PipelineUpdateDefinition && (options.ArrayFilters != null && options.ArrayFilters.Any())) { throw new NotSupportedException("An arrayfilter is not supported in the pipeline-style update."); @@ -1030,7 +1033,6 @@ private FindOneAndUpdateOperation CreateFindOneAndUpdateOperation update, FindOneAndUpdateOptions options) { - options = options ?? new FindOneAndUpdateOptions(); var renderArgs = GetRenderArgs(); var projection = options.Projection ?? new ClientSideDeserializationProjectionDefinition(); var renderedProjection = projection.Render(renderArgs with { RenderForFind = true }); From f1cd24ef45f32e2309d4b1bd929da12405adcfce Mon Sep 17 00:00:00 2001 From: Oleksandr Poliakov Date: Thu, 5 Jun 2025 11:58:50 -0700 Subject: [PATCH 14/14] Pr --- src/MongoDB.Driver/MongoCollectionImpl.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/MongoDB.Driver/MongoCollectionImpl.cs b/src/MongoDB.Driver/MongoCollectionImpl.cs index 60347fb231c..4b0b144e960 100644 --- a/src/MongoDB.Driver/MongoCollectionImpl.cs +++ b/src/MongoDB.Driver/MongoCollectionImpl.cs @@ -1473,7 +1473,7 @@ public override void DropOne(IClientSessionHandle session, string name, DropInde Ensure.IsNotNullOrEmpty(name, nameof(name)); if (name == "*") { - throw new ArgumentException("Cannot specify '*' for the index name. Use DropAll and DropAllAsync to drop all indexes.", "name"); + throw new ArgumentException($"Cannot specify '*' for the index name. Use {nameof(DropAll)} to drop all indexes.", nameof(name)); } var operation = CreateDropOneOperation(name, options); @@ -1498,7 +1498,7 @@ public override Task DropOneAsync(IClientSessionHandle session, string name, Dro Ensure.IsNotNullOrEmpty(name, nameof(name)); if (name == "*") { - throw new ArgumentException("Cannot specify '*' for the index name. Use DropAll and DropAllAsync to drop all indexes.", "name"); + throw new ArgumentException($"Cannot specify '*' for the index name. Use {nameof(DropAllAsync)} to drop all indexes.", nameof(name)); } var operation = CreateDropOneOperation(name, options);