<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -5,11 +5,11 @@ define show_fair_peer
 	set $i = 0
 	while $i &lt; $peers-&gt;number
 		set $peer = &amp;$peers-&gt;peer[$i]
-		printf &quot;peer %d: %s weight: %d/%d fails: %d/%d acc: %d down: %d nreq: %u last_act: %u\n&quot;, $i, $peer-&gt;name.data,\
+		printf &quot;peer %d: %s weight: %d/%d fails: %d/%d acc: %d down: %d nreq: %u last_req_id: %u\n&quot;, $i, $peer-&gt;name.data,\
 			$peer-&gt;shared-&gt;current_weight, $peer-&gt;weight,\
 			$peer-&gt;shared-&gt;fails, $peer-&gt;max_fails,\
 			$peer-&gt;accessed, $peer-&gt;down,\
-			$peer-&gt;shared-&gt;nreq, $peer-&gt;shared-&gt;last_active
+			$peer-&gt;shared-&gt;nreq, $peer-&gt;shared-&gt;last_req_id
 		set $i = $i + 1
 	end
 	printf &quot;-----------------\n&quot;</diff>
      <filename>.gdbinit</filename>
    </modified>
    <modified>
      <diff>@@ -11,7 +11,8 @@
 
 typedef struct {
     ngx_atomic_t                        nreq;
-    ngx_atomic_t                        last_active;
+    ngx_atomic_t                        total_req;
+    ngx_atomic_t                        last_req_id;
     ngx_atomic_t                        fails;
     ngx_atomic_t                        current_weight;
 } ngx_http_upstream_fair_shared_t;
@@ -24,6 +25,7 @@ typedef struct {
     ngx_cycle_t                        *cycle;
     ngx_http_upstream_fair_peers_t     *peers;      /* forms a unique cookie together with cycle */
     ngx_int_t                           refcount;   /* accessed only under shmtx_lock */
+    ngx_uint_t                          total_requests;
     ngx_http_upstream_fair_shared_t     stats[1];
 } ngx_http_upstream_fair_shm_block_t;
 
@@ -597,11 +599,9 @@ ngx_http_upstream_init_fair(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us)
 
     peers-&gt;cycle = cf-&gt;cycle;
     peers-&gt;shared = NULL;
+    peers-&gt;current = n - 1;
     if (us-&gt;flags &amp; NGX_HTTP_UPSTREAM_FAIR_NO_RR) {
         peers-&gt;no_rr = 1;
-        peers-&gt;current = 0;
-    } else {
-        peers-&gt;current = n - 1;
     }
     peers-&gt;size_err = 0;
 
@@ -617,64 +617,58 @@ ngx_http_upstream_fair_update_nreq(ngx_http_upstream_fair_peer_data_t *fp, int d
     ngx_http_upstream_fair_shared_t     *fs;
 
     fs = fp-&gt;peers-&gt;peer[fp-&gt;current].shared;
-
     ngx_atomic_fetch_add(&amp;fs-&gt;nreq, delta);
-
-    fs-&gt;last_active = ngx_current_msec;
-
+    if (delta &gt; 0) {
+        ngx_atomic_fetch_add(&amp;fs-&gt;total_req, 1);
+    }
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, &quot;[upstream_fair] nreq for peer %ui now %d&quot;, fp-&gt;current, fs-&gt;nreq);
 }
 
 /*
- * SCHED_TIME_BITS is the portion of an ngx_uint_t which represents the
- * last_time_delta part (time since last activity in msec). The rest
- * (top bits) represents the number of currently processed requests.
+ * SCHED_COUNTER_BITS is the portion of an ngx_uint_t which represents
+ * the req_delta part (number of requests serviced on _other_
+ * backends). The rest (top bits) represents the number of currently
+ * processed requests.
  *
  * The value is not too critical because overflow is handled via
- * saturation. With the default value of 24, scheduling is exact for
- * requests shorter than 16777 sec and for less than 256 requests per
- * backend (on 32-bit architectures). Beyond these limits, the algorithm
- * essentially falls back to pure weighted round-robin
+ * saturation. With the default value of 20, scheduling is exact for
+ * fewer than 4k concurrent requests per backend (on 32-bit
+ * architectures) and fewer than 1M concurrent requests to all backends
+ * together. Beyond these limits, the algorithm essentially falls back
+ * to pure weighted round-robin.
  *
- * A higher score means less suitable -- this changed from previous
- * releases.
+ * A higher score means less suitable.
  *
  * The `delta' parameter is bit-negated so that high values yield low
  * scores and get chosen more often.
  */
 
