void
mongoc_bulk_operation_update_one (mongoc_bulk_operation_t *bulk,
                                  const bson_t            *selector,
                                  const bson_t            *document,
                                  bool                     upsert)
{
   mongoc_write_command_t command = { 0 };
   bson_iter_t iter;

   bson_return_if_fail (bulk);
   bson_return_if_fail (selector);
   bson_return_if_fail (document);

   ENTRY;

   if (bson_iter_init (&iter, document)) {
      while (bson_iter_next (&iter)) {
         if (!strchr (bson_iter_key (&iter), '$')) {
            MONGOC_WARNING ("%s(): update_one only works with $ operators.",
                            __FUNCTION__);
            EXIT;
         }
      }
   }

   _mongoc_write_command_init_update (&command, selector, document, upsert,
                                      false, bulk->ordered);
   _mongoc_array_append_val (&bulk->commands, command);
   EXIT;
}
void
mongoc_bulk_operation_insert (mongoc_bulk_operation_t *bulk,
                              const bson_t            *document)
{
   mongoc_write_command_t command = { 0 };
   mongoc_write_command_t *last;

   ENTRY;

   bson_return_if_fail (bulk);
   bson_return_if_fail (document);

   if (bulk->commands.len) {
      last = &_mongoc_array_index (&bulk->commands,
                                   mongoc_write_command_t,
                                   bulk->commands.len - 1);
      if (last->type == MONGOC_WRITE_COMMAND_INSERT) {
         _mongoc_write_command_insert_append (last, &document, 1);
         EXIT;
      }
   }

   _mongoc_write_command_init_insert (&command, &document, 1, bulk->ordered,
      !_mongoc_write_concern_needs_gle (bulk->write_concern));

   _mongoc_array_append_val (&bulk->commands, command);

   EXIT;
}
void
mongoc_bulk_operation_replace_one (mongoc_bulk_operation_t *bulk,
                                   const bson_t            *selector,
                                   const bson_t            *document,
                                   bool                     upsert)
{
   mongoc_write_command_t command = { 0 };
   size_t err_off;

   bson_return_if_fail (bulk);
   bson_return_if_fail (selector);
   bson_return_if_fail (document);

   ENTRY;

   if (!bson_validate (document,
                       (BSON_VALIDATE_DOT_KEYS | BSON_VALIDATE_DOLLAR_KEYS),
                       &err_off)) {
      MONGOC_WARNING ("%s(): replacement document may not contain "
                      "$ or . in keys. Ingoring document.",
                      __FUNCTION__);
      EXIT;
   }

   _mongoc_write_command_init_update (&command, selector, document, upsert,
                                      false, bulk->ordered);
   _mongoc_array_append_val (&bulk->commands, command);

   EXIT;
}
void
mongoc_bulk_operation_insert (mongoc_bulk_operation_t *bulk,
                              const bson_t            *document)
{
   mongoc_write_command_t command = { 0 };
   mongoc_write_command_t *last;

   ENTRY;

   BSON_ASSERT (bulk);
   BSON_ASSERT (document);

   if (bulk->commands.len) {
      last = &_mongoc_array_index (&bulk->commands,
                                   mongoc_write_command_t,
                                   bulk->commands.len - 1);

      if (last->type == MONGOC_WRITE_COMMAND_INSERT) {
         _mongoc_write_command_insert_append (last, document);
         EXIT;
      }
   }

   _mongoc_write_command_init_insert (
      &command, document, bulk->flags, bulk->operation_id,
      !mongoc_write_concern_is_acknowledged (bulk->write_concern));

   _mongoc_array_append_val (&bulk->commands, command);

   EXIT;
}
void
mongoc_bulk_operation_remove_one (mongoc_bulk_operation_t *bulk,     /* IN */
                                  const bson_t            *selector) /* IN */
{
   mongoc_write_command_t command = { 0 };
   mongoc_write_command_t *last;

   ENTRY;

   BSON_ASSERT (bulk);
   BSON_ASSERT (selector);

   if (bulk->commands.len) {
      last = &_mongoc_array_index (&bulk->commands,
                                   mongoc_write_command_t,
                                   bulk->commands.len - 1);
      if ((last->type == MONGOC_WRITE_COMMAND_DELETE) &&
          !last->u.delete_.multi) {
         _mongoc_write_command_delete_append (last, selector);
         EXIT;
      }
   }

   _mongoc_write_command_init_delete (&command, selector, false, bulk->flags,
                                      bulk->operation_id);

   _mongoc_array_append_val (&bulk->commands, command);

   EXIT;
}
Beispiel #6
0
bool
mongoc_bulk_operation_insert_with_opts (mongoc_bulk_operation_t *bulk,
                                        const bson_t *document,
                                        const bson_t *opts,
                                        bson_error_t *error)
{
   mongoc_bulk_insert_opts_t insert_opts;
   mongoc_write_command_t command = {0};
   mongoc_write_command_t *last;
   bool ret = false;

   ENTRY;

   BSON_ASSERT (bulk);
   BSON_ASSERT (document);

   BULK_RETURN_IF_PRIOR_ERROR;

   if (!_mongoc_bulk_insert_opts_parse (
          bulk->client, opts, &insert_opts, error)) {
      GOTO (done);
   }

   if (!_mongoc_validate_new_document (document, insert_opts.validate, error)) {
      GOTO (done);
   }

   if (bulk->commands.len) {
      last = &_mongoc_array_index (
         &bulk->commands, mongoc_write_command_t, bulk->commands.len - 1);

      if (last->type == MONGOC_WRITE_COMMAND_INSERT) {
         _mongoc_write_command_insert_append (last, document);
         ret = true;
         GOTO (done);
      }
   }

   _mongoc_write_command_init_insert (
      &command,
      document,
      opts,
      bulk->flags,
      bulk->operation_id,
      !mongoc_write_concern_is_acknowledged (bulk->write_concern));

   _mongoc_array_append_val (&bulk->commands, command);

   ret = true;

done:
   _mongoc_bulk_insert_opts_cleanup (&insert_opts);
   RETURN (ret);
}
void
mongoc_bulk_operation_remove_one (mongoc_bulk_operation_t *bulk,     /* IN */
                                  const bson_t            *selector) /* IN */
{
   mongoc_write_command_t command = { 0 };

   bson_return_if_fail (bulk);
   bson_return_if_fail (selector);

   ENTRY;

   _mongoc_write_command_init_delete (&command, selector, false, bulk->ordered);
   _mongoc_array_append_val (&bulk->commands, command);

   EXIT;
}
Beispiel #8
0
static void
_mongoc_bulk_operation_update_append (
   mongoc_bulk_operation_t *bulk,
   const bson_t *selector,
   const bson_t *document,
   const mongoc_bulk_update_opts_t *update_opts,
   const bson_t *extra_opts)
{
   mongoc_write_command_t command = {0};
   mongoc_write_command_t *last;
   bson_t opts;
   bool has_collation;

   bson_init (&opts);
   bson_append_bool (&opts, "upsert", 6, update_opts->upsert);
   bson_append_bool (&opts, "multi", 5, update_opts->multi);

   has_collation = !bson_empty (&update_opts->collation);
   if (has_collation) {
      bson_append_document (&opts, "collation", 9, &update_opts->collation);
   }

   if (extra_opts) {
      bson_concat (&opts, extra_opts);
   }

   if (bulk->commands.len) {
      last = &_mongoc_array_index (
         &bulk->commands, mongoc_write_command_t, bulk->commands.len - 1);
      if (last->type == MONGOC_WRITE_COMMAND_UPDATE) {
         last->flags.has_collation |= has_collation;
         last->flags.has_multi_write |= update_opts->multi;
         _mongoc_write_command_update_append (last, selector, document, &opts);
         bson_destroy (&opts);
         return;
      }
   }

   _mongoc_write_command_init_update (
      &command, selector, document, &opts, bulk->flags, bulk->operation_id);

   command.flags.has_collation = has_collation;
   command.flags.has_multi_write = update_opts->multi;

   _mongoc_array_append_val (&bulk->commands, command);
   bson_destroy (&opts);
}
Beispiel #9
0
int
mock_server_autoresponds (mock_server_t *server,
                          autoresponder_t responder,
                          void *data,
                          destructor_t destructor)
{
   autoresponder_handle_t handle = { responder, data, destructor };
   int id;

   mongoc_mutex_lock (&server->mutex);
   id = handle.id = server->last_autoresponder_id++;
   /* TODO: peek and see if a matching request is enqueued */
   _mongoc_array_append_val (&server->autoresponders, handle);
   mongoc_mutex_unlock (&server->mutex);

   return id;
}
void
mongoc_bulk_operation_update (mongoc_bulk_operation_t *bulk,
                              const bson_t            *selector,
                              const bson_t            *document,
                              bool                     upsert)
{
   bool multi = true;
   mongoc_write_command_t command = { 0 };
   bson_iter_t iter;
   mongoc_write_command_t *last;

   BSON_ASSERT (bulk);
   BSON_ASSERT (selector);
   BSON_ASSERT (document);

   ENTRY;

   if (bson_iter_init (&iter, document)) {
      while (bson_iter_next (&iter)) {
         if (!strchr (bson_iter_key (&iter), '$')) {
            MONGOC_WARNING ("%s(): update only works with $ operators.",
                            BSON_FUNC);
            EXIT;
         }
      }
   }

   if (bulk->commands.len) {
      last = &_mongoc_array_index (&bulk->commands,
                                   mongoc_write_command_t,
                                   bulk->commands.len - 1);
      if (last->type == MONGOC_WRITE_COMMAND_UPDATE) {
         _mongoc_write_command_update_append (last, selector, document, upsert, multi);
         EXIT;
      }
   }

   _mongoc_write_command_init_update (&command, selector, document, upsert,
                                      multi, bulk->flags, bulk->operation_id);
   _mongoc_array_append_val (&bulk->commands, command);
   EXIT;
}
void
mongoc_bulk_operation_replace_one (mongoc_bulk_operation_t *bulk,
                                   const bson_t            *selector,
                                   const bson_t            *document,
                                   bool                     upsert)
{
   mongoc_write_command_t command = { 0 };
   size_t err_off;
   mongoc_write_command_t *last;
   int flags = BSON_VALIDATE_DOT_KEYS|BSON_VALIDATE_DOLLAR_KEYS;

   BSON_ASSERT (bulk);
   BSON_ASSERT (selector);
   BSON_ASSERT (document);

   ENTRY;

   if (!bson_validate (document, (bson_validate_flags_t)flags, &err_off)) {
      MONGOC_WARNING ("%s(): replacement document may not contain "
                      "$ or . in keys. Ignoring document.",
                      BSON_FUNC);
      EXIT;
   }

   if (bulk->commands.len) {
      last = &_mongoc_array_index (&bulk->commands,
                                   mongoc_write_command_t,
                                   bulk->commands.len - 1);
      if (last->type == MONGOC_WRITE_COMMAND_UPDATE) {
         _mongoc_write_command_update_append (last, selector, document, upsert, false);
         EXIT;
      }
   }

   _mongoc_write_command_init_update (&command, selector, document, upsert,
                                      false, bulk->flags, bulk->operation_id);
   _mongoc_array_append_val (&bulk->commands, command);

   EXIT;
}
Beispiel #12
0
static void *
main_thread (void *data)
{
   mock_server_t *server = (mock_server_t *)data;
   mongoc_socket_t *client_sock;
   bool stopped;
   uint16_t port;
   mongoc_stream_t *client_stream;
   worker_closure_t *closure;
   mongoc_thread_t thread;
   mongoc_array_t worker_threads;
   size_t i;

   mongoc_mutex_lock (&server->mutex);
   server->running = true;
   mongoc_cond_signal (&server->cond);
   mongoc_mutex_unlock (&server->mutex);

   for (; ;) {
      client_sock = mongoc_socket_accept_ex (
            server->sock,
            bson_get_monotonic_time () + TIMEOUT,
            &port);

      mongoc_mutex_lock (&server->mutex);
      stopped = server->stopped;
      mongoc_mutex_unlock (&server->mutex);

      if (stopped) {
         break;
      }

      if (client_sock) {
         if (mock_server_get_verbose (server)) {
            printf ("%5.2f  %hu -> server port %hu (connected)\n",
                    mock_server_get_uptime_sec (server),
                    port, server->port);
            fflush (stdout);
         }

         client_stream = mongoc_stream_socket_new (client_sock);

#ifdef MONGOC_ENABLE_SSL
         mongoc_mutex_lock (&server->mutex);
         if (server->ssl) {
            server->ssl_opts.weak_cert_validation = 1;
            client_stream = mongoc_stream_tls_new (client_stream,
                                                   &server->ssl_opts, 0);
            if (!client_stream) {
               mongoc_mutex_unlock (&server->mutex);
               perror ("Failed to attach tls stream");
               break;
            }
         }
         mongoc_mutex_unlock (&server->mutex);
#endif
         closure = (worker_closure_t *)bson_malloc (sizeof *closure);
         closure->server = server;
         closure->client_stream = client_stream;
         closure->port = port;

         mongoc_thread_create (&thread, worker_thread, closure);

         mongoc_mutex_lock (&server->mutex);
         _mongoc_array_append_val (&server->worker_threads, thread);
         mongoc_mutex_unlock (&server->mutex);
      }
   }

   /* copy list of worker threads and join them all */
   _mongoc_array_init (&worker_threads, sizeof (mongoc_thread_t));
   mongoc_mutex_lock (&server->mutex);
   _mongoc_array_copy (&worker_threads, &server->worker_threads);
   mongoc_mutex_unlock (&server->mutex);

   for (i = 0; i < worker_threads.len; i++) {
      mongoc_thread_join (
         _mongoc_array_index (&worker_threads, mongoc_thread_t, i));
   }

   _mongoc_array_destroy (&worker_threads);

   mongoc_mutex_lock (&server->mutex);
   server->running = false;
   mongoc_mutex_unlock (&server->mutex);

   return NULL;
}
Beispiel #13
0
bool
_mongoc_bulk_operation_remove_with_opts (
   mongoc_bulk_operation_t *bulk,
   const bson_t *selector,
   const mongoc_bulk_remove_opts_t *remove_opts,
   int32_t limit,
   bson_error_t *error) /* OUT */
{
   mongoc_write_command_t command = {0};
   mongoc_write_command_t *last;
   bson_t opts;
   bool has_collation;
   bool ret = false;

   ENTRY;

   BSON_ASSERT (bulk);
   BSON_ASSERT (selector);

   bson_init (&opts);

   /* allow "limit" in opts, but it must be the correct limit */
   if (remove_opts->limit != limit) {
      bson_set_error (error,
                      MONGOC_ERROR_COMMAND,
                      MONGOC_ERROR_COMMAND_INVALID_ARG,
                      "Invalid \"limit\" in opts: %" PRId32 "."
                      " The value must be %" PRId32 ", or omitted.",
                      remove_opts->limit,
                      limit);
      GOTO (done);
   }

   bson_append_int32 (&opts, "limit", 5, limit);
   has_collation = !bson_empty (&remove_opts->collation);
   if (has_collation) {
      bson_append_document (&opts, "collation", 9, &remove_opts->collation);
   }

   if (bulk->commands.len) {
      last = &_mongoc_array_index (
         &bulk->commands, mongoc_write_command_t, bulk->commands.len - 1);
      if (last->type == MONGOC_WRITE_COMMAND_DELETE) {
         last->flags.has_collation |= has_collation;
         last->flags.has_multi_write |= (remove_opts->limit == 0);
         _mongoc_write_command_delete_append (last, selector, &opts);
         ret = true;
         GOTO (done);
      }
   }

   _mongoc_write_command_init_delete (
      &command, selector, NULL, &opts, bulk->flags, bulk->operation_id);

   command.flags.has_collation = has_collation;
   command.flags.has_multi_write = (remove_opts->limit == 0);

   _mongoc_array_append_val (&bulk->commands, command);
   ret = true;

done:
   bson_destroy (&opts);
   RETURN (ret);
}
void
mongoc_topology_description_suitable_servers (
   mongoc_array_t                *set, /* OUT */
   mongoc_ss_optype_t             optype,
   mongoc_topology_description_t *topology,
   const mongoc_read_prefs_t     *read_pref,
   size_t                         local_threshold_ms)
{
   mongoc_suitable_data_t data;
   mongoc_server_description_t **candidates;
   mongoc_server_description_t *server;
   int64_t nearest = -1;
   int i;
   mongoc_read_mode_t read_mode = mongoc_read_prefs_get_mode(read_pref);

   candidates = (mongoc_server_description_t **)bson_malloc0(sizeof(*candidates) * topology->servers->items_len);

   data.read_mode = read_mode;
   data.topology_type = topology->type;
   data.primary = NULL;
   data.candidates = candidates;
   data.candidates_len = 0;
   data.has_secondary = false;

   /* Single server --
    * Either it is suitable or it isn't */
   if (topology->type == MONGOC_TOPOLOGY_SINGLE) {
      server = (mongoc_server_description_t *)mongoc_set_get_item (topology->servers, 0);
      if (_mongoc_topology_description_server_is_candidate (server->type, read_mode, topology->type)) {
         _mongoc_array_append_val (set, server);
      }
      goto DONE;
   }

   /* Replica sets --
    * Find suitable servers based on read mode */
   if (topology->type == MONGOC_TOPOLOGY_RS_NO_PRIMARY ||
       topology->type == MONGOC_TOPOLOGY_RS_WITH_PRIMARY) {

      if (optype == MONGOC_SS_READ) {

         mongoc_set_for_each(topology->servers, _mongoc_replica_set_read_suitable_cb, &data);

         /* if we have a primary, it's a candidate, for some read modes we are done */
         if (read_mode == MONGOC_READ_PRIMARY || read_mode == MONGOC_READ_PRIMARY_PREFERRED) {
            if (data.primary) {
               _mongoc_array_append_val (set, data.primary);
               goto DONE;
            }
         }

         if (! mongoc_server_description_filter_eligible (data.candidates, data.candidates_len, read_pref)) {
            if (read_mode == MONGOC_READ_NEAREST) {
               goto DONE;
            } else {
               data.has_secondary = false;
            }
         }

         if (data.has_secondary &&
             (read_mode == MONGOC_READ_SECONDARY || read_mode == MONGOC_READ_SECONDARY_PREFERRED)) {
            /* secondary or secondary preferred and we have one. */

            for (i = 0; i < data.candidates_len; i++) {
               if (candidates[i] && candidates[i]->type == MONGOC_SERVER_RS_PRIMARY) {
                  candidates[i] = NULL;
               }
            }
         } else if (read_mode == MONGOC_READ_SECONDARY_PREFERRED && data.primary) {
            /* secondary preferred, but only the one primary is a candidate */
            _mongoc_array_append_val (set, data.primary);
            goto DONE;
         }

      } else if (topology->type == MONGOC_TOPOLOGY_RS_WITH_PRIMARY) {
         /* includes optype == MONGOC_SS_WRITE as the exclusion of the above if */
         mongoc_set_for_each(topology->servers, _mongoc_topology_description_has_primary_cb,
                             &data.primary);
         if (data.primary) {
            _mongoc_array_append_val (set, data.primary);
            goto DONE;
         }
      }
   }

   /* Sharded clusters --
    * All candidates in the latency window are suitable */
   if (topology->type == MONGOC_TOPOLOGY_SHARDED) {
      mongoc_set_for_each (topology->servers, _mongoc_find_suitable_mongos_cb, &data);
   }

   /* Ways to get here:
    *   - secondary read
    *   - secondary preferred read
    *   - primary_preferred and no primary read
    *   - sharded anything
    * Find the nearest, then select within the window */

   for (i = 0; i < data.candidates_len; i++) {
      if (candidates[i] && (nearest == -1 || nearest > candidates[i]->round_trip_time)) {
         nearest = candidates[i]->round_trip_time;
      }
   }

   for (i = 0; i < data.candidates_len; i++) {
      if (candidates[i] && (candidates[i]->round_trip_time <= nearest + local_threshold_ms)) {
         _mongoc_array_append_val (set, candidates[i]);
      }
   }

DONE:

   bson_free (candidates);

   return;
}