static as_status as_admin_execute(aerospike* as, as_error* err, const as_policy_admin* policy, uint8_t* buffer, uint8_t* end) { uint32_t timeout_ms = (policy)? policy->timeout : as->config.policies.admin.timeout; if (timeout_ms <= 0) { timeout_ms = DEFAULT_TIMEOUT; } uint64_t deadline_ms = as_socket_deadline(timeout_ms); as_node* node = as_node_get_random(as->cluster); if (! node) { return as_error_set_message(err, AEROSPIKE_ERR_CLIENT, "Failed to find server node."); } int fd; as_status status = as_node_get_connection(err, node, &fd); if (status) { as_node_release(node); return status; } status = as_admin_send(err, fd, buffer, end, deadline_ms); if (status) { as_close(fd); as_node_release(node); return status; } status = as_socket_read_deadline(err, fd, buffer, HEADER_SIZE, deadline_ms); if (status) { as_close(fd); as_node_release(node); return status; } as_node_put_connection(node, fd); as_node_release(node); status = buffer[RESULT_CODE]; if (status) { return as_error_set_message(err, status, as_error_string(status)); } return status; }
static as_status as_admin_read_list(aerospike* as, as_error* err, const as_policy_admin* policy, uint8_t* command, uint8_t* end, as_admin_parse_fn parse_fn, as_vector* list) { int timeout_ms = (policy)? policy->timeout : as->config.policies.admin.timeout; if (timeout_ms <= 0) { timeout_ms = DEFAULT_TIMEOUT; } uint64_t deadline_ms = cf_getms() + timeout_ms; as_node* node = as_node_get_random(as->cluster); if (! node) { return as_error_set_message(err, AEROSPIKE_ERR_CLIENT, "Failed to find server node."); } int fd; as_status status = as_node_get_connection(err, node, &fd); if (status) { as_node_release(node); return status; } status = as_admin_send(err, fd, command, end, deadline_ms); if (status) { as_close(fd); as_node_release(node); return status; } status = as_admin_read_blocks(err, fd, deadline_ms, parse_fn, list); if (status) { as_close(fd); as_node_release(node); return status; } as_node_put_connection(node, fd); as_node_release(node); return status; }
static void as_cluster_find_nodes_to_add(as_cluster* cluster, as_vector* /* <as_host> */ friends, as_vector* /* <as_node*> */ nodes_to_add) { as_error err; as_error_init(&err); as_vector addresses; as_vector_inita(&addresses, sizeof(struct sockaddr_in), 5); as_node_info node_info; for (uint32_t i = 0; i < friends->size; i++) { as_host* friend = as_vector_get(friends, i); as_vector_clear(&addresses); as_status status = as_lookup(&err, friend->name, friend->port, &addresses); if (status != AEROSPIKE_OK) { as_log_warn("%s %s", as_error_string(status), err.message); continue; } for (uint32_t i = 0; i < addresses.size; i++) { struct sockaddr_in* addr = as_vector_get(&addresses, i); status = as_lookup_node(cluster, &err, addr, &node_info); if (status == AEROSPIKE_OK) { as_node* node = as_cluster_find_node(cluster->nodes, nodes_to_add, node_info.name); if (node) { // Duplicate node name found. This usually occurs when the server // services list contains both internal and external IP addresses // for the same node. Add new host to list of alias filters // and do not add new node. as_close(node_info.fd); as_address* a = as_node_get_address_full(node); as_log_info("Node %s:%d already exists with nodeid %s and address %s:%d", friend->name, friend->port, node->name, a->name, (int)cf_swap_from_be16(a->addr.sin_port)); node->friends++; as_node_add_address(node, friend, addr); continue; } node = as_node_create(cluster, friend, addr, &node_info); as_address* a = as_node_get_address_full(node); as_log_info("Add node %s %s:%d", node_info.name, a->name, (int)cf_swap_from_be16(a->addr.sin_port)); as_vector_append(nodes_to_add, &node); } else { as_log_warn("Failed to connect to friend %s:%d. %s %s", friend->name, friend->port, as_error_string(status), err.message); } }
static as_status as_cluster_seed_nodes(as_cluster* cluster, as_error* err, bool enable_warnings) { // Add all nodes at once to avoid copying entire array multiple times. as_vector nodes_to_add; as_vector_inita(&nodes_to_add, sizeof(as_node*), 64); as_vector addresses; as_vector_inita(&addresses, sizeof(struct sockaddr_in), 5); as_node_info node_info; as_error error_local; as_error_init(&error_local); // AEROSPIKE_ERR_TIMEOUT doesn't come with a message; make sure it's initialized. as_status status = AEROSPIKE_OK; as_seeds* seeds = as_seeds_reserve(cluster); for (uint32_t i = 0; i < seeds->size; i++) { as_seed* seed = &seeds->array[i]; as_vector_clear(&addresses); status = as_lookup(&error_local, seed->name, seed->port, &addresses); if (status != AEROSPIKE_OK) { if (enable_warnings) { as_log_warn("Failed to lookup %s:%d. %s %s", seed->name, seed->port, as_error_string(status), error_local.message); } continue; } for (uint32_t i = 0; i < addresses.size; i++) { struct sockaddr_in* addr = as_vector_get(&addresses, i); status = as_lookup_node(cluster, &error_local, addr, &node_info); if (status == AEROSPIKE_OK) { as_host host; if (as_strncpy(host.name, seed->name, sizeof(host.name))) { as_log_warn("Hostname has been truncated: %s", host.name); } host.port = seed->port; as_node* node = as_cluster_find_node_in_vector(&nodes_to_add, node_info.name); if (node) { as_close(node_info.fd); as_node_add_address(node, &host, addr); } else { node = as_node_create(cluster, &host, addr, &node_info); as_address* a = as_node_get_address_full(node); as_log_info("Add node %s %s:%d", node->name, a->name, (int)cf_swap_from_be16(a->addr.sin_port)); as_vector_append(&nodes_to_add, &node); } } else { if (enable_warnings) { as_log_warn("Failed to connect to seed %s:%d. %s %s", seed->name, seed->port, as_error_string(status), error_local.message); } } } } as_seeds_release(seeds); if (nodes_to_add.size > 0) { as_cluster_add_nodes(cluster, &nodes_to_add); status = AEROSPIKE_OK; } else { status = as_error_set_message(err, AEROSPIKE_ERR_CLIENT, "Failed to seed cluster"); } as_vector_destroy(&nodes_to_add); as_vector_destroy(&addresses); return status; }
static as_status as_lookup_node(as_cluster* cluster, as_error* err, struct sockaddr_in* addr, as_node_info* node_info) { uint64_t deadline = as_socket_deadline(cluster->conn_timeout_ms); int fd; as_status status = as_info_create_socket(cluster, err, addr, deadline, &fd); if (status) { return status; } char* response = 0; status = as_info_command(err, fd, "node\nfeatures\n", true, deadline, 0, &response); if (status) { as_close(fd); return status; } as_vector values; as_vector_inita(&values, sizeof(as_name_value), 2); as_info_parse_multi_response(response, &values); if (values.size != 2) { goto Error; } as_name_value* nv = as_vector_get(&values, 0); char* node_name = nv->value; if (node_name == 0 || *node_name == 0) { goto Error; } as_strncpy(node_info->name, node_name, AS_NODE_NAME_SIZE); node_info->fd = fd; nv = as_vector_get(&values, 1); char* features = nv->value; if (features == 0) { goto Error; } char* begin = features; char* end = begin; uint8_t has_batch_index = 0; uint8_t has_replicas_all = 0; uint8_t has_double = 0; uint8_t has_geo = 0; while (*begin && ! (has_batch_index && has_replicas_all && has_double && has_geo)) { while (*end) { if (*end == ';') { *end++ = 0; break; } end++; } if (strcmp(begin, "batch-index") == 0) { has_batch_index = 1; } if (strcmp(begin, "replicas-all") == 0) { has_replicas_all = 1; } if (strcmp(begin, "float") == 0) { has_double = 1; } if (strcmp(begin, "geo") == 0) { has_geo = 1; } begin = end; } node_info->has_batch_index = has_batch_index; node_info->has_replicas_all = has_replicas_all; node_info->has_double = has_double; node_info->has_geo = has_geo; cf_free(response); return AEROSPIKE_OK; Error: { char addr_name[INET_ADDRSTRLEN]; as_socket_address_name(addr, addr_name); as_error_update(err, status, "Invalid node info response from %s: %s", addr_name, response); cf_free(response); as_close(fd); return AEROSPIKE_ERR_CLIENT; } }
as_status as_command_execute(as_cluster* cluster, as_error * err, as_command_node* cn, uint8_t* command, size_t command_len, uint32_t timeout_ms, uint32_t retry, as_parse_results_fn parse_results_fn, void* parse_results_data ) { uint64_t deadline_ms = as_socket_deadline(timeout_ms); uint32_t sleep_between_retries_ms = 0; uint32_t failed_nodes = 0; uint32_t failed_conns = 0; uint32_t iterations = 0; bool release_node; // Execute command until successful, timed out or maximum iterations have been reached. while (true) { as_node* node; if (cn->node) { node = cn->node; release_node = false; } else { node = as_node_get(cluster, cn->ns, cn->digest, cn->write, cn->replica); release_node = true; } if (!node) { failed_nodes++; sleep_between_retries_ms = 10; goto Retry; } int fd; as_status status = as_node_get_connection(err, node, deadline_ms, &fd); if (status) { if (release_node) { as_node_release(node); } failed_conns++; sleep_between_retries_ms = 1; goto Retry; } // Send command. status = as_socket_write_deadline(err, fd, command, command_len, deadline_ms); if (status) { // Socket errors are considered temporary anomalies. Retry. // Close socket to flush out possible garbage. Do not put back in pool. as_close(fd); if (release_node) { as_node_release(node); } sleep_between_retries_ms = 0; goto Retry; } // Parse results returned by server. status = parse_results_fn(err, fd, deadline_ms, parse_results_data); if (status == AEROSPIKE_OK) { // Reset error code if retry had occurred. if (iterations > 0) { as_error_reset(err); } } else { switch (status) { // Retry on timeout. case AEROSPIKE_ERR_TIMEOUT: as_close(fd); if (release_node) { as_node_release(node); } sleep_between_retries_ms = 0; goto Retry; // Close socket on errors that can leave unread data in socket. case AEROSPIKE_ERR_QUERY_ABORTED: case AEROSPIKE_ERR_SCAN_ABORTED: case AEROSPIKE_ERR_CLIENT_ABORT: case AEROSPIKE_ERR_CLIENT: as_close(fd); if (release_node) { as_node_release(node); } err->code = status; return status; default: err->code = status; break; } } // Put connection back in pool. as_node_put_connection(node, fd, cluster->conn_queue_size); // Release resources. if (release_node) { as_node_release(node); } return status; Retry: // Check if max retries reached. if (++iterations > retry) { break; } // Check for client timeout. if (deadline_ms > 0) { int remaining_ms = (int)(deadline_ms - cf_getms() - sleep_between_retries_ms); if (remaining_ms <= 0) { break; } // Reset timeout in send buffer (destined for server). *(uint32_t*)(command + 22) = cf_swap_to_be32(remaining_ms); } if (sleep_between_retries_ms > 0) { // Sleep before trying again. usleep(sleep_between_retries_ms * 1000); } } return as_error_update(err, AEROSPIKE_ERR_TIMEOUT, "Client timeout: timeout=%d iterations=%u failedNodes=%u failedConns=%u", timeout_ms, iterations, failed_nodes, failed_conns); }