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