[MEDIUM] backend: introduce the "static-rr" LB algorithm

The "static-rr" is just the old round-robin algorithm. It is still
in use when a hash algorithm is used and the data to hash is not
present, but it was impossible to configure it explicitly. This one
is cheaper in terms of CPU and supports unlimited numbers of servers,
so it makes sense to be able to use it.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index c7e582d..3b7648b 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -915,7 +915,23 @@
                   This is the smoothest and fairest algorithm when the server's
                   processing time remains equally distributed. This algorithm
                   is dynamic, which means that server weights may be adjusted
-                  on the fly for slow starts for instance.
+                  on the fly for slow starts for instance. It is limited by
+                  design to 4128 active servers per backend. Note that in some
+                  large farms, when a server becomes up after having been down
+                  for a very short time, it may sometimes take a few hundreds
+                  requests for it to be re-integrated into the farm and start
+                  receiving traffic. This is normal, though very rare. It is
+                  indicated here in case you would have the chance to observe
+                  it, so that you don't worry.
+
+      static-rr   Each server is used in turns, according to their weights.
+                  This algorithm is as similar to roundrobin except that it is
+                  static, which means that changing a server's weight on the
+                  fly will have no effect. On the other hand, it has no design
+                  limitation on the number of servers, and when a server goes
+                  up, it is always immediately reintroduced into the farm, once
+                  the full map is recomputed. It also uses slightly less CPU to
+                  run (around -1%).
 
       leastconn   The server with the lowest number of connections receives the
                   connection. Round-robin is performed within groups of servers
diff --git a/include/types/backend.h b/include/types/backend.h
index a73a36a..a8f8586 100644
--- a/include/types/backend.h
+++ b/include/types/backend.h
@@ -42,6 +42,9 @@
 #define BE_LB_HASH_PRM  0x00002  /* hash HTTP URL parameter */
 #define BE_LB_HASH_HDR  0x00003  /* hash HTTP header value */
 #define BE_LB_HASH_RDP  0x00004  /* hash RDP cookie value */
+
+#define BE_LB_RR_DYN    0x00000  /* dynamic round robin (default) */
+#define BE_LB_RR_STATIC 0x00001  /* static round robin */
 #define BE_LB_PARM      0x000FF  /* mask to get/clear the LB param */
 
 /* Required input(s) */
@@ -65,6 +68,7 @@
 #define BE_LB_ALGO_NONE (BE_LB_KIND_NONE | BE_LB_NEED_NONE)    /* not defined */
 #define BE_LB_ALGO_RR   (BE_LB_KIND_RR | BE_LB_NEED_NONE)      /* round robin */
 #define BE_LB_ALGO_LC   (BE_LB_KIND_LC | BE_LB_NEED_NONE)      /* least connections */
+#define BE_LB_ALGO_SRR  (BE_LB_KIND_RR | BE_LB_NEED_NONE | BE_LB_RR_STATIC) /* static round robin */
 #define BE_LB_ALGO_SH	(BE_LB_KIND_HI | BE_LB_NEED_ADDR | BE_LB_HASH_SRC) /* hash: source IP */
 #define BE_LB_ALGO_UH	(BE_LB_KIND_HI | BE_LB_NEED_HTTP | BE_LB_HASH_URI) /* hash: HTTP URI  */
 #define BE_LB_ALGO_PH	(BE_LB_KIND_HI | BE_LB_NEED_HTTP | BE_LB_HASH_PRM) /* hash: HTTP URL parameter */
diff --git a/src/backend.c b/src/backend.c
index 14ae705..39726ce 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -516,7 +516,11 @@
 			break;
 
 		case BE_LB_LKUP_MAP:
-			if ((s->be->lbprm.algo & BE_LB_KIND) != BE_LB_KIND_HI) {
+			if ((s->be->lbprm.algo & BE_LB_KIND) == BE_LB_KIND_RR) {
+				s->srv = map_get_server_rr(s->be, s->prev_srv);
+				break;
+			}
+			else if ((s->be->lbprm.algo & BE_LB_KIND) != BE_LB_KIND_HI) {
 				/* unknown balancing algorithm */
 				err = SRV_STATUS_INTERNAL;
 				goto out;
@@ -973,6 +977,10 @@
 		curproxy->lbprm.algo &= ~BE_LB_ALGO;
 		curproxy->lbprm.algo |= BE_LB_ALGO_RR;
 	}
+	else if (!strcmp(args[0], "static-rr")) {
+		curproxy->lbprm.algo &= ~BE_LB_ALGO;
+		curproxy->lbprm.algo |= BE_LB_ALGO_SRR;
+	}
 	else if (!strcmp(args[0], "leastconn")) {
 		curproxy->lbprm.algo &= ~BE_LB_ALGO;
 		curproxy->lbprm.algo |= BE_LB_ALGO_LC;
@@ -1098,7 +1106,7 @@
 		}
 	}
 	else {
-		snprintf(err, errlen, "'balance' only supports 'roundrobin', 'leastconn', 'source', 'uri', 'url_param', 'hdr(name)' and 'rdp-cookie(name)' options.");
+		snprintf(err, errlen, "'balance' only supports 'roundrobin', 'static-rr', 'leastconn', 'source', 'uri', 'url_param', 'hdr(name)' and 'rdp-cookie(name)' options.");
 		return -1;
 	}
 	return 0;
diff --git a/src/cfgparse.c b/src/cfgparse.c
index de84f37..7bb94b8 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -4196,8 +4196,13 @@
 		curproxy->lbprm.algo &= ~(BE_LB_LKUP | BE_LB_PROP_DYN);
 		switch (curproxy->lbprm.algo & BE_LB_KIND) {
 		case BE_LB_KIND_RR:
-			curproxy->lbprm.algo |= BE_LB_LKUP_RRTREE | BE_LB_PROP_DYN;
-			fwrr_init_server_groups(curproxy);
+			if ((curproxy->lbprm.algo & BE_LB_PARM) == BE_LB_RR_STATIC) {
+				curproxy->lbprm.algo |= BE_LB_LKUP_MAP;
+				init_server_map(curproxy);
+			} else {
+				curproxy->lbprm.algo |= BE_LB_LKUP_RRTREE | BE_LB_PROP_DYN;
+				fwrr_init_server_groups(curproxy);
+			}
 			break;
 		case BE_LB_KIND_LC:
 			curproxy->lbprm.algo |= BE_LB_LKUP_LCTREE | BE_LB_PROP_DYN;