Skip to content

Commit dff7de8

Browse files
committed
CSHARP-2221: Update JSON driven transaction tests.
1 parent 46d3c00 commit dff7de8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+17450
-152
lines changed

src/MongoDB.Driver.Core/Core/Bindings/CoreSession.cs

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,6 @@ public bool IsInTransaction
127127
ExecuteEndTransactionOnPrimary(firstAttempt, cancellationToken);
128128
return;
129129
}
130-
catch (Exception exception) when (ShouldIgnoreAbortTransactionException(exception))
131-
{
132-
return; // ignore exception and return
133-
}
134130
catch (Exception exception) when (ShouldRetryEndTransactionException(exception))
135131
{
136132
// ignore exception and retry
@@ -174,10 +170,6 @@ public bool IsInTransaction
174170
await ExecuteEndTransactionOnPrimaryAsync(firstAttempt, cancellationToken).ConfigureAwait(false);
175171
return;
176172
}
177-
catch (Exception exception) when (ShouldIgnoreAbortTransactionException(exception))
178-
{
179-
return; // ignore exception and return
180-
}
181173
catch (Exception exception) when (ShouldRetryEndTransactionException(exception))
182174
{
183175
// ignore exception and retry
@@ -470,17 +462,6 @@ private WriteConcern GetTransactionWriteConcern()
470462
WriteConcern.WMajority;
471463
}
472464

