Skip to content

Commit 8912f5b

Browse files
committed
CDRIVER-5718 fix logic for returning bulk write result on error (#1749)
do not return bulk write result if there are no known successful responses
1 parent a65cfc4 commit 8912f5b

File tree

5 files changed

+582
-8
lines changed

5 files changed

+582
-8
lines changed

NEWS

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
libmongoc 1.28.1 (unreleased)
2+
=============================
3+
4+
Fixed:
5+
6+
* Do not return result in `mongoc_bulkwritereturn_t` if there are no known successful writes.
7+
18
libmongoc 1.28.0
29
================
310

src/libmongoc/doc/mongoc_bulkwritereturn_t.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Synopsis
99
.. code-block:: c
1010
1111
typedef struct {
12-
mongoc_bulkwriteresult_t *res; // NULL if write was unacknowledged.
12+
mongoc_bulkwriteresult_t *res; // NULL if no known successful writes or write was unacknowledged.
1313
mongoc_bulkwriteexception_t *exc; // NULL if no error.
1414
} mongoc_bulkwritereturn_t;
1515
@@ -20,7 +20,7 @@ Description
2020

2121
``res`` or ``exc`` may outlive the :symbol:`mongoc_bulkwrite_t` that was executed.
2222

23-
``res`` is NULL if the :symbol:`mongoc_bulkwrite_t` was executed with an unacknowledged write concern.
23+
``res`` is NULL if the :symbol:`mongoc_bulkwrite_t` has no known successful writes or was executed with an unacknowledged write concern.
2424

2525
``res`` must be freed with :symbol:`mongoc_bulkwriteresult_destroy`.
2626

src/libmongoc/src/mongoc/mongoc-bulkwrite.c

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,11 @@ struct _mongoc_bulkwriteresult_t {
822822
int64_t matchedcount;
823823
int64_t modifiedcount;
824824
int64_t deletedcount;
825+
int64_t errorscount; // sum of all `nErrors`.
826+
struct {
827+
bool isset;
828+
int64_t index;
829+
} first_error_index;
825830
uint32_t serverid;
826831
bson_t insertresults;
827832
bson_t updateresults;
@@ -1253,6 +1258,12 @@ _bulkwritereturn_apply_reply (mongoc_bulkwritereturn_t *self, const bson_t *cmd_
12531258
}
12541259
self->res->upsertedcount += nUpserted;
12551260

1261+
int64_t nErrors;
1262+
if (!lookup_as_int64 (cmd_reply, "nErrors", &nErrors, NULL, self->exc)) {
1263+
return false;
1264+
}
1265+
self->res->errorscount += nErrors;
1266+
12561267
bson_error_t error;
12571268
bson_iter_t iter;
12581269
if (bson_iter_init_find (&iter, cmd_reply, "writeConcernError")) {
@@ -1332,6 +1343,10 @@ _bulkwritereturn_apply_result (mongoc_bulkwritereturn_t *self,
13321343
// `models_idx` is the index of the model that produced this result.
13331344
size_t models_idx = (size_t) idx + ops_doc_offset;
13341345
if (ok == 0) {
1346+
if (!self->res->first_error_index.isset) {
1347+
self->res->first_error_index.isset = true;
1348+
self->res->first_error_index.index = idx;
1349+
}
13351350
bson_iter_t result_iter;
13361351

13371352
// Parse `code`.
@@ -1437,6 +1452,7 @@ mongoc_bulkwrite_execute (mongoc_bulkwrite_t *self, const mongoc_bulkwriteopts_t
14371452
BSON_ASSERT_PARAM (self);
14381453
BSON_OPTIONAL_PARAM (opts);
14391454

1455+
bool has_successful_results = false;
14401456
mongoc_bulkwritereturn_t ret = {0};
14411457
bson_error_t error = {0};
14421458
mongoc_server_stream_t *ss = NULL;
@@ -1447,6 +1463,8 @@ mongoc_bulkwrite_execute (mongoc_bulkwrite_t *self, const mongoc_bulkwriteopts_t
14471463
if (!opts) {
14481464
opts = &defaults;
14491465
}
1466+
bool is_ordered =
1467+
mongoc_optional_is_set (&opts->ordered) ? mongoc_optional_value (&opts->ordered) : true; // default.
14501468
bool is_acknowledged = false;
14511469
// Create empty result and exception to collect results/errors from batches.
14521470
ret.res = _bulkwriteresult_new ();
@@ -1506,8 +1524,7 @@ mongoc_bulkwrite_execute (mongoc_bulkwrite_t *self, const mongoc_bulkwriteopts_t
15061524
// errorsOnly is default true. Set to false if verboseResults requested.
15071525
BSON_ASSERT (BSON_APPEND_BOOL (&cmd, "errorsOnly", !verboseresults));
15081526
// ordered is default true.
1509-
BSON_ASSERT (BSON_APPEND_BOOL (
1510-
&cmd, "ordered", (mongoc_optional_is_set (&opts->ordered)) ? mongoc_optional_value (&opts->ordered) : true));
1527+
BSON_ASSERT (BSON_APPEND_BOOL (&cmd, "ordered", is_ordered));
15111528

15121529
if (opts->comment.value_type != BSON_TYPE_EOD) {
15131530
BSON_ASSERT (BSON_APPEND_VALUE (&cmd, "comment", &opts->comment));
@@ -1826,8 +1843,6 @@ mongoc_bulkwrite_execute (mongoc_bulkwrite_t *self, const mongoc_bulkwriteopts_t
18261843
if (!batch_ok) {
18271844
goto fail;
18281845
}
1829-
bool is_ordered =
1830-
mongoc_optional_is_set (&opts->ordered) ? mongoc_optional_value (&opts->ordered) : true; // default.
18311846
if (has_write_errors && is_ordered) {
18321847
// Ordered writes must not continue to send batches once an error is
18331848
// occurred. An individual write error is not a top-level error.
@@ -1836,7 +1851,19 @@ mongoc_bulkwrite_execute (mongoc_bulkwrite_t *self, const mongoc_bulkwriteopts_t
18361851
}
18371852

18381853
fail:
1839-
if (!is_acknowledged) {
1854+
if (is_ordered) {
1855+
// Ordered writes stop on first error. If the error reported is for an index > 0, assume some writes suceeded.
1856+
if (ret.res->errorscount == 0 || (ret.res->first_error_index.isset && ret.res->first_error_index.index > 0)) {
1857+
has_successful_results = true;
1858+
}
1859+
} else {
1860+
BSON_ASSERT (bson_in_range_size_t_signed (ret.res->errorscount));
1861+
size_t errorscount_sz = (size_t) ret.res->errorscount;
1862+
if (errorscount_sz < self->n_ops) {
1863+
has_successful_results = true;
1864+
}
1865+
}
1866+
if (!is_acknowledged || !has_successful_results) {
18401867
mongoc_bulkwriteresult_destroy (ret.res);
18411868
ret.res = NULL;
18421869
}

src/libmongoc/src/mongoc/mongoc-bulkwrite.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ mongoc_bulkwrite_append_deletemany (mongoc_bulkwrite_t *self,
235235

236236
// `mongoc_bulkwritereturn_t` may outlive `mongoc_bulkwrite_t`.
237237
typedef struct {
238-
mongoc_bulkwriteresult_t *res; // NULL if write was unacknowledged.
238+
mongoc_bulkwriteresult_t *res; // NULL if no known successful writes or write was unacknowledged.
239239
mongoc_bulkwriteexception_t *exc; // NULL if no error.
240240
} mongoc_bulkwritereturn_t;
241241

0 commit comments

Comments
 (0)