mongoc_database_t * _mongoc_database_new (mongoc_client_t *client, const char *name, const mongoc_read_prefs_t *read_prefs, const mongoc_write_concern_t *write_concern) { mongoc_database_t *db; ENTRY; bson_return_val_if_fail(client, NULL); bson_return_val_if_fail(name, NULL); db = bson_malloc0(sizeof *db); db->client = client; db->write_concern = write_concern ? mongoc_write_concern_copy(write_concern) : mongoc_write_concern_new(); db->read_prefs = read_prefs ? mongoc_read_prefs_copy(read_prefs) : mongoc_read_prefs_new(MONGOC_READ_PRIMARY); bson_strncpy (db->name, name, sizeof db->name); RETURN(db); }
static void test_read_prefs_standalone_primary (void) { mongoc_read_prefs_t *read_prefs; /* Server Selection Spec: for topology type single and server types other * than mongos, "clients MUST always set the slaveOK wire protocol flag on * reads to ensure that any server type can handle the request." * */ read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); _test_read_prefs (READ_PREF_TEST_STANDALONE, read_prefs, "{}", "{}", MONGOC_QUERY_SLAVE_OK, "{'find': 'test', 'filter': {}}", MONGOC_QUERY_SLAVE_OK); _test_read_prefs (READ_PREF_TEST_STANDALONE, read_prefs, "{'a': 1}", "{'a': 1}", MONGOC_QUERY_SLAVE_OK, "{'find': 'test', 'filter': {'a': 1}}", MONGOC_QUERY_SLAVE_OK); mongoc_read_prefs_destroy (read_prefs); }
static void test_read_prefs_mongos_secondary_preferred (void) { mongoc_read_prefs_t *read_prefs; read_prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY_PREFERRED); /* $readPreference not sent, only slaveOk */ _test_read_prefs (READ_PREF_TEST_MONGOS, read_prefs, "{}", "{}", MONGOC_QUERY_SLAVE_OK, "{'find': 'test', 'filter': {}}", MONGOC_QUERY_SLAVE_OK); _test_read_prefs (READ_PREF_TEST_MONGOS, read_prefs, "{'a': 1}", "{'a': 1}", MONGOC_QUERY_SLAVE_OK, "{'find': 'test', 'filter': {'a': 1}}", MONGOC_QUERY_SLAVE_OK); mongoc_read_prefs_destroy (read_prefs); }
static void test_read_prefs_mongos_tags (void) { bson_t b = BSON_INITIALIZER; mongoc_read_prefs_t *read_prefs; bson_append_utf8 (&b, "dc", 2, "ny", 2); read_prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY_PREFERRED); mongoc_read_prefs_add_tag (read_prefs, &b); mongoc_read_prefs_add_tag (read_prefs, NULL); _test_read_prefs ( READ_PREF_TEST_MONGOS, read_prefs, "{}", "{'$query': {}, '$readPreference': {'mode': 'secondaryPreferred'," " 'tags': [{'dc': 'ny'}, {}]}}", MONGOC_QUERY_SLAVE_OK, "{'$query': {'find': 'test', 'filter': {}}," " '$readPreference': {'mode': 'secondaryPreferred'," " 'tags': [{'dc': 'ny'}, {}]}}", MONGOC_QUERY_SLAVE_OK); _test_read_prefs ( READ_PREF_TEST_MONGOS, read_prefs, "{'a': 1}", "{'$query': {'a': 1}," " '$readPreference': {'mode': 'secondaryPreferred'," " 'tags': [{'dc': 'ny'}, {}]}}", MONGOC_QUERY_SLAVE_OK, "{'$query': {'find': 'test', 'filter': {}}," " '$readPreference': {'mode': 'secondaryPreferred'," " 'tags': [{'dc': 'ny'}, {}]}}", MONGOC_QUERY_SLAVE_OK); mongoc_read_prefs_destroy (read_prefs); }
static void test_read_prefs_secondary_rssecondary (void) { mongoc_read_prefs_t *read_prefs; read_prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY); _test_read_prefs (READ_PREF_TEST_SECONDARY, read_prefs, "{}", "{}", MONGOC_QUERY_SLAVE_OK, "{'find': 'test', 'filter': {}}", MONGOC_QUERY_SLAVE_OK); _test_read_prefs (READ_PREF_TEST_SECONDARY, read_prefs, "{'a': 1}", "{'a': 1}", MONGOC_QUERY_SLAVE_OK, "{'find': 'test', 'filter': {'a': 1}}", MONGOC_QUERY_SLAVE_OK); mongoc_read_prefs_destroy (read_prefs); }
void mongoc_client_kill_cursor (mongoc_client_t *client, int64_t cursor_id) { mongoc_topology_t *topology; mongoc_server_description_t *selected_server; mongoc_read_prefs_t *read_prefs; uint32_t server_id = 0; topology = client->topology; read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); mongoc_mutex_lock (&topology->mutex); /* see if there's a known writable server - do no I/O or retries */ selected_server = mongoc_topology_description_select(&topology->description, MONGOC_SS_WRITE, read_prefs, 15); if (selected_server) { server_id = selected_server->id; } mongoc_mutex_unlock (&topology->mutex); if (server_id) { _mongoc_client_kill_cursor (client, selected_server->id, cursor_id); } else { MONGOC_INFO ("No server available for mongoc_client_kill_cursor"); } mongoc_read_prefs_destroy (read_prefs); }
static void test_read_prefs_standalone_tags (void) { bson_t b = BSON_INITIALIZER; mongoc_read_prefs_t *read_prefs; bson_append_utf8 (&b, "dc", 2, "ny", 2); read_prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY_PREFERRED); mongoc_read_prefs_add_tag (read_prefs, &b); mongoc_read_prefs_add_tag (read_prefs, NULL); _test_read_prefs (READ_PREF_TEST_STANDALONE, read_prefs, "{}", "{}", MONGOC_QUERY_SLAVE_OK, "{'find': 'test', 'filter': {}}", MONGOC_QUERY_SLAVE_OK); _test_read_prefs (READ_PREF_TEST_STANDALONE, read_prefs, "{'a': 1}", "{'a': 1}", MONGOC_QUERY_SLAVE_OK, "{'find': 'test', 'filter': {'a': 1}}", MONGOC_QUERY_SLAVE_OK); mongoc_read_prefs_destroy (read_prefs); }
int main (int argc, char *argv[]) { mongoc_read_prefs_t *read_prefs; mongoc_client_t *client; mongoc_uri_t *uri; if (argc < 2) { fprintf(stderr, "usage: %s mongodb://...\n", argv[0]); return EXIT_FAILURE; } uri = mongoc_uri_new(argv[1]); if (!uri) { fprintf(stderr, "Invalid URI: \"%s\"\n", argv[1]); return EXIT_FAILURE; } signal(SIGUSR1, sighandler); signal(SIGUSR2, sighandler); client = mongoc_client_new_from_uri(uri); read_prefs = mongoc_read_prefs_new(MONGOC_READ_SECONDARY); mongoc_client_set_read_prefs(client, read_prefs); mongoc_read_prefs_destroy(read_prefs); test_secondary(client); mongoc_client_destroy(client); mongoc_uri_destroy(uri); return EXIT_SUCCESS; }
static void test_mongoc_client_command_secondary (void) { mongoc_client_t *client; mongoc_cursor_t *cursor; mongoc_read_prefs_t *read_prefs; bson_t cmd = BSON_INITIALIZER; client = mongoc_client_new (gTestUri); assert (client); BSON_APPEND_INT32 (&cmd, "invalid_command_here", 1); read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY_PREFERRED); suppress_one_message (); cursor = mongoc_client_command (client, "admin", MONGOC_QUERY_NONE, 0, 1, 0, &cmd, NULL, read_prefs); mongoc_read_prefs_destroy (read_prefs); /* ensure we detected this must go to primary */ assert (cursor->redir_primary); mongoc_cursor_destroy (cursor); mongoc_client_destroy (client); bson_destroy (&cmd); }
mongoc_database_t * _mongoc_database_new (mongoc_client_t *client, const char *name, const mongoc_read_prefs_t *read_prefs, const mongoc_read_concern_t *read_concern, const mongoc_write_concern_t *write_concern) { mongoc_database_t *db; ENTRY; BSON_ASSERT (client); BSON_ASSERT (name); db = (mongoc_database_t *)bson_malloc0(sizeof *db); db->client = client; db->write_concern = write_concern ? mongoc_write_concern_copy(write_concern) : mongoc_write_concern_new(); db->read_concern = read_concern ? mongoc_read_concern_copy(read_concern) : mongoc_read_concern_new(); db->read_prefs = read_prefs ? mongoc_read_prefs_copy(read_prefs) : mongoc_read_prefs_new(MONGOC_READ_PRIMARY); bson_strncpy (db->name, name, sizeof db->name); RETURN(db); }
static void test_read_prefs_mongos_primary (void) { mongoc_read_prefs_t *read_prefs; read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); _test_read_prefs (READ_PREF_TEST_MONGOS, read_prefs, "{}", "{}", MONGOC_QUERY_NONE, "{'find': 'test', 'filter': {}}", MONGOC_QUERY_NONE); _test_read_prefs (READ_PREF_TEST_MONGOS, read_prefs, "{'a': 1}", "{'a': 1}", MONGOC_QUERY_NONE, "{'find': 'test', 'filter': {'a': 1}}", MONGOC_QUERY_NONE); mongoc_read_prefs_destroy (read_prefs); }
static void test_read_prefs_mongos_secondary (void) { mongoc_read_prefs_t *read_prefs; read_prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY); _test_read_prefs ( READ_PREF_TEST_MONGOS, read_prefs, "{}", "{'$query': {}, '$readPreference': {'mode': 'secondary'}}", MONGOC_QUERY_SLAVE_OK, "{'$query': {'find': 'test', 'filter': {}}," " '$readPreference': {'mode': 'secondary'}}", MONGOC_QUERY_SLAVE_OK); _test_read_prefs ( READ_PREF_TEST_MONGOS, read_prefs, "{'a': 1}", "{'$query': {'a': 1}, '$readPreference': {'mode': 'secondary'}}", MONGOC_QUERY_SLAVE_OK, "{'$query': {'find': 'test', 'filter': {'a': 1}}," " '$readPreference': {'mode': 'secondary'}}", MONGOC_QUERY_SLAVE_OK); _test_read_prefs ( READ_PREF_TEST_MONGOS, read_prefs, "{'$query': {'a': 1}}", "{'$query': {'a': 1}, '$readPreference': {'mode': 'secondary'}}", MONGOC_QUERY_SLAVE_OK, "{'$query': {'find': 'test', 'filter': {'a': 1}}," " '$readPreference': {'mode': 'secondary'}}", MONGOC_QUERY_SLAVE_OK); mongoc_read_prefs_destroy (read_prefs); }
/* direct connection to a secondary requires read pref primaryPreferred to * avoid "not master" error from server */ static void _test_op_msg_direct_connection (bool is_mongos, test_op_msg_direct_fn_t fn, const char *expected_cmd) { mock_server_t *server; mongoc_client_t *client; mongoc_collection_t *collection; mongoc_read_prefs_t *prefs = NULL; mongoc_cursor_t *cursor; const bson_t *doc; bson_t *cmd; future_t *future; request_t *request; const char *reply; int i; if (is_mongos) { server = mock_mongos_new (WIRE_VERSION_OP_MSG); } else { server = mock_server_with_autoismaster (WIRE_VERSION_OP_MSG); } mock_server_auto_endsessions (server); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); collection = mongoc_client_get_collection (client, "db", "collection"); for (i = 0; i < 2; i++) { if (i == 1) { /* user-supplied read preference primary makes no difference */ prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); } cursor = fn (collection, prefs); future = future_cursor_next (cursor, &doc); cmd = tmp_bson (expected_cmd); request = mock_server_receives_msg (server, 0, cmd); reply = "{'ok': 1," " 'cursor': {" " 'id': 0," " 'ns': 'db.collection'," " 'firstBatch': [{'a': 1}]}}"; mock_server_replies_simple (request, reply); BSON_ASSERT (future_get_bool (future)); future_destroy (future); request_destroy (request); mongoc_cursor_destroy (cursor); mongoc_read_prefs_destroy (prefs); /* null ok */ } mongoc_collection_destroy (collection); mongoc_client_destroy (client); mock_server_destroy (server); }
/** * mongoc_database_has_collection: * @database: (in): A #mongoc_database_t. * @name: (in): The name of the collection to check for. * @error: (out) (allow-none): A location for a #bson_error_t, or %NULL. * * Checks to see if a collection exists within the database on the MongoDB * server. * * This will return %false if their was an error communicating with the * server, or if the collection does not exist. * * If @error is provided, it will first be zeroed. Upon error, error.domain * will be set. * * Returns: %true if @name exists, otherwise %false. @error may be set. */ bool mongoc_database_has_collection (mongoc_database_t *database, const char *name, bson_error_t *error) { mongoc_collection_t *collection; mongoc_read_prefs_t *read_prefs; mongoc_cursor_t *cursor; const bson_t *doc; bson_iter_t iter; bool ret = false; const char *cur_name; bson_t q = BSON_INITIALIZER; char ns[140]; ENTRY; BSON_ASSERT (database); BSON_ASSERT (name); if (error) { memset (error, 0, sizeof *error); } bson_snprintf (ns, sizeof ns, "%s.%s", database->name, name); ns[sizeof ns - 1] = '\0'; read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); collection = mongoc_client_get_collection (database->client, database->name, "system.namespaces"); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0, &q, NULL, read_prefs); while (!mongoc_cursor_error (cursor, error) && mongoc_cursor_more (cursor)) { while (mongoc_cursor_next (cursor, &doc) && bson_iter_init_find (&iter, doc, "name") && BSON_ITER_HOLDS_UTF8 (&iter)) { cur_name = bson_iter_utf8(&iter, NULL); if (!strcmp(cur_name, ns)) { ret = true; GOTO(cleanup); } } } cleanup: mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); mongoc_read_prefs_destroy (read_prefs); RETURN(ret); }
mongoc_read_prefs_t * mongoc_read_prefs_copy (const mongoc_read_prefs_t *read_prefs) { mongoc_read_prefs_t *ret = NULL; if (read_prefs) { ret = mongoc_read_prefs_new(read_prefs->mode); bson_copy_to(&read_prefs->tags, &ret->tags); } return ret; }
mongoc_cursor_t * mongoc_database_find_collections (mongoc_database_t *database, const bson_t *filter, bson_error_t *error) { mongoc_cursor_t *cursor; mongoc_read_prefs_t *read_prefs; bson_t cmd = BSON_INITIALIZER; bson_t child; bson_error_t lerror; BSON_ASSERT (database); BSON_APPEND_INT32 (&cmd, "listCollections", 1); if (filter) { BSON_APPEND_DOCUMENT (&cmd, "filter", filter); BSON_APPEND_DOCUMENT_BEGIN (&cmd, "cursor", &child); bson_append_document_end (&cmd, &child); } read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); cursor = _mongoc_cursor_new (database->client, database->name, MONGOC_QUERY_SLAVE_OK, 0, 0, 0, true, NULL, NULL, NULL, NULL); _mongoc_cursor_cursorid_init (cursor, &cmd); if (_mongoc_cursor_cursorid_prime (cursor)) { /* intentionally empty */ } else { if (mongoc_cursor_error (cursor, &lerror)) { if (lerror.code == MONGOC_ERROR_QUERY_COMMAND_NOT_FOUND) { /* We are talking to a server that doesn' support listCollections. */ /* clear out the error. */ memset (&lerror, 0, sizeof lerror); /* try again with using system.namespaces */ mongoc_cursor_destroy (cursor); cursor = _mongoc_database_find_collections_legacy ( database, filter, error); } else if (error) { memcpy (error, &lerror, sizeof *error); } } } bson_destroy (&cmd); mongoc_read_prefs_destroy (read_prefs); return cursor; }
/* test that we add readConcern only inside $query, not outside it too */ static void test_mongos_read_concern (void) { mock_server_t *server; mongoc_client_t *client; mongoc_collection_t *collection; mongoc_read_prefs_t *prefs; mongoc_cursor_t *cursor; const bson_t *doc; future_t *future; request_t *request; server = mock_mongos_new (WIRE_VERSION_READ_CONCERN); mock_server_run (server); client = mongoc_client_new_from_uri (mock_server_get_uri (server)); collection = mongoc_client_get_collection (client, "test", "test"); prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY); cursor = mongoc_collection_find_with_opts ( collection, tmp_bson ("{'a': 1}"), tmp_bson ("{'readConcern': {'level': 'foo'}}"), prefs); future = future_cursor_next (cursor, &doc); request = mock_server_receives_command ( server, "test", MONGOC_QUERY_SLAVE_OK, "{" " '$query': {" " 'find': 'test', 'filter': {}, 'readConcern': {'level': 'foo'}" " }," " '$readPreference': {" " 'mode': 'secondary'" " }," " 'readConcern': {'$exists': false}" "}"); mock_server_replies_to_find ( request, MONGOC_QUERY_SLAVE_OK, 0, 1, "db.collection", "{}", true); /* mongoc_cursor_next returned true */ BSON_ASSERT (future_get_bool (future)); request_destroy (request); future_destroy (future); mongoc_cursor_destroy (cursor); mongoc_read_prefs_destroy (prefs); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mock_server_destroy (server); }
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_client_t * mongoc_client_new (const char *uri_string) { const mongoc_write_concern_t *write_concern; mongoc_client_t *client; mongoc_uri_t *uri; const bson_t *options; bson_iter_t iter; bool has_ssl = false; if (!uri_string) { uri_string = "mongodb://127.0.0.1/"; } if (!(uri = mongoc_uri_new(uri_string))) { return NULL; } options = mongoc_uri_get_options (uri); if (bson_iter_init_find (&iter, options, "ssl") && BSON_ITER_HOLDS_BOOL (&iter) && bson_iter_bool (&iter)) { has_ssl = true; } client = bson_malloc0(sizeof *client); client->uri = uri; client->request_id = rand (); client->initiator = mongoc_client_default_stream_initiator; client->initiator_data = client; write_concern = mongoc_uri_get_write_concern (uri); client->write_concern = mongoc_write_concern_copy (write_concern); client->read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); _mongoc_cluster_init (&client->cluster, client->uri, client); #ifdef MONGOC_ENABLE_SSL if (has_ssl) { mongoc_client_set_ssl_opts (client, mongoc_ssl_opt_get_default ()); } #endif mongoc_counter_clients_active_inc (); return client; }
void mongoc_client_set_read_prefs (mongoc_client_t *client, const mongoc_read_prefs_t *read_prefs) { bson_return_if_fail (client); if (read_prefs != client->read_prefs) { if (client->read_prefs) { mongoc_read_prefs_destroy(client->read_prefs); } client->read_prefs = read_prefs ? mongoc_read_prefs_copy(read_prefs) : mongoc_read_prefs_new(MONGOC_READ_PRIMARY); } }
void mongoc_client_set_read_prefs (mongoc_client_t *client, const mongoc_read_prefs_t *read_prefs) { BSON_ASSERT (client); if (read_prefs != client->read_prefs) { if (client->read_prefs) { mongoc_read_prefs_destroy(client->read_prefs); } client->read_prefs = read_prefs ? mongoc_read_prefs_copy(read_prefs) : mongoc_read_prefs_new(MONGOC_READ_PRIMARY); } }
bson_t * mongoc_database_get_collection_info (mongoc_database_t *database, const bson_t *filter, bson_error_t *error) { mongoc_read_prefs_t *read_prefs; bson_t *reply = bson_new(); bson_t cmd = BSON_INITIALIZER; bool cmd_success; BSON_ASSERT (database); BSON_APPEND_INT32 (&cmd, "listCollections", 1); if (filter) { BSON_APPEND_DOCUMENT (&cmd, "filter", filter); } read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); cmd_success = mongoc_database_command_simple (database, &cmd, read_prefs, reply, error); if (cmd_success) { /* intentionally empty */ } else if (error->code == MONGOC_ERROR_QUERY_COMMAND_NOT_FOUND) { bson_destroy (reply); /* We are talking to a server that doesn' support listCollections. */ /* clear out the error. */ error->code = 0; error->domain = 0; /* try again with using system.namespaces */ reply = _mongoc_database_get_collection_info_legacy (database, filter, error); } else { /* network error */ bson_destroy (reply); reply = NULL; } bson_destroy (&cmd); mongoc_read_prefs_destroy (read_prefs); return reply; }
/* {{{ proto MongoDB\Driver\ReadPreference ReadPreference::__construct(integer $readPreference[, array $tagSets = array()]) Constructs a new ReadPreference */ PHP_METHOD(ReadPreference, __construct) { php_phongo_readpreference_t *intern; zend_error_handling error_handling; long readPreference; zval *tagSets = NULL; (void)return_value_ptr; (void)return_value; (void)return_value_used; zend_replace_error_handling(EH_THROW, phongo_exception_from_phongo_domain(PHONGO_ERROR_INVALID_ARGUMENT), &error_handling TSRMLS_CC); intern = (php_phongo_readpreference_t *)zend_object_store_get_object(getThis() TSRMLS_CC); if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|a!", &readPreference, &tagSets) == FAILURE) { zend_restore_error_handling(&error_handling TSRMLS_CC); return; } zend_restore_error_handling(&error_handling TSRMLS_CC); switch(readPreference) { case MONGOC_READ_PRIMARY: case MONGOC_READ_SECONDARY: case MONGOC_READ_PRIMARY_PREFERRED: case MONGOC_READ_SECONDARY_PREFERRED: case MONGOC_READ_NEAREST: intern->read_preference = mongoc_read_prefs_new(readPreference); if (tagSets) { bson_t *tags = bson_new(); zval_to_bson(tagSets, PHONGO_BSON_NONE, (bson_t *)tags, NULL TSRMLS_CC); mongoc_read_prefs_set_tags(intern->read_preference, tags); bson_destroy(tags); if (!mongoc_read_prefs_is_valid(intern->read_preference)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "%s", "Invalid tagSet"); return; } } break; default: phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "%s", "Invalid ReadPreference"); return; } }
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_mongoc_client_read_prefs (void) { mongoc_collection_t *collection; mongoc_read_prefs_t *read_prefs; mongoc_cursor_t *cursor; mongoc_client_t *client; mock_server_t *server; uint16_t port; const bson_t *doc; bson_error_t error; bool success = false; bson_t b = BSON_INITIALIZER; bson_t q = BSON_INITIALIZER; char *uristr; port = 20000 + (rand () % 1000); server = mock_server_new ("127.0.0.1", port, read_prefs_handler, &success); mock_server_run_in_thread (server); usleep (5000); uristr = bson_strdup_printf ("mongodb://127.0.0.1:%hu/", port); client = mongoc_client_new (uristr); if (!_mongoc_client_warm_up (client, &error)) { assert (false); } collection = mongoc_client_get_collection (client, "test", "test"); bson_append_utf8 (&b, "dc", 2, "ny", 2); read_prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY_PREFERRED); mongoc_read_prefs_add_tag (read_prefs, &b); mongoc_read_prefs_add_tag (read_prefs, NULL); mongoc_collection_set_read_prefs (collection, read_prefs); cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 1, 0, &q, NULL, read_prefs); mongoc_cursor_next (cursor, &doc); usleep (50000); assert (success); mongoc_read_prefs_destroy (read_prefs); mongoc_cursor_destroy (cursor); mongoc_collection_destroy (collection); mongoc_client_destroy (client); mock_server_quit (server, 0); bson_destroy (&b); bson_free (uristr); }
/* Uses old way of querying system.namespaces. */ mongoc_cursor_t * _mongoc_database_find_collections_legacy (mongoc_database_t *database, const bson_t *filter, bson_error_t *error) { mongoc_collection_t *col; mongoc_cursor_t *cursor = NULL; mongoc_read_prefs_t *read_prefs; uint32_t dbname_len; bson_t legacy_filter; bson_iter_t iter; const char *col_filter; bson_t q = BSON_INITIALIZER; mongoc_database_find_collections_legacy_ctx_t *ctx; BSON_ASSERT (database); col = mongoc_client_get_collection (database->client, database->name, "system.namespaces"); BSON_ASSERT (col); dbname_len = (uint32_t)strlen (database->name); ctx = bson_malloc (sizeof (*ctx)); ctx->dbname = database->name; ctx->dbname_len = dbname_len; /* Filtering on name needs to be handled differently for old servers. */ if (filter && bson_iter_init_find (&iter, filter, "name")) { bson_string_t *buf; /* on legacy servers, this must be a string (i.e. not a regex) */ if (!BSON_ITER_HOLDS_UTF8 (&iter)) { bson_set_error (error, MONGOC_ERROR_NAMESPACE, MONGOC_ERROR_NAMESPACE_INVALID_FILTER_TYPE, "On legacy servers, a filter on name can only be a string."); goto cleanup_filter; } BSON_ASSERT (BSON_ITER_HOLDS_UTF8 (&iter)); col_filter = bson_iter_utf8 (&iter, NULL); bson_init (&legacy_filter); bson_copy_to_excluding_noinit (filter, &legacy_filter, "name", NULL); /* We must db-qualify filters on name. */ buf = bson_string_new (database->name); bson_string_append_c (buf, '.'); bson_string_append (buf, col_filter); BSON_APPEND_UTF8 (&legacy_filter, "name", buf->str); bson_string_free (buf, true); filter = &legacy_filter; } read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); cursor = mongoc_collection_find (col, MONGOC_QUERY_NONE, 0, 0, 0, filter ? filter : &q, NULL, read_prefs); _mongoc_cursor_transform_init ( cursor, _mongoc_database_find_collections_legacy_filter, _mongoc_database_find_collections_legacy_mutate, &bson_free, ctx); mongoc_read_prefs_destroy (read_prefs); cleanup_filter: mongoc_collection_destroy (col); return cursor; }
void HHVM_METHOD(MongoDBDriverReadPreference, _setReadPreference, int readPreference) { MongoDBDriverReadPreferenceData* data = Native::data<MongoDBDriverReadPreferenceData>(this_); data->m_read_preference = mongoc_read_prefs_new((mongoc_read_mode_t) readPreference); }
static void test1 (void) { mongoc_server_description_t *description; mongoc_collection_t *collection; mongoc_read_prefs_t *read_prefs; mongoc_cursor_t *cursor; mongoc_client_t *client; mongoc_client_pool_t *pool = NULL; const bson_t *doc; bson_error_t error; bool r; ha_node_t *replica; bson_t q; int i; bson_init(&q); if (use_pool) { pool = ha_replica_set_create_client_pool(replica_set); client = mongoc_client_pool_pop (pool); } else { client = ha_replica_set_create_client(replica_set); } collection = mongoc_client_get_collection(client, "test1", "test1"); MONGOC_DEBUG("Inserting test documents."); insert_test_docs(collection); MONGOC_INFO("Test documents inserted."); read_prefs = mongoc_read_prefs_new(MONGOC_READ_SECONDARY); MONGOC_DEBUG("Sending query to a SECONDARY."); cursor = mongoc_collection_find(collection, MONGOC_QUERY_NONE, 0, 0, 100, &q, NULL, read_prefs); BSON_ASSERT(cursor); BSON_ASSERT(!cursor->server_id); /* * Send OP_QUERY to server and get first document back. */ MONGOC_INFO("Sending OP_QUERY."); r = mongoc_cursor_next(cursor, &doc); BSON_ASSERT(r); BSON_ASSERT(cursor->server_id); BSON_ASSERT(cursor->sent); BSON_ASSERT(!cursor->done); BSON_ASSERT(cursor->rpc.reply.n_returned == 100); BSON_ASSERT(!cursor->end_of_event); /* * Make sure we queried a secondary. */ description = mongoc_topology_server_by_id(client->topology, cursor->server_id, &error); ASSERT_OR_PRINT (description, error); BSON_ASSERT (description->type != MONGOC_SERVER_RS_PRIMARY); mongoc_server_description_destroy(description); /* * Exhaust the items in our first OP_REPLY. */ MONGOC_DEBUG("Exhausting OP_REPLY."); for (i = 0; i < 98; i++) { r = mongoc_cursor_next(cursor, &doc); BSON_ASSERT(r); BSON_ASSERT(cursor->server_id); BSON_ASSERT(!cursor->done); BSON_ASSERT(!cursor->end_of_event); } /* * Finish off the last item in this OP_REPLY. */ MONGOC_INFO("Fetcing last doc from OP_REPLY."); r = mongoc_cursor_next(cursor, &doc); BSON_ASSERT(r); BSON_ASSERT(cursor->server_id); BSON_ASSERT(cursor->sent); BSON_ASSERT(!cursor->done); BSON_ASSERT(!cursor->end_of_event); /* * Determine which node we queried by using the server_id to * get the cluster information. */ BSON_ASSERT(cursor->server_id); replica = get_replica(client, cursor->server_id); /* * Kill the node we are communicating with. */ MONGOC_INFO("Killing replicaSet node to synthesize failure."); ha_node_kill(replica); /* * Try to fetch the next result set, expect failure. */ MONGOC_DEBUG("Checking for expected failure."); r = mongoc_cursor_next(cursor, &doc); BSON_ASSERT(!r); r = mongoc_cursor_error(cursor, &error); BSON_ASSERT(r); MONGOC_WARNING("%s", error.message); mongoc_cursor_destroy(cursor); mongoc_read_prefs_destroy(read_prefs); mongoc_collection_destroy(collection); if (use_pool) { mongoc_client_pool_push (pool, client); mongoc_client_pool_destroy (pool); } else { mongoc_client_destroy(client); } bson_destroy(&q); ha_node_restart(replica); }
static void test2 (void) { mongoc_read_prefs_t *read_prefs; mongoc_collection_t *collection; mongoc_cursor_t *cursor; mongoc_client_t *client; mongoc_client_pool_t *pool = NULL; const bson_t *doc; bson_error_t error; bool r; bson_t q; bson_init(&q); /* * Start by killing 2 of the replica set nodes. */ ha_node_kill(r1); ha_node_kill(r2); if (use_pool) { pool = ha_replica_set_create_client_pool(replica_set); client = mongoc_client_pool_pop (pool); } else { client = ha_replica_set_create_client(replica_set); } collection = mongoc_client_get_collection(client, "test2", "test2"); /* * Perform a query and ensure it fails with no nodes available. */ read_prefs = mongoc_read_prefs_new(MONGOC_READ_SECONDARY_PREFERRED); cursor = mongoc_collection_find(collection, MONGOC_QUERY_NONE, 0, 100, 0, &q, NULL, read_prefs); /* * Try to submit OP_QUERY. Since it is SECONDARY PREFERRED, it should * succeed if there is any node up (which r3 is up). */ r = mongoc_cursor_next(cursor, &doc); BSON_ASSERT(!r); /* No docs */ /* No error, slaveOk was set */ ASSERT_OR_PRINT (!mongoc_cursor_error(cursor, &error), error); mongoc_read_prefs_destroy(read_prefs); mongoc_cursor_destroy(cursor); mongoc_collection_destroy(collection); if (use_pool) { mongoc_client_pool_push (pool, client); mongoc_client_pool_destroy (pool); } else { mongoc_client_destroy(client); } bson_destroy(&q); ha_node_restart(r1); ha_node_restart(r2); }
mongoc_cursor_t * _mongoc_cursor_new (mongoc_client_t *client, const char *db_and_collection, mongoc_query_flags_t flags, uint32_t skip, uint32_t limit, uint32_t batch_size, bool is_command, const bson_t *query, const bson_t *fields, const mongoc_read_prefs_t *read_prefs) { mongoc_read_prefs_t *local_read_prefs = NULL; mongoc_read_mode_t mode; mongoc_cursor_t *cursor; const bson_t *tags; bson_iter_t iter; const char *key; const char *mode_str; bson_t child; bool found = false; int i; ENTRY; BSON_ASSERT (client); BSON_ASSERT (db_and_collection); BSON_ASSERT (query); if (!read_prefs) { read_prefs = client->read_prefs; } cursor = bson_malloc0 (sizeof *cursor); /* * CDRIVER-244: * * If this is a command, we need to verify we can send it to the location * specified by the read preferences. Otherwise, log a warning that we * are rerouting to the primary instance. */ if (is_command && read_prefs && (mongoc_read_prefs_get_mode (read_prefs) != MONGOC_READ_PRIMARY) && bson_iter_init (&iter, query) && bson_iter_next (&iter) && (key = bson_iter_key (&iter))) { for (i = 0; gSecondaryOkCommands [i]; i++) { if (0 == strcasecmp (key, gSecondaryOkCommands [i])) { found = true; break; } } if (!found) { cursor->redir_primary = true; local_read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); read_prefs = local_read_prefs; MONGOC_INFO ("Database command \"%s\" rerouted to primary node", key); } } /* * Cursors execute their query lazily. This sadly means that we must copy * some extra data around between the bson_t structures. This should be * small in most cases, so it reduces to a pure memcpy. The benefit to this * design is simplified error handling by API consumers. */ cursor->client = client; bson_strncpy (cursor->ns, db_and_collection, sizeof cursor->ns); cursor->nslen = (uint32_t)strlen(cursor->ns); cursor->flags = flags; cursor->skip = skip; cursor->limit = limit; cursor->batch_size = batch_size; cursor->is_command = is_command; #define MARK_FAILED(c) \ do { \ (c)->failed = true; \ (c)->done = true; \ (c)->end_of_event = true; \ (c)->sent = true; \ } while (0) /* we can't have exhaust queries with limits */ if ((flags & MONGOC_QUERY_EXHAUST) && limit) { bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "Cannot specify MONGOC_QUERY_EXHAUST and set a limit."); MARK_FAILED (cursor); GOTO (finish); } /* we can't have exhaust queries with sharded clusters */ if ((flags & MONGOC_QUERY_EXHAUST) && (client->cluster.mode == MONGOC_CLUSTER_SHARDED_CLUSTER)) { bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "Cannot specify MONGOC_QUERY_EXHAUST with sharded cluster."); MARK_FAILED (cursor); GOTO (finish); } /* * Check types of various optional parameters. */ if (!is_command) { if (bson_iter_init_find (&iter, query, "$explain") && !(BSON_ITER_HOLDS_BOOL (&iter) || BSON_ITER_HOLDS_INT32 (&iter))) { bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "$explain must be a boolean."); MARK_FAILED (cursor); GOTO (finish); } if (bson_iter_init_find (&iter, query, "$snapshot") && !BSON_ITER_HOLDS_BOOL (&iter) && !BSON_ITER_HOLDS_INT32 (&iter)) { bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "$snapshot must be a boolean."); MARK_FAILED (cursor); GOTO (finish); } } if (!cursor->is_command && !bson_has_field (query, "$query")) { bson_init (&cursor->query); bson_append_document (&cursor->query, "$query", 6, query); } else { bson_copy_to (query, &cursor->query); } if (read_prefs) { cursor->read_prefs = mongoc_read_prefs_copy (read_prefs); mode = mongoc_read_prefs_get_mode (read_prefs); tags = mongoc_read_prefs_get_tags (read_prefs); if (mode != MONGOC_READ_PRIMARY) { flags |= MONGOC_QUERY_SLAVE_OK; if ((mode != MONGOC_READ_SECONDARY_PREFERRED) || tags) { bson_append_document_begin (&cursor->query, "$readPreference", 15, &child); mode_str = _mongoc_cursor_get_read_mode_string (mode); bson_append_utf8 (&child, "mode", 4, mode_str, -1); if (tags) { bson_append_array (&child, "tags", 4, tags); } bson_append_document_end (&cursor->query, &child); } } } if (fields) { bson_copy_to(fields, &cursor->fields); } else { bson_init(&cursor->fields); } _mongoc_buffer_init(&cursor->buffer, NULL, 0, NULL); finish: mongoc_counter_cursors_active_inc(); if (local_read_prefs) { mongoc_read_prefs_destroy (local_read_prefs); } RETURN (cursor); }