All of lore.kernel.org
 help / color / mirror / Atom feed
From: Junio C Hamano <gitster@pobox.com>
To: Michael Haggerty <mhagger@alum.mit.edu>
Cc: Brad King <brad.king@kitware.com>,
	Johan Herland <johan@herland.net>, Jeff King <peff@peff.net>,
	Vicent Marti <tanoku@gmail.com>,
	git@vger.kernel.org
Subject: Re: [PATCH v2 19/27] refs: Add a concept of a reference transaction
Date: Tue, 01 Apr 2014 12:39:14 -0700	[thread overview]
Message-ID: <xmqqtxaczvod.fsf@gitster.dls.corp.google.com> (raw)
In-Reply-To: <1395683820-17304-20-git-send-email-mhagger@alum.mit.edu> (Michael Haggerty's message of "Mon, 24 Mar 2014 18:56:52 +0100")

Michael Haggerty <mhagger@alum.mit.edu> writes:

> Build out the API for dealing with a bunch of reference checks and
> changes within a transaction.  Define an opaque ref_transaction type
> that is managed entirely within refs.c.  Introduce functions for
> beginning a transaction, adding updates to a transaction, and
> committing/rolling back a transaction.
>
> This API will soon replace update_refs().
>
> Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
> ---
>  refs.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  refs.h | 65 +++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 161 insertions(+)
>
> diff --git a/refs.c b/refs.c
> index 1305eb1..e788c27 100644
> --- a/refs.c
> +++ b/refs.c
> @@ -3267,6 +3267,93 @@ static int update_ref_write(const char *action, const char *refname,
>  	return 0;
>  }
>  
> +/*
> + * Data structure for holding a reference transaction, which can
> + * consist of checks and updates to multiple references, carried out
> + * as atomically as possible.  This structure is opaque to callers.
> + */
> +struct ref_transaction {
> +	struct ref_update **updates;

Don't we try to name an array update[] (not plural updates[]) so
that we can say update[7] to mean the seventh update?

> +	size_t alloc;
> +	size_t nr;
> +};
> +
> +struct ref_transaction *ref_transaction_begin(void)
> +{
> +	return xcalloc(1, sizeof(struct ref_transaction));
> +}
> +
> +static void ref_transaction_free(struct ref_transaction *transaction)
> +{
> +	int i;
> +
> +	for (i = 0; i < transaction->nr; i++) {
> +		struct ref_update *update = transaction->updates[i];
> +
> +		free((char *)update->ref_name);
> +		free(update);
> +	}
> +
> +	free(transaction->updates);
> +	free(transaction);
> +}

OK.

> +void ref_transaction_rollback(struct ref_transaction *transaction)
> +{
> +	ref_transaction_free(transaction);
> +}

OK.

> +static struct ref_update *add_update(struct ref_transaction *transaction,
> +				     const char *refname)
> +{
> +	struct ref_update *update = xcalloc(1, sizeof(*update));
> +
> +	update->ref_name = xstrdup(refname);
> +	ALLOC_GROW(transaction->updates, transaction->nr + 1, transaction->alloc);
> +	transaction->updates[transaction->nr++] = update;
> +	return update;
> +}
> +
> +void ref_transaction_update(struct ref_transaction *transaction,
> +			    const char *refname,
> +			    unsigned char *new_sha1, unsigned char *old_sha1,
> +			    int flags, int have_old)
> +{
> +	struct ref_update *update = add_update(transaction, refname);
> +
> +	hashcpy(update->new_sha1, new_sha1);
> +	update->flags = flags;
> +	update->have_old = have_old;
> +	if (have_old)
> +		hashcpy(update->old_sha1, old_sha1);
> +}
> +
> +void ref_transaction_create(struct ref_transaction *transaction,
> +			    const char *refname,
> +			    unsigned char *new_sha1,
> +			    int flags)
> +{
> +	struct ref_update *update = add_update(transaction, refname);
> +
> +	hashcpy(update->new_sha1, new_sha1);
> +	hashclr(update->old_sha1);
> +	update->flags = flags;
> +	update->have_old = 1;
> +}
> +
> +void ref_transaction_delete(struct ref_transaction *transaction,
> +			    const char *refname,
> +			    unsigned char *old_sha1,
> +			    int flags, int have_old)
> +{
> +	struct ref_update *update = add_update(transaction, refname);
> +
> +	update->flags = flags;
> +	update->have_old = have_old;
> +	if (have_old)
> +		hashcpy(update->old_sha1, old_sha1);
> +}
> +

I can see that the chosen set of primitives update/create/delete
mirrors what update-ref allows us to do, but given the explanation
of "update" in refs.h, wouldn't it make more sense to implement the
others in terms of it?

>  int update_ref(const char *action, const char *refname,
>  	       const unsigned char *sha1, const unsigned char *oldval,
>  	       int flags, enum action_on_err onerr)
> @@ -3378,6 +3465,15 @@ cleanup:
>  	return ret;
>  }
>  
> +int ref_transaction_commit(struct ref_transaction *transaction,
> +			   const char *msg, enum action_on_err onerr)
> +{
> +	int ret = update_refs(msg, transaction->updates, transaction->nr,
> +			      onerr);
> +	ref_transaction_free(transaction);
> +	return ret;
> +}

