uint32_t server_pool_idx(struct server_pool *pool, uint8_t *key, uint32_t keylen) { uint32_t hash, idx; ASSERT(array_n(&pool->server) != 0); ASSERT(key != NULL); /* * If hash_tag: is configured for this server pool, we use the part of * the key within the hash tag as an input to the distributor. Otherwise * we use the full key */ if (!string_empty(&pool->hash_tag)) { struct string *tag = &pool->hash_tag; uint8_t *tag_start, *tag_end; tag_start = nc_strchr(key, key + keylen, tag->data[0]); if (tag_start != NULL) { tag_end = nc_strchr(tag_start + 1, key + keylen, tag->data[1]); if ((tag_end != NULL) && (tag_end - tag_start > 1)) { key = tag_start + 1; keylen = (uint32_t)(tag_end - key); } } } switch (pool->dist_type) { case DIST_KETAMA: hash = server_pool_hash(pool, key, keylen); idx = ketama_dispatch(pool->continuum, pool->ncontinuum, hash); break; case DIST_MODULA: hash = server_pool_hash(pool, key, keylen); idx = modula_dispatch(pool->continuum, pool->ncontinuum, hash); break; case DIST_RANDOM: idx = random_dispatch(pool->continuum, pool->ncontinuum, 0); break; default: NOT_REACHED(); return 0; } ASSERT(idx < array_n(&pool->server)); return idx; }
static void req_forward(struct context *ctx, struct conn *c_conn, struct msg *msg) { rstatus_t status; struct conn *s_conn; struct server_pool *pool; uint8_t *key; uint32_t keylen; ASSERT(c_conn->client && !c_conn->proxy); /* enqueue message (request) into client outq, if response is expected */ if (!msg->noreply) { c_conn->enqueue_outq(ctx, c_conn, msg); } pool = c_conn->owner; key = NULL; keylen = 0; /* * If hash_tag: is configured for this server pool, we use the part of * the key within the hash tag as an input to the distributor. Otherwise * we use the full key */ if (!string_empty(&pool->hash_tag)) { struct string *tag = &pool->hash_tag; uint8_t *tag_start, *tag_end; tag_start = nc_strchr(msg->key_start, msg->key_end, tag->data[0]); if (tag_start != NULL) { tag_end = nc_strchr(tag_start + 1, msg->key_end, tag->data[1]); if (tag_end != NULL) { key = tag_start + 1; keylen = (uint32_t)(tag_end - key); } } } if (keylen == 0) { key = msg->key_start; keylen = (uint32_t)(msg->key_end - msg->key_start); } s_conn = server_pool_conn(ctx, c_conn->owner, key, keylen); if (s_conn == NULL) { req_forward_error(ctx, c_conn, msg); return; } ASSERT(!s_conn->client && !s_conn->proxy); /* enqueue the message (request) into server inq */ status = event_add_out_with_conn(ctx, s_conn, msg); if (status != NC_OK) { req_forward_error(ctx, c_conn, msg); s_conn->err = errno; return; } req_forward_stats(ctx, s_conn->owner, msg); log_debug(LOG_VERB, "forward from c %d to s %d req %"PRIu64" len %"PRIu32 " type %d with key '%.*s'", c_conn->sd, s_conn->sd, msg->id, msg->mlen, msg->type, keylen, key); }
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); }