From: Michael Haggerty <mhagger@alum.mit.edu>
To: Ronnie Sahlberg <sahlberg@google.com>, git@vger.kernel.org
Cc: Jeff King <peff@peff.net>
Subject: Re: [PATCH v4 2/3] refs.c: split delete_ref_loose() into a separate flag-for-deletion and commit phase
Date: Tue, 15 Apr 2014 19:19:01 +0200 [thread overview]
Message-ID: <534D6A05.8040609@alum.mit.edu> (raw)
In-Reply-To: <1397500163-7617-3-git-send-email-sahlberg@google.com>
On 04/14/2014 08:29 PM, Ronnie Sahlberg wrote:
> Change delete_ref_loose()) to just flag that a ref is to be deleted but do
> not actually unlink the files.
> Change commit_ref_lock() so that it will unlink refs that are flagged for
> deletion.
> Change all callers of delete_ref_loose() to explicitely call commit_ref_lock()
s/explicitely/explicitly/
> to commit the deletion.
>
> The new pattern for deleting loose refs thus become:
>
> lock = lock_ref_sha1_basic() (or varient of)
s/varient/variant/
> delete_ref_loose(lock)
> unlock_ref(lock) | commit_ref_lock(lock)
Formatting: sentences should be flowed together if they are within a
paragraph, or separated with blank lines if they constitute separate
paragraphs, or have "bullet" characters and be indented if they are a
bullet list.
Code should be indented to set it off from the prose.
> Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
> ---
> refs.c | 32 ++++++++++++++++++++------------
> refs.h | 2 ++
> 2 files changed, 22 insertions(+), 12 deletions(-)
>
> diff --git a/refs.c b/refs.c
> index 646afd7..a14addb 100644
> --- a/refs.c
> +++ b/refs.c
> @@ -2484,16 +2484,9 @@ static int repack_without_ref(const char *refname)
>
> static int delete_ref_loose(struct ref_lock *lock, int flag)
> {
> - if (!(flag & REF_ISPACKED) || flag & REF_ISSYMREF) {
> - /* loose */
> - int err, i = strlen(lock->lk->filename) - 5; /* .lock */
> -
> - lock->lk->filename[i] = 0;
> - err = unlink_or_warn(lock->lk->filename);
> - lock->lk->filename[i] = '.';
> - if (err && errno != ENOENT)
> - return 1;
> - }
> + lock->delete_ref = 1;
> + lock->delete_flag = flag;
> +
> return 0;
> }
>
> @@ -2515,7 +2508,7 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
>
> unlink_or_warn(git_path("logs/%s", lock->ref_name));
> clear_loose_ref_cache(&ref_cache);
> - unlock_ref(lock);
> + ret |= commit_ref_lock(lock);
> return ret;
> }
Before this patch, the sequence for deleting a reference was
acquire lock on loose ref file
delete loose ref file
acquire lock on packed-refs file
rewrite packed-refs file, omitting ref
activate packed-refs file and release its lock
release lock on loose ref file
Another process that tries to read the reference's value between steps 2
and 4 sees some old value of the reference from the packed-refs file
rather than seeing either its recent value or seeing it undefined. The
value that it sees can be arbitrarily old, and might even point at an
object that has long-since been garbage-collected. If the packed-refs
lock acquisition fails, then the old value can be left in the
packed-refs file and becomes the value of the reference permanently. So
this is not correct (it's a known problem).
After the patch, it is
acquire lock on loose ref file
acquire lock on packed-refs file
rewrite packed-refs file, omitting ref
activate packed-refs file and release its lock
delete loose ref file <-- now this happens later
release lock on loose ref file
A pack-refs process that runs between steps 4 and 5 might be able to
acquire the packed-refs file lock, see the doomed loose value of the
reference, and pack it, with the end effect that the reference is not
deleted after all. But this is less bad than what can happen now. Can
anybody think of any new races that the new sequence would open?
Michael
--
Michael Haggerty
mhagger@alum.mit.edu
http://softwareswirl.blogspot.com/
next prev parent reply other threads:[~2014-04-15 17:19 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-04-14 18:29 [PATCH v4 0/3] Make update refs more atomic Ronnie Sahlberg
2014-04-14 18:29 ` [PATCH v4 1/3] refs.c: split writing and commiting a ref into two separate functions Ronnie Sahlberg
2014-04-15 11:17 ` Michael Haggerty
2014-04-14 18:29 ` [PATCH v4 2/3] refs.c: split delete_ref_loose() into a separate flag-for-deletion and commit phase Ronnie Sahlberg
2014-04-15 17:19 ` Michael Haggerty [this message]
2014-04-14 18:29 ` [PATCH v4 3/3] refs.c: change ref_transaction_commit to run the commit loops once all work is finished Ronnie Sahlberg
2014-04-14 20:24 ` [PATCH v4 0/3] Make update refs more atomic Junio C Hamano
2014-04-15 16:41 ` Ronnie Sahlberg
2014-04-15 6:36 ` Michael Haggerty
2014-04-15 16:33 ` Ronnie Sahlberg
2014-04-15 20:32 ` Michael Haggerty
2014-04-16 17:11 ` Ronnie Sahlberg
2014-04-16 19:31 ` Junio C Hamano
2014-04-16 21:31 ` Ronnie Sahlberg
2014-04-16 21:42 ` Junio C Hamano
2014-04-16 21:51 ` 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=534D6A05.8040609@alum.mit.edu \
--to=mhagger@alum.mit.edu \
--cc=git@vger.kernel.org \
--cc=peff@peff.net \
--cc=sahlberg@google.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).