chgserver: add an explicit "reconnect" instruction to validate
authorJun Wu <quark@fb.com>
Mon, 14 Mar 2016 13:48:33 +0000
changeset 28535 aa082a8125da
parent 28534 293adbaa14a7
child 28536 a979f5b03320
chgserver: add an explicit "reconnect" instruction to validate In some rare cases (next patch), we may want validate to do "unlink" without forcing the client reconnect. This patch addes a new "reconnect" instruction and makes "unlink" not to reconnect by default.
contrib/chg/chg.c
contrib/chg/hgclient.c
hgext/chgserver.py
--- a/contrib/chg/chg.c	Mon Mar 14 11:06:34 2016 +0000
+++ b/contrib/chg/chg.c	Mon Mar 14 13:48:33 2016 +0000
@@ -444,9 +444,14 @@
 	abortmsg("failed to prepare pager (errno = %d)", errno);
 }
 
-/* Run instructions sent from the server like unlink and set redirect path */
-static void runinstructions(struct cmdserveropts *opts, const char **insts)
+/* Run instructions sent from the server like unlink and set redirect path
+ * Return 1 if reconnect is needed, otherwise 0 */
+static int runinstructions(struct cmdserveropts *opts, const char **insts)
 {
+	int needreconnect = 0;
+	if (!insts)
+		return needreconnect;
+
 	assert(insts);
 	opts->redirectsockname[0] = '\0';
 	const char **pinst;
@@ -460,15 +465,19 @@
 					 "%s", *pinst + 9);
 			if (r < 0 || r >= (int)sizeof(opts->redirectsockname))
 				abortmsg("redirect path is too long (%d)", r);
+			needreconnect = 1;
 		} else if (strncmp(*pinst, "exit ", 5) == 0) {
 			int n = 0;
 			if (sscanf(*pinst + 5, "%d", &n) != 1)
 				abortmsg("cannot read the exit code");
 			exit(n);
+		} else if (strcmp(*pinst, "reconnect") == 0) {
+			needreconnect = 1;
 		} else {
 			abortmsg("unknown instruction: %s", *pinst);
 		}
 	}
+	return needreconnect;
 }
 
 /*
@@ -542,10 +551,10 @@
 			abortmsg("cannot open hg client");
 		hgc_setenv(hgc, envp);
 		const char **insts = hgc_validate(hgc, argv + 1, argc - 1);
-		if (insts == NULL)
+		int needreconnect = runinstructions(&opts, insts);
+		free(insts);
+		if (!needreconnect)
 			break;
-		runinstructions(&opts, insts);
-		free(insts);
 		hgc_close(hgc);
 		if (++retry > 10)
 			abortmsg("too many redirections.\n"
--- a/contrib/chg/hgclient.c	Mon Mar 14 11:06:34 2016 +0000
+++ b/contrib/chg/hgclient.c	Mon Mar 14 13:48:33 2016 +0000
@@ -478,8 +478,8 @@
  *
  * @return - NULL, the server believes it can handle our request, or does not
  *           support "validate" command.
- *         - a list of strings, the server cannot handle our request and it
- *           sent instructions telling us how to fix the issue. See
+ *         - a list of strings, the server probably cannot handle our request
+ *           and it sent instructions telling us what to do next. See
  *           chgserver.py for possible instruction formats.
  *           the list should be freed by the caller.
  *           the last string is guaranteed to be NULL.
--- a/hgext/chgserver.py	Mon Mar 14 11:06:34 2016 +0000
+++ b/hgext/chgserver.py	Mon Mar 14 13:48:33 2016 +0000
@@ -427,10 +427,16 @@
         An instruction string could be either:
             - "unlink $path", the client should unlink the path to stop the
               outdated server.
-            - "redirect $path", the client should try to connect to another
-              server instead.
+            - "redirect $path", the client should attempt to connect to $path
+              first. If it does not work, start a new server. It implies
+              "reconnect".
             - "exit $n", the client should exit directly with code n.
               This may happen if we cannot parse the config.
+            - "reconnect", the client should close the connection and
+              reconnect.
+        If neither "reconnect" nor "redirect" is included in the instruction
+        list, the client can continue with this server after completing all
+        the instructions.
         """
         args = self._readlist()
         try:
@@ -445,6 +451,7 @@
         if newhash.mtimehash != self.hashstate.mtimehash:
             addr = _hashaddress(self.baseaddress, self.hashstate.confighash)
             insts.append('unlink %s' % addr)
+            insts.append('reconnect')
         if newhash.confighash != self.hashstate.confighash:
             addr = _hashaddress(self.baseaddress, newhash.confighash)
             insts.append('redirect %s' % addr)