/** * Sends a ping command to the server and stores the result. * * Returns 1 when it worked, and 0 when an error was encountered. */ int mongo_connection_ping(mongo_con_manager *manager, mongo_connection *con, mongo_server_options *options, char **error_message) { mcon_str *packet; struct timeval start, end; char *data_buffer; /* If we haven't hit the ping_interval yet, then there is no need to do a roundtrip to the server */ if (!mongo_connection_ping_check(manager, con->last_ping, &start)) { return 1; } mongo_manager_log(manager, MLOG_CON, MLOG_INFO, "is_ping: pinging %s", con->hash); packet = bson_create_ping_packet(con); if (!mongo_connect_send_packet(manager, con, options, packet, &data_buffer, error_message)) { return 0; } gettimeofday(&end, NULL); free(data_buffer); con->last_ping = end.tv_sec; con->ping_ms = (end.tv_sec - start.tv_sec) * 1000 + (end.tv_usec - start.tv_usec) / 1000; if (con->ping_ms < 0) { /* some clocks do weird stuff */ con->ping_ms = 0; } mongo_manager_log(manager, MLOG_CON, MLOG_INFO, "is_ping: last pinged at %ld; time: %dms", con->last_ping, con->ping_ms); return 1; }
/* Helpers */ static mongo_connection *mongo_get_connection_single(mongo_con_manager *manager, mongo_server_def *server, mongo_server_options *options, int connection_flags, char **error_message) { char *hash; mongo_connection *con = NULL; mongo_connection_blacklist *blacklist = NULL; hash = mongo_server_create_hash(server); /* See if a connection is in our blacklist to short-circut trying to * connect to a node that is known to be down. This is done so we don't * waste precious time in connecting to unreachable nodes */ blacklist = mongo_manager_blacklist_find_by_hash(manager, hash); if (blacklist) { struct timeval start; /* It is blacklisted, but it may have been a long time again and * chances are we should give it another try */ if (mongo_connection_ping_check(manager, blacklist->last_ping, &start)) { /* The connection is blacklisted, but we've reached our ping * interval so lets remove the blacklisting and pretend we didn't * know about it */ mongo_manager_blacklist_deregister(manager, blacklist, hash); } else { /* Otherwise short-circut the connection attempt, and say we failed * right away */ free(hash); *error_message = strdup("Previous connection attempts failed, server blacklisted"); return NULL; } } con = mongo_manager_connection_find_by_hash(manager, hash); /* If we aren't about to (re-)connect then all we care about if it was a * known connection or not */ if (connection_flags & MONGO_CON_FLAG_DONT_CONNECT) { free(hash); return con; } /* If we found a valid connection check if we need to ping it */ if (con) { /* Do the ping, if needed */ if (!mongo_connection_ping(manager, con, options, error_message)) { /* If the ping failed, deregister the connection */ mongo_manager_connection_deregister(manager, con); /* Set the return value to NULL, as the connection is broken and * has been removed */ con = NULL; } free(hash); return con; } /* Since we didn't find an existing connection, lets make one! */ con = mongo_connection_create(manager, hash, server, options, error_message); if (con) { /* When we make a connection, we need to figure out the server version it is */ if (!mongo_connection_get_server_version(manager, con, options, error_message)) { mongo_manager_log(manager, MLOG_CON, MLOG_WARN, "server_version: error while getting the server version %s:%d: %s", server->host, server->port, *error_message); mongo_connection_destroy(manager, con, MONGO_CLOSE_BROKEN); free(hash); return NULL; } /* Do authentication if requested */ /* Note: Arbiters don't contain any data, including auth stuff, so you cannot authenticate on an arbiter */ if (con->connection_type != MONGO_NODE_ARBITER) { if (!manager->authenticate(manager, con, options, server, error_message)) { mongo_connection_destroy(manager, con, MONGO_CLOSE_BROKEN); free(hash); return NULL; } } /* Do the first-time ping to record the latency of the connection */ if (mongo_connection_ping(manager, con, options, error_message)) { /* Register the connection on successful pinging */ mongo_manager_connection_register(manager, con); } else { /* Or kill it and reset the return value if the ping somehow failed */ mongo_connection_destroy(manager, con, MONGO_CLOSE_BROKEN); con = NULL; } } free(hash); return con; }
static mongo_connection *mongo_get_connection_single(mongo_con_manager *manager, mongo_server_def *server, mongo_server_options *options, int connection_flags, char **error_message) { char *hash; mongo_connection *con = NULL; mongo_connection_blacklist *blacklist = NULL; hash = mongo_server_create_hash(server); /* See if a connection is in our blacklist to short-circut trying to connect * to a node that is known to be down. This is done so we don't waste * precious time in connecting to unreachable nodes */ blacklist = mongo_manager_blacklist_find_by_hash(manager, hash); if (blacklist) { struct timeval start; /* It is blacklisted, but it may have been a long time again and chances are * we should give it another try */ if (mongo_connection_ping_check(manager, blacklist->last_ping, &start)) { /* The connection is blacklisted, but we've reached our ping interval * so lets remove the blacklisting and pretend we didn't know about it */ mongo_manager_blacklist_deregister(manager, blacklist, hash); con = NULL; } else { /* Otherwise short-circut the connection attempt, and say we failed right away */ free(hash); return NULL; } } con = mongo_manager_connection_find_by_hash(manager, hash); /* If we aren't about to (re-)connect then all we care about if it was a known connection or not */ if (connection_flags & MONGO_CON_FLAG_DONT_CONNECT) { free(hash); return con; } /* If we found a valid connection check if we need to ping it */ if (con) { /* Do the ping, if needed */ if (!mongo_connection_ping(manager, con, options, error_message)) { /* If the ping failed, deregister the connection */ mongo_manager_connection_deregister(manager, con); /* Set the return value to NULL, as the connection is broken and has been removed */ con = NULL; } free(hash); return con; } /* Since we didn't find an existing connection, lets make one! */ con = mongo_connection_create(manager, hash, server, options, error_message); if (con) { /* Do authentication if requested */ if (server->db && server->username && server->password) { mongo_manager_log(manager, MLOG_CON, MLOG_INFO, "get_connection_single: authenticating %s", hash); if (!authenticate_connection(manager, con, options, server->authdb ? server->authdb : server->db, server->username, server->password, error_message)) { mongo_connection_destroy(manager, con, MONGO_CLOSE_BROKEN); free(hash); return NULL; } } /* Do the first-time ping to record the latency of the connection */ if (mongo_connection_ping(manager, con, options, error_message)) { /* Register the connection on successful pinging */ mongo_manager_connection_register(manager, con); } else { /* Or kill it and reset the return value if the ping somehow failed */ mongo_connection_destroy(manager, con, MONGO_CLOSE_BROKEN); con = NULL; } } free(hash); return con; }