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_callback(struct ev_loop* loop, ev_io* watcher, int revents)
{
	if (revents & EV_READ) {
		as_event_connection* conn = watcher->data;
		as_event_command* cmd;
		
		if (conn->pipeline) {
			as_pipe_connection* pipe = (as_pipe_connection*)conn;
			
			if (pipe->writer && cf_ll_size(&pipe->readers) == 0) {
				// Authentication response will only have a writer.
				cmd = pipe->writer;
			}
			else {
				// Next response is at head of reader linked list.
				cf_ll_element* link = cf_ll_get_head(&pipe->readers);
				
				if (link) {
					cmd = as_pipe_link_to_command(link);
				}
				else {
					as_log_debug("Pipeline read event ignored");
					return;
				}
			}
		}
		else {
			cmd = ((as_async_connection*)conn)->cmd;
		}
		as_ev_command_read(cmd);
	}
	else if (revents & EV_WRITE) {
		as_event_connection* conn = watcher->data;
		
		as_event_command* cmd = conn->pipeline ?
			((as_pipe_connection*)conn)->writer :
			((as_async_connection*)conn)->cmd;
		
		int ret = as_ev_write(cmd);
		
		if (ret == AS_EVENT_WRITE_COMPLETE) {
			// Done with write. Register for read.
			if (cmd->state == AS_ASYNC_STATE_AUTH_WRITE) {
				as_event_set_auth_read_header(cmd);
				as_ev_watch_read(cmd);
			}
			else {
				as_ev_command_read_start(cmd);
			}
		}
	}
	else if (revents & EV_ERROR) {
		as_log_error("Async error occurred: %d", revents);
	}
	else {
		as_log_warn("Unknown event received: %d", revents);
	}
}
bool
as_event_create_loop(as_event_loop* event_loop)
{
	event_loop->loop = ev_loop_new(EVFLAG_AUTO);
	
	if (! event_loop->loop) {
		as_log_error("Failed to create event loop");
		return false;
	}
	as_ev_init_loop(event_loop);
	
	return pthread_create(&event_loop->thread, NULL, as_ev_worker, event_loop->loop) == 0;
}
Exemple #4
0
/**
 *	Compute the digest value.
 */
