Skip to content

repo.Index.Stage() won't notice a change if it occurs within the same second #688

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 4, 2015

Conversation

nulltoken
Copy link
Member

The test below actually fails

[Fact]
public void CanSuccessfullyStageAModifiedFileOfTheSameSizeWithinTheSameSecond()
{
    string repoPath = InitNewRepository();

    using (var repo = new Repository(repoPath))
    {
        for (int i = 0; i < 10; i++)
        {
            Touch(repo.Info.WorkingDirectory, "test.txt",
                       Guid.NewGuid().ToString());

            repo.Index.Stage("test.txt");

            Assert.DoesNotThrow(() => repo.Commit(
                        "Commit", Constants.Signature, Constants.Signature));
        } 
    }
}

See this SO question for some background information.

@nulltoken
Copy link
Member Author

/cc @arrbee @ethomson

@carlosmn
Copy link
Member

I don't recall exactly what Index.Stage() in the lower layers, but this is widespread in the library. If the mtime and size match, we often won't load the new contents of the file.

@nulltoken
Copy link
Member Author

It looks like @arrbee added some foundation code to support this in libgit2/libgit2@e35e268

@arrbee
Copy link
Member

arrbee commented Apr 23, 2014

Yes - it is a problem. If a file appears to have no changes to time and size, then we try not to actually reread it. Despite this, we get libgit2/libgit2#1625 where we do excessive OID calculation and go too slow. It seems like libgit2 is right now being both too forgiving about allowing unchanged stat data to hide a change and too rigid about calculating OIDs for some files that are not changed. I had promised to work on this a while ago - I'll bump it back up the priority list...

@nulltoken
Copy link
Member Author

Related #747

@nulltoken
Copy link
Member Author

@nulltoken
Copy link
Member Author

@nulltoken nulltoken force-pushed the ntk/subsecond_staging branch from 5386591 to 230fed9 Compare June 17, 2015 09:15
@nulltoken
Copy link
Member Author

@carlosmn Rebased on top of latest libgit2. Still failing 😿

@carlosmn
Copy link
Member

The error I see on AppVeyor was due to the null references on the Filter tests, one of the builds did pass fine. I've restarted.

@ethomson
Copy link
Member

Looks like an unrelated failure.

@nulltoken
Copy link
Member Author

Indeed, but randomly fails on my local box.

Applying the following patch

diff --git a/LibGit2Sharp.Tests/StageFixture.cs b/LibGit2Sharp.Tests/StageFixture.cs
index 9a6c624..85633dc 100644
--- a/LibGit2Sharp.Tests/StageFixture.cs
+++ b/LibGit2Sharp.Tests/StageFixture.cs
@@ -382,11 +382,18 @@ public void CanSuccessfullyStageTheContentOfAModifiedFileOfTheSameSizeWithinTheS
             {
                 for (int i = 0; i < 10; i++)
                 {
+                    Console.WriteLine("Iteration " + i);
+
+                    var content = Guid.NewGuid().ToString();
+
                     Touch(repo.Info.WorkingDirectory, "test.txt",
-                               Guid.NewGuid().ToString());
+                               content);
+                    Console.WriteLine("Content = " + content);

                     repo.Stage("test.txt");

+                    Console.WriteLine("Index entry Id = " + repo.Index["test.txt"].Id.Sha);
+
                     Assert.DoesNotThrow(() => repo.Commit(
                                 "Commit", Constants.Signature, Constants.Signature));
                 }

Produces the following output

------ Test started: Assembly: LibGit2Sharp.Tests.dll ------

Test 'LibGit2Sharp.Tests.StageFixture.CanSuccessfullyStageTheContentOfAModifiedFileOfTheSameSizeWithinTheSameSecond' failed:
    Assert.DoesNotThrow() failure
Expected: (No exception)
Actual:   LibGit2Sharp.EmptyCommitException: No changes; nothing to commit.
    Repository.cs(1071,0): at LibGit2Sharp.Repository.Commit(String message, Signature author, Signature committer, CommitOptions options)
    RepositoryExtensions.cs(616,0): at LibGit2Sharp.RepositoryExtensions.Commit(IRepository repository, String message, Signature author, Signature committer)
    StageFixture.cs(397,0): at LibGit2Sharp.Tests.StageFixture.<>c__DisplayClass28.<CanSuccessfullyStageTheContentOfAModifiedFileOfTheSameSizeWithinTheSameSecond>b__26()
    at Xunit.Record.Exception(ThrowsDelegate code)

