pack: move {,re}prepare_packed_git and approximate_object_count

Signed-off-by: Jonathan Tan <jonathantanmy@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jonathan Tan committed Aug 18, 2017 at 15:20 UTC 0abe14f6a5b7681b4ea02d1bd0a64332587ae053
11 files changed +238 -232
builtin/gc.c
+1
@@ -19,6 +19,7 @@
19 #include "sigchain.h"
20 #include "argv-array.h"
21 #include "commit.h"
22 +#include "packfile.h"
23
24 #define FAILED_RUN "failed to run %s"
25
bulk-checkin.c
+1
@@ -6,6 +6,7 @@
6 #include "csum-file.h"
7 #include "pack.h"
8 #include "strbuf.h"
9 +#include "packfile.h"
10
11 static struct bulk_checkin_state {
12 unsigned plugged:1;
cache.h
-15
@@ -1605,21 +1605,6 @@ struct pack_entry {
1605 struct packed_git *p;
1606 };
1607
1608 -/* A hook to report invalid files in pack directory */
1609 -#define PACKDIR_FILE_PACK 1
1610 -#define PACKDIR_FILE_IDX 2
1611 -#define PACKDIR_FILE_GARBAGE 4
1612 -extern void (*report_garbage)(unsigned seen_bits, const char *path);
1613 -
1614 -extern void prepare_packed_git(void);
1615 -extern void reprepare_packed_git(void);
1616 -
1617 -/*
1618 - * Give a rough count of objects in the repository. This sacrifices accuracy
1619 - * for speed.
1620 - */
1621 -unsigned long approximate_object_count(void);
1622 -
1608 extern struct packed_git *find_sha1_pack(const unsigned char *sha1,
1609 struct packed_git *packs);
1610
connected.c
+1 -1
@@ -3,7 +3,7 @@
3 #include "sigchain.h"
4 #include "connected.h"
5 #include "transport.h"
6 -#include "pack.h"
6 +#include "packfile.h"
7
8 /*
9 * If we feed all the commits we want to verify to this command
fetch-pack.c
+1
@@ -17,6 +17,7 @@
17 #include "prio-queue.h"
18 #include "sha1-array.h"
19 #include "oidset.h"
20 +#include "packfile.h"
21
22 static int transfer_unpack_limit = -1;
23 static int fetch_unpack_limit = -1;
http-backend.c
+1
@@ -9,6 +9,7 @@
9 #include "string-list.h"
10 #include "url.h"
11 #include "argv-array.h"
12 +#include "packfile.h"
13
14 static const char content_type[] = "Content-Type";
15 static const char content_length[] = "Content-Length";
packfile.c
+217
@@ -1,6 +1,9 @@
1 #include "cache.h"
2 #include "mru.h"
3 #include "pack.h"
4 +#include "dir.h"
5 +#include "mergesort.h"
6 +#include "packfile.h"
7
8 char *odb_pack_name(struct strbuf *buf,
9 const unsigned char *sha1,
@@ -667,3 +670,217 @@ void install_packed_git(struct packed_git *pack)
670 pack->next = packed_git;
671 packed_git = pack;
672 }
673 +
674 +void (*report_garbage)(unsigned seen_bits, const char *path);
675 +
676 +static void report_helper(const struct string_list *list,
677 + int seen_bits, int first, int last)
678 +{
679 + if (seen_bits == (PACKDIR_FILE_PACK|PACKDIR_FILE_IDX))
680 + return;
681 +
682 + for (; first < last; first++)
683 + report_garbage(seen_bits, list->items[first].string);
684 +}
685 +
686 +static void report_pack_garbage(struct string_list *list)
687 +{
688 + int i, baselen = -1, first = 0, seen_bits = 0;
689 +
690 + if (!report_garbage)
691 + return;
692 +
693 + string_list_sort(list);
694 +
695 + for (i = 0; i < list->nr; i++) {
696 + const char *path = list->items[i].string;
697 + if (baselen != -1 &&
698 + strncmp(path, list->items[first].string, baselen)) {
699 + report_helper(list, seen_bits, first, i);
700 + baselen = -1;
701 + seen_bits = 0;
702 + }
703 + if (baselen == -1) {
704 + const char *dot = strrchr(path, '.');
705 + if (!dot) {
706 + report_garbage(PACKDIR_FILE_GARBAGE, path);
707 + continue;
708 + }
709 + baselen = dot - path + 1;
710 + first = i;
711 + }
712 + if (!strcmp(path + baselen, "pack"))
713 + seen_bits |= 1;
714 + else if (!strcmp(path + baselen, "idx"))
715 + seen_bits |= 2;
716 + }
717 + report_helper(list, seen_bits, first, list->nr);
718 +}
719 +
720 +static void prepare_packed_git_one(char *objdir, int local)
721 +{
722 + struct strbuf path = STRBUF_INIT;
723 + size_t dirnamelen;
724 + DIR *dir;
725 + struct dirent *de;
726 + struct string_list garbage = STRING_LIST_INIT_DUP;
727 +
728 + strbuf_addstr(&path, objdir);
729 + strbuf_addstr(&path, "/pack");
730 + dir = opendir(path.buf);
731 + if (!dir) {
732 + if (errno != ENOENT)
733 + error_errno("unable to open object pack directory: %s",
734 + path.buf);
735 + strbuf_release(&path);
736 + return;
737 + }
738 + strbuf_addch(&path, '/');
739 + dirnamelen = path.len;
740 + while ((de = readdir(dir)) != NULL) {
741 + struct packed_git *p;
742 + size_t base_len;
743 +
744 + if (is_dot_or_dotdot(de->d_name))
745 + continue;
746 +
747 + strbuf_setlen(&path, dirnamelen);
748 + strbuf_addstr(&path, de->d_name);
749 +
750 + base_len = path.len;
751 + if (strip_suffix_mem(path.buf, &base_len, ".idx")) {
752 + /* Don't reopen a pack we already have. */
753 + for (p = packed_git; p; p = p->next) {
754 + size_t len;
755 + if (strip_suffix(p->pack_name, ".pack", &len) &&
756 + len == base_len &&
757 + !memcmp(p->pack_name, path.buf, len))
758 + break;
759 + }
760 + if (p == NULL &&
761 + /*
762 + * See if it really is a valid .idx file with
763 + * corresponding .pack file that we can map.
764 + */
765 + (p = add_packed_git(path.buf, path.len, local)) != NULL)
766 + install_packed_git(p);
767 + }
768 +
769 + if (!report_garbage)
770 + continue;
771 +
772 + if (ends_with(de->d_name, ".idx") ||
773 + ends_with(de->d_name, ".pack") ||
774 + ends_with(de->d_name, ".bitmap") ||
775 + ends_with(de->d_name, ".keep"))
776 + string_list_append(&garbage, path.buf);
777 + else
778 + report_garbage(PACKDIR_FILE_GARBAGE, path.buf);
779 + }
780 + closedir(dir);
781 + report_pack_garbage(&garbage);
782 + string_list_clear(&garbage, 0);
783 + strbuf_release(&path);
784 +}
785 +
786 +static int approximate_object_count_valid;
787 +
788 +/*
789 + * Give a fast, rough count of the number of objects in the repository. This
790 + * ignores loose objects completely. If you have a lot of them, then either
791 + * you should repack because your performance will be awful, or they are
792 + * all unreachable objects about to be pruned, in which case they're not really
793 + * interesting as a measure of repo size in the first place.
794 + */
795 +unsigned long approximate_object_count(void)
796 +{
797 + static unsigned long count;
798 + if (!approximate_object_count_valid) {
799 + struct packed_git *p;
800 +
801 + prepare_packed_git();
802 + count = 0;
803 + for (p = packed_git; p; p = p->next) {
804 + if (open_pack_index(p))
805 + continue;
806 + count += p->num_objects;
807 + }
808 + }
809 + return count;
810 +}
811 +
812 +static void *get_next_packed_git(const void *p)
813 +{
814 + return ((const struct packed_git *)p)->next;
815 +}
816 +
817 +static void set_next_packed_git(void *p, void *next)
818 +{
819 + ((struct packed_git *)p)->next = next;
820 +}
821 +
822 +static int sort_pack(const void *a_, const void *b_)
823 +{
824 + const struct packed_git *a = a_;
825 + const struct packed_git *b = b_;
826 + int st;
827 +
828 + /*
829 + * Local packs tend to contain objects specific to our
830 + * variant of the project than remote ones. In addition,
831 + * remote ones could be on a network mounted filesystem.
832 + * Favor local ones for these reasons.
833 + */
834 + st = a->pack_local - b->pack_local;
835 + if (st)
836 + return -st;
837 +
838 + /*
839 + * Younger packs tend to contain more recent objects,
840 + * and more recent objects tend to get accessed more
841 + * often.
842 + */
843 + if (a->mtime < b->mtime)
844 + return 1;
845 + else if (a->mtime == b->mtime)
846 + return 0;
847 + return -1;
848 +}
849 +
850 +static void rearrange_packed_git(void)
851 +{
852 + packed_git = llist_mergesort(packed_git, get_next_packed_git,
853 + set_next_packed_git, sort_pack);
854 +}
855 +
856 +static void prepare_packed_git_mru(void)
857 +{
858 + struct packed_git *p;
859 +
860 + mru_clear(packed_git_mru);
861 + for (p = packed_git; p; p = p->next)
862 + mru_append(packed_git_mru, p);
863 +}
864 +
865 +static int prepare_packed_git_run_once = 0;
866 +void prepare_packed_git(void)
867 +{
868 + struct alternate_object_database *alt;
869 +
870 + if (prepare_packed_git_run_once)
871 + return;
872 + prepare_packed_git_one(get_object_directory(), 1);
873 + prepare_alt_odb();
874 + for (alt = alt_odb_list; alt; alt = alt->next)
875 + prepare_packed_git_one(alt->path, 0);
876 + rearrange_packed_git();
877 + prepare_packed_git_mru();
878 + prepare_packed_git_run_once = 1;
879 +}
880 +
881 +void reprepare_packed_git(void)
882 +{
883 + approximate_object_count_valid = 0;
884 + prepare_packed_git_run_once = 0;
885 + prepare_packed_git();
886 +}
packfile.h
+14 -2
@@ -24,12 +24,24 @@ extern char *sha1_pack_name(const unsigned char *sha1);
24 */
25 extern char *sha1_pack_index_name(const unsigned char *sha1);
26
27 -extern unsigned int pack_open_fds;
28 -
27 extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
28
29 +/* A hook to report invalid files in pack directory */
30 +#define PACKDIR_FILE_PACK 1
31 +#define PACKDIR_FILE_IDX 2
32 +#define PACKDIR_FILE_GARBAGE 4
33 +extern void (*report_garbage)(unsigned seen_bits, const char *path);
34 +
35 +extern void prepare_packed_git(void);
36 +extern void reprepare_packed_git(void);
37 extern void install_packed_git(struct packed_git *pack);
38
39 +/*
40 + * Give a rough count of objects in the repository. This sacrifices accuracy
41 + * for speed.
42 + */
43 +unsigned long approximate_object_count(void);
44 +
45 extern void pack_report(void);
46
47 /*
path.c
+1
@@ -9,6 +9,7 @@
9 #include "worktree.h"
10 #include "submodule-config.h"
11 #include "path.h"
12 +#include "packfile.h"
13
14 static int get_st_mode_bits(const char *path, int *mode)
15 {
server-info.c
+1
@@ -3,6 +3,7 @@
3 #include "object.h"
4 #include "commit.h"
5 #include "tag.h"
6 +#include "packfile.h"
7
8 /*
9 * Create the file "path" by writing to a temporary file and renaming
sha1_file.c
-214
@@ -719,220 +719,6 @@ void *xmmap(void *start, size_t length,
719 return ret;
720 }
721
722 -void (*report_garbage)(unsigned seen_bits, const char *path);
723 -
724 -static void report_helper(const struct string_list *list,
725 - int seen_bits, int first, int last)
726 -{
727 - if (seen_bits == (PACKDIR_FILE_PACK|PACKDIR_FILE_IDX))
728 - return;
729 -
730 - for (; first < last; first++)
731 - report_garbage(seen_bits, list->items[first].string);
732 -}
733 -
734 -static void report_pack_garbage(struct string_list *list)
735 -{
736 - int i, baselen = -1, first = 0, seen_bits = 0;
737 -
738 - if (!report_garbage)
739 - return;
740 -
741 - string_list_sort(list);
742 -
743 - for (i = 0; i < list->nr; i++) {
744 - const char *path = list->items[i].string;
745 - if (baselen != -1 &&
746 - strncmp(path, list->items[first].string, baselen)) {
747 - report_helper(list, seen_bits, first, i);
748 - baselen = -1;
749 - seen_bits = 0;
750 - }
751 - if (baselen == -1) {
752 - const char *dot = strrchr(path, '.');
753 - if (!dot) {
754 - report_garbage(PACKDIR_FILE_GARBAGE, path);
755 - continue;
756 - }
757 - baselen = dot - path + 1;
758 - first = i;
759 - }
760 - if (!strcmp(path + baselen, "pack"))
761 - seen_bits |= 1;
762 - else if (!strcmp(path + baselen, "idx"))
763 - seen_bits |= 2;
764 - }
765 - report_helper(list, seen_bits, first, list->nr);
766 -}
767 -
768 -static void prepare_packed_git_one(char *objdir, int local)
769 -{
770 - struct strbuf path = STRBUF_INIT;
771 - size_t dirnamelen;
772 - DIR *dir;
773 - struct dirent *de;
774 - struct string_list garbage = STRING_LIST_INIT_DUP;
775 -
776 - strbuf_addstr(&path, objdir);
777 - strbuf_addstr(&path, "/pack");
778 - dir = opendir(path.buf);
779 - if (!dir) {
780 - if (errno != ENOENT)
781 - error_errno("unable to open object pack directory: %s",
782 - path.buf);
783 - strbuf_release(&path);
784 - return;
785 - }
786 - strbuf_addch(&path, '/');
787 - dirnamelen = path.len;
788 - while ((de = readdir(dir)) != NULL) {
789 - struct packed_git *p;
790 - size_t base_len;
791 -
792 - if (is_dot_or_dotdot(de->d_name))
793 - continue;
794 -
795 - strbuf_setlen(&path, dirnamelen);
796 - strbuf_addstr(&path, de->d_name);
797 -
798 - base_len = path.len;
799 - if (strip_suffix_mem(path.buf, &base_len, ".idx")) {
800 - /* Don't reopen a pack we already have. */
801 - for (p = packed_git; p; p = p->next) {
802 - size_t len;
803 - if (strip_suffix(p->pack_name, ".pack", &len) &&
804 - len == base_len &&
805 - !memcmp(p->pack_name, path.buf, len))
806 - break;
807 - }
808 - if (p == NULL &&
809 - /*
810 - * See if it really is a valid .idx file with
811 - * corresponding .pack file that we can map.
812 - */
813 - (p = add_packed_git(path.buf, path.len, local)) != NULL)
814 - install_packed_git(p);
815 - }
816 -
817 - if (!report_garbage)
818 - continue;
819 -
820 - if (ends_with(de->d_name, ".idx") ||
821 - ends_with(de->d_name, ".pack") ||
822 - ends_with(de->d_name, ".bitmap") ||
823 - ends_with(de->d_name, ".keep"))
824 - string_list_append(&garbage, path.buf);
825 - else
826 - report_garbage(PACKDIR_FILE_GARBAGE, path.buf);
827 - }
828 - closedir(dir);
829 - report_pack_garbage(&garbage);
830 - string_list_clear(&garbage, 0);
831 - strbuf_release(&path);
832 -}
833 -
834 -static int approximate_object_count_valid;
835 -
836 -/*
837 - * Give a fast, rough count of the number of objects in the repository. This
838 - * ignores loose objects completely. If you have a lot of them, then either
839 - * you should repack because your performance will be awful, or they are
840 - * all unreachable objects about to be pruned, in which case they're not really
841 - * interesting as a measure of repo size in the first place.
842 - */
843 -unsigned long approximate_object_count(void)
844 -{
845 - static unsigned long count;
846 - if (!approximate_object_count_valid) {
847 - struct packed_git *p;
848 -
849 - prepare_packed_git();
850 - count = 0;
851 - for (p = packed_git; p; p = p->next) {
852 - if (open_pack_index(p))
853 - continue;
854 - count += p->num_objects;
855 - }
856 - }
857 - return count;
858 -}
859 -
860 -static void *get_next_packed_git(const void *p)
861 -{
862 - return ((const struct packed_git *)p)->next;
863 -}
864 -
865 -static void set_next_packed_git(void *p, void *next)
866 -{
867 - ((struct packed_git *)p)->next = next;
868 -}
869 -
870 -static int sort_pack(const void *a_, const void *b_)
871 -{
872 - const struct packed_git *a = a_;
873 - const struct packed_git *b = b_;
874 - int st;
875 -
876 - /*
877 - * Local packs tend to contain objects specific to our
878 - * variant of the project than remote ones. In addition,
879 - * remote ones could be on a network mounted filesystem.
880 - * Favor local ones for these reasons.
881 - */
882 - st = a->pack_local - b->pack_local;
883 - if (st)
884 - return -st;
885 -
886 - /*
887 - * Younger packs tend to contain more recent objects,
888 - * and more recent objects tend to get accessed more
889 - * often.
890 - */
891 - if (a->mtime < b->mtime)
892 - return 1;
893 - else if (a->mtime == b->mtime)
894 - return 0;
895 - return -1;
896 -}
897 -
898 -static void rearrange_packed_git(void)
899 -{
900 - packed_git = llist_mergesort(packed_git, get_next_packed_git,
901 - set_next_packed_git, sort_pack);
902 -}
903 -
904 -static void prepare_packed_git_mru(void)
905 -{
906 - struct packed_git *p;
907 -
908 - mru_clear(packed_git_mru);
909 - for (p = packed_git; p; p = p->next)
910 - mru_append(packed_git_mru, p);
911 -}
912 -
913 -static int prepare_packed_git_run_once = 0;
914 -void prepare_packed_git(void)
915 -{
916 - struct alternate_object_database *alt;
917 -
918 - if (prepare_packed_git_run_once)
919 - return;
920 - prepare_packed_git_one(get_object_directory(), 1);
921 - prepare_alt_odb();
922 - for (alt = alt_odb_list; alt; alt = alt->next)
923 - prepare_packed_git_one(alt->path, 0);
924 - rearrange_packed_git();
925 - prepare_packed_git_mru();
926 - prepare_packed_git_run_once = 1;
927 -}
928 -
929 -void reprepare_packed_git(void)
930 -{
931 - approximate_object_count_valid = 0;
932 - prepare_packed_git_run_once = 0;
933 - prepare_packed_git();
934 -}
935 -
722 static void mark_bad_packed_object(struct packed_git *p,
723 const unsigned char *sha1)
724 {