Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/815894/?format=api
{ "id": 815894, "url": "http://patchwork.ozlabs.org/api/patches/815894/?format=api", "web_url": "http://patchwork.ozlabs.org/project/openvswitch/patch/20170919220125.32535-42-blp@ovn.org/", "project": { "id": 47, "url": "http://patchwork.ozlabs.org/api/projects/47/?format=api", "name": "Open vSwitch", "link_name": "openvswitch", "list_id": "ovs-dev.openvswitch.org", "list_email": "ovs-dev@openvswitch.org", "web_url": "http://openvswitch.org/", "scm_url": "git@github.com:openvswitch/ovs.git", "webscm_url": "https://github.com/openvswitch/ovs", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20170919220125.32535-42-blp@ovn.org>", "list_archive_url": null, "date": "2017-09-19T22:01:14", "name": "[ovs-dev,RFC,41/52] reconnect: Add ability to do a number of retries without backoff.", "commit_ref": null, "pull_url": null, "state": "rfc", "archived": false, "hash": "e00caeee201252cbe0aa0bb6e32cee819a6796c6", "submitter": { "id": 67603, "url": "http://patchwork.ozlabs.org/api/people/67603/?format=api", "name": "Ben Pfaff", "email": "blp@ovn.org" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/openvswitch/patch/20170919220125.32535-42-blp@ovn.org/mbox/", "series": [ { "id": 3975, "url": "http://patchwork.ozlabs.org/api/series/3975/?format=api", "web_url": "http://patchwork.ozlabs.org/project/openvswitch/list/?series=3975", "date": "2017-09-19T22:00:34", "name": "clustering implementation", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/3975/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/815894/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/815894/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<ovs-dev-bounces@openvswitch.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "dev@openvswitch.org" ], "Delivered-To": [ "patchwork-incoming@bilbo.ozlabs.org", "ovs-dev@mail.linuxfoundation.org" ], "Authentication-Results": "ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=openvswitch.org\n\t(client-ip=140.211.169.12; helo=mail.linuxfoundation.org;\n\tenvelope-from=ovs-dev-bounces@openvswitch.org;\n\treceiver=<UNKNOWN>)", "Received": [ "from mail.linuxfoundation.org (mail.linuxfoundation.org\n\t[140.211.169.12])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xxcks3pdZz9sBW\n\tfor <incoming@patchwork.ozlabs.org>;\n\tWed, 20 Sep 2017 08:20:21 +1000 (AEST)", "from mail.linux-foundation.org (localhost [127.0.0.1])\n\tby mail.linuxfoundation.org (Postfix) with ESMTP id E70ABD07;\n\tTue, 19 Sep 2017 22:02:44 +0000 (UTC)", "from smtp1.linuxfoundation.org (smtp1.linux-foundation.org\n\t[172.17.192.35])\n\tby mail.linuxfoundation.org (Postfix) with ESMTPS id 00309D05\n\tfor <dev@openvswitch.org>; Tue, 19 Sep 2017 22:02:42 +0000 (UTC)", "from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net\n\t[217.70.183.196])\n\tby smtp1.linuxfoundation.org (Postfix) with ESMTPS id D796220D\n\tfor <dev@openvswitch.org>; Tue, 19 Sep 2017 22:02:40 +0000 (UTC)", "from sigabrt.benpfaff.org (unknown [208.91.2.3])\n\t(Authenticated sender: blp@ovn.org)\n\tby relay4-d.mail.gandi.net (Postfix) with ESMTPSA id AC7A1172094;\n\tWed, 20 Sep 2017 00:02:38 +0200 (CEST)" ], "X-Greylist": "domain auto-whitelisted by SQLgrey-1.7.6", "X-Originating-IP": "208.91.2.3", "From": "Ben Pfaff <blp@ovn.org>", "To": "dev@openvswitch.org", "Date": "Tue, 19 Sep 2017 15:01:14 -0700", "Message-Id": "<20170919220125.32535-42-blp@ovn.org>", "X-Mailer": "git-send-email 2.10.2", "In-Reply-To": "<20170919220125.32535-1-blp@ovn.org>", "References": "<20170919220125.32535-1-blp@ovn.org>", "X-Spam-Status": "No, score=-0.7 required=5.0 tests=RCVD_IN_DNSWL_LOW\n\tautolearn=disabled version=3.3.1", "X-Spam-Checker-Version": "SpamAssassin 3.3.1 (2010-03-16) on\n\tsmtp1.linux-foundation.org", "Cc": "Ben Pfaff <blp@ovn.org>", "Subject": "[ovs-dev] [PATCH RFC 41/52] reconnect: Add ability to do a number\n\tof retries without backoff.", "X-BeenThere": "ovs-dev@openvswitch.org", "X-Mailman-Version": "2.1.12", "Precedence": "list", "List-Id": "<ovs-dev.openvswitch.org>", "List-Unsubscribe": "<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>", "List-Archive": "<http://mail.openvswitch.org/pipermail/ovs-dev/>", "List-Post": "<mailto:ovs-dev@openvswitch.org>", "List-Help": "<mailto:ovs-dev-request@openvswitch.org?subject=help>", "List-Subscribe": "<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=subscribe>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=\"us-ascii\"", "Content-Transfer-Encoding": "7bit", "Sender": "ovs-dev-bounces@openvswitch.org", "Errors-To": "ovs-dev-bounces@openvswitch.org" }, "content": "This is aimed at an upcoming database clustering implementation, where it's\ndesirable to try all of the cluster members quickly before backing off to\nretry them again in sequence.\n\nSigned-off-by: Ben Pfaff <blp@ovn.org>\n---\n lib/reconnect.c | 52 ++++++++++++++++++++++++++++++---------------\n lib/reconnect.h | 3 +++\n python/ovs/reconnect.py | 53 ++++++++++++++++++++++++++++++----------------\n tests/reconnect.at | 56 ++++++++++++++++++++++++++++++++++++++++++++++++-\n tests/test-reconnect.c | 8 +++++++\n tests/test-reconnect.py | 5 +++++\n 6 files changed, 141 insertions(+), 36 deletions(-)", "diff": "diff --git a/lib/reconnect.c b/lib/reconnect.c\nindex 471fb7fc8d61..f91b4c09ae5d 100644\n--- a/lib/reconnect.c\n+++ b/lib/reconnect.c\n@@ -62,6 +62,7 @@ struct reconnect {\n long long int last_connected;\n long long int last_disconnected;\n unsigned int max_tries;\n+ unsigned int backoff_free_tries;\n \n /* These values are simply for statistics reporting, not otherwise used\n * directly by anything internal. */\n@@ -206,6 +207,15 @@ reconnect_get_max_tries(struct reconnect *fsm)\n return fsm->max_tries;\n }\n \n+/* Sets the number of connection attempts that will be made without backoff to\n+ * 'backoff_free_tries'. Values 0 and 1 both represent a single attempt. */\n+void\n+reconnect_set_backoff_free_tries(struct reconnect *fsm,\n+ unsigned int backoff_free_tries)\n+{\n+ fsm->backoff_free_tries = backoff_free_tries;\n+}\n+\n /* Configures the backoff parameters for 'fsm'. 'min_backoff' is the minimum\n * number of milliseconds, and 'max_backoff' is the maximum, between connection\n * attempts. The current backoff is also the duration that 'fsm' is willing to\n@@ -346,7 +356,7 @@ reconnect_disconnected(struct reconnect *fsm, long long int now, int error)\n VLOG(fsm->info, \"%s: error listening for connections\",\n fsm->name);\n }\n- } else {\n+ } else if (fsm->backoff < fsm->max_backoff) {\n const char *type = fsm->passive ? \"listen\" : \"connection\";\n if (error > 0) {\n VLOG_INFO(\"%s: %s attempt failed (%s)\",\n@@ -359,30 +369,38 @@ reconnect_disconnected(struct reconnect *fsm, long long int now, int error)\n if (fsm->state & (S_ACTIVE | S_IDLE)) {\n fsm->last_disconnected = now;\n }\n+\n+ if (!reconnect_may_retry(fsm)) {\n+ reconnect_transition__(fsm, now, S_VOID);\n+ return;\n+ }\n+\n /* Back off. */\n- if (fsm->state & (S_ACTIVE | S_IDLE)\n- && (fsm->last_activity - fsm->last_connected >= fsm->backoff\n- || fsm->passive)) {\n+ if (fsm->backoff_free_tries > 1) {\n+ fsm->backoff_free_tries--;\n+ fsm->backoff = 0;\n+ } else if (fsm->state & (S_ACTIVE | S_IDLE)\n+ && (fsm->last_activity - fsm->last_connected >= fsm->backoff\n+ || fsm->passive)) {\n fsm->backoff = fsm->passive ? 0 : fsm->min_backoff;\n } else {\n if (fsm->backoff < fsm->min_backoff) {\n fsm->backoff = fsm->min_backoff;\n- } else if (fsm->backoff >= fsm->max_backoff / 2) {\n- fsm->backoff = fsm->max_backoff;\n- } else {\n+ } else if (fsm->backoff < fsm->max_backoff / 2) {\n fsm->backoff *= 2;\n- }\n- if (fsm->passive) {\n- VLOG(fsm->info, \"%s: waiting %.3g seconds before trying to \"\n- \"listen again\", fsm->name, fsm->backoff / 1000.0);\n+ VLOG(fsm->info, \"%s: waiting %.3g seconds before %s\",\n+ fsm->name, fsm->backoff / 1000.0,\n+ fsm->passive ? \"trying to listen again\" : \"reconnect\");\n } else {\n- VLOG(fsm->info, \"%s: waiting %.3g seconds before reconnect\",\n- fsm->name, fsm->backoff / 1000.0);\n+ if (fsm->backoff < fsm->max_backoff) {\n+ VLOG_INFO(\"%s: continuing to %s in the background but \"\n+ \"suppressing further logging\", fsm->name,\n+ fsm->passive ? \"try to listen\" : \"reconnect\");\n+ }\n+ fsm->backoff = fsm->max_backoff;\n }\n }\n-\n- reconnect_transition__(fsm, now,\n- reconnect_may_retry(fsm) ? S_BACKOFF : S_VOID);\n+ reconnect_transition__(fsm, now, S_BACKOFF);\n }\n }\n \n@@ -397,7 +415,7 @@ reconnect_connecting(struct reconnect *fsm, long long int now)\n if (fsm->state != S_CONNECTING) {\n if (fsm->passive) {\n VLOG(fsm->info, \"%s: listening...\", fsm->name);\n- } else {\n+ } else if (fsm->backoff < fsm->max_backoff) {\n VLOG(fsm->info, \"%s: connecting...\", fsm->name);\n }\n reconnect_transition__(fsm, now, S_CONNECTING);\ndiff --git a/lib/reconnect.h b/lib/reconnect.h\nindex 4446713ce873..9f2d469e2ddd 100644\n--- a/lib/reconnect.h\n+++ b/lib/reconnect.h\n@@ -51,6 +51,8 @@ int reconnect_get_probe_interval(const struct reconnect *);\n \n void reconnect_set_max_tries(struct reconnect *, unsigned int max_tries);\n unsigned int reconnect_get_max_tries(struct reconnect *);\n+void reconnect_set_backoff_free_tries(struct reconnect *,\n+ unsigned int backoff_free_tries);\n \n void reconnect_set_backoff(struct reconnect *,\n int min_backoff, int max_backoff);\n@@ -65,6 +67,7 @@ void reconnect_enable(struct reconnect *, long long int now);\n void reconnect_disable(struct reconnect *, long long int now);\n \n void reconnect_force_reconnect(struct reconnect *, long long int now);\n+void reconnect_skip_backoff(struct reconnect *);\n \n bool reconnect_is_connected(const struct reconnect *);\n unsigned int reconnect_get_last_connect_elapsed(const struct reconnect *,\ndiff --git a/python/ovs/reconnect.py b/python/ovs/reconnect.py\nindex ec52ebb7affc..34cc76987031 100644\n--- a/python/ovs/reconnect.py\n+++ b/python/ovs/reconnect.py\n@@ -154,6 +154,7 @@ class Reconnect(object):\n self.last_connected = None\n self.last_disconnected = None\n self.max_tries = None\n+ self.backoff_free_tries = 0\n \n self.creation_time = now\n self.n_attempted_connections = 0\n@@ -242,6 +243,12 @@ class Reconnect(object):\n self.backoff > self.max_backoff):\n self.backoff = self.max_backoff\n \n+ def set_backoff_free_tries(self, backoff_free_tries):\n+ \"\"\"Sets the number of connection attempts that will be made without\n+ backoff to 'backoff_free_tries'. Values 0 and 1 both\n+ represent a single attempt.\"\"\"\n+ self.backoff_free_tries = backoff_free_tries\n+\n def set_probe_interval(self, probe_interval):\n \"\"\"Sets the \"probe interval\" to 'probe_interval', in milliseconds. If\n this is zero, it disables the connection keepalive feature. If it is\n@@ -337,7 +344,7 @@ class Reconnect(object):\n else:\n self.info_level(\"%s: error listening for connections\"\n % self.name)\n- else:\n+ elif self.backoff < self.max_backoff:\n if self.passive:\n type_ = \"listen\"\n else:\n@@ -352,8 +359,15 @@ class Reconnect(object):\n if (self.state in (Reconnect.Active, Reconnect.Idle)):\n self.last_disconnected = now\n \n+ if not self.__may_retry():\n+ self._transition(now, Reconnect.Void)\n+ return\n+\n # Back off\n- if (self.state in (Reconnect.Active, Reconnect.Idle) and\n+ if self.backoff_free_tries > 1:\n+ self.backoff_free_tries -= 1\n+ self.backoff = 0\n+ elif (self.state in (Reconnect.Active, Reconnect.Idle) and\n (self.last_activity - self.last_connected >= self.backoff or\n self.passive)):\n if self.passive:\n@@ -363,23 +377,26 @@ class Reconnect(object):\n else:\n if self.backoff < self.min_backoff:\n self.backoff = self.min_backoff\n- elif self.backoff >= self.max_backoff / 2:\n- self.backoff = self.max_backoff\n- else:\n+ elif self.backoff < self.max_backoff / 2:\n self.backoff *= 2\n-\n- if self.passive:\n- self.info_level(\"%s: waiting %.3g seconds before trying \"\n- \"to listen again\"\n- % (self.name, self.backoff / 1000.0))\n+ if self.passive:\n+ action = \"trying to listen again\"\n+ else:\n+ action = \"reconnect\"\n+ self.info_level(\"%s: waiting %.3g seconds before %s\"\n+ % (self.name, self.backoff / 1000.0,\n+ action))\n else:\n- self.info_level(\"%s: waiting %.3g seconds before reconnect\"\n- % (self.name, self.backoff / 1000.0))\n-\n- if self.__may_retry():\n- self._transition(now, Reconnect.Backoff)\n- else:\n- self._transition(now, Reconnect.Void)\n+ if self.backoff < self.max_backoff:\n+ if self.passive:\n+ action = \"try to listen\"\n+ else:\n+ action = \"reconnect\"\n+ self.info_level(\"%s: continuing to %s in the \"\n+ \"background but suppressing further \"\n+ \"logging\" % (self.name, action))\n+ self.backoff = self.max_backoff\n+ self._transition(now, Reconnect.Backoff)\n \n def connecting(self, now):\n \"\"\"Tell this FSM that a connection or listening attempt is in progress.\n@@ -390,7 +407,7 @@ class Reconnect(object):\n if self.state != Reconnect.ConnectInProgress:\n if self.passive:\n self.info_level(\"%s: listening...\" % self.name)\n- else:\n+ elif self.backoff < self.max_backoff:\n self.info_level(\"%s: connecting...\" % self.name)\n self._transition(now, Reconnect.ConnectInProgress)\n \ndiff --git a/tests/reconnect.at b/tests/reconnect.at\nindex c88ca785cad2..59c95d95bdd3 100644\n--- a/tests/reconnect.at\n+++ b/tests/reconnect.at\n@@ -1037,6 +1037,60 @@ timeout\n ])\n \n ######################################################################\n+RECONNECT_CHECK([backoff-free tries work],\n+ [set-backoff-free-tries 2\n+enable\n+\n+# Connection fails quickly.\n+run\n+connect-failed ECONNREFUSED\n+\n+# No backoff.\n+run\n+timeout\n+\n+# Connection fails quickly again.\n+run\n+connect-failed ECONNREFUSED\n+\n+# Back off for 1000 ms.\n+run\n+timeout\n+],\n+ [### t=1000 ###\n+set-backoff-free-tries 2\n+enable\n+ in BACKOFF for 0 ms (0 ms backoff)\n+\n+# Connection fails quickly.\n+run\n+ should connect\n+connect-failed ECONNREFUSED\n+ 0 successful connections out of 1 attempts, seqno 0\n+\n+# No backoff.\n+run\n+ should connect\n+timeout\n+ advance 0 ms\n+\n+# Connection fails quickly again.\n+run\n+ should connect\n+connect-failed ECONNREFUSED\n+ in BACKOFF for 0 ms (1000 ms backoff)\n+ 0 successful connections out of 2 attempts, seqno 0\n+\n+# Back off for 1000 ms.\n+run\n+timeout\n+ advance 1000 ms\n+\n+### t=2000 ###\n+ in BACKOFF for 1000 ms (1000 ms backoff)\n+])\n+\n+######################################################################\n RECONNECT_CHECK([max-tries of 1 honored],\n [set-max-tries 1\n enable\n@@ -1090,7 +1144,7 @@ timeout\n run\n should disconnect\n disconnected\n- in VOID for 0 ms (1000 ms backoff)\n+ in VOID for 0 ms (0 ms backoff)\n 1 successful connections out of 1 attempts, seqno 2\n disconnected\n disconnected at 11000 ms (0 ms ago)\ndiff --git a/tests/test-reconnect.c b/tests/test-reconnect.c\nindex 72252b8f707b..5a14e7fe58da 100644\n--- a/tests/test-reconnect.c\n+++ b/tests/test-reconnect.c\n@@ -208,6 +208,12 @@ do_set_max_tries(struct ovs_cmdl_context *ctx)\n }\n \n static void\n+do_set_backoff_free_tries(struct ovs_cmdl_context *ctx)\n+{\n+ reconnect_set_backoff_free_tries(reconnect, atoi(ctx->argv[1]));\n+}\n+\n+static void\n diff_stats(const struct reconnect_stats *old,\n const struct reconnect_stats *new,\n int delta)\n@@ -284,6 +290,8 @@ static const struct ovs_cmdl_command all_commands[] = {\n { \"advance\", NULL, 1, 1, do_advance, OVS_RO },\n { \"timeout\", NULL, 0, 0, do_timeout, OVS_RO },\n { \"set-max-tries\", NULL, 1, 1, do_set_max_tries, OVS_RO },\n+ { \"set-backoff-free-tries\", NULL, 1, 1, do_set_backoff_free_tries,\n+ OVS_RO },\n { \"passive\", NULL, 0, 0, do_set_passive, OVS_RO },\n { \"listening\", NULL, 0, 0, do_listening, OVS_RO },\n { \"listen-error\", NULL, 1, 1, do_listen_error, OVS_RO },\ndiff --git a/tests/test-reconnect.py b/tests/test-reconnect.py\nindex 8132fd9258ef..6cd052878eb1 100644\n--- a/tests/test-reconnect.py\n+++ b/tests/test-reconnect.py\n@@ -104,6 +104,10 @@ def do_set_max_tries(arg):\n r.set_max_tries(int(arg))\n \n \n+def do_set_backoff_free_tries(arg):\n+ r.set_backoff_free_tries(int(arg))\n+\n+\n def diff_stats(old, new, delta):\n if (old.state != new.state or\n old.state_elapsed != new.state_elapsed or\n@@ -173,6 +177,7 @@ def main():\n \"advance\": do_advance,\n \"timeout\": do_timeout,\n \"set-max-tries\": do_set_max_tries,\n+ \"set-backoff-free-tries\": do_set_backoff_free_tries,\n \"passive\": do_set_passive,\n \"listening\": do_listening,\n \"listen-error\": do_listen_error\n", "prefixes": [ "ovs-dev", "RFC", "41/52" ] }