<feed xmlns='http://www.w3.org/2005/Atom'>
<title>delta/git.git, branch jk/has-sha1-file-retry-packed</title>
<subtitle>github.com: git/git.git
</subtitle>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/git.git/'/>
<entry>
<title>has_sha1_file: re-check pack directory before giving up</title>
<updated>2013-08-30T21:53:45+00:00</updated>
<author>
<name>Jeff King</name>
<email>peff@peff.net</email>
</author>
<published>2013-08-30T19:14:13+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/git.git/commit/?id=45e8a7487339c0f0ea28244ef06851308d07387c'/>
<id>45e8a7487339c0f0ea28244ef06851308d07387c</id>
<content type='text'>
When we read a sha1 file, we first look for a packed
version, then a loose version, and then re-check the pack
directory again before concluding that we cannot find it.
This lets us handle a process that is writing to the
repository simultaneously (e.g., receive-pack writing a new
pack followed by a ref update, or git-repack packing
existing loose objects into a new pack).

However, we do not do the same trick with has_sha1_file; we
only check the packed objects once, followed by loose
objects. This means that we might incorrectly report that we
do not have an object, even though we could find it if we
simply re-checked the pack directory.

By itself, this is usually not a big deal. The other process
is running simultaneously, so we may run has_sha1_file
before it writes, anyway. It is a race whether we see the
object or not.  However, we may also see other things
the writing process has done (like updating refs); and in
that case, we must be able to also see the new objects.

For example, imagine we are doing a for_each_ref iteration,
and somebody simultaneously pushes. Receive-pack may write
the pack and update a ref after we have examined the
objects/pack directory, but before the iteration gets to the
updated ref. When we do finally see the updated ref,
for_each_ref will call has_sha1_file to check whether the
ref is broken. If has_sha1_file returns the wrong answer, we
erroneously will think that the ref is broken.

For a normal iteration without DO_FOR_EACH_INCLUDE_BROKEN,
this means that the caller does not see the ref at all
(neither the old nor the new value).  So not only will we
fail to see the new value of the ref (which is acceptable,
since we are running simultaneously with the writer, and we
might well read the ref before the writer commits its
write), but we will not see the old value either. For
programs that act on reachability like pack-objects or
prune, this can cause data loss, as we may see the objects
referenced by the original ref value as dangling (and either
omit them from the pack, or delete them via prune).

There's no test included here, because the success case is
two processes running simultaneously forever. But you can
replicate the issue with:

  # base.sh
  # run this in one terminal; it creates and pushes
  # repeatedly to a repository
  git init parent &amp;&amp;
  (cd parent &amp;&amp;

    # create a base commit that will trigger us looking at
    # the objects/pack directory before we hit the updated ref
    echo content &gt;file &amp;&amp;
    git add file &amp;&amp;
    git commit -m base &amp;&amp;

    # set the unpack limit abnormally low, which
    # lets us simulate full-size pushes using tiny ones
    git config receive.unpackLimit 1
  ) &amp;&amp;
  git clone parent child &amp;&amp;
  cd child &amp;&amp;
  n=0 &amp;&amp;
  while true; do
    echo $n &gt;file &amp;&amp; git add file &amp;&amp; git commit -m $n &amp;&amp;
    git push origin HEAD:refs/remotes/child/master &amp;&amp;
    n=$(($n + 1))
  done

  # fsck.sh
  # now run this simultaneously in another terminal; it
  # repeatedly fscks, looking for us to consider the
  # newly-pushed ref broken. We cannot use for-each-ref
  # here, as it uses DO_FOR_EACH_INCLUDE_BROKEN, which
  # skips the has_sha1_file check (and if it wants
  # more information on the object, it will actually read
  # the object, which does the proper two-step lookup)
  cd parent &amp;&amp;
  while true; do
    broken=`git fsck 2&gt;&amp;1 | grep remotes/child`
    if test -n "$broken"; then
      echo $broken
      exit 1
    fi
  done