473-
private bool ShouldIgnoreAbortTransactionException(Exception exception)
474-
{
475-
var commandException = exception as MongoCommandException;
476-
if (commandException != null)
477-
{
478-
return true;
479-
}
480-
481-
return false;
482-
}
483-
484465
private bool ShouldRetryEndTransactionException(Exception exception)
485466
{
486467
return RetryabilityHelper.IsRetryableWriteException(exception);

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

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public MessageEncoderSettings MessageEncoderSettings
7575

7676
// public methods
7777
/// <inheritdoc />
78-
public BsonDocument Execute(IReadBinding binding, CancellationToken cancellationToken)
78+
public virtual BsonDocument Execute(IReadBinding binding, CancellationToken cancellationToken)
7979
{
8080
Ensure.IsNotNull(binding, nameof(binding));
8181

@@ -91,7 +91,7 @@ public BsonDocument Execute(IReadBinding binding, CancellationToken cancellation
9191
}
9292

9393
/// <inheritdoc />
94-
public async Task<BsonDocument> ExecuteAsync(IReadBinding binding, CancellationToken cancellationToken)
94+
public virtual async Task<BsonDocument> ExecuteAsync(IReadBinding binding, CancellationToken cancellationToken)
9595
{
9696
Ensure.IsNotNull(binding, nameof(binding));
9797

@@ -161,5 +161,75 @@ public CommitTransactionOperation(WriteConcern writeConcern)
161161
// protected properties
162162
/// <inheritdoc />
163163
protected override string CommandName => "commitTransaction";
164+
165+
// public methods
166+
/// <inheritdoc />
167+
public override BsonDocument Execute(IReadBinding binding, CancellationToken cancellationToken)
168+
{
169+
try
170+
{
171+
return base.Execute(binding, cancellationToken);
172+
}
173+
catch (MongoException exception) when (ShouldReplaceTransientTransactionErrorWithUnknownTransactionCommitResult(exception))
174+
{
175+
ReplaceTransientTransactionErrorWithUnknownTransactionCommitResult(exception);
176+
throw;
177+
}
178+
}
179+
180+
/// <inheritdoc />
181+
public override async Task<BsonDocument> ExecuteAsync(IReadBinding binding, CancellationToken cancellationToken)
182+
{
183+
try
184+
{
185+
return await base.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false);
186+
}
187+
catch (MongoException exception) when (ShouldReplaceTransientTransactionErrorWithUnknownTransactionCommitResult(exception))
188+
{
189+
ReplaceTransientTransactionErrorWithUnknownTransactionCommitResult(exception);
190+
throw;
191+
}
192+
}
193+
194+
// private methods
195+
private void ReplaceTransientTransactionErrorWithUnknownTransactionCommitResult(MongoException exception)
196+
{
197+
exception.RemoveErrorLabel("TransientTransactionError");
198+
exception.AddErrorLabel("UnknownTransactionCommitResult");
199+
}
200+
201+
private bool ShouldReplaceTransientTransactionErrorWithUnknownTransactionCommitResult(MongoException exception)
202+
{
203+
if (exception is MongoConnectionException)
204+
{
205+
return true;
206+
}
207+
208+
if (exception is MongoNotPrimaryException || exception is MongoNodeIsRecoveringException)
209+
{
210+
return true;
211+
}
212+
213+
var writeConcernException = exception as MongoWriteConcernException;
214+
if (writeConcernException != null)
215+
{
216+
var writeConcernError = writeConcernException.WriteConcernResult.Response?.GetValue("writeConcernError", null)?.AsBsonDocument;
217+
if (writeConcernError != null)
218+
{
219+
var code = (ServerErrorCode)writeConcernError.GetValue("code", -1).ToInt32();
220+
switch (code)
221+
{
222+
case ServerErrorCode.UnsatisfiableWriteConcern:
223+
case ServerErrorCode.UnknownReplWriteConcern:
224+
return false;
225+
226+
default:
227+
return true;
228+
}
229+
}
230+
}
231+
232+
return false;
233+
}
164234
}
165235
}

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

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,42 @@ public static bool IsRetryableWriteException(Exception exception)
9292
if (commandException != null)
9393
{
9494
var code = (ServerErrorCode)commandException.Code;
95-
return __retryableWriteErrorCodes.Contains(code);
95+
if (__retryableWriteErrorCodes.Contains(code))
96+
{
97+
return true;
98+
}
99+
}
100+
101+
var writeConcernException = exception as MongoWriteConcernException;
102+
if (writeConcernException != null)
103+
{
104+
var writeConcernError = writeConcernException.WriteConcernResult.Response.GetValue("writeConcernError", null)?.AsBsonDocument;
105+
if (writeConcernError != null)
106+
{
107+
var code = (ServerErrorCode)writeConcernError.GetValue("code", -1).AsInt32;
108+
switch (code)
109+
{
110+
case ServerErrorCode.InterruptedAtShutdown:
111+
case ServerErrorCode.InterruptedDueToReplStateChange:
112+
case ServerErrorCode.NotMaster:
113+
case ServerErrorCode.NotMasterNoSlaveOk:
114+
case ServerErrorCode.NotMasterOrSecondary:
115+
case ServerErrorCode.PrimarySteppedDown:
116+
case ServerErrorCode.ShutdownInProgress:
117+
case ServerErrorCode.HostNotFound:
118+
case ServerErrorCode.HostUnreachable:
119+
case ServerErrorCode.NetworkTimeout:
120+
case ServerErrorCode.SocketException:
121+
return true;
122+
}
123+
124+
var message = writeConcernError.GetValue("errmsg", null)?.AsString;
125+
if (message.IndexOf("not master", StringComparison.OrdinalIgnoreCase) != -1 ||
126+
message.IndexOf("node is recovering", StringComparison.OrdinalIgnoreCase) != -1)
127+
{
128+
return true;
129+
}
130+
}
96131
}
97132

98133
return false;

src/MongoDB.Driver.Core/Core/WireProtocol/CommandUsingCommandMessageWireProtocol.cs

