/* The algorithm works as follows: In case we have a read preference of * primary, secondary or nearest the set will always contain a set of all nodes * that should always be considered to be returned. With primary, there is only * going to be one node, with primary the set contains only secondaries and * with nearest we do not prefer a secondary over a primary or v.v. * * In case we have a read preference of primaryPreferred or * secondaryPreferred, we need to do a bit more logic for selecting the node * that we use. */ mongo_connection *mongo_pick_server_from_set(mongo_con_manager *manager, mcon_collection *col, mongo_read_preference *rp) { mongo_connection *con = NULL; int entry; /* If we prefer the primary, we check whether the first node is a primary * (which it should be if it's available and sorted according to primary > * secondary). If the first node in the list is no primary, we fall back * to picking a random node from the set. */ if (rp->type == MONGO_RP_PRIMARY_PREFERRED) { if (((mongo_connection*)col->data[0])->connection_type == MONGO_NODE_PRIMARY) { mongo_manager_log(manager, MLOG_RS, MLOG_INFO, "pick server: the primary"); con = (mongo_connection*)col->data[0]; mongo_print_connection_info(manager, con, MLOG_INFO); return con; } } /* If we prefer a secondary, then we need to ignore the last item from the * list, as this is the primary node - but only if there is more than one * node in the list AND the last node in the list is a primary. */ if (rp->type == MONGO_RP_SECONDARY_PREFERRED) { if ( (col->count > 1) && (((mongo_connection*)col->data[col->count - 1])->connection_type == MONGO_NODE_PRIMARY) ) { entry = rand() % (col->count - 1); mongo_manager_log(manager, MLOG_RS, MLOG_INFO, "pick server: random element %d while ignoring the primary", entry); con = (mongo_connection*)col->data[entry]; mongo_print_connection_info(manager, con, MLOG_INFO); return con; } } /* For now, we just pick a random server from the set */ entry = rand() % col->count; mongo_manager_log(manager, MLOG_RS, MLOG_INFO, "pick server: random element %d", entry); con = (mongo_connection*)col->data[entry]; mongo_print_connection_info(manager, con, MLOG_INFO); return con; }
static mcon_collection *mongo_filter_candidates_by_credentials(mongo_con_manager *manager, mcon_collection *candidates, mongo_servers *servers) { int i; char *db, *username, *auth_hash, *hashed = NULL; mcon_collection *filtered; mongo_manager_log(manager, MLOG_RS, MLOG_FINE, "limiting by credentials"); filtered = mcon_init_collection(sizeof(mongo_connection*)); for (i = 0; i < candidates->count; i++) { db = username = auth_hash = hashed = NULL; mongo_server_split_hash(((mongo_connection *) candidates->data[i])->hash, NULL, NULL, NULL, &db, &username, &auth_hash, NULL); if (servers->server[0]->username && servers->server[0]->password && servers->server[0]->db) { if (strcmp(db, servers->server[0]->db) != 0) { mongo_manager_log(manager, MLOG_RS, MLOG_FINE, "- skipping '%s', database didn't match ('%s' vs '%s')", ((mongo_connection *) candidates->data[i])->hash, db, servers->server[0]->db); goto skip; } if (strcmp(username, servers->server[0]->username) != 0) { mongo_manager_log(manager, MLOG_RS, MLOG_FINE, "- skipping '%s', username didn't match ('%s' vs '%s')", ((mongo_connection *) candidates->data[i])->hash, username, servers->server[0]->username); goto skip; } hashed = mongo_server_create_hashed_password(username, servers->server[0]->password); if (strcmp(auth_hash, hashed) != 0) { mongo_manager_log(manager, MLOG_RS, MLOG_FINE, "- skipping '%s', authentication hash didn't match ('%s' vs '%s')", ((mongo_connection *) candidates->data[i])->hash, auth_hash, hashed); goto skip; } } mcon_collection_add(filtered, (mongo_connection *) candidates->data[i]); mongo_print_connection_info(manager, (mongo_connection *) candidates->data[i], MLOG_FINE); skip: if (db) { free(db); } if (username) { free(username); } if (auth_hash) { free(auth_hash); } if (hashed) { free(hashed); } } mongo_manager_log(manager, MLOG_RS, MLOG_FINE, "limiting by credentials: done"); return filtered; }
/* Collecting the correct servers */ static mcon_collection *filter_connections(mongo_con_manager *manager, int types, mongo_read_preference *rp) { mcon_collection *col; mongo_con_manager_item *ptr = manager->connections; col = mcon_init_collection(sizeof(mongo_connection*)); mongo_manager_log(manager, MLOG_RS, MLOG_FINE, "filter_connections: adding connections:"); while (ptr) { if (ptr->connection->connection_type & types) { mongo_print_connection_info(manager, ptr->connection, MLOG_FINE); mcon_collection_add(col, ptr->connection); } ptr = ptr->next; } mongo_manager_log(manager, MLOG_RS, MLOG_FINE, "filter_connections: done"); return col; }
static mcon_collection *mongo_filter_candidates_by_seed(mongo_con_manager *manager, mcon_collection *candidates, mongo_servers *servers) { int i, j; mcon_collection *filtered; char *server_hash; mongo_manager_log(manager, MLOG_RS, MLOG_FINE, "limiting by seeded/discovered servers"); filtered = mcon_init_collection(sizeof(mongo_connection*)); for (j = 0; j < servers->count; j++) { server_hash = mongo_server_create_hash(servers->server[j]); for (i = 0; i < candidates->count; i++) { if (strcmp(((mongo_connection *) candidates->data[i])->hash, server_hash) == 0) { mongo_print_connection_info(manager, (mongo_connection *) candidates->data[i], MLOG_FINE); mcon_collection_add(filtered, (mongo_connection *) candidates->data[i]); } } free(server_hash); } mongo_manager_log(manager, MLOG_RS, MLOG_FINE, "limiting by seeded/discovered servers: done"); return filtered; }
void mongo_print_connection_iterate_wrapper(mongo_con_manager *manager, void *elem) { mongo_connection *con = (mongo_connection*) elem; mongo_print_connection_info(manager, con, MLOG_FINE); }