static void test_write_concern_wtimeout_validity (void) { mongoc_write_concern_t *write_concern = mongoc_write_concern_new(); /* Test defaults */ ASSERT(write_concern); ASSERT(mongoc_write_concern_get_w(write_concern) == MONGOC_WRITE_CONCERN_W_DEFAULT); ASSERT(mongoc_write_concern_get_wtimeout(write_concern) == 0); ASSERT(!mongoc_write_concern_get_wmajority(write_concern)); /* mongoc_write_concern_set_wtimeout() ignores invalid wtimeout */ mongoc_write_concern_set_wtimeout(write_concern, -1); ASSERT(mongoc_write_concern_get_w(write_concern) == MONGOC_WRITE_CONCERN_W_DEFAULT); ASSERT(mongoc_write_concern_get_wtimeout(write_concern) == 0); ASSERT(!mongoc_write_concern_get_wmajority(write_concern)); ASSERT(mongoc_write_concern_is_valid (write_concern)); /* mongoc_write_concern_set_wmajority() ignores invalid wtimeout */ mongoc_write_concern_set_wmajority(write_concern, -1); ASSERT(mongoc_write_concern_get_w(write_concern) == MONGOC_WRITE_CONCERN_W_MAJORITY); ASSERT(mongoc_write_concern_get_wtimeout(write_concern) == 0); ASSERT(mongoc_write_concern_get_wmajority(write_concern)); ASSERT(mongoc_write_concern_is_valid (write_concern)); /* Manually assigning a negative wtimeout will make the write concern invalid */ write_concern->wtimeout = -1; ASSERT(!mongoc_write_concern_is_valid (write_concern)); mongoc_write_concern_destroy(write_concern); }
static void test_invalid_write_concern (void) { mongoc_bulk_write_flags_t write_flags = MONGOC_BULK_WRITE_FLAGS_INIT; mongoc_write_command_t command; mongoc_write_result_t result; mongoc_collection_t *collection; mongoc_client_t *client; mongoc_write_concern_t *write_concern; mongoc_server_stream_t *server_stream; bson_t *doc; bson_t reply = BSON_INITIALIZER; bson_error_t error; bool r; client = test_framework_client_new (); assert(client); collection = get_test_collection(client, "test_invalid_write_concern"); assert(collection); write_concern = mongoc_write_concern_new(); assert(write_concern); mongoc_write_concern_set_w(write_concern, 0); mongoc_write_concern_set_journal(write_concern, true); assert(!mongoc_write_concern_is_valid (write_concern)); doc = BCON_NEW("_id", BCON_INT32(0)); _mongoc_write_command_init_insert(&command, doc, write_flags, ++client->cluster.operation_id, true); _mongoc_write_result_init (&result); server_stream = mongoc_cluster_stream_for_writes (&client->cluster, &error); ASSERT_OR_PRINT (server_stream, error); _mongoc_write_command_execute (&command, client, server_stream, collection->db, collection->collection, write_concern, 0, &result); r = _mongoc_write_result_complete (&result, 2, collection->write_concern, &reply, &error); assert(!r); ASSERT_CMPINT(error.domain, ==, MONGOC_ERROR_COMMAND); ASSERT_CMPINT(error.code, ==, MONGOC_ERROR_COMMAND_INVALID_ARG); _mongoc_write_command_destroy (&command); _mongoc_write_result_destroy (&result); bson_destroy(doc); mongoc_server_stream_cleanup (server_stream); mongoc_collection_destroy(collection); mongoc_client_destroy(client); mongoc_write_concern_destroy(write_concern); }
bool _mongoc_write_concern_validate (const mongoc_write_concern_t *write_concern, bson_error_t *error) { if (write_concern && !mongoc_write_concern_is_valid (write_concern)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Invalid mongoc_write_concern_t"); return false; } return true; }
void _mongoc_write_command_execute ( mongoc_write_command_t *command, /* IN */ mongoc_client_t *client, /* IN */ mongoc_server_stream_t *server_stream, /* IN */ const char *database, /* IN */ const char *collection, /* IN */ const mongoc_write_concern_t *write_concern, /* IN */ uint32_t offset, /* IN */ mongoc_client_session_t *cs, /* IN */ mongoc_write_result_t *result) /* OUT */ { mongoc_crud_opts_t crud = {0}; ENTRY; BSON_ASSERT (command); BSON_ASSERT (client); BSON_ASSERT (server_stream); BSON_ASSERT (database); BSON_ASSERT (collection); BSON_ASSERT (result); if (!write_concern) { write_concern = client->write_concern; } if (!mongoc_write_concern_is_valid (write_concern)) { bson_set_error (&result->error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The write concern is invalid."); result->failed = true; EXIT; } crud.client_session = cs; crud.writeConcern = (mongoc_write_concern_t *) write_concern; _mongoc_write_command_execute_idl (command, client, server_stream, database, collection, offset, &crud, result); EXIT; }
mongoc_uri_t * mongoc_uri_new (const char *uri_string) { mongoc_uri_t *uri; #ifdef MONGOC_EXPERIMENTAL_FEATURES int32_t max_staleness_ms; #endif uri = (mongoc_uri_t *)bson_malloc0(sizeof *uri); bson_init(&uri->options); bson_init(&uri->credentials); /* Initialize read_prefs since tag parsing may add to it */ uri->read_prefs = mongoc_read_prefs_new(MONGOC_READ_PRIMARY); /* Initialize empty read_concern */ uri->read_concern = mongoc_read_concern_new (); if (!uri_string) { uri_string = "mongodb://127.0.0.1/"; } if (!mongoc_uri_parse(uri, uri_string)) { mongoc_uri_destroy(uri); return NULL; } uri->str = bson_strdup(uri_string); _mongoc_uri_assign_read_prefs_mode(uri); #ifdef MONGOC_EXPERIMENTAL_FEATURES max_staleness_ms = mongoc_uri_get_option_as_int32 (uri, "maxstalenessms", 0); mongoc_read_prefs_set_max_staleness_ms (uri->read_prefs, max_staleness_ms); #endif if (!mongoc_read_prefs_is_valid(uri->read_prefs)) { mongoc_uri_destroy(uri); return NULL; } _mongoc_uri_build_write_concern (uri); if (!mongoc_write_concern_is_valid (uri->write_concern)) { mongoc_uri_destroy(uri); return NULL; } return uri; }
/** * mongoc_write_concern_append: * @write_concern: (in): A mongoc_write_concern_t. * @command: (out): A pointer to a bson document. * * Appends a write_concern document to a command, to send to * a server. * * Returns true on success, false on failure. * */ bool mongoc_write_concern_append (mongoc_write_concern_t *write_concern, bson_t *command) { if (!mongoc_write_concern_is_valid (write_concern)) { MONGOC_ERROR ("Invalid writeConcern passed into " "mongoc_write_concern_append."); return false; } if (!bson_append_document (command, "writeConcern", 12, _mongoc_write_concern_get_bson (write_concern))) { MONGOC_ERROR ("Could not append writeConcern to command."); return false; } return true; }
mongoc_uri_t * mongoc_uri_new (const char *uri_string) { mongoc_uri_t *uri; uri = (mongoc_uri_t *)bson_malloc0(sizeof *uri); bson_init(&uri->options); bson_init(&uri->credentials); /* Initialize read_prefs since tag parsing may add to it */ uri->read_prefs = mongoc_read_prefs_new(MONGOC_READ_PRIMARY); /* Initialize empty read_concern */ uri->read_concern = mongoc_read_concern_new (); if (!uri_string) { uri_string = "mongodb://127.0.0.1/"; } if (!mongoc_uri_parse(uri, uri_string)) { mongoc_uri_destroy(uri); return NULL; } uri->str = bson_strdup(uri_string); _mongoc_uri_assign_read_prefs_mode(uri); if (!mongoc_read_prefs_is_valid(uri->read_prefs)) { mongoc_uri_destroy(uri); return NULL; } _mongoc_uri_build_write_concern (uri); if (!mongoc_write_concern_is_valid (uri->write_concern)) { mongoc_uri_destroy(uri); return NULL; } return uri; }
static void test_write_concern_fsync_and_journal_gle_and_validity (void) { mongoc_write_concern_t *write_concern = mongoc_write_concern_new(); /* * Journal and fsync should imply GLE regardless of w; however, journal and * fsync logically conflict with w=0 and w=-1, so a write concern with such * a combination of options will be considered invalid. */ /* No write concern needs GLE, but not "valid" */ ASSERT(mongoc_write_concern_is_acknowledged (NULL)); ASSERT(!mongoc_write_concern_is_valid (NULL)); /* Default write concern needs GLE and is valid */ ASSERT(write_concern); ASSERT(mongoc_write_concern_is_acknowledged (write_concern)); ASSERT(mongoc_write_concern_is_valid (write_concern)); ASSERT(!mongoc_write_concern_journal_is_set (write_concern)); /* w=0 does not need GLE and is valid */ mongoc_write_concern_set_w(write_concern, MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED); ASSERT(!mongoc_write_concern_is_acknowledged (write_concern)); ASSERT(mongoc_write_concern_is_valid (write_concern)); ASSERT(!mongoc_write_concern_journal_is_set (write_concern)); /* fsync=true needs GLE, but it conflicts with w=0 */ mongoc_write_concern_set_fsync(write_concern, true); ASSERT(mongoc_write_concern_is_acknowledged (write_concern)); ASSERT(!mongoc_write_concern_is_valid (write_concern)); ASSERT(!mongoc_write_concern_journal_is_set (write_concern)); mongoc_write_concern_set_fsync(write_concern, false); /* journal=true needs GLE, but it conflicts with w=0 */ mongoc_write_concern_set_journal(write_concern, true); ASSERT(mongoc_write_concern_is_acknowledged (write_concern)); ASSERT(!mongoc_write_concern_is_valid (write_concern)); ASSERT(mongoc_write_concern_journal_is_set (write_concern)); mongoc_write_concern_set_journal(write_concern, false); /* w=-1 does not need GLE and is valid */ mongoc_write_concern_set_w(write_concern, MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED); ASSERT(!mongoc_write_concern_is_acknowledged (write_concern)); ASSERT(mongoc_write_concern_is_valid (write_concern)); ASSERT(mongoc_write_concern_journal_is_set (write_concern)); /* fsync=true needs GLE, but it conflicts with w=-1 */ mongoc_write_concern_set_fsync(write_concern, true); ASSERT(mongoc_write_concern_is_acknowledged (write_concern)); ASSERT(!mongoc_write_concern_is_valid (write_concern)); ASSERT(mongoc_write_concern_journal_is_set (write_concern)); /* journal=true needs GLE, but it conflicts with w=-1 */ mongoc_write_concern_set_fsync(write_concern, false); mongoc_write_concern_set_journal(write_concern, true); ASSERT(mongoc_write_concern_is_acknowledged (write_concern)); ASSERT(mongoc_write_concern_journal_is_set (write_concern)); /* fsync=true with w=default needs GLE and is valid */ mongoc_write_concern_set_journal(write_concern, false); mongoc_write_concern_set_fsync(write_concern, true); mongoc_write_concern_set_w(write_concern, MONGOC_WRITE_CONCERN_W_DEFAULT); ASSERT(mongoc_write_concern_is_acknowledged (write_concern)); ASSERT(mongoc_write_concern_is_valid (write_concern)); ASSERT(mongoc_write_concern_journal_is_set (write_concern)); /* journal=true with w=default needs GLE and is valid */ mongoc_write_concern_set_journal(write_concern, false); mongoc_write_concern_set_fsync(write_concern, true); mongoc_write_concern_set_w(write_concern, MONGOC_WRITE_CONCERN_W_DEFAULT); ASSERT(mongoc_write_concern_is_acknowledged (write_concern)); ASSERT(mongoc_write_concern_is_valid (write_concern)); ASSERT(mongoc_write_concern_journal_is_set (write_concern)); mongoc_write_concern_destroy(write_concern); }
void _mongoc_write_command_execute ( mongoc_write_command_t *command, /* IN */ mongoc_client_t *client, /* IN */ mongoc_server_stream_t *server_stream, /* IN */ const char *database, /* IN */ const char *collection, /* IN */ const mongoc_write_concern_t *write_concern, /* IN */ uint32_t offset, /* IN */ mongoc_client_session_t *cs, /* IN */ mongoc_write_result_t *result) /* OUT */ { ENTRY; BSON_ASSERT (command); BSON_ASSERT (client); BSON_ASSERT (server_stream); BSON_ASSERT (database); BSON_ASSERT (collection); BSON_ASSERT (result); if (!write_concern) { write_concern = client->write_concern; } if (!mongoc_write_concern_is_valid (write_concern)) { bson_set_error (&result->error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The write concern is invalid."); result->failed = true; EXIT; } if (command->flags.has_collation) { if (!mongoc_write_concern_is_acknowledged (write_concern)) { result->failed = true; bson_set_error (&result->error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Cannot set collation for unacknowledged writes"); EXIT; } if (server_stream->sd->max_wire_version < WIRE_VERSION_COLLATION) { bson_set_error (&result->error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION, "Collation is not supported by the selected server"); result->failed = true; EXIT; } } if (command->flags.bypass_document_validation != MONGOC_BYPASS_DOCUMENT_VALIDATION_DEFAULT) { if (!mongoc_write_concern_is_acknowledged (write_concern)) { result->failed = true; bson_set_error ( &result->error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Cannot set bypassDocumentValidation for unacknowledged writes"); EXIT; } } if (command->payload.len == 0) { _empty_error (command, &result->error); EXIT; } if (server_stream->sd->max_wire_version >= WIRE_VERSION_OP_MSG) { if (cs && !mongoc_write_concern_is_acknowledged (write_concern)) { bson_set_error ( &result->error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Cannot use client session with unacknowledged writes"); EXIT; } _mongoc_write_opmsg (command, client, server_stream, database, collection, write_concern, offset, cs, result, &result->error); } else { if (mongoc_write_concern_is_acknowledged (write_concern)) { _mongoc_write_opquery (command, client, server_stream, database, collection, write_concern, offset, result, &result->error); } else { gLegacyWriteOps[command->type](command, client, server_stream, database, collection, offset, result, &result->error); } } EXIT; }
static bool hippo_mongo_driver_manager_apply_wc(mongoc_uri_t *uri, const Array options) { int32_t wtimeoutms; mongoc_write_concern_t *new_wc; const mongoc_write_concern_t *old_wc; if (!(old_wc = mongoc_uri_get_write_concern(uri))) { throw MongoDriver::Utils::throwRunTimeException("mongoc_uri_t does not have a write concern"); return false; } if (options.size() == 0) { return true; } if ( !options.exists(s_MongoDBDriverManager_journal) && !options.exists(s_MongoDBDriverManager_safe) && !options.exists(s_MongoDBDriverManager_w) && !options.exists(s_MongoDBDriverManager_wtimeoutms) ) { return true; } wtimeoutms = mongoc_write_concern_get_wtimeout(old_wc); new_wc = mongoc_write_concern_copy(old_wc); if (options.exists(s_MongoDBDriverManager_safe) && options[s_MongoDBDriverManager_safe].isBoolean()) { mongoc_write_concern_set_w(new_wc, options[s_MongoDBDriverManager_safe].toBoolean() ? 1 : MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED); } if (options.exists(s_MongoDBDriverManager_wtimeoutms) && options[s_MongoDBDriverManager_wtimeoutms].isInteger()) { wtimeoutms = (int32_t) options[s_MongoDBDriverManager_wtimeoutms].toInt64(); } if (options.exists(s_MongoDBDriverManager_journal) && options[s_MongoDBDriverManager_journal].isBoolean()) { mongoc_write_concern_set_journal(new_wc, !!options[s_MongoDBDriverManager_journal].toBoolean()); } if (options.exists(s_MongoDBDriverManager_w)) { if (options[s_MongoDBDriverManager_w].isInteger()) { int32_t value = (int32_t) options[s_MongoDBDriverManager_w].toInt64(); switch (value) { case MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED: case MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED: mongoc_write_concern_set_w(new_wc, value); break; default: if (value > 0) { mongoc_write_concern_set_w(new_wc, value); break; } throw MongoDriver::Utils::throwInvalidArgumentException("Unsupported w value: " + Variant(value).toString()); mongoc_write_concern_destroy(new_wc); return false; } } else if (options[s_MongoDBDriverManager_w].isString()) { const char *str = options[s_MongoDBDriverManager_w].toString().c_str(); if (0 == strcasecmp("majority", str)) { mongoc_write_concern_set_wmajority(new_wc, wtimeoutms); } else { mongoc_write_concern_set_wtag(new_wc, str); } } } /* Only set wtimeout if it's still applicable; otherwise, clear it. */ if (mongoc_write_concern_get_w(new_wc) > 1 || mongoc_write_concern_get_wmajority(new_wc) || mongoc_write_concern_get_wtag(new_wc)) { mongoc_write_concern_set_wtimeout(new_wc, wtimeoutms); } else { mongoc_write_concern_set_wtimeout(new_wc, 0); } if (mongoc_write_concern_get_journal(new_wc)) { int32_t w = mongoc_write_concern_get_w(new_wc); if (w == MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED || w == MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED) { throw MongoDriver::Utils::throwInvalidArgumentException("Journal conflicts with w value: " + Variant(w).toString()); mongoc_write_concern_destroy(new_wc); return false; } } /* This may be redundant in light of the last check (unacknowledged w with * journal), but we'll check anyway in case additional validation is * implemented. */ if (!mongoc_write_concern_is_valid(new_wc)) { throw MongoDriver::Utils::throwInvalidArgumentException("Write concern is not valid"); mongoc_write_concern_destroy(new_wc); return false; } mongoc_uri_set_write_concern(uri, new_wc); mongoc_write_concern_destroy(new_wc); return true; }