summaryrefslogtreecommitdiff
path: root/ref-filter.c
diff options
context:
space:
mode:
authorDerrick Stolee <dstolee@microsoft.com>2018-05-01 12:47:15 (GMT)
committerJunio C Hamano <gitster@pobox.com>2018-05-22 03:36:34 (GMT)
commit819807b33f820dc17d96f043747daf18c5e38516 (patch)
treea631978767968ce79e76f5937e998f1d8a18d03e /ref-filter.c
parente2838d85b6d35592ff5851d67f0232a78083ada7 (diff)
downloadgit-819807b33f820dc17d96f043747daf18c5e38516.zip
git-819807b33f820dc17d96f043747daf18c5e38516.tar.gz
git-819807b33f820dc17d96f043747daf18c5e38516.tar.bz2
ref-filter: use generation number for --contains
A commit A can reach a commit B only if the generation number of A is strictly larger than the generation number of B. This condition allows significantly short-circuiting commit-graph walks. Use generation number for '--contains' type queries. On a copy of the Linux repository where HEAD is contained in v4.13 but no earlier tag, the command 'git tag --contains HEAD' had the following peformance improvement: Before: 0.81s After: 0.04s Rel %: -95% Helped-by: Jeff King <peff@peff.net> Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'ref-filter.c')
-rw-r--r--ref-filter.c24
1 files changed, 20 insertions, 4 deletions
diff --git a/ref-filter.c b/ref-filter.c
index aff24d9..fb35067 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -16,6 +16,7 @@
#include "trailer.h"
#include "wt-status.h"
#include "commit-slab.h"
+#include "commit-graph.h"
static struct ref_msg {
const char *gone;
@@ -1587,7 +1588,8 @@ static int in_commit_list(const struct commit_list *want, struct commit *c)
*/
static enum contains_result contains_test(struct commit *candidate,
const struct commit_list *want,
- struct contains_cache *cache)
+ struct contains_cache *cache,
+ uint32_t cutoff)
{
enum contains_result *cached = contains_cache_at(cache, candidate);
@@ -1603,6 +1605,10 @@ static enum contains_result contains_test(struct commit *candidate,
/* Otherwise, we don't know; prepare to recurse */
parse_commit_or_die(candidate);
+
+ if (candidate->generation < cutoff)
+ return CONTAINS_NO;
+
return CONTAINS_UNKNOWN;
}
@@ -1618,8 +1624,18 @@ static enum contains_result contains_tag_algo(struct commit *candidate,
struct contains_cache *cache)
{
struct contains_stack contains_stack = { 0, 0, NULL };
- enum contains_result result = contains_test(candidate, want, cache);
+ enum contains_result result;
+ uint32_t cutoff = GENERATION_NUMBER_INFINITY;
+ const struct commit_list *p;
+
+ for (p = want; p; p = p->next) {
+ struct commit *c = p->item;
+ load_commit_graph_info(c);
+ if (c->generation < cutoff)
+ cutoff = c->generation;
+ }
+ result = contains_test(candidate, want, cache, cutoff);
if (result != CONTAINS_UNKNOWN)
return result;
@@ -1637,7 +1653,7 @@ static enum contains_result contains_tag_algo(struct commit *candidate,
* If we just popped the stack, parents->item has been marked,
* therefore contains_test will return a meaningful yes/no.
*/
- else switch (contains_test(parents->item, want, cache)) {
+ else switch (contains_test(parents->item, want, cache, cutoff)) {
case CONTAINS_YES:
*contains_cache_at(cache, commit) = CONTAINS_YES;
contains_stack.nr--;
@@ -1651,7 +1667,7 @@ static enum contains_result contains_tag_algo(struct commit *candidate,
}
}
free(contains_stack.contains_stack);
- return contains_test(candidate, want, cache);
+ return contains_test(candidate, want, cache, cutoff);
}
static int commit_contains(struct ref_filter *filter, struct commit *commit,