diff mbox series

[v2,2/4] fetch: refactor `s_update_ref` to use common exit path

Message ID 718a8bf5d7a0ed92c3004991a42419279ff38253.1610107599.git.ps@pks.im (mailing list archive)
State Superseded
Headers show
Series fetch: implement support for atomic reference updates | expand

Commit Message

Patrick Steinhardt Jan. 8, 2021, 12:11 p.m. UTC
The cleanup code in `s_update_ref()` is currently duplicated for both
succesful and erroneous exit paths. This commit refactors the function
to have a shared exit path for both cases to remove the duplication.

Suggested-by: Christian Couder <christian.couder@gmail.com>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/fetch.c | 37 ++++++++++++++++++++-----------------
 1 file changed, 20 insertions(+), 17 deletions(-)

Comments

Junio C Hamano Jan. 8, 2021, 11:50 p.m. UTC | #1
Patrick Steinhardt <ps@pks.im> writes:

> @@ -598,30 +598,33 @@ static int s_update_ref(const char *action,
>  	msg = xstrfmt("%s: %s", rla, action);
>  
>  	transaction = ref_transaction_begin(&err);
> -	if (!transaction ||
> -	    ref_transaction_update(transaction, ref->name,
> -				   &ref->new_oid,
> -				   check_old ? &ref->old_oid : NULL,
> -				   0, msg, &err))
> -		goto fail;
> +	if (!transaction) {
> +		ret = STORE_REF_ERROR_OTHER;
> +		goto out;
> +	}
> +
> +	ret = ref_transaction_update(transaction, ref->name, &ref->new_oid,
> +				     check_old ? &ref->old_oid : NULL,
> +				     0, msg, &err);
> +	if (ret) {
> +		ret = STORE_REF_ERROR_OTHER;
> +		goto out;
> +	}

The above certainly got cleaner thanks to Christian's suggestion,
but I wonder why

	transaction = ref_transaction_begin(&err);
	if (!transaction ||
	    ref_transaction_update(transaction, ref->name,
				   &ref->new_oid,
				   check_old ? &ref->old_oid : NULL,
				   0, msg, &err)) {
		ret = STORE_REF_ERROR_OTHER;
		goto out;
	}

shouldn't be sufficient.

>  	ret = ref_transaction_commit(transaction, &err);
>  	if (ret) {
> -		df_conflict = (ret == TRANSACTION_NAME_CONFLICT);
> -		goto fail;
> +		ret = (ret == TRANSACTION_NAME_CONFLICT) ? STORE_REF_ERROR_DF_CONFLICT
> +							 : STORE_REF_ERROR_OTHER;
> +		goto out;
>  	}
> 
> +out:
>  	ref_transaction_free(transaction);

It is a bit funny to see a goto that jumps to the label without
having anything else in between, but we know we will be adding more
code just before the "out:" label, so it is a good preliminary
preparation.

I think a variant that is much easier to follow would be to write
like this instead:

	switch (ref_transaction_commit(transaction, &err)) {
        case 0: /* happy */
		break;
	case TRANSACTION_NAME_CONFLICT:
		ret = STORE_REF_ERROR_DF_CONFLICT;
		goto out;
	default:
		ret = STORE_REF_ERROR_OTHER;
		goto out;
	}

> +	if (ret)
> +		error("%s", err.buf);

OK.

>  	strbuf_release(&err);
>  	free(msg);
> -	return 0;
> -fail:
> -	ref_transaction_free(transaction);
> -	error("%s", err.buf);
> -	strbuf_release(&err);
> -	free(msg);
> -	return df_conflict ? STORE_REF_ERROR_DF_CONFLICT
> -			   : STORE_REF_ERROR_OTHER;
> +	return ret;
>  }
>  
>  static int refcol_width = 10;

THanks.
Patrick Steinhardt Jan. 11, 2021, 10:28 a.m. UTC | #2
On Fri, Jan 08, 2021 at 03:50:00PM -0800, Junio C Hamano wrote:
> Patrick Steinhardt <ps@pks.im> writes:
[snip]
> >  	ret = ref_transaction_commit(transaction, &err);
> >  	if (ret) {
> > -		df_conflict = (ret == TRANSACTION_NAME_CONFLICT);
> > -		goto fail;
> > +		ret = (ret == TRANSACTION_NAME_CONFLICT) ? STORE_REF_ERROR_DF_CONFLICT
> > +							 : STORE_REF_ERROR_OTHER;
> > +		goto out;
> >  	}
> > 
> > +out:
> >  	ref_transaction_free(transaction);
> 
> It is a bit funny to see a goto that jumps to the label without
> having anything else in between, but we know we will be adding more
> code just before the "out:" label, so it is a good preliminary
> preparation.
> 
> I think a variant that is much easier to follow would be to write
> like this instead:
> 
> 	switch (ref_transaction_commit(transaction, &err)) {
>         case 0: /* happy */
> 		break;
> 	case TRANSACTION_NAME_CONFLICT:
> 		ret = STORE_REF_ERROR_DF_CONFLICT;
> 		goto out;
> 	default:
> 		ret = STORE_REF_ERROR_OTHER;
> 		goto out;
> 	}

Agreed, that is easier to read. Thanks!

Patrick
diff mbox series

Patch

diff --git a/builtin/fetch.c b/builtin/fetch.c
index 557ec130db..5221a9dbed 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -589,7 +589,7 @@  static int s_update_ref(const char *action,
 	char *rla = getenv("GIT_REFLOG_ACTION");
 	struct ref_transaction *transaction;
 	struct strbuf err = STRBUF_INIT;
-	int ret, df_conflict = 0;
+	int ret;
 
 	if (dry_run)
 		return 0;
@@ -598,30 +598,33 @@  static int s_update_ref(const char *action,
 	msg = xstrfmt("%s: %s", rla, action);
 
 	transaction = ref_transaction_begin(&err);
-	if (!transaction ||
-	    ref_transaction_update(transaction, ref->name,
-				   &ref->new_oid,
-				   check_old ? &ref->old_oid : NULL,
-				   0, msg, &err))
-		goto fail;
+	if (!transaction) {
+		ret = STORE_REF_ERROR_OTHER;
+		goto out;
+	}
+
+	ret = ref_transaction_update(transaction, ref->name, &ref->new_oid,
+				     check_old ? &ref->old_oid : NULL,
+				     0, msg, &err);
+	if (ret) {
+		ret = STORE_REF_ERROR_OTHER;
+		goto out;
+	}
 
 	ret = ref_transaction_commit(transaction, &err);
 	if (ret) {
-		df_conflict = (ret == TRANSACTION_NAME_CONFLICT);
-		goto fail;
+		ret = (ret == TRANSACTION_NAME_CONFLICT) ? STORE_REF_ERROR_DF_CONFLICT
+							 : STORE_REF_ERROR_OTHER;
+		goto out;
 	}
 
+out:
 	ref_transaction_free(transaction);
+	if (ret)
+		error("%s", err.buf);
 	strbuf_release(&err);
 	free(msg);
-	return 0;
-fail:
-	ref_transaction_free(transaction);
-	error("%s", err.buf);
-	strbuf_release(&err);
-	free(msg);
-	return df_conflict ? STORE_REF_ERROR_DF_CONFLICT
-			   : STORE_REF_ERROR_OTHER;
+	return ret;
 }
 
 static int refcol_width = 10;