Skip to content

Commit f11ded8

Browse files
CSHARP-2808: Support ability to pass hint to update
1 parent aa919d7 commit f11ded8

33 files changed

+1380
-42
lines changed

src/MongoDB.Driver.Core/Core/Misc/Feature.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ public class Feature
5858
private static readonly Feature __findCommand = new Feature("FindCommand", new SemanticVersion(3, 2, 0));
5959
private static readonly Feature __geoNearCommand = new Feature("GeoNearCommand", new SemanticVersion(1, 0, 0), new SemanticVersion(4, 1, 0, ""));
6060
private static readonly Feature __groupCommand = new Feature("GroupCommand", new SemanticVersion(1, 0, 0), new SemanticVersion(4, 1, 1, ""));
61+
private static readonly HintForUpdateAndReplaceOperationsFeature __hintForUpdateAndReplaceOperations = new HintForUpdateAndReplaceOperationsFeature("HintForUpdateAndReplaceOperations", new SemanticVersion(4, 2, 0));
6162
private static readonly Feature __keepConnectionPoolWhenNotMasterConnectionException = new Feature("KeepConnectionPoolWhenNotMasterConnectionException", new SemanticVersion(4, 1, 10));
6263
private static readonly Feature __keepConnectionPoolWhenReplSetStepDown = new Feature("KeepConnectionPoolWhenReplSetStepDown", new SemanticVersion(4, 1, 10));
6364
private static readonly Feature __killCursorsCommand = new Feature("KillCursorsCommand", new SemanticVersion(3, 2, 0));
@@ -258,6 +259,11 @@ public class Feature
258259
/// </summary>
259260
public static Feature GroupCommand => __groupCommand;
260261

262+
/// <summary>
263+
/// Gets the hint for write operations feature.
264+
/// </summary>
265+
public static HintForUpdateAndReplaceOperationsFeature HintForUpdateAndReplaceOperations => __hintForUpdateAndReplaceOperations;
266+
261267
/// <summary>
262268
/// Gets the keep connection pool when NotMaster connection exception feature.
263269
/// </summary>
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/* Copyright 2020-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
namespace MongoDB.Driver.Core.Misc
17+
{
18+
/// <summary>
19+
/// Represents the hint for update and replace operations feature.
20+
/// </summary>
21+
/// <seealso cref="MongoDB.Driver.Core.Misc.Feature" />
22+
public class HintForUpdateAndReplaceOperationsFeature : Feature
23+
{
24+
private readonly SemanticVersion _firstServerVersionWhereWeRelyOnServerToReturnError = new SemanticVersion(3, 4, 0);
25+
26+
/// <summary>
27+
/// Initializes a new instance of the <see cref="HintForUpdateAndReplaceOperationsFeature"/> class.
28+
/// </summary>
29+
/// <param name="name">The name of the feature.</param>
30+
/// <param name="firstSupportedVersion">The first server version that supports the feature.</param>
31+
public HintForUpdateAndReplaceOperationsFeature(string name, SemanticVersion firstSupportedVersion)
32+
: base(name, firstSupportedVersion)
33+
{
34+
}
35+
36+
/// <summary>
37+
/// Determines whether the driver must throw an exception if the feature is not supported by the server.
38+
/// </summary>
39+
/// <param name="serverVersion">The server version.</param>
40+
/// <returns>Whether the driver must throw if feature is not supported.</returns>
41+
public bool DriverMustThrowIfNotSupported(SemanticVersion serverVersion)
42+
{
43+
return serverVersion < _firstServerVersionWhereWeRelyOnServerToReturnError;
44+
}
45+
}
46+
}

src/MongoDB.Driver.Core/Core/Operations/BulkDeleteOperation.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,10 @@ protected override bool RequestHasCollation(DeleteRequest request)
4747
{
4848
return request.Collation != null;
4949
}
50+
51+
protected override bool RequestHasHint(DeleteRequest request)
52+
{
53+
return false;
54+
}
5055
}
5156
}

src/MongoDB.Driver.Core/Core/Operations/BulkInsertOperation.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
* limitations under the License.
1414
*/
1515

16-
using System;
1716
using System.Collections.Generic;
1817
using MongoDB.Bson;
1918
using MongoDB.Bson.Serialization;
@@ -51,6 +50,11 @@ protected override bool RequestHasCollation(InsertRequest request)
5150
return false;
5251
}
5352

