]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] improve behaviour with large number of servers per proxy
authorWilly Tarreau <w@1wt.eu>
Tue, 24 Jul 2007 21:32:33 +0000 (23:32 +0200)
committerWilly Tarreau <w@1wt.eu>
Sun, 9 Sep 2007 19:09:28 +0000 (21:09 +0200)
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.

include/proto/backend.h
include/types/proxy.h
src/backend.c
src/cfgparse.c
src/checks.c
src/proto_http.c

index f0295b0f5ecb61328b94aaf8be33e78622be3238..467e756806adf5d52a7df48d9e3cad4c1f4188bc 100644 (file)
@@ -52,6 +52,9 @@ static inline struct server *get_server_rr_with_conns(struct proxy *px)
        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_with_conns(struct proxy *px)
  */
 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 @@ static inline struct server *get_server_rr(struct proxy *px)
  * 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 @@ static inline struct server *get_server_uh(struct proxy *px, char *uri, int uri_
        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;
 
index 6d87f806da9cec24d0f86c61a84a9c3a76841a35..d205c42d029e184f2b986c357f6d53c6bc3c2b06 100644 (file)
@@ -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 proxy {
        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 */
index 8abaf1ca5e18ab32b961bec24c0882118e2017e7..da8b8ac36a92e0811d92124466300ee550f68bb2 100644 (file)
@@ -90,6 +90,7 @@ void recalc_server_map(struct proxy *px)
                        tot = 1; /* the first server is enough */
        } else {
                px->srv_map_sz = 0;
+               px->map_state &= ~PR_MAP_RECALC;
                return;
        }
 
@@ -130,6 +131,7 @@ void recalc_server_map(struct proxy *px)
                best->wscore -= tot;
        }
        px->srv_map_sz = tot;
+       px->map_state &= ~PR_MAP_RECALC;
 }
 
 
index 39abbc318adba2ef5f82b41ca0bc02b6fe3e73e5..967b9ca74d70b889d8ac4eba2d1cc20317dfb17b 100644 (file)
@@ -2637,6 +2637,7 @@ int readcfgfile(const char *file)
 
                        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);
                }
index 4c8a009718be2301cd47fb7fb0560c7609e3d21a..2c581ef1c8bf147171eb97532dbb23885f523edc 100644 (file)
@@ -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 @@ static void set_server_down(struct server *s)
 
        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 @@ void process_chk(struct task *t, struct timeval *next)
                                        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.
index 9044d5d0a2c263ad853ba2eb39ac2f42cec9e2e5..f717bdf32663dfc37aede62ae9efab5fd9e9db15 100644 (file)
@@ -3848,6 +3848,9 @@ int produce_content_stats_proxy(struct session *s, struct proxy *px)
        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>"