// Looked up the message in the store. Time to send the response value back to // the requester. The CF_BYTEARRAY is handed off in this case. If you want to // keep a reference, then keep the reference yourself. int as_proxy_send_response(cf_node dst, msg *m, uint32_t result_code, uint32_t generation, uint32_t void_time, as_msg_op **ops, as_bin **bins, uint16_t bin_count, as_namespace *ns, uint64_t trid, const char *setname) { uint32_t tid; msg_get_uint32(m, PROXY_FIELD_TID, &tid); #ifdef DEBUG cf_debug(AS_PROXY, "proxy send response: message %p bytearray %p tid %d", m, result_code, tid); #endif msg_reset(m); msg_set_uint32(m, PROXY_FIELD_OP, PROXY_OP_RESPONSE); msg_set_uint32(m, PROXY_FIELD_TID, tid); size_t msg_sz = 0; cl_msg * msgp = as_msg_make_response_msg(result_code, generation, void_time, ops, bins, bin_count, ns, 0, &msg_sz, trid, setname); msg_set_buf(m, PROXY_FIELD_AS_PROTO, (byte *) msgp, msg_sz, MSG_SET_HANDOFF_MALLOC); int rv = as_fabric_send(dst, m, AS_FABRIC_PRIORITY_MEDIUM); if (rv != 0) { cf_debug(AS_PROXY, "sending proxy response: fabric send err %d, catch you on the retry", rv); as_fabric_msg_put(m); } return 0; } // end as_proxy_send_response()
int as_proxy_send_ops_response(cf_node dst, msg *m, cf_dyn_buf *db) { uint32_t tid; msg_get_uint32(m, PROXY_FIELD_TID, &tid); #ifdef DEBUG cf_debug(AS_PROXY, "proxy send response: message %p bytearray %p tid %d", m, result_code, tid); #endif msg_reset(m); msg_set_uint32(m, PROXY_FIELD_OP, PROXY_OP_RESPONSE); msg_set_uint32(m, PROXY_FIELD_TID, tid); uint8_t *msgp = db->buf; size_t msg_sz = db->used_sz; if (db->is_stack) { msg_set_buf(m, PROXY_FIELD_AS_PROTO, msgp, msg_sz, MSG_SET_COPY); } else { msg_set_buf(m, PROXY_FIELD_AS_PROTO, msgp, msg_sz, MSG_SET_HANDOFF_MALLOC); db->buf = NULL; // the fabric owns the buffer now } int rv = as_fabric_send(dst, m, AS_FABRIC_PRIORITY_MEDIUM); if (rv != 0) { cf_debug(AS_PROXY, "sending proxy response: fabric send err %d, catch you on the retry", rv); as_fabric_msg_put(m); } return 0; } // end as_proxy_send_ops_response()
/* * Check and validate parameter before performing operation * * return: * 2 : UDF_ERR_INTERNAL_PARAM * 3 : UDF_ERR_RECORD_IS_NOT_VALID * 4 : UDF_ERR_PARAMETER * 0 : Success * */ int udf_record_param_check(const as_rec *rec, const char *bname, char *fname, int lineno) { if (!rec || !bname) { cf_warning(AS_UDF, "Invalid Paramters: record=%p bname=%p", rec, bname); return UDF_ERR_INTERNAL_PARAMETER; } udf_record * urecord = (udf_record *) as_rec_source(rec); if (!urecord) { return UDF_ERR_INTERNAL_PARAMETER;; } if (!(urecord->flag & UDF_RECORD_FLAG_ISVALID)) { if (!(urecord->flag & UDF_RECORD_FLAG_IS_SUBRECORD)) { cf_debug(AS_UDF, "(%s:%d): Trying to Open Invalid Record ", fname, lineno); } else { cf_debug(AS_UDF, "(%s:%d): Trying to Open Invalid SubRecord ", fname, lineno); } return UDF_ERR_RECORD_NOT_VALID; } as_namespace * ns = urecord->tr->rsv.ns; if (strlen(bname) >= AS_ID_BIN_SZ || !as_bin_name_within_quota(ns, bname)) { cf_debug(AS_UDF, "Invalid Parameter: bin name %s too big", bname); return UDF_ERR_PARAMETER; } return 0; }
void udf_record_cache_free(udf_record * urecord) { cf_debug(AS_UDF, "[ENTER] NumUpdates(%d) ", urecord->nupdates ); for (uint32_t i = 0; i < urecord->nupdates; i ++ ) { udf_record_bin * bin = &urecord->updates[i]; if ( bin->name[0] != '\0' && bin->value != NULL ) { bin->name[0] = '\0'; as_val_destroy(bin->value); bin->value = NULL; } if ( bin->name[0] != '\0' && bin->oldvalue != NULL ) { bin->name[0] = '\0'; as_val_destroy(bin->oldvalue); bin->oldvalue = NULL; } } for (uint32_t i = 0; i < UDF_RECORD_BIN_ULIMIT; i++) { if (urecord->updates[i].particle_buf) { cf_free(urecord->updates[i].particle_buf); urecord->updates[i].particle_buf = NULL; } } urecord->nupdates = 0; urecord->flag &= ~UDF_RECORD_FLAG_TOO_MANY_BINS; }
/** * Add a FULL NODE Entry, which has port, group and node id inside * Add a Node and Group to the Topology Info. */ int cc_add_fullnode_group_entry(cluster_config_t * cc, cf_node fullnode ) { static char * meth = "add_fullnode_group_entry()"; int rc = 0; // printf("[ENTER]<%s:%s> fullnode(%"PRIx64")\n", MOD, meth, fullnode ); // Look for the group -- if found, then save the index. // And, if not found, add it, and save the index. cc_group_t group_id = cc_compute_group_id( fullnode ); int group_ndx = cc_add_group( cc, group_id ); // Group is all set. Now add the node (we shouldn't have one already). int node_ndx = cc_add_fullnode( cc, fullnode ); // Quick validation step -- if the membership array shows a NON-negative // entry, point that out, but ALSO if( cc->membership[node_ndx] > 0 && cc->membership[node_ndx] != group_ndx) { cf_debug(AS_PARTITION, "[ERROR]<%s:%s>Adding FULLNODE[%d](%"PRIx64") MEMBER(%d) \n", MOD, meth, node_ndx, fullnode, cc->membership[node_ndx] ); rc = -1; } // Just overwrite the weird case for now -- and we'll figure it out later. // TODO: Handle the overwrite error if it ever comes up. It would probably // be ONLY a user error -- but it most likely shows that the user screwed // up the config file. cc->membership[node_ndx] = group_ndx; cc->group_node_count[group_ndx]++; // One more in this group return rc; } // end add_node_group_entry()
/* cf_svcmsocket_init * Initialize a multicast service/receive socket * Bind is done to INADDR_ANY - all interfaces * */ int cf_mcastsocket_init(cf_mcastsocket_cfg *ms) { cf_socket_cfg *s = &(ms->s); if (0 > (s->sock = socket(AF_INET, SOCK_DGRAM, 0))) { cf_warning(CF_SOCKET, "multicast socket open error: %d %s", errno, cf_strerror(errno)); return(-1); } cf_debug(CF_SOCKET, "mcast_socket init: socket %d",s->sock); // allows multiple readers on the same address uint yes=1; if (setsockopt(s->sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) { cf_warning(CF_SOCKET, "multicast socket reuse failed: %d %s", errno, cf_strerror(errno)); return(-1); } /* Set close-on-exec */ fcntl(s->sock, F_SETFD, 1); // Bind to the incoming port on inaddr any memset(&s->saddr, 0, sizeof(s->saddr)); s->saddr.sin_family = AF_INET; s->saddr.sin_addr.s_addr = INADDR_ANY; s->saddr.sin_port = htons(s->port); if (ms->tx_addr) { struct in_addr iface_in; memset((char *)&iface_in,0,sizeof(iface_in)); iface_in.s_addr = inet_addr(ms->tx_addr); if(setsockopt(s->sock, IPPROTO_IP, IP_MULTICAST_IF, (const char*)&iface_in, sizeof(iface_in)) == -1) { cf_warning(CF_SOCKET, "IP_MULTICAST_IF: %d %s", errno, cf_strerror(errno)); return(-1); } } unsigned char ttlvar = ms->mcast_ttl; if (ttlvar>0) { if (setsockopt(s->sock,IPPROTO_IP,IP_MULTICAST_TTL,(char *)&ttlvar, sizeof(ttlvar)) == -1) { cf_warning(CF_SOCKET, "IP_MULTICAST_TTL: %d %s", errno, cf_strerror(errno)); } else { cf_info(CF_SOCKET, "setting multicast TTL to be %d",ttlvar); } } while (0 > (bind(s->sock, (struct sockaddr *)&s->saddr, sizeof(struct sockaddr)))) { cf_info(CF_SOCKET, "multicast socket bind failed: %d %s", errno, cf_strerror(errno)); } // Register for the multicast group inet_pton(AF_INET, s->addr, &ms->ireq.imr_multiaddr.s_addr); ms->ireq.imr_interface.s_addr = htonl(INADDR_ANY); if (ms->tx_addr) { ms->ireq.imr_interface.s_addr = inet_addr(ms->tx_addr); } setsockopt(s->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const void *)&ms->ireq, sizeof(struct ip_mreq)); return(0); }
/** * Add Node/Group Entry * Add a Node and Group to the Topology Info. */ int cc_add_node_group_entry(cluster_config_t *cc, const cc_node_t node, const cc_group_t group) { int rc = 0; // Look for the group -- if found, then save the index. // And, if not found, add it, and save the index. int group_ndx = cc_add_group(cc, group); // Group is all set. Now add the node (we shouldn't have one already). int node_ndx = cc_add_node(cc, node); // Quick validation step -- if the membership array shows a NON-negative // entry, point that out, but ALSO if (cc->membership[node_ndx] > 0 && cc->membership[node_ndx] != group_ndx) { cf_debug(AS_PARTITION, "adding node:%d group:%d set:%d", node, group, cc->membership[node_ndx]); rc = -1; } // Just overwrite the weird case for now -- and we'll figure it out later. // TODO: Handle the overwrite error if it ever comes up. It would probably // be ONLY a user error -- but it most likely shows that the user screwed // up the config file. cc->membership[node_ndx] = group_ndx; cc->group_node_count[group_ndx]++; // One more in this group return rc; } // end add_node_group_entry()
/** * Send failure notification of general UDF execution, but check for special * LDT errors and return specific Wire Protocol error codes for these cases: * (1) Record not found (2) * (2) LDT Collection item not found (125) * * All other errors get the generic 100 (UDF FAIL) code. */ static inline int send_udf_failure(udf_call *call, const as_string *s) { char *val = as_string_tostring(s); size_t vlen = as_string_len((as_string *)s); // TODO - make as_string_len() take const long error_code = ldt_get_error_code(val, vlen); if (error_code) { if (error_code == AS_PROTO_RESULT_FAIL_NOTFOUND || error_code == AS_PROTO_RESULT_FAIL_COLLECTION_ITEM_NOT_FOUND) { call->tr->result_code = error_code; // Send an "empty" response, with no failure bin. as_transaction * tr = call->tr; single_transaction_response(tr, tr->rsv.ns, NULL/*ops*/, NULL /*bin*/, 0 /*nbins*/, 0, 0, NULL, NULL); return 0; } } cf_debug(AS_UDF, "Non-special LDT or General UDF Error(%s)", (char *) val); call->tr->result_code = AS_PROTO_RESULT_FAIL_UDF_EXECUTION; return send_failure(call, as_string_toval(s)); }
/* * Implementation of the "udf-list" Info. Command. */ int udf_cask_info_list(char *name, cf_dyn_buf *out) { cf_debug(AS_UDF, "UDF CASK INFO LIST"); pthread_mutex_t get_data_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t get_data_cond_var = PTHREAD_COND_INITIALIZER; udf_get_data_t get_data; get_data.db = out; get_data.cv = &get_data_cond_var; pthread_mutex_lock(&get_data_mutex); int retval = as_smd_get_metadata(udf_smd_module_name, "", udf_cask_get_metadata_cb, &get_data); if (!retval) { if ((retval = pthread_cond_wait(&get_data_cond_var, &get_data_mutex))) { cf_warning(AS_UDF, "pthread_cond_wait failed (rv %d)", retval); } } else { cf_warning(AS_UDF, "failed to get UDF metadata (rv %d)", retval); } pthread_mutex_unlock(&get_data_mutex); pthread_mutex_destroy(&get_data_mutex); pthread_cond_destroy(&get_data_cond_var); return retval; }
static uint32_t udf_record_ttl(const as_rec * rec) { int ret = udf_record_param_check(rec, UDF_BIN_NONAME, __FILE__, __LINE__); if (ret) { return 0; } udf_record * urecord = (udf_record *) as_rec_source(rec); if (urecord->flag & UDF_RECORD_FLAG_IS_SUBRECORD) { cf_debug(AS_UDF, "Return 0 TTL for subrecord "); return 0; } if ((urecord->flag & UDF_RECORD_FLAG_STORAGE_OPEN)) { uint32_t now = as_record_void_time_get(); return urecord->r_ref->r->void_time > now ? urecord->r_ref->r->void_time - now : 0; } else { cf_info(AS_UDF, "Error in getting ttl: no record found"); return 0; // since we can't indicate the record doesn't exist } return 0; }
static int is_connected(int fd) { uint8_t buf[8]; ssize_t rv = recv(fd, (void*)buf, sizeof(buf), MSG_PEEK | MSG_DONTWAIT | MSG_NOSIGNAL); if (rv == 0) { cf_debug("Connected check: Found disconnected fd %d", fd); return CONNECTED_NOT; } if (rv < 0) { if (errno == EBADF) { cf_warn("Connected check: Bad fd %d", fd); return CONNECTED_BADFD; } else if (errno == EWOULDBLOCK || errno == EAGAIN) { // The normal case. return CONNECTED; } else { cf_info("Connected check: fd %d error %d", fd, errno); return CONNECTED_ERROR; } } cf_info("Connected check: Peek got unexpected data for fd %d", fd); return CONNECTED; }
int citrusleaf_info(char *hostname, short port, char *names, char **values, int timeout_ms) { int rv = -1; cf_vector sockaddr_in_v; cf_vector_init(&sockaddr_in_v, sizeof( struct sockaddr_in ), 5, 0); if (0 != cl_lookup(NULL, hostname, port, &sockaddr_in_v)) { cf_debug("Could not find host %s", hostname); goto Done; } for (uint i=0; i < cf_vector_size(&sockaddr_in_v) ; i++) { struct sockaddr_in sa_in; cf_vector_get(&sockaddr_in_v, i, &sa_in); if (0 == citrusleaf_info_host(&sa_in, names, values, timeout_ms, false)) { rv = 0; goto Done; } } Done: cf_vector_destroy( &sockaddr_in_v ); return(rv); }
/* * Implementation of the "udf-list" Info. Command. */ int udf_cask_info_list(char *name, cf_dyn_buf *out) { cf_debug(AS_UDF, "UDF CASK INFO LIST"); pthread_mutex_t get_data_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t get_data_cond_var = PTHREAD_COND_INITIALIZER; udf_get_data_t get_data; get_data.db = out; get_data.cv = &get_data_cond_var; get_data.mt = &get_data_mutex; get_data.done = false; pthread_mutex_lock(&get_data_mutex); int retval = as_smd_get_metadata(udf_smd_module_name, "", udf_cask_get_metadata_cb, &get_data); if (!retval) { do { // [Note: Loop protects against spurious wakeups.] if ((retval = pthread_cond_wait(&get_data_cond_var, &get_data_mutex))) { cf_warning(AS_UDF, "pthread_cond_wait failed (rv %d)", retval); break; } } while (!get_data.done); } else { cf_warning(AS_UDF, "failed to get UDF metadata (rv %d)", retval); } pthread_mutex_unlock(&get_data_mutex); pthread_mutex_destroy(&get_data_mutex); pthread_cond_destroy(&get_data_cond_var); return retval; }
static int ldt_aerospike_rec_update(const as_aerospike * as, const as_rec * rec) { static const char * meth = "ldt_aerospike_rec_update()"; if (!as || !rec) { cf_warning(AS_LDT, "%s: Invalid Parameters [as=%p, record=%p]... Fail", meth, as, rec); return 2; } cf_detail(AS_LDT, "[ENTER]<%s> as(%p) rec(%p)", meth, as, rec ); ldt_record *lrecord = (ldt_record *)as_rec_source(rec); if (!lrecord) { return 2; } as_rec *h_urec = lrecord->h_urec; as_aerospike *las = lrecord->as; int ret = as_aerospike_rec_update(las, h_urec); if (0 == ret) { cf_detail(AS_LDT, "<%s> ZERO return(%d) from as_aero_rec_update()", meth, ret ); } else if (ret == -1) { // execution error return as it is cf_debug(AS_LDT, "<%s> Exec Error(%d) from as_aero_rec_update()", meth, ret ); } else if (ret == -2) { // Record is not open. Unexpected with LDT usage, though a UDF test case // does come through here. cf_warning(AS_LDT, "%s: Record does not exist or is not open, cannot update"); } return ret; }
/** * Set the flags for a specific bin. This is how LDTs mark Hidden Bins. Other * uses may also apply. */ static int udf_record_set_flags(const as_rec * rec, const char * name, uint8_t flags) { int ret = udf_record_param_check(rec, name, __FILE__, __LINE__); if (ret) { return ret; } udf_record * urecord = (udf_record *) as_rec_source(rec); if (!(urecord->flag & UDF_RECORD_FLAG_ALLOW_UPDATES)) { return -1; } if ( urecord && name ) { if (flags & LDT_FLAG_HIDDEN_BIN || flags & LDT_FLAG_LDT_BIN || flags & LDT_FLAG_CONTROL_BIN ) { cf_debug(AS_UDF, "LDT flag(%d) Designates Hidden Bin", flags); udf_record_cache_sethidden(urecord, name); } else { cf_warning(AS_UDF, "Unidentified flag setting up %d", flags); return -2; } } urecord->flag |= UDF_RECORD_FLAG_METADATA_UPDATED; return 0; }
/* * Function to open chunk record * Parameters: * lrd : Parent ldt record * keyd : Key digest for the record to be opened * slot(out): Filled with slot in case of success * * Return value : * 0 in case of success returns positive slot value * -1 in case record is already open * -2 in case free slot cannot be found * -3 in case record cannot be opened * * Description: * 1. Get the empty chunk slot. * 2. Read the record into it * * Callers: * ldt_aerospike_crec_open */ int crec_open(ldt_record *lrecord, cf_digest *keyd, ldt_slot **lslotp) { cf_detail_digest(AS_LDT, keyd, "[ENTER] crec_open(): Digest: "); // 1. Search in opened record *lslotp = slot_lookup_by_digest(lrecord, keyd); if (*lslotp) { cf_debug(AS_LDT, "ldt_aerospike_crec_open : Found already open"); return 0; } // 2. Find free slot and setup chunk *lslotp = slot_lookup_free(lrecord, "crec_open"); if (!*lslotp) { return -2; } slot_init(*lslotp, lrecord); slot_setup_digest(*lslotp, keyd); // 3. Open Record int rv = udf_record_open((udf_record *)as_rec_source((*lslotp)->c_urec_p)); if (rv) { // free the slot for reuse slot_destroy(*lslotp, lrecord); *lslotp = NULL; return -3; } return 0; }
int as_msg_send_reply(as_file_handle *fd_h, uint32_t result_code, uint32_t generation, uint32_t void_time, as_msg_op **ops, as_bin **bins, uint16_t bin_count, as_namespace *ns, uint *written_sz, uint64_t trid, const char *setname) { int rv = 0; // most cases are small messages - try to stack alloc if we can byte fb[MSG_STACK_BUFFER_SZ]; size_t msg_sz = sizeof(fb); // memset(fb,0xff,msg_sz); // helpful to see what you might not be setting uint8_t *msgp = (uint8_t *) as_msg_make_response_msg( result_code, generation, void_time, ops, bins, bin_count, ns, (cl_msg *)fb, &msg_sz, trid, setname); if (!msgp) return(-1); if (fd_h->fd == 0) { cf_warning(AS_PROTO, "write to fd 0 internal error"); cf_crash(AS_PROTO, "send reply: can't write to fd 0"); } // cf_detail(AS_PROTO, "write fd %d",fd); size_t pos = 0; while (pos < msg_sz) { int rv = send(fd_h->fd, msgp + pos, msg_sz - pos, MSG_NOSIGNAL); if (rv > 0) { pos += rv; } else if (rv < 0) { if (errno != EWOULDBLOCK) { // common message when a client aborts cf_debug(AS_PROTO, "protocol write fail: fd %d sz %zd pos %zd rv %d errno %d", fd_h->fd, msg_sz, pos, rv, errno); as_end_of_transaction_force_close(fd_h); rv = -1; goto Exit; } usleep(1); // Yield } else { cf_info(AS_PROTO, "protocol write fail zero return: fd %d sz %d pos %d ", fd_h->fd, msg_sz, pos); as_end_of_transaction_force_close(fd_h); rv = -1; goto Exit; } } // good for stats as a higher layer if (written_sz) *written_sz = msg_sz; as_end_of_transaction_ok(fd_h); Exit: if ((uint8_t *)msgp != fb) cf_free(msgp); return(rv); }
/* * Reading local directory to get specific module item's contents. * In future if needed we can change this to reading from smd metadata. */ int udf_cask_info_get(char *name, char * params, cf_dyn_buf * out) { int resp = 0; char filename[128] = {0}; int filename_len = sizeof(filename); uint8_t * content = NULL; size_t content_len = 0; unsigned char content_gen[256] = {0}; uint8_t udf_type = AS_UDF_TYPE_LUA; cf_debug(AS_INFO, "UDF CASK INFO GET"); // get (required) script filename if ( as_info_parameter_get(params, "filename", filename, &filename_len) ) { cf_info(AS_INFO, "invalid or missing filename"); cf_dyn_buf_append_string(out, "error=invalid_filename"); return 0; } mod_lua_rdlock(&mod_lua); // read the script from filesystem resp = file_read(filename, &content, &content_len, content_gen); mod_lua_unlock(&mod_lua); if ( resp ) { switch ( resp ) { case 1 : { cf_dyn_buf_append_string(out, "error=not_found"); break; } case 2 : { cf_dyn_buf_append_string(out, "error=empty"); break; } default : { cf_dyn_buf_append_string(out, "error=unknown_error"); break; // complier complains without a break; } } } else { // put back the result cf_dyn_buf_append_string(out, "gen="); cf_dyn_buf_append_string(out, (char *) content_gen); cf_dyn_buf_append_string(out, ";type="); cf_dyn_buf_append_string(out, as_udf_type_name[udf_type]); cf_dyn_buf_append_string(out, ";content="); cf_dyn_buf_append_buf(out, content, content_len); cf_dyn_buf_append_string(out, ";"); } if ( content ) { cf_free(content); content = NULL; } return 0; }
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; }
int udf_cask_info_remove(char *name, char * params, cf_dyn_buf * out) { char filename[128] = {0}; int filename_len = sizeof(filename); char file_path[1024] = {0}; struct stat buf; cf_debug(AS_INFO, "UDF CASK INFO REMOVE"); // get (required) script filename if ( as_info_parameter_get(params, "filename", filename, &filename_len) ) { cf_info(AS_UDF, "invalid or missing filename"); cf_dyn_buf_append_string(out, "error=invalid_filename"); } // now check if such a file-name exists : if (!g_config.mod_lua.user_path) { return -1; } snprintf(file_path, 1024, "%s/%s", g_config.mod_lua.user_path, filename); cf_debug(AS_INFO, " Lua file removal full-path is : %s \n", file_path); if (stat(file_path, &buf) != 0) { cf_info(AS_UDF, "failed to read file from : %s, error : %s", file_path, cf_strerror(errno)); cf_dyn_buf_append_string(out, "error=file_not_found"); return -1; } as_smd_delete_metadata(udf_smd_module_name, filename); // this is what an error would look like // cf_dyn_buf_append_string(out, "error="); // cf_dyn_buf_append_int(out, resp); cf_dyn_buf_append_string(out, "ok"); cf_info(AS_UDF, "UDF module '%s' (%s) removed", filename, file_path); return 0; }
int udf_cask_smd_merge_fn (char *module, as_smd_item_list_t **item_list_out, as_smd_item_list_t **item_lists_in, size_t num_lists, void *udata) { cf_debug(AS_UDF, "UDF CASK merge function"); // (For now, just send back an empty metadata item list.) as_smd_item_list_t *item_list = as_smd_item_list_create(0); *item_list_out = item_list; return(0); }
/* cf_socket_send * Send to a socket */ int cf_socket_send(int sock, void *buf, size_t buflen, int flags) { int i; flags |= MSG_NOSIGNAL; if (0 >= (i = send(sock, buf, buflen, flags))) { cf_debug(CF_SOCKET, "send() failed: %d %s", errno, cf_strerror(errno)); } return(i); }
int cf_ipaddr_get(int socket, char *nic_id, char **node_ip ) { struct sockaddr_in sin; struct ifreq ifr; in_addr_t ip_addr; memset(&ip_addr, 0, sizeof(in_addr_t)); memset(&sin, 0, sizeof(struct sockaddr)); memset(&ifr, 0, sizeof(ifr)); // copy the nic name (eth0, eth1, eth2, etc.) ifr variable structure strncpy(ifr.ifr_name, nic_id, IFNAMSIZ); // get the ifindex for the adapter... if (ioctl(socket, SIOCGIFINDEX, &ifr) < 0) { cf_debug(CF_MISC, "Can't get ifindex for adapter %s - %d %s\n", nic_id, errno, cf_strerror(errno)); return(-1); } // get the IP address memset(&sin, 0, sizeof(struct sockaddr)); memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, nic_id, IFNAMSIZ); ifr.ifr_addr.sa_family = AF_INET; if (ioctl(socket, SIOCGIFADDR, &ifr)< 0) { cf_debug(CF_MISC, "can't get IP address: %d %s", errno, cf_strerror(errno)); return(-1); } memcpy(&sin, &ifr.ifr_addr, sizeof(struct sockaddr)); ip_addr = sin.sin_addr.s_addr; char cpaddr[24]; if (NULL == inet_ntop(AF_INET, &ip_addr, (char *)cpaddr, sizeof(cpaddr))) { cf_warning(CF_MISC, "received suspicious address %s : %s", cpaddr, cf_strerror(errno)); return(-1); } cf_info (CF_MISC, "Node ip: %s", cpaddr); *node_ip = cf_strdup(cpaddr); return(0); }
int match_partial_index_name(char *iname) { char tmp_name[TBLD_HASH_KEY_SIZE]; memset(tmp_name, 0, TBLD_HASH_KEY_SIZE); memcpy(tmp_name, iname, strlen(iname)); long val = -1; if(SHASH_OK != shash_get(IndD, (void*)tmp_name, (void*)&val)) { cf_debug(AS_SINDEX, "shash get failed on %s", iname); } return val != -1 ? val - 1 : -1; }
/** * Set the cache value for a bin, including flags. */ static void udf_record_cache_set(udf_record * urecord, const char * name, as_val * value, bool dirty) { cf_debug(AS_UDF, "[ENTER] urecord(%p) name(%p)[%s] dirty(%d)", urecord, name, name, dirty); bool modified = false; for ( uint32_t i = 0; i < urecord->nupdates; i++ ) { udf_record_bin * bin = &(urecord->updates[i]); // bin exists, then we will release old value and set new value. if ( strncmp(name, bin->name, AS_ID_BIN_SZ) == 0 ) { cf_detail(AS_UDF, "udf_record_set: %s found", name); // release previously set value as_val_destroy(bin->value); // set new value, with dirty flag if( value != NULL ) { bin->value = (as_val *) value; } bin->dirty = dirty; cf_detail(AS_UDF, "udf_record_set: %s set for %p:%p", name, urecord, bin->value); modified = true; break; } } // If not modified, then we will add the bin to the cache if ( ! modified ) { if ( urecord->nupdates < UDF_RECORD_BIN_ULIMIT ) { udf_record_bin * bin = &(urecord->updates[urecord->nupdates]); strncpy(bin->name, name, AS_ID_BIN_SZ); bin->value = (as_val *) value; bin->dirty = dirty; bin->ishidden = false; urecord->nupdates++; cf_detail(AS_UDF, "udf_record_set: %s not modified, add for %p:%p", name, urecord, bin->value); } else { cf_warning(AS_UDF, "UDF bin limit (%d) exceeded (bin %s)", UDF_RECORD_BIN_ULIMIT, name); urecord->flag |= UDF_RECORD_FLAG_TOO_MANY_BINS; } } }
/** * Send failure notification of general UDF execution, but check for special * LDT errors and return specific Wire Protocol error codes for these cases: * (1) Record not found (2) * (2) LDR Collection item not found (125) * * All other errors get the generic 100 (UDF FAIL) code. * * Parse (Actually, probe) the error string, and if we see this pattern: * FileName:Line# 4digits:LDT-<Error String> * For example: * .../aerospike-lua-core/src/ldt/lib_llist.lua:982: 0002:LDT-Top Record Not Found * All UDF errors (LDT included), have the "filename:line# " prefix, and then * LDT errors follow that with a known pattern: * (4 digits, colon, LDT-<Error String>). * We will check the error string by looking for specific markers after the * the space that follows the filename:line#. If we see the markers, we will * parse the LDT error code and use that as the wire protocol error if it is * one of the special ones: * (1) "0002:LDT-Top Record Not Found" * (2) "0125:LDT-Item Not Found" */ static inline int send_udf_failure(udf_call *call, int vtype, void *val, size_t vlen) { // We need to do a quick look to see if this is an LDT error string. If it // is, then we'll look deeper. We start looking after the first space. char * charptr; char * valptr = (char *) val; long error_code; // Start with the space, if it exists, as the marker for where we start // looking for the LDT error contents. if ((charptr = strchr((const char *) val, ' ')) != NULL) { // We must be at least 10 chars from the end, so if we're less than that // we are obviously not looking at an LDT error. if (&charptr[9] < &valptr[vlen]) { if (memcmp(&charptr[5], ":LDT-", 5) == 0) { error_code = strtol(&charptr[1], NULL, 10); if (error_code == AS_PROTO_RESULT_FAIL_NOTFOUND || error_code == AS_PROTO_RESULT_FAIL_COLLECTION_ITEM_NOT_FOUND) { call->transaction->result_code = error_code; cf_debug(AS_UDF, "LDT Error: Code(%ld) String(%s)", error_code, (char *) val); // Send an "empty" response, with no failure bin. as_transaction * tr = call->transaction; single_transaction_response(tr, tr->rsv.ns, NULL/*ops*/, NULL /*bin*/, 0 /*nbins*/, 0, 0, NULL, NULL); return 0; } } } } cf_debug(AS_UDF, "Non-special LDT or General UDF Error(%s)", (char *) val); call->transaction->result_code = AS_PROTO_RESULT_FAIL_UDF_EXECUTION; return send_response(call, "FAILURE", 7, vtype, val, vlen); }
bool udf_timer_timedout(const as_timer *as_tt) { time_tracker *tt = (time_tracker *)pthread_getspecific(timer_tlskey); if (!tt || !tt->end_time || !tt->udata) { return true; } bool timedout = (cf_getms() > tt->end_time(tt)); if (timedout) { cf_debug(AS_UDF, "UDF Timed Out [%ld:%ld]", cf_getms(), tt->end_time(tt)); return true; } return false; }
/* * Check and validate parameter before performing operation * * return: * UDF_ERR * in case of failure * 0 in case of success */ static int udf_aerospike_param_check(const as_aerospike *as, const as_rec *rec, char *fname, int lineno) { if (!as) { cf_debug(AS_UDF, "Invalid Paramters: aerospike=%p", as); return UDF_ERR_INTERNAL_PARAMETER; } int ret = udf_record_param_check(rec, UDF_BIN_NONAME, fname, lineno); if (ret) { return ret; } return 0; }
int as_netio_send_packet(as_file_handle *fd_h, cf_buf_builder *bb_r, uint32_t *offset, bool blocking) { #if defined(USE_SYSTEMTAP) uint64_t nodeid = g_config.self_node; #endif uint32_t len = bb_r->used_sz; uint8_t *buf = bb_r->buf; as_proto proto; proto.version = PROTO_VERSION; proto.type = PROTO_TYPE_AS_MSG; proto.sz = len - 8; as_proto_swap(&proto); memcpy(bb_r->buf, &proto, 8); uint32_t pos = *offset; ASD_QUERY_SENDPACKET_STARTING(nodeid, pos, len); int rv; int retry = 0; cf_detail(AS_PROTO," Start At %p %d %d", buf, pos, len); while (pos < len) { rv = send(fd_h->fd, buf + pos, len - pos, MSG_NOSIGNAL); if (rv <= 0) { if (errno != EAGAIN) { cf_debug(AS_PROTO, "Packet send response error returned %d errno %d fd %d", rv, errno, fd_h->fd); return AS_NETIO_IO_ERR; } if (!blocking && (retry > AS_NETIO_MAX_IO_RETRY)) { *offset = pos; cf_detail(AS_PROTO," End At %p %d %d", buf, pos, len); ASD_QUERY_SENDPACKET_CONTINUE(nodeid, pos); return AS_NETIO_CONTINUE; } retry++; // bigger packets so try few extra times usleep(100); } else { pos += rv; } } ASD_QUERY_SENDPACKET_FINISHED(nodeid); return AS_NETIO_OK; }
/* * Function: Get bin value from cached copy. All the update in a * commit window is not applied to the record directly * but maintained in-memory cache. This function used * to retrieve cached value * * Similar function for get and free of cache * * Parameters: * urec : Parent ldt record * * Return value : * value (as_val) in case of success [for get] * NULL in case of failure * set and free return Nothing * * Callers: * GET and SET * udf_record_get * udf_record_set * udf_record_remove * * FREE * udf_aerospike__execute_updates (when crossing commit window) * ldt_aerospike_crec_close (when closing chunk sub record) * udf_record_close (finally closing record/generally subrecord) * udf_rw_commit (commit the udf record or parent ldt record) * * ldt_aerospike_crec_create */ static as_val * udf_record_cache_get(udf_record * urecord, const char * name) { cf_debug(AS_UDF, "[ENTER] BinName(%s) ", name ); if ( urecord->nupdates > 0 ) { cf_detail(AS_UDF, "udf_record_get: %s find", name); for ( uint32_t i = 0; i < urecord->nupdates; i++ ) { udf_record_bin * bin = &(urecord->updates[i]); if ( strncmp(name, bin->name, AS_ID_BIN_SZ) == 0 ) { cf_detail(AS_UDF, "Bin %s found, type(%d)", name, bin->value->type ); return bin->value; // note it's OK if the bin contains a nil } } } return NULL; }