@@ -1014,6 +1014,65 @@ static void clear_midx_files(struct odb_source *source,
10141014 strbuf_release (& buf );
10151015}
10161016
1017+ static bool midx_needs_update (struct multi_pack_index * midx , struct write_midx_context * ctx )
1018+ {
1019+ struct strset packs = STRSET_INIT ;
1020+ struct strbuf buf = STRBUF_INIT ;
1021+ bool needed = true;
1022+
1023+ /*
1024+ * Ignore incremental updates for now. The assumption is that any
1025+ * incremental update would be either empty (in which case we will bail
1026+ * out later) or it would actually cover at least one new pack.
1027+ */
1028+ if (ctx -> incremental )
1029+ goto out ;
1030+
1031+ /*
1032+ * Otherwise, we need to verify that the packs covered by the existing
1033+ * MIDX match the packs that we already have. The logic to do so is way
1034+ * more complicated than it has any right to be. This is because:
1035+ *
1036+ * - We cannot assume any ordering.
1037+ *
1038+ * - The MIDX packs may not be loaded at all, and loading them would
1039+ * be wasteful. So we need to use the pack names tracked by the
1040+ * MIDX itself.
1041+ *
1042+ * - The MIDX pack names are tracking the ".idx" files, whereas the
1043+ * packs themselves are tracking the ".pack" files. So we need to
1044+ * strip suffixes.
1045+ */
1046+ if (ctx -> nr != midx -> num_packs + midx -> num_packs_in_base )
1047+ goto out ;
1048+
1049+ for (uint32_t i = 0 ; i < ctx -> nr ; i ++ ) {
1050+ strbuf_reset (& buf );
1051+ strbuf_addstr (& buf , pack_basename (ctx -> info [i ].p ));
1052+ strbuf_strip_suffix (& buf , ".pack" );
1053+
1054+ if (!strset_add (& packs , buf .buf ))
1055+ BUG ("same pack added twice?" );
1056+ }
1057+
1058+ for (uint32_t i = 0 ; i < ctx -> nr ; i ++ ) {
1059+ strbuf_reset (& buf );
1060+ strbuf_addstr (& buf , midx -> pack_names [i ]);
1061+ strbuf_strip_suffix (& buf , ".idx" );
1062+
1063+ if (!strset_contains (& packs , buf .buf ))
1064+ goto out ;
1065+ strset_remove (& packs , buf .buf );
1066+ }
1067+
1068+ needed = false;
1069+
1070+ out :
1071+ strbuf_release (& buf );
1072+ strset_clear (& packs );
1073+ return needed ;
1074+ }
1075+
10171076static int write_midx_internal (struct odb_source * source ,
10181077 struct string_list * packs_to_include ,
10191078 struct string_list * packs_to_drop ,
@@ -1031,6 +1090,7 @@ static int write_midx_internal(struct odb_source *source,
10311090 struct write_midx_context ctx = {
10321091 .preferred_pack_idx = NO_PREFERRED_PACK ,
10331092 };
1093+ struct multi_pack_index * midx_to_free = NULL ;
10341094 int bitmapped_packs_concat_len = 0 ;
10351095 int pack_name_concat_len = 0 ;
10361096 int dropped_packs = 0 ;
@@ -1111,27 +1171,39 @@ static int write_midx_internal(struct odb_source *source,
11111171 for_each_file_in_pack_dir (source -> path , add_pack_to_midx , & ctx );
11121172 stop_progress (& ctx .progress );
11131173
1114- if ((ctx .m && ctx .nr == ctx .m -> num_packs + ctx .m -> num_packs_in_base ) &&
1115- !ctx .incremental &&
1116- !(packs_to_include || packs_to_drop )) {
1117- struct bitmap_index * bitmap_git ;
1118- int bitmap_exists ;
1119- int want_bitmap = flags & MIDX_WRITE_BITMAP ;
1120-
1121- bitmap_git = prepare_midx_bitmap_git (ctx .m );
1122- bitmap_exists = bitmap_git && bitmap_is_midx (bitmap_git );
1123- free_bitmap_index (bitmap_git );
1124-
1125- if (bitmap_exists || !want_bitmap ) {
1126- /*
1127- * The correct MIDX already exists, and so does a
1128- * corresponding bitmap (or one wasn't requested).
1129- */
1130- if (!want_bitmap )
1131- clear_midx_files_ext (source , "bitmap" , NULL );
1132- result = 0 ;
1133- goto cleanup ;
1174+ if (!packs_to_drop ) {
1175+ /*
1176+ * If there is no MIDX then either it doesn't exist, or we're
1177+ * doing a geometric repack. Try to load it from the source to
1178+ * tell these two cases apart.
1179+ */
1180+ struct multi_pack_index * midx = ctx .m ;
1181+ if (!midx )
1182+ midx = midx_to_free = load_multi_pack_index (ctx .source );
1183+
1184+ if (midx && !midx_needs_update (midx , & ctx )) {
1185+ struct bitmap_index * bitmap_git ;
1186+ int bitmap_exists ;
1187+ int want_bitmap = flags & MIDX_WRITE_BITMAP ;
1188+
1189+ bitmap_git = prepare_midx_bitmap_git (midx );
1190+ bitmap_exists = bitmap_git && bitmap_is_midx (bitmap_git );
1191+ free_bitmap_index (bitmap_git );
1192+
1193+ if (bitmap_exists || !want_bitmap ) {
1194+ /*
1195+ * The correct MIDX already exists, and so does a
1196+ * corresponding bitmap (or one wasn't requested).
1197+ */
1198+ if (!want_bitmap )
1199+ clear_midx_files_ext (source , "bitmap" , NULL );
1200+ result = 0 ;
1201+ goto cleanup ;
1202+ }
11341203 }
1204+
1205+ close_midx (midx_to_free );
1206+ midx_to_free = NULL ;
11351207 }
11361208
11371209 if (ctx .incremental && !ctx .nr ) {
@@ -1487,6 +1559,7 @@ static int write_midx_internal(struct odb_source *source,
14871559 free (keep_hashes );
14881560 }
14891561 strbuf_release (& midx_name );
1562+ close_midx (midx_to_free );
14901563
14911564 trace2_region_leave ("midx" , "write_midx_internal" , r );
14921565
0 commit comments