libgit2/libgit2 — pull request #2308 by arrbee (2014-04-28 22:13:51+00:00)
Title: Reduce excessive OID calculation for diff and stat

To begin to address #1625, this makes two changes that should help reduce the discrepancy between libgit2 and core Git.

1. Add logic so that when a file's size and/or mode have clearly changed from the index value, then we don't bother calculating the OID for the working directory entry to mark it as MODIFIED. This optimization reduced the number of OID calculations in my simple example code by about 40%.

The cost of this is that there is an increased possibility that we will mark a file as modified that will yield an empty diff when the text diffs are actually generated (probably due to line-ending filtering). However, from the testing I've done with command-line Git, it appears we actually match the behavior of the command-line now. (The `test_status_worktree__line_endings_dont_count_as_changes_with_autocrlf` test had to be changed to account for this.)

2. Add a new flag `GIT_DIFF_UPDATE_INDEX` which will refresh the index stat cache when we are forced to calculate the OID of a file and it turns out that the file in question is actually unchanged. In my tests, this was able to remove the remaining OID calculations in successive runs of `git_diff_index_to_workdir`. Right now, this flag defaults to being off, but it would allow a saavy user of libgit2 to more easily keep the stat cache up-to-date and minimize work.

Some other changes that deserve comment (and potential reviewers should know about):

* I've added a new compile option `GIT_PERF` that can be used to activate internal counters for performance measurement. I'm not sure how folks will feel about the route I've gone here, but I didn't have a great alternative for checking that `GIT_DIFF_UPDATE_INDEX` was going to do what I wanted, plus it was fun to see the other optimizations improve these numbers.
* Because of how I implemented the stat cache refresh code, I've also ended up making the `path` member of the `git_index_entry` struct be a `const char *` instead of just a `char *`. It really isn't safe to be modifying the path of an existing entry anyhow, so I don't think this will be a big deal, but it is a change to the public declaration of the `git_index_entry` struct.

- [x] Add a way to measure diff performance from tests
- [x] Optimize case where stat cache seems valid and file seems definitely modified
- [x] Add `GIT_DIFF_UPDATE_INDEX` option to refresh stat cache
- [ ] Add `GIT_STATUS_UPDATE_INDEX` option to refresh stat cache