|
28 | 28 | #include "object-file.h" |
29 | 29 | #include "object-name.h" |
30 | 30 | #include "odb.h" |
| 31 | +#include "oid-array.h" |
| 32 | +#include "oidset.h" |
31 | 33 | #include "packfile.h" |
32 | 34 | #include "pager.h" |
33 | 35 | #include "path.h" |
| 36 | +#include "promisor-remote.h" |
34 | 37 | #include "read-cache-ll.h" |
35 | 38 | #include "write-or-die.h" |
36 | 39 |
|
@@ -692,6 +695,143 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, |
692 | 695 | return hit; |
693 | 696 | } |
694 | 697 |
|
| 698 | +static void collect_blob_oids_for_tree(struct repository *repo, |
| 699 | + const struct pathspec *pathspec, |
| 700 | + struct tree_desc *tree, |
| 701 | + struct strbuf *base, |
| 702 | + int tn_len, |
| 703 | + struct oidset *blob_oids) |
| 704 | +{ |
| 705 | + struct name_entry entry; |
| 706 | + int old_baselen = base->len; |
| 707 | + struct strbuf name = STRBUF_INIT; |
| 708 | + enum interesting match = entry_not_interesting; |
| 709 | + |
| 710 | + while (tree_entry(tree, &entry)) { |
| 711 | + if (match != all_entries_interesting) { |
| 712 | + strbuf_addstr(&name, base->buf + tn_len); |
| 713 | + match = tree_entry_interesting(repo->index, |
| 714 | + &entry, &name, |
| 715 | + pathspec); |
| 716 | + strbuf_reset(&name); |
| 717 | + |
| 718 | + if (match == all_entries_not_interesting) |
| 719 | + break; |
| 720 | + if (match == entry_not_interesting) |
| 721 | + continue; |
| 722 | + } |
| 723 | + |
| 724 | + strbuf_add(base, entry.path, tree_entry_len(&entry)); |
| 725 | + |
| 726 | + if (S_ISREG(entry.mode)) { |
| 727 | + oidset_insert(blob_oids, &entry.oid); |
| 728 | + } else if (S_ISDIR(entry.mode)) { |
| 729 | + enum object_type type; |
| 730 | + struct tree_desc sub_tree; |
| 731 | + void *data; |
| 732 | + unsigned long size; |
| 733 | + |
| 734 | + data = odb_read_object(repo->objects, &entry.oid, |
| 735 | + &type, &size); |
| 736 | + if (!data) |
| 737 | + die(_("unable to read tree (%s)"), |
| 738 | + oid_to_hex(&entry.oid)); |
| 739 | + |
| 740 | + strbuf_addch(base, '/'); |
| 741 | + init_tree_desc(&sub_tree, &entry.oid, data, size); |
| 742 | + collect_blob_oids_for_tree(repo, pathspec, &sub_tree, |
| 743 | + base, tn_len, blob_oids); |
| 744 | + free(data); |
| 745 | + } |
| 746 | + /* |
| 747 | + * ...no else clause for S_ISGITLINK: submodules have their |
| 748 | + * own promisor configuration and would need separate fetches |
| 749 | + * anyway. |
| 750 | + */ |
| 751 | + |
| 752 | + strbuf_setlen(base, old_baselen); |
| 753 | + } |
| 754 | + |
| 755 | + strbuf_release(&name); |
| 756 | +} |
| 757 | + |
| 758 | +static void collect_blob_oids_for_treeish(struct grep_opt *opt, |
| 759 | + const struct pathspec *pathspec, |
| 760 | + const struct object_id *tree_ish_oid, |
| 761 | + const char *name, |
| 762 | + struct oidset *blob_oids) |
| 763 | +{ |
| 764 | + struct tree_desc tree; |
| 765 | + void *data; |
| 766 | + unsigned long size; |
| 767 | + struct strbuf base = STRBUF_INIT; |
| 768 | + int len; |
| 769 | + |
| 770 | + data = odb_read_object_peeled(opt->repo->objects, tree_ish_oid, |
| 771 | + OBJ_TREE, &size, NULL); |
| 772 | + |
| 773 | + if (!data) |
| 774 | + return; |
| 775 | + |
| 776 | + len = name ? strlen(name) : 0; |
| 777 | + if (len) { |
| 778 | + strbuf_add(&base, name, len); |
| 779 | + strbuf_addch(&base, ':'); |
| 780 | + } |
| 781 | + init_tree_desc(&tree, tree_ish_oid, data, size); |
| 782 | + |
| 783 | + collect_blob_oids_for_tree(opt->repo, pathspec, &tree, |
| 784 | + &base, base.len, blob_oids); |
| 785 | + |
| 786 | + strbuf_release(&base); |
| 787 | + free(data); |
| 788 | +} |
| 789 | + |
| 790 | +static void prefetch_grep_blobs(struct grep_opt *opt, |
| 791 | + const struct pathspec *pathspec, |
| 792 | + const struct object_array *list) |
| 793 | +{ |
| 794 | + struct oidset blob_oids = OIDSET_INIT; |
| 795 | + |
| 796 | + /* Exit if we're not in a partial clone */ |
| 797 | + if (!repo_has_promisor_remote(opt->repo)) |
| 798 | + return; |
| 799 | + |
| 800 | + /* For each tree, gather the blobs in it */ |
| 801 | + for (int i = 0; i < list->nr; i++) { |
| 802 | + struct object *real_obj; |
| 803 | + |
| 804 | + obj_read_lock(); |
| 805 | + real_obj = deref_tag(opt->repo, list->objects[i].item, |
| 806 | + NULL, 0); |
| 807 | + obj_read_unlock(); |
| 808 | + |
| 809 | + if (real_obj && |
| 810 | + (real_obj->type == OBJ_COMMIT || |
| 811 | + real_obj->type == OBJ_TREE)) |
| 812 | + collect_blob_oids_for_treeish(opt, pathspec, |
| 813 | + &real_obj->oid, |
| 814 | + list->objects[i].name, |
| 815 | + &blob_oids); |
| 816 | + } |
| 817 | + |
| 818 | + /* Prefetch the blobs we found */ |
| 819 | + if (oidset_size(&blob_oids)) { |
| 820 | + struct oid_array to_fetch = OID_ARRAY_INIT; |
| 821 | + struct oidset_iter iter; |
| 822 | + const struct object_id *oid; |
| 823 | + |
| 824 | + oidset_iter_init(&blob_oids, &iter); |
| 825 | + while ((oid = oidset_iter_next(&iter))) |
| 826 | + oid_array_append(&to_fetch, oid); |
| 827 | + |
| 828 | + promisor_remote_get_direct(opt->repo, to_fetch.oid, to_fetch.nr); |
| 829 | + |
| 830 | + oid_array_clear(&to_fetch); |
| 831 | + } |
| 832 | + oidset_clear(&blob_oids); |
| 833 | +} |
| 834 | + |
695 | 835 | static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec, |
696 | 836 | struct object *obj, const char *name, const char *path) |
697 | 837 | { |
@@ -732,6 +872,8 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec, |
732 | 872 | int hit = 0; |
733 | 873 | const unsigned int nr = list->nr; |
734 | 874 |
|
| 875 | + prefetch_grep_blobs(opt, pathspec, list); |
| 876 | + |
735 | 877 | for (i = 0; i < nr; i++) { |
736 | 878 | struct object *real_obj; |
737 | 879 |
|
|
0 commit comments