Пример #1
0
LIBCOUCHBASE_API
lcb_error_t
lcb_get3(lcb_t instance, const void *cookie, const lcb_CMDGET *cmd)
{
    mc_PIPELINE *pl;
    mc_PACKET *pkt;
    mc_REQDATA *rdata;
    mc_CMDQUEUE *q = &instance->cmdq;
    lcb_error_t err;
    lcb_uint8_t extlen = 0;
    lcb_uint8_t opcode = PROTOCOL_BINARY_CMD_GET;
    protocol_binary_request_gat gcmd;
    protocol_binary_request_header *hdr = &gcmd.message.header;

    if (LCB_KEYBUF_IS_EMPTY(&cmd->key)) {
        return LCB_EMPTY_KEY;
    }
    if (cmd->cas) {
        return LCB_OPTIONS_CONFLICT;
    }

    if (cmd->lock) {
        extlen = 4;
        opcode = PROTOCOL_BINARY_CMD_GET_LOCKED;
    } else if (cmd->exptime) {
        extlen = 4;
        opcode = PROTOCOL_BINARY_CMD_GAT;
    }

    err = mcreq_basic_packet(q, (const lcb_CMDBASE *)cmd, hdr, extlen, &pkt, &pl,
        MCREQ_BASICPACKET_F_FALLBACKOK);
    if (err != LCB_SUCCESS) {
        return err;
    }

    rdata = &pkt->u_rdata.reqdata;
    rdata->cookie = cookie;
    rdata->start = gethrtime();

    hdr->request.magic = PROTOCOL_BINARY_REQ;
    hdr->request.opcode = opcode;
    hdr->request.datatype = PROTOCOL_BINARY_RAW_BYTES;
    hdr->request.bodylen = htonl(extlen + ntohs(hdr->request.keylen));
    hdr->request.opaque = pkt->opaque;
    hdr->request.cas = 0;

    if (extlen) {
        gcmd.message.body.expiration = htonl(cmd->exptime);
    }

    if (cmd->cmdflags & LCB_CMD_F_INTERNAL_CALLBACK) {
        pkt->flags |= MCREQ_F_PRIVCALLBACK;
    }

    memcpy(SPAN_BUFFER(&pkt->kh_span), gcmd.bytes, MCREQ_PKT_BASESIZE + extlen);
    mcreq_sched_add(pl, pkt);
    TRACE_GET_BEGIN(hdr, cmd);

    return LCB_SUCCESS;
}
Пример #2
0
static void get_replica_response_handler(lcb_server_t *server,
                                         packet_info *info)
{
    lcb_t root = server->instance;
    lcb_uint16_t nkey;
    const char *key;
    char *packet;
    lcb_uint16_t status = PACKET_STATUS(info);

    lcb_error_t rc = map_error(root, status);

    /**
     * Success? always perform the callback
     */
    if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
        const protocol_binary_response_get *get = PACKET_EPHEMERAL_START(info);
        lcb_get_resp_t resp;
        setup_lcb_get_resp_t(&resp,
                             PACKET_KEY(info), PACKET_NKEY(info),
                             PACKET_VALUE(info), PACKET_NVALUE(info),
                             ntohl(get->message.body.flags),
                             PACKET_CAS(info),
                             PACKET_DATATYPE(info));
        root->callbacks.get(root, info->ct.cookie, rc, &resp);
        return;
    }

    key = get_key(server, &nkey, &packet);

    /**
     * Following code handles errors.
     */
    if (info->ct.replica == -1) {
        /* Perform the callback. Either SELECT or ALL */
        lcb_get_resp_t resp;
        setup_lcb_get_resp_t(&resp, key, nkey, NULL, 0, 0, 0, 0);
        PACKET_TRACE(TRACE_GET_END, info, rc, &resp);
        root->callbacks.get(root, info->ct.cookie, rc, &resp);
        release_key(server, packet);
        return;
    }

    /** LCB_REPLICA_FIRST */
    if (status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET) {
        /**
         * the config was updated, start from first replica.
         * Reset the iteration count
         */
        info->ct.replica = 0;
    } else {
        info->ct.replica++;
    }

    if (info->ct.replica < root->nreplicas) {
        /* try next replica */
        protocol_binary_request_get req;
        lcb_server_t *new_server;
        int idx = vbucket_get_replica(root->vbucket_config,
                                      info->ct.vbucket,
                                      info->ct.replica);
        if (idx < 0 || idx > (int)root->nservers) {
            lcb_error_handler(root, LCB_NETWORK_ERROR,
                              "GET_REPLICA: missing server");
            release_key(server, packet);
            return;
        }
        new_server = root->servers + idx;
        memset(&req, 0, sizeof(req));
        req.message.header.request.magic = PROTOCOL_BINARY_REQ;
        req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
        req.message.header.request.opcode = CMD_GET_REPLICA;
        req.message.header.request.keylen = ntohs((lcb_uint16_t)nkey);
        req.message.header.request.vbucket = ntohs(info->ct.vbucket);
        req.message.header.request.bodylen = ntohl((lcb_uint32_t)nkey);
        req.message.header.request.opaque = ++root->seqno;
        TRACE_GET_BEGIN(&req, key, nkey, 0);
        lcb_server_retry_packet(new_server, &info->ct,
                                req.bytes, sizeof(req.bytes));
        lcb_server_write_packet(new_server, key, nkey);
        lcb_server_end_packet(new_server);
        lcb_server_send_packets(new_server);
    } else {
        /* give up and report the error */
        lcb_get_resp_t resp;
        setup_lcb_get_resp_t(&resp, key, nkey, NULL, 0, 0, 0, 0);
        PACKET_TRACE(TRACE_GET_END, info, rc, &resp)
        root->callbacks.get(root, info->ct.cookie, rc, &resp);
    }

    release_key(server, packet);
}
Пример #3
0
static void get_replica_response_handler(lcb_server_t *server,
                                         struct lcb_command_data_st *command_data,
                                         protocol_binary_response_header *res)
{
    lcb_t root = server->instance;
    protocol_binary_response_get *get = (void *)res;
    lcb_uint16_t status = ntohs(res->response.status);
    lcb_uint16_t nkey = ntohs(res->response.keylen);
    const char *key = (const char *)res;
    char *packet;

    lcb_error_t rc = map_error(root, status);

    key += sizeof(get->bytes);
    if (key == NULL) {
        lcb_error_handler(server->instance, LCB_EINTERNAL, NULL);
        return;
    }
    /**
     * Success? always perform the callback
     */
    if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
        const char *bytes = key + nkey;
        lcb_size_t nbytes = ntohl(res->response.bodylen) - nkey - res->response.extlen;
        lcb_get_resp_t resp;
        setup_lcb_get_resp_t(&resp, key, nkey, bytes, nbytes,
                             ntohl(get->message.body.flags),
                             res->response.cas,
                             res->response.datatype);
        TRACE_GET_END(res->response.opaque, command_data->vbucket,
                      res->response.opcode, rc, &resp);
        root->callbacks.get(root, command_data->cookie, rc, &resp);
        return;
    }

    key = get_key(server, &nkey, &packet);

    /**
     * Following code handles errors.
     */
    if (command_data->replica == -1) {
        /* Perform the callback. Either SELECT or ALL */
        lcb_get_resp_t resp;
        setup_lcb_get_resp_t(&resp, key, nkey, NULL, 0, 0, 0, 0);
        TRACE_GET_END(res->response.opaque, command_data->vbucket,
                      res->response.opcode, rc, &resp);
        root->callbacks.get(root, command_data->cookie, rc, &resp);
        release_key(server, packet);
        return;
    }

    /** LCB_REPLICA_FIRST */
    if (status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET) {
        /**
         * the config was updated, start from first replica.
         * Reset the iteration count
         */
        command_data->replica = 0;
    } else {
        command_data->replica++;
    }

    if (command_data->replica < root->nreplicas) {
        /* try next replica */
        protocol_binary_request_get req;
        lcb_server_t *new_server;
        int idx = vbucket_get_replica(root->vbucket_config,
                                      command_data->vbucket,
                                      command_data->replica);
        if (idx < 0 || idx > (int)root->nservers) {
            lcb_error_handler(root, LCB_NETWORK_ERROR,
                              "GET_REPLICA: missing server");
            release_key(server, packet);
            return;
        }
        new_server = root->servers + idx;
        memset(&req, 0, sizeof(req));
        req.message.header.request.magic = PROTOCOL_BINARY_REQ;
        req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
        req.message.header.request.opcode = CMD_GET_REPLICA;
        req.message.header.request.keylen = ntohs((lcb_uint16_t)nkey);
        req.message.header.request.vbucket = ntohs(command_data->vbucket);
        req.message.header.request.bodylen = ntohl((lcb_uint32_t)nkey);
        req.message.header.request.opaque = ++root->seqno;
        TRACE_GET_BEGIN(&req, key, nkey, 0);
        lcb_server_retry_packet(new_server, command_data,
                                req.bytes, sizeof(req.bytes));
        lcb_server_write_packet(new_server, key, nkey);
        lcb_server_end_packet(new_server);
        lcb_server_send_packets(new_server);
    } else {
        /* give up and report the error */
        lcb_get_resp_t resp;
        setup_lcb_get_resp_t(&resp, key, nkey, NULL, 0, 0, 0,
                             res->response.datatype);
        TRACE_GET_END(res->response.opaque, command_data->vbucket,
                      res->response.opcode, rc, &resp);
        root->callbacks.get(root, command_data->cookie, rc, &resp);
    }

    release_key(server, packet);
}