Ejemplo n.º 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;
}
Ejemplo n.º 2
0
LIBCOUCHBASE_API
lcb_error_t
lcb_remove3(lcb_t instance, const void *cookie, const lcb_CMDREMOVE * cmd)
{
    mc_CMDQUEUE *cq = &instance->cmdq;
    mc_PIPELINE *pl;
    mc_PACKET *pkt;
    lcb_error_t err;
    protocol_binary_request_header hdr;

    err = mcreq_basic_packet(cq, cmd, &hdr, 0, &pkt, &pl);
    if (err != LCB_SUCCESS) {
        return err;
    }


    hdr.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
    hdr.request.magic = PROTOCOL_BINARY_REQ;
    hdr.request.opcode = PROTOCOL_BINARY_CMD_DELETE;
    hdr.request.cas = cmd->options.cas;
    hdr.request.opaque = pkt->opaque;
    hdr.request.bodylen = htonl((lcb_uint32_t)ntohs(hdr.request.keylen));

    pkt->u_rdata.reqdata.cookie = cookie;
    pkt->u_rdata.reqdata.start = gethrtime();
    memcpy(SPAN_BUFFER(&pkt->kh_span), hdr.bytes, sizeof(hdr.bytes));
    mcreq_sched_add(pl, pkt);
    return LCB_SUCCESS;
}
Ejemplo n.º 3
0
LIBCOUCHBASE_API
lcb_error_t
lcb_touch3(lcb_t instance, const void *cookie, const lcb_CMDTOUCH *cmd)
{
    protocol_binary_request_touch tcmd;
    protocol_binary_request_header *hdr = &tcmd.message.header;
    mc_PIPELINE *pl;
    mc_PACKET *pkt;
    lcb_error_t err;

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

    err = mcreq_basic_packet(&instance->cmdq, cmd, hdr, 4, &pkt, &pl,
        MCREQ_BASICPACKET_F_FALLBACKOK);
    if (err != LCB_SUCCESS) {
        return err;
    }

    hdr->request.magic = PROTOCOL_BINARY_REQ;
    hdr->request.opcode = PROTOCOL_BINARY_CMD_TOUCH;
    hdr->request.cas = 0;
    hdr->request.datatype = PROTOCOL_BINARY_RAW_BYTES;
    hdr->request.opaque = pkt->opaque;
    hdr->request.bodylen = htonl(4 + ntohs(hdr->request.keylen));
    tcmd.message.body.expiration = htonl(cmd->exptime);
    memcpy(SPAN_BUFFER(&pkt->kh_span), tcmd.bytes, sizeof(tcmd.bytes));
    pkt->u_rdata.reqdata.cookie = cookie;
    pkt->u_rdata.reqdata.start = gethrtime();
    mcreq_sched_add(pl, pkt);
    return LCB_SUCCESS;
}
Ejemplo n.º 4
0
static lcb_error_t
obs_ctxdone(lcb_MULTICMD_CTX *mctx, const void *cookie)
{
    unsigned ii;
    OBSERVECTX *ctx = CTX_FROM_MULTI(mctx);
    mc_CMDQUEUE *cq = &ctx->instance->cmdq;

    for (ii = 0; ii < ctx->nrequests; ii++) {
        protocol_binary_request_header hdr;
        mc_PACKET *pkt;
        mc_PIPELINE *pipeline;
        lcb_string *rr = ctx->requests + ii;
        pipeline = cq->pipelines[ii];

        if (!rr->nused) {
            continue;
        }

        pkt = mcreq_allocate_packet(pipeline);
        lcb_assert(pkt);

        mcreq_reserve_header(pipeline, pkt, MCREQ_PKT_BASESIZE);
        mcreq_reserve_value2(pipeline, pkt, rr->nused);

        hdr.request.magic = PROTOCOL_BINARY_REQ;
        hdr.request.opcode = PROTOCOL_BINARY_CMD_OBSERVE;
        hdr.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
        hdr.request.keylen = 0;
        hdr.request.cas = 0;
        hdr.request.vbucket = 0;
        hdr.request.extlen = 0;
        hdr.request.opaque = pkt->opaque;
        hdr.request.bodylen = htonl((lcb_uint32_t)rr->nused);

        memcpy(SPAN_BUFFER(&pkt->kh_span), hdr.bytes, sizeof(hdr.bytes));
        memcpy(SPAN_BUFFER(&pkt->u_value.single), rr->base, rr->nused);

        pkt->flags |= MCREQ_F_REQEXT;
        pkt->u_rdata.exdata = (mc_REQDATAEX *)ctx;
        mcreq_sched_add(pipeline, pkt);
        TRACE_OBSERVE_BEGIN(&hdr, SPAN_BUFFER(&pkt->u_value.single));
    }

    destroy_requests(ctx);
    ctx->base.start = gethrtime();
    ctx->base.cookie = cookie;
    ctx->base.procs = &obs_procs;

    if (ctx->nrequests == 0 || ctx->remaining == 0) {
        free(ctx);
        return LCB_EINVAL;
    } else {
        MAYBE_SCHEDLEAVE(ctx->instance);
        return LCB_SUCCESS;
    }
}
Ejemplo n.º 5
0
LIBCOUCHBASE_API
lcb_error_t
lcb_counter3(
        lcb_t instance, const void *cookie, const lcb_CMDCOUNTER *cmd)
{
    mc_CMDQUEUE *q = &instance->cmdq;
    mc_PIPELINE *pipeline;
    mc_PACKET *packet;
    mc_REQDATA *rdata;
    lcb_error_t err;

    protocol_binary_request_incr acmd;
    protocol_binary_request_header *hdr = &acmd.message.header;

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

    err = mcreq_basic_packet(q, (const lcb_CMDBASE *)cmd, hdr, 20, &packet,
        &pipeline, MCREQ_BASICPACKET_F_FALLBACKOK);

    if (err != LCB_SUCCESS) {
        return err;
    }

    rdata = &packet->u_rdata.reqdata;
    rdata->cookie = cookie;
    rdata->start = gethrtime();
    hdr->request.magic = PROTOCOL_BINARY_REQ;
    hdr->request.datatype = PROTOCOL_BINARY_RAW_BYTES;
    hdr->request.cas = 0;
    hdr->request.opaque = packet->opaque;
    hdr->request.bodylen =
            htonl(hdr->request.extlen + ntohs(hdr->request.keylen));

    acmd.message.body.delta = ntohll((lcb_uint64_t)cmd->delta);
    acmd.message.body.initial = ntohll(cmd->initial);
    if (!cmd->create) {
        memset(&acmd.message.body.expiration, 0xff,
               sizeof(acmd.message.body.expiration));
    } else {
        acmd.message.body.expiration = htonl(cmd->exptime);
    }

    if (cmd->delta < 0) {
        hdr->request.opcode = PROTOCOL_BINARY_CMD_DECREMENT;
        acmd.message.body.delta = ntohll((lcb_uint64_t)(cmd->delta * -1));
    } else {
        hdr->request.opcode = PROTOCOL_BINARY_CMD_INCREMENT;
    }

    memcpy(SPAN_BUFFER(&packet->kh_span), acmd.bytes, sizeof(acmd.bytes));
    TRACE_ARITHMETIC_BEGIN(hdr, cmd);
    mcreq_sched_add(pipeline, packet);
    return LCB_SUCCESS;
}
Ejemplo n.º 6
0
static void
rget_callback(mc_PIPELINE *pl, mc_PACKET *pkt, lcb_error_t err, const void *arg)
{
    rget_cookie *rck = (rget_cookie *)pkt->u_rdata.exdata;
    lcb_RESPGET *resp = (void *)arg;
    lcb_RESPCALLBACK callback;
    lcb_t instance = rck->instance;

    callback = lcb_find_callback(instance, LCB_CALLBACK_GETREPLICA);

    /** Figure out what the strategy is.. */
    if (rck->strategy == LCB_REPLICA_SELECT || rck->strategy == LCB_REPLICA_ALL) {
        /** Simplest */
        if (rck->strategy == LCB_REPLICA_SELECT || rck->remaining == 1) {
            resp->rflags |= LCB_RESP_F_FINAL;
        }
        callback(instance, LCB_CALLBACK_GETREPLICA, (const lcb_RESPBASE *)resp);
    } else {
        mc_CMDQUEUE *cq = &instance->cmdq;
        mc_PIPELINE *nextpl = NULL;

        /** FIRST */
        do {
            int nextix;
            rck->r_cur++;
            nextix = lcbvb_vbreplica(cq->config, rck->vbucket, rck->r_cur);
            if (nextix > -1 && nextix < (int)cq->npipelines) {
                /* have a valid next index? */
                nextpl = cq->pipelines[nextix];
                break;
            }
        } while (rck->r_cur < rck->r_max);

        if (err == LCB_SUCCESS || rck->r_cur == rck->r_max || nextpl == NULL) {
            resp->rflags |= LCB_RESP_F_FINAL;
            callback(instance, LCB_CALLBACK_GETREPLICA, (lcb_RESPBASE *)resp);
            /* refcount=1 . Free this now */
            rck->remaining = 1;
        } else if (err != LCB_SUCCESS) {
            mc_PACKET *newpkt = mcreq_renew_packet(pkt);
            newpkt->flags &= ~MCREQ_STATE_FLAGS;
            mcreq_sched_add(nextpl, newpkt);
            /* Use this, rather than lcb_sched_leave(), because this is being
             * invoked internally by the library. */
            mcreq_sched_leave(cq, 1);
            /* wait */
            rck->remaining = 2;
        }
    }

    if (!--rck->remaining) {
        free(rck);
    }
    (void)pl;
}
Ejemplo n.º 7
0
static void
rget_callback(mc_PIPELINE *pl, mc_PACKET *pkt, lcb_error_t err, const void *arg)
{
    rget_cookie *rck = (rget_cookie *)pkt->u_rdata.exdata;
    const lcb_get_resp_t *resp = arg;
    lcb_t instance = rck->instance;

    /** Figure out what the strategy is.. */
    if (rck->strategy == LCB_REPLICA_SELECT || rck->strategy == LCB_REPLICA_ALL) {
        /** Simplest */
        instance->callbacks.get(instance, rck->base.cookie, err, resp);
    } else {
        mc_CMDQUEUE *cq = &instance->cmdq;
        mc_PIPELINE *nextpl = NULL;

        /** FIRST */
        do {
            int nextix;
            rck->r_cur++;
            nextix = lcbvb_vbreplica(cq->config, rck->vbucket, rck->r_cur);
            if (nextix > -1 && nextix < (int)cq->npipelines) {
                /* have a valid next index? */
                nextpl = cq->pipelines[nextix];
                break;
            }
        } while (rck->r_cur < rck->r_max);

        if (err == LCB_SUCCESS || rck->r_cur == rck->r_max || nextpl == NULL) {
            instance->callbacks.get(instance, rck->base.cookie, err, resp);
            /* refcount=1 . Free this now */
            rck->remaining = 1;
        } else if (err != LCB_SUCCESS) {
            mc_PACKET *newpkt = mcreq_dup_packet(pkt);
            mcreq_sched_add(nextpl, newpkt);
            mcreq_sched_leave(cq, 1);
            /* wait */
            rck->remaining = 2;
        }
    }
    if (!--rck->remaining) {
        free(rck);
    }
    (void)pl;
}
Ejemplo n.º 8
0
LIBCOUCHBASE_API
lcb_error_t
lcb_unlock3(lcb_t instance, const void *cookie, const lcb_CMDUNLOCK *cmd)
{
    mc_CMDQUEUE *cq = &instance->cmdq;
    mc_PIPELINE *pl;
    mc_PACKET *pkt;
    mc_REQDATA *rd;
    lcb_error_t err;
    protocol_binary_request_header hdr;

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

    err = mcreq_basic_packet(cq, cmd, &hdr, 0, &pkt, &pl,
        MCREQ_BASICPACKET_F_FALLBACKOK);
    if (err != LCB_SUCCESS) {
        return err;
    }

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

    hdr.request.magic = PROTOCOL_BINARY_REQ;
    hdr.request.opcode = PROTOCOL_BINARY_CMD_UNLOCK_KEY;
    hdr.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
    hdr.request.bodylen = htonl((lcb_uint32_t)ntohs(hdr.request.keylen));
    hdr.request.opaque = pkt->opaque;
    hdr.request.cas = cmd->cas;

    memcpy(SPAN_BUFFER(&pkt->kh_span), hdr.bytes, sizeof(hdr.bytes));
    TRACE_UNLOCK_BEGIN(&hdr, cmd);
    mcreq_sched_add(pl, pkt);
    return LCB_SUCCESS;
}
Ejemplo n.º 9
0
LIBCOUCHBASE_API
lcb_error_t
lcb_rget3(lcb_t instance, const void *cookie, const lcb_CMDGETREPLICA *cmd)
{
    /**
     * Because we need to direct these commands to specific servers, we can't
     * just use the 'basic_packet()' function.
     */
    mc_CMDQUEUE *cq = &instance->cmdq;
    const void *hk;
    lcb_size_t nhk;
    int vbid;
    protocol_binary_request_header req;
    unsigned r0, r1;
    rget_cookie *rck = NULL;

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

    mcreq_extract_hashkey(&cmd->key, &cmd->hashkey, MCREQ_PKT_BASESIZE, &hk, &nhk);
    vbid = lcbvb_k2vb(cq->config, hk, nhk);

    /** Get the vbucket by index */
    if (cmd->strategy == LCB_REPLICA_SELECT) {
        r0 = r1 = cmd->index;
    } else if (cmd->strategy == LCB_REPLICA_ALL) {
        r0 = 0;
        r1 = instance->nreplicas;
    } else {
        /* first */
        r0 = r1 = 0;
    }

    if (r1 < r0 || r1 >= cq->npipelines) {
        return LCB_NO_MATCHING_SERVER;
    }

    /* Initialize the cookie */
    rck = calloc(1, sizeof(*rck));
    rck->base.cookie = cookie;
    rck->base.start = gethrtime();
    rck->base.callback = rget_callback;
    rck->strategy = cmd->strategy;
    rck->r_cur = r0;
    rck->r_max = instance->nreplicas;
    rck->instance = instance;
    rck->vbucket = vbid;

    /* Initialize the packet */
    req.request.magic = PROTOCOL_BINARY_REQ;
    req.request.opcode = PROTOCOL_BINARY_CMD_GET_REPLICA;
    req.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
    req.request.vbucket = htons((lcb_uint16_t)vbid);
    req.request.cas = 0;
    req.request.extlen = 0;
    req.request.keylen = htons((lcb_uint16_t)cmd->key.contig.nbytes);
    req.request.bodylen = htonl((lcb_uint32_t)cmd->key.contig.nbytes);

    do {
        int curix;
        mc_PIPELINE *pl;
        mc_PACKET *pkt;

        curix = lcbvb_vbreplica(cq->config, vbid, r0);
        if (curix == -1) {
            return LCB_NO_MATCHING_SERVER;
        }

        pl = cq->pipelines[curix];
        pkt = mcreq_allocate_packet(pl);
        if (!pkt) {
            return LCB_CLIENT_ENOMEM;
        }

        pkt->u_rdata.exdata = &rck->base;
        pkt->flags |= MCREQ_F_REQEXT;

        mcreq_reserve_key(pl, pkt, sizeof(req.bytes), &cmd->key);

        req.request.opaque = pkt->opaque;
        rck->remaining++;
        mcreq_write_hdr(pkt, &req);
        mcreq_sched_add(pl, pkt);
    } while (++r0 < r1);
    return LCB_SUCCESS;
}
Ejemplo n.º 10
0
lcb_STATUS mc_forward_packet(mc_CMDQUEUE *cq, mc_IOVINFO *info, mc_PACKET **pkt_p, mc_PIPELINE **pl_p, int options)
{
    /* stack based header with our modifications. this is copied into the
     * packet's actual header */
    protocol_binary_request_header hdr;
    int vbid, srvix;
    mc_IOVCURSOR *mincur = &info->c;

    unsigned n_packet;     /* total packet size */
    unsigned n_header;     /* extras + key + memcached header */
    unsigned n_body_total; /* size of everything following the memcached header */
    unsigned n_body_key;   /* length of the key */
    unsigned n_body_value; /* packetsize - hdrsize */

    unsigned offset;

    /* stack buffer and key pointer. stack buffer is used if the key is not
     * contiguous */
    char kbuf_s[256];
    const char *kptr;

    /* pipeline and packet for command */
    mc_PIPELINE *pl;
    mc_PACKET *pkt;
    info->wanted = 0;

    /* not enough bytes */
    if (info->total < 24) {
        info->wanted = 24;
        return LCB_INCOMPLETE_PACKET;
    }

    iovcursor_peek(mincur, (char *)hdr.bytes, sizeof hdr.bytes, 0);

    /* Initialize our size variables */
    n_body_total = ntohl(hdr.request.bodylen);
    n_body_key = ntohs(hdr.request.keylen);
    n_header = sizeof hdr.bytes + n_body_key + hdr.request.extlen;
    n_packet = n_body_total + sizeof hdr.bytes;
    n_body_value = n_packet - n_header;

    if (n_packet > info->total) {
        info->wanted = n_packet;
        return LCB_INCOMPLETE_PACKET;
    }

    info->total -= n_packet;

    /* seek ahead to read the item's key into the header */
    offset = sizeof hdr.bytes + hdr.request.extlen;

    iovcursor_peek_ex(mincur, kbuf_s, &kptr, n_body_key, offset);

    if (kptr == NULL) {
        /* key is not contiguous? that's ok. use the static buffer */
        kptr = kbuf_s;
    }

    if ((options & MC_FWD_OPT_NOMAP) == 0) {
        lcbvb_map_key(cq->config, kptr, n_body_key, &vbid, &srvix);
        if (srvix < 0 || (unsigned)srvix >= cq->npipelines) {
            return LCB_NO_MATCHING_SERVER;
        }
        pl = cq->pipelines[srvix];
        hdr.request.vbucket = htons(vbid);

    } else {
        pl = *pl_p;
        if (!pl) {
            return LCB_EINVAL;
        }
        srvix = pl->index;
    }

    pkt = mcreq_allocate_packet(pl);

    if (pkt == NULL) {
        return LCB_CLIENT_ENOMEM;
    }

    hdr.request.opaque = pkt->opaque;
    pkt->extlen = hdr.request.extlen;
    info->consumed = n_packet;

    if (options & MC_FWD_OPT_COPY) {
        /* reserve bytes for the entire packet */
        mcreq_reserve_header(pl, pkt, n_header);
        iovcursor_adv_copy(mincur, SPAN_BUFFER(&pkt->kh_span), n_header);
        if (n_body_value) {
            mcreq_reserve_value2(pl, pkt, n_body_value);
            iovcursor_adv_copy(mincur, SPAN_BUFFER(&pkt->u_value.single), n_body_value);
            pkt->flags |= MCREQ_F_HASVALUE;
        }

    } else {
        if (IOVCURSOR_HAS_CONTIG(mincur, n_header)) {
            span_from_first(mincur, n_header, &pkt->kh_span);
            pkt->flags |= MCREQ_F_KEY_NOCOPY;

        } else {
            /* header is fragmented into multiple IOVs */
            mcreq_reserve_header(pl, pkt, n_header);
            iovcursor_adv_copy(mincur, SPAN_BUFFER(&pkt->kh_span), n_header);
        }

        /* do we have a value payload still? */
        if (n_body_value) {
            pkt->flags |= MCREQ_F_HASVALUE | MCREQ_F_VALUE_NOCOPY;
            if (IOVCURSOR_HAS_CONTIG(mincur, n_body_value)) {
                span_from_first(mincur, n_body_value, &pkt->u_value.single);

            } else {
                /* body is fragmented */
                iovcursor_adv_iovalloc(mincur, n_body_value, (nb_IOV **)&pkt->u_value.multi.iov,
                                       &pkt->u_value.multi.niov);
                pkt->u_value.multi.total_length = n_body_value;
                pkt->flags |= MCREQ_F_VALUE_IOV;
            }
        }
    }

    /* Copy the first 24 bytes into the header span */
    memcpy(SPAN_BUFFER(&pkt->kh_span), hdr.bytes, sizeof hdr.bytes);

    *pkt_p = pkt;
    *pl_p = pl;

    /* Set the UFWD flag. This causes the rest of the system to invoke the
     * handler for the raw response, rather than the "Contiguous" structures*/
    pkt->flags |= MCREQ_F_UFWD;
    mcreq_sched_add(pl, pkt);
    return LCB_SUCCESS;
}
Ejemplo n.º 11
0
static lcb_error_t
do_store3(lcb_t instance, const void *cookie,
    const lcb_CMDBASE *cmd, int is_durstore)
{
    mc_PIPELINE *pipeline;
    mc_PACKET *packet;
    mc_REQDATA *rdata;
    mc_CMDQUEUE *cq = &instance->cmdq;
    int hsize;
    int should_compress = 0;
    lcb_error_t err;

    lcb_storage_t operation;
    lcb_U32 flags;
    const lcb_VALBUF *vbuf;
    lcb_datatype_t datatype;

    protocol_binary_request_set scmd;
    protocol_binary_request_header *hdr = &scmd.message.header;

    if (!is_durstore) {
        const lcb_CMDSTORE *simple_cmd = (const lcb_CMDSTORE *)cmd;
        operation = simple_cmd->operation;
        flags = simple_cmd->flags;
        vbuf = &simple_cmd->value;
        datatype = simple_cmd->datatype;
    } else {
        const lcb_CMDSTOREDUR *durcmd = (const lcb_CMDSTOREDUR *)cmd;
        operation = durcmd->operation;
        flags = durcmd->flags;
        vbuf = &durcmd->value;
        datatype = durcmd->datatype;
    }

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

    err = get_esize_and_opcode(
        operation, &hdr->request.opcode, &hdr->request.extlen);
    if (err != LCB_SUCCESS) {
        return err;
    }

    switch (operation) {
    case LCB_APPEND:
    case LCB_PREPEND:
        if (cmd->exptime || flags) {
            return LCB_OPTIONS_CONFLICT;
        }
        break;
    case LCB_ADD:
        if (cmd->cas) {
            return LCB_OPTIONS_CONFLICT;
        }
        break;
    default:
        break;
    }

    hsize = hdr->request.extlen + sizeof(*hdr);

    err = mcreq_basic_packet(cq, (const lcb_CMDBASE *)cmd, hdr,
        hdr->request.extlen, &packet, &pipeline, MCREQ_BASICPACKET_F_FALLBACKOK);

    if (err != LCB_SUCCESS) {
        return err;
    }

    should_compress = can_compress(instance, pipeline, vbuf, datatype);
    if (should_compress) {
        int rv = mcreq_compress_value(pipeline, packet, &vbuf->u_buf.contig);
        if (rv != 0) {
            mcreq_release_packet(pipeline, packet);
            return LCB_CLIENT_ENOMEM;
        }
    } else {
        mcreq_reserve_value(pipeline, packet, vbuf);
    }

    if (is_durstore) {
        int duropts = 0;
        lcb_U16 persist_u , replicate_u;
        const lcb_CMDSTOREDUR *dcmd = (const lcb_CMDSTOREDUR *)cmd;
        DURSTORECTX *dctx = calloc(1, sizeof(*dctx));

        persist_u = dcmd->persist_to;
        replicate_u = dcmd->replicate_to;
        if (dcmd->replicate_to == -1 || dcmd->persist_to == -1) {
            duropts = LCB_DURABILITY_VALIDATE_CAPMAX;
        }

        err = lcb_durability_validate(instance, &persist_u, &replicate_u, duropts);
        if (err != LCB_SUCCESS) {
            mcreq_wipe_packet(pipeline, packet);
            mcreq_release_packet(pipeline, packet);
            return err;
        }

        dctx->instance = instance;
        dctx->persist_to = persist_u;
        dctx->replicate_to = replicate_u;
        packet->u_rdata.exdata = &dctx->base;
        packet->flags |= MCREQ_F_REQEXT;

        dctx->base.cookie = cookie;
        dctx->base.procs = &storedur_procs;
    }

    rdata = MCREQ_PKT_RDATA(packet);
    rdata->cookie = cookie;
    rdata->start = gethrtime();

    scmd.message.body.expiration = htonl(cmd->exptime);
    scmd.message.body.flags = htonl(flags);
    hdr->request.magic = PROTOCOL_BINARY_REQ;
    hdr->request.cas = cmd->cas;
    hdr->request.datatype = PROTOCOL_BINARY_RAW_BYTES;

    if (should_compress || (datatype & LCB_VALUE_F_SNAPPYCOMP)) {
        hdr->request.datatype |= PROTOCOL_BINARY_DATATYPE_COMPRESSED;
    }
    if (datatype & LCB_VALUE_F_JSON) {
        hdr->request.datatype |= PROTOCOL_BINARY_DATATYPE_JSON;
    }

    hdr->request.opaque = packet->opaque;
    hdr->request.bodylen = htonl(
            hdr->request.extlen + ntohs(hdr->request.keylen)
            + get_value_size(packet));

    memcpy(SPAN_BUFFER(&packet->kh_span), scmd.bytes, hsize);
    mcreq_sched_add(pipeline, packet);
    TRACE_STORE_BEGIN(hdr, (lcb_CMDSTORE* )cmd);
    return LCB_SUCCESS;
}
Ejemplo n.º 12
0
LIBCOUCHBASE_API
lcb_error_t
lcb_rget3(lcb_t instance, const void *cookie, const lcb_CMDGETREPLICA *cmd)
{
    /**
     * Because we need to direct these commands to specific servers, we can't
     * just use the 'basic_packet()' function.
     */
    mc_CMDQUEUE *cq = &instance->cmdq;
    int vbid, ixtmp;
    protocol_binary_request_header req;
    unsigned r0, r1 = 0;
    rget_cookie *rck = NULL;

    if (LCB_KEYBUF_IS_EMPTY(&cmd->key)) {
        return LCB_EMPTY_KEY;
    }
    if (!cq->config) {
        return LCB_CLIENT_ETMPFAIL;
    }
    if (!LCBT_NREPLICAS(instance)) {
        return LCB_NO_MATCHING_SERVER;
    }

    mcreq_map_key(cq, &cmd->key, &cmd->_hashkey, MCREQ_PKT_BASESIZE,
        &vbid, &ixtmp);

    /* The following blocks will also validate that the entire index range is
     * valid. This is in order to ensure that we don't allocate the cookie
     * if there aren't enough replicas online to satisfy the requirements */

    if (cmd->strategy == LCB_REPLICA_SELECT) {
        r0 = r1 = cmd->index;
        if ((ixtmp = lcbvb_vbreplica(cq->config, vbid, r0)) < 0) {
            return LCB_NO_MATCHING_SERVER;
        }

    } else if (cmd->strategy == LCB_REPLICA_ALL) {
        unsigned ii;
        r0 = 0;
        r1 = LCBT_NREPLICAS(instance);
        /* Make sure they're all online */
        for (ii = 0; ii < LCBT_NREPLICAS(instance); ii++) {
            if ((ixtmp = lcbvb_vbreplica(cq->config, vbid, ii)) < 0) {
                return LCB_NO_MATCHING_SERVER;
            }
        }
    } else {
        for (r0 = 0; r0 < LCBT_NREPLICAS(instance); r0++) {
            if ((ixtmp = lcbvb_vbreplica(cq->config, vbid, r0)) > -1) {
                r1 = r0;
                break;
            }
        }
        if (r0 == LCBT_NREPLICAS(instance)) {
            return LCB_NO_MATCHING_SERVER;
        }
    }

    if (r1 < r0 || r1 >= cq->npipelines) {
        return LCB_NO_MATCHING_SERVER;
    }

    /* Initialize the cookie */
    rck = calloc(1, sizeof(*rck));
    rck->base.cookie = cookie;
    rck->base.start = gethrtime();
    rck->base.procs = &rget_procs;
    rck->strategy = cmd->strategy;
    rck->r_cur = r0;
    rck->r_max = LCBT_NREPLICAS(instance);
    rck->instance = instance;
    rck->vbucket = vbid;

    /* Initialize the packet */
    req.request.magic = PROTOCOL_BINARY_REQ;
    req.request.opcode = PROTOCOL_BINARY_CMD_GET_REPLICA;
    req.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
    req.request.vbucket = htons((lcb_uint16_t)vbid);
    req.request.cas = 0;
    req.request.extlen = 0;
    req.request.keylen = htons((lcb_uint16_t)cmd->key.contig.nbytes);
    req.request.bodylen = htonl((lcb_uint32_t)cmd->key.contig.nbytes);

    do {
        int curix;
        mc_PIPELINE *pl;
        mc_PACKET *pkt;

        curix = lcbvb_vbreplica(cq->config, vbid, r0);
        /* XXX: this is always expected to be in range. For the FIRST mode
         * it will seek to the first valid index (checked above), and for the
         * ALL mode, it will fail if not all replicas are already online
         * (also checked above) */
        pl = cq->pipelines[curix];
        pkt = mcreq_allocate_packet(pl);
        if (!pkt) {
            return LCB_CLIENT_ENOMEM;
        }

        pkt->u_rdata.exdata = &rck->base;
        pkt->flags |= MCREQ_F_REQEXT;

        mcreq_reserve_key(pl, pkt, sizeof(req.bytes), &cmd->key);

        req.request.opaque = pkt->opaque;
        rck->remaining++;
        mcreq_write_hdr(pkt, &req);
        mcreq_sched_add(pl, pkt);
    } while (++r0 < r1);

    return LCB_SUCCESS;
}
Ejemplo n.º 13
0
LIBCOUCHBASE_API
lcb_error_t
lcb_store3(lcb_t instance, const void *cookie, const lcb_CMDSTORE *cmd)
{
    mc_PIPELINE *pipeline;
    mc_PACKET *packet;
    mc_REQDATA *rdata;
    mc_CMDQUEUE *cq = &instance->cmdq;
    int hsize;
    int should_compress = 0;
    lcb_error_t err;

    protocol_binary_request_set scmd;
    protocol_binary_request_header *hdr = &scmd.message.header;

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

    err = get_esize_and_opcode(
            cmd->operation, &hdr->request.opcode, &hdr->request.extlen);
    if (err != LCB_SUCCESS) {
        return err;
    }

    hsize = hdr->request.extlen + sizeof(*hdr);

    err = mcreq_basic_packet(cq, (const lcb_CMDBASE *)cmd, hdr,
        hdr->request.extlen, &packet, &pipeline, MCREQ_BASICPACKET_F_FALLBACKOK);

    if (err != LCB_SUCCESS) {
        return err;
    }

    should_compress = can_compress(instance, pipeline, cmd);
    if (should_compress) {
        int rv = mcreq_compress_value(pipeline, packet, &cmd->value.u_buf.contig);
        if (rv != 0) {
            mcreq_release_packet(pipeline, packet);
            return LCB_CLIENT_ENOMEM;
        }
    } else {
        mcreq_reserve_value(pipeline, packet, &cmd->value);
    }

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

    scmd.message.body.expiration = htonl(cmd->exptime);
    scmd.message.body.flags = htonl(cmd->flags);
    hdr->request.magic = PROTOCOL_BINARY_REQ;
    hdr->request.cas = cmd->cas;
    hdr->request.datatype = PROTOCOL_BINARY_RAW_BYTES;

    if (should_compress || (cmd->datatype & LCB_VALUE_F_SNAPPYCOMP)) {
        hdr->request.datatype |= PROTOCOL_BINARY_DATATYPE_COMPRESSED;
    }
    if (cmd->datatype & LCB_VALUE_F_JSON) {
        hdr->request.datatype |= PROTOCOL_BINARY_DATATYPE_JSON;
    }

    hdr->request.opaque = packet->opaque;
    hdr->request.bodylen = htonl(
            hdr->request.extlen + ntohs(hdr->request.keylen)
            + get_value_size(packet));

    memcpy(SPAN_BUFFER(&packet->kh_span), scmd.bytes, hsize);
    mcreq_sched_add(pipeline, packet);
    TRACE_STORE_BEGIN(hdr, cmd);
    return LCB_SUCCESS;
}