@matheusbsbs / matheus-bagliano / commits / eb42feca97
Fork 0

unpack-trees: hash less in cone mode

The sparse-checkout feature in "cone mode" can use the fact that the recursive patterns are "connected" to the root via parent patterns to decide if a directory is entirely contained in the sparse-checkout or entirely removed. In these cases, we can skip hashing the paths within those directories and simply set the skipworktree bit to the correct value. Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Derrick Stolee committed Nov 21, 2019 at 22:04 UTC eb42feca974a333e58c2ca0f3cfa8bf0dd421402
3 files changed +26 -17
dir.c
+2 -2
@@ -1270,7 +1270,7 @@ enum pattern_match_result path_matches_pattern_list(
1270
1271 if (hashmap_contains_path(&pl->recursive_hashmap,
1272 &parent_pathname)) {
1273 - result = MATCHED;
1273 + result = MATCHED_RECURSIVE;
1274 goto done;
1275 }
1276
@@ -1292,7 +1292,7 @@ enum pattern_match_result path_matches_pattern_list(
1292 if (hashmap_contains_parent(&pl->recursive_hashmap,
1293 pathname,
1294 &parent_pathname))
1295 - result = MATCHED;
1295 + result = MATCHED_RECURSIVE;
1296
1297 done:
1298 strbuf_release(&parent_pathname);
dir.h
+1
@@ -264,6 +264,7 @@ enum pattern_match_result {
264 UNDECIDED = -1,
265 NOT_MATCHED = 0,
266 MATCHED = 1,
267 + MATCHED_RECURSIVE = 2,
268 };
269
270 /*
unpack-trees.c
+23 -15
@@ -1283,15 +1283,17 @@ static int clear_ce_flags_dir(struct index_state *istate,
1283 struct cache_entry **cache_end;
1284 int dtype = DT_DIR;
1285 int rc;
1286 - enum pattern_match_result ret;
1287 - ret = path_matches_pattern_list(prefix->buf, prefix->len,
1288 - basename, &dtype, pl, istate);
1286 + enum pattern_match_result ret, orig_ret;
1287 + orig_ret = path_matches_pattern_list(prefix->buf, prefix->len,
1288 + basename, &dtype, pl, istate);
1289
1290 strbuf_addch(prefix, '/');
1291
1292 /* If undecided, use matching result of parent dir in defval */
1293 - if (ret == UNDECIDED)
1293 + if (orig_ret == UNDECIDED)
1294 ret = default_match;
1295 + else
1296 + ret = orig_ret;
1297
1298 for (cache_end = cache; cache_end != cache + nr; cache_end++) {
1299 struct cache_entry *ce = *cache_end;
@@ -1299,17 +1301,23 @@ static int clear_ce_flags_dir(struct index_state *istate,
1301 break;
1302 }
1303
1302 - /*
1303 - * TODO: check pl, if there are no patterns that may conflict
1304 - * with ret (iow, we know in advance the incl/excl
1305 - * decision for the entire directory), clear flag here without
1306 - * calling clear_ce_flags_1(). That function will call
1307 - * the expensive path_matches_pattern_list() on every entry.
1308 - */
1309 - rc = clear_ce_flags_1(istate, cache, cache_end - cache,
1310 - prefix,
1311 - select_mask, clear_mask,
1312 - pl, ret);
1304 + if (pl->use_cone_patterns && orig_ret == MATCHED_RECURSIVE) {
1305 + struct cache_entry **ce = cache;
1306 + rc = (cache_end - cache) / sizeof(struct cache_entry *);
1307 +
1308 + while (ce < cache_end) {
1309 + (*ce)->ce_flags &= ~clear_mask;
1310 + ce++;
1311 + }
1312 + } else if (pl->use_cone_patterns && orig_ret == NOT_MATCHED) {
1313 + rc = (cache_end - cache) / sizeof(struct cache_entry *);
1314 + } else {
1315 + rc = clear_ce_flags_1(istate, cache, cache_end - cache,
1316 + prefix,
1317 + select_mask, clear_mask,
1318 + pl, ret);
1319 + }
1320 +
1321 strbuf_setlen(prefix, prefix->len - 1);
1322 return rc;
1323 }