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);
}
Пример #2
0
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;
}
Пример #4
0
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;
}
Пример #5
0
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;
}
Пример #7
0
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);
}
Пример #9
0
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;
}
Пример #10
0
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;
}