-#define SCHED_TIME_BITS 24
-#define SCHED_NREQ_MAX ((~0UL) &gt;&gt; SCHED_TIME_BITS)
-#define SCHED_TIME_MAX ((1 &lt;&lt; SCHED_TIME_BITS) - 1)
-#define SCHED_SCORE(nreq,delta) (((nreq) &lt;&lt; SCHED_TIME_BITS) | (~(delta)))
+#define SCHED_COUNTER_BITS 20
+#define SCHED_NREQ_MAX ((~0UL) &gt;&gt; SCHED_COUNTER_BITS)
+#define SCHED_COUNTER_MAX ((1 &lt;&lt; SCHED_COUNTER_BITS) - 1)
+#define SCHED_SCORE(nreq,delta) (((nreq) &lt;&lt; SCHED_COUNTER_BITS) | (~(delta)))
 #define ngx_upstream_fair_min(a,b) (((a) &lt; (b)) ? (a) : (b))
 
 static ngx_uint_t
 ngx_http_upstream_fair_sched_score(ngx_peer_connection_t *pc,
-    ngx_http_upstream_fair_shared_t *fs,
-    ngx_http_upstream_fair_peer_t *peer, ngx_uint_t n)
+    ngx_http_upstream_fair_peer_data_t *fp,
+    ngx_uint_t n)
 {
-    ngx_msec_t                          last_active_delta;
-
-    last_active_delta = ngx_current_msec - fs-&gt;last_active;
-    if ((ngx_int_t) last_active_delta &lt; 0) {
-        ngx_log_error(NGX_LOG_WARN, pc-&gt;log, 0, &quot;[upstream_fair] Clock skew of at least %i msec detected&quot;, -(ngx_int_t) last_active_delta);
-
-        /* a pretty arbitrary value */
-        last_active_delta = abs(last_active_delta);
-    }
+    ngx_http_upstream_fair_peer_t      *peer = &amp;fp-&gt;peers-&gt;peer[n];
+    ngx_http_upstream_fair_shared_t    *fs = peer-&gt;shared;
+    ngx_uint_t req_delta = fp-&gt;peers-&gt;shared-&gt;total_requests - fs-&gt;last_req_id;
 
     /* sanity check */
     if ((ngx_int_t)fs-&gt;nreq &lt; 0) {
         ngx_log_error(NGX_LOG_WARN, pc-&gt;log, 0, &quot;[upstream_fair] upstream %ui has negative nreq (%i)&quot;, n, fs-&gt;nreq);
-        return SCHED_SCORE(0, last_active_delta);
+        return SCHED_SCORE(0, req_delta);
     }
 
-    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc-&gt;log, 0, &quot;[upstream_fair] nreq = %i, last_active_delta = %ui&quot;, fs-&gt;nreq, last_active_delta);
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc-&gt;log, 0, &quot;[upstream_fair] nreq = %i, req_delta = %ui&quot;, fs-&gt;nreq, req_delta);
 
     return SCHED_SCORE(
         ngx_upstream_fair_min(fs-&gt;nreq, SCHED_NREQ_MAX),
-        ngx_upstream_fair_min(last_active_delta, SCHED_TIME_MAX));
+        ngx_upstream_fair_min(req_delta, SCHED_COUNTER_MAX));
 }
 
 /*
@@ -761,7 +755,7 @@ ngx_http_upstream_choose_fair_peer(ngx_peer_connection_t *pc,
 
         peer = &amp;fp-&gt;peers-&gt;peer[n];
         fsc = *peer-&gt;shared;
-        sched_score = ngx_http_upstream_fair_sched_score(pc, &amp;fsc, peer, n);
+        sched_score = ngx_http_upstream_fair_sched_score(pc, fp, n);
 
         /*
          * take peer weight into account
@@ -832,6 +826,7 @@ ngx_http_upstream_get_fair_peer(ngx_peer_connection_t *pc, void *data)
     pc-&gt;socklen = peer-&gt;socklen;
     pc-&gt;name = &amp;peer-&gt;name;
 
+    peer-&gt;shared-&gt;last_req_id = fp-&gt;peers-&gt;shared-&gt;total_requests;
     ngx_http_upstream_fair_update_nreq(data, 1, pc-&gt;log);
     return ret;
 }
@@ -970,10 +965,12 @@ ngx_http_upstream_fair_shm_alloc(ngx_http_upstream_fair_peers_t *usfp, ngx_log_t
     usfp-&gt;shared-&gt;refcount = 1;
     usfp-&gt;shared-&gt;cycle = usfp-&gt;cycle;
     usfp-&gt;shared-&gt;peers = usfp;
+    usfp-&gt;shared-&gt;total_requests = 0;
 
     for (i = 0; i &lt; usfp-&gt;number; i++) {
             usfp-&gt;shared-&gt;stats[i].nreq = 0;
-            usfp-&gt;shared-&gt;stats[i].last_active = ngx_current_msec;
+            usfp-&gt;shared-&gt;stats[i].last_req_id = 0;
+            usfp-&gt;shared-&gt;stats[i].total_req = 0;
     }
 
     ngx_rbtree_insert(ngx_http_upstream_fair_rbtree, &amp;usfp-&gt;shared-&gt;node);
@@ -1015,6 +1012,7 @@ ngx_http_upstream_init_fair_peer(ngx_http_request_t *r,
 
     fp-&gt;current = usfp-&gt;current;
     fp-&gt;peers = usfp;
+    usfp-&gt;shared-&gt;total_requests++;
 
     for (n = 0; n &lt; usfp-&gt;number; n++) {
         usfp-&gt;peer[n].shared = &amp;usfp-&gt;shared-&gt;stats[n];
@@ -1145,13 +1143,13 @@ ngx_http_upstream_fair_walk_status(ngx_pool_t *pool, ngx_chain_t *cl, ngx_int_t
 
     peers = s_node-&gt;peers;
 
-    b-&gt;last = ngx_sprintf(b-&gt;last, &quot;upstream %V (%p): current peer %d/%d\n&quot;, peers-&gt;name, (void*) node, peers-&gt;current, peers-&gt;number);
+    b-&gt;last = ngx_sprintf(b-&gt;last, &quot;upstream %V (%p): current peer %d/%d, total requests: %ui\n&quot;, peers-&gt;name, (void*) node, peers-&gt;current, peers-&gt;number, s_node-&gt;total_requests);
     for (i = 0; i &lt; peers-&gt;number; i++) {
         ngx_http_upstream_fair_peer_t *peer = &amp;peers-&gt;peer[i];
         ngx_http_upstream_fair_shared_t *sh = peer-&gt;shared;
-        b-&gt;last = ngx_sprintf(b-&gt;last, &quot; peer %d: %V weight: %d/%d, fails: %d/%d, acc: %d, down: %d, nreq: %d, last_act: %ui\n&quot;,
+        b-&gt;last = ngx_sprintf(b-&gt;last, &quot; peer %d: %V weight: %d/%d, fails: %d/%d, acc: %d, down: %d, nreq: %d, total_req: %ui, last_req: %ui\n&quot;,
             i, &amp;peer-&gt;name, sh-&gt;current_weight, peer-&gt;weight, sh-&gt;fails, peer-&gt;max_fails, peer-&gt;accessed, peer-&gt;down,
-            sh-&gt;nreq, sh-&gt;last_active);
+            sh-&gt;nreq, sh-&gt;total_req, sh-&gt;last_req_id);
     }
     b-&gt;last = ngx_sprintf(b-&gt;last, &quot;\n&quot;);
     b-&gt;last_buf = 1;</diff>
      <filename>ngx_http_upstream_fair_module.c</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>085e8a1ff18dab46f0b0fc78f3a39f414129a39d</id>
    </parent>
  </parents>
  <author>
    <name>Grzegorz Nosek</name>
    <email>root@localdomain.pl</email>
  </author>
  <url>http://github.com/gnosek/nginx-upstream-fair/commit/be0d30a0c1de5596dfc70e4b2e345013b44730d9</url>
  <id>be0d30a0c1de5596dfc70e4b2e345013b44730d9</id>
  <committed-date>2008-09-16T14:05:35-07:00</committed-date>
  <authored-date>2008-09-16T14:05:35-07:00</authored-date>
  <message>Use monotonic request counter instead of time data, track total number of requests per upstream and per backend</message>
  <tree>531f92634d5e53c356510d8082a9573a254cbeed</tree>
  <committer>
    <name>Grzegorz Nosek</name>
    <email>root@localdomain.pl</email>
  </committer>
</commit>
