Skip to content

Commit 486c148

Browse files
committed
CDRIVER-2699 don't retry WriteConcernFailed error
Error code 64, "WriteConcernFailed", is no longer a retryable write. If commitTransaction returns error code 64, add the error label "UnknownTransactionCommitResult".
1 parent 87b6a54 commit 486c148

File tree

6 files changed

+512
-18
lines changed

6 files changed

+512
-18
lines changed

src/libmongoc/src/mongoc/mongoc-client-session.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ txn_finish (mongoc_client_session_t *session,
121121
bson_error_t err_local;
122122
bson_error_t *err_ptr = error ? error : &err_local;
123123
bson_t reply_local = BSON_INITIALIZER;
124+
mongoc_write_err_type_t error_type;
124125
bool r = false;
125126

126127
_mongoc_bson_init_if_set (reply);
@@ -151,19 +152,23 @@ txn_finish (mongoc_client_session_t *session,
151152

152153
/* Transactions Spec: "Drivers MUST retry the commitTransaction command once
153154
* after it fails with a retryable error", same for abort */
155+
error_type = _mongoc_write_error_get_type (&reply_local);
154156
if (!r && (err_ptr->domain == MONGOC_ERROR_STREAM ||
155-
_mongoc_write_is_retryable_error (&reply_local))) {
157+
error_type == MONGOC_WRITE_ERR_RETRY)) {
156158
bson_destroy (&reply_local);
157159
r = mongoc_client_write_command_with_opts (
158160
session->client, "admin", &cmd, &opts, &reply_local, err_ptr);
161+
162+
error_type = _mongoc_write_error_get_type (&reply_local);
159163
}
160164

161165
/* Transactions Spec: "add the UnknownTransactionCommitResult error label
162166
* when commitTransaction fails with a network error, server selection
163167
* error, or write concern failed / timeout." */
164168
if (intent == TXN_COMMIT && reply) {
165169
if (!r && (err_ptr->domain == MONGOC_ERROR_STREAM ||
166-
_mongoc_write_is_retryable_error (&reply_local))) {
170+
error_type == MONGOC_WRITE_ERR_RETRY ||
171+
error_type == MONGOC_WRITE_ERR_WRITE_CONCERN)) {
167172
bson_copy_to_excluding_noinit (
168173
&reply_local, reply, "errorLabels", NULL);
169174
copy_labels_plus_unknown_commit_result (&reply_local, reply);

src/libmongoc/src/mongoc/mongoc-client.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1555,8 +1555,9 @@ _mongoc_client_retryable_write_command_with_stream (
15551555
* a new writable stream and retry. If server selection fails or the selected
15561556
* server does not support retryable writes, fall through and allow the
15571557
* original error to be reported. */
1558-
if (!ret && is_retryable && (error->domain == MONGOC_ERROR_STREAM ||
1559-
_mongoc_write_is_retryable_error (reply))) {
1558+
if (!ret && is_retryable &&
1559+
(error->domain == MONGOC_ERROR_STREAM ||
1560+
_mongoc_write_error_get_type (reply) == MONGOC_WRITE_ERR_RETRY)) {
15601561
bson_error_t ignored_error;
15611562

15621563
/* each write command may be retried at most once */

src/libmongoc/src/mongoc/mongoc-collection.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3325,8 +3325,9 @@ mongoc_collection_find_and_modify_with_opts (
33253325
* a new writable stream and retry. If server selection fails or the selected
33263326
* server does not support retryable writes, fall through and allow the
33273327
* original error to be reported. */
3328-
if (!ret && is_retryable && (error->domain == MONGOC_ERROR_STREAM ||
3329-
_mongoc_write_is_retryable_error (reply_ptr))) {
3328+
if (!ret && is_retryable &&
3329+
(error->domain == MONGOC_ERROR_STREAM ||
3330+
_mongoc_write_error_get_type (reply_ptr) == MONGOC_WRITE_ERR_RETRY)) {
33303331
bson_error_t ignored_error;
33313332

33323333
/* each write command may be retried at most once */

src/libmongoc/src/mongoc/mongoc-write-command-private.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,14 @@ typedef struct {
9292
} mongoc_write_result_t;
9393

9494

95+
typedef enum {
96+
MONGOC_WRITE_ERR_NONE,
97+
MONGOC_WRITE_ERR_OTHER,
98+
MONGOC_WRITE_ERR_RETRY,
99+
MONGOC_WRITE_ERR_WRITE_CONCERN,
100+
} mongoc_write_err_type_t;
101+
102+
95103
const char *
96104
_mongoc_command_type_to_field_name (int command_type);
97105
const char *
@@ -212,8 +220,8 @@ _mongoc_write_result_destroy (mongoc_write_result_t *result);
212220
void
213221
_append_array_from_command (mongoc_write_command_t *command, bson_t *bson);
214222

215-
bool
216-
_mongoc_write_is_retryable_error (const bson_t *reply);
223+
mongoc_write_err_type_t
224+
_mongoc_write_error_get_type (const bson_t *reply);
217225

218226
BSON_END_DECLS
219227

src/libmongoc/src/mongoc/mongoc-write-command.c

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,7 @@ _mongoc_write_opmsg (mongoc_write_command_t *command,
560560

561561
if (ship_it) {
562562
bool is_retryable = parts.is_retryable_write;
563+
mongoc_write_err_type_t error_type;
563564

564565
/* Seek past the document offset we have already sent */
565566
parts.assembled.payload = command->payload.data + payload_total_offset;
@@ -589,9 +590,9 @@ _mongoc_write_opmsg (mongoc_write_command_t *command,
589590
* select a new writable stream and retry. If server selection fails or
590591
* the selected server does not support retryable writes, fall through
591592
* and allow the original error to be reported. */
592-
if (!ret && is_retryable &&
593-
(error->domain == MONGOC_ERROR_STREAM ||
594-
_mongoc_write_is_retryable_error (&reply))) {
593+
error_type = _mongoc_write_error_get_type (&reply);
594+
if (!ret && is_retryable && (error->domain == MONGOC_ERROR_STREAM ||
595+
error_type == MONGOC_WRITE_ERR_RETRY)) {
595596
bson_error_t ignored_error;
596597

597598
/* each write command may be retried at most once */
@@ -1430,13 +1431,14 @@ _mongoc_write_result_complete (
14301431
RETURN (!result->failed && result->error.code == 0);
14311432
}
14321433

1433-
bool
1434-
_mongoc_write_is_retryable_error (const bson_t *reply)
1434+
1435+
mongoc_write_err_type_t
1436+
_mongoc_write_error_get_type (const bson_t *reply)
14351437
{
14361438
bson_error_t error;
14371439
if (_mongoc_cmd_check_ok_no_wce (
14381440
reply, MONGOC_ERROR_API_VERSION_2, &error)) {
1439-
return false;
1441+
return MONGOC_WRITE_ERR_NONE;
14401442
}
14411443

14421444
switch (error.code) {
@@ -1447,17 +1449,18 @@ _mongoc_write_is_retryable_error (const bson_t *reply)
14471449
case 13436: /* NotMasterOrSecondary */
14481450
case 189: /* PrimarySteppedDown */
14491451
case 91: /* ShutdownInProgress */
1450-
case 64: /* WriteConcernFailed */
14511452
case 7: /* HostNotFound */
14521453
case 6: /* HostUnreachable */
14531454
case 89: /* NetworkTimeout */
14541455
case 9001: /* SocketException */
1455-
return true;
1456+
return MONGOC_WRITE_ERR_RETRY;
1457+
case 64: /* WriteConcernFailed */
1458+
return MONGOC_WRITE_ERR_WRITE_CONCERN;
14561459
default:
14571460
if (strstr (error.message, "not master") ||
14581461
strstr (error.message, "node is recovering")) {
1459-
return true;
1462+
return MONGOC_WRITE_ERR_RETRY;
14601463
}
1461-
return false;
1464+
return MONGOC_WRITE_ERR_OTHER;
14621465
}
14631466
}

0 commit comments

Comments
 (0)