From: Michael Haggerty <mhagger@alum.mit.edu>
To: Stefan Beller <sbeller@google.com>
Cc: "Junio C Hamano" <gitster@pobox.com>,
"Ronnie Sahlberg" <ronniesahlberg@gmail.com>,
"Jonathan Nieder" <jrnieder@gmail.com>,
"Nguyễn Thái Ngọc" <pclouds@gmail.com>,
"git@vger.kernel.org" <git@vger.kernel.org>,
"Carlos Martín Nieto" <cmn@elego.de>
Subject: Re: [PATCH 8/8] reflog_expire(): lock symbolic refs themselves, not their referent
Date: Fri, 13 Feb 2015 17:26:04 +0100 [thread overview]
Message-ID: <54DE259C.4030001@alum.mit.edu> (raw)
In-Reply-To: <CAGZ79kZgjRNS3zd4Tif6M66mjkP6-tDpy4FAtio8jiwqHxUtgw@mail.gmail.com>
On 02/12/2015 07:04 PM, Stefan Beller wrote:
> On Thu, Feb 12, 2015 at 8:52 AM, Michael Haggerty <mhagger@alum.mit.edu> wrote:
>> However, another important question is whether other Git implementations
>> have copied this unusual locking policy. If so, that would be a reason
>> not to change it. I just pinged the libgit2 maintainer to find out their
>> policy. Maybe you could find out about JGit?
>
> I could not really find reflog expiration for jgit for a while, but
> then I stumbled upon this:
>
> // TODO: implement reflog_expire(pm, repo);
>
> so I think it's safe to change it in git.git for now.
Stefan: This locking policy doesn't only affect "reflog expire"; we also
need to lock the reflog when we add a new entry to it, for example when
updating refs/heads/master through HEAD. Do you know what JGit locks in
that scenario?
I had a discussion in IRC [1] with Carlos Martín Nieto about how libgit2
handles this:
* When libgit2 updates a reference through a symref, it locks the
pointed-to reference while updating the reflog for the symbolic ref. So,
for example, "git commit" would hold refs/heads/master.lock while
updating both logs/refs/heads/master and logs/HEAD. (This matches the
current Git behavior.)
* libgit2 doesn't support "reflog expire", though it does have an API
that allows users to overwrite the reflog with a specified list of
entries. That API locks the reference itself; i.e., HEAD.lock. This
disagrees with Git's current behavior.
I also realized that Git's current policy is probably not tenable if one
process is re-seating a symref at the same time as another process is
expiring its reflog. The "git reflog expire HEAD" might grab
"refs/heads/master.lock" then start rewriting "logs/HEAD". Meanwhile,
"git checkout foo" would grab "HEAD.lock" (not being blocked by the
"expire" process), then rewrite it to "ref: refs/heads/foo", then grab
"refs/heads/foo.lock" before updating "logs/HEAD". So both processes
could be writing "logs/HEAD" at the same time.
In fact, it's even worse. "git checkout foo" and "git symbolic-ref HEAD
refs/heads/foo" release "HEAD.lock" *before* updating logs/HEAD--in
other words, they append to logs/HEAD without holding *any* lock.
What is the best way forward?
I think the current locking policy is untenable, even aside from the bug
in "symbolic-ref".
Switching to holding only "HEAD.lock" while updating "logs/HEAD" is the
right solution, but it would introduce an incompatibility with old
versions of Git and libgit2 (and maybe JGit?) Probably nobody would
notice, but who knows?
Therefore, I propose that we hold *both* "HEAD.lock" *and*
"refs/heads/master.lock" when modifying "logs/HEAD" (even when running
"reflog expire" or "reflog delete"). I think this will be compatible
with old versions of Git and libgit2, and it will also fix some design
problems mentioned above. Plus, it will prevent updates to the two
reflogs from appearing out of order relative to each other.
Someday, when old clients have been retired, we can optionally switch to
locking *only* "HEAD.lock" when modifying "logs/HEAD".
What do people think?
Michael
[1] https://github.com/libgit2/libgit2/issues/2902
--
Michael Haggerty
mhagger@alum.mit.edu
next prev parent reply other threads:[~2015-02-13 16:33 UTC|newest]
Thread overview: 46+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-02-09 9:12 [PATCH 0/8] Fix some problems with reflog expiration Michael Haggerty
2015-02-09 9:12 ` [PATCH 1/8] write_ref_sha1(): remove check for lock == NULL Michael Haggerty
2015-02-10 22:52 ` Stefan Beller
2015-02-11 0:06 ` Jeff King
2015-02-09 9:12 ` [PATCH 2/8] write_ref_sha1(): Move write elision test to callers Michael Haggerty
2015-02-12 19:58 ` Junio C Hamano
2015-02-09 9:12 ` [PATCH 3/8] lock_ref_sha1_basic(): do not set force_write for missing references Michael Haggerty
2015-02-10 23:24 ` Stefan Beller
2015-02-11 0:05 ` Jeff King
2015-02-11 0:07 ` Stefan Beller
2015-02-12 12:09 ` Michael Haggerty
2015-02-09 9:12 ` [PATCH 4/8] reflog: fix documentation Michael Haggerty
2015-02-10 23:25 ` Stefan Beller
2015-02-09 9:12 ` [PATCH 5/8] reflog: rearrange the manpage Michael Haggerty
2015-02-10 23:42 ` Stefan Beller
2015-02-12 15:17 ` Michael Haggerty
2015-02-12 20:09 ` Junio C Hamano
2015-02-09 9:12 ` [PATCH 6/8] reflog_expire(): ignore --updateref for symbolic references Michael Haggerty
2015-02-11 0:44 ` Stefan Beller
2015-02-12 16:08 ` Michael Haggerty
2015-02-12 17:04 ` Stefan Beller
2015-02-12 20:16 ` Junio C Hamano
2015-02-12 21:54 ` Jeff King
2015-02-13 14:34 ` Michael Haggerty
2015-02-09 9:12 ` [PATCH 7/8] reflog_expire(): never update a reference to null_sha1 Michael Haggerty
2015-02-09 20:55 ` Eric Sunshine
2015-02-12 11:51 ` Michael Haggerty
2015-02-09 9:12 ` [PATCH 8/8] reflog_expire(): lock symbolic refs themselves, not their referent Michael Haggerty
2015-02-11 0:49 ` Stefan Beller
2015-02-11 22:49 ` Junio C Hamano
2015-02-11 23:25 ` Stefan Beller
2015-02-12 16:52 ` Michael Haggerty
2015-02-12 18:04 ` Stefan Beller
2015-02-13 16:26 ` Michael Haggerty [this message]
2015-02-13 17:16 ` Stefan Beller
2015-02-13 18:05 ` Junio C Hamano
2015-02-13 18:21 ` Stefan Beller
2015-02-13 18:26 ` Junio C Hamano
2015-02-13 18:32 ` Stefan Beller
2015-02-13 19:12 ` Junio C Hamano
2015-02-13 20:11 ` Michael Haggerty
2015-02-13 21:53 ` Junio C Hamano
2015-02-14 5:58 ` Michael Haggerty
2015-02-09 18:57 ` [PATCH 0/8] Fix some problems with reflog expiration Stefan Beller
2015-02-10 23:12 ` [PATCH] refs.c: get rid of force_write flag Stefan Beller
2015-02-12 15:35 ` 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=54DE259C.4030001@alum.mit.edu \
--to=mhagger@alum.mit.edu \
--cc=cmn@elego.de \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=jrnieder@gmail.com \
--cc=pclouds@gmail.com \
--cc=ronniesahlberg@gmail.com \
--cc=sbeller@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).