예제 #1
0
Array HHVM_METHOD(MongoDBDriverReadPreference, __debugInfo)
{
	MongoDBDriverReadPreferenceData* data = Native::data<MongoDBDriverReadPreferenceData>(this_);
	Array retval = Array::Create();
	Variant v_tags;
	const bson_t *tags = mongoc_read_prefs_get_tags(data->m_read_preference);

	mongoc_read_mode_t mode = mongoc_read_prefs_get_mode(data->m_read_preference);

	switch (mode) {
		case MONGOC_READ_PRIMARY: retval.set(s_mode, "primary"); break;
		case MONGOC_READ_PRIMARY_PREFERRED: retval.set(s_mode, "primaryPreferred"); break;
		case MONGOC_READ_SECONDARY: retval.set(s_mode, "secondary"); break;
		case MONGOC_READ_SECONDARY_PREFERRED: retval.set(s_mode, "secondaryPreferred"); break;
		case MONGOC_READ_NEAREST: retval.set(s_mode, "nearest"); break;
		default: /* Do nothing */
			break;
	}

	if (!bson_empty(tags)) {
		hippo_bson_conversion_options_t options = HIPPO_TYPEMAP_INITIALIZER;
		BsonToVariantConverter convertor(bson_get_data(tags), tags->len, options);
		convertor.convert(&v_tags);
		retval.set(s_tags, v_tags.toArray());
	}

	if (mongoc_read_prefs_get_max_staleness_ms(data->m_read_preference) != 0) {
		retval.set(s_maxStalenessMS, mongoc_read_prefs_get_max_staleness_ms(data->m_read_preference));
	}

	return retval;
}
예제 #2
0
void HHVM_METHOD(MongoDBDriverReadPreference, _setReadPreferenceTags, const Array &tagSets)
{
	MongoDBDriverReadPreferenceData* data = Native::data<MongoDBDriverReadPreferenceData>(this_);
	bson_t *bson;

	/* Check validity */
	if (!hippo_mongo_driver_readpreference_are_valid(tagSets)) {
		throw MongoDriver::Utils::throwInvalidArgumentException("tagSets must be an array of zero or more documents");
	}

	/* Validate that readPreferenceTags are not used with PRIMARY readPreference */
	if (mongoc_read_prefs_get_mode(data->m_read_preference) == MONGOC_READ_PRIMARY) {
		throw MongoDriver::Utils::throwInvalidArgumentException("tagSets may not be used with primary mode");
	}

	/* Convert argument */
	VariantToBsonConverter converter(tagSets, HIPPO_BSON_NO_FLAGS);
	bson = bson_new();
	converter.convert(bson);

	/* Set and check errors */
	mongoc_read_prefs_set_tags(data->m_read_preference, bson);
	bson_destroy(bson);
	if (!mongoc_read_prefs_is_valid(data->m_read_preference)) {
		/* Throw exception */
		throw MongoDriver::Utils::throwInvalidArgumentException("Read preference is not valid");
	}
}
예제 #3
0
void HHVM_METHOD(MongoDBDriverReadPreference, _setMaxStalenessMS, int maxStalenessMS)
{
	MongoDBDriverReadPreferenceData* data = Native::data<MongoDBDriverReadPreferenceData>(this_);

	/* Validate that maxStalenessMS is not used with PRIMARY readPreference */
	if (mongoc_read_prefs_get_mode(data->m_read_preference) == MONGOC_READ_PRIMARY) {
		throw MongoDriver::Utils::throwInvalidArgumentException("maxStalenessMS may not be used with primary mode");
	}

	mongoc_read_prefs_set_max_staleness_ms(data->m_read_preference, maxStalenessMS);

	if (!mongoc_read_prefs_is_valid(data->m_read_preference)) {
		/* Throw exception */
		throw MongoDriver::Utils::throwInvalidArgumentException("Read preference is not valid");
	}
}
예제 #4
0
static void
_mongoc_uri_assign_read_prefs_mode (mongoc_uri_t *uri) /* IN */
{
   const char *str;
   bson_iter_t iter;

   BSON_ASSERT(uri);

   if (mongoc_uri_get_option_as_bool (uri, "slaveok", false)) {
      mongoc_read_prefs_set_mode(uri->read_prefs, MONGOC_READ_SECONDARY_PREFERRED);
   }

   if (bson_iter_init_find_case(&iter, &uri->options, "readpreference") &&
       BSON_ITER_HOLDS_UTF8(&iter)) {
      str = bson_iter_utf8(&iter, NULL);

      if (0 == strcasecmp("primary", str)) {
         mongoc_read_prefs_set_mode(uri->read_prefs, MONGOC_READ_PRIMARY);
      } else if (0 == strcasecmp("primarypreferred", str)) {
         mongoc_read_prefs_set_mode(uri->read_prefs, MONGOC_READ_PRIMARY_PREFERRED);
      } else if (0 == strcasecmp("secondary", str)) {
         mongoc_read_prefs_set_mode(uri->read_prefs, MONGOC_READ_SECONDARY);
      } else if (0 == strcasecmp("secondarypreferred", str)) {
         mongoc_read_prefs_set_mode(uri->read_prefs, MONGOC_READ_SECONDARY_PREFERRED);
      } else if (0 == strcasecmp("nearest", str)) {
         mongoc_read_prefs_set_mode(uri->read_prefs, MONGOC_READ_NEAREST);
      } else {
         MONGOC_WARNING("Unsupported readPreference value [readPreference=%s].", str);
      }
   }

   /* Warn on conflict, since read preference will be validated later */
   if (mongoc_read_prefs_get_mode(uri->read_prefs) == MONGOC_READ_PRIMARY &&
       !bson_empty(mongoc_read_prefs_get_tags(uri->read_prefs))) {
      MONGOC_WARNING("Primary read preference mode conflicts with tags.");
   }
}
예제 #5
0
mongoc_cursor_t *
_mongoc_cursor_new (mongoc_client_t           *client,
                    const char                *db_and_collection,
                    mongoc_query_flags_t       flags,
                    bson_uint32_t              skip,
                    bson_uint32_t              limit,
                    bson_uint32_t              batch_size,
                    bson_bool_t                is_command,
                    const bson_t              *query,
                    const bson_t              *fields,
                    const mongoc_read_prefs_t *read_prefs)
{
   mongoc_read_mode_t mode;
   mongoc_cursor_t *cursor;
   const bson_t *tags;
   const char *mode_str;
   bson_t child;

   ENTRY;

   BSON_ASSERT(client);
   BSON_ASSERT(db_and_collection);
   BSON_ASSERT(query);

   /* we can't have exhaust queries with limits */
   BSON_ASSERT (!((flags & MONGOC_QUERY_EXHAUST) && limit));

   /* we can't have exhaust queries with sharded clusters */
   BSON_ASSERT (!((flags & MONGOC_QUERY_EXHAUST) && client->cluster.isdbgrid));

   /*
    * 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 = bson_malloc0(sizeof *cursor);
   cursor->client = client;
   strncpy(cursor->ns, db_and_collection, sizeof cursor->ns - 1);
   cursor->nslen = strlen(cursor->ns);
   cursor->flags = flags;
   cursor->skip = skip;
   cursor->limit = limit;
   cursor->batch_size = cursor->batch_size;

   cursor->is_command = is_command;

   if (!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);

   mongoc_counter_cursors_active_inc();

   RETURN(cursor);
}
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;
}
/* Update result with the read prefs, following Server Selection Spec.
 * The driver must have discovered the server is a mongos.
 */
static void
_apply_read_preferences_mongos (const mongoc_read_prefs_t *read_prefs,
                                const bson_t *query_bson,
                                mongoc_apply_read_prefs_result_t *result /* OUT */)
{
   mongoc_read_mode_t mode;
   const bson_t *tags = NULL;
   bson_t child;
   const char *mode_str;

   mode = mongoc_read_prefs_get_mode (read_prefs);
   if (read_prefs) {
      tags = mongoc_read_prefs_get_tags (read_prefs);
   }

   /* Server Selection Spec says:
    *
    * For mode 'primary', drivers MUST NOT set the slaveOK wire protocol flag
    *   and MUST NOT use $readPreference
    *
    * For mode 'secondary', drivers MUST set the slaveOK wire protocol flag and
    *   MUST also use $readPreference
    *
    * For mode 'primaryPreferred', drivers MUST set the slaveOK wire protocol
    *   flag and MUST also use $readPreference
    *
    * For mode 'secondaryPreferred', drivers MUST set the slaveOK wire protocol
    *   flag. If the read preference contains a non-empty tag_sets parameter,
    *   drivers MUST use $readPreference; otherwise, drivers MUST NOT use
    *   $readPreference
    *
    * For mode 'nearest', drivers MUST set the slaveOK wire protocol flag and
    *   MUST also use $readPreference
    */
   if (mode == MONGOC_READ_SECONDARY_PREFERRED && bson_empty0 (tags)) {
      result->flags |= MONGOC_QUERY_SLAVE_OK;

   } else if (mode != MONGOC_READ_PRIMARY) {
      result->flags |= MONGOC_QUERY_SLAVE_OK;

      /* Server Selection Spec: "When any $ modifier is used, including the
       * $readPreference modifier, the query MUST be provided using the $query
       * modifier".
       *
       * This applies to commands, too.
       */
      result->query_with_read_prefs = bson_new ();
      result->query_owned = true;

      if (bson_has_field (query_bson, "$query")) {
         bson_concat (result->query_with_read_prefs, query_bson);
      } else {
         bson_append_document (result->query_with_read_prefs,
                               "$query", 6, query_bson);
      }

      bson_append_document_begin (result->query_with_read_prefs,
                                  "$readPreference", 15, &child);
      mode_str = _get_read_mode_string (mode);
      bson_append_utf8 (&child, "mode", 4, mode_str, -1);
      if (!bson_empty0 (tags)) {
         bson_append_array (&child, "tags", 4, tags);
      }

      bson_append_document_end (result->query_with_read_prefs, &child);
   }
}
예제 #8
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);
}
예제 #9
0
int64_t HHVM_METHOD(MongoDBDriverReadPreference, getMode)
{
	MongoDBDriverReadPreferenceData* data = Native::data<MongoDBDriverReadPreferenceData>(this_);

	return mongoc_read_prefs_get_mode(data->m_read_preference);
}
예제 #10
0
static bool hippo_mongo_driver_manager_apply_rp(mongoc_uri_t *uri, const Array options)
{
	mongoc_read_prefs_t *new_rp;
	const mongoc_read_prefs_t *old_rp;
	const char *rp_str = NULL;
	bson_t *b_tags;

	if (!(old_rp = mongoc_uri_get_read_prefs_t(uri))) {
		throw MongoDriver::Utils::throwRunTimeException("mongoc_uri_t does not have a read preference");

		return false;
	}

	if (options.size() == 0) {
		return true;
	}

	if (
		!options.exists(s_MongoDBDriverManager_slaveok) &&
		!options.exists(s_MongoDBDriverManager_readpreference) &&
		!options.exists(s_MongoDBDriverManager_readpreferencetags) &&
		!options.exists(s_MongoDBDriverManager_readPreference) &&
		!options.exists(s_MongoDBDriverManager_readPreferenceTags)
	) {
		return true;
	}

	new_rp = mongoc_read_prefs_copy(old_rp);

	if (options.exists(s_MongoDBDriverManager_slaveok) && options[s_MongoDBDriverManager_slaveok].isBoolean()) {
		mongoc_read_prefs_set_mode(new_rp, MONGOC_READ_SECONDARY_PREFERRED);
	}

	if (options.exists(s_MongoDBDriverManager_readpreference) && options[s_MongoDBDriverManager_readpreference].isString()) {
		rp_str = options[s_MongoDBDriverManager_readpreference].toString().c_str();
	}
	if (options.exists(s_MongoDBDriverManager_readPreference) && options[s_MongoDBDriverManager_readPreference].isString()) {
		rp_str = options[s_MongoDBDriverManager_readPreference].toString().c_str();
	}

	if (rp_str) {
		if (0 == strcasecmp("primary", rp_str)) {
			mongoc_read_prefs_set_mode(new_rp, MONGOC_READ_PRIMARY);
		} else if (0 == strcasecmp("primarypreferred", rp_str)) {
			mongoc_read_prefs_set_mode(new_rp, MONGOC_READ_PRIMARY_PREFERRED);
		} else if (0 == strcasecmp("secondary", rp_str)) {
			mongoc_read_prefs_set_mode(new_rp, MONGOC_READ_SECONDARY);
		} else if (0 == strcasecmp("secondarypreferred", rp_str)) {
			mongoc_read_prefs_set_mode(new_rp, MONGOC_READ_SECONDARY_PREFERRED);
		} else if (0 == strcasecmp("nearest", rp_str)) {
			mongoc_read_prefs_set_mode(new_rp, MONGOC_READ_NEAREST);
		} else {
			throw MongoDriver::Utils::throwInvalidArgumentException("Unsupported readPreference value: '" + Variant(rp_str).toString() + "'");
			mongoc_read_prefs_destroy(new_rp);

			return false;
		}
	}

	if (options.exists(s_MongoDBDriverManager_readpreferencetags) && options[s_MongoDBDriverManager_readpreferencetags].isArray()) {
		VariantToBsonConverter converter(options[s_MongoDBDriverManager_readpreferencetags].toArray(), HIPPO_BSON_NO_FLAGS);
		b_tags = bson_new();
		converter.convert(b_tags);
		mongoc_read_prefs_set_tags(new_rp, b_tags);
	} else if (options.exists(s_MongoDBDriverManager_readPreferenceTags) && options[s_MongoDBDriverManager_readPreferenceTags].isArray()) {
		VariantToBsonConverter converter(options[s_MongoDBDriverManager_readPreferenceTags].toArray(), HIPPO_BSON_NO_FLAGS);
		b_tags = bson_new();
		converter.convert(b_tags);
		mongoc_read_prefs_set_tags(new_rp, b_tags);
	}

	if (
		mongoc_read_prefs_get_mode(new_rp) == MONGOC_READ_PRIMARY &&
		!bson_empty(mongoc_read_prefs_get_tags(new_rp))
	) {
		throw MongoDriver::Utils::throwInvalidArgumentException("Primary read preference mode conflicts with tags");
		mongoc_read_prefs_destroy(new_rp);

		return false;
	}

	/* This may be redundant in light of the last check (primary with tags),
	 * but we'll check anyway in case additional validation is implemented. */
	if (!mongoc_read_prefs_is_valid(new_rp)) {
		throw MongoDriver::Utils::throwInvalidArgumentException("Read preference is not valid");
		mongoc_read_prefs_destroy(new_rp);

		return false;
	}

	mongoc_uri_set_read_prefs_t(uri, new_rp);
	mongoc_read_prefs_destroy(new_rp);

	return true;
}
예제 #11
0
ReadPrefs::ReadMode ReadPrefs :: mode () const
{
   return (ReadMode)mongoc_read_prefs_get_mode
      (static_cast <const mongoc_read_prefs_t*> 
       (readPrefs.get()));       
}
예제 #12
0
Array HHVM_METHOD(MongoDBDriverCursor, __debugInfo)
{
	MongoDBDriverCursorData* data = Native::data<MongoDBDriverCursorData>(this_);
	Array retval = Array::Create();

	if (data->cursor) {
		Array cretval = Array::Create();
		const bson_t *tags = mongoc_read_prefs_get_tags(data->cursor->read_prefs);

		cretval.add(s_MongoDBDriverCursor_stamp, (int64_t) data->cursor->stamp);
		cretval.add(s_MongoDBDriverCursor_is_command, !!(data->cursor->is_command));
		cretval.add(s_MongoDBDriverCursor_sent, !!data->cursor->sent);
		cretval.add(s_MongoDBDriverCursor_done, !!data->cursor->done);
		cretval.add(s_MongoDBDriverCursor_end_of_event, !!data->cursor->end_of_event);
		cretval.add(s_MongoDBDriverCursor_in_exhaust, !!data->cursor->in_exhaust);
		cretval.add(s_MongoDBDriverCursor_has_fields, !!data->cursor->has_fields);

		{
			Variant v_query;

			hippo_bson_conversion_options_t options = HIPPO_TYPEMAP_INITIALIZER;
			BsonToVariantConverter convertor(bson_get_data(&data->cursor->query), data->cursor->query.len, options);
			convertor.convert(&v_query);
			cretval.add(s_MongoDBDriverCursor_query, v_query);
		}
		{
			Variant v_fields;

			hippo_bson_conversion_options_t options = HIPPO_TYPEMAP_INITIALIZER;
			BsonToVariantConverter convertor(bson_get_data(&data->cursor->fields), data->cursor->fields.len, options);
			convertor.convert(&v_fields);
			cretval.add(s_MongoDBDriverCursor_fields, v_fields);
		}
		if (tags->len) {
			Array rp_retval = Array::Create();
			Variant v_read_preference;

			rp_retval.add(s_MongoDBDriverCursor_read_preference_mode, (int64_t) mongoc_read_prefs_get_mode(data->cursor->read_prefs));

			hippo_bson_conversion_options_t options = HIPPO_TYPEMAP_DEBUG_INITIALIZER;
			BsonToVariantConverter convertor(bson_get_data(tags), tags->len, options);
			convertor.convert(&v_read_preference);
			rp_retval.add(s_MongoDBDriverCursor_read_preference_tags, v_read_preference);

			cretval.add(s_MongoDBDriverCursor_read_preference, rp_retval);
		} else {
			cretval.add(s_MongoDBDriverCursor_read_preference, Variant());
		}

		cretval.add(s_MongoDBDriverCursor_flags, (int64_t) data->cursor->flags);
		cretval.add(s_MongoDBDriverCursor_skip, (int64_t) data->cursor->skip);
		cretval.add(s_MongoDBDriverCursor_limit, (int64_t) data->cursor->limit);
		cretval.add(s_MongoDBDriverCursor_count, (int64_t) data->cursor->count);
		cretval.add(s_MongoDBDriverCursor_batch_size, (int64_t) data->cursor->batch_size);

		cretval.add(s_MongoDBDriverCursor_ns, data->cursor->ns);

		if (data->cursor->current) {
			Array doc_retval = Array::Create();
			Variant v_doc;

			hippo_bson_conversion_options_t options = HIPPO_TYPEMAP_INITIALIZER;
			BsonToVariantConverter convertor(bson_get_data(data->cursor->current), data->cursor->current->len, options);
			convertor.convert(&v_doc);
			cretval.add(s_MongoDBDriverCursor_current_doc, v_doc);
		}

		retval.add(s_MongoDBDriverCursor_cursor, cretval);
	} else {
		retval.add(s_MongoDBDriverCursor_cursor, Variant());
	}

	retval.add(s_MongoDBDriverCursor_server_id, data->m_server_id);

	return retval;
}