Skip to content

Commit 0f738fd

Browse files
authored
CSHARP-1378: Make BulkWrite enumerate requests argument only once (#1298)
1 parent 5f7fc33 commit 0f738fd

File tree

4 files changed

+65
-26
lines changed

4 files changed

+65
-26
lines changed

src/MongoDB.Driver/BulkWriteResult.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,10 @@ public abstract class BulkWriteResult<TDocument> : BulkWriteResult
104104
/// <param name="processedRequests">The processed requests.</param>
105105
protected BulkWriteResult(
106106
int requestCount,
107-
IEnumerable<WriteModel<TDocument>> processedRequests)
107+
IReadOnlyList<WriteModel<TDocument>> processedRequests)
108108
: base(requestCount)
109109
{
110-
_processedRequests = processedRequests.ToList();
110+
_processedRequests = processedRequests;
111111
}
112112

113113
// public properties
@@ -130,16 +130,16 @@ internal static BulkWriteResult<TDocument> FromCore(Core.Operations.BulkWriteOpe
130130
result.DeletedCount,
131131
result.InsertedCount,
132132
result.IsModifiedCountAvailable ? (long?)result.ModifiedCount : null,
133-
result.ProcessedRequests.Select(r => WriteModel<TDocument>.FromCore(r)),
134-
result.Upserts.Select(u => BulkWriteUpsert.FromCore(u)));
133+
result.ProcessedRequests.Select(WriteModel<TDocument>.FromCore).ToArray(),
134+
result.Upserts.Select(BulkWriteUpsert.FromCore));
135135
}
136136

137137
return new Unacknowledged(
138138
result.RequestCount,
139-
result.ProcessedRequests.Select(r => WriteModel<TDocument>.FromCore(r)));
139+
result.ProcessedRequests.Select(WriteModel<TDocument>.FromCore).ToArray());
140140
}
141141

142-
internal static BulkWriteResult<TDocument> FromCore(Core.Operations.BulkWriteOperationResult result, IEnumerable<WriteModel<TDocument>> requests)
142+
internal static BulkWriteResult<TDocument> FromCore(Core.Operations.BulkWriteOperationResult result, IReadOnlyList<WriteModel<TDocument>> requests)
143143
{
144144
if (result.IsAcknowledged)
145145
{
@@ -150,7 +150,7 @@ internal static BulkWriteResult<TDocument> FromCore(Core.Operations.BulkWriteOpe
150150
result.InsertedCount,
151151
result.IsModifiedCountAvailable ? (long?)result.ModifiedCount : null,
152152
requests,
153-
result.Upserts.Select(u => BulkWriteUpsert.FromCore(u)));
153+
result.Upserts.Select(BulkWriteUpsert.FromCore));
154154
}
155155

