mcon_collection* mongo_find_candidate_servers(mongo_con_manager *manager, mongo_read_preference *rp, mongo_servers *servers)
{
	int              i;
	mcon_collection *all, *filtered;

	mongo_manager_log(manager, MLOG_RS, MLOG_FINE, "finding candidate servers");
	all = mongo_find_all_candidate_servers(manager, rp);

	if (servers->options.con_type == MONGO_CON_TYPE_REPLSET) {
		filtered = mongo_filter_candidates_by_replicaset_name(manager, all, servers);
	} else {
		filtered = mongo_filter_candidates_by_seed(manager, all, servers);
	}
	mcon_collection_free(all);
	all = filtered;

	filtered = mongo_filter_candidates_by_credentials(manager, all, servers);
	mcon_collection_free(all);
	all = filtered;

	if (rp->tagset_count != 0) {
		mongo_manager_log(manager, MLOG_RS, MLOG_FINE, "limiting by tagsets");
		/* If we have tagsets configured for the replicaset then we need to do
		 * some more filtering */
		for (i = 0; i < rp->tagset_count; i++) {
			char *tmp_ts = mongo_read_preference_squash_tagset(rp->tagsets[i]);

			mongo_manager_log(manager, MLOG_RS, MLOG_FINE, "checking tagset: %s", tmp_ts);
			filtered = mongo_filter_candidates_by_tagset(manager, all, rp->tagsets[i]);
			mongo_manager_log(manager, MLOG_RS, MLOG_FINE, "tagset %s matched %d candidates", tmp_ts, filtered->count);
			free(tmp_ts);

			if (filtered->count > 0) {
				mcon_collection_free(all);
				return filtered;
			}
		}
		mcon_collection_free(filtered);
		mcon_collection_free(all);
		return NULL;
	} else {
		return all;
	}
}
mcon_collection *mongo_select_nearest_servers(mongo_con_manager *manager, mcon_collection *col, mongo_read_preference *rp)
{
	mcon_collection *filtered;
	int              i, nearest_ping;

	filtered = mcon_init_collection(sizeof(mongo_connection*));

	mongo_manager_log(manager, MLOG_RS, MLOG_FINE, "selecting near servers");

	switch (rp->type) {
		case MONGO_RP_PRIMARY:
		case MONGO_RP_PRIMARY_PREFERRED:
		case MONGO_RP_SECONDARY:
		case MONGO_RP_SECONDARY_PREFERRED:
		case MONGO_RP_NEAREST:
			/* The nearest ping time is in the first element */
			nearest_ping = ((mongo_connection*)col->data[0])->ping_ms;
			mongo_manager_log(manager, MLOG_RS, MLOG_FINE, "selecting near servers: nearest is %dms", nearest_ping);

			/* FIXME: Change to iterator later */
			for (i = 0; i < col->count; i++) {
				if (((mongo_connection*)col->data[i])->ping_ms <= nearest_ping + MONGO_RP_CUTOFF) {
					mcon_collection_add(filtered, col->data[i]);
				}
			}
			break;

		default:
			return NULL;
	}

	/* Clean up the old collection that we no longer need */
	mcon_collection_free(col);

	mcon_collection_iterate(manager, filtered, mongo_print_connection_iterate_wrapper);
	mongo_manager_log(manager, MLOG_RS, MLOG_FINE, "selecting near server: done");

	return filtered;
}
示例#3
0
static mongo_connection *mongo_get_connection_multiple(mongo_con_manager *manager, mongo_servers *servers, int connection_flags, char **error_message)
{
	mongo_connection *con = NULL;
	mongo_connection *tmp;
	mcon_collection  *collection = NULL;
	mongo_read_preference tmp_rp; /* We only support NEAREST for MULTIPLE right now */
	int i;
	int found_connected_server = 0;
	mcon_str         *messages;
	int found_supported_wire_version = 1;

	mcon_str_ptr_init(messages);

	/* Create a connection to every of the servers in the seed list */
	for (i = 0; i < servers->count; i++) {
		int ismaster_error = 0;
		char *con_error_message = NULL;
		tmp = mongo_get_connection_single(manager, servers->server[i], &servers->options, connection_flags, (char **) &con_error_message);

		if (tmp) {
			found_connected_server++;

			/* Run ismaster, if needed, to extract server flags */
			ismaster_error = mongo_connection_ismaster(manager, tmp, &servers->options, NULL, NULL, NULL, &con_error_message, NULL);
			switch (ismaster_error) {
				case 1: /* Run just fine */
				case 2: /* ismaster() skipped due to interval */
					break;

				case 0: /* Some error */
				case 3: /* Run just fine, but hostname didn't match what we expected */
				case 4: /* Danger danger, reported wire version does not overlap what we support */
				default:
					mongo_manager_log(manager, MLOG_CON, MLOG_WARN, "server_flags: error while getting the server configuration %s:%d: %s", servers->server[i]->host, servers->server[i]->port, con_error_message);
					/* If it failed because of wire version, we have to bail out completely
					 * later on, but we should continue to aggregate the errors in case more
					 * servers are unsupported */
					if (ismaster_error == 4) {
						mongo_manager_connection_deregister(manager, tmp);
						found_supported_wire_version = 0;
					} else {
						mongo_connection_destroy(manager, tmp, MONGO_CLOSE_BROKEN);
					}
					tmp = NULL;
					found_connected_server--;
			}
		}
		if (!tmp) {
			if (!(connection_flags & MONGO_CON_FLAG_DONT_CONNECT)) {
				mongo_manager_log(manager, MLOG_CON, MLOG_WARN, "Couldn't connect to '%s:%d': %s", servers->server[i]->host, servers->server[i]->port, con_error_message);
				if (messages->l) {
					mcon_str_addl(messages, "; ", 2, 0);
				}
				mcon_str_add(messages, "Failed to connect to: ", 0);
				mcon_str_add(messages, servers->server[i]->host, 0);
				mcon_str_addl(messages, ":", 1, 0);
				mcon_str_add_int(messages, servers->server[i]->port);
				mcon_str_addl(messages, ": ", 2, 0);
				mcon_str_add(messages, con_error_message, 1); /* Also frees con_error_message */
			} else {
				free(con_error_message);
			}
		}
	}

	if (!found_supported_wire_version) {
		*error_message = strdup("Found a server running unsupported wire version. Please upgrade the driver, or take the server out of rotation");
		mcon_str_ptr_dtor(messages);
		return NULL;
	}

	/* If we don't have a connected server then there is no point in continueing */
	if (!found_connected_server && (connection_flags & MONGO_CON_FLAG_DONT_CONNECT)) {
		mcon_str_ptr_dtor(messages);
		return NULL;
	}

	/* When selecting a *mongos* node, readPreferences make no sense as we
	 * don't have a "primary" or "secondary" mongos. The mongos nodes aren't
	 * tagged either.  To pick a mongos we therefore simply pick the "nearest"
	 * mongos node. */
	tmp_rp.type = MONGO_RP_NEAREST;
	tmp_rp.tagsets = NULL;
	tmp_rp.tagset_count = 0;
	collection = mongo_find_candidate_servers(manager, &tmp_rp, servers);
	if (!collection || collection->count == 0) {
		if (messages->l) {
			*error_message = strdup(messages->d);
		} else {
			*error_message = strdup("No candidate servers found");
		}
		goto bailout;
	}
	collection = mongo_sort_servers(manager, collection, &servers->read_pref);
	collection = mongo_select_nearest_servers(manager, collection, &servers->options, &servers->read_pref);
	if (!collection) {
		*error_message = strdup("No server near us");
		goto bailout;
	}
	con = mongo_pick_server_from_set(manager, collection, &servers->read_pref);

bailout:
	/* Cleaning up */
	mcon_str_ptr_dtor(messages);
	if (collection) {
		mcon_collection_free(collection);	
	}
	return con;
}
示例#4
0
static mongo_connection *mongo_get_read_write_connection_replicaset(mongo_con_manager *manager, mongo_servers *servers, int connection_flags, char **error_message)
{
	mongo_connection *con = NULL;
	mongo_connection *tmp;
	mcon_collection  *collection;
	char             *con_error_message = NULL;
	int i;
	int found_connected_server = 0;

	/* Create a connection to all of the servers in the seed list */
	for (i = 0; i < servers->count; i++) {
		tmp = mongo_get_connection_single(manager, servers->server[i], &servers->options, connection_flags, (char **) &con_error_message);

		if (tmp) {
			found_connected_server++;
		} else if (!(connection_flags & MONGO_CON_FLAG_DONT_CONNECT)) {
			mongo_manager_log(manager, MLOG_CON, MLOG_WARN, "Couldn't connect to '%s:%d': %s", servers->server[i]->host, servers->server[i]->port, con_error_message);
			free(con_error_message);
		}
	}
	if (!found_connected_server && (connection_flags & MONGO_CON_FLAG_DONT_CONNECT)) {
		return NULL;
	}

	/* Discover more nodes. This also adds a connection to "servers" for each
	 * new node */
	if (!mongo_discover_topology(manager, servers)) {
		/* Total failure, we cannot proceed */
		*error_message = strdup("Incompatible server detected. This driver release is not compatible with one of the connected servers");
		return NULL;
	}

	/* Depending on whether we want a read or a write connection, run the correct algorithms */
	if (connection_flags & MONGO_CON_FLAG_WRITE) {
		mongo_read_preference tmp_rp;

		tmp_rp.type = MONGO_RP_PRIMARY;
		tmp_rp.tagsets = NULL;
		tmp_rp.tagset_count = 0;

		collection = mongo_find_candidate_servers(manager, &tmp_rp, servers);
		mongo_read_preference_dtor(&tmp_rp);
	} else if (connection_flags & MONGO_CON_FLAG_DONT_FILTER) {
		/* We just want to know if we have something to talk to, irregardless of RP */
		mongo_read_preference tmp_rp;

		tmp_rp.type = MONGO_RP_NEAREST;
		tmp_rp.tagsets = NULL;
		tmp_rp.tagset_count = 0;

		collection = mongo_find_candidate_servers(manager, &tmp_rp, servers);
		mongo_read_preference_dtor(&tmp_rp);
	} else {
		collection = mongo_find_candidate_servers(manager, &servers->read_pref, servers);
	}
	if (!collection) {
		*error_message = strdup("No candidate servers found");
		return NULL;
	}
	if (collection->count == 0) {
		*error_message = strdup("No candidate servers found");
		mcon_collection_free(collection);	
		return NULL;
	}
	collection = mongo_sort_servers(manager, collection, &servers->read_pref);
	collection = mongo_select_nearest_servers(manager, collection, &servers->options, &servers->read_pref);
	con = mongo_pick_server_from_set(manager, collection, &servers->read_pref);

	/* Cleaning up */
	mcon_collection_free(collection);	
	return con;
}
示例#5
0
static mongo_connection *mongo_get_connection_multiple(mongo_con_manager *manager, mongo_servers *servers, int connection_flags, char **error_message)
{
	mongo_connection *con = NULL;
	mongo_connection *tmp;
	mcon_collection  *collection = NULL;
	char             *con_error_message = NULL;
	mongo_read_preference tmp_rp; /* We only support NEAREST for MULTIPLE right now */
	int i;
	int found_connected_server = 0;
	mcon_str         *messages;

	mcon_str_ptr_init(messages);

	/* Create a connection to every of the servers in the seed list */
	for (i = 0; i < servers->count; i++) {
		tmp = mongo_get_connection_single(manager, servers->server[i], &servers->options, connection_flags, (char **) &con_error_message);

		if (tmp) {
			found_connected_server = 1;
		} else if (!(connection_flags & MONGO_CON_FLAG_DONT_CONNECT)) {
			mongo_manager_log(manager, MLOG_CON, MLOG_WARN, "Couldn't connect to '%s:%d': %s", servers->server[i]->host, servers->server[i]->port, con_error_message);
			if (messages->l) {
				mcon_str_addl(messages, "; ", 2, 0);
			}
			mcon_str_add(messages, "Failed to connect to: ", 0);
			mcon_str_add(messages, servers->server[i]->host, 0);
			mcon_str_addl(messages, ":", 1, 0);
			mcon_str_add_int(messages, servers->server[i]->port);
			mcon_str_addl(messages, ": ", 2, 0);
			mcon_str_add(messages, con_error_message, 1); /* Also frees con_error_message */
		}
	}

	/* If we don't have a connected server then there is no point in continueing */
	if (!found_connected_server && (connection_flags & MONGO_CON_FLAG_DONT_CONNECT)) {
		return NULL;
	}

	/* When selecting a *mongos* node, readPreferences make no sense as we
	 * don't have a "primary" or "secondary" mongos. The mongos nodes aren't
	 * tagged either.  To pick a mongos we therefore simply pick the "nearest"
	 * mongos node. */
	tmp_rp.type = MONGO_RP_NEAREST;
	tmp_rp.tagsets = NULL;
	tmp_rp.tagset_count = 0;
	collection = mongo_find_candidate_servers(manager, &tmp_rp, servers);
	if (!collection || collection->count == 0) {
		if (messages->l) {
			*error_message = strdup(messages->d);
		} else {
			*error_message = strdup("No candidate servers found");
		}
		goto bailout;
	}
	collection = mongo_sort_servers(manager, collection, &servers->read_pref);
	collection = mongo_select_nearest_servers(manager, collection, &servers->read_pref);
	if (!collection) {
		*error_message = strdup("No server near us");
		goto bailout;
	}
	con = mongo_pick_server_from_set(manager, collection, &servers->read_pref);

bailout:
	/* Cleaning up */
	mcon_str_ptr_dtor(messages);
	if (collection) {
		mcon_collection_free(collection);	
	}
	return con;
}