void lcb_timeout_server(lcb_server_t *server) { hrtime_t now, min_valid, next_ns = 0; lcb_uint32_t next_us; LOG(server, ERR, "Server timed out"); lcb_bootstrap_errcount_incr(server->instance); if (!server->connection_ready) { lcb_failout_server(server, LCB_ETIMEDOUT); return; } now = gethrtime(); /** The oldest valid command timestamp */ min_valid = now - ((hrtime_t)MCSERVER_TIMEOUT(server)) * 1000; purge_single_server(server, LCB_ETIMEDOUT, min_valid, &next_ns); if (next_ns) { next_us = (lcb_uint32_t) (next_ns / 1000); } else { next_us = MCSERVER_TIMEOUT(server); } lcb_log(LOGARGS(server, INFO), "%p, Scheduling next timeout for %d ms", server, next_us / 1000); lcb_timer_rearm(server->io_timer, next_us); lcb_maybe_breakout(server->instance); }
void lcb_server_send_packets(lcb_server_t *server) { if (server->pending.nbytes > 0 || server->connection.output->nbytes > 0) { if (server->connection_ready) { lcb_sockrw_set_want(&server->connection, LCB_WRITE_EVENT, 0); if (!server->inside_handler) { lcb_sockrw_apply_want(&server->connection); if (!lcb_timer_armed(server->io_timer)) { lcb_timer_rearm(server->io_timer, MCSERVER_TIMEOUT(server)); } } } else if (server->connection.state == LCB_CONNSTATE_UNINIT) { lcb_server_connect(server); } } }
void mcserver_flush(mc_SERVER *server) { /** Call into the wwant stuff.. */ if (!server->connctx->rdwant) { lcbio_ctx_rwant(server->connctx, 24); } lcbio_ctx_wwant(server->connctx); lcbio_ctx_schedule(server->connctx); if (!lcbio_timer_armed(server->io_timer)) { /** * XXX: Maybe use get_next_timeout(), although here we can assume * that a command was just scheduled */ lcbio_timer_rearm(server->io_timer, MCSERVER_TIMEOUT(server)); } }
lcb_error_t lcb_server_initialize(lcb_server_t *server, int servernum) { /* Initialize all members */ lcb_error_t err; char *p; const char *n = vbucket_config_get_server(server->instance->vbucket_config, servernum); err = lcb_connection_init(&server->connection, server->instance->settings.io, &server->instance->settings); if (err != LCB_SUCCESS) { return err; } server->connection.data = server; server->index = servernum; server->authority = strdup(n); strcpy(server->curhost.host, n); p = strchr(server->curhost.host, ':'); *p = '\0'; strcpy(server->curhost.port, p + 1); n = vbucket_config_get_couch_api_base(server->instance->vbucket_config, servernum); server->couch_api_base = (n != NULL) ? strdup(n) : NULL; n = vbucket_config_get_rest_api_server(server->instance->vbucket_config, servernum); server->rest_api_server = strdup(n); server->io_timer = lcb_timer_create_simple(server->instance->settings.io, server, MCSERVER_TIMEOUT(server), tmo_thunk); lcb_timer_disarm(server->io_timer); return LCB_SUCCESS; }
/** * Returns 1 if retried, 0 if the command should fail, -1 for an internal * error */ static int handle_not_my_vbucket(lcb_server_t *c, packet_info *resinfo, protocol_binary_request_header *oldreq, struct lcb_command_data_st *oldct) { int idx; char *body; lcb_size_t nbody, nr; lcb_server_t *new_srv; struct lcb_command_data_st ct; protocol_binary_request_header req; hrtime_t now; lcb_string config_string; lcb_error_t err = LCB_ERROR; lcb_log(LOGARGS(c, WARN), "NOT_MY_VBUCKET; Server=%p,ix=%d,real_start=%lu,vb=%d", (void *)c, c->index, (unsigned long)oldct->real_start, (int)ntohs(oldreq->request.vbucket)); lcb_string_init(&config_string); if (PACKET_NBODY(resinfo)) { lcb_string_append(&config_string, PACKET_VALUE(resinfo), PACKET_NVALUE(resinfo)); err = lcb_cccp_update(lcb_confmon_get_provider(c->instance->confmon, LCB_CLCONFIG_CCCP), c->curhost.host, &config_string); } lcb_string_release(&config_string); if (err != LCB_SUCCESS) { lcb_bootstrap_refresh(c->instance); } /* re-schedule command to new server */ if (!c->instance->settings.vb_noguess) { idx = vbucket_found_incorrect_master(c->instance->vbucket_config, ntohs(oldreq->request.vbucket), (int)c->index); } else { idx = c->index; } if (idx == -1) { lcb_log(LOGARGS(c, ERR), "no alternate server"); return 0; } lcb_log(LOGARGS(c, INFO), "Mapped key to new server %d -> %d", c->index, idx); now = gethrtime(); if (oldct->real_start) { hrtime_t min_ok = now - MCSERVER_TIMEOUT(c) * 1000; if (oldct->real_start < min_ok) { /** Timed out in a 'natural' manner */ return 0; } } req = *oldreq; lcb_assert((lcb_size_t)idx < c->instance->nservers); new_srv = c->instance->servers + idx; nr = ringbuffer_read(&c->cmd_log, req.bytes, sizeof(req)); lcb_assert(nr == sizeof(req)); req.request.opaque = ++c->instance->seqno; nbody = ntohl(req.request.bodylen); body = malloc(nbody); if (body == NULL) { lcb_error_handler(c->instance, LCB_CLIENT_ENOMEM, NULL); return -1; } nr = ringbuffer_read(&c->cmd_log, body, nbody); lcb_assert(nr == nbody); nr = ringbuffer_read(&c->output_cookies, &ct, sizeof(ct)); lcb_assert(nr == sizeof(ct)); /* Preserve the cookie and reset timestamp for the command. This * means that the library will retry the command until it will * get code different from LCB_NOT_MY_VBUCKET */ if (!ct.real_start) { ct.real_start = ct.start; } ct.start = now; lcb_server_retry_packet(new_srv, &ct, &req, sizeof(req)); /* FIXME dtrace instrumentation */ lcb_server_write_packet(new_srv, body, nbody); lcb_server_end_packet(new_srv); lcb_server_send_packets(new_srv); free(body); return 1; }