git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: Daniel Santos <daniel.santos@pobox.com>
To: Jeff King <peff@peff.net>,
	Johannes Schindelin <johannes.schindelin@gmx.de>
Cc: git@vger.kernel.org
Subject: Re: [PATCH] git: add --no-optional-locks option
Date: Fri, 22 Sep 2017 01:42:10 -0500	[thread overview]
Message-ID: <c474bf47-5049-1425-d03c-2417eb53549e@pobox.com> (raw)
In-Reply-To: <20170921043214.pyhdsrpy4omy54rm@sigill.intra.peff.net>

On 09/20/2017 11:32 PM, Jeff King wrote:
> Johannes, this is an adaptation of your 67e5ce7f63 (status: offer *not*
> to lock the index and update it, 2016-08-12). Folks working on GitHub
> Desktop complained to me that it's only available on Windows. :)
>
> I expanded the scope a bit to let us give the same treatment to more
> commands in the long run.  I'd also be OK with just cherry-picking your
> patch to non-Windows Git if you don't find my reasoning below
> compelling. But I think we need _something_ like this, as the other
> solutions I could come up with don't seem very promising.
>
> -Peff
>
> -- >8 --
> Some tools like IDEs or fancy editors may periodically run
> commands like "git status" in the background to keep track
> of the state of the repository. Some of these commands may
> refresh the index and write out the result in an
> opportunistic way: if they can get the index lock, then they
> update the on-disk index with any updates they find. And if
> not, then their in-core refresh is lost and just has to be
> recomputed by the next caller.
>
> But taking the index lock may conflict with other operations
> in the repository. Especially ones that the user is doing
> themselves, which _aren't_ opportunistic. In other words,
> "git status" knows how to back off when somebody else is
> holding the lock, but other commands don't know that status
> would be happy to drop the lock if somebody else wanted it.

Interestingly, this usually slaps me when performing an _interactive_
rebase.  It occurred to me that if I'm performing an interaction
operation, it doesn't seem unreasonable for git wait up to 125ms or so
for the lock and then prompting the user to ask if they want to continue
waiting for the lock.

> There are a couple possible solutions:
>
>   1. Have some kind of "pseudo-lock" that allows other
>      commands to tell status that they want the lock.
>
>      This is likely to be complicated and error-prone to
>      implement (and maybe even impossible with just
>      dotlocks to work from, as it requires some
>      inter-process communication).
>
>   2. Avoid background runs of commands like "git status"
>      that want to do opportunistic updates, preferring
>      instead plumbing like diff-files, etc.
>
>      This is awkward for a couple of reasons. One is that
>      "status --porcelain" reports a lot more about the
>      repository state than is available from individual
>      plumbing commands. And two is that we actually _do_
>      want to see the refreshed index. We just don't want to
>      take a lock or write out the result. Whereas commands
>      like diff-files expect us to refresh the index
>      separately and write it to disk so that they can depend
>      on the result. But that write is exactly what we're
>      trying to avoid.
>
>   3. Ask "status" not to lock or write the index.
>
>      This is easy to implement. The big downside is that any
>      work done in refreshing the index for such a call is
>      lost when the process exits. So a background process
>      may end up re-hashing a changed file multiple times
>      until the user runs a command that does an index
>      refresh themselves.

That is not necessarily the case.  I don't actually know git on the
inside, but I would ask you to consider a read-write lock and a hybrid
of one and three.

