Skip to content

Commit 8b10a20

Browse files
matvoregitster
authored andcommitted
list-objects: support for skipping tree traversal
The tree:0 filter does not need to traverse the trees that it has filtered out, so optimize list-objects and list-objects-filter to skip traversing the trees entirely. Before this patch, we iterated over all children of the tree, and did nothing for all of them, which was wasteful. Signed-off-by: Matthew DeVore <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent d9e6d09 commit 8b10a20

File tree

4 files changed

+32
-3
lines changed

4 files changed

+32
-3
lines changed

list-objects-filter.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,16 @@ static enum list_objects_filter_result filter_trees_none(
102102

103103
case LOFS_BEGIN_TREE:
104104
case LOFS_BLOB:
105-
if (filter_data->omits)
105+
if (filter_data->omits) {
106106
oidset_insert(filter_data->omits, &obj->oid);
107-
return LOFR_MARK_SEEN; /* but not LOFR_DO_SHOW (hard omit) */
107+
/* _MARK_SEEN but not _DO_SHOW (hard omit) */
108+
return LOFR_MARK_SEEN;
109+
} else {
110+
/*
111+
* Not collecting omits so no need to to traverse tree.
112+
*/
113+
return LOFR_SKIP_TREE | LOFR_MARK_SEEN;
114+
}
108115

109116
case LOFS_END_TREE:
110117
assert(obj->type == OBJ_TREE);

list-objects-filter.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
* In general, objects should only be shown once, but
2121
* this result DOES NOT imply that we mark it SEEN.
2222
*
23+
* _SKIP_TREE : Used in LOFS_BEGIN_TREE situation - indicates that
24+
* the tree's children should not be iterated over. This
25+
* is used as an optimization when all children will
26+
* definitely be ignored.
27+
*
2328
* Most of the time, you want the combination (_MARK_SEEN | _DO_SHOW)
2429
* but they can be used independently, such as when sparse-checkout
2530
* pattern matching is being applied.
@@ -41,6 +46,7 @@ enum list_objects_filter_result {
4146
LOFR_ZERO = 0,
4247
LOFR_MARK_SEEN = 1<<0,
4348
LOFR_DO_SHOW = 1<<1,
49+
LOFR_SKIP_TREE = 1<<2,
4450
};
4551

4652
enum list_objects_filter_situation {

list-objects.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "list-objects-filter-options.h"
1212
#include "packfile.h"
1313
#include "object-store.h"
14+
#include "trace.h"
1415

1516
struct traversal_context {
1617
struct rev_info *revs;
@@ -184,7 +185,9 @@ static void process_tree(struct traversal_context *ctx,
184185
if (base->len)
185186
strbuf_addch(base, '/');
186187

187-
if (!failed_parse)
188+
if (r & LOFR_SKIP_TREE)
189+
trace_printf("Skipping contents of tree %s...\n", base->buf);
190+
else if (!failed_parse)
188191
process_tree_contents(ctx, tree, base);
189192

190193
if ((obj->flags & NOT_USER_GIVEN) && ctx->filter_fn) {

t/t6112-rev-list-filters-objects.sh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,19 @@ test_expect_success 'verify tree:0 includes trees in "filtered" output' '
245245
test_cmp expected filtered_types
246246
'
247247

248+
# Make sure tree:0 does not iterate through any trees.
249+
250+
test_expect_success 'filter a GIANT tree through tree:0' '
251+
GIT_TRACE=1 git -C r3 rev-list \
252+
--objects --filter=tree:0 HEAD 2>filter_trace &&
253+
grep "Skipping contents of tree [.][.][.]" filter_trace >actual &&
254+
# One line for each commit traversed.
255+
test_line_count = 2 actual &&
256+
257+
# Make sure no other trees were considered besides the root.
258+
! grep "Skipping contents of tree [^.]" filter_trace
259+
'
260+
248261
# Delete some loose objects and use rev-list, but WITHOUT any filtering.
249262
# This models previously omitted objects that we did not receive.
250263

0 commit comments

Comments
 (0)