MONGOC_CLIENT_SESSION_START_TRANSACTION(3) | libmongoc | MONGOC_CLIENT_SESSION_START_TRANSACTION(3) |
SYNOPSIS¶
bool mongoc_client_session_start_transaction (mongoc_client_session_t *session,
const mongoc_transaction_opt_t *opts,
bson_error_t *error);
Start a multi-document transaction for all following operations in this session. Any options provided in opts override options passed to mongoc_session_opts_set_default_transaction_opts(), and options inherited from the mongoc_client_t. The opts argument is copied and can be freed after calling this function.
The transaction must be completed with mongoc_client_session_commit_transaction() or mongoc_client_session_abort_transaction(). An in-progress transaction is automatically aborted by mongoc_client_session_destroy().
If a command inside of the transaction fails, it may cause the transaction on the server to be aborted. An attempt to commit such transaction will be rejected with NoSuchTransaction error.
PARAMETERS¶
- session: A mongoc_client_session_t.
- opts: A mongoc_transaction_opt_t or NULL.
- error: An optional location for a bson_error_t or NULL.
RETURN¶
Returns true if the transaction was started. Returns false and sets error if there are invalid arguments, such as a session with a transaction already in progress.
EXAMPLE¶
The following example demonstrates how to use error labels to reliably execute a multi-document transaction despite network errors and other transient failures.
example-transaction.c
/* gcc example-transaction.c -o example-transaction \
* $(pkg-config --cflags --libs libmongoc-1.0) */ /* ./example-transaction [CONNECTION_STRING] */ #include <stdio.h> #include <mongoc/mongoc.h> int main (int argc, char *argv[]) {
int exit_code = EXIT_FAILURE;
mongoc_client_t *client = NULL;
mongoc_database_t *database = NULL;
mongoc_collection_t *collection = NULL;
mongoc_client_session_t *session = NULL;
mongoc_session_opt_t *session_opts = NULL;
mongoc_transaction_opt_t *default_txn_opts = NULL;
mongoc_transaction_opt_t *txn_opts = NULL;
mongoc_read_concern_t *read_concern = NULL;
mongoc_write_concern_t *write_concern = NULL;
const char *uri_string = "mongodb://127.0.0.1/?appname=transaction-example";
mongoc_uri_t *uri;
bson_error_t error;
bson_t *doc = NULL;
bson_t *insert_opts = NULL;
int32_t i;
int64_t start;
bson_t reply = BSON_INITIALIZER;
char *reply_json;
bool r;
mongoc_init ();
if (argc > 1) {
uri_string = argv[1];
}
uri = mongoc_uri_new_with_error (uri_string, &error);
if (!uri) {
MONGOC_ERROR ("failed to parse URI: %s\n"
"error message: %s\n",
uri_string,
error.message);
goto done;
}
client = mongoc_client_new_from_uri (uri);
if (!client) {
goto done;
}
mongoc_client_set_error_api (client, 2);
database = mongoc_client_get_database (client, "example-transaction");
/* inserting into a nonexistent collection normally creates it, but a
* collection can't be created in a transaction; create it now */
collection = mongoc_database_create_collection (database, "collection", NULL, &error);
if (!collection) {
/* code 48 is NamespaceExists, see error_codes.err in mongodb source */
if (error.code == 48) {
collection = mongoc_database_get_collection (database, "collection");
} else {
MONGOC_ERROR ("Failed to create collection: %s", error.message);
goto done;
}
}
/* a transaction's read preferences, read concern, and write concern can be
* set on the client, on the default transaction options, or when starting
* the transaction. for the sake of this example, set read concern on the
* default transaction options. */
default_txn_opts = mongoc_transaction_opts_new ();
read_concern = mongoc_read_concern_new ();
mongoc_read_concern_set_level (read_concern, "snapshot");
mongoc_transaction_opts_set_read_concern (default_txn_opts, read_concern);
session_opts = mongoc_session_opts_new ();
mongoc_session_opts_set_default_transaction_opts (session_opts, default_txn_opts);
session = mongoc_client_start_session (client, session_opts, &error);
if (!session) {
MONGOC_ERROR ("Failed to start session: %s", error.message);
goto done;
}
/* in this example, set write concern when starting the transaction */
txn_opts = mongoc_transaction_opts_new ();
write_concern = mongoc_write_concern_new ();
mongoc_write_concern_set_wmajority (write_concern, 1000 /* wtimeout */);
mongoc_transaction_opts_set_write_concern (txn_opts, write_concern);
insert_opts = bson_new ();
if (!mongoc_client_session_append (session, insert_opts, &error)) {
MONGOC_ERROR ("Could not add session to opts: %s", error.message);
goto done;
} retry_transaction:
r = mongoc_client_session_start_transaction (session, txn_opts, &error);
if (!r) {
MONGOC_ERROR ("Failed to start transaction: %s", error.message);
goto done;
}
/* insert two documents - on error, retry the whole transaction */
for (i = 0; i < 2; i++) {
doc = BCON_NEW ("_id", BCON_INT32 (i));
bson_destroy (&reply);
r = mongoc_collection_insert_one (collection, doc, insert_opts, &reply, &error);
bson_destroy (doc);
if (!r) {
MONGOC_ERROR ("Insert failed: %s", error.message);
mongoc_client_session_abort_transaction (session, NULL);
/* a network error, primary failover, or other temporary error in a
* transaction includes {"errorLabels": ["TransientTransactionError"]},
* meaning that trying the entire transaction again may succeed
*/
if (mongoc_error_has_label (&reply, "TransientTransactionError")) {
goto retry_transaction;
}
goto done;
}
reply_json = bson_as_relaxed_extended_json (&reply, NULL);
printf ("%s\n", reply_json);
bson_free (reply_json);
}
/* in case of transient errors, retry for 5 seconds to commit transaction */
start = bson_get_monotonic_time ();
while (bson_get_monotonic_time () - start < 5 * 1000 * 1000) {
bson_destroy (&reply);
r = mongoc_client_session_commit_transaction (session, &reply, &error);
if (r) {
/* success */
break;
} else {
MONGOC_ERROR ("Warning: commit failed: %s", error.message);
if (mongoc_error_has_label (&reply, "TransientTransactionError")) {
goto retry_transaction;
} else if (mongoc_error_has_label (&reply, "UnknownTransactionCommitResult")) {
/* try again to commit */
continue;
}
/* unrecoverable error trying to commit */
break;
}
}
exit_code = EXIT_SUCCESS; done:
bson_destroy (&reply);
bson_destroy (insert_opts);
mongoc_write_concern_destroy (write_concern);
mongoc_read_concern_destroy (read_concern);
mongoc_transaction_opts_destroy (txn_opts);
mongoc_transaction_opts_destroy (default_txn_opts);
mongoc_client_session_destroy (session);
mongoc_collection_destroy (collection);
mongoc_database_destroy (database);
mongoc_uri_destroy (uri);
mongoc_client_destroy (client);
mongoc_cleanup ();
return exit_code; }
AUTHOR¶
MongoDB, Inc
COPYRIGHT¶
2009-present, MongoDB, Inc.
December 12, 2024 | 1.29.1 |