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
}