Exemplo n.º 1
0
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;
}
Exemplo n.º 3
0
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;
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 5
0
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];
}
Exemplo n.º 6
0
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);
}
Exemplo n.º 7
0
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;
}