static void getq_response_handler(lcb_server_t *server, packet_info *info) { lcb_t root = server->instance; char *packet; lcb_uint16_t nkey; const char *key = get_key(server, &nkey, &packet); lcb_error_t rc; lcb_get_resp_t resp; fprintf(stderr, "\n The datatype is ...%d", PACKET_DATATYPE(info)); if (key == NULL) { lcb_error_handler(server->instance, LCB_EINTERNAL, NULL); return; } else if (PACKET_STATUS(info) == PROTOCOL_BINARY_RESPONSE_SUCCESS) { const protocol_binary_response_getq *getq = PACKET_EPHEMERAL_START(info); rc = LCB_SUCCESS; setup_lcb_get_resp_t(&resp, key, nkey, PACKET_VALUE(info), PACKET_NVALUE(info), ntohl(getq->message.body.flags), PACKET_CAS(info), PACKET_DATATYPE(info)); } else { rc = map_error(root, PACKET_STATUS(info)); setup_lcb_get_resp_t(&resp, key, nkey, NULL, 0, 0, 0, 0); } root->callbacks.get(root, info->ct.cookie, rc, &resp); release_key(server, packet); }
static void getq_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_getq *getq = (void *)res; lcb_uint16_t status = ntohs(res->response.status); lcb_size_t nbytes = ntohl(res->response.bodylen); char *packet; lcb_uint16_t nkey; const char *key = get_key(server, &nkey, &packet); lcb_error_t rc = map_error(root, status); nbytes -= res->response.extlen; if (key == NULL) { lcb_error_handler(server->instance, LCB_EINTERNAL, NULL); return; } else if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) { const char *bytes = (const char *)res; lcb_get_resp_t resp; bytes += sizeof(getq->bytes); setup_lcb_get_resp_t(&resp, key, nkey, bytes, nbytes, ntohl(getq->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); } else { 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); }
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 failout_single_request(lcb_server_t *server, protocol_binary_request_header *req, struct lcb_command_data_st *ct, lcb_error_t error, const void *keyptr, lcb_size_t nkey, const void *packet) { lcb_t root = server->instance; union { lcb_get_resp_t get; lcb_store_resp_t store; lcb_remove_resp_t remove; lcb_touch_resp_t touch; lcb_unlock_resp_t unlock; lcb_arithmetic_resp_t arithmetic; lcb_observe_resp_t observe; lcb_server_stat_resp_t stats; lcb_server_version_resp_t versions; lcb_verbosity_resp_t verbosity; lcb_flush_resp_t flush; } resp; switch (req->request.opcode) { case PROTOCOL_BINARY_CMD_NOOP: break; case CMD_GET_LOCKED: case PROTOCOL_BINARY_CMD_GAT: case PROTOCOL_BINARY_CMD_GATQ: case PROTOCOL_BINARY_CMD_GET: case PROTOCOL_BINARY_CMD_GETQ: setup_lcb_get_resp_t(&resp.get, keyptr, nkey, NULL, 0, 0, 0, 0); TRACE_GET_END(req->request.opaque, ntohs(req->request.vbucket), req->request.opcode, error, &resp.get); root->callbacks.get(root, ct->cookie, error, &resp.get); break; case CMD_UNLOCK_KEY: setup_lcb_unlock_resp_t(&resp.unlock, keyptr, nkey); TRACE_UNLOCK_END(req->request.opaque, ntohs(req->request.vbucket), error, &resp.unlock); root->callbacks.unlock(root, ct->cookie, error, &resp.unlock); break; case PROTOCOL_BINARY_CMD_FLUSH: setup_lcb_flush_resp_t(&resp.flush, server->authority); TRACE_FLUSH_PROGRESS(req->request.opaque, ntohs(req->request.vbucket), req->request.opcode, error, &resp.flush); root->callbacks.flush(root, ct->cookie, error, &resp.flush); if (lcb_lookup_server_with_command(root, PROTOCOL_BINARY_CMD_FLUSH, req->request.opaque, server) < 0) { setup_lcb_flush_resp_t(&resp.flush, NULL); TRACE_FLUSH_END(req->request.opaque, ntohs(req->request.vbucket), req->request.opcode, error); root->callbacks.flush(root, ct->cookie, error, &resp.flush); } break; case PROTOCOL_BINARY_CMD_ADD: setup_lcb_store_resp_t(&resp.store, keyptr, nkey, 0); TRACE_STORE_END(req->request.opaque, ntohs(req->request.vbucket), req->request.opcode, error, &resp.store); root->callbacks.store(root, ct->cookie, LCB_ADD, error, &resp.store); break; case PROTOCOL_BINARY_CMD_REPLACE: setup_lcb_store_resp_t(&resp.store, keyptr, nkey, 0); TRACE_STORE_END(req->request.opaque, ntohs(req->request.vbucket), req->request.opcode, error, &resp.store); root->callbacks.store(root, ct->cookie, LCB_REPLACE, error, &resp.store); break; case PROTOCOL_BINARY_CMD_SET: setup_lcb_store_resp_t(&resp.store, keyptr, nkey, 0); TRACE_STORE_END(req->request.opaque, ntohs(req->request.vbucket), req->request.opcode, error, &resp.store); root->callbacks.store(root, ct->cookie, LCB_SET, error, &resp.store); break; case PROTOCOL_BINARY_CMD_APPEND: setup_lcb_store_resp_t(&resp.store, keyptr, nkey, 0); TRACE_STORE_END(req->request.opaque, ntohs(req->request.vbucket), req->request.opcode, error, &resp.store); root->callbacks.store(root, ct->cookie, LCB_APPEND, error, &resp.store); break; case PROTOCOL_BINARY_CMD_PREPEND: setup_lcb_store_resp_t(&resp.store, keyptr, nkey, 0); TRACE_STORE_END(req->request.opaque, ntohs(req->request.vbucket), req->request.opcode, error, &resp.store); root->callbacks.store(root, ct->cookie, LCB_PREPEND, error, &resp.store); break; case PROTOCOL_BINARY_CMD_DELETE: setup_lcb_remove_resp_t(&resp.remove, keyptr, nkey, 0); TRACE_REMOVE_END(req->request.opaque, ntohs(req->request.vbucket), req->request.opcode, error, &resp.remove); root->callbacks.remove(root, ct->cookie, error, &resp.remove); break; case PROTOCOL_BINARY_CMD_INCREMENT: case PROTOCOL_BINARY_CMD_DECREMENT: setup_lcb_arithmetic_resp_t(&resp.arithmetic, keyptr, nkey, 0, 0); TRACE_ARITHMETIC_END(req->request.opaque, ntohs(req->request.vbucket), req->request.opcode, error, &resp.arithmetic); root->callbacks.arithmetic(root, ct->cookie, error, &resp.arithmetic); break; case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS: case PROTOCOL_BINARY_CMD_SASL_AUTH: case PROTOCOL_BINARY_CMD_SASL_STEP: /* no need to notify user about these commands */ break; case PROTOCOL_BINARY_CMD_TOUCH: setup_lcb_touch_resp_t(&resp.touch, keyptr, nkey, 0); TRACE_TOUCH_END(req->request.opaque, ntohs(req->request.vbucket), req->request.opcode, error, &resp.touch); root->callbacks.touch(root, ct->cookie, error, &resp.touch); break; case PROTOCOL_BINARY_CMD_STAT: setup_lcb_server_stat_resp_t(&resp.stats, server->authority, NULL, 0, NULL, 0); TRACE_STATS_PROGRESS(req->request.opaque, ntohs(req->request.vbucket), req->request.opcode, error, &resp.stats); root->callbacks.stat(root, ct->cookie, error, &resp.stats); if (lcb_lookup_server_with_command(root, PROTOCOL_BINARY_CMD_STAT, req->request.opaque, server) < 0) { setup_lcb_server_stat_resp_t(&resp.stats, NULL, NULL, 0, NULL, 0); TRACE_STATS_END(req->request.opaque, ntohs(req->request.vbucket), req->request.opcode, error); root->callbacks.stat(root, ct->cookie, error, &resp.stats); } break; case PROTOCOL_BINARY_CMD_VERBOSITY: setup_lcb_verbosity_resp_t(&resp.verbosity, server->authority); TRACE_VERBOSITY_END(req->request.opaque, ntohs(req->request.vbucket), req->request.opcode, error, &resp.verbosity); root->callbacks.verbosity(root, ct->cookie, error, &resp.verbosity); if (lcb_lookup_server_with_command(root, PROTOCOL_BINARY_CMD_VERBOSITY, req->request.opaque, server) < 0) { setup_lcb_verbosity_resp_t(&resp.verbosity, NULL); TRACE_VERBOSITY_END(req->request.opaque, ntohs(req->request.vbucket), req->request.opcode, error, &resp.verbosity); root->callbacks.verbosity(root, ct->cookie, error, &resp.verbosity); } break; case PROTOCOL_BINARY_CMD_VERSION: setup_lcb_server_version_resp_t(&resp.versions, server->authority, NULL, 0); TRACE_VERSIONS_PROGRESS(req->request.opaque, ntohs(req->request.vbucket), req->request.opcode, error, &resp.versions); root->callbacks.version(root, ct->cookie, error, &resp.versions); if (lcb_lookup_server_with_command(root, PROTOCOL_BINARY_CMD_VERSION, req->request.opaque, server) < 0) { TRACE_VERSIONS_END(req->request.opaque, ntohs(req->request.vbucket), req->request.opcode, error); setup_lcb_server_version_resp_t(&resp.versions, NULL, NULL, 0); root->callbacks.version(root, ct->cookie, error, &resp.versions); } break; case CMD_OBSERVE: lcb_failout_observe_request(server, ct, packet, sizeof(req->bytes) + ntohl(req->request.bodylen), error); break; case CMD_GET_CLUSTER_CONFIG: lcb_cccp_update2(ct->cookie, error, NULL, 0, NULL); break; case PROTOCOL_BINARY_CMD_HELLO: lcb_cccp_update2(ct->cookie, error, NULL, 0, NULL); break; case PROTOCOL_BINARY_CMD_COMPACTDB: lcb_cccp_update2(ct->cookie, error, NULL, 0, NULL); break; default: lcb_assert("unexpected opcode while purging the server" && 0); } }
/* * Drop all packets with sequence number less than specified. * * The packets are considered as stale and the caller will receive * appropriate error code in the operation callback. * * Returns 0 on success */ int lcb_server_purge_implicit_responses(lcb_server_t *c, lcb_uint32_t seqno, hrtime_t end, int all) { protocol_binary_request_header req; /** Instance level allocated buffers */ ringbuffer_t *cmdlog, *cookies; lcb_size_t nr = ringbuffer_peek(&c->cmd_log, req.bytes, sizeof(req)); /* There should at _LEAST_ be _ONE_ message in here if we're not * trying to purge _ALL_ of the messages in the queue */ if (all && nr == 0) { return 0; } /** * Reading the command log is not re-entrant safe, as an additional * command to the same server may result in the command log being modified. * To this end, we must first buffer all the commands in a separate * ringbuffer (or simple buffer) for that matter, and only *then* * invoke the callbacks */ lcb_assert(nr == sizeof(req)); if (req.request.opaque >= seqno) { return 0; } cmdlog = &c->instance->purged_buf; cookies = &c->instance->purged_cookies; ringbuffer_reset(cmdlog); ringbuffer_reset(cookies); /** * Move all the commands we want to purge into the relevant ("local") buffers. * We will later read from these local buffers */ while (req.request.opaque < seqno) { lcb_size_t packetsize = ntohl(req.request.bodylen) + (lcb_uint32_t)sizeof(req); ringbuffer_memcpy(cmdlog, &c->cmd_log, packetsize); ringbuffer_consumed(&c->cmd_log, packetsize); ringbuffer_memcpy(cookies, &c->output_cookies, sizeof(struct lcb_command_data_st)); ringbuffer_consumed(&c->output_cookies, sizeof(struct lcb_command_data_st)); nr = ringbuffer_peek(&c->cmd_log, req.bytes, sizeof(req.bytes)); if (!nr) { break; } lcb_assert(nr == sizeof(req)); } nr = ringbuffer_peek(cmdlog, req.bytes, sizeof(req)); lcb_assert(nr == sizeof(req)); if (!all) { lcb_assert(c->cmd_log.nbytes); } do { struct lcb_command_data_st ct; char *packet = cmdlog->read_head; lcb_size_t packetsize = ntohl(req.request.bodylen) + (lcb_uint32_t)sizeof(req); char *keyptr; union { lcb_get_resp_t get; lcb_store_resp_t store; lcb_remove_resp_t remove; lcb_touch_resp_t touch; lcb_unlock_resp_t unlock; lcb_arithmetic_resp_t arithmetic; lcb_observe_resp_t observe; } resp; nr = ringbuffer_read(cookies, &ct, sizeof(ct)); lcb_assert(nr == sizeof(ct)); if (c->instance->histogram) { lcb_record_metrics(c->instance, end - ct.start, req.request.opcode); } if (!ringbuffer_is_continous(cmdlog, RINGBUFFER_READ, packetsize)) { packet = malloc(packetsize); if (packet == NULL) { lcb_error_handler(c->instance, LCB_CLIENT_ENOMEM, NULL); return -1; } nr = ringbuffer_peek(cmdlog, packet, packetsize); if (nr != packetsize) { lcb_error_handler(c->instance, LCB_EINTERNAL, NULL); free(packet); return -1; } } switch (req.request.opcode) { case PROTOCOL_BINARY_CMD_GATQ: case PROTOCOL_BINARY_CMD_GETQ: keyptr = packet + sizeof(req) + req.request.extlen; setup_lcb_get_resp_t(&resp.get, keyptr, ntohs(req.request.keylen), NULL, 0, 0, 0, 0); TRACE_GET_END(req.request.opaque, ntohs(req.request.vbucket), req.request.opcode, LCB_KEY_ENOENT, &resp.get); c->instance->callbacks.get(c->instance, ct.cookie, LCB_KEY_ENOENT, &resp.get); break; case CMD_OBSERVE: lcb_failout_observe_request(c, &ct, packet, sizeof(req.bytes) + ntohl(req.request.bodylen), LCB_SERVER_BUG); break; case PROTOCOL_BINARY_CMD_NOOP: break; default: { char errinfo[128] = { '\0' }; snprintf(errinfo, 128, "Unknown implicit send message op=%0x", req.request.opcode); lcb_error_handler(c->instance, LCB_EINTERNAL, errinfo); return -1; } } if (packet != cmdlog->read_head) { free(packet); } ringbuffer_consumed(cmdlog, packetsize); nr = ringbuffer_peek(cmdlog, req.bytes, sizeof(req)); if (nr == 0) { return 0; } lcb_assert(nr == sizeof(req)); } while (1); /* CONSTCOND */ return 0; }
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); }