Skip to content

Commit f42ef7d

Browse files
committed
Do not retry a read operation when in a transaction (#982)
Fixes a regression introduced in 4.4.0 in scope of JAVA-4034, and was undetected due to the lack of a specification test for the required behavior. JAVA-4684
1 parent 06c0820 commit f42ef7d

File tree

3 files changed

+130
-25
lines changed

3 files changed

+130
-25
lines changed

driver-core/src/main/com/mongodb/internal/operation/OperationHelper.java

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@
2929
import com.mongodb.diagnostics.logging.Loggers;
3030
import com.mongodb.internal.async.AsyncBatchCursor;
3131
import com.mongodb.internal.async.SingleResultCallback;
32+
import com.mongodb.internal.async.function.AsyncCallbackBiFunction;
3233
import com.mongodb.internal.async.function.AsyncCallbackFunction;
34+
import com.mongodb.internal.async.function.AsyncCallbackSupplier;
3335
import com.mongodb.internal.binding.AsyncConnectionSource;
3436
import com.mongodb.internal.binding.AsyncReadBinding;
3537
import com.mongodb.internal.binding.AsyncWriteBinding;
@@ -44,8 +46,6 @@
4446
import com.mongodb.internal.connection.AsyncConnection;
4547
import com.mongodb.internal.connection.Connection;
4648
import com.mongodb.internal.connection.QueryResult;
47-
import com.mongodb.internal.async.function.AsyncCallbackBiFunction;
48-
import com.mongodb.internal.async.function.AsyncCallbackSupplier;
4949
import com.mongodb.internal.session.SessionContext;
5050
import com.mongodb.lang.NonNull;
5151
import org.bson.BsonDocument;
@@ -437,21 +437,12 @@ static boolean canRetryWrite(final ServerDescription serverDescription, final Co
437437
return true;
438438
}
439439

440-
static boolean isRetryableRead(final boolean retryReads, final ServerDescription serverDescription,
441-
final ConnectionDescription connectionDescription, final SessionContext sessionContext) {
442-
if (!retryReads) {
443-
return false;
444-
} else if (sessionContext.hasActiveTransaction()) {
445-
LOGGER.debug("retryReads set to true but in an active transaction.");
446-
return false;
447-
} else {
448-
return canRetryRead(serverDescription, connectionDescription, sessionContext);
449-
}
450-
}
451-
452440
static boolean canRetryRead(final ServerDescription serverDescription, final ConnectionDescription connectionDescription,
453441
final SessionContext sessionContext) {
454-
if (serverIsLessThanVersionThreeDotSix(connectionDescription)) {
442+
if (sessionContext.hasActiveTransaction()) {
443+
LOGGER.debug("retryReads set to true but in an active transaction.");
444+
return false;
445+
} else if (serverIsLessThanVersionThreeDotSix(connectionDescription)) {
455446
LOGGER.debug("retryReads set to true but the server does not support retryable reads.");
456447
return false;
457448
} else if (serverDescription.getLogicalSessionTimeoutMinutes() == null && serverDescription.getType() != ServerType.LOAD_BALANCER) {
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
{
2+
"description": "do not retry read in a transaction",
3+
"schemaVersion": "1.4",
4+
"runOnRequirements": [
5+
{
6+
"minServerVersion": "4.0.0",
7+
"topologies": [
8+
"replicaset"
9+
]
10+
},
11+
{
12+
"minServerVersion": "4.2.0",
13+
"topologies": [
14+
"sharded",
15+
"load-balanced"
16+
]
17+
}
18+
],
19+
"createEntities": [
20+
{
21+
"client": {
22+
"id": "client0",
23+
"useMultipleMongoses": false,
24+
"observeEvents": [
25+
"commandStartedEvent"
26+
],
27+
"uriOptions": {
28+
"retryReads": true
29+
}
30+
}
31+
},
32+
{
33+
"database": {
34+
"id": "database0",
35+
"client": "client0",
36+
"databaseName": "retryable-read-in-transaction-test"
37+
}
38+
},
39+
{
40+
"collection": {
41+
"id": "collection0",
42+
"database": "database0",
43+
"collectionName": "coll"
44+
}
45+
},
46+
{
47+
"session": {
48+
"id": "session0",
49+
"client": "client0"
50+
}
51+
}
52+
],
53+
"tests": [
54+
{
55+
"description": "find does not retry in a transaction",
56+
"operations": [
57+
{
58+
"name": "startTransaction",
59+
"object": "session0"
60+
},
61+
{
62+
"name": "failPoint",
63+
"object": "testRunner",
64+
"arguments": {
65+
"client": "client0",
66+
"failPoint": {
67+
"configureFailPoint": "failCommand",
68+
"mode": {
69+
"times": 1
70+
},
71+
"data": {
72+
"failCommands": [
73+
"find"
74+
],
75+
"closeConnection": true
76+
}
77+
}
78+
}
79+
},
80+
{
81+
"name": "find",
82+
"object": "collection0",
83+
"arguments": {
84+
"filter": {},
85+
"session": "session0"
86+
},
87+
"expectError": {
88+
"isError": true,
89+
"errorLabelsContain": [
90+
"TransientTransactionError"
91+
]
92+
}
93+
}
94+
],
95+
"expectEvents": [
96+
{
97+
"client": "client0",
98+
"events": [
99+
{
100+
"commandStartedEvent": {
101+
"command": {
102+
"find": "coll",
103+
"filter": {},
104+
"startTransaction": true
105+
},
106+
"commandName": "find",
107+
"databaseName": "retryable-read-in-transaction-test"
108+
}
109+
}
110+
]
111+
}
112+
]
113+
}
114+
]
115+
}

driver-core/src/test/unit/com/mongodb/internal/operation/OperationHelperSpecification.groovy

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import static com.mongodb.connection.ServerType.REPLICA_SET_PRIMARY
4343
import static com.mongodb.connection.ServerType.STANDALONE
4444
import static com.mongodb.internal.operation.OperationHelper.AsyncCallableWithConnection
4545
import static com.mongodb.internal.operation.OperationHelper.AsyncCallableWithConnectionAndSource
46-
import static com.mongodb.internal.operation.OperationHelper.isRetryableRead
46+
import static com.mongodb.internal.operation.OperationHelper.canRetryRead
4747
import static com.mongodb.internal.operation.OperationHelper.isRetryableWrite
4848
import static com.mongodb.internal.operation.OperationHelper.validateCollation
4949
import static com.mongodb.internal.operation.OperationHelper.validateCollationAndWriteConcern
@@ -434,17 +434,16 @@ class OperationHelperSpecification extends Specification {
434434
}
435435

436436
expect:
437-
isRetryableRead(retryReads, serverDescription, connectionDescription, noTransactionSessionContext) == expected
438-
!isRetryableRead(retryReads, serverDescription, connectionDescription, activeTransactionSessionContext)
439-
!isRetryableRead(retryReads, serverDescription, connectionDescription, noOpSessionContext)
437+
canRetryRead(serverDescription, connectionDescription, noTransactionSessionContext) == expected
438+
!canRetryRead(serverDescription, connectionDescription, activeTransactionSessionContext)
439+
!canRetryRead(serverDescription, connectionDescription, noOpSessionContext)
440440

441441
where:
442-
retryReads | serverDescription | connectionDescription | expected
443-
false | retryableServerDescription | threeSixConnectionDescription | false
444-
true | retryableServerDescription | threeSixConnectionDescription | true
445-
true | nonRetryableServerDescription | threeSixConnectionDescription | false
446-
true | retryableServerDescription | threeFourConnectionDescription | false
447-
true | retryableServerDescription | threeSixPrimaryConnectionDescription | true
442+
serverDescription | connectionDescription | expected
443+
retryableServerDescription | threeSixConnectionDescription | true
444+
nonRetryableServerDescription | threeSixConnectionDescription | false
445+
retryableServerDescription | threeFourConnectionDescription | false
446+
retryableServerDescription | threeSixPrimaryConnectionDescription | true
448447
}
449448

450449

0 commit comments

Comments
 (0)