Without this patch, the fsck loop fails within a few seconds
(and almost instantly if the test repository actually has a
large number of refs). With it, the two can run
indefinitely.

Signed-off-by: Jeff King &lt;peff@peff.net&gt;
Signed-off-by: Junio C Hamano &lt;gitster@pobox.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
When we read a sha1 file, we first look for a packed
version, then a loose version, and then re-check the pack
directory again before concluding that we cannot find it.
This lets us handle a process that is writing to the
repository simultaneously (e.g., receive-pack writing a new
pack followed by a ref update, or git-repack packing
existing loose objects into a new pack).

However, we do not do the same trick with has_sha1_file; we
only check the packed objects once, followed by loose
objects. This means that we might incorrectly report that we
do not have an object, even though we could find it if we
simply re-checked the pack directory.

By itself, this is usually not a big deal. The other process
is running simultaneously, so we may run has_sha1_file
before it writes, anyway. It is a race whether we see the
object or not.  However, we may also see other things
the writing process has done (like updating refs); and in
that case, we must be able to also see the new objects.

For example, imagine we are doing a for_each_ref iteration,
and somebody simultaneously pushes. Receive-pack may write
the pack and update a ref after we have examined the
objects/pack directory, but before the iteration gets to the
updated ref. When we do finally see the updated ref,
for_each_ref will call has_sha1_file to check whether the
ref is broken. If has_sha1_file returns the wrong answer, we
erroneously will think that the ref is broken.

For a normal iteration without DO_FOR_EACH_INCLUDE_BROKEN,
this means that the caller does not see the ref at all
(neither the old nor the new value).  So not only will we
fail to see the new value of the ref (which is acceptable,
since we are running simultaneously with the writer, and we
might well read the ref before the writer commits its
write), but we will not see the old value either. For
programs that act on reachability like pack-objects or
prune, this can cause data loss, as we may see the objects
referenced by the original ref value as dangling (and either
omit them from the pack, or delete them via prune).

There's no test included here, because the success case is
two processes running simultaneously forever. But you can
replicate the issue with:

  # base.sh
  # run this in one terminal; it creates and pushes
  # repeatedly to a repository
  git init parent &amp;&amp;
  (cd parent &amp;&amp;

    # create a base commit that will trigger us looking at
    # the objects/pack directory before we hit the updated ref
    echo content &gt;file &amp;&amp;
    git add file &amp;&amp;
    git commit -m base &amp;&amp;

    # set the unpack limit abnormally low, which
    # lets us simulate full-size pushes using tiny ones
    git config receive.unpackLimit 1
  ) &amp;&amp;
  git clone parent child &amp;&amp;
  cd child &amp;&amp;
  n=0 &amp;&amp;
  while true; do
    echo $n &gt;file &amp;&amp; git add file &amp;&amp; git commit -m $n &amp;&amp;
    git push origin HEAD:refs/remotes/child/master &amp;&amp;
    n=$(($n + 1))
  done

  # fsck.sh
  # now run this simultaneously in another terminal; it
  # repeatedly fscks, looking for us to consider the
  # newly-pushed ref broken. We cannot use for-each-ref
  # here, as it uses DO_FOR_EACH_INCLUDE_BROKEN, which
  # skips the has_sha1_file check (and if it wants
  # more information on the object, it will actually read
  # the object, which does the proper two-step lookup)
  cd parent &amp;&amp;
  while true; do
    broken=`git fsck 2&gt;&amp;1 | grep remotes/child`
    if test -n "$broken"; then
      echo $broken
      exit 1
    fi
  done

Without this patch, the fsck loop fails within a few seconds
(and almost instantly if the test repository actually has a
large number of refs). With it, the two can run
indefinitely.

