static void as_uv_connected(uv_connect_t* req, int status) { if (uv_is_closing((uv_handle_t*)req->handle)) { return; } as_event_command* cmd = req->data; if (status == 0) { if (cmd->cluster->user) { as_uv_auth_write_start(cmd, req->handle); } else { as_uv_command_write_start(cmd, req->handle); } } else if (status != UV_ECANCELED) { as_node* node = cmd->node; as_address* primary = as_vector_get(&node->addresses, node->address_index); as_error err; as_error_update(&err, AEROSPIKE_ERR_ASYNC_CONNECTION, "Failed to connect: %s %s:%d", node->name, primary->name, (int)cf_swap_from_be16(primary->addr.sin_port)); as_uv_connect_error(cmd, &err); } }
int citrusleaf_info_auth(as_cluster *cluster, char *hostname, short port, char *names, char **values, int timeout_ms) { int rv = -1; as_vector sockaddr_in_v; as_vector_inita(&sockaddr_in_v, sizeof(struct sockaddr_in), 5); if (! as_lookup(NULL, hostname, port, true, &sockaddr_in_v)) { goto Done; } for (uint32_t i = 0; i < sockaddr_in_v.size; i++) { struct sockaddr_in* sa_in = as_vector_get(&sockaddr_in_v, i); if (0 == citrusleaf_info_host_auth(cluster, sa_in, names, values, timeout_ms, true, /* check bounds */ true)) { rv = 0; goto Done; } } Done: as_vector_destroy(&sockaddr_in_v); return(rv); }
static as_node* as_cluster_find_node(as_cluster* cluster, in_addr_t addr, in_port_t port) { as_nodes* nodes = (as_nodes*)cluster->nodes; as_node* node; as_vector* addresses; as_address* address; struct sockaddr_in* sockaddr; in_port_t port_be = cf_swap_to_be16(port); for (uint32_t i = 0; i < nodes->size; i++) { node = nodes->array[i]; addresses = &node->addresses; for (uint32_t j = 0; j < addresses->size; j++) { address = as_vector_get(addresses, j); sockaddr = &address->addr; if (sockaddr->sin_addr.s_addr == addr && sockaddr->sin_port == port_be) { return node; } } } return 0; }
static void as_free_users(as_vector* users, int offset) { for (uint32_t i = offset; i < users->size; i++) { as_user_roles* item = as_vector_get(users, i); cf_free(item); } as_vector_destroy(users); }
static int as_node_create_connection(as_node* node, int* fd) { // Create a non-blocking socket. *fd = cf_socket_create_nb(); if (*fd == -1) { // Local problem - socket create failed. cf_debug("Socket create failed for %s", node->name); return CITRUSLEAF_FAIL_CLIENT; } // Try primary address. as_address* primary = as_vector_get(&node->addresses, node->address_index); if (cf_socket_start_connect_nb(*fd, &primary->addr) == 0) { // Connection started ok - we have our socket. return as_node_authenticate_connection(node, fd); } // Try other addresses. as_vector* addresses = &node->addresses; for (uint32_t i = 0; i < addresses->size; i++) { as_address* address = as_vector_get(addresses, i); // Address points into alias array, so pointer comparison is sufficient. if (address != primary) { if (cf_socket_start_connect_nb(*fd, &address->addr) == 0) { // Replace invalid primary address with valid alias. // Other threads may not see this change immediately. // It's just a hint, not a requirement to try this new address first. cf_debug("Change node address %s %s:%d", node->name, address->name, (int)cf_swap_from_be16(address->addr.sin_port)); ck_pr_store_32(&node->address_index, i); return as_node_authenticate_connection(node, fd); } } } // Couldn't start a connection on any socket address - close the socket. cf_info("Failed to connect: %s %s:%d", node->name, primary->name, (int)cf_swap_from_be16(primary->addr.sin_port)); cf_close(*fd); *fd = -1; return CITRUSLEAF_FAIL_UNAVAILABLE; }
static void as_cluster_find_nodes_to_add(as_cluster* cluster, as_vector* /* <as_host> */ friends, as_vector* /* <as_node*> */ nodes_to_add) { as_error err; as_error_init(&err); as_vector addresses; as_vector_inita(&addresses, sizeof(struct sockaddr_in), 5); as_node_info node_info; for (uint32_t i = 0; i < friends->size; i++) { as_host* friend = as_vector_get(friends, i); as_vector_clear(&addresses); as_status status = as_lookup(&err, friend->name, friend->port, &addresses); if (status != AEROSPIKE_OK) { as_log_warn("%s %s", as_error_string(status), err.message); continue; } for (uint32_t i = 0; i < addresses.size; i++) { struct sockaddr_in* addr = as_vector_get(&addresses, i); status = as_lookup_node(cluster, &err, addr, &node_info); if (status == AEROSPIKE_OK) { as_node* node = as_cluster_find_node(cluster->nodes, nodes_to_add, node_info.name); if (node) { // Duplicate node name found. This usually occurs when the server // services list contains both internal and external IP addresses // for the same node. Add new host to list of alias filters // and do not add new node. as_close(node_info.fd); as_address* a = as_node_get_address_full(node); as_log_info("Node %s:%d already exists with nodeid %s and address %s:%d", friend->name, friend->port, node->name, a->name, (int)cf_swap_from_be16(a->addr.sin_port)); node->friends++; as_node_add_address(node, friend, addr); continue; } node = as_node_create(cluster, friend, addr, &node_info); as_address* a = as_node_get_address_full(node); as_log_info("Add node %s %s:%d", node_info.name, a->name, (int)cf_swap_from_be16(a->addr.sin_port)); as_vector_append(nodes_to_add, &node); } else { as_log_warn("Failed to connect to friend %s:%d. %s %s", friend->name, friend->port, as_error_string(status), err.message); } }
static void as_uv_connect(as_event_command* cmd) { int fd = as_event_create_socket(cmd); if (fd < 0) { return; } as_event_connection* conn = cmd->conn; uv_tcp_t* socket = &conn->socket; int status = uv_tcp_init(cmd->event_loop->loop, socket); if (status) { as_error err; as_error_update(&err, AEROSPIKE_ERR_ASYNC_CONNECTION, "uv_tcp_init failed: %s", uv_strerror(status)); // Call standard event connection error handler because as_uv_connect_error() requires that // uv_tcp_init() has already succeeded. as_event_connect_error(cmd, &err, fd); return; } // Define externally created fd to uv_tcp_t. status = uv_tcp_open(socket, fd); if (status) { as_error err; as_error_update(&err, AEROSPIKE_ERR_ASYNC_CONNECTION, "uv_tcp_open failed: %s", uv_strerror(status)); // Close fd directly because we created it outside of libuv and uv_tcp_t does not know about it here. close(fd); as_uv_connect_error(cmd, &err); return; } socket->data = conn; conn->req.connect.data = cmd; as_node* node = cmd->node; as_address* primary = as_vector_get(&node->addresses, node->address_index); status = uv_tcp_connect(&conn->req.connect, socket, (struct sockaddr*)&primary->addr, as_uv_connected); if (status) { as_error err; as_error_update(&err, AEROSPIKE_ERR_ASYNC_CONNECTION, "uv_tcp_connect failed: %s", uv_strerror(status)); as_uv_connect_error(cmd, &err); } }
/** * Send an info request to a specific host. The response must be freed by the caller on success. * * ~~~~~~~~~~{.c} * char * res = NULL; * if ( aerospike_info_host(&as, &err, NULL, "127.0.0.1", 3000, "info", &res) != AEROSPIKE_OK ) { * // handle error * } * else { * // handle response * free(res); * res = NULL; * } * ~~~~~~~~~~ * * @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 addr The IP address or hostname to send the request to. * @param port The port to send the request to. * @param req The info request to send. * @param res The response from the node. The response will be a NULL terminated string, allocated by the function, and must be freed by the caller. * * @return AEROSPIKE_OK on success. Otherwise an error. * * @ingroup info_operations */ as_status aerospike_info_host( aerospike * as, as_error * err, const as_policy_info * policy, const char * addr, uint16_t port, const char * req, char ** res) { as_error_reset(err); if (! policy) { policy = &as->config.policies.info; } as_vector sockaddr_in_v; as_vector_inita(&sockaddr_in_v, sizeof(struct sockaddr_in), 5); as_status status = as_lookup(NULL, err, (char*)addr, port, &sockaddr_in_v); if (status) { as_vector_destroy(&sockaddr_in_v); return status; } uint64_t deadline = as_socket_deadline(policy->timeout); as_cluster* cluster = as->cluster; status = AEROSPIKE_ERR_CLUSTER; bool loop = true; for (uint32_t i = 0; i < sockaddr_in_v.size && loop; i++) { struct sockaddr_in* sa_in = as_vector_get(&sockaddr_in_v, i); status = as_info_command_host(cluster, err, sa_in, (char*)req, policy->send_as_is, deadline, res); switch (status) { case AEROSPIKE_OK: case AEROSPIKE_ERR_TIMEOUT: case AEROSPIKE_ERR_INDEX_FOUND: case AEROSPIKE_ERR_INDEX_NOT_FOUND: loop = false; break; default: break; } } as_vector_destroy(&sockaddr_in_v); return status; }
static as_status as_cluster_seed_nodes(as_cluster* cluster, as_error* err, bool enable_warnings) { // Add all nodes at once to avoid copying entire array multiple times. as_vector nodes_to_add; as_vector_inita(&nodes_to_add, sizeof(as_node*), 64); as_vector addresses; as_vector_inita(&addresses, sizeof(struct sockaddr_in), 5); as_node_info node_info; as_error error_local; as_error_init(&error_local); // AEROSPIKE_ERR_TIMEOUT doesn't come with a message; make sure it's initialized. as_status status = AEROSPIKE_OK; as_seeds* seeds = as_seeds_reserve(cluster); for (uint32_t i = 0; i < seeds->size; i++) { as_seed* seed = &seeds->array[i]; as_vector_clear(&addresses); status = as_lookup(&error_local, seed->name, seed->port, &addresses); if (status != AEROSPIKE_OK) { if (enable_warnings) { as_log_warn("Failed to lookup %s:%d. %s %s", seed->name, seed->port, as_error_string(status), error_local.message); } continue; } for (uint32_t i = 0; i < addresses.size; i++) { struct sockaddr_in* addr = as_vector_get(&addresses, i); status = as_lookup_node(cluster, &error_local, addr, &node_info); if (status == AEROSPIKE_OK) { as_host host; if (as_strncpy(host.name, seed->name, sizeof(host.name))) { as_log_warn("Hostname has been truncated: %s", host.name); } host.port = seed->port; as_node* node = as_cluster_find_node_in_vector(&nodes_to_add, node_info.name); if (node) { as_close(node_info.fd); as_node_add_address(node, &host, addr); } else { node = as_node_create(cluster, &host, addr, &node_info); as_address* a = as_node_get_address_full(node); as_log_info("Add node %s %s:%d", node->name, a->name, (int)cf_swap_from_be16(a->addr.sin_port)); as_vector_append(&nodes_to_add, &node); } } else { if (enable_warnings) { as_log_warn("Failed to connect to seed %s:%d. %s %s", seed->name, seed->port, as_error_string(status), error_local.message); } } } } as_seeds_release(seeds); if (nodes_to_add.size > 0) { as_cluster_add_nodes(cluster, &nodes_to_add); status = AEROSPIKE_OK; } else { status = as_error_set_message(err, AEROSPIKE_ERR_CLIENT, "Failed to seed cluster"); } as_vector_destroy(&nodes_to_add); as_vector_destroy(&addresses); return status; }
static as_status as_lookup_node(as_cluster* cluster, as_error* err, struct sockaddr_in* addr, as_node_info* node_info) { uint64_t deadline = as_socket_deadline(cluster->conn_timeout_ms); int fd; as_status status = as_info_create_socket(cluster, err, addr, deadline, &fd); if (status) { return status; } char* response = 0; status = as_info_command(err, fd, "node\nfeatures\n", true, deadline, 0, &response); if (status) { as_close(fd); return status; } as_vector values; as_vector_inita(&values, sizeof(as_name_value), 2); as_info_parse_multi_response(response, &values); if (values.size != 2) { goto Error; } as_name_value* nv = as_vector_get(&values, 0); char* node_name = nv->value; if (node_name == 0 || *node_name == 0) { goto Error; } as_strncpy(node_info->name, node_name, AS_NODE_NAME_SIZE); node_info->fd = fd; nv = as_vector_get(&values, 1); char* features = nv->value; if (features == 0) { goto Error; } char* begin = features; char* end = begin; uint8_t has_batch_index = 0; uint8_t has_replicas_all = 0; uint8_t has_double = 0; uint8_t has_geo = 0; while (*begin && ! (has_batch_index && has_replicas_all && has_double && has_geo)) { while (*end) { if (*end == ';') { *end++ = 0; break; } end++; } if (strcmp(begin, "batch-index") == 0) { has_batch_index = 1; } if (strcmp(begin, "replicas-all") == 0) { has_replicas_all = 1; } if (strcmp(begin, "float") == 0) { has_double = 1; } if (strcmp(begin, "geo") == 0) { has_geo = 1; } begin = end; } node_info->has_batch_index = has_batch_index; node_info->has_replicas_all = has_replicas_all; node_info->has_double = has_double; node_info->has_geo = has_geo; cf_free(response); return AEROSPIKE_OK; Error: { char addr_name[INET_ADDRSTRLEN]; as_socket_address_name(addr, addr_name); as_error_update(err, status, "Invalid node info response from %s: %s", addr_name, response); cf_free(response); as_close(fd); return AEROSPIKE_ERR_CLIENT; } }
static void as_ev_connect(as_event_command* cmd) { int fd = as_event_create_socket(cmd); if (fd < 0) { return; } // Try primary address. as_node* node = cmd->node; as_address* primary = as_vector_get(&node->addresses, node->address_index); // Attempt non-blocking connection. if (connect(fd, (struct sockaddr*)&primary->addr, sizeof(struct sockaddr)) == 0) { as_ev_watcher_init(cmd, fd); return; } // Check if connection is in progress. if (errno == EINPROGRESS) { as_ev_watcher_init(cmd, fd); return; } // Try other addresses. as_vector* addresses = &node->addresses; for (uint32_t i = 0; i < addresses->size; i++) { as_address* address = as_vector_get(addresses, i); // Address points into alias array, so pointer comparison is sufficient. if (address != primary) { if (connect(fd, (struct sockaddr*)&address->addr, sizeof(struct sockaddr)) == 0) { // Replace invalid primary address with valid alias. // Other threads may not see this change immediately. // It's just a hint, not a requirement to try this new address first. as_log_debug("Change node address %s %s:%d", node->name, address->name, (int)cf_swap_from_be16(address->addr.sin_port)); ck_pr_store_32(&node->address_index, i); as_ev_watcher_init(cmd, fd); return; } // Check if connection is in progress. if (errno == EINPROGRESS) { // Replace invalid primary address with valid alias. // Other threads may not see this change immediately. // It's just a hint, not a requirement to try this new address first. as_log_debug("Change node address %s %s:%d", node->name, address->name, (int)cf_swap_from_be16(address->addr.sin_port)); ck_pr_store_32(&node->address_index, i); // Connection hasn't finished. as_ev_watcher_init(cmd, fd); return; } } } // Failed to start a connection on any socket address. as_error err; as_error_update(&err, AEROSPIKE_ERR_ASYNC_CONNECTION, "Failed to connect: %s %s:%d", node->name, primary->name, (int)cf_swap_from_be16(primary->addr.sin_port)); as_event_connect_error(cmd, &err, fd); }
/** ******************************************************************************************************* * This function will be called with the results with aerospike_batch_read(). * * @param records A vector list of as_batch_read_record entries * @param py_recs The pyobject to be filled with. * ******************************************************************************************************* */ static void batch_select_recs(AerospikeClient *self, as_error *err, as_batch_read_records* records, PyObject **py_recs) { as_vector* list = &records->list; for (uint32_t i = 0; i < list->size; i++) { as_batch_read_record* batch = as_vector_get(list, i); PyObject * rec = NULL; PyObject * py_rec = NULL; PyObject * p_key = NULL; py_rec = PyTuple_New(3); p_key = PyTuple_New(4); if ( batch->key.ns && strlen(batch->key.ns) > 0 ) { PyTuple_SetItem(p_key, 0, PyString_FromString(batch->key.ns)); } if ( batch->key.set && strlen(batch->key.set) > 0 ) { PyTuple_SetItem(p_key, 1, PyString_FromString(batch->key.set)); } if(batch->key.valuep) { switch(((as_val*)(batch->key.valuep))->type){ case AS_INTEGER: PyTuple_SetItem(p_key, 2, PyInt_FromLong((long)batch->key.value.integer.value)); break; case AS_STRING: PyTuple_SetItem(p_key, 2, PyString_FromString((const char *)batch->key.value.string.value)); break; default: break; } } else { Py_INCREF(Py_None); PyTuple_SetItem(p_key, 2, Py_None); } if (batch->key.digest.init) { PyTuple_SetItem(p_key, 3, PyByteArray_FromStringAndSize((char *) batch->key.digest.value, AS_DIGEST_VALUE_SIZE)); } PyTuple_SetItem(py_rec, 0, p_key); if ( batch->result == AEROSPIKE_OK ){ record_to_pyobject(self, err, &batch->record, &batch->key, &rec); PyObject *py_obj = PyTuple_GetItem(rec, 1); Py_INCREF(py_obj); PyTuple_SetItem(py_rec, 1, py_obj); py_obj = PyTuple_GetItem(rec, 2); Py_INCREF(py_obj); PyTuple_SetItem(py_rec, 2, py_obj); PyList_SetItem( *py_recs, i, py_rec ); Py_DECREF(rec); } else if (batch->result == AEROSPIKE_ERR_RECORD_NOT_FOUND) { Py_INCREF(Py_None); PyTuple_SetItem(py_rec, 1, Py_None); Py_INCREF(Py_None); PyTuple_SetItem(py_rec, 2, Py_None); PyList_SetItem( *py_recs, i, py_rec); } } }
/* {{{ proto int Aerospike::info( string request, string &response [, array host [, array options ]] ) Sends an info command to a cluster node */ PHP_METHOD(Aerospike, info) { as_error err; as_error_init(&err); reset_client_error(getThis()); char* request = NULL; size_t request_len; zval* response_zval = NULL; zval* z_policy = NULL; as_host* host = NULL; char* host_str = NULL; uint16_t port_number; char* response_str = NULL; HashTable* destination_host = NULL; zval* host_zval = NULL; zval* port_zval = NULL; as_policy_info info_policy; as_policy_info* info_policy_p = NULL; AerospikeClient* php_client = NULL; aerospike* as_client = NULL; if (check_object_and_connection(getThis(), &err) != AEROSPIKE_OK) { update_client_error(getThis(), err.code, err.message, err.in_doubt); RETURN_LONG(err.code); } php_client = get_aerospike_from_zobj(Z_OBJ_P(getThis())); as_client = php_client->as_client; host = (as_host *)as_vector_get(as_client->config.hosts, 0); host_str = host->name; port_number = host->port; if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/|h!z", &request, &request_len, &response_zval, &destination_host, &z_policy) == FAILURE) { update_client_error(getThis(),AEROSPIKE_ERR_PARAM, "Invalid arguments to info", false); RETURN_LONG(AEROSPIKE_ERR_PARAM); } /* Cleanup any thing held by the return parameter */ zval_dtor(response_zval); ZVAL_NULL(response_zval); if (z_policy){ if (zval_to_as_policy_info(z_policy, &info_policy, &info_policy_p, &as_client->config.policies.info) != AEROSPIKE_OK) { update_client_error(getThis(), AEROSPIKE_ERR_PARAM, "Invalid policy.", false); RETURN_LONG(AEROSPIKE_ERR_PARAM); } info_policy_p = &info_policy; } // addr hostname or IP of the node // port /* This should be of the form ['addr'=>'hostname', 'port'=>3000] */ if (destination_host) { host_zval = zend_hash_str_find(destination_host, "addr", strlen("addr")); if (!host_zval) { as_error_update(&err, AEROSPIKE_ERR_PARAM, "Host entry must contain an addr"); goto CLEANUP; } if (Z_TYPE_P(host_zval) != IS_STRING) { as_error_update(&err, AEROSPIKE_ERR_PARAM, "addr entry must be a string"); goto CLEANUP; } host_str = Z_STRVAL_P(host_zval); port_zval = zend_hash_str_find(destination_host, "port", strlen("port")); if (!port_zval) { as_error_update(&err, AEROSPIKE_ERR_PARAM, "Host entry must contain a port"); goto CLEANUP; } if (Z_TYPE_P(port_zval) != IS_LONG) { as_error_update(&err, AEROSPIKE_ERR_PARAM, "port entry must be an integer"); goto CLEANUP; } port_number = (uint16_t)Z_LVAL_P(port_zval); } if (aerospike_info_host(as_client, &err, info_policy_p, host_str, port_number, request, &response_str) != AEROSPIKE_OK) { goto CLEANUP; } /* It is possible that an empty response will be returned, so only setup the return * if we get one back. */ if (response_str) { ZVAL_STRING(response_zval, response_str); } CLEANUP: if (err.code != AEROSPIKE_OK) { update_client_error(getThis(), err.code, err.message, err.in_doubt); } if (response_str) { free(response_str); } RETURN_LONG(err.code); }
/** ******************************************************************************************************* * This callback will be called with the results with aerospike_batch_exists(). * * @param err Error object * @param records An array of as_batch_read_record entries * @param py_recs The pyobject to be filled in with the return * value * * Returns boolean value(true or false). ******************************************************************************************************* */ static void batch_exists_recs(as_error *err, as_batch_read_records* records, PyObject **py_recs) { // Loop over records array as_vector* list = &records->list; for (uint32_t i = 0; i < list->size; i++) { as_batch_read_record* batch = as_vector_get(list, i); PyObject * rec = PyDict_New(); PyObject * p_key = NULL; PyObject * py_rec = NULL; py_rec = PyTuple_New(2); p_key = PyTuple_New(4); if ( batch->key.ns && strlen(batch->key.ns) > 0 ) { PyTuple_SetItem(p_key, 0, PyStr_FromString(batch->key.ns)); } if ( batch->key.set && strlen(batch->key.set) > 0 ) { PyTuple_SetItem(p_key, 1, PyStr_FromString(batch->key.set)); } if ( batch->key.valuep ) { switch(((as_val*)(batch->key.valuep))->type){ case AS_INTEGER: PyTuple_SetItem(p_key, 2, PyInt_FromLong((long)batch->key.value.integer.value)); break; case AS_STRING: PyTuple_SetItem(p_key, 2, PyStr_FromString((const char *)batch->key.value.string.value)); break; default: break; } } else { Py_INCREF(Py_None); PyTuple_SetItem(p_key, 2, Py_None); } if (batch->key.digest.init) { PyTuple_SetItem(p_key, 3, PyByteArray_FromStringAndSize((char *) batch->key.digest.value, AS_DIGEST_VALUE_SIZE)); } PyTuple_SetItem(py_rec, 0, p_key); if ( batch->result == AEROSPIKE_OK ){ PyObject *py_gen = PyInt_FromLong((long)batch->record.gen); PyDict_SetItemString( rec, "gen", py_gen ); Py_DECREF(py_gen); PyObject *py_ttl = PyInt_FromLong((long)batch->record.ttl); PyDict_SetItemString( rec, "ttl", py_ttl ); Py_DECREF(py_ttl); PyTuple_SetItem(py_rec, 1, rec); PyList_SetItem( *py_recs, i, py_rec ); } else if (batch->result == AEROSPIKE_ERR_RECORD_NOT_FOUND){ Py_DECREF(rec); Py_INCREF(Py_None); PyTuple_SetItem(py_rec, 1, Py_None); PyList_SetItem( *py_recs, i, py_rec); } } }
/** * @return AEROSPIKE_OK if successful. Otherwise an error occurred. */ as_status aerospike_udf_list( aerospike * as, as_error * err, const as_policy_info * policy, as_udf_files * files) { as_error_reset(err); if (! policy) { policy = &as->config.policies.info; } char* response = 0; as_status status = aerospike_info_any(as, err, policy, "udf-list", &response); if (status) { return status; } // response := udf-list\tfilename=<name>,hash=<hash>,type=<type>;[filename=<name>...] char* p = strchr(response, '\t'); if (!p) { as_error_update(err, AEROSPIKE_ERR_PARAM, "Invalid udf-list response: %s", response); free(response); return AEROSPIKE_ERR_PARAM; } p++; uint32_t capacity = (files->capacity <= 0) ? 500 : files->capacity; as_vector ptrs; as_vector_inita(&ptrs, sizeof(as_udf_file_ptr), capacity); as_udf_file_ptr ptr = {0,0,0}; char* token = p; while (*p) { switch (*p) { case '=': *p++ = 0; as_udf_parse_file(token, p, &ptr); break; case ',': *p++ = 0; token = p; break; case ';': *p++ = 0; token = p; as_vector_append(&ptrs, &ptr); ptr.name = 0; ptr.hash = 0; ptr.type = 0; break; default: p++; break; } } if (files->capacity == 0 && files->entries == NULL) { as_udf_files_init(files, ptrs.size); } uint32_t limit = ptrs.size < files->capacity ? ptrs.size : files->capacity; files->size = limit; for (uint32_t i = 0; i < limit; i++) { as_udf_file_ptr* ptr = as_vector_get(&ptrs, i); as_udf_file* file = &files->entries[i]; if (ptr->name) { as_strncpy(file->name, ptr->name, AS_UDF_FILE_NAME_SIZE); } else { file->name[0] = 0; } if (ptr->hash) { // The hash is not null terminated, so normal strncpy is appropriate here. // strncpy will also pad zeroes if hash size is incorrect. strncpy((char*)file->hash, ptr->hash, AS_UDF_FILE_HASH_SIZE); } else { file->hash[0] = 0; } file->type = AS_UDF_TYPE_LUA; file->content._free = false; file->content.size = 0; file->content.capacity = 0; file->content.bytes = NULL; } as_vector_destroy(&ptrs); free(response); return AEROSPIKE_OK; }
// ---------------------------------------------------------------------------------- // // getting batch of records in one call // batch size is limited on aerospike server (default: 5000) // // def batch_get(keys, specific_bins = nil, options = {}) // // params: // keys - Array of AerospikeC::Key objects // specific bins - Array of strings representing bin names // options - hash of options: // with_header: returns also generation and expire_in field (default: false) // // ------ // RETURN: Array of hashes where each hash represents record bins // // @TODO options policy // static VALUE batch_get(int argc, VALUE * argv, VALUE self) { rb_aero_TIMED(tm); as_error err; as_status status; aerospike * as = rb_aero_CLIENT; char ** bin_names; long n_bin_names; VALUE keys; VALUE specific_bins; VALUE options; rb_scan_args(argc, argv, "12", &keys, &specific_bins, &options); // default values for optional arguments if ( NIL_P(specific_bins) ) { specific_bins = Qnil; } else { if ( TYPE(specific_bins) != T_ARRAY ) rb_raise(rb_aero_OptionError, "[AerospikeC::Client][batch_get] specific_bins must be an Array"); bin_names = rb_array2bin_names(specific_bins); n_bin_names = rb_ary_len_long(specific_bins); } if ( NIL_P(options) ) { options = rb_hash_new(); rb_hash_aset(options, with_header_sym, Qfalse); } long keys_len = rb_ary_len_long(keys); VALUE records_bins = rb_ary_new(); as_batch_read_records records; as_batch_read_inita(&records, keys_len); // map array into as_batch_read_record * record for (int i = 0; i < keys_len; ++i) { VALUE element = rb_ary_entry(keys, i); VALUE tmp; tmp = rb_funcall(element, rb_intern("namespace"), 0); char * c_namespace = StringValueCStr( tmp ); tmp = rb_funcall(element, rb_intern("set"), 0); char * c_set = StringValueCStr( tmp ); as_batch_read_record * record = as_batch_read_reserve(&records); tmp = rb_funcall(element, rb_intern("key"), 0); if ( TYPE(tmp) != T_FIXNUM ) { char * c_key = StringValueCStr( tmp ); as_key_init(&record->key, c_namespace, c_set, c_key); } else { as_key_init_int64(&record->key, c_namespace, c_set, FIX2LONG(tmp)); } if ( specific_bins == Qnil ) { record->read_all_bins = true; } else { record->bin_names = bin_names; record->n_bin_names = n_bin_names; } } // read here! if ( ( status = aerospike_batch_read(as, &err, NULL, &records) ) != AEROSPIKE_OK ) { if ( status == AEROSPIKE_ERR_RECORD_NOT_FOUND ) { rb_aero_logger(AS_LOG_LEVEL_WARN, &tm, 1, rb_str_new2("[Client][batch_get] AEROSPIKE_ERR_RECORD_NOT_FOUND")); return Qnil; } as_batch_read_destroy(&records); raise_as_error(err); } as_vector list = records.list; // map records into array of hashes for (long i = 0; i < list.size; ++i) { as_batch_read_record * record = as_vector_get(&list, i); as_record rec = record->record; VALUE bins = record2hash(&rec); bins = check_with_header(bins, options, &rec); rb_ary_push(records_bins, bins); } as_batch_read_destroy(&records); if ( specific_bins != Qnil ) bin_names_destroy(bin_names, n_bin_names); rb_aero_logger(AS_LOG_LEVEL_DEBUG, &tm, 1, rb_str_new2("[Client][batch_get] success")); return records_bins; }