This patch implements the "leastconn" load balancing algorithm.
It was sent to me by Oleksandr Krailo. I've not tried it yet, but
it looks correct. However, I will change it before merging it, so
that it still implements round robin among servers with equal
numbers of connections, otherwise the first servers declared will
get all the traffic.


--- haproxy-1.2.14.orig/haproxy.c
+++ haproxy-1.2.14/haproxy.c
@@ -378,8 +378,9 @@
 #define PR_O_USE_ALL_BK	0x00100000	/* load-balance between backup servers */
 #define PR_O_FORCE_CLO	0x00200000	/* enforce the connection close immediately after server response */
 #define PR_O_BALANCE_SH	0x00400000	/* balance on source IP hash */
-#define PR_O_BALANCE	(PR_O_BALANCE_RR | PR_O_BALANCE_SH)
 #define PR_O_ABRT_CLOSE	0x00800000	/* immediately abort request when client closes */
+#define PR_O_BALANCE_LC	0x01000000	/* balance on least connection (fewer active jobs) server */
+#define PR_O_BALANCE	(PR_O_BALANCE_RR | PR_O_BALANCE_SH | PR_O_BALANCE_LC)
 
 /* various session flags, bits values 0x01 to 0x20 (shift 0) */
 #define SN_DIRECT	0x00000001	/* connection made on the server matching the client cookie */
@@ -2221,6 +2222,34 @@
 
 
 /*
+ * This function tries to find a running server for the proxy <px> following
+ * the least load method. If no valid server is found, NULL is returned.
+ */
+static inline struct server *get_server_lc(struct proxy *px) {
+    int s, i;
+    struct server *srv, *t;
+
+    if (px->srv_map_sz == 0)
+	return NULL;
+
+    i = 0;
+    t = NULL;
+    s = 0;
+
+    while (i < px->srv_map_sz) {
+	srv = px->srv_map[i++];
+	if (!srv->maxconn || srv->cur_sess < srv_dynamic_maxconn(srv)) {
+	    if (s > srv->cur_sess || t == NULL) {
+		t = srv;
+		s = srv->cur_sess;
+	    }
+	}
+    }
+    return t;
+}
+
+
+/*
  * This function marks the session as 'assigned' in direct or dispatch modes,
  * or tries to assign one in balance mode, according to the algorithm. It does
  * nothing if the session had already been assigned a server.
@@ -2270,6 +2299,11 @@
 				       (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
 				       len);
 	    }
+	    else if (s->proxy->options & PR_O_BALANCE_LC) {
+		s->srv = get_server_lc(s->proxy);
+		if (!s->srv)
+		    return SRV_STATUS_FULL;
+	    }
 	    else /* unknown balancing algorithm */
 		return SRV_STATUS_INTERNAL;
 	}
@@ -8461,8 +8495,11 @@
 	    else if (!strcmp(args[1], "source")) {
 		curproxy->options |= PR_O_BALANCE_SH;
 	    }
+	    else if (!strcmp(args[1], "leastconn")) {
+		curproxy->options |= PR_O_BALANCE_LC;
+	    }
 	    else {
-		Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
+		Alert("parsing [%s:%d] : '%s' only supports 'roundrobin', 'source' and 'leastconn' options.\n", file, linenum, args[0]);
 		return -1;
 	    }
 	}


syntax highlighted by Code2HTML, v. 0.9.1