Merge branch 'jk/ref-filter-flags-cleanup'

"git tag --contains" used to (ab)use the object bits to keep track
of the state of object reachability without clearing them after
use; this has been cleaned up and made to use the newer commit-slab
facility.

* jk/ref-filter-flags-cleanup:
  ref-filter: use separate cache for contains_tag_algo
  ref-filter: die on parse_commit errors
  ref-filter: use contains_result enum consistently
  ref-filter: move ref_cbdata definition into ref-filter.c
This commit is contained in:
Junio C Hamano 2017-03-17 13:50:25 -07:00
commit 60cf6cd71a
2 changed files with 44 additions and 31 deletions

View File

@ -15,6 +15,7 @@
#include "version.h" #include "version.h"
#include "trailer.h" #include "trailer.h"
#include "wt-status.h" #include "wt-status.h"
#include "commit-slab.h"
static struct ref_msg { static struct ref_msg {
const char *gone; const char *gone;
@ -1470,10 +1471,22 @@ static void get_ref_atom_value(struct ref_array_item *ref, int atom, struct atom
*v = &ref->value[atom]; *v = &ref->value[atom];
} }
/*
* Unknown has to be "0" here, because that's the default value for
* contains_cache slab entries that have not yet been assigned.
*/
enum contains_result { enum contains_result {
CONTAINS_UNKNOWN = -1, CONTAINS_UNKNOWN = 0,
CONTAINS_NO = 0, CONTAINS_NO,
CONTAINS_YES = 1 CONTAINS_YES
};
define_commit_slab(contains_cache, enum contains_result);
struct ref_filter_cbdata {
struct ref_array *array;
struct ref_filter *filter;
struct contains_cache contains_cache;
}; };
/* /*
@ -1504,24 +1517,24 @@ static int in_commit_list(const struct commit_list *want, struct commit *c)
* Do not recurse to find out, though, but return -1 if inconclusive. * Do not recurse to find out, though, but return -1 if inconclusive.
*/ */
static enum contains_result contains_test(struct commit *candidate, static enum contains_result contains_test(struct commit *candidate,
const struct commit_list *want) const struct commit_list *want,
struct contains_cache *cache)
{ {
/* was it previously marked as containing a want commit? */ enum contains_result *cached = contains_cache_at(cache, candidate);
if (candidate->object.flags & TMP_MARK)
return 1; /* If we already have the answer cached, return that. */
/* or marked as not possibly containing a want commit? */ if (*cached)
if (candidate->object.flags & UNINTERESTING) return *cached;
return 0;
/* or are we it? */ /* or are we it? */
if (in_commit_list(want, candidate)) { if (in_commit_list(want, candidate)) {
candidate->object.flags |= TMP_MARK; *cached = CONTAINS_YES;
return 1; return CONTAINS_YES;
} }
if (parse_commit(candidate) < 0) /* Otherwise, we don't know; prepare to recurse */
return 0; parse_commit_or_die(candidate);
return CONTAINS_UNKNOWN;
return -1;
} }
static void push_to_contains_stack(struct commit *candidate, struct contains_stack *contains_stack) static void push_to_contains_stack(struct commit *candidate, struct contains_stack *contains_stack)
@ -1532,10 +1545,11 @@ static void push_to_contains_stack(struct commit *candidate, struct contains_sta
} }
static enum contains_result contains_tag_algo(struct commit *candidate, static enum contains_result contains_tag_algo(struct commit *candidate,
const struct commit_list *want) const struct commit_list *want,
struct contains_cache *cache)
{ {
struct contains_stack contains_stack = { 0, 0, NULL }; struct contains_stack contains_stack = { 0, 0, NULL };
int result = contains_test(candidate, want); enum contains_result result = contains_test(candidate, want, cache);
if (result != CONTAINS_UNKNOWN) if (result != CONTAINS_UNKNOWN)
return result; return result;
@ -1547,16 +1561,16 @@ static enum contains_result contains_tag_algo(struct commit *candidate,
struct commit_list *parents = entry->parents; struct commit_list *parents = entry->parents;
if (!parents) { if (!parents) {
commit->object.flags |= UNINTERESTING; *contains_cache_at(cache, commit) = CONTAINS_NO;
contains_stack.nr--; contains_stack.nr--;
} }
/* /*
* If we just popped the stack, parents->item has been marked, * If we just popped the stack, parents->item has been marked,
* therefore contains_test will return a meaningful 0 or 1. * therefore contains_test will return a meaningful yes/no.
*/ */
else switch (contains_test(parents->item, want)) { else switch (contains_test(parents->item, want, cache)) {
case CONTAINS_YES: case CONTAINS_YES:
commit->object.flags |= TMP_MARK; *contains_cache_at(cache, commit) = CONTAINS_YES;
contains_stack.nr--; contains_stack.nr--;
break; break;
case CONTAINS_NO: case CONTAINS_NO:
@ -1568,13 +1582,14 @@ static enum contains_result contains_tag_algo(struct commit *candidate,
} }
} }
free(contains_stack.contains_stack); free(contains_stack.contains_stack);
return contains_test(candidate, want); return contains_test(candidate, want, cache);
} }
static int commit_contains(struct ref_filter *filter, struct commit *commit) static int commit_contains(struct ref_filter *filter, struct commit *commit,
struct contains_cache *cache)
{ {
if (filter->with_commit_tag_algo) if (filter->with_commit_tag_algo)
return contains_tag_algo(commit, filter->with_commit); return contains_tag_algo(commit, filter->with_commit, cache) == CONTAINS_YES;
return is_descendant_of(commit, filter->with_commit); return is_descendant_of(commit, filter->with_commit);
} }
@ -1771,7 +1786,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,
return 0; return 0;
/* We perform the filtering for the '--contains' option */ /* We perform the filtering for the '--contains' option */
if (filter->with_commit && if (filter->with_commit &&
!commit_contains(filter, commit)) !commit_contains(filter, commit, &ref_cbdata->contains_cache))
return 0; return 0;
} }
@ -1871,6 +1886,8 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int
broken = 1; broken = 1;
filter->kind = type & FILTER_REFS_KIND_MASK; filter->kind = type & FILTER_REFS_KIND_MASK;
init_contains_cache(&ref_cbdata.contains_cache);
/* Simple per-ref filtering */ /* Simple per-ref filtering */
if (!filter->kind) if (!filter->kind)
die("filter_refs: invalid type"); die("filter_refs: invalid type");
@ -1893,6 +1910,7 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int
head_ref(ref_filter_handler, &ref_cbdata); head_ref(ref_filter_handler, &ref_cbdata);
} }
clear_contains_cache(&ref_cbdata.contains_cache);
/* Filters that need revision walking */ /* Filters that need revision walking */
if (filter->merge_commit) if (filter->merge_commit)

View File

@ -71,11 +71,6 @@ struct ref_filter {
verbose; verbose;
}; };
struct ref_filter_cbdata {
struct ref_array *array;
struct ref_filter *filter;
};
/* Macros for checking --merged and --no-merged options */ /* Macros for checking --merged and --no-merged options */
#define _OPT_MERGED_NO_MERGED(option, filter, h) \ #define _OPT_MERGED_NO_MERGED(option, filter, h) \
{ OPTION_CALLBACK, 0, option, (filter), N_("commit"), (h), \ { OPTION_CALLBACK, 0, option, (filter), N_("commit"), (h), \