static void as_uv_wakeup(uv_async_t* wakeup) { // Read command pointers from queue. as_event_loop* event_loop = wakeup->data; as_uv_command cmd; pthread_mutex_lock(&event_loop->lock); while (as_queue_pop(&event_loop->queue, &cmd)) { switch (cmd.type) { case AS_UV_PROCESS_COMMAND: as_event_command_execute_in_loop(cmd.ptr); break; case AS_UV_CLOSE_CONNECTION: uv_close((uv_handle_t*)cmd.ptr, as_uv_connection_closed); break; case AS_UV_EXIT_LOOP: as_event_close_loop(event_loop); return; } } pthread_mutex_unlock(&event_loop->lock); }
static bool as_uv_queue_close_connections(as_node* node, as_queue* conn_queue, as_queue* cmd_queue) { as_uv_command qcmd; qcmd.type = AS_UV_CLOSE_CONNECTION; as_event_connection* conn; // Queue connection commands to event loops. while (as_queue_pop(conn_queue, &conn)) { qcmd.ptr = conn; if (! as_queue_push(cmd_queue, &qcmd)) { as_log_error("Failed to queue connection close"); return false; } // In this case, connection counts are decremented before the connection is closed. // This is done because the node will be invalid when the deferred connection close occurs. // Since node destroy always waits till there are no node references, all transactions that // referenced this node should be completed by the time this code is executed. as_event_decr_connection(node->cluster, conn_queue); ck_pr_dec_32(&node->cluster->async_conn_pool); } return true; }
static void as_ev_close_connections(as_node* node, as_queue* conn_queue) { as_event_connection* conn; // Queue connection commands to event loops. while (as_queue_pop(conn_queue, &conn)) { close(conn->fd); cf_free(conn); as_event_decr_connection(node->cluster, conn_queue); ck_pr_dec_32(&node->cluster->async_conn_pool); } as_queue_destroy(conn_queue); }
as_connection_status as_event_get_connection(as_event_command* cmd) { as_queue* queue = &cmd->node->async_conn_qs[cmd->event_loop->index]; as_async_connection* conn; // Find connection. while (as_queue_pop(queue, &conn)) { ck_pr_dec_32(&cmd->cluster->async_conn_pool); // Verify that socket is active and receive buffer is empty. int len = as_event_validate_connection(&conn->base); if (len == 0) { conn->cmd = cmd; cmd->conn = (as_event_connection*)conn; return AS_CONNECTION_FROM_POOL; } as_log_debug("Invalid async socket from pool: %d", len); as_event_release_connection(cmd->cluster, &conn->base, queue); } // Create connection structure only when node connection count within queue limit. if (as_queue_incr_total(queue)) { ck_pr_inc_32(&cmd->cluster->async_conn_count); conn = cf_malloc(sizeof(as_async_connection)); conn->base.pipeline = false; conn->cmd = cmd; cmd->conn = &conn->base; return AS_CONNECTION_NEW; } else { as_error err; as_error_update(&err, AEROSPIKE_ERR_NO_MORE_CONNECTIONS, "Max node/event loop %s async connections would be exceeded: %u", cmd->node->name, queue->capacity); as_event_stop_timer(cmd); as_event_error_callback(cmd, &err); return AS_CONNECTION_TOO_MANY; } }
static void as_ev_wakeup(struct ev_loop* loop, ev_async* wakeup, int revents) { // Read command pointers from queue. as_event_loop* event_loop = wakeup->data; void* cmd; pthread_mutex_lock(&event_loop->lock); while (as_queue_pop(&event_loop->queue, &cmd)) { if (cmd) { // Process new command. as_event_command_execute_in_loop(cmd); } else { // Received stop signal. as_event_close_loop(event_loop); return; } } pthread_mutex_unlock(&event_loop->lock); }