1515#include "version.h"
1616#include "trailer.h"
1717#include "wt-status.h"
18+ #include "commit-slab.h"
1819
1920static struct ref_msg {
2021 const char * gone ;
@@ -1470,15 +1471,22 @@ static void get_ref_atom_value(struct ref_array_item *ref, int atom, struct atom
14701471 * v = & ref -> value [atom ];
14711472}
14721473
1474+ /*
1475+ * Unknown has to be "0" here, because that's the default value for
1476+ * contains_cache slab entries that have not yet been assigned.
1477+ */
14731478enum contains_result {
1474- CONTAINS_UNKNOWN = -1 ,
1475- CONTAINS_NO = 0 ,
1476- CONTAINS_YES = 1
1479+ CONTAINS_UNKNOWN = 0 ,
1480+ CONTAINS_NO ,
1481+ CONTAINS_YES
14771482};
14781483
1484+ define_commit_slab (contains_cache , enum contains_result );
1485+
14791486struct ref_filter_cbdata {
14801487 struct ref_array * array ;
14811488 struct ref_filter * filter ;
1489+ struct contains_cache contains_cache ;
14821490};
14831491
14841492/*
@@ -1509,20 +1517,22 @@ static int in_commit_list(const struct commit_list *want, struct commit *c)
15091517 * Do not recurse to find out, though, but return -1 if inconclusive.
15101518 */
15111519static enum contains_result contains_test (struct commit * candidate ,
1512- const struct commit_list * want )
1520+ const struct commit_list * want ,
1521+ struct contains_cache * cache )
15131522{
1514- /* was it previously marked as containing a want commit? */
1515- if ( candidate -> object . flags & TMP_MARK )
1516- return CONTAINS_YES ;
1517- /* or marked as not possibly containing a want commit? */
1518- if ( candidate -> object . flags & UNINTERESTING )
1519- return CONTAINS_NO ;
1523+ enum contains_result * cached = contains_cache_at ( cache , candidate );
1524+
1525+ /* If we already have the answer cached, return that. */
1526+ if ( * cached )
1527+ return * cached ;
1528+
15201529 /* or are we it? */
15211530 if (in_commit_list (want , candidate )) {
1522- candidate -> object . flags |= TMP_MARK ;
1531+ * cached = CONTAINS_YES ;
15231532 return CONTAINS_YES ;
15241533 }
15251534
1535+ /* Otherwise, we don't know; prepare to recurse */
15261536 parse_commit_or_die (candidate );
15271537 return CONTAINS_UNKNOWN ;
15281538}
@@ -1535,10 +1545,11 @@ static void push_to_contains_stack(struct commit *candidate, struct contains_sta
15351545}
15361546
15371547static enum contains_result contains_tag_algo (struct commit * candidate ,
1538- const struct commit_list * want )
1548+ const struct commit_list * want ,
1549+ struct contains_cache * cache )
15391550{
15401551 struct contains_stack contains_stack = { 0 , 0 , NULL };
1541- enum contains_result result = contains_test (candidate , want );
1552+ enum contains_result result = contains_test (candidate , want , cache );
15421553
15431554 if (result != CONTAINS_UNKNOWN )
15441555 return result ;
@@ -1550,16 +1561,16 @@ static enum contains_result contains_tag_algo(struct commit *candidate,
15501561 struct commit_list * parents = entry -> parents ;
15511562
15521563 if (!parents ) {
1553- commit -> object . flags |= UNINTERESTING ;
1564+ * contains_cache_at ( cache , commit ) = CONTAINS_NO ;
15541565 contains_stack .nr -- ;
15551566 }
15561567 /*
15571568 * If we just popped the stack, parents->item has been marked,
15581569 * therefore contains_test will return a meaningful yes/no.
15591570 */
1560- else switch (contains_test (parents -> item , want )) {
1571+ else switch (contains_test (parents -> item , want , cache )) {
15611572 case CONTAINS_YES :
1562- commit -> object . flags |= TMP_MARK ;
1573+ * contains_cache_at ( cache , commit ) = CONTAINS_YES ;
15631574 contains_stack .nr -- ;
15641575 break ;
15651576 case CONTAINS_NO :
@@ -1571,13 +1582,14 @@ static enum contains_result contains_tag_algo(struct commit *candidate,
15711582 }
15721583 }
15731584 free (contains_stack .contains_stack );
1574- return contains_test (candidate , want );
1585+ return contains_test (candidate , want , cache );
15751586}
15761587
1577- static int commit_contains (struct ref_filter * filter , struct commit * commit )
1588+ static int commit_contains (struct ref_filter * filter , struct commit * commit ,
1589+ struct contains_cache * cache )
15781590{
15791591 if (filter -> with_commit_tag_algo )
1580- return contains_tag_algo (commit , filter -> with_commit ) == CONTAINS_YES ;
1592+ return contains_tag_algo (commit , filter -> with_commit , cache ) == CONTAINS_YES ;
15811593 return is_descendant_of (commit , filter -> with_commit );
15821594}
15831595
@@ -1774,7 +1786,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,
17741786 return 0 ;
17751787 /* We perform the filtering for the '--contains' option */
17761788 if (filter -> with_commit &&
1777- !commit_contains (filter , commit ))
1789+ !commit_contains (filter , commit , & ref_cbdata -> contains_cache ))
17781790 return 0 ;
17791791 }
17801792
@@ -1874,6 +1886,8 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int
18741886 broken = 1 ;
18751887 filter -> kind = type & FILTER_REFS_KIND_MASK ;
18761888
1889+ init_contains_cache (& ref_cbdata .contains_cache );
1890+
18771891 /* Simple per-ref filtering */
18781892 if (!filter -> kind )
18791893 die ("filter_refs: invalid type" );
@@ -1896,6 +1910,7 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int
18961910 head_ref (ref_filter_handler , & ref_cbdata );
18971911 }
18981912
1913+ clear_contains_cache (& ref_cbdata .contains_cache );
18991914
19001915 /* Filters that need revision walking */
19011916 if (filter -> merge_commit )
0 commit comments