void as_event_executor_complete(as_event_command* cmd) { as_event_response_complete(cmd); as_event_executor* executor = cmd->udata; pthread_mutex_lock(&executor->lock); bool notify = executor->valid; executor->count++; bool complete = executor->count == executor->max; int next = executor->count + executor->max_concurrent - 1; bool start_new_command = next < executor->max && executor->valid; pthread_mutex_unlock(&executor->lock); if (complete) { // All commands completed. if (notify) { executor->complete_fn(executor, 0); } as_event_executor_destroy(executor); } else { // Determine if a new command needs to be started. if (start_new_command) { as_error err; as_status status = as_event_command_execute(executor->commands[next], &err); if (status != AEROSPIKE_OK) { as_event_executor_error(executor, &err, next); } } } as_event_command_release(cmd); }
static as_status as_scan_async( aerospike* as, as_error* err, const as_policy_scan* policy, const as_scan* scan, uint64_t* scan_id, as_async_scan_listener listener, void* udata, as_event_loop* event_loop, as_node** nodes, uint32_t n_nodes ) { if (! policy) { policy = &as->config.policies.scan; } // Assign task id. uint64_t task_id; if (scan_id) { if (*scan_id == 0) { *scan_id = as_random_get_uint64(); } task_id = *scan_id; } else { task_id = as_random_get_uint64(); } bool daisy_chain = ! (scan->concurrent || n_nodes == 1); // Scan will be split up into a command for each node. // Allocate scan data shared by each command. as_async_scan_executor* executor = cf_malloc(sizeof(as_async_scan_executor)); as_event_executor* exec = &executor->executor; pthread_mutex_init(&exec->lock, NULL); exec->commands = cf_malloc(sizeof(as_event_command*) * n_nodes); exec->event_loop = as_event_assign(event_loop); exec->complete_fn = as_scan_complete_async; exec->udata = udata; exec->err = NULL; exec->ns = NULL; exec->cluster_key = 0; exec->max_concurrent = daisy_chain ? 1 : n_nodes; exec->max = n_nodes; exec->count = 0; exec->queued = 0; exec->notify = true; exec->valid = true; executor->listener = listener; // Create scan command buffer. as_buffer argbuffer; uint16_t n_fields = 0; uint32_t predexp_sz = 0; size_t size = as_scan_command_size(scan, &n_fields, &argbuffer, &predexp_sz); uint8_t* cmd_buf = as_command_buffer_init(size); size = as_scan_command_init(cmd_buf, policy, scan, task_id, n_fields, &argbuffer, predexp_sz); // Allocate enough memory to cover, then, round up memory size in 8KB increments to allow socket // read to reuse buffer. size_t s = (sizeof(as_async_scan_command) + size + AS_AUTHENTICATION_MAX_SIZE + 8191) & ~8191; // Create all scan commands. for (uint32_t i = 0; i < n_nodes; i++) { as_event_command* cmd = cf_malloc(s); cmd->total_deadline = policy->base.total_timeout; cmd->socket_timeout = policy->base.socket_timeout; cmd->max_retries = policy->base.max_retries; cmd->iteration = 0; cmd->replica = AS_POLICY_REPLICA_MASTER; cmd->event_loop = exec->event_loop; cmd->cluster = as->cluster; cmd->node = nodes[i]; cmd->ns = NULL; cmd->partition = NULL; cmd->udata = executor; // Overload udata to be the executor. cmd->parse_results = as_scan_parse_records_async; cmd->pipe_listener = NULL; cmd->buf = ((as_async_scan_command*)cmd)->space; cmd->write_len = (uint32_t)size; cmd->read_capacity = (uint32_t)(s - size - sizeof(as_async_scan_command)); cmd->type = AS_ASYNC_TYPE_SCAN; cmd->state = AS_ASYNC_STATE_UNREGISTERED; cmd->flags = AS_ASYNC_FLAGS_MASTER; cmd->flags2 = scan->deserialize_list_map ? AS_ASYNC_FLAGS2_DESERIALIZE : 0; memcpy(cmd->buf, cmd_buf, size); exec->commands[i] = cmd; } // Free command buffer. as_command_buffer_free(cmd_buf, size); if (policy->fail_on_cluster_change && (nodes[0]->features & AS_FEATURES_CLUSTER_STABLE)) { // Verify migrations are not in progress. return as_query_validate_begin_async(exec, scan->ns, err); } // Run scan commands. for (uint32_t i = 0; i < exec->max_concurrent; i++) { exec->queued++; as_event_command* cmd = exec->commands[i]; as_status status = as_event_command_execute(cmd, err); if (status != AEROSPIKE_OK) { as_event_executor_cancel(exec, i); return status; } } return AEROSPIKE_OK; }