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; }
/** * 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; }