Skip to content

Commit 29feedc

Browse files
committed
CDRIVER-2558 add mongoc_error_has_labels
1 parent a26570b commit 29feedc

13 files changed

+138
-79
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
Next Release
22
============
33

4+
* New function mongoc_error_has_label to check for specific error labels such
5+
as "TransientTransactionError" or "UnknownTransactionCommitResult" in
6+
error replies.
47
* All "destroy" functions such as bson_destroy or mongoc_collection_destroy
58
now ignore a NULL argument.
69
* Update functions include a new "upsertedCount" field in the reply document.

src/libmongoc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ set (SOURCES ${SOURCES}
401401
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-cursor-legacy.c
402402
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-cursor-array.c
403403
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-database.c
404+
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-error.c
404405
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-find-and-modify.c
405406
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-init.c
406407
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-gridfs.c

src/libmongoc/doc/errors.rst

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,33 @@ See also: :doc:`Handling Errors in libbson <bson:errors>`.
8282
| ``MONGOC_ERROR_TRANSACTION`` | ``MONGOC_ERROR_TRANSACTION_INVALID`` | You attempted to start a transaction when one is already in progress, or commit or abort when there is no transaction. |
8383
+-----------------------------------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
8484

85+
.. _error_labels:
86+
87+
Error Labels
88+
------------
89+
90+
In some cases your application must make decisions based on what category of error the driver has returned, but these categories do not correspond perfectly to an error domain or code. In such cases, error *labels* provide a reliable way to determine how your application should respond to an error.
91+
92+
Any C Driver function that has a :symbol:`bson:bson_t` out-parameter named ``reply`` may include error labels to the reply, in the form of a BSON field named "errorLabels" containing an array of strings:
93+
94+
.. code-block:: none
95+
96+
{ "errorLabels": [ "TransientTransactionError" ] }
97+
98+
Use :symbol:`mongoc_error_has_label` to test if a reply contains a specific label. See :symbol:`mongoc_client_session_start_transaction` for example code that demonstrates the use of error labels in application logic.
99+
100+
The following error labels are currently defined. Future versions of MongoDB may introduce new labels.
101+
102+
TransientTransactionError
103+
^^^^^^^^^^^^^^^^^^^^^^^^^
104+
105+
Within a multi-document transaction, certain errors can leave the transaction in an unknown or aborted state. These include write conflicts, primary stepdowns, and network errors. In response, the application should abort the transaction and try the same sequence of operations again in a new transaction.
106+
107+
UnknownTransactionCommitResult
108+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
109+
110+
When :symbol:`mongoc_client_session_commit_transaction` encounters a network error or certain server errors, it is not known whether the transaction was committed. Applications should attempt to commit the transaction again until: the commit succeeds, the commit fails with an error *not* labeled "UnknownTransactionCommitResult", or the application chooses to give up.
111+
85112
.. _errors_error_api_version:
86113
.. _error_api_version:
87114

@@ -127,3 +154,13 @@ See Also
127154

128155
`MongoDB Server Error Codes <https://github.com/mongodb/mongo/blob/master/src/mongo/base/error_codes.err>`_
129156

157+
.. only:: html
158+
159+
Functions
160+
---------
161+
162+
.. toctree::
163+
:titlesonly:
164+
:maxdepth: 1
165+
166+
mongoc_error_has_label

src/libmongoc/doc/mongoc_client_session_start_transaction.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ Returns true if the transaction was started. Returns ``false`` and sets ``error`
3535
Example
3636
-------
3737

38+
The following example demonstrates how to use :ref:`error labels <error_labels>` to reliably execute a multi-document transaction despite network errors and other transient failures.
39+
3840
.. literalinclude:: ../examples/example-transaction.c
3941
:language: c
4042
:caption: example-transaction.c
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
:man_page: mongoc_error_has_label
2+
3+
mongoc_error_has_label()
4+
========================
5+
6+
Synopsis
7+
--------
8+
9+
.. code-block:: c
10+
11+
bool
12+
mongoc_error_has_label (const bson_t *reply, const char *label);
13+
14+
Test whether a reply from a failed operation includes a specific error label. See :ref:`Error Labels <error_labels>` for details, and see :symbol:`mongoc_client_session_start_transaction` for example code that demonstrates their use.
15+
16+
Parameters
17+
----------
18+
19+
* ``reply``: A :symbol:`bson:bson_t`, the reply to a failed operation.
20+
* ``label``: The label to test for, such as "TransientTransactionError" or "UnknownTransactionCommitResult".
21+
22+
Returns
23+
-------
24+
25+
Returns true if ``reply`` contains the error label.

src/libmongoc/examples/example-transaction.c

Lines changed: 9 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,6 @@
77
#include <mongoc.h>
88

99

10-
/* defined below */
11-
static bool
12-
has_label (const bson_t *reply, const char *label);
13-
1410
int
1511
main (int argc, char *argv[])
1612
{
@@ -123,9 +119,12 @@ main (int argc, char *argv[])
123119
if (!r) {
124120
MONGOC_ERROR ("Insert failed: %s", error.message);
125121
mongoc_client_session_abort_transaction (session, NULL);
126-
if (has_label (&reply, "TransientTransactionError")) {
127-
/* network error, primary failover, or other temporary error.
128-
* trying the entire transaction from the start may succeed */
122+
123+
/* a network error, primary failover, or other temporary error in a
124+
* transaction includes {"errorLabels": ["TransientTransactionError"]},
125+
* meaning that trying the entire transaction again may succeed
126+
*/
127+
if (mongoc_error_has_label (&reply, "TransientTransactionError")) {
129128
goto retry_transaction;
130129
}
131130

@@ -147,10 +146,11 @@ main (int argc, char *argv[])
147146
break;
148147
} else {
149148
MONGOC_ERROR ("Warning: commit failed: %s", error.message);
150-
if (has_label (&reply, "TransientTransactionError")) {
149+
if (mongoc_error_has_label (&reply, "TransientTransactionError")) {
151150
mongoc_client_session_abort_transaction (session, NULL);
152151
goto retry_transaction;
153-
} else if (has_label (&reply, "UnknownTransactionCommitResult")) {
152+
} else if (mongoc_error_has_label (&reply,
153+
"UnknownTransactionCommitResult")) {
154154
/* try again to commit */
155155
continue;
156156
}
@@ -179,30 +179,3 @@ main (int argc, char *argv[])
179179

180180
return exit_code;
181181
}
182-
183-
184-
/* An error reply from mongoc_client_session_commit_transaction can include:
185-
*
186-
* { "errorLabels" : ["TransientTxnError"] }
187-
*
188-
* Return true if the reply contains the given label.
189-
*/
190-
static bool
191-
has_label (const bson_t *reply, const char *label)
192-
{
193-
bson_iter_t iter;
194-
bson_iter_t labels;
195-
196-
if (!bson_iter_init_find (&iter, reply, "errorLabels")) {
197-
return false;
198-
}
199-
200-
bson_iter_recurse (&iter, &labels);
201-
while (bson_iter_next (&labels)) {
202-
if (!strcmp (bson_iter_utf8 (&labels, NULL), label)) {
203-
return true;
204-
}
205-
}
206-
207-
return false;
208-
}

src/libmongoc/src/mongoc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ set (src_libmongoc_src_mongoc_DIST_cs
174174
mongoc-cursor-cmd.c
175175
mongoc-cursor-cmd-deprecated.c
176176
mongoc-database.c
177+
mongoc-error.c
177178
mongoc-find-and-modify.c
178179
mongoc-host-list.c
179180
mongoc-init.c
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2018-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include <bson.h>
18+
19+
#include "mongoc-error.h"
20+
21+
bool
22+
mongoc_error_has_label (const bson_t *reply, const char *label)
23+
{
24+
bson_iter_t iter;
25+
bson_iter_t error_labels;
26+
27+
BSON_ASSERT (reply);
28+
BSON_ASSERT (label);
29+
30+
if (bson_iter_init_find (&iter, reply, "errorLabels")) {
31+
bson_iter_recurse (&iter, &error_labels);
32+
while (bson_iter_next (&error_labels)) {
33+
if (BSON_ITER_HOLDS_UTF8 (&error_labels) &&
34+
!strcmp (bson_iter_utf8 (&error_labels, NULL), label)) {
35+
return true;
36+
}
37+
}
38+
}
39+
40+
return false;
41+
}

src/libmongoc/src/mongoc/mongoc-error.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323

2424
#include <bson.h>
2525

26+
#include "mongoc-macros.h"
27+
2628
#define MONGOC_ERROR_API_VERSION_LEGACY 1
2729
#define MONGOC_ERROR_API_VERSION_2 2
2830

@@ -115,6 +117,8 @@ typedef enum {
115117
MONGOC_ERROR_TRANSACTION_INVALID_STATE,
116118
} mongoc_error_code_t;
117119

120+
MONGOC_EXPORT (bool)
121+
mongoc_error_has_label (const bson_t *reply, const char *label);
118122

119123
BSON_END_DECLS
120124

src/libmongoc/src/mongoc/mongoc-util-private.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,6 @@ mongoc_lowercase (const char *src, char *buf /* OUT */);
124124
bool
125125
mongoc_parse_port (uint16_t *port, const char *str);
126126

127-
bool
128-
_mongoc_bson_array_has_label (bson_t *bson, const char *label);
129-
130127
void
131128
_mongoc_bson_array_add_label (bson_t *bson, const char *label);
132129

0 commit comments

Comments
 (0)