Signed-off-by: Jeff King &lt;peff@peff.net&gt;
Signed-off-by: Junio C Hamano &lt;gitster@pobox.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Git 1.8.4</title>
<updated>2013-08-23T18:49:46+00:00</updated>
<author>
<name>Junio C Hamano</name>
<email>gitster@pobox.com</email>
</author>
<published>2013-08-23T18:49:46+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/git.git/commit/?id=e230c568c4b9a991e3175e5f65171a566fd8e39c'/>
<id>e230c568c4b9a991e3175e5f65171a566fd8e39c</id>
<content type='text'>
Signed-off-by: Junio C Hamano &lt;gitster@pobox.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Signed-off-by: Junio C Hamano &lt;gitster@pobox.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Typofix draft release notes to 1.8.4</title>
<updated>2013-08-21T22:30:04+00:00</updated>
<author>
<name>Junio C Hamano</name>
<email>gitster@pobox.com</email>
</author>
<published>2013-08-21T22:30:04+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/git.git/commit/?id=0d8beaa5b76e824c9869f0d1f1b19ec7acf4982f'/>
<id>0d8beaa5b76e824c9869f0d1f1b19ec7acf4982f</id>
<content type='text'>
Signed-off-by: Junio C Hamano &lt;gitster@pobox.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Signed-off-by: Junio C Hamano &lt;gitster@pobox.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Git 1.8.4-rc4</title>
<updated>2013-08-19T17:34:14+00:00</updated>
<author>
<name>Junio C Hamano</name>
<email>gitster@pobox.com</email>
</author>
<published>2013-08-19T17:34:14+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/git.git/commit/?id=4d06473928ee574910accbde05c19ef2263abdf6'/>
<id>4d06473928ee574910accbde05c19ef2263abdf6</id>
<content type='text'>
As we had to revert two topics at the last minute, let's have
another (hopefully short) round of rc to make sure the final release
will be sound.

Signed-off-by: Junio C Hamano &lt;gitster@pobox.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
As we had to revert two topics at the last minute, let's have
another (hopefully short) round of rc to make sure the final release
will be sound.

Signed-off-by: Junio C Hamano &lt;gitster@pobox.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Revert "Add new @ shortcut for HEAD"</title>
<updated>2013-08-14T22:04:24+00:00</updated>
<author>
<name>Junio C Hamano</name>
<email>gitster@pobox.com</email>
</author>
<published>2013-08-14T17:57:24+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/git.git/commit/?id=2c2b6646c2723459dbd334c7ced6f77ffb0d596e'/>
<id>2c2b6646c2723459dbd334c7ced6f77ffb0d596e</id>
<content type='text'>
This reverts commit cdfd94837b27c220f70f032b596ea993d195488f, as it
does not just apply to "@" (and forms with modifiers like @{u}
applied to it), but also affects e.g. "refs/heads/@/foo", which it
shouldn't.

The basic idea of giving a short-hand might be good, and the topic
can be retried later, but let's revert to avoid affecting existing
use cases for now for the upcoming release.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This reverts commit cdfd94837b27c220f70f032b596ea993d195488f, as it
does not just apply to "@" (and forms with modifiers like @{u}
applied to it), but also affects e.g. "refs/heads/@/foo", which it
shouldn't.

The basic idea of giving a short-hand might be good, and the topic
can be retried later, but let's revert to avoid affecting existing
use cases for now for the upcoming release.
</pre>
</div>
</content>
</entry>
<entry>
<title>Revert "git stash: avoid data loss when "git stash save" kills a directory"</title>
<updated>2013-08-14T16:53:43+00:00</updated>
<author>
<name>Junio C Hamano</name>
<email>gitster@pobox.com</email>
</author>
<published>2013-08-14T16:53:43+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/git.git/commit/?id=c1ebd90c832e28ff27654c21f9985aebe986352d'/>
<id>c1ebd90c832e28ff27654c21f9985aebe986352d</id>
<content type='text'>
This reverts commit a73653130edd6a8977106d45a8092c09040f9132, as it
has been reported that "ls-files --killed" is too time-consuming in
a deep directory with too many untracked crufts (e.g. $HOME/.git
tracking only a few files).

