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