Skip to content

Commit 50ba959

Browse files
committed
Add top-level error labels to write concern error (#766)
This will allow the driver to properly retry writes that the server has labeled as a RetryableWriteError. JAVA-4244
1 parent cdaa7b4 commit 50ba959

File tree

5 files changed

+483
-1
lines changed

5 files changed

+483
-1
lines changed

driver-core/src/main/com/mongodb/internal/connection/ProtocolHelper.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,14 @@ public static MongoException createSpecialException(final BsonDocument response,
264264
} else if (isNotPrimaryError(errorCode, errorMessage)) {
265265
return new MongoNotPrimaryException(response, serverAddress);
266266
} else if (response.containsKey("writeConcernError")) {
267-
return createSpecialException(response.getDocument("writeConcernError"), serverAddress, "errmsg");
267+
MongoException writeConcernException = createSpecialException(response.getDocument("writeConcernError"), serverAddress,
268+
"errmsg");
269+
if (writeConcernException != null && response.isArray("errorLabels")) {
270+
for (BsonValue errorLabel : response.getArray("errorLabels")) {
271+
writeConcernException.addLabel(errorLabel.asString().getValue());
272+
}
273+
}
274+
return writeConcernException;
268275
} else {
269276
return null;
270277
}
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
{
2+
"description": "retryable-writes bulkWrite serverErrors",
3+
"schemaVersion": "1.0",
4+
"runOnRequirements": [
5+
{
6+
"minServerVersion": "3.6",
7+
"topologies": [
8+
"replicaset"
9+
]
10+
}
11+
],
12+
"createEntities": [
13+
{
14+
"client": {
15+
"id": "client0",
16+
"useMultipleMongoses": false,
17+
"observeEvents": [
18+
"commandStartedEvent"
19+
]
20+
}
21+
},
22+
{
23+
"database": {
24+
"id": "database0",
25+
"client": "client0",
26+
"databaseName": "retryable-writes-tests"
27+
}
28+
},
29+
{
30+
"collection": {
31+
"id": "collection0",
32+
"database": "database0",
33+
"collectionName": "coll"
34+
}
35+
}
36+
],
37+
"initialData": [
38+
{
39+
"collectionName": "coll",
40+
"databaseName": "retryable-writes-tests",
41+
"documents": [
42+
{
43+
"_id": 1,
44+
"x": 11
45+
},
46+
{
47+
"_id": 2,
48+
"x": 22
49+
}
50+
]
51+
}
52+
],
53+
"tests": [
54+
{
55+
"description": "BulkWrite succeeds after retryable writeConcernError in first batch",
56+
"runOnRequirements": [
57+
{
58+
"minServerVersion": "4.0",
59+
"topologies": [
60+
"replicaset"
61+
]
62+
},
63+
{
64+
"minServerVersion": "4.1.7",
65+
"topologies": [
66+
"sharded-replicaset"
67+
]
68+
}
69+
],
70+
"operations": [
71+
{
72+
"name": "failPoint",
73+
"object": "testRunner",
74+
"arguments": {
75+
"client": "client0",
76+
"failPoint": {
77+
"configureFailPoint": "failCommand",
78+
"mode": {
79+
"times": 1
80+
},
81+
"data": {
82+
"failCommands": [
83+
"insert"
84+
],
85+
"errorLabels": [
86+
"RetryableWriteError"
87+
],
88+
"writeConcernError": {
89+
"code": 91,
90+
"errmsg": "Replication is being shut down"
91+
}
92+
}
93+
}
94+
}
95+
},
96+
{
97+
"name": "bulkWrite",
98+
"object": "collection0",
99+
"arguments": {
100+
"requests": [
101+
{
102+
"insertOne": {
103+
"document": {
104+
"_id": 3,
105+
"x": 33
106+
}
107+
}
108+
},
109+
{
110+
"deleteOne": {
111+
"filter": {
112+
"_id": 2
113+
}
114+
}
115+
}
116+
]
117+
},
118+
"expectResult": {
119+
"deletedCount": 1,
120+
"insertedCount": 1,
121+
"matchedCount": 0,
122+
"modifiedCount": 0,
123+
"upsertedCount": 0,
124+
"insertedIds": {
125+
"$$unsetOrMatches": {
126+
"0": 3
127+
}
128+
},
129+
"upsertedIds": {}
130+
}
131+
}
132+
],
133+
"expectEvents": [
134+
{
135+
"client": "client0",
136+
"events": [
137+
{
138+
"commandStartedEvent": {
139+
"command": {
140+
"insert": "coll",
141+
"documents": [
142+
{
143+
"_id": 3,
144+
"x": 33
145+
}
146+
]
147+
},
148+
"commandName": "insert",
149+
"databaseName": "retryable-writes-tests"
150+
}
151+
},
152+
{
153+
"commandStartedEvent": {
154+
"command": {
155+
"insert": "coll",
156+
"documents": [
157+
{
158+
"_id": 3,
159+
"x": 33
160+
}
161+
]
162+
},
163+
"commandName": "insert",
164+
"databaseName": "retryable-writes-tests"
165+
}
166+
},
167+
{
168+
"commandStartedEvent": {
169+
"command": {
170+
"delete": "coll",
171+
"deletes": [
172+
{
173+
"q": {
174+
"_id": 2
175+
},
176+
"limit": 1
177+
}
178+
]
179+
},
180+
"commandName": "delete",
181+
"databaseName": "retryable-writes-tests"
182+
}
183+
}
184+
]
185+
}
186+
],
187+
"outcome": [
188+
{
189+
"collectionName": "coll",
190+
"databaseName": "retryable-writes-tests",
191+
"documents": [
192+
{
193+
"_id": 1,
194+
"x": 11
195+
},
196+
{
197+
"_id": 3,
198+
"x": 33
199+
}
200+
]
201+
}
202+
]
203+
}
204+
]
205+
}
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
{
2+
"description": "retryable-writes insertOne serverErrors",
3+
"schemaVersion": "1.0",
4+
"runOnRequirements": [
5+
{
6+
"minServerVersion": "3.6",
7+
"topologies": [
8+
"replicaset"
9+
]
10+
}
11+
],
12+
"createEntities": [
13+
{
14+
"client": {
15+
"id": "client0",
16+
"useMultipleMongoses": false,
17+
"observeEvents": [
18+
"commandStartedEvent"
19+
]
20+
}
21+
},
22+
{
23+
"database": {
24+
"id": "database0",
25+
"client": "client0",
26+
"databaseName": "retryable-writes-tests"
27+
}
28+
},
29+
{
30+
"collection": {
31+
"id": "collection0",
32+
"database": "database0",
33+
"collectionName": "coll"
34+
}
35+
}
36+
],
37+
"initialData": [
38+
{
39+
"collectionName": "coll",
40+
"databaseName": "retryable-writes-tests",
41+
"documents": [
42+
{
43+
"_id": 1,
44+
"x": 11
45+
},
46+
{
47+
"_id": 2,
48+
"x": 22
49+
}
50+
]
51+
}
52+
],
53+
"tests": [
54+
{
55+
"description": "InsertOne succeeds after retryable writeConcernError",
56+
"runOnRequirements": [
57+
{
58+
"minServerVersion": "4.0",
59+
"topologies": [
60+
"replicaset"
61+
]
62+
},
63+
{
64+
"minServerVersion": "4.1.7",
65+
"topologies": [
66+
"sharded-replicaset"
67+
]
68+
}
69+
],
70+
"operations": [
71+
{
72+
"name": "failPoint",
73+
"object": "testRunner",
74+
"arguments": {
75+
"client": "client0",
76+
"failPoint": {
77+
"configureFailPoint": "failCommand",
78+
"mode": {
79+
"times": 1
80+
},
81+
"data": {
82+
"failCommands": [
83+
"insert"
84+
],
85+
"errorLabels": [
86+
"RetryableWriteError"
87+
],
88+
"writeConcernError": {
89+
"code": 91,
90+
"errmsg": "Replication is being shut down"
91+
}
92+
}
93+
}
94+
}
95+
},
96+
{
97+
"name": "insertOne",
98+
"object": "collection0",
99+
"arguments": {
100+
"document": {
101+
"_id": 3,
102+
"x": 33
103+
}
104+
},
105+
"expectResult": {
106+
"$$unsetOrMatches": {
107+
"insertedId": {
108+
"$$unsetOrMatches": 3
109+
}
110+
}
111+
}
112+
}
113+
],
114+
"expectEvents": [
115+
{
116+
"client": "client0",
117+
"events": [
118+
{
119+
"commandStartedEvent": {
120+
"command": {
121+
"insert": "coll",
122+
"documents": [
123+
{
124+
"_id": 3,
125+
"x": 33
126+
}
127+
]
128+
},
129+
"commandName": "insert",
130+
"databaseName": "retryable-writes-tests"
131+
}
132+
},
133+
{
134+
"commandStartedEvent": {
135+
"command": {
136+
"insert": "coll",
137+
"documents": [
138+
{
139+
"_id": 3,
140+
"x": 33
141+
}
142+
]
143+
},
144+
"commandName": "insert",
145+
"databaseName": "retryable-writes-tests"
146+
}
147+
}
148+
]
149+
}
150+
],
151+
"outcome": [
152+
{
153+
"collectionName": "coll",
154+
"databaseName": "retryable-writes-tests",
155+
"documents": [
156+
{
157+
"_id": 1,
158+
"x": 11
159+
},
160+
{
161+
"_id": 2,
162+
"x": 22
163+
},
164+
{
165+
"_id": 3,
166+
"x": 33
167+
}
168+
]
169+
}
170+
]
171+
}
172+
]
173+
}

0 commit comments

Comments
 (0)