git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH 5/5] ref_transaction_commit(): only keep one lockfile open at a time

From
Jeff King <peff@peff.net>
Date
Apr 28, 2015, 04:36 UTC
Message-ID
<20150428043653.GC24580@peff.net>
In-Reply-To
<xmqqoamcypy4.fsf@gitster.dls.corp.google.com>
On Sat, Apr 25, 2015 at 12:21:07PM -0700, Junio C Hamano wrote:
Show 21 quoted lines
> Junio C Hamano <gitster@pobox.com> writes:
> 
> > I am not too worried about "push --atomic", as we can just add a few
> > words to Release Notes and documentation saying "this is still an
> > experimental broken code that is unusable; don't use the feature in
> > production".
> >
> > I however am more worried about the other one "update-ref --stdin";
> > the change will be pure regression for those who want to do many
> > updates and do not care if the update is atomic, no?
> 
> I should have refrained from touching the keyboard so late at night
> X-<.  This regression was done long time ago (even in v2.1.0 I see
> that ref_transaction_commit() tries to grab all locks at once).
> 
> So it is only "push --atomic".
> 
> The choice is between (1) shipping "push --atomic" that is known to
> be broken, (2) applying your five-patch series which may (a) fix
> both "push --atomic" and "update-ref --stdin", or (b) break other
> transaction users including "update-ref -stdin" in unexpected ways.
I'm not sure "--atomic" is foolproof even with these patches.

Certainly there is the obvious problem that the filesystem is not atomic (so a power loss halfway through committing the locks will result in a non-atomic push). But there are also subtle locking issues related to D/F conflicts.

For instance, if we do (and I take no credit for this discovery; Michael showed it to me last week):

  {
    echo "create refs/heads/branch $sha1"
    echo "create refs/heads/foo/bar $sha1" &&
    echo "create refs/heads/foo $sha1"
  } | git update-ref --stdin

we do not notice the conflict between "foo" and "foo/bar" until the commit stage. Fortunately our ref-ordering rules mean we will always try to write "foo" before "foo/bar", which will fail because "foo" must be a directory (because we have "foo/bar.lock"). But because "branch" comes alphabetically first, we will have written that ref already, committing part of the request.

You can work around this with code to check for D/F conflicts in a single transaction, but then you are subject to races with other processes. E.g., one process writes "branch" and "foo", the other is simultaneously writing "foo/bar". There is no lock contention, but the write of "foo" may fail at the commit stage.

So I think it is OK to restrict the definition of "atomic" here to the common case of making sure that we can lock and check the $old_sha1 for each of the refs. Under that definition, "push --atomic" is not broken as-is, but there is room for improving its robustness. And I have no problem with trying to make our storage format as robust as possible in these cases, but I think we need to admit that the filesystem ref storage is never going to be 100% transactional.

I know that sounds a bit like moving the goalposts to say "eh, this feature is not broken, your definition of broken is just wrong". But my point is that shipping "push --atomic" as-is is still a useful step forward, and we can continue to iterate and improve on the concept in future releases.

-Peff
Previous: Junio C HamanoNext: Jeff King
Message 15 of 19 in “Avoid file descriptor exhaustion in ref_transaction_commit()”
  1. 0/5 Avoid file descriptor exhaustion in ref_transaction_commit()Michael Haggerty, Apr 24, 2015
  2. 1/5 write_ref_to_lockfile(): new function, extracted from write_ref_sha1()Michael Haggerty, Apr 24, 2015
  3. 2/5 commit_ref_update(): new function, extracted from write_ref_sha1()Michael Haggerty, Apr 24, 2015
  4. 3/5 write_ref_sha1(): inline function at callersMichael Haggerty, Apr 24, 2015
  5. 4/5 ref_transaction_commit(): remove the local flags variablesMichael Haggerty, Apr 24, 2015
  6. Jeff KingApr 24, 2015
  7. Michael HaggertyApr 24, 2015
  8. Jeff KingApr 24, 2015
  9. Eric SunshineApr 24, 2015
  10. Michael HaggertyApr 24, 2015
  11. 5/5 ref_transaction_commit(): only keep one lockfile open at a timeMichael Haggerty, Apr 24, 2015
  12. Michael HaggertyApr 25, 2015
  13. Junio C HamanoApr 25, 2015
  14. Junio C HamanoApr 25, 2015
  15. Jeff KingApr 28, 2015
  16. Jeff KingApr 24, 2015
  17. Stefan BellerApr 24, 2015
  18. Junio C HamanoApr 25, 2015
  19. Junio C HamanoApr 25, 2015

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.