as_digest * as_key_digest(as_key * key)
{
	as_error err;
	as_status status = as_key_set_digest(&err, key);
	
	if (status == AEROSPIKE_OK) {
		return &key->digest;
	}
	else {
		as_log_error(err.message);
		return NULL;
	}
}
static void*
as_uv_worker(void* udata)
{
	as_uv_thread_data* data = udata;
	as_event_loop* event_loop = data->event_loop;
	
	event_loop->loop = cf_malloc(sizeof(uv_loop_t));
	
	if (! event_loop->loop) {
		as_log_error("Failed to create event loop");
		return 0;
	}
	
	event_loop->wakeup = cf_malloc(sizeof(uv_async_t));
	
	if (! event_loop->wakeup) {
		as_log_error("Failed to create wakeup");
		return 0;
	}

	event_loop->wakeup->data = event_loop;

	uv_loop_init(event_loop->loop);
	uv_async_init(event_loop->loop, event_loop->wakeup, as_uv_wakeup);
	as_monitor_notify(&data->monitor);
	
	uv_run(event_loop->loop, UV_RUN_DEFAULT);
	
	int status = uv_loop_close(event_loop->loop);

	if (status) {
		as_log_warn("uv_loop_close failed: %s", uv_strerror(status));
	}
	cf_free(event_loop->loop);
	return NULL;
}
as_event_loop*
as_event_set_external_loop(void* loop)
{
    uint32_t current = ck_pr_faa_32(&as_event_loop_size, 1);

    if (current >= as_event_loop_capacity) {
        as_log_error("Failed to add external loop. Capacity is %u", as_event_loop_capacity);
        return 0;
    }

    as_event_loop* event_loop = &as_event_loops[current];
    event_loop->loop = loop;
    pthread_mutex_init(&event_loop->lock, 0);
    event_loop->thread = pthread_self();  // Current thread must be same as event loop thread!
    event_loop->index = current;
    as_queue_init(&event_loop->pipe_cb_queue, sizeof(as_queued_pipe_cb), AS_EVENT_QUEUE_INITIAL_CAPACITY);
    event_loop->pipe_cb_calling = false;
    as_event_register_external_loop(event_loop);
    return event_loop;
}
void
as_event_close_loops()
{
    if (! as_event_loops) {
        return;
    }

    pthread_t self = pthread_self();
    bool status = true;

    // Close or send close signal to all event loops.
    // This will eventually release resources associated with each event loop.
    for (uint32_t i = 0; i < as_event_loop_size; i++) {
        as_event_loop* event_loop = &as_event_loops[i];

        if (event_loop->thread == self) {
            // Can close event loop immediately.
            as_event_close_loop(event_loop);
        }
        else {
            // Queue close command to event loop.
            if (! as_event_send_close_loop(event_loop)) {
                as_log_error("Failed to send stop command to event loop");
                status = false;
            }
        }
    }

    // Only join threads if event loops were created internally.
    // It is not possible to join on externally created event loop threads.
    if (as_event_threads_created && status) {
        for (uint32_t i = 0; i < as_event_loop_size; i++) {
            as_event_loop* event_loop = &as_event_loops[i];
            pthread_join(event_loop->thread, NULL);
        }

        cf_free(as_event_loops);
        as_event_loops = NULL;
        as_event_loop_size = 0;
    }
}
uint8_t*
as_command_parse_key(uint8_t* p, uint32_t n_fields, as_key* key)
{
    uint32_t len;
    uint32_t size;

    for (uint32_t i = 0; i < n_fields; i++) {
        len = cf_swap_from_be32(*(uint32_t*)p) - 1;
        p += 4;

        switch (*p++) {
        case AS_FIELD_DIGEST:
            size = (len < AS_DIGEST_VALUE_SIZE) ? len : AS_DIGEST_VALUE_SIZE;
            key->digest.init = true;
            memcpy(key->digest.value, p, size);
            break;

        case AS_FIELD_NAMESPACE:
            size = (len < (AS_NAMESPACE_MAX_SIZE-1)) ? len : (AS_NAMESPACE_MAX_SIZE-1);
            memcpy(key->ns, p, size);
            key->ns[size] = 0;
            break;

        case AS_FIELD_SETNAME:
            size = (len < (AS_SET_MAX_SIZE-1)) ? len : (AS_SET_MAX_SIZE-1);
            memcpy(key->set, p, size);
            key->set[size] = 0;
            break;

        case AS_FIELD_KEY:
            len--;
            uint8_t type = *p++;

            switch (type) {
            case AS_BYTES_INTEGER: {
                int64_t value;
                if (as_command_bytes_to_int(p, len, &value) == 0) {
                    as_integer_init((as_integer*)&key->value, value);
                    key->valuep = &key->value;
                }
                break;
            }
            case AS_BYTES_DOUBLE: {
                double value = cf_swap_from_big_float64(*(double*)p);
                as_double_init((as_double*)&key->value, value);
                key->valuep = &key->value;
                break;
            }
            case AS_BYTES_STRING: {
                char* value = malloc(len+1);
                memcpy(value, p, len);
                value[len] = 0;
                as_string_init_wlen((as_string*)&key->value, value, len, true);
                key->valuep = &key->value;
                break;
            }
            case AS_BYTES_BLOB: {
                void* value = malloc(len);
                memcpy(value, p, len);
                as_bytes_init_wrap((as_bytes*)&key->value, (uint8_t*)value, len, true);
                key->valuep = &key->value;
                break;
            }
            default: {
                as_log_error("Invalid key type: %d", type);
                break;
            }
            }
            break;
        }
        p += len;
    }
    return p;
}