static void H_store(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_t root = pipeline->parent->cqdata; lcb_RESPSTORE resp = { 0 }; lcb_U8 opcode; init_resp3(root, response, request, immerr, (lcb_RESPBASE*)&resp); if (!immerr) { opcode = PACKET_OPCODE(response); } else { protocol_binary_request_header hdr; mcreq_read_hdr(request, &hdr); opcode = hdr.request.opcode; } if (opcode == PROTOCOL_BINARY_CMD_ADD) { resp.op = LCB_ADD; } else if (opcode == PROTOCOL_BINARY_CMD_REPLACE) { resp.op = LCB_REPLACE; } else if (opcode == PROTOCOL_BINARY_CMD_APPEND) { resp.op = LCB_APPEND; } else if (opcode == PROTOCOL_BINARY_CMD_PREPEND) { resp.op = LCB_PREPEND; } else if (opcode == PROTOCOL_BINARY_CMD_SET) { resp.op = LCB_SET; } handle_synctoken(root, response, request, &resp.synctoken); TRACE_STORE_END(response, &resp); if (request->flags & MCREQ_F_REQEXT) { request->u_rdata.exdata->procs->handler(pipeline, request, immerr, &resp); } else { INVOKE_CALLBACK3(request, &resp, root, LCB_CALLBACK_STORE); } }
/** * Invoked when get a NOT_MY_VBUCKET response. If the response contains a JSON * payload then we refresh the configuration with it. * * This function returns 1 if the operation was successfully rescheduled; * otherwise it returns 0. If it returns 0 then we give the error back to the * user. */ static int handle_nmv(mc_SERVER *oldsrv, packet_info *resinfo, mc_PACKET *oldpkt) { mc_PACKET *newpkt; protocol_binary_request_header hdr; lcb_error_t err = LCB_ERROR; lcb_t instance = oldsrv->instance; lcb_U16 vbid; clconfig_provider *cccp = lcb_confmon_get_provider(instance->confmon, LCB_CLCONFIG_CCCP); mcreq_read_hdr(oldpkt, &hdr); vbid = ntohs(hdr.request.vbucket); lcb_log(LOGARGS(oldsrv, WARN), LOGFMT "NOT_MY_VBUCKET. Packet=%p (S=%u). VBID=%u", LOGID(oldsrv), (void*)oldpkt, oldpkt->opaque, vbid); /* Notify of new map */ lcb_vbguess_remap(instance, vbid, oldsrv->pipeline.index); if (PACKET_NBODY(resinfo) && cccp->enabled) { lcb_string s; lcb_string_init(&s); lcb_string_append(&s, PACKET_VALUE(resinfo), PACKET_NVALUE(resinfo)); err = lcb_cccp_update(cccp, mcserver_get_host(oldsrv), &s); lcb_string_release(&s); } if (err != LCB_SUCCESS) { int bs_options; if (instance->cur_configinfo->origin == LCB_CLCONFIG_CCCP) { /** * XXX: Not enough to see if cccp was enabled, since cccp might * be requested by a user, but would still not actually be active * for clusters < 2.5 If our current config is from CCCP * then we can be fairly certain that CCCP is indeed working. * * For this reason, we don't use if (cccp->enabled) {...} */ bs_options = LCB_BS_REFRESH_THROTTLE; } else { bs_options = LCB_BS_REFRESH_ALWAYS; } lcb_bootstrap_common(instance, bs_options); } if (!lcb_should_retry(oldsrv->settings, oldpkt, LCB_NOT_MY_VBUCKET)) { return 0; } /** Reschedule the packet again .. */ newpkt = mcreq_renew_packet(oldpkt); newpkt->flags &= ~MCREQ_STATE_FLAGS; lcb_retryq_nmvadd(instance->retryq, (mc_EXPACKET*)newpkt); return 1; }
/** * Invoked when get a NOT_MY_VBUCKET response. If the response contains a JSON * payload then we refresh the configuration with it. * * This function returns 1 if the operation was successfully rescheduled; * otherwise it returns 0. If it returns 0 then we give the error back to the * user. */ static int handle_nmv(mc_SERVER *oldsrv, packet_info *resinfo, mc_PACKET *oldpkt) { mc_PACKET *newpkt; protocol_binary_request_header hdr; lcb_error_t err = LCB_ERROR; lcb_t instance = oldsrv->instance; lcb_U16 vbid; int tmpix; clconfig_provider *cccp = lcb_confmon_get_provider(instance->confmon, LCB_CLCONFIG_CCCP); mcreq_read_hdr(oldpkt, &hdr); vbid = ntohs(hdr.request.vbucket); lcb_log(LOGARGS(oldsrv, WARN), LOGFMT "NOT_MY_VBUCKET. Packet=%p (S=%u). VBID=%u", LOGID(oldsrv), (void*)oldpkt, oldpkt->opaque, vbid); /* Notify of new map */ tmpix = lcb_vbguess_remap(LCBT_VBCONFIG(instance), instance->vbguess, vbid, oldsrv->pipeline.index); if (tmpix > -1 && tmpix != oldsrv->pipeline.index) { lcb_log(LOGARGS(oldsrv, TRACE), LOGFMT "Heuristically set IX=%d as master for VBID=%u", LOGID(oldsrv), tmpix, vbid); } if (PACKET_NBODY(resinfo) && cccp->enabled) { lcb_string s; lcb_string_init(&s); lcb_string_append(&s, PACKET_VALUE(resinfo), PACKET_NVALUE(resinfo)); err = lcb_cccp_update(cccp, mcserver_get_host(oldsrv), &s); lcb_string_release(&s); } if (err != LCB_SUCCESS) { lcb_bootstrap_common(instance, LCB_BS_REFRESH_ALWAYS); } if (!lcb_should_retry(oldsrv->settings, oldpkt, LCB_NOT_MY_VBUCKET)) { return 0; } /** Reschedule the packet again .. */ newpkt = mcreq_renew_packet(oldpkt); newpkt->flags &= ~MCREQ_STATE_FLAGS; lcb_retryq_add(instance->retryq, (mc_EXPACKET*)newpkt, LCB_NOT_MY_VBUCKET); return 1; }
int lcb_should_retry(lcb_settings *settings, mc_PACKET *pkt, lcb_error_t err) { lcb_RETRYCMDOPTS policy; lcb_RETRYMODEOPTS mode; protocol_binary_request_header hdr; mcreq_read_hdr(pkt, &hdr); switch (hdr.request.opcode) { /* None of these commands can be 'redistributed' to other servers */ case PROTOCOL_BINARY_CMD_GET_REPLICA: case PROTOCOL_BINARY_CMD_FLUSH: case PROTOCOL_BINARY_CMD_OBSERVE: case PROTOCOL_BINARY_CMD_STAT: case PROTOCOL_BINARY_CMD_VERBOSITY: case PROTOCOL_BINARY_CMD_VERSION: return 0; } if (err == LCB_ETIMEDOUT || err == LCB_MAP_CHANGED) { /* We can't exceed a timeout for ETIMEDOUT */ /* MAP_CHANGED is sent after we've already called this function on the * packet once before */ return 0; } else if (err == LCB_AUTH_ERROR) { /* spurious auth error */ return 1; } else if (err == LCB_NOT_MY_VBUCKET) { mode = LCB_RETRY_ON_VBMAPERR; } else if (err == LCB_MAX_ERROR) { /* special, topology change */ mode = LCB_RETRY_ON_TOPOCHANGE; } else if (LCB_EIFNET(err)) { mode = LCB_RETRY_ON_SOCKERR; } else { /* invalid mode */ return 0; } policy = settings->retry[mode]; if (policy == LCB_RETRY_CMDS_ALL) { return 1; } else if (policy == LCB_RETRY_CMDS_NONE) { return 0; } /** read the header */ switch (hdr.request.opcode) { /* get is a safe operation which may be retried */ case PROTOCOL_BINARY_CMD_GET: case PROTOCOL_BINARY_CMD_GETKQ: return policy & LCB_RETRY_CMDS_GET; case PROTOCOL_BINARY_CMD_ADD: return policy & LCB_RETRY_CMDS_SAFE; /* mutation operations are retriable so long as they provide a CAS */ case PROTOCOL_BINARY_CMD_SET: case PROTOCOL_BINARY_CMD_REPLACE: case PROTOCOL_BINARY_CMD_APPEND: case PROTOCOL_BINARY_CMD_PREPEND: case PROTOCOL_BINARY_CMD_DELETE: case PROTOCOL_BINARY_CMD_UNLOCK_KEY: if (hdr.request.cas) { return policy & LCB_RETRY_CMDS_SAFE; } else { return 0; } /* none of these commands accept a CAS, so they are not safe */ case PROTOCOL_BINARY_CMD_INCREMENT: case PROTOCOL_BINARY_CMD_DECREMENT: case PROTOCOL_BINARY_CMD_TOUCH: case PROTOCOL_BINARY_CMD_GAT: case PROTOCOL_BINARY_CMD_GET_LOCKED: default: return 0; } }