diff --git a/src/http/modules/ngx_http_upstream_sticky_module.c b/src/http/modules/ngx_http_upstream_sticky_module.c index c76bfd6db..8d8df7e7e 100644 --- a/src/http/modules/ngx_http_upstream_sticky_module.c +++ b/src/http/modules/ngx_http_upstream_sticky_module.c @@ -126,6 +126,7 @@ ngx_http_upstream_sticky_select_peer(ngx_http_upstream_rr_peer_data_t *rrp, ngx_uint_t i, n; ngx_http_request_t *r; + ngx_http_upstream_state_t *us; ngx_http_upstream_rr_peer_t *peer; ngx_http_upstream_rr_peers_t *peers; ngx_http_upstream_sticky_srv_conf_t *scf; @@ -133,8 +134,11 @@ ngx_http_upstream_sticky_select_peer(ngx_http_upstream_rr_peer_data_t *rrp, r = pc->ctx; hint = &sp->hint; + us = r->upstream->state; if (hint->len == 0) { + us->sticky_status = NGX_HTTP_UPSTREAM_STICKY_STATUS_NEW; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "sticky: no hint provided"); return NGX_OK; @@ -200,6 +204,8 @@ ngx_http_upstream_sticky_select_peer(ngx_http_upstream_rr_peer_data_t *rrp, continue; } + us->sticky_status = NGX_HTTP_UPSTREAM_STICKY_STATUS_HIT; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "sticky: found matching peer %ui", i); @@ -236,6 +242,8 @@ ngx_http_upstream_sticky_select_peer(ngx_http_upstream_rr_peer_data_t *rrp, goto again; } + us->sticky_status = NGX_HTTP_UPSTREAM_STICKY_STATUS_MISS; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "sticky: no match"); ngx_http_upstream_rr_peers_unlock(peers); diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index f121936f8..609361c6a 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -11,6 +11,12 @@ #include +#if (NGX_HTTP_UPSTREAM_STICKY) +static ngx_int_t ngx_http_upstream_sticky_status_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +#endif + + #if (NGX_HTTP_CACHE) static ngx_int_t ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u); @@ -445,6 +451,14 @@ static ngx_http_variable_t ngx_http_upstream_vars[] = { ngx_http_upstream_cache_etag, 0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, +#endif + +#if (NGX_HTTP_UPSTREAM_STICKY) + + { ngx_string("upstream_sticky_status"), NULL, + ngx_http_upstream_sticky_status_variable, 0, + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + #endif { ngx_string("upstream_http_"), NULL, ngx_http_upstream_header_variable, @@ -6103,6 +6117,84 @@ ngx_http_upstream_cache_etag(ngx_http_request_t *r, #endif +#if (NGX_HTTP_UPSTREAM_STICKY) + +static ngx_str_t ngx_http_upstream_sticky_status[4] = { + ngx_string(""), + ngx_string("new"), /* NGX_HTTP_UPSTREAM_STICKY_STATUS_NEW */ + ngx_string("hit"), /* NGX_HTTP_UPSTREAM_STICKY_STATUS_HIT */ + ngx_string("miss") /* NGX_HTTP_UPSTREAM_STICKY_STATUS_MISS */ +}; + + +static ngx_int_t +ngx_http_upstream_sticky_status_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + u_char *p; + size_t len; + ngx_uint_t i; + ngx_http_upstream_state_t *state; + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + if (r->upstream_states == NULL || r->upstream_states->nelts == 0) { + v->not_found = 1; + return NGX_OK; + } + + len = r->upstream_states->nelts * (sizeof("miss") - 1 + 2); + + p = ngx_pnalloc(r->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + v->data = p; + + i = 0; + state = r->upstream_states->elts; + + for ( ;; ) { + if (state[i].status) { + p = ngx_sprintf(p, "%V", + &ngx_http_upstream_sticky_status[state[i].sticky_status]); + + } else { + *p++ = '-'; + } + + if (++i == r->upstream_states->nelts) { + break; + } + + if (state[i].peer) { + *p++ = ','; + *p++ = ' '; + + } else { + *p++ = ' '; + *p++ = ':'; + *p++ = ' '; + + if (++i == r->upstream_states->nelts) { + break; + } + + continue; + } + } + + v->len = p - v->data; + + return NGX_OK; +} + +#endif + + static char * ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) { diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index a43321cd9..eaf5e59cf 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -45,6 +45,11 @@ #define NGX_HTTP_UPSTREAM_INVALID_HEADER 40 +/* zero indicates no sticky */ +#define NGX_HTTP_UPSTREAM_STICKY_STATUS_NEW 1 +#define NGX_HTTP_UPSTREAM_STICKY_STATUS_HIT 2 +#define NGX_HTTP_UPSTREAM_STICKY_STATUS_MISS 3 + #define NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT 0x00000002 #define NGX_HTTP_UPSTREAM_IGN_XA_EXPIRES 0x00000004 @@ -66,6 +71,9 @@ typedef struct { off_t response_length; off_t bytes_received; off_t bytes_sent; +#if (NGX_HTTP_UPSTREAM_STICKY) + ngx_uint_t sticky_status; +#endif ngx_str_t *peer; } ngx_http_upstream_state_t;