156156
return new Unacknowledged(
@@ -174,7 +174,7 @@ public class Acknowledged : BulkWriteResult<TDocument>
174174

175175
// constructors
176176
/// <summary>
177-
/// Initializes a new instance of the <see cref="Acknowledged" /> class.
177+
/// Initializes a new instance of the <see cref="BulkWriteResult{TDocument}.Acknowledged" /> class.
178178
/// </summary>
179179
/// <param name="requestCount">The request count.</param>
180180
/// <param name="matchedCount">The matched count.</param>
@@ -189,7 +189,7 @@ public Acknowledged(
189189
long deletedCount,
190190
long insertedCount,
191191
long? modifiedCount,
192-
IEnumerable<WriteModel<TDocument>> processedRequests,
192+
IReadOnlyList<WriteModel<TDocument>> processedRequests,
193193
IEnumerable<BulkWriteUpsert> upserts)
194194
: base(requestCount, processedRequests)
195195
{
@@ -259,13 +259,13 @@ public class Unacknowledged : BulkWriteResult<TDocument>
259259
{
260260
// constructors
261261
/// <summary>
262-
/// Initializes a new instance of the <see cref="Unacknowledged"/> class.
262+
/// Initializes a new instance of the <see cref="BulkWriteResult{TDocument}.Unacknowledged"/> class.
263263
/// </summary>
264264
/// <param name="requestCount">The request count.</param>
265265
/// <param name="processedRequests">The processed requests.</param>
266266
public Unacknowledged(
267267
int requestCount,
268-
IEnumerable<WriteModel<TDocument>> processedRequests)
268+
IReadOnlyList<WriteModel<TDocument>> processedRequests)
269269
: base(requestCount, processedRequests)
270270
{
271271
}

src/MongoDB.Driver/MongoBulkWriteException.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ internal static MongoBulkWriteException<TDocument> FromCore(MongoBulkWriteOperat
234234

235235
return new MongoBulkWriteException<TDocument>(
236236
ex.ConnectionId,
237-
BulkWriteResult<TDocument>.FromCore(ex.Result, processedRequests),
237+
BulkWriteResult<TDocument>.FromCore(ex.Result, processedRequests.ToArray()),
238238
ex.WriteErrors.Select(e => BulkWriteError.FromCore(e)),
239239
WriteConcernError.FromCore(ex.WriteConcernError),
240240
unprocessedRequests);

src/MongoDB.Driver/MongoCollectionImpl.cs

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -218,27 +218,30 @@ public override MongoCollectionSettings Settings
218218
public override BulkWriteResult<TDocument> BulkWrite(IClientSessionHandle session, IEnumerable<WriteModel<TDocument>> requests, BulkWriteOptions options, CancellationToken cancellationToken = default(CancellationToken))
219219
{
220220
Ensure.IsNotNull(session, nameof(session));
221-
Ensure.IsNotNull(requests, nameof(requests));
222-
if (!requests.Any())
221+
Ensure.IsNotNull((object)requests, nameof(requests));
222+
223+
var requestsArray = requests.ToArray();
224+
if (requestsArray.Length == 0)
223225
{
224-
throw new ArgumentException("Must contain at least 1 request.", "requests");
226+
throw new ArgumentException("Must contain at least 1 request.", nameof(requests));
225227
}
226-
foreach (var request in requests)
228+
229+
foreach (var request in requestsArray)
227230
{
228231
request.ThrowIfNotValid();
229232
}
230233

231234
options = options ?? new BulkWriteOptions();
232235

233-
var operation = CreateBulkWriteOperation(session, requests, options);
236+
var operation = CreateBulkWriteOperation(session, requestsArray, options);
234237
try
235238
{
236239
var result = ExecuteWriteOperation(session, operation, cancellationToken);
237-
return BulkWriteResult<TDocument>.FromCore(result, requests);
240+
return BulkWriteResult<TDocument>.FromCore(result, requestsArray);
238241
}
239242
catch (MongoBulkWriteOperationException ex)
240243
{
241-
throw MongoBulkWriteException<TDocument>.FromCore(ex, requests.ToList());
244+
throw MongoBulkWriteException<TDocument>.FromCore(ex, requestsArray);
242245
}
243246
}
244247

@@ -250,27 +253,30 @@ public override MongoCollectionSettings Settings
250253
public override async Task<BulkWriteResult<TDocument>> BulkWriteAsync(IClientSessionHandle session, IEnumerable<WriteModel<TDocument>> requests, BulkWriteOptions options, CancellationToken cancellationToken = default(CancellationToken))
251254
{
252255
Ensure.IsNotNull(session, nameof(session));
253-
Ensure.IsNotNull(requests, nameof(requests));
254-
if (!requests.Any())
256+
Ensure.IsNotNull((object)requests, nameof(requests));
257+
258+
var requestsArray = requests.ToArray();
259+
if (requestsArray.Length == 0)
255260
{
256-
throw new ArgumentException("Must contain at least 1 request.", "requests");
261+
throw new ArgumentException("Must contain at least 1 request.", nameof(requests));
257262
}
258-
foreach (var request in requests)
263+
264+
foreach (var request in requestsArray)
259265
{
260266
request.ThrowIfNotValid();
261267
}
262268

263269
options = options ?? new BulkWriteOptions();
264270

265-
var operation = CreateBulkWriteOperation(session, requests, options);
271+
var operation = CreateBulkWriteOperation(session, requestsArray, options);
266272
try
267273
{
268274
var result = await ExecuteWriteOperationAsync(session, operation, cancellationToken).ConfigureAwait(false);
269-
return BulkWriteResult<TDocument>.FromCore(result, requests);
275+
return BulkWriteResult<TDocument>.FromCore(result, requestsArray);
270276
}
271277
catch (MongoBulkWriteOperationException ex)
272278
{
273-
throw MongoBulkWriteException<TDocument>.FromCore(ex, requests.ToList());
279+
throw MongoBulkWriteException<TDocument>.FromCore(ex, requestsArray);
274280
}
275281
}
276282

tests/MongoDB.Driver.Tests/MongoCollectionImplTests.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
using System.Linq.Expressions;
2020
using System.Net;
2121
using System.Threading;
22+
using System.Threading.Tasks;
2223
using FluentAssertions;
2324
using MongoDB.Bson;
2425
using MongoDB.Bson.Serialization;
@@ -31,6 +32,7 @@
3132
using MongoDB.Driver.Core.Operations;
3233
using MongoDB.Driver.Core.Servers;
3334
using MongoDB.Driver.Core.TestHelpers.XunitExtensions;
35+
using MongoDB.Driver.TestHelpers;
3436
using MongoDB.Driver.Tests;
3537
using Moq;
3638
using Xunit;
@@ -442,6 +444,37 @@ public void AggregateToCollection_should_throw_when_last_stage_is_not_an_output_
442444
exception.Should().BeOfType<InvalidOperationException>();
443445
}
444446

447+
[Theory]
448+
[ParameterAttributeData]
449+
public async Task BulkWrite_should_enumerate_requests_once([Values(false, true)] bool async)
450+
{
451+
var subject = CreateSubject<BsonDocument>();
452+
var document = new BsonDocument("_id", 1).Add("a", 1);
453+
var requests = new WriteModel<BsonDocument>[]
454+
{
455+
new InsertOneModel<BsonDocument>(document)
456+
};
457+
var processedRequest = new InsertRequest(document) { CorrelationId = 0 };
458+
var operationResult = new BulkWriteOperationResult.Acknowledged(
459+
requestCount: 1,
460+
matchedCount: 0,
461+
deletedCount: 0,
462+
insertedCount: 1,
463+
modifiedCount: 0,
464+
processedRequests: new[] { processedRequest },
465+
upserts: new List<BulkWriteOperationUpsert>());
466+
_operationExecutor.EnqueueResult<BulkWriteOperationResult>(operationResult);
467+
var wrappedRequests = new Mock<IEnumerable<WriteModel<BsonDocument>>>();
468+
wrappedRequests.Setup(e => e.GetEnumerator()).Returns(((IEnumerable<WriteModel<BsonDocument>>)requests).GetEnumerator());
469+
470+
var result = async ? await subject.BulkWriteAsync(wrappedRequests.Object) : subject.BulkWrite(wrappedRequests.Object);
471+
472+
wrappedRequests.Verify(e => e.GetEnumerator(), Times.Once);
473+
result.Should().NotBeNull();
474+
result.RequestCount.Should().Be(1);
475+
result.ProcessedRequests.ShouldBeEquivalentTo(requests);
476+
}
477+
445478
[Theory]
446479
[ParameterAttributeData]
447480
public void BulkWrite_should_execute_a_BulkMixedWriteOperation(

0 commit comments

Comments
 (0)