* SCHED_COUNTER_BITS is the portion of an ngx_uint_t which represents
664 * the req_delta part (number of requests serviced on _other_
665 * backends). The rest (top bits) represents the number of currently
666 * processed requests.
667 *
668 * The value is not too critical because overflow is handled via
669 * saturation. With the default value of 20, scheduling is exact for
670 * fewer than 4k concurrent requests per backend (on 32-bit
671 * architectures) and fewer than 1M concurrent requests to all backends
672 * together. Beyond these limits, the algorithm essentially falls back
673 * to pure weighted round-robin.
674 *
675 * A higher score means less suitable.
676 *
677 * The `delta' parameter is bit-negated so that high values yield low
678 * scores and get chosen more often.
679 */
680
681 #define SCHED_COUNTER_BITS 20
682 #define SCHED_NREQ_MAX ((~0UL) >> SCHED_COUNTER_BITS)
683 #define SCHED_COUNTER_MAX ((1 << SCHED_COUNTER_BITS) - 1)
684 #define SCHED_SCORE(nreq,delta) (((nreq) << SCHED_COUNTER_BITS) | (~(delta) & SCHED_COUNTER_MAX))
685 #define ngx_upstream_fair_min(a,b) (((a) < (b)) ? (a) : (b))
686
687 static ngx_uint_t
688 ngx_http_upstream_fair_sched_score(ngx_peer_connection_t *pc,
689 ngx_http_upstream_fair_peer_data_t *fp,
690 ngx_uint_t n)
691 {
692 ngx_http_upstream_fair_peer_t *peer = &fp->peers->peer[n];
693 ngx_http_upstream_fair_shared_t *fs = peer->shared;
694 ngx_uint_t req_delta = fp->peers->shared->total_requests - fs->last_req_id;
695
696 /* sanity check */
697 if ((ngx_int_t)fs->nreq < 0) {
698 ngx_log_error(NGX_LOG_WARN, pc->log, 0, "[upstream_fair] upstream %ui has negative nreq (%i)", n, fs->nreq);
699 return SCHED_SCORE(0, req_delta);
700 }
701
702 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, pc->log, 0, "[upstream_fair] peer %ui: nreq = %i, req_delta = %ui", n, fs->nreq, req_delta);
703
704 return SCHED_SCORE(
705 ngx_upstream_fair_min(fs->nreq, SCHED_NREQ_MAX),
706 ngx_upstream_fair_min(req_delta, SCHED_COUNTER_MAX));
}