示例#1
0
文件: testapp.c 项目: bcui6611/moxi
static void testWrongServer(const char *fname) {
    VBUCKET_CONFIG_HANDLE vb = vbucket_config_parse_file(configPath(fname));
    if (vb == NULL) {
        fprintf(stderr, "vbucket_config_parse_file error: %s\n",
                vbucket_get_error());
        abort();
    }

    /* Starts at 0 */
    assert(vbucket_get_master(vb, 0) == 0);
    /* Does not change when I told it I found the wrong thing */
    assert(vbucket_found_incorrect_master(vb, 0, 1) == 0);
    assert(vbucket_get_master(vb, 0) == 0);
    /* Does change if I tell it I got the right thing and it was wrong. */
    assert(vbucket_found_incorrect_master(vb, 0, 0) == 1);
    assert(vbucket_get_master(vb, 0) == 1);
    /* ...and again */
    assert(vbucket_found_incorrect_master(vb, 0, 1) == 2);
    assert(vbucket_get_master(vb, 0) == 2);
    /* ...and then wraps */
    assert(vbucket_found_incorrect_master(vb, 0, 2) == 0);
    assert(vbucket_get_master(vb, 0) == 0);

    vbucket_config_destroy(vb);
}
示例#2
0
VBUCKET_CONFIG_DIFF* vbucket_compare(VBUCKET_CONFIG_HANDLE from,
                                     VBUCKET_CONFIG_HANDLE to) {
    VBUCKET_CONFIG_DIFF *rv = calloc(1, sizeof(VBUCKET_CONFIG_DIFF));
    int num_servers = (from->num_servers > to->num_servers
                       ? from->num_servers : to->num_servers) + 1;
    assert(rv);
    rv->servers_added = calloc(num_servers, sizeof(char*));
    rv->servers_removed = calloc(num_servers, sizeof(char*));

    /* Compute the added and removed servers */
    compute_vb_list_diff(from, to, rv->servers_added);
    compute_vb_list_diff(to, from, rv->servers_removed);

    /* Verify the servers are equal in their positions */
    if (to->num_servers == from->num_servers) {
        int i;
        rv->sequence_changed = false;
        for (i = 0; i < from->num_servers; i++) {
            rv->sequence_changed |= (0 != strcmp(vbucket_config_get_server(from, i),
                                                 vbucket_config_get_server(to, i)));

        }
    } else {
        /* Just say yes */
        rv->sequence_changed = true;
    }

    /* Consider the sequence changed if the auth credentials changed */
    if (from->user != NULL && to->user != NULL) {
        rv->sequence_changed |= (strcmp(from->user, to->user) != 0);
    } else {
        rv->sequence_changed |= ((from->user != NULL) ^ (to->user != NULL));
    }

    if (from->password != NULL && to->password != NULL) {
        rv->sequence_changed |= (strcmp(from->password, to->password) != 0);
    } else {
        rv->sequence_changed |= ((from->password != NULL) ^ (to->password != NULL));
    }

    /* Count the number of vbucket differences */
    if (to->num_vbuckets == from->num_vbuckets) {
        int i;
        for (i = 0; i < to->num_vbuckets; i++) {
            rv->n_vb_changes += (vbucket_get_master(from, i)
                                 == vbucket_get_master(to, i)) ? 0 : 1;
        }
    } else {
        rv->n_vb_changes = -1;
    }

    return rv;
}
示例#3
0
int vbucket_map(VBUCKET_CONFIG_HANDLE vb, const void *key, size_t nkey,
                int *vbucket_id, int *server_idx)
{
    uint32_t digest, mid, prev;
    struct continuum_item_st *beginp, *endp, *midp, *highp, *lowp;

    if (vb->distribution == VBUCKET_DISTRIBUTION_KETAMA) {
        assert(vb->continuum);
        if (vbucket_id) {
            *vbucket_id = 0;
        }
        digest = hash_ketama(key, nkey);
        beginp = lowp = vb->continuum;
        endp = highp = vb->continuum + vb->num_continuum;

        /* divide and conquer array search to find server with next biggest
         * point after what this key hashes to */
        while (1)
        {
            /* pick the middle point */
            midp = lowp + (highp - lowp) / 2;

            if (midp == endp) {
                /* if at the end, roll back to zeroth */
                *server_idx = beginp->index;
                break;
            }

            mid = midp->point;
            prev = (midp == beginp) ? 0 : (midp-1)->point;

            if (digest <= mid && digest > prev) {
                /* we found nearest server */
                *server_idx = midp->index;
                break;
            }

            /* adjust the limits */
            if (mid < digest) {
                lowp = midp + 1;
            } else {
                highp = midp - 1;
            }

            if (lowp > highp) {
                *server_idx = beginp->index;
                break;
            }
        }
    } else {
        *vbucket_id = vbucket_get_vbucket_by_key(vb, key, nkey);
        *server_idx = vbucket_get_master(vb, *vbucket_id);
    }
    return 0;
}
示例#4
0
文件: mcs.c 项目: MediaMath/moxi
uint32_t lvb_key_hash(mcs_st *ptr, const char *key, size_t key_length, int *vbucket) {
    assert(ptr->kind == MCS_KIND_LIBVBUCKET);
    assert(ptr->data != NULL);

    VBUCKET_CONFIG_HANDLE vch = (VBUCKET_CONFIG_HANDLE) ptr->data;

    int v = vbucket_get_vbucket_by_key(vch, key, key_length);
    if (vbucket != NULL) {
        *vbucket = v;
    }

    return (uint32_t) vbucket_get_master(vch, v);
}
示例#5
0
/**
 * This callback is invoked for packet relocation twice. It tries to relocate
 * commands to their destination server. Some commands may not be relocated
 * either because they have no explicit "Relocation Information" (i.e. no
 * specific vbucket) or because the command is tied to a specific server (i.e.
 * CMD_STAT)
 */
