Re: [PATCHv8 6/9] receive-pack.c: add execute_commands_atomic function

2014-12-30 Thread Eric Sunshine
On Mon, Dec 29, 2014 at 9:36 PM, Stefan Beller sbel...@google.com wrote:
 Update receive-pack to use an atomic transaction iff the client negotiated
 that it wanted atomic push.

This first line seems germane to this patch...

 This leaves the default behavior to be the old
 non-atomic one ref at a time update. This is to cause as little disruption
 as possible to existing clients. It is unknown if there are client scripts
 that depend on the old non-atomic behavior so we make it opt-in for now.

 If it turns out over time that there are no client scripts that depend on the
 old behavior we can change git to default to use atomic pushes and instead
 offer an opt-out argument for people that do not want atomic pushes.

However, the remainder feels like it belongs with some other patch,
such as a patch which introduces an --atomic option.

 Inspired-by: Ronnie Sahlberg sahlb...@google.com
 Helped-by: Eric Sunshine sunsh...@sunshineco.com
 Signed-off-by: Stefan Beller sbel...@google.com
 ---
 diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
 index 5f44466..35a2264 100644
 --- a/builtin/receive-pack.c
 +++ b/builtin/receive-pack.c
 @@ -1076,8 +1076,8 @@ static void check_shallow_bugs(struct command *commands,
   the reported refs above);
  }

 -static void execute_commands_loop(struct command *commands,
 - struct shallow_info *si)
 +static void execute_commands_non_atomic(struct command *commands,
 +   struct shallow_info *si)

Style: Indent the wrapped line to align with the text following the
'(' in the first line.

  {
 struct command *cmd;
 struct strbuf err = STRBUF_INIT;
 @@ -1104,7 +1104,50 @@ static void execute_commands_loop(struct command 
 *commands,
 }
 ref_transaction_free(transaction);
 }
 +   strbuf_release(err);
 +}
 +
 +static void execute_commands_atomic(struct command *commands,
 +   struct shallow_info *si)

Style: Indentation.

 +{
 +   struct command *cmd;
 +   struct strbuf err = STRBUF_INIT;
 +   const char *reported_error = atomic push failure;
 +
 +   transaction = ref_transaction_begin(err);
 +   if (!transaction) {
 +   rp_error(%s, err.buf);
 +   strbuf_reset(err);
 +   reported_error = transaction failed to start;
 +   goto failure;
 +   }
 +
 +   for (cmd = commands; cmd; cmd = cmd-next) {
 +   if (!should_process_cmd(cmd))
 +   continue;

 +   cmd-error_string = update(cmd, si);
 +
 +   if (cmd-error_string)
 +   goto failure;
 +   }
 +
 +   if (ref_transaction_commit(transaction, err)) {
 +   rp_error(%s, err.buf);
 +   reported_error = atomic transaction failed;
 +   goto failure;
 +   }
 +
 +   ref_transaction_free(transaction);
 +   strbuf_release(err);
 +   return;

Minor comment: This cleanup code is repeated in both the success and
fail branches. It _might_ (or not) be a bit cleaner and more
maintainable to replace the above three lines with:

goto done;

 +
 +failure:
 +   for (cmd = commands; cmd; cmd = cmd-next)
 +   if (!cmd-error_string)
 +   cmd-error_string = reported_error;

And add a 'done' label here:

done:

 +   ref_transaction_free(transaction);
 strbuf_release(err);
  }

 @@ -1142,7 +1185,10 @@ static void execute_commands(struct command *commands,
 free(head_name_to_free);
 head_name = head_name_to_free = resolve_refdup(HEAD, 0, sha1, NULL);

 -   execute_commands_loop(commands, si);
 +   if (use_atomic)
 +   execute_commands_atomic(commands, si);
 +   else
 +   execute_commands_non_atomic(commands, si);

 check_shallow_bugs(commands, si);
  }
 --
 2.2.1.62.g3f15098
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv8 6/9] receive-pack.c: add execute_commands_atomic function

2014-12-29 Thread Stefan Beller
Update receive-pack to use an atomic transaction iff the client negotiated
that it wanted atomic push. This leaves the default behavior to be the old
non-atomic one ref at a time update. This is to cause as little disruption
as possible to existing clients. It is unknown if there are client scripts
that depend on the old non-atomic behavior so we make it opt-in for now.

If it turns out over time that there are no client scripts that depend on the
old behavior we can change git to default to use atomic pushes and instead
offer an opt-out argument for people that do not want atomic pushes.

Inspired-by: Ronnie Sahlberg sahlb...@google.com
Helped-by: Eric Sunshine sunsh...@sunshineco.com
Signed-off-by: Stefan Beller sbel...@google.com
---

Notes:
Changes in v8:
removed superflous } to make it compile again

Changes in v7:
Eric suggested to replace [PATCH 4/7] receive-pack.c:
receive-pack.c: use a single ref_transaction for atomic pushes
by smaller patches
This is the last patch replacing said large commit.

Changes in v6:
This is a complete rewrite of the patch essentially.
Eric suggested to split up the flow into functions, so
it is easier to read. It's more lines of code, but indeed
it's easier to follow. Thanks Eric!

Note there is another patch following this one
moving the helper functions above execute_commands.
I just choose the order of the functions in this patch
to have a better diff (just inserting the call to the function
execute_commands_non_atomic and that function directly follows.)
The next patch of the series will move that up.

Because of the rewrite and the fixes of the previous five
versions there is not much left of Ronnies original patch,
so I'll claim authorship of this one.

Changes v1 - v2:
* update(...) assumes to be always in a transaction
* Caring about when to begin/commit transactions is put
  into execute_commands
v2-v3:
* meditated about the error flow. Now we always construct a local
  strbuf err if required. Then the flow is easier to follow and
  destruction of it is performed nearby.
* early return in execute_commands if transaction_begin fails.

v3-v4:
* revamp logic again. This should keep the non atomic behavior
  as is (in case of error say so, in non error case just free the
  transaction). In the atomic case we either do nothing (when no error),
  or abort with the goto.

if (!cmd-error_string) {
if (!use_atomic
 ref_transaction_commit(transaction, err)) {
ref_transaction_free(transaction);
rp_error(%s, err.buf);
strbuf_release(err);
cmd-error_string = failed to update ref;
}
} else if (use_atomic) {
goto atomic_failure;
} else {
ref_transaction_free(transaction);
}

 * Having the goto directly there when checking for cmd-error_string,
   we don't need to do it again, so the paragraph explaining the error
   checking is gone as well. (Previous patch had the following, this is
   put at the end of the function, where the goto jumps to and the 
comment
   has been dropped.
+   /*
+* update(...) may abort early (i.e. because the hook refused to
+* update that ref) which then doesn't even record a transaction
+* regarding that ref. Make sure all commands are without error
+* and then commit atomically.
+*/
+   for (cmd = commands; cmd; cmd = cmd-next)
+   if (cmd-error_string)
+   break;

v4-v5:
Eric wrote:
 Repeating from my earlier review[1]: If the 'pre-receive' hook
 declines, then this transaction is left dangling (and its resources
 leaked).

You're right. The initialization of the transaction is now
near the actual loop after the pre receive hook.

 The !use_atomic case (below), calls this error failed to start
 transaction, not merely transaction error.

ok, now both are transaction failed to start.
In all cases where these generic errors are reported,
we do have a rp_error(...) with details.

 Furthermore, in the use_atomic case (also below), when a commit fails,
 you assign err.buf to cmd-error_string rather than a generic
 transaction error message. What differs between these cases which
 makes the generic message preferable here over the more specific
 err.buf message?

They are the