Lines changed: 59 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -82,51 +82,67 @@ public CommandUsingCommandMessageWireProtocol(
8282
// public methods
8383
public TCommandResult Execute(IConnection connection, CancellationToken cancellationToken)
8484
{
85-
var message = CreateCommandMessage(connection.Description);
86-
8785
try
8886
{
89-
connection.SendMessage(message, _messageEncoderSettings, cancellationToken);
90-
}
91-
finally
92-
{
93-
MessageWasProbablySent(message);
94-
}
87+
var message = CreateCommandMessage(connection.Description);
9588

96-
if (message.WrappedMessage.ResponseExpected)
97-
{
98-
var encoderSelector = new CommandResponseMessageEncoderSelector();
99-
var response = (CommandResponseMessage)connection.ReceiveMessage(message.RequestId, encoderSelector, _messageEncoderSettings, cancellationToken);
100-
return ProcessResponse(connection.ConnectionId, response.WrappedMessage);
89+
try
90+
{
91+
connection.SendMessage(message, _messageEncoderSettings, cancellationToken);
92+
}
93+
finally
94+
{
95+
MessageWasProbablySent(message);
96+
}
97+
98+
if (message.WrappedMessage.ResponseExpected)
99+
{
100+
var encoderSelector = new CommandResponseMessageEncoderSelector();
101+
var response = (CommandResponseMessage)connection.ReceiveMessage(message.RequestId, encoderSelector, _messageEncoderSettings, cancellationToken);
102+
return ProcessResponse(connection.ConnectionId, response.WrappedMessage);
103+
}
104+
else
105+
{
106+
return default(TCommandResult);
107+
}
101108
}
102-
else
109+
catch (MongoException exception) when (ShouldAddTransientTransactionError(exception))
103110
{
104-
return default(TCommandResult);
111+
exception.AddErrorLabel("TransientTransactionError");
112+
throw;
105113
}
106114
}
107115

108116
public async Task<TCommandResult> ExecuteAsync(IConnection connection, CancellationToken cancellationToken)
109117
{
110-
var message = CreateCommandMessage(connection.Description);
111-
112118
try
113119
{
114-
await connection.SendMessageAsync(message, _messageEncoderSettings, cancellationToken).ConfigureAwait(false);
115-
}
116-
finally
117-
{
118-
MessageWasProbablySent(message);
119-
}
120+
var message = CreateCommandMessage(connection.Description);
120121

121-
if (message.WrappedMessage.ResponseExpected)
122-
{
123-
var encoderSelector = new CommandResponseMessageEncoderSelector();
124-
var response = (CommandResponseMessage)await connection.ReceiveMessageAsync(message.RequestId, encoderSelector, _messageEncoderSettings, cancellationToken).ConfigureAwait(false);
125-
return ProcessResponse(connection.ConnectionId, response.WrappedMessage);
122+
try
123+
{
124+
await connection.SendMessageAsync(message, _messageEncoderSettings, cancellationToken).ConfigureAwait(false);
125+
}
126+
finally
127+
{
128+
MessageWasProbablySent(message);
129+
}
130+
131+
if (message.WrappedMessage.ResponseExpected)
132+
{
133+
var encoderSelector = new CommandResponseMessageEncoderSelector();
134+
var response = (CommandResponseMessage)await connection.ReceiveMessageAsync(message.RequestId, encoderSelector, _messageEncoderSettings, cancellationToken).ConfigureAwait(false);
135+
return ProcessResponse(connection.ConnectionId, response.WrappedMessage);
136+
}
137+
else
138+
{
139+
return default(TCommandResult);
140+
}
126141
}
127-
else
142+
catch (MongoException exception) when (ShouldAddTransientTransactionError(exception))
128143
{
129-
return default(TCommandResult);
144+
exception.AddErrorLabel("TransientTransactionError");
145+
throw;
130146
}
131147
}
132148

@@ -297,5 +313,18 @@ private TCommandResult ProcessResponse(ConnectionId connectionId, CommandMessage
297313
}
298314
}
299315
}
316+
317+
private bool ShouldAddTransientTransactionError(MongoException exception)
318+
{
319+
if (_session.IsInTransaction)
320+
{
321+
if (exception is MongoConnectionException)
322+
{
323+
return true;
324+
}
325+
}
326+
327+
return false;
328+
}
300329
}
301330
}

src/MongoDB.Driver.Core/ServerErrorCode.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ namespace MongoDB.Driver
1818
internal enum ServerErrorCode
1919
{
2020
// this is not a complete list, more will be added as needed
21+
// see: https://github.com/mongodb/mongo/blob/master/src/mongo/base/error_codes.err
2122
CappedPositionLost = 136,
2223
CursorKilled = 237,
2324
ElectionInProgress = 216,
@@ -35,6 +36,8 @@ internal enum ServerErrorCode
3536
RetryChangeStream = 234,
3637
ShutdownInProgress = 91,
3738
SocketException = 9001,
39+
UnknownReplWriteConcern = 79,
40+
UnsatisfiableWriteConcern = 100,
3841
WriteConcernFailed = 64
3942
}
4043
}

0 commit comments

Comments
 (0)