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