53+
protected override bool RequestHasHint(InsertRequest request)
54+
{
55+
return false;
56+
}
57+
5458
// nested types
5559
private class InsertRequestSerializer : SealedClassSerializerBase<InsertRequest>
5660
{

src/MongoDB.Driver.Core/Core/Operations/BulkMixedWriteOperation.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ public BulkWriteOperationResult Execute(IWriteBinding binding, CancellationToken
214214
using (var context = RetryableWriteContext.Create(binding, _retryRequested, cancellationToken))
215215
{
216216
EnsureCollationIsSupportedIfAnyRequestHasCollation(context);
217+
EnsureHintIsSupportedIfAnyRequestHasHint(context);
217218
context.DisableRetriesIfAnyWriteRequestIsNotRetryable(_requests);
218219
var helper = new BatchHelper(_requests, _isOrdered, _writeConcern);
219220
foreach (var batch in helper.GetBatches())
@@ -231,6 +232,7 @@ public async Task<BulkWriteOperationResult> ExecuteAsync(IWriteBinding binding,
231232
using (var context = await RetryableWriteContext.CreateAsync(binding, _retryRequested, cancellationToken).ConfigureAwait(false))
232233
{
233234
EnsureCollationIsSupportedIfAnyRequestHasCollation(context);
235+
EnsureHintIsSupportedIfAnyRequestHasHint(context);
234236
context.DisableRetriesIfAnyWriteRequestIsNotRetryable(_requests);
235237
var helper = new BatchHelper(_requests, _isOrdered, _writeConcern);
236238
foreach (var batch in helper.GetBatches())
@@ -309,6 +311,21 @@ private void EnsureCollationIsSupportedIfAnyRequestHasCollation(RetryableWriteCo
309311
}
310312
}
311313

314+
private void EnsureHintIsSupportedIfAnyRequestHasHint(RetryableWriteContext context)
315+
{
316+
var serverVersion = context.Channel.ConnectionDescription.ServerVersion;
317+
if (Feature.HintForUpdateAndReplaceOperations.DriverMustThrowIfNotSupported(serverVersion))
318+
{
319+
foreach (var request in _requests)
320+
{
321+
if (RequestHasHint(request))
322+
{
323+
throw new NotSupportedException($"Server version {serverVersion} does not support hints.");
324+
}
325+
}
326+
}
327+
}
328+
312329
private BulkWriteBatchResult ExecuteBatch(RetryableWriteContext context, Batch batch, CancellationToken cancellationToken)
313330
{
314331
BulkWriteOperationResult result;
@@ -362,6 +379,11 @@ private bool RequestHasCollation(WriteRequest request)
362379
return false;
363380
}
364381

382+
private bool RequestHasHint(WriteRequest request)
383+
{
384+
return request is UpdateRequest updateRequest && updateRequest.Hint != null;
385+
}
386+
365387
// nested types
366388
private class Batch
367389
{

src/MongoDB.Driver.Core/Core/Operations/BulkUnmixedWriteOperationBase.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ public WriteConcern WriteConcern
116116
public BulkWriteOperationResult Execute(RetryableWriteContext context, CancellationToken cancellationToken)
117117
{
118118
EnsureCollationIsSupportedIfAnyRequestHasCollation(context, _requests);
119+
EnsureHintIsSupportedIfAnyRequestHasHint(context, _requests);
119120

120121
return ExecuteBatches(context, cancellationToken);
121122
}
@@ -133,6 +134,7 @@ public BulkWriteOperationResult Execute(IWriteBinding binding, CancellationToken
133134
public Task<BulkWriteOperationResult> ExecuteAsync(RetryableWriteContext context, CancellationToken cancellationToken)
134135
{
135136
EnsureCollationIsSupportedIfAnyRequestHasCollation(context, _requests);
137+
EnsureHintIsSupportedIfAnyRequestHasHint(context, _requests);
136138

137139
return ExecuteBatchesAsync(context, cancellationToken);
138140
}
@@ -152,6 +154,8 @@ public async Task<BulkWriteOperationResult> ExecuteAsync(IWriteBinding binding,
152154

153155
protected abstract bool RequestHasCollation(TWriteRequest request);
154156

157+
protected abstract bool RequestHasHint(TWriteRequest request);
158+
155159
// private methods
156160
private BulkWriteBatchResult CreateBatchResult(Batch batch, BsonDocument writeCommandResult)
157161
{
@@ -179,6 +183,22 @@ private void EnsureCollationIsSupportedIfAnyRequestHasCollation(RetryableWriteCo
179183
}
180184
}
181185
}
186+
187+
private void EnsureHintIsSupportedIfAnyRequestHasHint(RetryableWriteContext context, IEnumerable<TWriteRequest> requests)
188+
{
189+
var serverVersion = context.Channel.ConnectionDescription.ServerVersion;
190+
if (Feature.HintForUpdateAndReplaceOperations.DriverMustThrowIfNotSupported(serverVersion))
191+
{
192+
foreach (var request in requests)
193+
{
194+
if (RequestHasHint(request))
195+
{
196+
throw new NotSupportedException($"Server version {serverVersion} does not support hints.");
197+
}
198+
}
199+
}
200+
}
201+
182202
private BulkWriteBatchResult ExecuteBatch(RetryableWriteContext context, Batch batch, CancellationToken cancellationToken)
183203
{
184204
var operation = CreateBatchOperation(batch);

src/MongoDB.Driver.Core/Core/Operations/BulkUpdateOperation.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,10 @@ protected override bool RequestHasCollation(UpdateRequest request)
4848
{
4949
return request.Collation != null;
5050
}
51+
52+
protected override bool RequestHasHint(UpdateRequest request)
53+
{
54+
return request.Hint != null;
55+
}
5156
}
5257
}

src/MongoDB.Driver.Core/Core/Operations/RetryableUpdateCommandOperation.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,13 @@ protected override BsonDocument CreateCommand(ICoreSessionHandle session, Connec
108108
throw new NotSupportedException($"Server version {serverVersion} does not support arrayFilters.");
109109
}
110110
}
111+
if (Feature.HintForUpdateAndReplaceOperations.DriverMustThrowIfNotSupported(serverVersion))
112+
{
113+
if (_updates.Items.Skip(_updates.Offset).Take(_updates.Count).Any(u => u.Hint != null))
114+
{
115+
throw new NotSupportedException($"Server version {serverVersion} does not support hints.");
116+
}
117+
}
111118

112119
var writeConcern = WriteConcernHelper.GetWriteConcernForWriteCommand(session, WriteConcern);
113120
return new BsonDocument
@@ -176,6 +183,11 @@ protected override void SerializeValue(BsonSerializationContext context, BsonSer
176183
}
177184
writer.WriteEndArray();
178185
}
186+
if (value.Hint != null)
187+
{
188+
writer.WriteName("hint");
189+
BsonValueSerializer.Instance.Serialize(context, value.Hint);
190+
}
179191
writer.WriteEndDocument();
180192
}
181193

src/MongoDB.Driver.Core/Core/Operations/UpdateRequest.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public sealed class UpdateRequest : WriteRequest
3030
private IEnumerable<BsonDocument> _arrayFilters;
3131
private Collation _collation;
3232
private readonly BsonDocument _filter;
33+
private BsonValue _hint;
3334
private bool _isMulti;
3435
private bool _isUpsert;
3536
private readonly BsonValue _update;
@@ -80,6 +81,15 @@ public BsonDocument Filter
8081
get { return _filter; }
8182
}
8283

84+
/// <summary>
85+
/// Gets or sets the hint.
86+
/// </summary>
87+
public BsonValue Hint
88+
{
89+
get { return _hint; }
90+
set { _hint = value; }
91+
}
92+
8393
/// <summary>
8494
/// Gets or sets a value indicating whether this update should affect all matching documents.
8595
/// </summary>

src/MongoDB.Driver/FilteredMongoCollectionBase.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ private IEnumerable<WriteModel<TDocument>> CombineModelFilters(IEnumerable<Write
341341
return new ReplaceOneModel<TDocument>(CombineFilters(replaceOneModel.Filter), replaceOneModel.Replacement)
342342
{
343343
Collation = replaceOneModel.Collation,
344+
Hint = replaceOneModel.Hint,
344345
IsUpsert = replaceOneModel.IsUpsert
345346
};
346347
case WriteModelType.UpdateMany:
@@ -349,6 +350,7 @@ private IEnumerable<WriteModel<TDocument>> CombineModelFilters(IEnumerable<Write
349350
{
350351
ArrayFilters = updateManyModel.ArrayFilters,
351352
Collation = updateManyModel.Collation,
353+
Hint = updateManyModel.Hint,
352354
IsUpsert = updateManyModel.IsUpsert
353355
};
354356
case WriteModelType.UpdateOne:
@@ -357,6 +359,7 @@ private IEnumerable<WriteModel<TDocument>> CombineModelFilters(IEnumerable<Write
357359
{
358360
ArrayFilters = updateOneModel.ArrayFilters,
359361
Collation = updateOneModel.Collation,
362+
Hint = updateOneModel.Hint,
360363
IsUpsert = updateOneModel.IsUpsert
361364
};
362365
default:

0 commit comments

Comments
 (0)