static void td_to_bson (const mongoc_topology_description_t *td, bson_t *bson) { size_t i; bson_t servers = BSON_INITIALIZER; bson_t server; char str[16]; const char *key; for (i = 0; i < td->servers->items_len; i++) { bson_uint32_to_string ((uint32_t) i, &key, str, sizeof str); sd_to_bson (mongoc_set_get_item (td->servers, (int) i), &server); BSON_APPEND_DOCUMENT (&servers, key, &server); bson_destroy (&server); } bson_init (bson); BSON_APPEND_UTF8 (bson, "topologyType", mongoc_topology_description_type (td)); if (td->set_name) { BSON_APPEND_UTF8 (bson, "setName", td->set_name); } BSON_APPEND_ARRAY (bson, "servers", &servers); bson_destroy (&servers); }
mongoc_server_description_t * mongoc_topology_description_select (mongoc_topology_description_t *topology, mongoc_ss_optype_t optype, const mongoc_read_prefs_t *read_pref, int64_t local_threshold_ms) { mongoc_array_t suitable_servers; mongoc_server_description_t *sd = NULL; ENTRY; if (!topology->compatible) { /* TODO, should we return an error object here, or just treat as a case where there are no suitable servers? */ RETURN(NULL); } if (topology->type == MONGOC_TOPOLOGY_SINGLE) { sd = (mongoc_server_description_t *)mongoc_set_get_item (topology->servers, 0); if (sd->has_is_master) { RETURN(sd); } else { RETURN(NULL); } } _mongoc_array_init(&suitable_servers, sizeof(mongoc_server_description_t *)); mongoc_topology_description_suitable_servers(&suitable_servers, optype, topology, read_pref, local_threshold_ms); if (suitable_servers.len != 0) { sd = _mongoc_array_index(&suitable_servers, mongoc_server_description_t*, rand() % suitable_servers.len); }
/* Send TopologyOpeningEvent when first called on this topology description. * td is not const: we set its "opened" field here */ void _mongoc_topology_description_monitor_opening (mongoc_topology_description_t *td) { mongoc_topology_description_t *prev_td = NULL; size_t i; mongoc_server_description_t *sd; if (td->opened) { return; } if (td->apm_callbacks.topology_changed) { /* prepare to call monitor_changed */ prev_td = bson_malloc0 (sizeof (mongoc_topology_description_t)); mongoc_topology_description_init ( prev_td, MONGOC_TOPOLOGY_UNKNOWN, td->heartbeat_msec); } td->opened = true; if (td->apm_callbacks.topology_opening) { mongoc_apm_topology_opening_t event; bson_oid_copy (&td->topology_id, &event.topology_id); event.context = td->apm_context; td->apm_callbacks.topology_opening (&event); } if (td->apm_callbacks.topology_changed) { /* send initial description-changed event */ _mongoc_topology_description_monitor_changed (prev_td, td); } for (i = 0; i < td->servers->items_len; i++) { sd = (mongoc_server_description_t *) mongoc_set_get_item (td->servers, (int) i); _mongoc_topology_description_monitor_server_opening (td, sd); } if (prev_td) { mongoc_topology_description_destroy (prev_td); bson_free (prev_td); } }
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; }