Output from LibGit2Sharp.Tests.StageFixture.CanSuccessfullyStageTheContentOfAModifiedFileOfTheSameSizeWithinTheSameSecond:
  ProcessInvocation86.exe Information: 0 : Using default test path value
  ProcessInvocation86.exe Information: 0 : Test working directory set to 'C:\Users\Em\AppData\Local\Temp\LibGit2Sharp-TestRepos'
  Iteration 0
  Content = 2baf6bd9-3a2d-46c0-8f87-b818ca6b06c8
  Index entry Id = 4eba44411bf83ca543cae495abf28901dd75c40a
  Iteration 1
  Content = bd1901cf-86fc-4cdd-b6a2-dc5068b9326e
  Index entry Id = d504d7cf49ca3f989a0505fa20f364d8f5b94ed9
  Iteration 2
  Content = 2abd9538-274b-4273-8abe-36e3ac445a96
  Index entry Id = fb139ef35f0025a116f0fff071405f0f83f07879
  Iteration 3
  Content = cf8130ee-ff55-4682-bccf-26d121a614fc
  Index entry Id = d1dd201310f1404b957dc3413e632a86501fc239
  Iteration 4
  Content = 508655ff-1f2a-4d91-ab58-d4a0783e0169
  Index entry Id = d1dd201310f1404b957dc3413e632a86501fc239

0 passed, 1 failed, 0 skipped, took 1,31 seconds (xUnit.net 1.9.2 build 1705).

@nulltoken
Copy link
Member Author

Looks like an unrelated failure.

wrt AppVeyor. I restarted it. It now shows

LibGit2Sharp.Tests.StageFixture.CanSuccessfullyStageTheContentOfAModifiedFileOfTheSameSizeWithinTheSameSecond [FAIL]
   Assert.DoesNotThrow() failure
   Expected: (No exception)
   Actual:   LibGit2Sharp.EmptyCommitException: No changes; nothing to commit.
   Stack Trace:
      c:\projects\libgit2sharp\LibGit2Sharp\Repository.cs(1071,0): at LibGit2Sharp.Repository.Commit(String message, Signature author, Signature committer, CommitOptions options)
      c:\projects\libgit2sharp\LibGit2Sharp.Tests\StageFixture.cs(390,0): at LibGit2Sharp.Tests.StageFixture.<>c__DisplayClass28.<CanSuccessfullyStageTheContentOfAModifiedFileOfTheSameSizeWithinTheSameSecond>b__26()
      at Xunit.Record.Exception(ThrowsDelegate code)

@carlosmn
Copy link
Member

I've been adding my own debug prints (including collecting the sizes into the managed struct) and it looks like we do behave exactly as we should wrt zeroing out files with the same timestamp as the index, which is the bit which we just merged a fix for.

When it fails to update the entry (and thus have this error happen) is when an iteration happens across the second barrier, and the rewritten test.txt is e.g. at second 24 and the index was last written at second 23 (which was the prvious iteration). During this iteration , the timestamps won't match and we'll write out the object/file's size (in this case 36) so we won't force a re-read the next time.

And it is in the iteration after the one I've described above that we fail to detect the size of the file. This is odd, as I was sure this did in fact work. The timestamps are different, so we have to re-read the file to check. I suspect a timestamp going backwards on us, which IIRC FAT can do, though I'm not sure if NTFS is capable of such a feat.

@carlosmn
Copy link
Member

So, a two-year-old TODO to actually implement the bit I was sure we already had Is what bit us. If you run this on top of libgit2/libgit2#3226 you should be unable to make it fail.

@carlosmn
Copy link
Member

Now for reals, putting this on top of libgit2's master really should make it work.

@nulltoken nulltoken force-pushed the ntk/subsecond_staging branch 2 times, most recently from 49778e4 to 794a8bd Compare June 30, 2015 22:10
@nulltoken nulltoken force-pushed the ntk/subsecond_staging branch from 794a8bd to db02403 Compare July 4, 2015 17:37
nulltoken added a commit that referenced this pull request Jul 4, 2015
repo.Index.Stage() won't notice a change if it occurs within the same second
@nulltoken nulltoken merged commit 302c162 into vNext Jul 4, 2015
@nulltoken nulltoken deleted the ntk/subsecond_staging branch July 4, 2015 17:45
@nulltoken nulltoken added this to the v0.22 milestone Jul 4, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants