1MONGOC_CLIENT_SESSION_START_TRANSACTlIiMObONmN(oG3nO)gCo_cCLIENT_SESSION_START_TRANSACTION(3)
2
3
4
6 bool
7 mongoc_client_session_start_transaction (mongoc_client_session_t *session,
8 const mongoc_transaction_opt_t *opts,
9 bson_error_t *error);
10
11 Start a multi-document transaction for all following operations in this
12 session. Any options provided in opts override options passed to
13 mongoc_session_opts_set_default_transaction_opts(), and options inher‐
14 ited from the mongoc_client_t. The opts argument is copied and can be
15 freed after calling this function.
16
17 The transaction must be completed with
18 mongoc_client_session_commit_transaction() or
19 mongoc_client_session_abort_transaction(). An in-progress transaction
20 is automatically aborted by mongoc_client_session_destroy().
21
23 • session: A mongoc_client_session_t.
24
25 • opts: A mongoc_transaction_opt_t or NULL.
26
27 • error: An optional location for a bson_error_t or NULL.
28
30 Returns true if the transaction was started. Returns false and sets er‐
31 ror if there are invalid arguments, such as a session with a transac‐
32 tion already in progress.
33
35 The following example demonstrates how to use error labels to reliably
36 execute a multi-document transaction despite network errors and other
37 transient failures.
38
39 example-transaction.c
40
41 /* gcc example-transaction.c -o example-transaction \
42 * $(pkg-config --cflags --libs libmongoc-1.0) */
43
44 /* ./example-transaction [CONNECTION_STRING] */
45
46 #include <stdio.h>
47 #include <mongoc/mongoc.h>
48
49
50 int
51 main (int argc, char *argv[])
52 {
53 int exit_code = EXIT_FAILURE;
54
55 mongoc_client_t *client = NULL;
56 mongoc_database_t *database = NULL;
57 mongoc_collection_t *collection = NULL;
58 mongoc_client_session_t *session = NULL;
59 mongoc_session_opt_t *session_opts = NULL;
60 mongoc_transaction_opt_t *default_txn_opts = NULL;
61 mongoc_transaction_opt_t *txn_opts = NULL;
62 mongoc_read_concern_t *read_concern = NULL;
63 mongoc_write_concern_t *write_concern = NULL;
64 const char *uri_string = "mongodb://127.0.0.1/?appname=transaction-example";
65 mongoc_uri_t *uri;
66 bson_error_t error;
67 bson_t *doc = NULL;
68 bson_t *insert_opts = NULL;
69 int32_t i;
70 int64_t start;
71 bson_t reply = BSON_INITIALIZER;
72 char *reply_json;
73 bool r;
74
75 mongoc_init ();
76
77 if (argc > 1) {
78 uri_string = argv[1];
79 }
80
81 uri = mongoc_uri_new_with_error (uri_string, &error);
82 if (!uri) {
83 MONGOC_ERROR ("failed to parse URI: %s\n"
84 "error message: %s\n",
85 uri_string,
86 error.message);
87 goto done;
88 }
89
90 client = mongoc_client_new_from_uri (uri);
91 if (!client) {
92 goto done;
93 }
94
95 mongoc_client_set_error_api (client, 2);
96 database = mongoc_client_get_database (client, "example-transaction");
97
98 /* inserting into a nonexistent collection normally creates it, but a
99 * collection can't be created in a transaction; create it now */
100 collection =
101 mongoc_database_create_collection (database, "collection", NULL, &error);
102
103 if (!collection) {
104 /* code 48 is NamespaceExists, see error_codes.err in mongodb source */
105 if (error.code == 48) {
106 collection = mongoc_database_get_collection (database, "collection");
107 } else {
108 MONGOC_ERROR ("Failed to create collection: %s", error.message);
109 goto done;
110 }
111 }
112
113 /* a transaction's read preferences, read concern, and write concern can be
114 * set on the client, on the default transaction options, or when starting
115 * the transaction. for the sake of this example, set read concern on the
116 * default transaction options. */
117 default_txn_opts = mongoc_transaction_opts_new ();
118 read_concern = mongoc_read_concern_new ();
119 mongoc_read_concern_set_level (read_concern, "snapshot");
120 mongoc_transaction_opts_set_read_concern (default_txn_opts, read_concern);
121 session_opts = mongoc_session_opts_new ();
122 mongoc_session_opts_set_default_transaction_opts (session_opts,
123 default_txn_opts);
124
125 session = mongoc_client_start_session (client, session_opts, &error);
126 if (!session) {
127 MONGOC_ERROR ("Failed to start session: %s", error.message);
128 goto done;
129 }
130
131 /* in this example, set write concern when starting the transaction */
132 txn_opts = mongoc_transaction_opts_new ();
133 write_concern = mongoc_write_concern_new ();
134 mongoc_write_concern_set_wmajority (write_concern, 1000 /* wtimeout */);
135 mongoc_transaction_opts_set_write_concern (txn_opts, write_concern);
136
137 insert_opts = bson_new ();
138 if (!mongoc_client_session_append (session, insert_opts, &error)) {
139 MONGOC_ERROR ("Could not add session to opts: %s", error.message);
140 goto done;
141 }
142
143 retry_transaction:
144 r = mongoc_client_session_start_transaction (session, txn_opts, &error);
145 if (!r) {
146 MONGOC_ERROR ("Failed to start transaction: %s", error.message);
147 goto done;
148 }
149
150 /* insert two documents - on error, retry the whole transaction */
151 for (i = 0; i < 2; i++) {
152 doc = BCON_NEW ("_id", BCON_INT32 (i));
153 bson_destroy (&reply);
154 r = mongoc_collection_insert_one (
155 collection, doc, insert_opts, &reply, &error);
156
157 bson_destroy (doc);
158
159 if (!r) {
160 MONGOC_ERROR ("Insert failed: %s", error.message);
161 mongoc_client_session_abort_transaction (session, NULL);
162
163 /* a network error, primary failover, or other temporary error in a
164 * transaction includes {"errorLabels": ["TransientTransactionError"]},
165 * meaning that trying the entire transaction again may succeed
166 */
167 if (mongoc_error_has_label (&reply, "TransientTransactionError")) {
168 goto retry_transaction;
169 }
170
171 goto done;
172 }
173
174 reply_json = bson_as_json (&reply, NULL);
175 printf ("%s\n", reply_json);
176 bson_free (reply_json);
177 }
178
179 /* in case of transient errors, retry for 5 seconds to commit transaction */
180 start = bson_get_monotonic_time ();
181 while (bson_get_monotonic_time () - start < 5 * 1000 * 1000) {
182 bson_destroy (&reply);
183 r = mongoc_client_session_commit_transaction (session, &reply, &error);
184 if (r) {
185 /* success */
186 break;
187 } else {
188 MONGOC_ERROR ("Warning: commit failed: %s", error.message);
189 if (mongoc_error_has_label (&reply, "TransientTransactionError")) {
190 goto retry_transaction;
191 } else if (mongoc_error_has_label (&reply,
192 "UnknownTransactionCommitResult")) {
193 /* try again to commit */
194 continue;
195 }
196
197 /* unrecoverable error trying to commit */
198 break;
199 }
200 }
201
202 exit_code = EXIT_SUCCESS;
203
204 done:
205 bson_destroy (&reply);
206 bson_destroy (insert_opts);
207 mongoc_write_concern_destroy (write_concern);
208 mongoc_read_concern_destroy (read_concern);
209 mongoc_transaction_opts_destroy (txn_opts);
210 mongoc_transaction_opts_destroy (default_txn_opts);
211 mongoc_client_session_destroy (session);
212 mongoc_collection_destroy (collection);
213 mongoc_database_destroy (database);
214 mongoc_uri_destroy (uri);
215 mongoc_client_destroy (client);
216
217 mongoc_cleanup ();
218
219 return exit_code;
220 }
221
222
224 MongoDB, Inc
225
227 2017-present, MongoDB, Inc
228
229
230
231
2321.25.1 NovM0O8N,GO2C0_2C3LIENT_SESSION_START_TRANSACTION(3)