DBClientBase *mongo_connection_pool_get(mongo_connection_pool_t *conn_pool) { DBClientBase *conn = NULL; void *data = NULL; switch_assert(conn_pool != NULL); switch_mutex_lock(conn_pool->mutex); if (switch_queue_trypop(conn_pool->connections, &data) == SWITCH_STATUS_SUCCESS) { conn = (DBClientBase *) data; } else if (mongo_connection_create(&conn, conn_pool->conn_str) == SWITCH_STATUS_SUCCESS) { if (++conn_pool->size > conn_pool->max_connections) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Connection pool is empty. You may want to increase 'max-connections'\n"); } } switch_mutex_unlock(conn_pool->mutex); #ifdef MONGO_POOL_DEBUG switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "POOL get: size %d conn: %p\n", (int) switch_queue_size(conn_pool->connections), conn); #endif return conn; }
switch_status_t mongo_connection_pool_create(mongo_connection_pool_t **conn_pool, switch_size_t min_connections, switch_size_t max_connections, const char *conn_str) { switch_memory_pool_t *pool = NULL; switch_status_t status = SWITCH_STATUS_SUCCESS; mongo_connection_pool_t *cpool = NULL; DBClientBase *conn = NULL; if ((status = switch_core_new_memory_pool(&pool)) != SWITCH_STATUS_SUCCESS) { return status; } if (!(cpool = (mongo_connection_pool_t *)switch_core_alloc(pool, sizeof(mongo_connection_pool_t)))) { switch_goto_status(SWITCH_STATUS_MEMERR, done); } if ((status = switch_mutex_init(&cpool->mutex, SWITCH_MUTEX_NESTED, pool)) != SWITCH_STATUS_SUCCESS) { goto done; } if ((status = switch_queue_create(&cpool->connections, max_connections, pool)) != SWITCH_STATUS_SUCCESS) { goto done; } cpool->min_connections = min_connections; cpool->max_connections = max_connections; cpool->conn_str = switch_core_strdup(pool, conn_str); cpool->pool = pool; for (cpool->size = 0; cpool->size < min_connections; cpool->size++) { if (mongo_connection_create(&conn, conn_str) == SWITCH_STATUS_SUCCESS) { mongo_connection_pool_put(cpool, conn); } else { break; } } done: if (status == SWITCH_STATUS_SUCCESS) { *conn_pool = cpool; } else { switch_core_destroy_memory_pool(&pool); } return status; }
/* 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; }