We'd need to revisit it later but "ls-files --killed" needs to be
optimized before it happens.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This reverts commit a73653130edd6a8977106d45a8092c09040f9132, as it
has been reported that "ls-files --killed" is too time-consuming in
a deep directory with too many untracked crufts (e.g. $HOME/.git
tracking only a few files).

We'd need to revisit it later but "ls-files --killed" needs to be
optimized before it happens.
</pre>
</div>
</content>
</entry>
<entry>
<title>Git 1.8.4-rc3</title>
<updated>2013-08-13T18:10:18+00:00</updated>
<author>
<name>Junio C Hamano</name>
<email>gitster@pobox.com</email>
</author>
<published>2013-08-13T18:10:18+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/git.git/commit/?id=425df881e08bed7a8fcc9a23f452cff792f9ec6c'/>
<id>425df881e08bed7a8fcc9a23f452cff792f9ec6c</id>
<content type='text'>
Signed-off-by: Junio C Hamano &lt;gitster@pobox.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Signed-off-by: Junio C Hamano &lt;gitster@pobox.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Merge git://github.com/git-l10n/git-po</title>
<updated>2013-08-13T17:50:01+00:00</updated>
<author>
<name>Junio C Hamano</name>
<email>gitster@pobox.com</email>
</author>
<published>2013-08-13T17:50:01+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/git.git/commit/?id=eaaec50fcd705b10f59e1104e22914f844eaf4de'/>
<id>eaaec50fcd705b10f59e1104e22914f844eaf4de</id>
<content type='text'>
* git://github.com/git-l10n/git-po:
  l10n: Add reference for french translation team
  l10n: fr.po: 821/2112 messages translated
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
* git://github.com/git-l10n/git-po:
  l10n: Add reference for french translation team
  l10n: fr.po: 821/2112 messages translated
</pre>
</div>
</content>
</entry>
<entry>
<title>Merge branch 'sb/mailmap-updates'</title>
<updated>2013-08-13T17:49:33+00:00</updated>
<author>
<name>Junio C Hamano</name>
<email>gitster@pobox.com</email>
</author>
<published>2013-08-13T17:49:33+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/git.git/commit/?id=2809258c28b92add5dfa0b72703c477a7f5ac0ff'/>
<id>2809258c28b92add5dfa0b72703c477a7f5ac0ff</id>
<content type='text'>
* sb/mailmap-updates:
  .mailmap: Combine more (name, email) to individual persons
  .mailmap: update long-lost friends with multiple defunct addresses
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
* sb/mailmap-updates:
  .mailmap: Combine more (name, email) to individual persons
  .mailmap: update long-lost friends with multiple defunct addresses
</pre>
</div>
</content>
</entry>
<entry>
<title>.mailmap: Combine more (name, email) to individual persons</title>
<updated>2013-08-13T17:49:06+00:00</updated>
<author>
<name>Stefan Beller</name>
<email>stefanbeller@googlemail.com</email>
</author>
<published>2013-08-12T08:12:09+00:00</published>
<link rel='alternate' type='text/html' href='http://git.baserock.org/cgit/delta/git.git/commit/?id=cdb6b5ac67a48e6d25eb44dd2d632b60cfc7b743'/>
<id>cdb6b5ac67a48e6d25eb44dd2d632b60cfc7b743</id>
<content type='text'>
Signed-off-by: Stefan Beller &lt;stefanbeller@googlemail.com&gt;
Signed-off-by: Junio C Hamano &lt;gitster@pobox.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Signed-off-by: Stefan Beller &lt;stefanbeller@googlemail.com&gt;
Signed-off-by: Junio C Hamano &lt;gitster@pobox.com&gt;
</pre>
</div>
</content>
</entry>
</feed>
