static void H_stats(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_t root = pipeline->parent->cqdata; lcb_RESPSTATS resp = { 0 }; mc_REQDATAEX *exdata; MK_ERROR(root, &resp, response, immerr); resp.version = 0; exdata = request->u_rdata.exdata; if (resp.rc != LCB_SUCCESS || PACKET_NKEY(response) == 0) { /* Call the handler without a response, this indicates that this server * has finished responding */ exdata->procs->handler(pipeline, request, resp.rc, NULL); return; } if ((resp.nkey = PACKET_NKEY(response))) { resp.key = PACKET_KEY(response); if ((resp.value = PACKET_VALUE(response))) { resp.nvalue = PACKET_NVALUE(response); } } exdata->procs->handler(pipeline, request, resp.rc, &resp); }
static void H_stats(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response, lcb_error_t immerr) { lcb_t root = pipeline->parent->instance; lcb_error_t rc; lcb_server_stat_resp_t resp; mc_REQDATAEX *exdata; MK_ERROR(root, rc, response, immerr); resp.version = 0; exdata = request->u_rdata.exdata; if (rc != LCB_SUCCESS || PACKET_NKEY(response) == 0) { /* Call the handler without a response, this indicates that this server * has finished responding */ exdata->callback(pipeline, request, rc, NULL); return; } if ((resp.v.v0.nkey = PACKET_NKEY(response))) { resp.v.v0.key = PACKET_KEY(response); if ((resp.v.v0.nbytes = PACKET_NVALUE(response))) { resp.v.v0.bytes = PACKET_VALUE(response); } } exdata->callback(pipeline, request, rc, &resp); }
static void stat_response_handler(lcb_server_t *server, packet_info *info) { lcb_t root = server->instance; lcb_uint16_t status = PACKET_STATUS(info); lcb_error_t rc = map_error(root, status); lcb_server_stat_resp_t resp; struct lcb_command_data_st *command_data = &info->ct; if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) { if (!PACKET_NKEY(info)) { if (lcb_lookup_server_with_command(root, PROTOCOL_BINARY_CMD_STAT, PACKET_OPAQUE(info), server) < 0) { /* notify client that data is ready */ setup_lcb_server_stat_resp_t(&resp, NULL, NULL, 0, NULL, 0); root->callbacks.stat(root, command_data->cookie, rc, &resp); } return; } setup_lcb_server_stat_resp_t(&resp, server->authority, PACKET_KEY(info), PACKET_NKEY(info), PACKET_VALUE(info), PACKET_NVALUE(info)); root->callbacks.stat(root, command_data->cookie, rc, &resp); } else { setup_lcb_server_stat_resp_t(&resp, server->authority, NULL, 0, NULL, 0); root->callbacks.stat(root, command_data->cookie, rc, &resp); /* run callback with null-null-null to signal the end of transfer */ if (lcb_lookup_server_with_command(root, PROTOCOL_BINARY_CMD_STAT, PACKET_OPAQUE(info), server) < 0) { setup_lcb_server_stat_resp_t(&resp, NULL, NULL, 0, NULL, 0); root->callbacks.stat(root, command_data->cookie, LCB_SUCCESS, &resp); } } }
/* This function is called within a loop to process a single packet. * * If a full packet is available, it will process the packet and return * PKT_READ_COMPLETE, resulting in the `on_read()` function calling this * function in a loop. * * When a complete packet is not available, PKT_READ_PARTIAL will be returned * and the `on_read()` loop will exit, scheduling any required pending I/O. */ static int try_read(lcbio_CTX *ctx, mc_SERVER *server, rdb_IOROPE *ior) { packet_info info_s, *info = &info_s; mc_PACKET *request; mc_PIPELINE *pl = &server->pipeline; unsigned pktsize = 24, is_last = 1; #define RETURN_NEED_MORE(n) \ if (mcserver_has_pending(server)) { \ lcbio_ctx_rwant(ctx, n); \ } \ return PKT_READ_PARTIAL; \ #define DO_ASSIGN_PAYLOAD() \ rdb_consumed(ior, sizeof(info->res.bytes)); \ if (PACKET_NBODY(info)) { \ info->payload = rdb_get_consolidated(ior, PACKET_NBODY(info)); \ } { #define DO_SWALLOW_PAYLOAD() \ } if (PACKET_NBODY(info)) { \ rdb_consumed(ior, PACKET_NBODY(info)); \ } if (rdb_get_nused(ior) < pktsize) { RETURN_NEED_MORE(pktsize) } /* copy bytes into the info structure */ rdb_copyread(ior, info->res.bytes, sizeof info->res.bytes); pktsize += PACKET_NBODY(info); if (rdb_get_nused(ior) < pktsize) { RETURN_NEED_MORE(pktsize); } /* Find the packet */ if (PACKET_OPCODE(info) == PROTOCOL_BINARY_CMD_STAT && PACKET_NKEY(info) != 0) { is_last = 0; request = mcreq_pipeline_find(pl, PACKET_OPAQUE(info)); } else { is_last = 1; request = mcreq_pipeline_remove(pl, PACKET_OPAQUE(info)); } if (!request) { lcb_log(LOGARGS(server, WARN), LOGFMT "Found stale packet (OP=0x%x, RC=0x%x, SEQ=%u)", LOGID(server), PACKET_OPCODE(info), PACKET_STATUS(info), PACKET_OPAQUE(info)); rdb_consumed(ior, pktsize); return PKT_READ_COMPLETE; } if (PACKET_STATUS(info) == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET) { /* consume the header */ DO_ASSIGN_PAYLOAD() if (!handle_nmv(server, info, request)) { mcreq_dispatch_response(pl, request, info, LCB_NOT_MY_VBUCKET); } DO_SWALLOW_PAYLOAD() return PKT_READ_COMPLETE; }
static void io_read_handler(lcb_connection_t conn) { packet_info pi; cccp_provider *cccp = conn->data; lcb_string jsonstr; lcb_error_t err; int rv; lcb_host_t curhost; memset(&pi, 0, sizeof(pi)); rv = lcb_packet_read_ringbuffer(&pi, conn->input); if (rv < 0) { LOG(cccp, ERR, "Couldn't parse packet!?"); mcio_error(cccp, LCB_EINTERNAL); return; } else if (rv == 0) { lcb_sockrw_set_want(conn, LCB_READ_EVENT, 1); lcb_sockrw_apply_want(conn); return; } if (PACKET_STATUS(&pi) != PROTOCOL_BINARY_RESPONSE_SUCCESS) { lcb_log(LOGARGS(cccp, ERR), "CCCP Packet responded with 0x%x; nkey=%d, nbytes=%lu, cmd=0x%x, seq=0x%x", PACKET_STATUS(&pi), PACKET_NKEY(&pi), PACKET_NBODY(&pi), PACKET_OPCODE(&pi), PACKET_OPAQUE(&pi)); switch (PACKET_STATUS(&pi)) { case PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED: case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND: mcio_error(cccp, LCB_NOT_SUPPORTED); break; default: mcio_error(cccp, LCB_PROTOCOL_ERROR); break; } return; } if (!PACKET_NBODY(&pi)) { mcio_error(cccp, LCB_PROTOCOL_ERROR); return; } if (lcb_string_init(&jsonstr)) { mcio_error(cccp, LCB_CLIENT_ENOMEM); return; } if (lcb_string_append(&jsonstr, PACKET_BODY(&pi), PACKET_NBODY(&pi))) { mcio_error(cccp, LCB_CLIENT_ENOMEM); return; } curhost = *lcb_connection_get_host(&cccp->connection); lcb_packet_release_ringbuffer(&pi, conn->input); release_socket(cccp, 1); err = lcb_cccp_update(&cccp->base, curhost.host, &jsonstr); lcb_string_release(&jsonstr); if (err == LCB_SUCCESS) { lcb_timer_disarm(cccp->timer); cccp->server_active = 0; } else { schedule_next_request(cccp, LCB_PROTOCOL_ERROR, 0); } }
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); }