static int
iterwipe_cb(mc_CMDQUEUE *cq, mc_PIPELINE *oldpl, mc_PACKET *oldpkt, void *arg)
{
    protocol_binary_request_header hdr;
    mc_SERVER *srv = (mc_SERVER *)oldpl;
    mc_PIPELINE *newpl;
    mc_PACKET *newpkt;
    int newix;
    uint8_t op;

    (void)arg;

    memcpy(&hdr, SPAN_BUFFER(&oldpkt->kh_span), sizeof(hdr.bytes));
    op = hdr.request.opcode;
    if (op == PROTOCOL_BINARY_CMD_OBSERVE ||
            op == PROTOCOL_BINARY_CMD_STAT ||
            op == PROTOCOL_BINARY_CMD_GET_CLUSTER_CONFIG) {
        return MCREQ_KEEP_PACKET;
    }

    newix = vbucket_get_master(cq->config, ntohs(hdr.request.vbucket));
    if (newix < 0 || newix > (int)cq->npipelines) {
        return MCREQ_KEEP_PACKET;
    }

    if (!lcb_should_retry(srv->settings, oldpkt, LCB_MAX_ERROR)) {
        return MCREQ_KEEP_PACKET;
    }

    newpl = cq->pipelines[newix];
    if (newpl == oldpl || newpl == NULL) {
        return MCREQ_KEEP_PACKET;
    }

    lcb_log(LOGARGS(cq->instance, DEBUG), "Remapped packet %p (SEQ=%u) from "SERVER_FMT " to " SERVER_FMT,
        (void*)oldpkt, oldpkt->opaque, SERVER_ARGS((mc_SERVER*)oldpl), SERVER_ARGS((mc_SERVER*)newpl));

    /** Otherwise, copy over the packet and find the new vBucket to map to */
    newpkt = mcreq_dup_packet(oldpkt);
    newpkt->flags &= ~MCREQ_STATE_FLAGS;
    mcreq_reenqueue_packet(newpl, newpkt);
    mcreq_packet_handled(oldpl, oldpkt);
    return MCREQ_REMOVE_PACKET;
}
示例#6
0
文件: testapp.c 项目: bcui6611/moxi
static void testConfig(const char *fname) {
    int whoops = 0;
    const struct key_st *k;
    int i = 0;

    VBUCKET_CONFIG_HANDLE vb = vbucket_config_parse_file(configPath(fname));
    if (vb == NULL) {
        fprintf(stderr, "vbucket_config_parse_file error: %s\n",
                vbucket_get_error());
        abort();
    }

    while ((k = &keys[i++])->key != NULL) {
        int id = vbucket_get_vbucket_by_key(vb, k->key, strlen(k->key));
        if (id != k->vbucket) {
            fprintf(stderr, "Expected vbucket %d for key '%s' but got %d\n",
                    k->vbucket, k->key, id);
            whoops = 1;
        }
    }

    if (whoops) {
        abort();
    }

    assert(vbucket_config_get_num_servers(vb) == 3 || vbucket_config_get_num_servers(vb) == 4);
    assert(vbucket_config_get_num_replicas(vb) == 2);

    for (i = 0; i < 3; ++i) {
        assert(strcmp(vbucket_config_get_server(vb, i), servers[i]) == 0);
    }

    for (i = 0; i < 4; ++i) {
        assert(vbucket_get_master(vb, i) == vbuckets[i].master);
        assert(vbucket_get_replica(vb, i, 0) == vbuckets[i].replicas[0]);
        assert(vbucket_get_replica(vb, i, 1) == vbuckets[i].replicas[1]);
    }

    assert(vbucket_config_get_user(vb) == NULL);
    assert(vbucket_config_get_password(vb) == NULL);

    vbucket_config_destroy(vb);
}
示例#7
0
static void testWrongServerFFT(const char *fname) {
    VBUCKET_CONFIG_HANDLE vb = vbucket_config_parse_file(configPath(fname));
    int rv = 0;
    int nvb = 0;
    int i = 0;

    if (vb == NULL) {
        fprintf(stderr, "vbucket_config_parse_file error: %s\n", vbucket_get_error());
        abort();
    }

    /* found incorrect master should not be the same as get master now */
    nvb = vbucket_config_get_num_vbuckets(vb);
    for (i = 0; i < nvb; i++) {
        rv = vbucket_get_master(vb, i);
        assert(rv != vbucket_found_incorrect_master(vb, i, rv));
    }
    /* the ideal test case should be that we check that the vbucket */
    /* and the fvbucket map are identical at this point. TODO untill */
    /* we have a vbucketlib function that diffs vbuckets and fvbuckets */
    vbucket_config_destroy(vb);
}
示例#8
0
static void observe_response_handler(lcb_server_t *server,
                                     packet_info *info)
{
    lcb_t root = server->instance;
    lcb_error_t rc = map_error(root, PACKET_STATUS(info));
    lcb_uint32_t ttp;
    lcb_uint32_t ttr;
    lcb_size_t pos;

    VBUCKET_CONFIG_HANDLE config;
    const char *end, *ptr;

    /**
     * If we have an error we must decode the request instead
     */
    if (rc != LCB_SUCCESS) {
        protocol_binary_request_header req;
        lcb_size_t nr;

        nr = ringbuffer_peek(&server->cmd_log, req.bytes, sizeof(req.bytes));
        if (nr != sizeof(req.bytes)) {
            lcb_error_handler(server->instance, LCB_EINTERNAL, NULL);
            abort();
        }

        if (req.request.bodylen) {
            lcb_size_t npacket = sizeof(req.bytes) + ntohl(req.request.bodylen);
            char *packet = server->cmd_log.read_head;
            int allocated = 0;

            if (!ringbuffer_is_continous(&server->cmd_log, RINGBUFFER_READ, npacket)) {
                packet = malloc(npacket);
                if (packet == NULL) {
                    lcb_error_handler(root, LCB_CLIENT_ENOMEM, NULL);
                    abort();
                }
                nr = ringbuffer_peek(&server->cmd_log, packet, npacket);
                if (nr != npacket) {
                    lcb_error_handler(root, LCB_EINTERNAL, NULL);
                    free(packet);
                    abort();
                }
                allocated = 1;
            }
            lcb_failout_observe_request(server, &info->ct, packet, npacket, rc);
            if (allocated) {
                free(packet);
            }
        }
        return;
    }

    /** The CAS field is split into TTP/TTR values */
    ptr = (char *)&info->res.response.cas;
    memcpy(&ttp, ptr, sizeof(ttp));
    memcpy(&ttr, ptr + sizeof(ttp), sizeof(ttp));

    ttp = ntohl(ttp);
    ttr = ntohl(ttr);

    /** Actual payload sequence of (vb, nkey, key). Repeats multiple times */
    ptr = info->payload;
    end = (char *)ptr + PACKET_NBODY(info);
    config = root->vbucket_config;

    for (pos = 0; ptr < end; pos++) {
        lcb_cas_t cas;
        lcb_uint8_t obs;
        lcb_uint16_t nkey, vb;
        const char *key;
        lcb_observe_resp_t resp;

        memcpy(&vb, ptr, sizeof(vb));
        vb = ntohs(vb);
        ptr += sizeof(vb);
        memcpy(&nkey, ptr, sizeof(nkey));
        nkey = ntohs(nkey);
        ptr += sizeof(nkey);
        key = (const char *)ptr;
        ptr += nkey;
        obs = *((lcb_uint8_t *)ptr);
        ptr += sizeof(obs);
        memcpy(&cas, ptr, sizeof(cas));
        ptr += sizeof(cas);

        setup_lcb_observe_resp_t(&resp, key, nkey, cas, obs,
                                 server->index == vbucket_get_master(config, vb),
                                 ttp, ttr);
        PACKET_TRACE(TRACE_OBSERVE_PROGRESS, info, rc, &resp);
        lcb_observe_invoke_callback(root, &info->ct, rc, &resp);
    }

    /* run callback with null-null-null to signal the end of transfer */
    if ((info->ct.flags & LCB_CMD_F_OBS_BCAST) &&
            lcb_lookup_server_with_command(root, CMD_OBSERVE,
                                           PACKET_OPAQUE(info), server) < 0) {

        lcb_observe_resp_t resp;
        memset(&resp, 0, sizeof(resp));
        PACKET_TRACE_NORES(TRACE_OBSERVE_END, info, rc);
        lcb_observe_invoke_callback(root, &info->ct, LCB_SUCCESS, &resp);
    }
}
示例#9
0
/**
 * Send a preformatted packet to the cluster
 * This prototype copies the buffers into the internal structures
 * instead of just keeping a reference...
 */
