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; }
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; }
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; }
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; } }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }