From 4c848659efdc93bc0de0c1c174bb25ff4f154c72 Mon Sep 17 00:00:00 2001
From: Joseph Lynch <joe.e.lynch@gmail.com>
Date: Thu, 26 Feb 2015 13:12:22 -0800
Subject: [PATCH] Allow redispatch on every request

For backend load balancing it sometimes makes sense to redispatch on
every request instead of retrying against the same server. For example,
when machines or routers fail you may not want to waste time retrying
against a dead server and would instead prefer to immediately redispatch
against other servers.

This patch allows backend sections to specify that they want to
redispatch on every retry instead of the default redispatch on last
retry behaviour. In low latency environments this can save a few hundred
milliseconds when backends fail.
---
 include/types/proxy.h | 3 ++-
 src/cfgparse.c        | 1 +
 src/session.c         | 5 +++--
 3 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/include/types/proxy.h b/include/types/proxy.h
index b33b634..d81ed33 100644
--- a/include/types/proxy.h
+++ b/include/types/proxy.h
@@ -77,7 +77,8 @@ enum pr_mode {
 /* bits for proxy->options */
 #define PR_O_REDISP     0x00000001      /* allow reconnection to dispatch in case of errors */
 #define PR_O_TRANSP     0x00000002      /* transparent mode : use original DEST as dispatch */
-/* unused: 0x04, 0x08, 0x10 */
+#define PR_O_ALLREDISP  0x00000004      /* redispatch on every retry */
+/* unused: 0x08, 0x10 */
 #define PR_O_PREF_LAST  0x00000020      /* prefer last server */
 #define PR_O_DISPATCH   0x00000040      /* use dispatch mode */
 /* unused: 0x00000080 */
diff --git a/src/cfgparse.c b/src/cfgparse.c
index a91e027..2790689 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -156,6 +156,7 @@ static const struct cfg_opt cfg_opts[] =
 	{ "nolinger",     PR_O_TCP_NOLING, PR_CAP_FE | PR_CAP_BE, 0, 0 },
 	{ "persist",      PR_O_PERSIST,    PR_CAP_BE, 0, 0 },
 	{ "redispatch",   PR_O_REDISP,     PR_CAP_BE, 0, 0 },
+	{ "allredisp",    PR_O_ALLREDISP,  PR_CAP_BE, 0, 0 },
 	{ "srvtcpka",     PR_O_TCP_SRV_KA, PR_CAP_BE, 0, 0 },
 #ifdef TPROXY
 	{ "transparent",  PR_O_TRANSP,     PR_CAP_BE, 0, 0 },
diff --git a/src/session.c b/src/session.c
index 5b9e407..5e4351c 100644
--- a/src/session.c
+++ b/src/session.c
@@ -876,7 +876,8 @@ static int sess_update_st_cer(struct session *s, struct stream_interface *si)
 	}
 
 	/* If the "redispatch" option is set on the backend, we are allowed to
-	 * retry on another server for the last retry. In order to achieve this,
+	 * retry on another server. We either redispatch on the last retry or
+	 * on every retry if the "allredisp" option is set. To achieve this,
 	 * we must mark the session unassigned, and eventually clear the DIRECT
 	 * bit to ignore any persistence cookie. We won't count a retry nor a
 	 * redispatch yet, because this will depend on what server is selected.
@@ -886,7 +887,7 @@ static int sess_update_st_cer(struct session *s, struct stream_interface *si)
 	 * we don't care about this particular server.
 	 */
 	if (objt_server(s->target) &&
-	    (si->conn_retries == 0 ||
+	    (s->be->options & PR_O_ALLREDISP || si->conn_retries == 0 ||
 	     (!(s->flags & SN_DIRECT) && s->be->srv_act > 1 &&
 	      ((s->be->lbprm.algo & BE_LB_KIND) == BE_LB_KIND_RR))) &&
 	    s->be->options & PR_O_REDISP && !(s->flags & SN_FORCE_PRST)) {
-- 
2.2.1

