2323#include "odb.h"
2424#include "odb/streaming.h"
2525#include "oid-array.h"
26- #include "oidset.h"
26+ #include "hash-lookup.h"
27+ #include "oidmap.h"
2728#include "path.h"
2829#include "replace-object.h"
2930#include "tree-walk.h"
@@ -105,6 +106,12 @@ static size_t base_cache_limit;
105106struct thread_local_data {
106107 pthread_t thread ;
107108 int pack_fd ;
109+ struct oidmap outgoing_links ;
110+ };
111+
112+ struct outgoing_link {
113+ struct oidmap_entry entry ;
114+ enum object_type type ;
108115};
109116
110117/* Remember to update object flag allocation in object.h */
@@ -155,11 +162,8 @@ static uint32_t input_crc32;
155162static int input_fd , output_fd ;
156163static const char * curr_pack ;
157164
158- /*
159- * outgoing_links is guarded by read_mutex, and record_outgoing_links is
160- * read-only in a thread.
161- */
162- static struct oidset outgoing_links = OIDSET_INIT ;
165+ /* Worker-local maps are merged after all workers have exited. */
166+ static struct oidmap outgoing_links = OIDMAP_INIT ;
163167static int record_outgoing_links ;
164168
165169static struct thread_local_data * thread_data ;
@@ -196,6 +200,55 @@ static inline void unlock_mutex(pthread_mutex_t *mutex)
196200 pthread_mutex_unlock (mutex );
197201}
198202
203+ static void record_outgoing_link_to (struct oidmap * map ,
204+ const struct object_id * oid ,
205+ enum object_type type )
206+ {
207+ struct outgoing_link * link = oidmap_get (map , oid );
208+
209+ if (link ) {
210+ if (type != OBJ_ANY && link -> type != OBJ_ANY &&
211+ type != link -> type )
212+ die (_ ("object %s is referred to as both a %s and a %s" ),
213+ oid_to_hex (oid ), type_name (link -> type ),
214+ type_name (type ));
215+ if (link -> type == OBJ_ANY )
216+ link -> type = type ;
217+ return ;
218+ }
219+
220+ CALLOC_ARRAY (link , 1 );
221+ oidcpy (& link -> entry .oid , oid );
222+ link -> type = type ;
223+ if (oidmap_put (map , link ))
224+ BUG ("duplicate outgoing link" );
225+ }
226+
227+ static void merge_outgoing_links (struct oidmap * dest , struct oidmap * src )
228+ {
229+ struct oidmap_iter iter ;
230+ struct outgoing_link * link ;
231+
232+ while ((link = oidmap_iter_first (src , & iter ))) {
233+ struct outgoing_link * old = oidmap_get (dest , & link -> entry .oid );
234+
235+ oidmap_remove (src , & link -> entry .oid );
236+ if (old ) {
237+ if (link -> type != OBJ_ANY && old -> type != OBJ_ANY &&
238+ link -> type != old -> type )
239+ die (_ ("object %s is referred to as both a %s and a %s" ),
240+ oid_to_hex (& link -> entry .oid ),
241+ type_name (old -> type ), type_name (link -> type ));
242+ if (old -> type == OBJ_ANY )
243+ old -> type = link -> type ;
244+ free (link );
245+ } else if (oidmap_put (dest , link )) {
246+ BUG ("duplicate outgoing link" );
247+ }
248+ }
249+ oidmap_clear (src , 0 );
250+ }
251+
199252/*
200253 * Mutex and conditional variable can't be statically-initialized on Windows.
201254 */
@@ -211,6 +264,7 @@ static void init_thread(void)
211264 CALLOC_ARRAY (thread_data , nr_threads );
212265 for (i = 0 ; i < nr_threads ; i ++ ) {
213266 thread_data [i ].pack_fd = xopen (curr_pack , O_RDONLY );
267+ oidmap_init (& thread_data [i ].outgoing_links , 0 );
214268 }
215269
216270 threads_active = 1 ;
@@ -221,14 +275,17 @@ static void cleanup_thread(void)
221275 int i ;
222276 if (!threads_active )
223277 return ;
224- threads_active = 0 ;
225278 pthread_mutex_destroy (& read_mutex );
226279 pthread_mutex_destroy (& counter_mutex );
227280 pthread_mutex_destroy (& work_mutex );
228281 if (show_stat )
229282 pthread_mutex_destroy (& deepest_delta_mutex );
230- for (i = 0 ; i < nr_threads ; i ++ )
283+ for (i = 0 ; i < nr_threads ; i ++ ) {
284+ merge_outgoing_links (& outgoing_links ,
285+ & thread_data [i ].outgoing_links );
231286 close (thread_data [i ].pack_fd );
287+ }
288+ threads_active = 0 ;
232289 pthread_key_delete (key );
233290 free (thread_data );
234291}
@@ -818,9 +875,14 @@ static int check_collison(struct object_entry *entry)
818875 return 0 ;
819876}
820877
821- static void record_outgoing_link (const struct object_id * oid )
878+ static void record_outgoing_link (const struct object_id * oid ,
879+ enum object_type type )
822880{
823- oidset_insert (& outgoing_links , oid );
881+ struct oidmap * map = & outgoing_links ;
882+
883+ if (threads_active && !strict && !do_fsck_object )
884+ map = & get_thread_data ()-> outgoing_links ;
885+ record_outgoing_link_to (map , oid , type );
824886}
825887
826888static void maybe_record_name_entry (const struct name_entry * entry )
@@ -849,7 +911,97 @@ static void maybe_record_name_entry(const struct name_entry *entry)
849911 * pack, so it won't be GC-ed, the tradeoff seems worth it.
850912 */
851913 if (S_ISDIR (entry -> mode ))
852- record_outgoing_link (& entry -> oid );
914+ record_outgoing_link (& entry -> oid , OBJ_ANY );
915+ }
916+
917+ static int parse_outgoing_link_oid (const char * * buf , const char * tail ,
918+ const char * header , struct object_id * oid )
919+ {
920+ const char * end ;
921+ size_t header_len = strlen (header );
922+
923+ if (tail - * buf <= header_len + the_hash_algo -> hexsz ||
924+ memcmp (* buf , header , header_len ) ||
925+ parse_oid_hex_algop (* buf + header_len , oid , & end ,
926+ the_hash_algo ) ||
927+ end >= tail || * end != '\n' )
928+ return -1 ;
929+ * buf = end + 1 ;
930+ return 0 ;
931+ }
932+
933+ static void record_outgoing_links_from_data (const void * data ,
934+ unsigned long size ,
935+ enum object_type type ,
936+ const struct object_id * oid )
937+ {
938+ const char * buf = data ;
939+ const char * tail = buf + size ;
940+
941+ if (type == OBJ_TREE ) {
942+ struct tree_desc desc ;
943+ struct name_entry entry ;
944+
945+ if (init_tree_desc_gently (& desc , oid , data , size , 0 ))
946+ return ;
947+ while (tree_entry_gently (& desc , & entry ))
948+ maybe_record_name_entry (& entry );
949+ } else if (type == OBJ_COMMIT ) {
950+ struct object_id link ;
951+ struct commit_graft * graft ;
952+ int i ;
953+
954+ if (threads_active &&
955+ !the_repository -> parsed_objects -> commit_graft_prepared )
956+ BUG ("commit grafts were not prepared before resolving deltas" );
957+ graft = lookup_commit_graft (the_repository , oid );
958+
959+ if (parse_outgoing_link_oid (& buf , tail , "tree " , & link ))
960+ die (_ ("invalid tree line in commit %s" ),
961+ oid_to_hex (oid ));
962+ if (buf >= tail )
963+ die (_ ("truncated commit %s after tree line" ),
964+ oid_to_hex (oid ));
965+ record_outgoing_link (& link , OBJ_TREE );
966+
967+ while (tail - buf > 7 + the_hash_algo -> hexsz &&
968+ starts_with (buf , "parent " )) {
969+ if (parse_outgoing_link_oid (& buf , tail , "parent " ,
970+ & link ))
971+ die (_ ("invalid parent line in commit %s" ),
972+ oid_to_hex (oid ));
973+ if (buf >= tail )
974+ die (_ ("truncated commit %s after parent line" ),
975+ oid_to_hex (oid ));
976+ if (!graft ||
977+ (graft -> nr_parent >= 0 && grafts_keep_true_parents ))
978+ record_outgoing_link (& link , OBJ_COMMIT );
979+ }
980+ if (graft )
981+ for (i = 0 ; i < graft -> nr_parent ; i ++ )
982+ record_outgoing_link (& graft -> parent [i ],
983+ OBJ_COMMIT );
984+ } else if (type == OBJ_TAG ) {
985+ struct object_id link ;
986+ const char * line_end ;
987+ enum object_type target_type ;
988+
989+ if (size < the_hash_algo -> hexsz + 24 ||
990+ parse_outgoing_link_oid (& buf , tail , "object " , & link ))
991+ die (_ ("invalid object line in tag %s" ), oid_to_hex (oid ));
992+ if (!skip_prefix (buf , "type " , & buf ) ||
993+ !(line_end = memchr (buf , '\n' , tail - buf )))
994+ die (_ ("invalid type line in tag %s" ), oid_to_hex (oid ));
995+ target_type = type_from_string_gently (buf , line_end - buf , 1 );
996+ if (target_type < 0 )
997+ die (_ ("invalid type line in tag %s" ), oid_to_hex (oid ));
998+ buf = line_end + 1 ;
999+ if (buf + 4 >= tail || !skip_prefix (buf , "tag " , & buf ) ||
1000+ !memchr (buf , '\n' , tail - buf ))
1001+ die (_ ("invalid tag name line in tag %s" ),
1002+ oid_to_hex (oid ));
1003+ record_outgoing_link (& link , target_type );
1004+ }
8531005}
8541006
8551007static void do_record_outgoing_links (struct object * obj )
@@ -871,12 +1023,13 @@ static void do_record_outgoing_links(struct object *obj)
8711023 struct commit * commit = (struct commit * ) obj ;
8721024 struct commit_list * parents = commit -> parents ;
8731025
874- record_outgoing_link (get_commit_tree_oid (commit ));
1026+ record_outgoing_link (get_commit_tree_oid (commit ), OBJ_TREE );
8751027 for (; parents ; parents = parents -> next )
876- record_outgoing_link (& parents -> item -> object .oid );
1028+ record_outgoing_link (& parents -> item -> object .oid ,
1029+ OBJ_COMMIT );
8771030 } else if (obj -> type == OBJ_TAG ) {
8781031 struct tag * tag = (struct tag * ) obj ;
879- record_outgoing_link (get_tagged_oid (tag ));
1032+ record_outgoing_link (get_tagged_oid (tag ), tag -> tagged -> type );
8801033 }
8811034}
8821035
@@ -925,6 +1078,12 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
9251078 free (has_data );
9261079 }
9271080
1081+ if (record_outgoing_links && !strict && !do_fsck_object ) {
1082+ if (type != OBJ_BLOB )
1083+ record_outgoing_links_from_data (data , size , type , oid );
1084+ goto out ;
1085+ }
1086+
9281087 if (strict || do_fsck_object || record_outgoing_links ) {
9291088 read_lock ();
9301089 if (type == OBJ_BLOB ) {
@@ -975,6 +1134,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
9751134 read_unlock ();
9761135 }
9771136
1137+ out :
9781138 free (new_data );
9791139}
9801140
@@ -1811,20 +1971,53 @@ static void show_pack_info(int stat_only)
18111971 free (chain_histogram );
18121972}
18131973
1974+ static const struct object_id * idx_object_oid (size_t pos , const void * table )
1975+ {
1976+ struct pack_idx_entry * const * entries = table ;
1977+
1978+ return & entries [pos ]-> oid ;
1979+ }
1980+
1981+ static void validate_outgoing_link_types (struct pack_idx_entry * * sorted ,
1982+ int nr )
1983+ {
1984+ struct oidmap_iter iter ;
1985+ struct outgoing_link * link ;
1986+
1987+ oidmap_iter_init (& outgoing_links , & iter );
1988+ while ((link = oidmap_iter_next (& iter ))) {
1989+ int pos ;
1990+ struct object_entry * actual ;
1991+
1992+ if (link -> type == OBJ_ANY )
1993+ continue ;
1994+ pos = oid_pos (& link -> entry .oid , sorted , nr , idx_object_oid );
1995+ if (pos < 0 )
1996+ continue ;
1997+ actual = container_of (sorted [pos ], struct object_entry , idx );
1998+ if (actual -> real_type != link -> type )
1999+ die (_ ("object %s is a %s, but was referred to as a %s" ),
2000+ oid_to_hex (& link -> entry .oid ),
2001+ type_name (actual -> real_type ),
2002+ type_name (link -> type ));
2003+ }
2004+ }
2005+
18142006static void repack_local_links (void )
18152007{
18162008 struct child_process cmd = CHILD_PROCESS_INIT ;
18172009 FILE * out ;
18182010 struct strbuf line = STRBUF_INIT ;
1819- struct oidset_iter iter ;
1820- struct object_id * oid ;
2011+ struct oidmap_iter iter ;
2012+ struct outgoing_link * link ;
18212013 char * base_name = NULL ;
18222014
1823- if (!oidset_size (& outgoing_links ))
2015+ if (!oidmap_get_size (& outgoing_links ))
18242016 return ;
18252017
1826- oidset_iter_init (& outgoing_links , & iter );
1827- while ((oid = oidset_iter_next (& iter ))) {
2018+ oidmap_iter_init (& outgoing_links , & iter );
2019+ while ((link = oidmap_iter_next (& iter ))) {
2020+ const struct object_id * oid = & link -> entry .oid ;
18282021 struct odb_source_info source_info ;
18292022 struct object_info info = {
18302023 .source_infop = & source_info ,
@@ -1919,6 +2112,7 @@ int cmd_index_pack(int argc,
19192112 fsck_options .walk = mark_link ;
19202113
19212114 reset_pack_idx_option (& opts );
2115+ oidmap_init (& outgoing_links , 0 );
19222116 opts .flags |= WRITE_REV ;
19232117 repo_config (the_repository , git_index_pack_config , & opts );
19242118 if (prefix && chdir (prefix ))
@@ -2102,6 +2296,7 @@ int cmd_index_pack(int argc,
21022296 idx_objects [i ] = & objects [i ].idx ;
21032297 curr_index = write_idx_file (the_repository , index_name , idx_objects ,
21042298 nr_objects , & opts , pack_hash );
2299+ validate_outgoing_link_types (idx_objects , nr_objects );
21052300 if (rev_index )
21062301 curr_rev_index = write_rev_file (the_repository , rev_index_name ,
21072302 idx_objects , nr_objects ,
@@ -2146,6 +2341,7 @@ int cmd_index_pack(int argc,
21462341 free (curr_rev_index );
21472342
21482343 repack_local_links ();
2344+ oidmap_clear (& outgoing_links , 1 );
21492345
21502346 /*
21512347 * Let the caller know this pack is not self contained
0 commit comments