static void rsp_forward(struct context *ctx, struct conn *s_conn, struct msg *msg) { rstatus_t status; struct msg *pmsg; struct conn *c_conn; ASSERT(!s_conn->client && !s_conn->proxy); /* response from server implies that server is ok and heartbeating */ server_ok(ctx, s_conn); /* dequeue peer message (request) from server */ pmsg = TAILQ_FIRST(&s_conn->omsg_q); ASSERT(pmsg != NULL && pmsg->peer == NULL); ASSERT(pmsg->request && !pmsg->done); s_conn->dequeue_outq(ctx, s_conn, pmsg); pmsg->done = 1; /* establish msg <-> pmsg (response <-> request) link */ pmsg->peer = msg; msg->peer = pmsg; #if 1 //shenzheng 2015-6-25 replace server if(pmsg->replace_server) { log_debug(LOG_DEBUG, "msg->error : %d", msg->error); struct server_pool *sp; struct conf_server *cs; struct server *ser_curr, *ser_new; struct conf_pool *cp; struct string host; struct stats_pool *stp; struct stats_server *sts; uint32_t p_idx, s_idx; uint8_t *p, *q, *last; int k = 0; ser_new = s_conn->owner; ASSERT(pmsg->server == ser_new); ASSERT(pmsg->conf_version_curr == ctx->conf_version); while(msg->error == 0 && k < 1) { string_init(&host); sp = ser_new->owner; p_idx = sp->idx; cp = array_get(&(ctx->cf->pool), p_idx); s_idx = ser_new->idx; ser_curr = array_get(&sp->server, s_idx); cs = array_get(&cp->server, s_idx); ASSERT(ser_curr->idx == ser_new->idx); ASSERT(ser_curr->owner == ser_new->owner); ASSERT(ser_curr->weight == ser_new->weight); ASSERT(ser_curr->name_null == ser_new->name_null); p = ser_new->pname.data; last = ser_new->pname.data + ser_new->pname.len; q = nc_strchr(p, last, ':'); if(q == NULL || q >= last || q <= ser_new->pname.data) { log_debug(LOG_DEBUG, "new server address(%s) error", ser_new->pname.data); break; } string_copy(&host, ser_new->pname.data, (uint32_t)(q - ser_new->pname.data)); log_debug(LOG_DEBUG, "new server host : %.*s", host.len, host.data); log_debug(LOG_DEBUG, "new server port : %d", ser_new->port); status = nc_resolve(&host, ser_new->port, &cs->info); if (status != NC_OK) { log_debug(LOG_DEBUG, "resolve new server address error(%d)", status); string_deinit(&host); break; } k ++; while (!TAILQ_EMPTY(&ser_curr->s_conn_q)) { struct conn *conn; ASSERT(ser_curr->ns_conn_q > 0); conn = TAILQ_FIRST(&ser_curr->s_conn_q); conn->err = ERROR_REPLACE_SERVER_TRY_AGAIN; status = event_del_conn(ctx->evb, conn); if (status < 0) { log_warn("event del conn s %d failed, ignored: %s", conn->sd, strerror(errno)); } conn->close(ctx, conn); } log_debug(LOG_DEBUG, "ser_curr->pname : %.*s", ser_curr->pname.len, ser_curr->pname.data); log_debug(LOG_DEBUG, "ser_new->pname : %.*s", ser_new->pname.len, ser_new->pname.data); status = conf_write_back_yaml(ctx, &ser_curr->pname, &ser_new->pname); if(status != NC_OK) { log_warn("warning: conf file write back error, but replace_server %.*s %.*s success.", ser_curr->pname.len, ser_curr->pname.data, ser_new->pname.len, ser_new->pname.data); } string_deinit(&cs->pname); cs->pname = ser_new->pname; string_init(&ser_new->pname); ser_curr->pname = cs->pname; if(ser_curr->name_null) { string_deinit(&cs->name); cs->name = ser_new->name; string_init(&ser_new->name); ser_curr->name = cs->name; stp = array_get(&ctx->stats->current, p_idx); sts = array_get(&stp->server, s_idx); sts->name = ser_curr->name; stp = array_get(&ctx->stats->shadow, p_idx); sts = array_get(&stp->server, s_idx); sts->name = ser_curr->name; stp = array_get(&ctx->stats->sum, p_idx); sts = array_get(&stp->server, s_idx); sts->name = ser_curr->name; } ser_curr->port = ser_new->port; ser_curr->family = cs->info.family; ser_curr->addrlen = cs->info.addrlen; ser_curr->addr = (struct sockaddr *)&cs->info.addr; ser_curr->next_retry = 0; ser_curr->failure_count = 0; string_deinit(&host); while (!TAILQ_EMPTY(&ser_new->s_conn_q)) { struct conn *conn; ASSERT(ser_new->ns_conn_q > 0); conn = TAILQ_FIRST(&ser_new->s_conn_q); ASSERT(conn->replace_server == 1); conn->replace_server = 0; conn->conf_version_curr = -1; conn->ctx = NULL; conn->unref(conn); conn->ref(conn, ser_curr); } } } #endif //shenzheng 2015-6-25 replace server msg->pre_coalesce(msg); c_conn = pmsg->owner; ASSERT(c_conn->client && !c_conn->proxy); if (req_done(c_conn, TAILQ_FIRST(&c_conn->omsg_q))) { status = event_add_out(ctx->evb, c_conn); if (status != NC_OK) { c_conn->err = errno; } } rsp_forward_stats(ctx, s_conn->owner, msg); }
/* * Return true if request is in error, false otherwise * * A request is in error, if there was an error in receiving response for the * given request. A multiget request is in error if there was an error in * receiving response for any its fragments. */ bool req_error(struct conn *conn, struct msg *msg) { struct msg *cmsg; /* current message */ uint64_t id; uint32_t nfragment; ASSERT(msg->request && req_done(conn, msg)); if (msg->error) { return true; } id = msg->frag_id; if (id == 0) { return false; } if (msg->ferror) { /* request has already been marked to be in error */ return true; } /* check if any of the fragments of the given request are in error */ for (cmsg = TAILQ_PREV(msg, msg_tqh, c_tqe); cmsg != NULL && cmsg->frag_id == id; cmsg = TAILQ_PREV(cmsg, msg_tqh, c_tqe)) { if (cmsg->error) { goto ferror; } } for (cmsg = TAILQ_NEXT(msg, c_tqe); cmsg != NULL && cmsg->frag_id == id; cmsg = TAILQ_NEXT(cmsg, c_tqe)) { if (cmsg->error) { goto ferror; } } return false; ferror: /* * Mark all fragments of the given request to be in error to speed up * future req_error calls for any of fragments of this request */ msg->ferror = 1; nfragment = 1; for (cmsg = TAILQ_PREV(msg, msg_tqh, c_tqe); cmsg != NULL && cmsg->frag_id == id; cmsg = TAILQ_PREV(cmsg, msg_tqh, c_tqe)) { cmsg->ferror = 1; nfragment++; } for (cmsg = TAILQ_NEXT(msg, c_tqe); cmsg != NULL && cmsg->frag_id == id; cmsg = TAILQ_NEXT(cmsg, c_tqe)) { cmsg->ferror = 1; nfragment++; } log_debug(LOG_DEBUG, "req from c %d with fid %"PRIu64" and %"PRIu32" " "fragments is in error", conn->sd, id, nfragment); return true; }
void server_close(struct context *ctx, struct conn *conn) { rstatus_t status; struct msg *msg, *nmsg; /* current and next message */ struct conn *c_conn; /* peer client connection */ ASSERT(!conn->client && !conn->proxy); server_close_stats(ctx, conn->owner, conn->err, conn->eof, conn->connected); if (conn->sd < 0) { server_failure(ctx, conn->owner); conn->unref(conn); conn_put(conn); return; } for (msg = TAILQ_FIRST(&conn->imsg_q); msg != NULL; msg = nmsg) { nmsg = TAILQ_NEXT(msg, s_tqe); /* dequeue the message (request) from server inq */ conn->dequeue_inq(ctx, conn, msg); /* * Don't send any error response, if * 1. request is tagged as noreply or, * 2. client has already closed its connection */ if (msg->swallow || msg->noreply) { log_debug(LOG_INFO, "close s %d swallow req %"PRIu64" len %"PRIu32 " type %d", conn->sd, msg->id, msg->mlen, msg->type); req_put(msg); } else { c_conn = msg->owner; ASSERT(c_conn->client && !c_conn->proxy); msg->done = 1; msg->error = 1; msg->err = conn->err; if (req_done(c_conn, TAILQ_FIRST(&c_conn->omsg_q))) { event_add_out(ctx->ep, msg->owner); } log_debug(LOG_INFO, "close s %d schedule error for req %"PRIu64" " "len %"PRIu32" type %d from c %d%c %s", conn->sd, msg->id, msg->mlen, msg->type, c_conn->sd, conn->err ? ':' : ' ', conn->err ? strerror(conn->err): " "); } } ASSERT(TAILQ_EMPTY(&conn->imsg_q)); for (msg = TAILQ_FIRST(&conn->omsg_q); msg != NULL; msg = nmsg) { nmsg = TAILQ_NEXT(msg, s_tqe); /* dequeue the message (request) from server outq */ conn->dequeue_outq(ctx, conn, msg); if (msg->swallow) { log_debug(LOG_INFO, "close s %d swallow req %"PRIu64" len %"PRIu32 " type %d", conn->sd, msg->id, msg->mlen, msg->type); req_put(msg); } else { c_conn = msg->owner; ASSERT(c_conn->client && !c_conn->proxy); msg->done = 1; msg->error = 1; msg->err = conn->err; if (req_done(c_conn, TAILQ_FIRST(&c_conn->omsg_q))) { event_add_out(ctx->ep, msg->owner); } log_debug(LOG_INFO, "close s %d schedule error for req %"PRIu64" " "len %"PRIu32" type %d from c %d%c %s", conn->sd, msg->id, msg->mlen, msg->type, c_conn->sd, conn->err ? ':' : ' ', conn->err ? strerror(conn->err): " "); } } ASSERT(TAILQ_EMPTY(&conn->omsg_q)); msg = conn->rmsg; if (msg != NULL) { conn->rmsg = NULL; ASSERT(!msg->request); ASSERT(msg->peer == NULL); rsp_put(msg); log_debug(LOG_INFO, "close s %d discarding rsp %"PRIu64" len %"PRIu32" " "in error", conn->sd, msg->id, msg->mlen); } ASSERT(conn->smsg == NULL); server_failure(ctx, conn->owner); conn->unref(conn); status = close(conn->sd); if (status < 0) { log_error("close s %d failed, ignored: %s", conn->sd, strerror(errno)); } conn->sd = -1; conn_put(conn); }
static void rsp_forward(struct context *ctx, struct conn *s_conn, struct msg *msg) { rstatus_t status; struct msg *pmsg; struct conn *c_conn; ASSERT(!s_conn->client && !s_conn->proxy); /* response from server implies that server is ok and heartbeating */ server_ok(ctx, s_conn); /* dequeue peer message (request) from server */ pmsg = TAILQ_FIRST(&s_conn->omsg_q); ASSERT(pmsg != NULL && pmsg->peer == NULL); ASSERT(pmsg->request && !pmsg->done); s_conn->dequeue_outq(ctx, s_conn, pmsg); pmsg->done = 1; /* establish msg <-> pmsg (response <-> request) link */ pmsg->peer = msg; msg->peer = pmsg; /* * Readjust responses of fragmented messages by not including the end * marker for all but the last response * * Valid responses for a fragmented requests are MSG_RSP_VALUE or, * MSG_RSP_END. For an invalid response, we send out SERVER_ERRROR with * EINVAL errno */ if (pmsg->frag_id != 0) { if (msg->type != MSG_RSP_VALUE && msg->type != MSG_RSP_END) { pmsg->error = 1; pmsg->err = EINVAL; } else if (!pmsg->last_fragment) { ASSERT(msg->end != NULL); for (;;) { struct mbuf *mbuf; mbuf = STAILQ_LAST(&msg->mhdr, mbuf, next); ASSERT(mbuf != NULL); /* * We cannot assert that end marker points to the last mbuf * Consider a scenario where end marker points to the * penultimate mbuf and the last mbuf only contains spaces * and CRLF: mhdr -> [...END] -> [\r\n] */ if (msg->end >= mbuf->pos && msg->end < mbuf->last) { /* end marker is within this mbuf */ msg->mlen -= (uint32_t)(mbuf->last - msg->end); mbuf->last = msg->end; break; } /* end marker is not in this mbuf */ msg->mlen -= mbuf_length(mbuf); mbuf_remove(&msg->mhdr, mbuf); mbuf_put(mbuf); } } } c_conn = pmsg->owner; ASSERT(c_conn->client && !c_conn->proxy); if (req_done(c_conn, TAILQ_FIRST(&c_conn->omsg_q))) { status = event_add_out(ctx->ep, c_conn); if (status != NC_OK) { c_conn->err = errno; } } rsp_forward_stats(ctx, s_conn->owner, msg); }
bool dnode_req_done(struct conn *conn, struct msg *msg) { ASSERT(!conn->dnode_client && !conn->dnode_server); return req_done(conn, msg); }
struct msg * rsp_send_next(struct context *ctx, struct conn *conn) { rstatus_t status; struct msg *rsp, *req; /* response and it's peer request */ ASSERT_LOG((conn->type == CONN_DNODE_PEER_CLIENT) || (conn->type = CONN_CLIENT), "conn %s", conn_get_type_string(conn)); req = TAILQ_FIRST(&conn->omsg_q); if (req == NULL || (!req->selected_rsp && !req_done(conn, req))) { /* nothing is outstanding, initiate close? */ if (req == NULL && conn->eof) { conn->done = 1; log_debug(LOG_INFO, "c %d is done", conn->sd); } status = event_del_out(ctx->evb, conn); if (status != DN_OK) { conn->err = errno; } return NULL; } rsp = conn->smsg; if (rsp != NULL) { ASSERT(!rsp->request); ASSERT(rsp->peer != NULL); req = TAILQ_NEXT(rsp->peer, c_tqe); } if (req == NULL || !req_done(conn, req)) { conn->smsg = NULL; return NULL; } ASSERT(req->request && !req->swallow); if (req_error(conn, req)) { rsp = rsp_make_error(ctx, conn, req); if (rsp == NULL) { conn->err = errno; return NULL; } rsp->peer = req; req->selected_rsp = rsp; log_debug(LOG_VERB, "creating new error rsp %p", rsp); if (conn->dyn_mode) { stats_pool_incr(ctx, peer_forward_error); } else { stats_pool_incr(ctx, forward_error); } } else { rsp = req->selected_rsp; } ASSERT(!rsp->request); conn->smsg = rsp; if (log_loggable(LOG_VVERB)) { log_debug(LOG_VVERB, "send next rsp %"PRIu64" on c %d", rsp->id, conn->sd); } return rsp; }
struct msg * rsp_send_next(struct context *ctx, struct conn *conn) { rstatus_t status; struct msg *msg, *pmsg; /* response and it's peer request */ ASSERT((conn->client && !conn->proxy) || (conn->dnode_client && !conn->dnode_server)); pmsg = TAILQ_FIRST(&conn->omsg_q); if (pmsg == NULL || !req_done(conn, pmsg)) { /* nothing is outstanding, initiate close? */ if (pmsg == NULL && conn->eof) { conn->done = 1; log_debug(LOG_INFO, "c %d is done", conn->sd); } status = event_del_out(ctx->evb, conn); if (status != DN_OK) { conn->err = errno; } return NULL; } msg = conn->smsg; if (msg != NULL) { ASSERT(!msg->request && msg->peer != NULL); ASSERT(req_done(conn, msg->peer)); pmsg = TAILQ_NEXT(msg->peer, c_tqe); } if (pmsg == NULL || !req_done(conn, pmsg)) { conn->smsg = NULL; return NULL; } ASSERT(pmsg->request && !pmsg->swallow); if (req_error(conn, pmsg)) { msg = rsp_make_error(ctx, conn, pmsg); if (msg == NULL) { conn->err = errno; return NULL; } msg->peer = pmsg; pmsg->peer = msg; if (!conn->dyn_mode) { stats_pool_incr(ctx, conn->owner, forward_error); } else { //dyn_mode stats_pool_incr(ctx, conn->owner, peer_forward_error); } } else { msg = pmsg->peer; } ASSERT(!msg->request); conn->smsg = msg; log_debug(LOG_VVERB, "send next rsp %"PRIu64" on c %d", msg->id, conn->sd); return msg; }