LIBCOUCHBASE_API
lcb_error_t lcb_forward_packet(lcb_t instance,
                               const void *command_cookie,
                               lcb_size_t num,
                               const lcb_packet_fwd_cmd_t *const *commands)
{
    lcb_size_t ii;

    lcb_error_handler(instance, LCB_SUCCESS, NULL);

    /* we need a vbucket config before we can start getting data.. */
    if (instance->vbucket_config == NULL) {
        switch (instance->type) {
        case LCB_TYPE_CLUSTER:
            return lcb_synchandler_return(instance, LCB_EBADHANDLE);
        case LCB_TYPE_BUCKET:
        default:
            return lcb_synchandler_return(instance, LCB_CLIENT_ETMPFAIL);
        }
    }

    /* Now handle all of the requests */
    for (ii = 0; ii < num; ++ii) {
        lcb_server_t *server;
        protocol_binary_request_no_extras *req;
        int idx;
        int vb = 0;

        /* @todo ensure that we support the current command */

        /* @todo currently the entire header needs to be in the first
         *       chunk */
        assert(commands[ii]->v.v0.buffer.iov[0].iov_len >= 24);

        /* I need to update the sequence number in the packet! */
        req = (void *)commands[ii]->v.v0.buffer.iov[0].iov_base;
        vb = ntohs(req->message.header.request.vbucket);

        if (commands[ii]->v.v0.to_master) {
            idx = vbucket_get_master(instance->vbucket_config, vb);
        } else {
            idx = vbucket_get_replica(instance->vbucket_config, vb,
                                      commands[ii]->v.v0.replica_index);
        }

        if (idx < 0 || idx > (int)instance->nservers) {
            return lcb_synchandler_return(instance, LCB_NO_MATCHING_SERVER);
        }

        server = instance->servers + idx;

        ++instance->seqno;
        /* avoid alignment crash by using memcpy */
        memcpy(&req->message.header.request.opaque, &instance->seqno, 4);

        lcb_server_start_packet(server, command_cookie,
                                commands[ii]->v.v0.buffer.iov[0].iov_base,
                                commands[ii]->v.v0.buffer.iov[0].iov_len);
        lcb_server_write_packet(server,
                                commands[ii]->v.v0.buffer.iov[1].iov_base,
                                commands[ii]->v.v0.buffer.iov[1].iov_len);
        lcb_server_end_packet(server);
        lcb_server_send_packets(server);
    }

    return lcb_synchandler_return(instance, LCB_SUCCESS);
}
示例#10
0
文件: handler.c 项目: a-c-m/couchnode
static void
H_observe(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response,
          lcb_error_t immerr)
{
    lcb_t root = pipeline->parent->instance;
    lcb_error_t rc;
    uint32_t ttp;
    uint32_t ttr;
    lcb_size_t pos;
    VBUCKET_CONFIG_HANDLE config;
    const char *end, *ptr;
    mc_REQDATAEX *rd = request->u_rdata.exdata;

    MK_ERROR(root, rc, response, immerr);

    if (rc != LCB_SUCCESS) {
        if (! (request->flags & MCREQ_F_INVOKED)) {
            rd->callback(pipeline, request, rc, NULL);
        }
        return;
    }

    /** The CAS field is split into TTP/TTR values */
    ptr = (char *)&response->res.response.cas;
    memcpy(&ttp, ptr, sizeof(ttp));
    memcpy(&ttr, ptr + sizeof(ttp), sizeof(ttp));

    ttp = ntohl(ttp);
    ttr = ntohl(ttr);

    /** Actual payload sequence of (vb, nkey, key). Repeats multiple times */
    ptr = response->payload;
    end = (char *)ptr + PACKET_NBODY(response);
    config = pipeline->parent->config;

    for (pos = 0; ptr < end; pos++) {
        lcb_cas_t cas;
        lcb_uint8_t obs;
        lcb_uint16_t nkey, vb;
        const char *key;
        lcb_observe_resp_t resp;

        memset(&resp, 0, sizeof(resp));

        memcpy(&vb, ptr, sizeof(vb));
        vb = ntohs(vb);
        ptr += sizeof(vb);
        memcpy(&nkey, ptr, sizeof(nkey));
        nkey = ntohs(nkey);
        ptr += sizeof(nkey);
        key = (const char *)ptr;
        ptr += nkey;
        obs = *((lcb_uint8_t *)ptr);
        ptr += sizeof(obs);
        memcpy(&cas, ptr, sizeof(cas));
        ptr += sizeof(cas);

        resp.v.v0.key = key;
        resp.v.v0.nkey = nkey;
        resp.v.v0.cas = cas;
        resp.v.v0.status = obs;
        resp.v.v0.ttp = 0;
        resp.v.v0.ttr = 0;
        resp.v.v0.from_master = pipeline->index == vbucket_get_master(config, vb);
        if (! (request->flags & MCREQ_F_INVOKED)) {
            rd->callback(pipeline, request, rc, &resp);
        }
    }
}
示例#11
0
static void observe_response_handler(lcb_server_t *server,
                                     struct lcb_command_data_st *command_data,
                                     protocol_binary_response_header *res)
{
    lcb_t root = server->instance;
    lcb_uint16_t status = ntohs(res->response.status);
    lcb_error_t rc = map_error(root, status);
    lcb_uint32_t ttp;
    lcb_uint32_t ttr;
    lcb_size_t pos;

    VBUCKET_CONFIG_HANDLE config;
    const char *end, *ptr = (const char *)&res->response.cas;

    /**
     * If we have an error we must decode the request instead
     */
    if (rc != LCB_SUCCESS) {
        protocol_binary_request_header req;
        lcb_size_t nr;

        nr = ringbuffer_peek(&server->cmd_log, req.bytes, sizeof(req.bytes));
        if (nr != sizeof(req.bytes)) {
            lcb_error_handler(server->instance, LCB_EINTERNAL, NULL);
            abort();
        }
        if (req.request.bodylen) {
            lcb_size_t npacket = sizeof(req.bytes) + ntohl(req.request.bodylen);
            char *packet = server->cmd_log.read_head;
            int allocated = 0;

            if (!ringbuffer_is_continous(&server->cmd_log, RINGBUFFER_READ, npacket)) {
                packet = malloc(npacket);
                if (packet == NULL) {
                    lcb_error_handler(root, LCB_CLIENT_ENOMEM, NULL);
                    abort();
                }
                nr = ringbuffer_peek(&server->cmd_log, packet, npacket);
                if (nr != npacket) {
                    lcb_error_handler(root, LCB_EINTERNAL, NULL);
                    free(packet);
                    abort();
                }
                allocated = 1;
            }
            lcb_failout_observe_request(server, command_data, packet, npacket, rc);
            if (allocated) {
                free(packet);
            }
        }
        return;
    }


    memcpy(&ttp, ptr, sizeof(ttp));
    ttp = ntohl(ttp);
    memcpy(&ttr, ptr + sizeof(ttp), sizeof(ttr));
    ttr = ntohl(ttr);


    ptr = (const char *)res + sizeof(res->bytes);
    end = ptr + ntohl(res->response.bodylen);
    config = root->vbucket_config;
    for (pos = 0; ptr < end; pos++) {
        lcb_cas_t cas;
        lcb_uint8_t obs;
        lcb_uint16_t nkey, vb;
        const char *key;
        lcb_observe_resp_t resp;

        memcpy(&vb, ptr, sizeof(vb));
        vb = ntohs(vb);
        ptr += sizeof(vb);
        memcpy(&nkey, ptr, sizeof(nkey));
        nkey = ntohs(nkey);
        ptr += sizeof(nkey);
        key = (const char *)ptr;
        ptr += nkey;
        obs = *((lcb_uint8_t *)ptr);
        ptr += sizeof(obs);
        memcpy(&cas, ptr, sizeof(cas));
        ptr += sizeof(cas);

        setup_lcb_observe_resp_t(&resp, key, nkey, cas, obs,
                                 server->index == vbucket_get_master(config, vb),
                                 ttp, ttr);
        TRACE_OBSERVE_PROGRESS(res->response.opaque, command_data->vbucket,
                               res->response.opcode, rc, &resp);
        lcb_observe_invoke_callback(root, command_data, rc, &resp);
    }

    /* run callback with null-null-null to signal the end of transfer */
    if ((command_data->flags & LCB_CMD_F_OBS_BCAST) &&
            lcb_lookup_server_with_command(root, CMD_OBSERVE,
                                           res->response.opaque, server) < 0) {

        lcb_observe_resp_t resp;
        memset(&resp, 0, sizeof(resp));
        TRACE_OBSERVE_END(res->response.opaque, command_data->vbucket,
                          res->response.opcode, rc);
        lcb_observe_invoke_callback(root, command_data, LCB_SUCCESS, &resp);
    }
}