/** * Remove the slot entry, but decrement the count only if the destroy() op * was successful. */ static void slot_destroy(ldt_slot *lslotp, ldt_record *lrecord) { if (lslotp->c_urec_p) { udf_record_destroy(lslotp->c_urec_p); as_rec_destroy(lslotp->c_urec_p); lslotp->c_urec_p = NULL; lrecord->num_slots_used--; lslotp->inuse = false; } else { cf_warning(AS_LDT, "slot_destroy: Internal Error [Attempt to free invalid slot] ... Skipped"); } }
static bool ldt_record_destroy(as_rec * rec) { static const char * meth = "ldt_record_destroy()"; if (!rec) { cf_warning(AS_UDF, "%s Invalid Paramters: record=%p", meth, rec); return false; } ldt_record *lrecord = (ldt_record *)as_rec_source(rec); if (!lrecord) { return false; } as_rec *h_urec = lrecord->h_urec; // Note: destroy of udf_record today is no-op because all the closing // of record happens after UDF has executed. // TODO: validate chunk handling here. FOR_EACH_SUBRECORD(i, lrecord) { as_rec *c_urec = &lrecord->chunk[i].c_urec; as_rec_destroy(c_urec); lrecord->chunk[i].slot = -1; }
/* * this is an actual instance of the scan, running on a scan thread * It reads on the node fd till it finds the last msg, in the meantime calling * task->callback on the returned data. The returned data is a bin of name SUCCESS/FAILURE * and the value of the bin is the return value from the udf. */ static int cl_scan_worker_do(cl_cluster_node * node, cl_scan_task * task) { uint8_t rd_stack_buf[STACK_BUF_SZ] = {0}; uint8_t * rd_buf = rd_stack_buf; size_t rd_buf_sz = 0; int fd = cl_cluster_node_fd_get(node, false, task->asc->nbconnect); if ( fd == -1 ) { LOG("[ERROR] cl_scan_worker_do: cannot get fd for node %s ",node->name); return CITRUSLEAF_FAIL_CLIENT; } // send it to the cluster - non blocking socket, but we're blocking if (0 != cf_socket_write_forever(fd, (uint8_t *) task->scan_buf, (size_t) task->scan_sz)) { close(fd); return CITRUSLEAF_FAIL_CLIENT; } cl_proto proto; int rc = CITRUSLEAF_OK; bool done = false; do { // multiple CL proto per response // Now turn around and read a fine cl_proto - that's the first 8 bytes // that has types and lengths if ( (rc = cf_socket_read_forever(fd, (uint8_t *) &proto, sizeof(cl_proto) ) ) ) { LOG("[ERROR] cl_scan_worker_do: network error: errno %d fd %d node name %s\n", rc, fd, node->name); close(fd); return CITRUSLEAF_FAIL_CLIENT; } cl_proto_swap(&proto); if ( proto.version != CL_PROTO_VERSION) { LOG("[ERROR] cl_scan_worker_do: network error: received protocol message of wrong version %d from node %s\n", proto.version, node->name); close(fd); return CITRUSLEAF_FAIL_CLIENT; } if ( proto.type != CL_PROTO_TYPE_CL_MSG && proto.type != CL_PROTO_TYPE_CL_MSG_COMPRESSED ) { LOG("[ERROR] cl_scan_worker_do: network error: received incorrect message version %d from node %s \n",proto.type, node->name); close(fd); return CITRUSLEAF_FAIL_CLIENT; } // second read for the remainder of the message - expect this to cover // lots of data, many lines if there's no error rd_buf_sz = proto.sz; if (rd_buf_sz > 0) { if (rd_buf_sz > sizeof(rd_stack_buf)){ rd_buf = malloc(rd_buf_sz); } else { rd_buf = rd_stack_buf; } if (rd_buf == NULL) { close(fd); return CITRUSLEAF_FAIL_CLIENT; } if ( (rc = cf_socket_read_forever(fd, rd_buf, rd_buf_sz)) ) { LOG("[ERROR] cl_scan_worker_do: network error: errno %d fd %d node name %s\n", rc, fd, node->name); if ( rd_buf != rd_stack_buf ) free(rd_buf); close(fd); return CITRUSLEAF_FAIL_CLIENT; } } // process all the cl_msg in this proto uint8_t * buf = rd_buf; uint pos = 0; cl_bin stack_bins[STACK_BINS]; cl_bin * bins; while (pos < rd_buf_sz) { uint8_t * buf_start = buf; cl_msg * msg = (cl_msg *) buf; cl_msg_swap_header(msg); buf += sizeof(cl_msg); if ( msg->header_sz != sizeof(cl_msg) ) { LOG("[ERROR] cl_scan_worker_do: received cl msg of unexpected size: expecting %zd found %d, internal error\n", sizeof(cl_msg),msg->header_sz); close(fd); return CITRUSLEAF_FAIL_CLIENT; } // parse through the fields cf_digest keyd; char ns_ret[33] = {0}; char * set_ret = NULL; cl_msg_field * mf = (cl_msg_field *)buf; for (int i=0; i < msg->n_fields; i++) { cl_msg_swap_field(mf); if (mf->type == CL_MSG_FIELD_TYPE_KEY) { LOG("[ERROR] cl_scan_worker_do: read: found a key - unexpected\n"); } else if (mf->type == CL_MSG_FIELD_TYPE_DIGEST_RIPE) { memcpy(&keyd, mf->data, sizeof(cf_digest)); } else if (mf->type == CL_MSG_FIELD_TYPE_NAMESPACE) { memcpy(ns_ret, mf->data, cl_msg_field_get_value_sz(mf)); ns_ret[ cl_msg_field_get_value_sz(mf) ] = 0; } else if (mf->type == CL_MSG_FIELD_TYPE_SET) { uint32_t set_name_len = cl_msg_field_get_value_sz(mf); set_ret = (char *)malloc(set_name_len + 1); memcpy(set_ret, mf->data, set_name_len); set_ret[ set_name_len ] = '\0'; } mf = cl_msg_field_get_next(mf); } buf = (uint8_t *) mf; if (msg->n_ops > STACK_BINS) { bins = malloc(sizeof(cl_bin) * msg->n_ops); } else { bins = stack_bins; } if (bins == NULL) { if (set_ret) { free(set_ret); } close(fd); return CITRUSLEAF_FAIL_CLIENT; } // parse through the bins/ops cl_msg_op * op = (cl_msg_op *) buf; for (int i=0;i<msg->n_ops;i++) { cl_msg_swap_op(op); #ifdef DEBUG_VERBOSE LOG("[DEBUG] cl_scan_worker_do: op receive: %p size %d op %d ptype %d pversion %d namesz %d \n", op,op->op_sz, op->op, op->particle_type, op->version, op->name_sz); #endif #ifdef DEBUG_VERBOSE dump_buf("individual op (host order)", (uint8_t *) op, op->op_sz + sizeof(uint32_t)); #endif cl_set_value_particular(op, &bins[i]); op = cl_msg_op_get_next(op); } buf = (uint8_t *) op; if (msg->result_code != CL_RESULT_OK) { rc = (int) msg->result_code; done = true; if (rc == CITRUSLEAF_FAIL_SCAN_ABORT) { LOG("[INFO] cl_scan_worker_do: Scan successfully aborted at node [%s]\n", node->name); } } else if (msg->info3 & CL_MSG_INFO3_LAST) { if ( cf_debug_enabled() ) { LOG("[INFO] cl_scan_worker_do: Received final message from node [%s], scan complete\n", node->name); } done = true; } else if ((msg->n_ops || (msg->info1 & CL_MSG_INFO1_NOBINDATA))) { cl_scan_response_rec rec; cl_scan_response_rec *recp = &rec; recp->ns = strdup(ns_ret); recp->keyd = keyd; recp->set = set_ret; recp->generation = msg->generation; recp->record_ttl = msg->record_ttl; recp->bins = bins; recp->n_bins = msg->n_ops; recp->ismalloc = false; as_rec r; as_rec *rp = &r; rp = as_rec_init(rp, recp, &scan_response_hooks); as_val * v = as_rec_get(rp, "SUCCESS"); if ( v != NULL && task->callback) { // Got a non null value for the resposne bin, // call callback on it and destroy the record task->callback(v, task->udata); as_rec_destroy(rp); } rc = CITRUSLEAF_OK; } // if done free it if (done) { citrusleaf_bins_free(bins, msg->n_ops); if (bins != stack_bins) { free(bins); bins = 0; } if (set_ret) { free(set_ret); set_ret = NULL; } } // don't have to free object internals. They point into the read buffer, where // a pointer is required pos += buf - buf_start; } if (rd_buf && (rd_buf != rd_stack_buf)) { free(rd_buf); rd_buf = 0; } } while ( done == false ); cl_cluster_node_fd_put(node, fd, false); #ifdef DEBUG_VERBOSE LOG("[DEBUG] cl_scan_worker_do: exited loop: rc %d\n", rc ); #endif return rc; }
void ldt_chunk_destroy(ldt_chunk *lchunk) { as_rec_destroy(lchunk->c_urec_p); lchunk->slot = -1; }
/** * Destroy the as_record and associated resources. */ void as_record_destroy(as_record * rec) { as_rec_destroy((as_rec *) rec); }