git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH v3] refs: implement reference transaction hook

From
Junio C Hamano <gitster@pobox.com>
Date
Jun 18, 2020, 22:23 UTC
Message-ID
<xmqqo8pgko8k.fsf@gitster.c.googlers.com>
In-Reply-To
<1de96b96e3448c8f7e7974f7c082fd08d2d14e96.1592475610.git.ps@pks.im>
Patrick Steinhardt <ps@pks.im> writes:
> +static const char hook_not_found;
> +static const char *hook;
;-)  Nice.
Show 33 quoted lines
> +static int run_transaction_hook(struct ref_transaction *transaction,
> +				const char *state)
> +{
> +	struct child_process proc = CHILD_PROCESS_INIT;
> +	struct strbuf buf = STRBUF_INIT;
> +	int saved_errno = 0, ret, i;
> +...
> +	ret = start_command(&proc);
> +	if (ret)
> +		return ret;
> +
> +	sigchain_push(SIGPIPE, SIG_IGN);
> +
> +	for (i = 0; i < transaction->nr; i++) {
> +		struct ref_update *update = transaction->updates[i];
> + ...
> +		if (write_in_full(proc.in, buf.buf, buf.len) < 0) {
> +			if (errno != EPIPE)
> +				saved_errno = errno;
> +			break;
> +		}
> +	}
> +
> +	close(proc.in);
> +	sigchain_pop(SIGPIPE);
> +	strbuf_release(&buf);
> +
> +	ret = finish_command(&proc);
> +	if (ret)
> +		return ret;
> +
> +	return saved_errno;
> +}

OK, the only thing that looked a bit tricky was the "saved_errno" that is used in an unusual (relative to its name) way. The use isn't incorrect per-se, but it rubs readers' expectation the wrong way to use the variable named saved_errno for any purpose other than the established pattern:

	saved_errno = errno;
	if (some_libcall_that_may_update_errno()) {
		... deal with an error and perform
		... some fallback action
	}
	errno = saved_errno;

that allows the caller to be oblivious to the library call that is made as a mere implementation detail whose failure does not matter to the caller.

In any case, the idea of the code in the patch is to make sure we remember the fact that we failed to write (or caught any other error, if we added more calls in the future) in a variable, and make sure we return an error even if we manage to cleanly call "finish_command()". For that purpose, in order to avoid overwriting the "ret" variable with the returned value from finish_command(), a separate variable is needed, and "saved_errno" was picked for the name of the variable.

But I do not think it is a good idea to return the errno in one codepath when the function can return an error status that is not an errno that is received from start_command() and finish_command(). The caller of this function cannot (and probably do not want to) tell what the failed syscall was and would be checking if the return value was success (=0) or failure (<0).

So I'd rather simplify the error handling to
 - Remove "saved_errno"; instead initialize ret to 0 at the beginning;
 - Return "ret" even if we return hardcoded 0 in the earlier part
   for consistency;
 - Update "ret" in the loop to -1 (the same error return status that
   is returned by start_command() and finish_command()) when we
   found a write error that we are not ignoring before breaking out
   of the loop.
 - We need to call finish_command() even if we earlier saw an error
   once we successfully called start_command().  So do something
   like this:
	ret |= finish_command(&proc);
	return ret;
   to make sure we retain an earlier error in "ret", we
   unconditionally call finish_command() when the control reaches
   there, and we mark the result a failure when finish_command()
   fails.
if I were writing this function.
Thanks.
Previous: Patrick SteinhardtNext: Patrick Steinhardt
Message 16 of 26 in “refs: implement reference transaction hooks”
  1. refs: implement reference transaction hooksPatrick Steinhardt, Jun 2, 2020
  2. Junio C HamanoJun 2, 2020
  3. Patrick SteinhardtJun 3, 2020
  4. SZEDER GáborJun 7, 2020
  5. Patrick SteinhardtJun 8, 2020
  6. SZEDER GáborJun 2, 2020
  7. Patrick SteinhardtJun 3, 2020
  8. refs: implement reference transaction hookPatrick Steinhardt, Jun 3, 2020
  9. Taylor BlauJun 3, 2020
  10. Patrick SteinhardtJun 4, 2020
  11. Taylor BlauJun 15, 2020
  12. Patrick SteinhardtJun 16, 2020
  13. Han-Wen NienhuysJun 3, 2020
  14. Junio C HamanoJun 3, 2020
  15. refs: implement reference transaction hookPatrick Steinhardt, Jun 18, 2020
  16. Junio C HamanoJun 18, 2020
  17. refs: implement reference transaction hookPatrick Steinhardt, Jun 19, 2020
  18. Jeff KingOct 23, 2020
  19. Junio C HamanoOct 23, 2020
  20. Taylor BlauOct 23, 2020
  21. Taylor BlauOct 23, 2020
  22. Patrick SteinhardtOct 26, 2020
  23. Taylor BlauOct 26, 2020
  24. Jeff KingOct 27, 2020
  25. Patrick SteinhardtOct 28, 2020
  26. Taylor BlauOct 23, 2020

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.