All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jeff King <peff@peff.net>
To: git@vger.kernel.org
Cc: Michael Haggerty <mhagger@alum.mit.edu>
Subject: Re: [PATCH 1/2] refs/files-backend: handle packed transaction prepare failure
Date: Thu, 21 Mar 2019 20:06:01 -0400	[thread overview]
Message-ID: <20190322000601.GA32671@sigill.intra.peff.net> (raw)
In-Reply-To: <20190321092844.GA2722@sigill.intra.peff.net>

On Thu, Mar 21, 2019 at 05:28:44AM -0400, Jeff King wrote:

>   - instead of disconnecting backend_data->packed_transaction on error,
>     we could wait to install it until we successfully prepare. That
>     might make the flow a little simpler, but it introduces a hassle.
>     Earlier parts of files_transaction_prepare() that encounter an error
>     will jump to the cleanup label, and expect that cleaning up the
>     outer transaction will clean up the packed transaction, too. We'd
>     have to adjust those sites to clean up the packed transaction.

This actually isn't too bad. Here's what it would look like as a
cleanup patch on top. I dunno if it's worth it or not.

-- >8 --
Subject: [PATCH] refs/files-backend: delay setting packed_transaction

When preparing a files_transaction, we have two pointers to the
subordinate packed transaction: a local variable, and one in
backend_data which will be carried forward if we succeed.

These always point to the same thing, so one is basically an alias of
the other. But in some of the trickier cleanup code added by the last
few commits, we have to set them to NULL if we've already freed the
struct. We only _need_ to do this for the one in backend_data, but that
leaves the local variable as a dangling pointer.

Instead, let's make the rules more obvious:

  - only point backend_data at the packed transaction when we know it is
    needed and preparation has succeeded. We should never need to roll
    back backend_data->packed_transaction

  - clean up the local packed_transaction variable on failure manually,
    instead of relying on files_transaction_cleanup() to do it

An alternative would be to drop the local variable entirely, and just
use backend_data->packed_transaction. That works, but the resulting code
is a bit harder to read because of the length of the name.

Signed-off-by: Jeff King <peff@peff.net>
---
 refs/files-backend.c | 41 ++++++++++++++++++++++++-----------------
 1 file changed, 24 insertions(+), 17 deletions(-)

diff --git a/refs/files-backend.c b/refs/files-backend.c
index 442204af4d..13a53bcb30 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -2672,9 +2672,6 @@ static int files_transaction_prepare(struct ref_store *ref_store,
 					ret = TRANSACTION_GENERIC_ERROR;
 					goto cleanup;
 				}
-
-				backend_data->packed_transaction =
-					packed_transaction;
 			}
 
 			ref_transaction_add_update(
@@ -2695,15 +2692,23 @@ static int files_transaction_prepare(struct ref_store *ref_store,
 		if (is_packed_transaction_needed(refs->packed_ref_store,
 						 packed_transaction)) {
 			ret = ref_transaction_prepare(packed_transaction, err);
-			/*
-			 * A failure during the prepare step will abort
-			 * itself, but not free. Do that now, and disconnect
-			 * from the files_transaction so it does not try to
-			 * abort us when we hit the cleanup code below.
-			 */
-			if (ret) {
+			if (!ret) {
+				/*
+				 * Attach the prepared packed transaction to
+				 * the files transaction so it can be committed
+				 * later.
+				 */
+				backend_data->packed_transaction =
+					packed_transaction;
+			} else {
+				/*
+				 * A failure during the prepare step will abort
+				 * itself, but not free. Do that now, so we
+				 * don't try to double-abort during the cleanup
+				 * below.
+				 */
 				ref_transaction_free(packed_transaction);
-				backend_data->packed_transaction = NULL;
+				packed_transaction = NULL;
 			}
 		} else {
 			/*
@@ -2712,25 +2717,27 @@ static int files_transaction_prepare(struct ref_store *ref_store,
 			 * that somebody else doesn't pack a reference
 			 * that we are trying to delete.
 			 *
-			 * We need to disconnect our transaction from
-			 * backend_data, since the abort (whether successful or
-			 * not) will free it.
+			 * We need to NULL our local pointer, since the abort
+			 * (whether successful or not) will free it.
 			 */
-			backend_data->packed_transaction = NULL;
 			if (ref_transaction_abort(packed_transaction, err)) {
 				ret = TRANSACTION_GENERIC_ERROR;
+				packed_transaction = NULL;
 				goto cleanup;
 			}
+			packed_transaction = NULL;
 		}
 	}
 
 cleanup:
 	free(head_ref);
 	string_list_clear(&affected_refnames, 0);
 
-	if (ret)
+	if (ret) {
 		files_transaction_cleanup(refs, transaction);
-	else
+		if (packed_transaction)
+			ref_transaction_abort(packed_transaction, err);
+	} else
 		transaction->state = REF_TRANSACTION_PREPARED;
 
 	return ret;
-- 
2.21.0.705.g64cb90f133


  reply	other threads:[~2019-03-22  0:06 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-03-21  9:28 [PATCH 0/2] refs/files-backend: fix two subtle error-handling bugs Jeff King
2019-03-21  9:28 ` [PATCH 1/2] refs/files-backend: handle packed transaction prepare failure Jeff King
2019-03-22  0:06   ` Jeff King [this message]
2019-03-22 14:34     ` Taylor Blau
2019-03-21  9:28 ` [PATCH 2/2] refs/files-backend: don't look at an aborted transaction Jeff King

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190322000601.GA32671@sigill.intra.peff.net \
    --to=peff@peff.net \
    --cc=git@vger.kernel.org \
    --cc=mhagger@alum.mit.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.