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);
}
示例#10
0
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);
}
示例#12
0
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;
}
示例#16
0
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);
}
示例#18
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_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;
}
示例#20
0
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);
   }
}
示例#21
0
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;
	}
}
示例#24
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_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);
}
示例#28
0
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);
}
示例#29
0
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);
}
示例#30
0
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);
}