@@ -155,11 +155,11 @@ static int input_fd, output_fd;
155
155
static const char * curr_pack ;
156
156
157
157
/*
158
- * local_links is guarded by read_mutex, and record_local_links is read-only in
159
- * a thread.
158
+ * outgoing_links is guarded by read_mutex, and record_outgoing_links is
159
+ * read-only in a thread.
160
160
*/
161
- static struct oidset local_links = OIDSET_INIT ;
162
- static int record_local_links ;
161
+ static struct oidset outgoing_links = OIDSET_INIT ;
162
+ static int record_outgoing_links ;
163
163
164
164
static struct thread_local_data * thread_data ;
165
165
static int nr_dispatched ;
@@ -812,18 +812,41 @@ static int check_collison(struct object_entry *entry)
812
812
return 0 ;
813
813
}
814
814
815
- static void record_if_local_object (const struct object_id * oid )
815
+ static void record_outgoing_link (const struct object_id * oid )
816
816
{
817
- struct object_info info = OBJECT_INFO_INIT ;
818
- if (oid_object_info_extended (the_repository , oid , & info , 0 ))
819
- /* Missing; assume it is a promisor object */
820
- return ;
821
- if (info .whence == OI_PACKED && info .u .packed .pack -> pack_promisor )
822
- return ;
823
- oidset_insert (& local_links , oid );
817
+ oidset_insert (& outgoing_links , oid );
824
818
}
825
819
826
- static void do_record_local_links (struct object * obj )
820
+ static void maybe_record_name_entry (const struct name_entry * entry )
821
+ {
822
+ /*
823
+ * Checking only trees here results in a significantly faster packfile
824
+ * indexing, but the drawback is that if the packfile to be indexed
825
+ * references a local blob only directly (that is, never through a
826
+ * local tree), that local blob is in danger of being garbage
827
+ * collected. Such a situation may arise if we push local commits,
828
+ * including one with a change to a blob in the root tree, and then the
829
+ * server incorporates them into its main branch through a "rebase" or
830
+ * "squash" merge strategy, and then we fetch the new main branch from
831
+ * the server.
832
+ *
833
+ * This situation has not been observed yet - we have only noticed
834
+ * missing commits, not missing trees or blobs. (In fact, if it were
835
+ * believed that only missing commits are problematic, one could argue
836
+ * that we should also exclude trees during the outgoing link check;
837
+ * but it is safer to include them.)
838
+ *
839
+ * Due to the rarity of the situation (it has not been observed to
840
+ * happen in real life), and because the "penalty" in such a situation
841
+ * is merely to refetch the missing blob when it's needed (and this
842
+ * happens only once - when refetched, the blob goes into a promisor
843
+ * pack, so it won't be GC-ed, the tradeoff seems worth it.
844
+ */
845
+ if (S_ISDIR (entry -> mode ))
846
+ record_outgoing_link (& entry -> oid );
847
+ }
848
+
849
+ static void do_record_outgoing_links (struct object * obj )
827
850
{
828
851
if (obj -> type == OBJ_TREE ) {
829
852
struct tree * tree = (struct tree * )obj ;
@@ -837,16 +860,17 @@ static void do_record_local_links(struct object *obj)
837
860
*/
838
861
return ;
839
862
while (tree_entry_gently (& desc , & entry ))
840
- record_if_local_object (& entry . oid );
863
+ maybe_record_name_entry (& entry );
841
864
} else if (obj -> type == OBJ_COMMIT ) {
842
865
struct commit * commit = (struct commit * ) obj ;
843
866
struct commit_list * parents = commit -> parents ;
844
867
868
+ record_outgoing_link (get_commit_tree_oid (commit ));
845
869
for (; parents ; parents = parents -> next )
846
- record_if_local_object (& parents -> item -> object .oid );
870
+ record_outgoing_link (& parents -> item -> object .oid );
847
871
} else if (obj -> type == OBJ_TAG ) {
848
872
struct tag * tag = (struct tag * ) obj ;
849
- record_if_local_object (get_tagged_oid (tag ));
873
+ record_outgoing_link (get_tagged_oid (tag ));
850
874
}
851
875
}
852
876
@@ -896,7 +920,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
896
920
free (has_data );
897
921
}
898
922
899
- if (strict || do_fsck_object || record_local_links ) {
923
+ if (strict || do_fsck_object || record_outgoing_links ) {
900
924
read_lock ();
901
925
if (type == OBJ_BLOB ) {
902
926
struct blob * blob = lookup_blob (the_repository , oid );
@@ -928,8 +952,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
928
952
die (_ ("fsck error in packed object" ));
929
953
if (strict && fsck_walk (obj , NULL , & fsck_options ))
930
954
die (_ ("Not all child objects of %s are reachable" ), oid_to_hex (& obj -> oid ));
931
- if (record_local_links )
932
- do_record_local_links (obj );
955
+ if (record_outgoing_links )
956
+ do_record_outgoing_links (obj );
933
957
934
958
if (obj -> type == OBJ_TREE ) {
935
959
struct tree * item = (struct tree * ) obj ;
@@ -1785,28 +1809,43 @@ static void repack_local_links(void)
1785
1809
struct strbuf line = STRBUF_INIT ;
1786
1810
struct oidset_iter iter ;
1787
1811
struct object_id * oid ;
1788
- char * base_name ;
1812
+ char * base_name = NULL ;
1789
1813
1790
- if (!oidset_size (& local_links ))
1814
+ if (!oidset_size (& outgoing_links ))
1791
1815
return ;
1792
1816
1793
- base_name = mkpathdup ("%s/pack/pack" , repo_get_object_directory (the_repository ));
1817
+ oidset_iter_init (& outgoing_links , & iter );
1818
+ while ((oid = oidset_iter_next (& iter ))) {
1819
+ struct object_info info = OBJECT_INFO_INIT ;
1820
+ if (oid_object_info_extended (the_repository , oid , & info , 0 ))
1821
+ /* Missing; assume it is a promisor object */
1822
+ continue ;
1823
+ if (info .whence == OI_PACKED && info .u .packed .pack -> pack_promisor )
1824
+ continue ;
1794
1825
1795
- strvec_push (& cmd .args , "pack-objects" );
1796
- strvec_push (& cmd .args , "--exclude-promisor-objects-best-effort" );
1797
- strvec_push (& cmd .args , base_name );
1798
- cmd .git_cmd = 1 ;
1799
- cmd .in = -1 ;
1800
- cmd .out = -1 ;
1801
- if (start_command (& cmd ))
1802
- die (_ ("could not start pack-objects to repack local links" ));
1826
+ if (!cmd .args .nr ) {
1827
+ base_name = mkpathdup (
1828
+ "%s/pack/pack" ,
1829
+ repo_get_object_directory (the_repository ));
1830
+ strvec_push (& cmd .args , "pack-objects" );
1831
+ strvec_push (& cmd .args ,
1832
+ "--exclude-promisor-objects-best-effort" );
1833
+ strvec_push (& cmd .args , base_name );
1834
+ cmd .git_cmd = 1 ;
1835
+ cmd .in = -1 ;
1836
+ cmd .out = -1 ;
1837
+ if (start_command (& cmd ))
1838
+ die (_ ("could not start pack-objects to repack local links" ));
1839
+ }
1803
1840
1804
- oidset_iter_init (& local_links , & iter );
1805
- while ((oid = oidset_iter_next (& iter ))) {
1806
1841
if (write_in_full (cmd .in , oid_to_hex (oid ), the_hash_algo -> hexsz ) < 0 ||
1807
1842
write_in_full (cmd .in , "\n" , 1 ) < 0 )
1808
1843
die (_ ("failed to feed local object to pack-objects" ));
1809
1844
}
1845
+
1846
+ if (!cmd .args .nr )
1847
+ return ;
1848
+
1810
1849
close (cmd .in );
1811
1850
1812
1851
out = xfdopen (cmd .out , "r" );
@@ -1905,7 +1944,7 @@ int cmd_index_pack(int argc,
1905
1944
} else if (skip_to_optional_arg (arg , "--keep" , & keep_msg )) {
1906
1945
; /* nothing to do */
1907
1946
} else if (skip_to_optional_arg (arg , "--promisor" , & promisor_msg )) {
1908
- record_local_links = 1 ;
1947
+ record_outgoing_links = 1 ;
1909
1948
} else if (starts_with (arg , "--threads=" )) {
1910
1949
char * end ;
1911
1950
nr_threads = strtoul (arg + 10 , & end , 0 );
0 commit comments