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_cluster* cluster = as->cluster; as_node* node = as_node_get_random(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, deadline_ms, &fd); if (status) { as_node_release(node); return status; } status = as_admin_send(err, fd, buffer, end, deadline_ms); if (status) { as_node_close_connection(node, fd); as_node_release(node); return status; } status = as_socket_read_deadline(err, fd, buffer, HEADER_SIZE, deadline_ms); if (status) { as_node_close_connection(node, 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; }
/** * Scan the records in the specified namespace and set for a single node. * * The callback function will be called for each record scanned. When all records have * been scanned, then callback will be called with a NULL value for the record. * * ~~~~~~~~~~{.c} * char* node_names = NULL; * int n_nodes = 0; * as_cluster_get_node_names(as->cluster, &n_nodes, &node_names); * * if (n_nodes <= 0) * return <error>; * * as_scan scan; * as_scan_init(&scan, "test", "demo"); * * if (aerospike_scan_node(&as, &err, NULL, &scan, node_names[0], callback, NULL) != AEROSPIKE_OK ) { * fprintf(stderr, "error(%d) %s at [%s:%d]", err.code, err.message, err.file, err.line); * } * * free(node_names); * as_scan_destroy(&scan); * ~~~~~~~~~~ * * @param as The aerospike instance to use for this operation. * @param err The as_error to be populated if an error occurs. * @param policy The policy to use for this operation. If NULL, then the default policy will be used. * @param scan The scan to execute against the cluster. * @param node_name The node name to scan. * @param callback The function to be called for each record scanned. * @param udata User-data to be passed to the callback. * * @return AEROSPIKE_OK on success. Otherwise an error occurred. */ as_status aerospike_scan_node( aerospike * as, as_error * err, const as_policy_scan * policy, const as_scan * scan, const char* node_name, aerospike_scan_foreach_callback callback, void * udata) { as_error_reset(err); if (! policy) { policy = &as->config.policies.scan; } // Retrieve node. as_node* node = as_node_get_by_name(as->cluster, node_name); if (! node) { return as_error_update(err, AEROSPIKE_ERR_PARAM, "Invalid node name: %s", node_name); } // Create scan command uint64_t task_id = cf_get_rand64() / 2; as_buffer argbuffer; uint16_t n_fields = 0; size_t size = as_scan_command_size(scan, &n_fields, &argbuffer); uint8_t* cmd = as_command_init(size); size = as_scan_command_init(cmd, policy, scan, task_id, n_fields, &argbuffer); // Initialize task. uint32_t error_mutex = 0; as_scan_task task; task.node = node; task.cluster = as->cluster; task.policy = policy; task.scan = scan; task.callback = callback; task.udata = udata; task.err = err; task.complete_q = 0; task.error_mutex = &error_mutex; task.task_id = task_id; task.cmd = cmd; task.cmd_size = size; // Run scan. as_status status = as_scan_command_execute(&task); // Free command memory. as_command_free(cmd, size); // Release node. as_node_release(node); // If completely successful, make the callback that signals completion. if (callback && status == AEROSPIKE_OK) { callback(NULL, udata); } 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 = as_socket_deadline(timeout_ms); as_cluster* cluster = as->cluster; as_node* node = as_node_get_random(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, deadline_ms, &fd); if (status) { as_node_release(node); return status; } status = as_admin_send(err, fd, command, end, deadline_ms); if (status) { as_node_close_connection(node, fd); as_node_release(node); return status; } status = as_admin_read_blocks(err, fd, deadline_ms, parse_fn, list); if (status) { as_node_close_connection(node, fd); as_node_release(node); return status; } as_node_put_connection(node, fd); as_node_release(node); return status; }
static int as_read_users(aerospike* as, const as_policy_admin* policy, uint8_t* buffer, uint8_t* end, as_vector* /*<as_user_roles*>*/ users) { 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 CITRUSLEAF_FAIL_CLIENT; } int fd; int status = as_node_get_connection(node, &fd); if (status) { as_node_release(node); return status; } if (as_send(fd, buffer, end, deadline_ms, timeout_ms)) { cf_close(fd); as_node_release(node); return CITRUSLEAF_FAIL_TIMEOUT; } status = as_read_user_blocks(fd, buffer, deadline_ms, timeout_ms, users); if (status >= 0) { as_node_put_connection(node, fd); } else { cf_close(fd); } as_node_release(node); return status; }
static int as_execute(aerospike* as, const as_policy_admin* policy, uint8_t* buffer, uint8_t* end) { 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 CITRUSLEAF_FAIL_CLIENT; } int fd; int status = as_node_get_connection(node, &fd); if (status) { as_node_release(node); return status; } if (as_send(fd, buffer, end, deadline_ms, timeout_ms)) { cf_close(fd); as_node_release(node); return CITRUSLEAF_FAIL_TIMEOUT; } if (cf_socket_read_timeout(fd, buffer, HEADER_SIZE, deadline_ms, timeout_ms)) { cf_close(fd); as_node_release(node); return CITRUSLEAF_FAIL_TIMEOUT; } as_node_put_connection(node, fd); as_node_release(node); return buffer[RESULT_CODE]; }
void as_event_command_free(as_event_command* cmd) { as_node_release(cmd->node); as_cluster* cluster = cmd->cluster; bool destroy; ck_pr_dec_32_zero(&cluster->async_pending, &destroy); // Only destroy cluster if cluster was closed and there are no pending async commands. if (destroy) { as_cluster_destroy(cluster); } if (cmd->free_buf) { cf_free(cmd->buf); } cf_free(cmd); }
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); }
static as_status as_scan_generic( aerospike* as, as_error* err, const as_policy_scan* policy, const as_scan* scan, aerospike_scan_foreach_callback callback, void* udata, uint64_t* task_id_ptr) { as_error_reset(err); if (! policy) { policy = &as->config.policies.scan; } as_cluster* cluster = as->cluster; as_nodes* nodes = as_nodes_reserve(cluster); uint32_t n_nodes = nodes->size; if (n_nodes == 0) { as_nodes_release(nodes); return as_error_set_message(err, AEROSPIKE_ERR_SERVER, "Scan command failed because cluster is empty."); } // Reserve each node in cluster. for (uint32_t i = 0; i < n_nodes; i++) { as_node_reserve(nodes->array[i]); } uint64_t task_id; if (task_id_ptr) { if (*task_id_ptr == 0) { *task_id_ptr = cf_get_rand64() / 2; } task_id = *task_id_ptr; } else { task_id = cf_get_rand64() / 2; } // Create scan command as_buffer argbuffer; uint16_t n_fields = 0; size_t size = as_scan_command_size(scan, &n_fields, &argbuffer); uint8_t* cmd = as_command_init(size); size = as_scan_command_init(cmd, policy, scan, task_id, n_fields, &argbuffer); // Initialize task. uint32_t error_mutex = 0; as_scan_task task; task.cluster = as->cluster; task.policy = policy; task.scan = scan; task.callback = callback; task.udata = udata; task.err = err; task.error_mutex = &error_mutex; task.task_id = task_id; task.cmd = cmd; task.cmd_size = size; as_status status = AEROSPIKE_OK; if (scan->concurrent) { uint32_t n_wait_nodes = n_nodes; task.complete_q = cf_queue_create(sizeof(as_scan_complete_task), true); // Run node scans in parallel. for (uint32_t i = 0; i < n_nodes; i++) { // Stack allocate task for each node. It should be fine since the task // only needs to be valid within this function. as_scan_task* task_node = alloca(sizeof(as_scan_task)); memcpy(task_node, &task, sizeof(as_scan_task)); task_node->node = nodes->array[i]; int rc = as_thread_pool_queue_task(&cluster->thread_pool, as_scan_worker, task_node); if (rc) { // Thread could not be added. Abort entire scan. if (ck_pr_fas_32(task.error_mutex, 1) == 0) { status = as_error_update(task.err, AEROSPIKE_ERR_CLIENT, "Failed to add scan thread: %d", rc); } // Reset node count to threads that were run. n_wait_nodes = i; break; } } // Wait for tasks to complete. for (uint32_t i = 0; i < n_wait_nodes; i++) { as_scan_complete_task complete; cf_queue_pop(task.complete_q, &complete, CF_QUEUE_FOREVER); if (complete.result != AEROSPIKE_OK && status == AEROSPIKE_OK) { status = complete.result; } } // Release temporary queue. cf_queue_destroy(task.complete_q); } else { task.complete_q = 0; // Run node scans in series. for (uint32_t i = 0; i < n_nodes && status == AEROSPIKE_OK; i++) { task.node = nodes->array[i]; status = as_scan_command_execute(&task); } } // Release each node in cluster. for (uint32_t i = 0; i < n_nodes; i++) { as_node_release(nodes->array[i]); } // Release nodes array. as_nodes_release(nodes); // Free command memory. as_command_free(cmd, size); // If user aborts query, command is considered successful. if (status == AEROSPIKE_ERR_CLIENT_ABORT) { status = AEROSPIKE_OK; } // If completely successful, make the callback that signals completion. if (callback && status == AEROSPIKE_OK) { callback(NULL, udata); } return status; }