[MEDIUM] improve behaviour with large number of servers per proxy

When a very large number of servers is configured (thousands),
shutting down many of them at once could lead to large number
of calls to recalc_server_map() which already takes some time.
This would result in an O(N^3) computation time, leading to
noticeable pauses on slow embedded CPUs on test platforms.

Instead, mark the map as dirty and recalc it only when needed.
diff --git a/include/proto/backend.h b/include/proto/backend.h
index f0295b0..467e756 100644
--- a/include/proto/backend.h
+++ b/include/proto/backend.h
@@ -52,6 +52,9 @@
 	int newidx;
 	struct server *srv;
 
+	if (px->map_state & PR_MAP_RECALC)
+		recalc_server_map(px);
+
 	if (px->srv_map_sz == 0)
 		return NULL;
 
@@ -81,6 +84,9 @@
  */
 static inline struct server *get_server_rr(struct proxy *px)
 {
+	if (px->map_state & PR_MAP_RECALC)
+		recalc_server_map(px);
+
 	if (px->srv_map_sz == 0)
 		return NULL;
 
@@ -97,11 +103,14 @@
  * If any server is found, it will be returned. If no valid server is found,
  * NULL is returned.
  */
-static inline struct server *get_server_sh(const struct proxy *px,
+static inline struct server *get_server_sh(struct proxy *px,
 					   const char *addr, int len)
 {
 	unsigned int h, l;
 
+	if (px->map_state & PR_MAP_RECALC)
+		recalc_server_map(px);
+
 	if (px->srv_map_sz == 0)
 		return NULL;
 
@@ -133,6 +142,9 @@
 	unsigned long hash = 0;
 	int c;
 
+	if (px->map_state & PR_MAP_RECALC)
+		recalc_server_map(px);
+
 	if (px->srv_map_sz == 0)
 		return NULL;
 
diff --git a/include/types/proxy.h b/include/types/proxy.h
index 6d87f80..d205c42 100644
--- a/include/types/proxy.h
+++ b/include/types/proxy.h
@@ -53,6 +53,9 @@
 #define PR_MODE_HTTP    1
 #define PR_MODE_HEALTH  2
 
+/* values for proxy->map_state */
+#define PR_MAP_RECALC  (1 << 0)
+
 /* flag values for proxy->cap. This is a bitmask of capabilities supported by the proxy */
 #define PR_CAP_NONE    0x0000
 #define PR_CAP_FE      0x0001
@@ -86,6 +89,7 @@
 	struct list acl;                        /* ACL declared on this proxy */
 	struct list block_cond;                 /* early blocking conditions (chained) */
 	struct list switching_rules;            /* content switching rules (chained) */
+	int map_state;				/* PR_MAP_RECALC */
 	struct server *srv;			/* known servers */
 	int srv_act, srv_bck;			/* # of running servers */
 	int tot_wact, tot_wbck;			/* total weights of active and backup servers */
diff --git a/src/backend.c b/src/backend.c
index 8abaf1c..da8b8ac 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -90,6 +90,7 @@
 			tot = 1; /* the first server is enough */
 	} else {
 		px->srv_map_sz = 0;
+		px->map_state &= ~PR_MAP_RECALC;
 		return;
 	}
 
@@ -130,6 +131,7 @@
 		best->wscore -= tot;
 	}
 	px->srv_map_sz = tot;
+	px->map_state &= ~PR_MAP_RECALC;
 }
 
 
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 39abbc3..967b9ca 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -2637,6 +2637,7 @@
 
 			curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
 			/* recounts servers and their weights */
+			curproxy->map_state = PR_MAP_RECALC;
 			recount_servers(curproxy);
 			recalc_server_map(curproxy);
 		}
diff --git a/src/checks.c b/src/checks.c
index 4c8a009..2c581ef 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -46,7 +46,8 @@
 
 /* Sets server <s> down, notifies by all available means, recounts the
  * remaining servers on the proxy and transfers queued sessions whenever
- * possible to other servers.
+ * possible to other servers. It automatically recomputes the number of
+ * servers, but not the map.
  */
 static void set_server_down(struct server *s)
 {
@@ -58,7 +59,7 @@
 
 	if (s->health == s->rise) {
 		recount_servers(s->proxy);
-		recalc_server_map(s->proxy);
+		s->proxy->map_state |= PR_MAP_RECALC;
 
 		/* we might have sessions queued on this server and waiting for
 		 * a connection. Those which are redispatchable will be queued
@@ -454,7 +455,7 @@
 					int xferred;
 
 					recount_servers(s->proxy);
-					recalc_server_map(s->proxy);
+					s->proxy->map_state |= PR_MAP_RECALC;
 
 					/* check if we can handle some connections queued at the proxy. We
 					 * will take as many as we can handle.
diff --git a/src/proto_http.c b/src/proto_http.c
index 9044d5d..f717bdf 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -3848,6 +3848,9 @@
 	case DATA_ST_PX_BE:
 		/* print the backend */
 		if (px->cap & PR_CAP_BE) {
+			if (px->map_state & PR_MAP_RECALC)
+				recalc_server_map(px);
+
 			chunk_printf(&msg, sizeof(trash),
 				     /* name */
 				     "<tr align=center class=\"backend\"><td>Backend</td>"