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,10 +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
1482+ };
1483+
1484+ define_commit_slab (contains_cache , enum contains_result );
1485+
1486+ struct ref_filter_cbdata {
1487+ struct ref_array * array ;
1488+ struct ref_filter * filter ;
1489+ struct contains_cache contains_cache ;
14771490};
14781491
14791492/*
@@ -1504,24 +1517,24 @@ static int in_commit_list(const struct commit_list *want, struct commit *c)
15041517 * Do not recurse to find out, though, but return -1 if inconclusive.
15051518 */
15061519static enum contains_result contains_test (struct commit * candidate ,
1507- const struct commit_list * want )
1520+ const struct commit_list * want ,
1521+ struct contains_cache * cache )
15081522{
1509- /* was it previously marked as containing a want commit? */
1510- if ( candidate -> object . flags & TMP_MARK )
1511- return 1 ;
1512- /* or marked as not possibly containing a want commit? */
1513- if ( candidate -> object . flags & UNINTERESTING )
1514- return 0 ;
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+
15151529 /* or are we it? */
15161530 if (in_commit_list (want , candidate )) {
1517- candidate -> object . flags |= TMP_MARK ;
1518- return 1 ;
1531+ * cached = CONTAINS_YES ;
1532+ return CONTAINS_YES ;
15191533 }
15201534
1521- if (parse_commit (candidate ) < 0 )
1522- return 0 ;
1523-
1524- return -1 ;
1535+ /* Otherwise, we don't know; prepare to recurse */
1536+ parse_commit_or_die (candidate );
1537+ return CONTAINS_UNKNOWN ;
15251538}
15261539
15271540static 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
15321545}
15331546
15341547static enum contains_result contains_tag_algo (struct commit * candidate ,
1535- const struct commit_list * want )
1548+ const struct commit_list * want ,
1549+ struct contains_cache * cache )
15361550{
15371551 struct contains_stack contains_stack = { 0 , 0 , NULL };
1538- int result = contains_test (candidate , want );
1552+ enum contains_result result = contains_test (candidate , want , cache );
15391553
15401554 if (result != CONTAINS_UNKNOWN )
15411555 return result ;
@@ -1547,16 +1561,16 @@ static enum contains_result contains_tag_algo(struct commit *candidate,
15471561 struct commit_list * parents = entry -> parents ;
15481562
15491563 if (!parents ) {
1550- commit -> object . flags |= UNINTERESTING ;
1564+ * contains_cache_at ( cache , commit ) = CONTAINS_NO ;
15511565 contains_stack .nr -- ;
15521566 }
15531567 /*
15541568 * If we just popped the stack, parents->item has been marked,
1555- * therefore contains_test will return a meaningful 0 or 1 .
1569+ * therefore contains_test will return a meaningful yes/no .
15561570 */
1557- else switch (contains_test (parents -> item , want )) {
1571+ else switch (contains_test (parents -> item , want , cache )) {
15581572 case CONTAINS_YES :
1559- commit -> object . flags |= TMP_MARK ;
1573+ * contains_cache_at ( cache , commit ) = CONTAINS_YES ;
15601574 contains_stack .nr -- ;
15611575 break ;
15621576 case CONTAINS_NO :
@@ -1568,13 +1582,14 @@ static enum contains_result contains_tag_algo(struct commit *candidate,
15681582 }
15691583 }
15701584 free (contains_stack .contains_stack );
1571- return contains_test (candidate , want );
1585+ return contains_test (candidate , want , cache );
15721586}
15731587
1574- 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 )
15751590{
15761591 if (filter -> with_commit_tag_algo )
1577- return contains_tag_algo (commit , filter -> with_commit ) ;
1592+ return contains_tag_algo (commit , filter -> with_commit , cache ) == CONTAINS_YES ;
15781593 return is_descendant_of (commit , filter -> with_commit );
15791594}
15801595
@@ -1771,7 +1786,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,
17711786 return 0 ;
17721787 /* We perform the filtering for the '--contains' option */
17731788 if (filter -> with_commit &&
1774- !commit_contains (filter , commit ))
1789+ !commit_contains (filter , commit , & ref_cbdata -> contains_cache ))
17751790 return 0 ;
17761791 }
17771792
@@ -1871,6 +1886,8 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int
18711886 broken = 1 ;
18721887 filter -> kind = type & FILTER_REFS_KIND_MASK ;
18731888
1889+ init_contains_cache (& ref_cbdata .contains_cache );
1890+
18741891 /* Simple per-ref filtering */
18751892 if (!filter -> kind )
18761893 die ("filter_refs: invalid type" );
@@ -1893,6 +1910,7 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int
18931910 head_ref (ref_filter_handler , & ref_cbdata );
18941911 }
18951912
1913+ clear_contains_cache (& ref_cbdata .contains_cache );
18961914
18971915 /* Filters that need revision walking */
18981916 if (filter -> merge_commit )
0 commit comments