Git fork

Merge branch 'ly/changed-path-traversal-with-magic-pathspec'

Revision traversal limited with pathspec, like "git log dir/*",
used to ignore changed-paths Bloom filter when the pathspec
contained wildcards; now they take advantage of the filter when
they can.

* ly/changed-path-traversal-with-magic-pathspec:
bloom: enable bloom filter with wildcard pathspec in revision traversal

+56 -17
+29 -13
revision.c
··· 671 671 672 672 static int forbid_bloom_filters(struct pathspec *spec) 673 673 { 674 - if (spec->has_wildcard) 675 - return 1; 676 - if (spec->magic & ~PATHSPEC_LITERAL) 674 + unsigned int allowed_magic = 675 + PATHSPEC_FROMTOP | 676 + PATHSPEC_MAXDEPTH | 677 + PATHSPEC_LITERAL | 678 + PATHSPEC_GLOB | 679 + PATHSPEC_ATTR; 680 + 681 + if (spec->magic & ~allowed_magic) 677 682 return 1; 678 683 for (size_t nr = 0; nr < spec->nr; nr++) 679 - if (spec->items[nr].magic & ~PATHSPEC_LITERAL) 684 + if (spec->items[nr].magic & ~allowed_magic) 680 685 return 1; 681 686 682 687 return 0; ··· 691 696 char *path_alloc = NULL; 692 697 const char *path; 693 698 size_t len; 694 - int res = 0; 699 + int res = -1; 695 700 701 + len = pi->nowildcard_len; 702 + if (len != pi->len) { 703 + /* 704 + * for path like "dir/file*", nowildcard part would be 705 + * "dir/file", but only "dir" should be used for the 706 + * bloom filter. 707 + */ 708 + while (len > 0 && pi->match[len - 1] != '/') 709 + len--; 710 + } 696 711 /* remove single trailing slash from path, if needed */ 697 - if (pi->len > 0 && pi->match[pi->len - 1] == '/') { 698 - path_alloc = xmemdupz(pi->match, pi->len - 1); 712 + if (len > 0 && pi->match[len - 1] == '/') 713 + len--; 714 + 715 + if (!len) 716 + goto cleanup; 717 + 718 + if (len != pi->len) { 719 + path_alloc = xmemdupz(pi->match, len); 699 720 path = path_alloc; 700 721 } else 701 722 path = pi->match; 702 723 703 - len = strlen(path); 704 - if (!len) { 705 - res = -1; 706 - goto cleanup; 707 - } 708 - 709 724 *out = bloom_keyvec_new(path, len, settings); 710 725 726 + res = 0; 711 727 cleanup: 712 728 free(path_alloc); 713 729 return res;
+27 -4
t/t4216-log-bloom.sh
··· 154 154 test_bloom_filters_used "-- file*" 155 155 ' 156 156 157 - test_expect_success 'git log with path contains a wildcard does not use Bloom filter' ' 157 + test_expect_success 'git log with paths all contain non-wildcard part uses Bloom filter' ' 158 + test_bloom_filters_used "-- A/\* file4" && 159 + test_bloom_filters_used "-- A/file\*" && 160 + test_bloom_filters_used "-- * A/\*" 161 + ' 162 + 163 + test_expect_success 'git log with path only contains wildcard part does not use Bloom filter' ' 158 164 test_bloom_filters_not_used "-- file\*" && 159 - test_bloom_filters_not_used "-- A/\* file4" && 160 - test_bloom_filters_not_used "-- file4 A/\*" && 161 - test_bloom_filters_not_used "-- * A/\*" 165 + test_bloom_filters_not_used "-- file\* A/\*" && 166 + test_bloom_filters_not_used "-- file\* *" && 167 + test_bloom_filters_not_used "-- \*" 168 + ' 169 + 170 + test_expect_success 'git log with path contains various magic signatures' ' 171 + cd A && 172 + test_bloom_filters_used "-- \:\(top\)B" && 173 + cd .. && 174 + 175 + test_bloom_filters_used "-- \:\(glob\)A/\*\*/C" && 176 + test_bloom_filters_not_used "-- \:\(icase\)FILE4" && 177 + test_bloom_filters_not_used "-- \:\(exclude\)A/B/C" && 178 + 179 + test_when_finished "rm -f .gitattributes" && 180 + cat >.gitattributes <<-EOF && 181 + A/file1 text 182 + A/B/file2 -text 183 + EOF 184 + test_bloom_filters_used "-- \:\(attr\:text\)A" 162 185 ' 163 186 164 187 test_expect_success 'setup - add commit-graph to the chain without Bloom filters' '