diff mbox series

[v3,1/6] refs: extract packed_refs_delete_refs() to allow control of transaction

Message ID abbc28822b8fde78976422c775afa83bef76ca6c.1642054003.git.ps@pks.im (mailing list archive)
State Superseded
Headers show
Series refs: excessive hook execution with packed refs | expand

Commit Message

Patrick Steinhardt Jan. 13, 2022, 6:11 a.m. UTC
When deleting loose refs, then we also have to delete the refs in the
packed backend. This is done by calling `refs_delete_refs()`, which
then uses the packed-backend's logic to delete refs. This doesn't allow
us to exercise any control over the reference transaction which is being
created in the packed backend, which is required in a subsequent commit.

Extract a new function `packed_refs_delete_refs()`, which hosts most of
the logic to delete refs except for creating the transaction itself.
Like this, we can easily create the transaction in the files backend
and thus exert more control over it.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 refs/files-backend.c  | 12 +++++++++---
 refs/packed-backend.c | 28 +++++++++++++++++++++-------
 refs/packed-backend.h |  7 +++++++
 3 files changed, 37 insertions(+), 10 deletions(-)

Comments

Ævar Arnfjörð Bjarmason Jan. 13, 2022, 12:43 p.m. UTC | #1
On Thu, Jan 13 2022, Patrick Steinhardt wrote:

> [[PGP Signed Part:Undecided]]
> When deleting loose refs, then we also have to delete the refs in the
> packed backend. This is done by calling `refs_delete_refs()`, which
> then uses the packed-backend's logic to delete refs. This doesn't allow
> us to exercise any control over the reference transaction which is being
> created in the packed backend, which is required in a subsequent commit.
>
> Extract a new function `packed_refs_delete_refs()`, which hosts most of
> the logic to delete refs except for creating the transaction itself.
> Like this, we can easily create the transaction in the files backend
> and thus exert more control over it.
>
> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
>  refs/files-backend.c  | 12 +++++++++---
>  refs/packed-backend.c | 28 +++++++++++++++++++++-------
>  refs/packed-backend.h |  7 +++++++
>  3 files changed, 37 insertions(+), 10 deletions(-)
>
> diff --git a/refs/files-backend.c b/refs/files-backend.c
> index 90b671025a..5795e54020 100644
> --- a/refs/files-backend.c
> +++ b/refs/files-backend.c
> @@ -1249,6 +1249,7 @@ static int files_delete_refs(struct ref_store *ref_store, const char *msg,
>  {
>  	struct files_ref_store *refs =
>  		files_downcast(ref_store, REF_STORE_WRITE, "delete_refs");
> +	struct ref_transaction *transaction = NULL;

nit: "NULL initialization never needed?
(re: https://lore.kernel.org/git/220113.86bl0gvtq3.gmgdl@evledraar.gmail.com/)

>  	struct strbuf err = STRBUF_INIT;
>  	int i, result = 0;
>  
> @@ -1258,10 +1259,14 @@ static int files_delete_refs(struct ref_store *ref_store, const char *msg,
>  	if (packed_refs_lock(refs->packed_ref_store, 0, &err))
>  		goto error;
>  
> -	if (refs_delete_refs(refs->packed_ref_store, msg, refnames, flags)) {
> -		packed_refs_unlock(refs->packed_ref_store);
> +	transaction = ref_store_transaction_begin(refs->packed_ref_store, &err);
> +	if (!transaction)
> +		goto error;
> +
> +	result = packed_refs_delete_refs(refs->packed_ref_store,
> +					 transaction, msg, refnames, flags);
> +	if (result)
>  		goto error;
> -	}
>  
>  	packed_refs_unlock(refs->packed_ref_store);
>  
> @@ -1288,6 +1293,7 @@ static int files_delete_refs(struct ref_store *ref_store, const char *msg,
>  	else
>  		error(_("could not delete references: %s"), err.buf);
>  
> +	ref_transaction_free(transaction);
>  	strbuf_release(&err);
>  	return -1;
>  }
> diff --git a/refs/packed-backend.c b/refs/packed-backend.c
> index 67152c664e..e97d67f932 100644
> --- a/refs/packed-backend.c
> +++ b/refs/packed-backend.c
> @@ -1522,15 +1522,10 @@ static int packed_initial_transaction_commit(struct ref_store *ref_store,
>  static int packed_delete_refs(struct ref_store *ref_store, const char *msg,
>  			     struct string_list *refnames, unsigned int flags)
>  {
> -	struct packed_ref_store *refs =
> -		packed_downcast(ref_store, REF_STORE_WRITE, "delete_refs");
>  	struct strbuf err = STRBUF_INIT;
>  	struct ref_transaction *transaction;
> -	struct string_list_item *item;
>  	int ret;
>  
> -	(void)refs; /* We need the check above, but don't use the variable */
> -
>  	if (!refnames->nr)
>  		return 0;
>  
> @@ -1544,6 +1539,27 @@ static int packed_delete_refs(struct ref_store *ref_store, const char *msg,
>  	if (!transaction)
>  		return -1;
>  
> +	ret = packed_refs_delete_refs(ref_store, transaction,
> +				      msg, refnames, flags);
> +
> +	ref_transaction_free(transaction);
> +	return ret;
> +}
> +
> +int packed_refs_delete_refs(struct ref_store *ref_store,
> +			    struct ref_transaction *transaction,
> +			    const char *msg,
> +			    struct string_list *refnames,
> +			    unsigned int flags)
> +{
> +	struct packed_ref_store *refs =
> +		packed_downcast(ref_store, REF_STORE_WRITE, "delete_refs");
> +	struct strbuf err = STRBUF_INIT;
> +	struct string_list_item *item;
> +	int ret;
> +
> +	(void)(refs); /* We need the check above, but don't use the variable */
> +
>  	for_each_string_list_item(item, refnames) {
>  		if (ref_transaction_delete(transaction, item->string, NULL,
>  					   flags, msg, &err)) {

I see you're just moving this code around, but FWIW we can just do this
(also in the pre-image):

	int packed_refs_delete_refs(...)
	{
		[declare variables]
                
                /* Assert ref store sanity */
                packed_downcast(ref_store, REF_STORE_WRITE, "delete_refs")

                [...]
	}

Not sure it's good to change it around just for this mostly-move, just a
note...

> @@ -1554,7 +1570,6 @@ static int packed_delete_refs(struct ref_store *ref_store, const char *msg,
>  	}
>  
>  	ret = ref_transaction_commit(transaction, &err);
> -

Stray whitespace change.
Patrick Steinhardt Jan. 17, 2022, 7:36 a.m. UTC | #2
On Thu, Jan 13, 2022 at 01:43:18PM +0100, Ævar Arnfjörð Bjarmason wrote:
> 
> On Thu, Jan 13 2022, Patrick Steinhardt wrote:
> 
> > [[PGP Signed Part:Undecided]]
> > When deleting loose refs, then we also have to delete the refs in the
> > packed backend. This is done by calling `refs_delete_refs()`, which
> > then uses the packed-backend's logic to delete refs. This doesn't allow
> > us to exercise any control over the reference transaction which is being
> > created in the packed backend, which is required in a subsequent commit.
> >
> > Extract a new function `packed_refs_delete_refs()`, which hosts most of
> > the logic to delete refs except for creating the transaction itself.
> > Like this, we can easily create the transaction in the files backend
> > and thus exert more control over it.
> >
> > Signed-off-by: Patrick Steinhardt <ps@pks.im>
> > ---
> >  refs/files-backend.c  | 12 +++++++++---
> >  refs/packed-backend.c | 28 +++++++++++++++++++++-------
> >  refs/packed-backend.h |  7 +++++++
> >  3 files changed, 37 insertions(+), 10 deletions(-)
> >
> > diff --git a/refs/files-backend.c b/refs/files-backend.c
> > index 90b671025a..5795e54020 100644
> > --- a/refs/files-backend.c
> > +++ b/refs/files-backend.c
> > @@ -1249,6 +1249,7 @@ static int files_delete_refs(struct ref_store *ref_store, const char *msg,
> >  {
> >  	struct files_ref_store *refs =
> >  		files_downcast(ref_store, REF_STORE_WRITE, "delete_refs");
> > +	struct ref_transaction *transaction = NULL;
> 
> nit: "NULL initialization never needed?
> (re: https://lore.kernel.org/git/220113.86bl0gvtq3.gmgdl@evledraar.gmail.com/)

It is needed: if locking the packed-refs file fails we `goto error;` and
try to free the transaction without it having been initialized yet.

> >  	struct strbuf err = STRBUF_INIT;
> >  	int i, result = 0;
> >  
> > @@ -1258,10 +1259,14 @@ static int files_delete_refs(struct ref_store *ref_store, const char *msg,
> >  	if (packed_refs_lock(refs->packed_ref_store, 0, &err))
> >  		goto error;
> >  
> > -	if (refs_delete_refs(refs->packed_ref_store, msg, refnames, flags)) {
> > -		packed_refs_unlock(refs->packed_ref_store);
> > +	transaction = ref_store_transaction_begin(refs->packed_ref_store, &err);
> > +	if (!transaction)
> > +		goto error;
> > +
> > +	result = packed_refs_delete_refs(refs->packed_ref_store,
> > +					 transaction, msg, refnames, flags);
> > +	if (result)
> >  		goto error;
> > -	}
> >  
> >  	packed_refs_unlock(refs->packed_ref_store);
> >  
> > @@ -1288,6 +1293,7 @@ static int files_delete_refs(struct ref_store *ref_store, const char *msg,
> >  	else
> >  		error(_("could not delete references: %s"), err.buf);
> >  
> > +	ref_transaction_free(transaction);
> >  	strbuf_release(&err);
> >  	return -1;
> >  }
> > diff --git a/refs/packed-backend.c b/refs/packed-backend.c
> > index 67152c664e..e97d67f932 100644
> > --- a/refs/packed-backend.c
> > +++ b/refs/packed-backend.c
> > @@ -1522,15 +1522,10 @@ static int packed_initial_transaction_commit(struct ref_store *ref_store,
> >  static int packed_delete_refs(struct ref_store *ref_store, const char *msg,
> >  			     struct string_list *refnames, unsigned int flags)
> >  {
> > -	struct packed_ref_store *refs =
> > -		packed_downcast(ref_store, REF_STORE_WRITE, "delete_refs");
> >  	struct strbuf err = STRBUF_INIT;
> >  	struct ref_transaction *transaction;
> > -	struct string_list_item *item;
> >  	int ret;
> >  
> > -	(void)refs; /* We need the check above, but don't use the variable */
> > -
> >  	if (!refnames->nr)
> >  		return 0;
> >  
> > @@ -1544,6 +1539,27 @@ static int packed_delete_refs(struct ref_store *ref_store, const char *msg,
> >  	if (!transaction)
> >  		return -1;
> >  
> > +	ret = packed_refs_delete_refs(ref_store, transaction,
> > +				      msg, refnames, flags);
> > +
> > +	ref_transaction_free(transaction);
> > +	return ret;
> > +}
> > +
> > +int packed_refs_delete_refs(struct ref_store *ref_store,
> > +			    struct ref_transaction *transaction,
> > +			    const char *msg,
> > +			    struct string_list *refnames,
> > +			    unsigned int flags)
> > +{
> > +	struct packed_ref_store *refs =
> > +		packed_downcast(ref_store, REF_STORE_WRITE, "delete_refs");
> > +	struct strbuf err = STRBUF_INIT;
> > +	struct string_list_item *item;
> > +	int ret;
> > +
> > +	(void)(refs); /* We need the check above, but don't use the variable */
> > +
> >  	for_each_string_list_item(item, refnames) {
> >  		if (ref_transaction_delete(transaction, item->string, NULL,
> >  					   flags, msg, &err)) {
> 
> I see you're just moving this code around, but FWIW we can just do this
> (also in the pre-image):
> 
> 	int packed_refs_delete_refs(...)
> 	{
> 		[declare variables]
>                 
>                 /* Assert ref store sanity */
>                 packed_downcast(ref_store, REF_STORE_WRITE, "delete_refs")
> 
>                 [...]
> 	}
> 
> Not sure it's good to change it around just for this mostly-move, just a
> note...

I think this change is trivial enough to make while at it.

Patrick

> > @@ -1554,7 +1570,6 @@ static int packed_delete_refs(struct ref_store *ref_store, const char *msg,
> >  	}
> >  
> >  	ret = ref_transaction_commit(transaction, &err);
> > -
> 
> Stray whitespace change.
diff mbox series

Patch

diff --git a/refs/files-backend.c b/refs/files-backend.c
index 90b671025a..5795e54020 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -1249,6 +1249,7 @@  static int files_delete_refs(struct ref_store *ref_store, const char *msg,
 {
 	struct files_ref_store *refs =
 		files_downcast(ref_store, REF_STORE_WRITE, "delete_refs");
+	struct ref_transaction *transaction = NULL;
 	struct strbuf err = STRBUF_INIT;
 	int i, result = 0;
 
@@ -1258,10 +1259,14 @@  static int files_delete_refs(struct ref_store *ref_store, const char *msg,
 	if (packed_refs_lock(refs->packed_ref_store, 0, &err))
 		goto error;
 
-	if (refs_delete_refs(refs->packed_ref_store, msg, refnames, flags)) {
-		packed_refs_unlock(refs->packed_ref_store);
+	transaction = ref_store_transaction_begin(refs->packed_ref_store, &err);
+	if (!transaction)
+		goto error;
+
+	result = packed_refs_delete_refs(refs->packed_ref_store,
+					 transaction, msg, refnames, flags);
+	if (result)
 		goto error;
-	}
 
 	packed_refs_unlock(refs->packed_ref_store);
 
@@ -1288,6 +1293,7 @@  static int files_delete_refs(struct ref_store *ref_store, const char *msg,
 	else
 		error(_("could not delete references: %s"), err.buf);
 
+	ref_transaction_free(transaction);
 	strbuf_release(&err);
 	return -1;
 }
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index 67152c664e..e97d67f932 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -1522,15 +1522,10 @@  static int packed_initial_transaction_commit(struct ref_store *ref_store,
 static int packed_delete_refs(struct ref_store *ref_store, const char *msg,
 			     struct string_list *refnames, unsigned int flags)
 {
-	struct packed_ref_store *refs =
-		packed_downcast(ref_store, REF_STORE_WRITE, "delete_refs");
 	struct strbuf err = STRBUF_INIT;
 	struct ref_transaction *transaction;
-	struct string_list_item *item;
 	int ret;
 
-	(void)refs; /* We need the check above, but don't use the variable */
-
 	if (!refnames->nr)
 		return 0;
 
@@ -1544,6 +1539,27 @@  static int packed_delete_refs(struct ref_store *ref_store, const char *msg,
 	if (!transaction)
 		return -1;
 
+	ret = packed_refs_delete_refs(ref_store, transaction,
+				      msg, refnames, flags);
+
+	ref_transaction_free(transaction);
+	return ret;
+}
+
+int packed_refs_delete_refs(struct ref_store *ref_store,
+			    struct ref_transaction *transaction,
+			    const char *msg,
+			    struct string_list *refnames,
+			    unsigned int flags)
+{
+	struct packed_ref_store *refs =
+		packed_downcast(ref_store, REF_STORE_WRITE, "delete_refs");
+	struct strbuf err = STRBUF_INIT;
+	struct string_list_item *item;
+	int ret;
+
+	(void)(refs); /* We need the check above, but don't use the variable */
+
 	for_each_string_list_item(item, refnames) {
 		if (ref_transaction_delete(transaction, item->string, NULL,
 					   flags, msg, &err)) {
@@ -1554,7 +1570,6 @@  static int packed_delete_refs(struct ref_store *ref_store, const char *msg,
 	}
 
 	ret = ref_transaction_commit(transaction, &err);
-
 	if (ret) {
 		if (refnames->nr == 1)
 			error(_("could not delete reference %s: %s"),
@@ -1563,7 +1578,6 @@  static int packed_delete_refs(struct ref_store *ref_store, const char *msg,
 			error(_("could not delete references: %s"), err.buf);
 	}
 
-	ref_transaction_free(transaction);
 	strbuf_release(&err);
 	return ret;
 }
diff --git a/refs/packed-backend.h b/refs/packed-backend.h
index f61a73ec25..a2cca5d9a3 100644
--- a/refs/packed-backend.h
+++ b/refs/packed-backend.h
@@ -3,6 +3,7 @@ 
 
 struct repository;
 struct ref_transaction;
+struct string_list;
 
 /*
  * Support for storing references in a `packed-refs` file.
@@ -27,6 +28,12 @@  int packed_refs_lock(struct ref_store *ref_store, int flags, struct strbuf *err)
 void packed_refs_unlock(struct ref_store *ref_store);
 int packed_refs_is_locked(struct ref_store *ref_store);
 
+int packed_refs_delete_refs(struct ref_store *ref_store,
+			    struct ref_transaction *transaction,
+			    const char *msg,
+			    struct string_list *refnames,
+			    unsigned int flags);
+
 /*
  * Return true if `transaction` really needs to be carried out against
  * the specified packed_ref_store, or false if it can be skipped