OK.

>  char *shorten_unambiguous_ref(const char *refname, int strict)
>  {
>  	int i;
> diff --git a/refs.h b/refs.h
> index 08e60ac..476a923 100644
> --- a/refs.h
> +++ b/refs.h
> @@ -24,6 +24,8 @@ struct ref_update {
>  	int have_old; /* 1 if old_sha1 is valid, 0 otherwise */
>  };
>  
> +struct ref_transaction;
> +
>  /*
>   * Bit values set in the flags argument passed to each_ref_fn():
>   */
> @@ -220,6 +222,69 @@ enum action_on_err {
>  	UPDATE_REFS_QUIET_ON_ERR
>  };
>  
> +/*
> + * Begin a reference transaction.  The reference transaction must
> + * eventually be commited using ref_transaction_commit() or rolled
> + * back using ref_transaction_rollback().
> + */
> +struct ref_transaction *ref_transaction_begin(void);
> +
> +/*
> + * Roll back a ref_transaction and free all associated data.
> + */
> +void ref_transaction_rollback(struct ref_transaction *transaction);
> +
> +
> +/*
> + * The following functions add a reference check or update to a
> + * ref_transaction.  In all of them, refname is the name of the
> + * reference to be affected.  The functions make internal copies of
> + * refname, so the caller retains ownership of the parameter.  flags

Good to see the ownership rules described.

> + * can be REF_NODEREF; it is passed to update_ref_lock().
> + */
> +
> +
> +/*
> + * Add a reference update to transaction.  new_sha1 is the value that
> + * the reference should have after the update, or zeros if it should
> + * be deleted.  If have_old is true, then old_sha1 holds the value
> + * that the reference should have had before the update, or zeros if
> + * it must not have existed beforehand.
> + */
> +void ref_transaction_update(struct ref_transaction *transaction,
> +			    const char *refname,
> +			    unsigned char *new_sha1, unsigned char *old_sha1,
> +			    int flags, int have_old);
> +
> +/*
> + * Add a reference creation to transaction.  new_sha1 is the value
> + * that the reference should have after the update, or zeros if it
> + * should be deleted.  It is verified that the reference does not
> + * exist already.
> + */

Sounds a bit crazy that you can ask "create", which verifies the
absense of the thing, to delete a thing.

> +void ref_transaction_create(struct ref_transaction *transaction,
> +			    const char *refname,
> +			    unsigned char *new_sha1,
> +			    int flags);
> +
> +/*
> + * Add a reference deletion to transaction.  If have_old is true, then
> + * old_sha1 holds the value that the reference should have had before
> + * the update.
> + */
> +void ref_transaction_delete(struct ref_transaction *transaction,
> +			    const char *refname,
> +			    unsigned char *old_sha1,
> +			    int flags, int have_old);
> +
> +/*
> + * Commit all of the changes that have been queued in transaction, as
> + * atomically as possible.  Return a nonzero value if there is a
> + * problem.  The ref_transaction is freed by this function.
> + */
> +int ref_transaction_commit(struct ref_transaction *transaction,
> +			   const char *msg, enum action_on_err onerr);
> +
>  /** Lock a ref and then write its file */
>  int update_ref(const char *action, const char *refname,
>  		const unsigned char *sha1, const unsigned char *oldval,

  parent reply	other threads:[~2014-04-01 19:39 UTC|newest]

Thread overview: 65+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-03-24 17:56 [PATCH v2 00/27] Clean up update-refs --stdin and implement ref_transaction Michael Haggerty
2014-03-24 17:56 ` [PATCH v2 01/27] t1400: Fix name and expected result of one test Michael Haggerty
2014-03-31 21:30   ` Junio C Hamano
2014-03-31 21:49     ` Michael Haggerty
2014-03-24 17:56 ` [PATCH v2 02/27] t1400: Provide more usual input to the command Michael Haggerty
2014-03-31 21:28   ` Junio C Hamano
2014-03-24 17:56 ` [PATCH v2 03/27] parse_arg(): Really test that argument is properly terminated Michael Haggerty
2014-03-31 21:36   ` Junio C Hamano
2014-03-31 22:11     ` Michael Haggerty
2014-03-24 17:56 ` [PATCH v2 04/27] t1400: Add some more tests involving quoted arguments Michael Haggerty
2014-03-24 17:56 ` [PATCH v2 05/27] refs.h: Rename the action_on_err constants Michael Haggerty
2014-03-24 17:56 ` [PATCH v2 06/27] update_refs(): Fix constness Michael Haggerty
2014-03-31 21:40   ` Junio C Hamano
2014-03-31 22:16     ` Michael Haggerty
2014-03-31 22:38       ` Junio C Hamano
2014-03-24 17:56 ` [PATCH v2 07/27] update-ref --stdin: Read the whole input at once Michael Haggerty
2014-03-24 17:56 ` [PATCH v2 08/27] parse_cmd_verify(): Copy old_sha1 instead of evaluating <oldvalue> twice Michael Haggerty
2014-03-24 17:56 ` [PATCH v2 09/27] update-ref.c: Extract a new function, parse_refname() Michael Haggerty
2014-03-24 17:56 ` [PATCH v2 10/27] update-ref --stdin: Improve error messages for invalid values Michael Haggerty
2014-03-24 17:56 ` [PATCH v2 11/27] update-ref --stdin: Make error messages more consistent Michael Haggerty
2014-03-24 17:56 ` [PATCH v2 12/27] update-ref --stdin: Simplify error messages for missing oldvalues Michael Haggerty
2014-03-24 17:56 ` [PATCH v2 13/27] t1400: Test that stdin -z update treats empty <newvalue> as zeros Michael Haggerty
2014-03-31 21:48   ` Junio C Hamano
2014-03-31 22:20     ` Michael Haggerty
2014-03-24 17:56 ` [PATCH v2 14/27] update-ref.c: Extract a new function, parse_next_sha1() Michael Haggerty
2014-03-26 18:39   ` Brad King
2014-03-24 17:56 ` [PATCH v2 15/27] update-ref --stdin -z: Deprecate interpreting the empty string as zeros Michael Haggerty
2014-03-31 21:49   ` Junio C Hamano
2014-03-24 17:56 ` [PATCH v2 16/27] t1400: Test one mistake at a time Michael Haggerty
2014-03-26 18:39   ` Brad King
2014-03-31 21:50   ` Junio C Hamano
2014-03-31 22:32     ` Michael Haggerty
2014-03-24 17:56 ` [PATCH v2 17/27] update-ref --stdin: Improve the error message for unexpected EOF Michael Haggerty
2014-03-24 17:56 ` [PATCH v2 18/27] update-ref --stdin: Harmonize error messages Michael Haggerty
2014-03-31 21:51   ` Junio C Hamano
2014-03-31 22:37     ` Michael Haggerty
2014-04-01  9:29       ` Michael Haggerty
2014-04-02 16:38         ` Junio C Hamano
2014-03-24 17:56 ` [PATCH v2 19/27] refs: Add a concept of a reference transaction Michael Haggerty
2014-03-26 18:39   ` Brad King
2014-03-26 21:42     ` Michael Haggerty
2014-04-01 19:39   ` Junio C Hamano [this message]
2014-04-02  4:57     ` Michael Haggerty
2014-03-24 17:56 ` [PATCH v2 20/27] update-ref --stdin: Reimplement using reference transactions Michael Haggerty
2014-04-01 19:46   ` Junio C Hamano
2014-04-02  5:03     ` Michael Haggerty
2014-04-03 15:57       ` Junio C Hamano
2014-04-04  5:02         ` Michael Haggerty
2014-03-24 17:56 ` [PATCH v2 21/27] refs: Remove API function update_refs() Michael Haggerty
2014-04-01 19:46   ` Junio C Hamano
2014-03-24 17:56 ` [PATCH v2 22/27] struct ref_update: Rename field "ref_name" to "refname" Michael Haggerty
2014-04-01 19:53   ` Junio C Hamano
2014-04-02  5:11     ` Michael Haggerty
2014-03-24 17:56 ` [PATCH v2 23/27] struct ref_update: Store refname as a FLEX_ARRAY Michael Haggerty
2014-04-01 19:54   ` Junio C Hamano
2014-03-24 17:56 ` [PATCH v2 24/27] ref_transaction_commit(): Introduce temporary variables Michael Haggerty
2014-04-01 19:26   ` Junio C Hamano
2014-03-24 17:56 ` [PATCH v2 25/27] struct ref_update: Add a lock member Michael Haggerty
2014-03-24 17:56 ` [PATCH v2 26/27] struct ref_update: Add type field Michael Haggerty
2014-04-01 20:03   ` Junio C Hamano
2014-04-02 10:13     ` Michael Haggerty
2014-04-02 17:44     ` Junio C Hamano
2014-03-24 17:57 ` [PATCH v2 27/27] ref_transaction_commit(): Work with transaction->updates in place Michael Haggerty
2014-03-26 18:39 ` [PATCH v2 00/27] Clean up update-refs --stdin and implement ref_transaction Brad King
2014-03-26 21:47   ` Michael Haggerty

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=xmqqtxaczvod.fsf@gitster.dls.corp.google.com \
    --to=gitster@pobox.com \
    --cc=brad.king@kitware.com \
    --cc=git@vger.kernel.org \
    --cc=johan@herland.net \
    --cc=mhagger@alum.mit.edu \
    --cc=peff@peff.net \
    --cc=tanoku@gmail.com \
    /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.