I don't know what dotlocks are, but I'm certain that you can implement a
rw lock using lock files and no other IPC, although it does increase the
complexity.  The way this works is that `git status' acquires a read
lock and does its thing.  If it has real changes, instead of discarding
them it attempts to upgrade to a write lock.  If that fails, you throw
it away, otherwise you write them and release.

In order to implement rw locks with only lock files, "off the cuff" I
say you have a single "lock list" file that should never be deleted and
a "lock lock" file that is held in order to read or modify the list. 
The format of the lock list would have a pair of 32-bit wrapping
modification counts (or versions) at the top -- one for modifications to
the lock list its self and another for modifications to the underlying
data (i.e., the number of times a write lock has been acquired).  This
header is followed by entries something like this:

<operation> <pid> <version> <timestamp>

<operation>  'r' if waiting for a read lock
             'R' if actively reading
             'w' if waiting for write lock
             'W' if actively writing
<pid>        The pid
<version>    If active, the version of the data at the time lock acquired or zero.
<timestamp>  Time began waiting or time lock acquired


An operation of 'r' or 'w' means that you are waiting and upper case
means that you are active.  <version> is the version of the data at the
time the lock became active and writers increment it when they acquire a
lock.  You wait with file alteration notification on the lock list (if
there is any doubt based upon timestamp precision then you can examine
the lock list version).  When you want to read or write, you lock the
lock-lock (this sounds like a joke... "Lock, lock.", "Who's there?",
"Reader.", "Reader who?"....) and examine the lock list.  If it's empty,
you add yourself as an active reader or writer with an upper case 'R' or
'W' and release the lock-lock.  If there are only readers, and you want
to read, you add yourself as an active reader.  The version of the lock
list is incremented every time it is modified.

Read-write locks need to be given a priority policy of either readers,
writers, fifo or don't-care.  In this case that should probably be
writers.  So if you want to read and there is an active or waiting
writer, the prospective reader would either add themselves with an 'r'
or fail if they don't want to wait.  If a process wants to write and
there are active readers or writers, it adds its self to the list or
fails as well.  When all active readers have exited, then which ever
prospective writers gets the lock-lock first can make themselves the
active writer.  When a process acquires a write lock, it increases the
data version number.  If a reader lock tries to upgrade to a writer lock
but the data version changed than it fails.

Is there not already a library somewhere that does this?  Either way,
your current effort seems like a step in the right direction -- and
thanks for that!

Daniel


  parent reply	other threads:[~2017-09-22  6:36 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-09-21  4:32 [PATCH] git: add --no-optional-locks option Jeff King
2017-09-21  4:55 ` Junio C Hamano
2017-09-21  5:08   ` Jeff King
2017-09-21  5:29     ` Junio C Hamano
2017-09-21 18:25 ` Johannes Sixt
2017-09-22  4:25   ` Jeff King
2017-09-22 11:22     ` Jeff Hostetler
2017-09-22 15:04       ` Jeff King
2017-09-22 20:09     ` Stefan Beller
2017-09-22 21:25       ` Jeff King
2017-09-22 21:41         ` Stefan Beller
2017-09-23  3:34           ` Jeff King
2017-09-25 18:51             ` Stefan Beller
2017-09-27  6:44               ` Jeff King
2017-09-22  6:42 ` Daniel Santos [this message]
2017-09-22 16:04   ` Jeff King
2017-09-24 11:31 ` Kaartic Sivaraam
2017-09-25 16:17   ` Johannes Schindelin
2017-09-26 14:44     ` Jeff Hostetler
2017-09-25 16:10 ` Johannes Schindelin
2017-09-25 17:00   ` Jeff King
     [not found] ` <79ed4c34-1727-7c1e-868a-1206902638ad@gmail.com>
2017-09-27  6:40   ` Jeff King
2017-09-27 13:50     ` Kaartic Sivaraam
2017-09-27 16:28       ` Jeff King
2017-09-27  6:54 ` [PATCH v2] " Jeff King
2017-09-28 16:15   ` Johannes Schindelin

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

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=c474bf47-5049-1425-d03c-2417eb53549e@pobox.com \
    --to=daniel.santos@pobox.com \
    --cc=git@vger.kernel.org \
    --cc=johannes.schindelin@gmx.de \
    --cc=peff@peff.net \
    /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.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

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 read-only IMAP folder(s) and NNTP newsgroup(s).