Exemplo n.º 1
0
/* 
 * 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;
}
Exemplo n.º 2
0
as_rec * map_rec_init(as_rec * r) {
    as_map * m = (as_map *) as_hashmap_new(32);
    return as_rec_init(r, m, &map_rec_hooks);
}