midx-write.c: introduce `struct write_midx_opts`

In the MIDX writing code, there are four functions which perform some sort of MIDX write operation. They are: - write_midx_file() - write_midx_file_only() - expire_midx_packs() - midx_repack() All of these functions are thin wrappers over `write_midx_internal()`, which implements the bulk of these routines. As a result, the `write_midx_internal()` function takes six arguments. Future commits in this series will want to add additional arguments, and in general this function's signature will be the union of parameters among *all* possible ways to write a MIDX. Instead of adding yet more arguments to this function to support MIDX compaction, introduce a `struct write_midx_opts`, which has the same struct members as `write_midx_internal()`'s arguments. Adding additional fields to the `write_midx_opts` struct is preferable to adding additional arguments to `write_midx_internal()`. This is because the callers below all zero-initialize the struct, so each time we add a new piece of information, we do not have to pass the zero value for it in all other call-sites that do not care about it. For now, no functional changes are included in this patch. Signed-off-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Taylor Blau committed Feb 24, 2026 at 14:00 UTC 82c905ea6bd79cd2045fea91b67f4c858379bff1
1 file changed +81 -54
midx-write.c
+81 -54
@@ -1078,14 +1078,20 @@ out:
1078 return needed;
1079 }
1080
1081 -static int write_midx_internal(struct odb_source *source,
1082 - struct string_list *packs_to_include,
1083 - struct string_list *packs_to_drop,
1084 - const char *preferred_pack_name,
1085 - const char *refs_snapshot,
1086 - unsigned flags)
1081 +struct write_midx_opts {
1082 + struct odb_source *source; /* non-optional */
1083 +
1084 + struct string_list *packs_to_include;
1085 + struct string_list *packs_to_drop;
1086 +
1087 + const char *preferred_pack_name;
1088 + const char *refs_snapshot;
1089 + unsigned flags;
1090 +};
1091 +
1092 +static int write_midx_internal(struct write_midx_opts *opts)
1093 {
1088 - struct repository *r = source->odb->repo;
1094 + struct repository *r = opts->source->odb->repo;
1095 struct strbuf midx_name = STRBUF_INIT;
1096 unsigned char midx_hash[GIT_MAX_RAWSZ];
1097 uint32_t start_pack;
@@ -1106,22 +1112,22 @@ static int write_midx_internal(struct odb_source *source,
1112 trace2_region_enter("midx", "write_midx_internal", r);
1113
1114 ctx.repo = r;
1109 - ctx.source = source;
1115 + ctx.source = opts->source;
1116
1111 - ctx.incremental = !!(flags & MIDX_WRITE_INCREMENTAL);
1117 + ctx.incremental = !!(opts->flags & MIDX_WRITE_INCREMENTAL);
1118
1119 if (ctx.incremental)
1120 strbuf_addf(&midx_name,
1121 "%s/pack/multi-pack-index.d/tmp_midx_XXXXXX",
1116 - source->path);
1122 + opts->source->path);
1123 else
1118 - get_midx_filename(source, &midx_name);
1124 + get_midx_filename(opts->source, &midx_name);
1125 if (safe_create_leading_directories(r, midx_name.buf))
1126 die_errno(_("unable to create leading directories of %s"),
1127 midx_name.buf);
1128
1123 - if (!packs_to_include || ctx.incremental) {
1124 - struct multi_pack_index *m = get_multi_pack_index(source);
1129 + if (!opts->packs_to_include || ctx.incremental) {
1130 + struct multi_pack_index *m = get_multi_pack_index(opts->source);
1131 if (m && !midx_checksum_valid(m)) {
1132 warning(_("ignoring existing multi-pack-index; checksum mismatch"));
1133 m = NULL;
@@ -1136,7 +1142,7 @@ static int write_midx_internal(struct odb_source *source,
1142 */
1143 if (ctx.incremental)
1144 ctx.base_midx = m;
1139 - else if (!packs_to_include)
1145 + else if (!opts->packs_to_include)
1146 ctx.m = m;
1147 }
1148 }
@@ -1149,7 +1155,7 @@ static int write_midx_internal(struct odb_source *source,
1155 if (ctx.incremental) {
1156 struct multi_pack_index *m = ctx.base_midx;
1157 while (m) {
1152 - if (flags & MIDX_WRITE_BITMAP && load_midx_revindex(m)) {
1158 + if (opts->flags & MIDX_WRITE_BITMAP && load_midx_revindex(m)) {
1159 error(_("could not load reverse index for MIDX %s"),
1160 midx_get_checksum_hex(m));
1161 goto cleanup;
@@ -1164,18 +1170,18 @@ static int write_midx_internal(struct odb_source *source,
1170 start_pack = ctx.nr;
1171
1172 ctx.pack_paths_checked = 0;
1167 - if (flags & MIDX_PROGRESS)
1173 + if (opts->flags & MIDX_PROGRESS)
1174 ctx.progress = start_delayed_progress(r,
1175 _("Adding packfiles to multi-pack-index"), 0);
1176 else
1177 ctx.progress = NULL;
1178
1173 - ctx.to_include = packs_to_include;
1179 + ctx.to_include = opts->packs_to_include;
1180
1175 - for_each_file_in_pack_dir(source->path, add_pack_to_midx, &ctx);
1181 + for_each_file_in_pack_dir(opts->source->path, add_pack_to_midx, &ctx);
1182 stop_progress(&ctx.progress);
1183
1178 - if (!packs_to_drop) {
1184 + if (!opts->packs_to_drop) {
1185 /*
1186 * If there is no MIDX then either it doesn't exist, or we're
1187 * doing a geometric repack. Try to load it from the source to
@@ -1188,7 +1194,7 @@ static int write_midx_internal(struct odb_source *source,
1194 if (midx && !midx_needs_update(midx, &ctx)) {
1195 struct bitmap_index *bitmap_git;
1196 int bitmap_exists;
1191 - int want_bitmap = flags & MIDX_WRITE_BITMAP;
1197 + int want_bitmap = opts->flags & MIDX_WRITE_BITMAP;
1198
1199 bitmap_git = prepare_midx_bitmap_git(midx);
1200 bitmap_exists = bitmap_git && bitmap_is_midx(bitmap_git);
@@ -1200,7 +1206,7 @@ static int write_midx_internal(struct odb_source *source,
1206 * corresponding bitmap (or one wasn't requested).
1207 */
1208 if (!want_bitmap)
1203 - clear_midx_files_ext(source, "bitmap", NULL);
1209 + clear_midx_files_ext(ctx.source, "bitmap", NULL);
1210 result = 0;
1211 goto cleanup;
1212 }
@@ -1215,11 +1221,11 @@ static int write_midx_internal(struct odb_source *source,
1221 goto cleanup; /* nothing to do */
1222 }
1223
1218 - if (preferred_pack_name) {
1224 + if (opts->preferred_pack_name) {
1225 ctx.preferred_pack_idx = NO_PREFERRED_PACK;
1226
1227 for (size_t i = 0; i < ctx.nr; i++) {
1222 - if (!cmp_idx_or_pack_name(preferred_pack_name,
1228 + if (!cmp_idx_or_pack_name(opts->preferred_pack_name,
1229 ctx.info[i].pack_name)) {
1230 ctx.preferred_pack_idx = i;
1231 break;
@@ -1228,9 +1234,9 @@ static int write_midx_internal(struct odb_source *source,
1234
1235 if (ctx.preferred_pack_idx == NO_PREFERRED_PACK)
1236 warning(_("unknown preferred pack: '%s'"),
1231 - preferred_pack_name);
1237 + opts->preferred_pack_name);
1238 } else if (ctx.nr &&
1233 - (flags & (MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP))) {
1239 + (opts->flags & (MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP))) {
1240 struct packed_git *oldest = ctx.info[0].p;
1241 ctx.preferred_pack_idx = 0;
1242
@@ -1241,7 +1247,7 @@ static int write_midx_internal(struct odb_source *source,
1247 */
1248 open_pack_index(oldest);
1249
1244 - if (packs_to_drop && packs_to_drop->nr)
1250 + if (opts->packs_to_drop && opts->packs_to_drop->nr)
1251 BUG("cannot write a MIDX bitmap during expiration");
1252
1253 /*
@@ -1303,20 +1309,21 @@ static int write_midx_internal(struct odb_source *source,
1309
1310 QSORT(ctx.info, ctx.nr, pack_info_compare);
1311
1306 - if (packs_to_drop && packs_to_drop->nr) {
1312 + if (opts->packs_to_drop && opts->packs_to_drop->nr) {
1313 size_t drop_index = 0;
1314 int missing_drops = 0;
1315
1310 - for (size_t i = 0; i < ctx.nr && drop_index < packs_to_drop->nr; i++) {
1316 + for (size_t i = 0;
1317 + i < ctx.nr && drop_index < opts->packs_to_drop->nr; i++) {
1318 int cmp = strcmp(ctx.info[i].pack_name,
1312 - packs_to_drop->items[drop_index].string);
1319 + opts->packs_to_drop->items[drop_index].string);
1320
1321 if (!cmp) {
1322 drop_index++;
1323 ctx.info[i].expired = 1;
1324 } else if (cmp > 0) {
1325 error(_("did not see pack-file %s to drop"),
1319 - packs_to_drop->items[drop_index].string);
1326 + opts->packs_to_drop->items[drop_index].string);
1327 drop_index++;
1328 missing_drops++;
1329 i--;
@@ -1353,8 +1360,8 @@ static int write_midx_internal(struct odb_source *source,
1360 }
1361
1362 /* Check that the preferred pack wasn't expired (if given). */
1356 - if (preferred_pack_name) {
1357 - struct pack_info *preferred = bsearch(preferred_pack_name,
1363 + if (opts->preferred_pack_name) {
1364 + struct pack_info *preferred = bsearch(opts->preferred_pack_name,
1365 ctx.info, ctx.nr,
1366 sizeof(*ctx.info),
1367 idx_or_pack_name_cmp);
@@ -1362,7 +1369,7 @@ static int write_midx_internal(struct odb_source *source,
1369 uint32_t perm = ctx.pack_perm[preferred->orig_pack_int_id];
1370 if (perm == PACK_EXPIRED)
1371 warning(_("preferred pack '%s' is expired"),
1365 - preferred_pack_name);
1372 + opts->preferred_pack_name);
1373 }
1374 }
1375
@@ -1376,15 +1383,15 @@ static int write_midx_internal(struct odb_source *source,
1383 }
1384
1385 if (!ctx.entries_nr) {
1379 - if (flags & MIDX_WRITE_BITMAP)
1386 + if (opts->flags & MIDX_WRITE_BITMAP)
1387 warning(_("refusing to write multi-pack .bitmap without any objects"));
1381 - flags &= ~(MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP);
1388 + opts->flags &= ~(MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP);
1389 }
1390
1391 if (ctx.incremental) {
1392 struct strbuf lock_name = STRBUF_INIT;
1393
1387 - get_midx_chain_filename(source, &lock_name);
1394 + get_midx_chain_filename(opts->source, &lock_name);
1395 hold_lock_file_for_update(&lk, lock_name.buf, LOCK_DIE_ON_ERROR);
1396 strbuf_release(&lock_name);
1397
@@ -1427,7 +1434,7 @@ static int write_midx_internal(struct odb_source *source,
1434 MIDX_CHUNK_LARGE_OFFSET_WIDTH),
1435 write_midx_large_offsets);
1436
1430 - if (flags & (MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP)) {
1437 + if (opts->flags & (MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP)) {
1438 ctx.pack_order = midx_pack_order(&ctx);
1439 add_chunk(cf, MIDX_CHUNKID_REVINDEX,
1440 st_mult(ctx.entries_nr, sizeof(uint32_t)),
@@ -1445,11 +1452,11 @@ static int write_midx_internal(struct odb_source *source,
1452 CSUM_FSYNC | CSUM_HASH_IN_STREAM);
1453 free_chunkfile(cf);
1454
1448 - if (flags & MIDX_WRITE_REV_INDEX &&
1455 + if (opts->flags & MIDX_WRITE_REV_INDEX &&
1456 git_env_bool("GIT_TEST_MIDX_WRITE_REV", 0))
1457 write_midx_reverse_index(&ctx, midx_hash);
1458
1452 - if (flags & MIDX_WRITE_BITMAP) {
1459 + if (opts->flags & MIDX_WRITE_BITMAP) {
1460 struct packing_data pdata;
1461 struct commit_stack commits = COMMIT_STACK_INIT;
1462
@@ -1458,7 +1465,7 @@ static int write_midx_internal(struct odb_source *source,
1465
1466 prepare_midx_packing_data(&pdata, &ctx);
1467
1461 - find_commits_for_midx_bitmap(&commits, refs_snapshot, &ctx);
1468 + find_commits_for_midx_bitmap(&commits, opts->refs_snapshot, &ctx);
1469
1470 /*
1471 * The previous steps translated the information from
@@ -1469,8 +1476,8 @@ static int write_midx_internal(struct odb_source *source,
1476 FREE_AND_NULL(ctx.entries);
1477 ctx.entries_nr = 0;
1478
1472 - if (write_midx_bitmap(&ctx, midx_hash, &pdata,
1473 - commits.items, commits.nr, flags) < 0) {
1479 + if (write_midx_bitmap(&ctx, midx_hash, &pdata, commits.items,
1480 + commits.nr, opts->flags) < 0) {
1481 error(_("could not write multi-pack bitmap"));
1482 clear_packing_data(&pdata);
1483 commit_stack_clear(&commits);
@@ -1503,7 +1510,7 @@ static int write_midx_internal(struct odb_source *source,
1510 if (link_midx_to_chain(ctx.base_midx) < 0)
1511 goto cleanup;
1512
1506 - get_split_midx_filename_ext(source, &final_midx_name,
1513 + get_split_midx_filename_ext(opts->source, &final_midx_name,
1514 midx_hash, MIDX_EXT_MIDX);
1515
1516 if (rename_tempfile(&incr, final_midx_name.buf) < 0) {
@@ -1536,7 +1543,7 @@ static int write_midx_internal(struct odb_source *source,
1543 if (commit_lock_file(&lk) < 0)
1544 die_errno(_("could not write multi-pack-index"));
1545
1539 - clear_midx_files(source, keep_hashes,
1546 + clear_midx_files(opts->source, keep_hashes,
1547 ctx.num_multi_pack_indexes_before + 1,
1548 ctx.incremental);
1549 result = 0;
@@ -1571,9 +1578,14 @@ int write_midx_file(struct odb_source *source,
1578 const char *preferred_pack_name,
1579 const char *refs_snapshot, unsigned flags)
1580 {
1574 - return write_midx_internal(source, NULL, NULL,
1575 - preferred_pack_name, refs_snapshot,
1576 - flags);
1581 + struct write_midx_opts opts = {
1582 + .source = source,
1583 + .preferred_pack_name = preferred_pack_name,
1584 + .refs_snapshot = refs_snapshot,
1585 + .flags = flags,
1586 + };
1587 +
1588 + return write_midx_internal(&opts);
1589 }
1590
1591 int write_midx_file_only(struct odb_source *source,
@@ -1581,8 +1593,15 @@ int write_midx_file_only(struct odb_source *source,
1593 const char *preferred_pack_name,
1594 const char *refs_snapshot, unsigned flags)
1595 {
1584 - return write_midx_internal(source, packs_to_include, NULL,
1585 - preferred_pack_name, refs_snapshot, flags);
1596 + struct write_midx_opts opts = {
1597 + .source = source,
1598 + .packs_to_include = packs_to_include,
1599 + .preferred_pack_name = preferred_pack_name,
1600 + .refs_snapshot = refs_snapshot,
1601 + .flags = flags,
1602 + };
1603 +
1604 + return write_midx_internal(&opts);
1605 }
1606
1607 int expire_midx_packs(struct odb_source *source, unsigned flags)
@@ -1641,9 +1660,14 @@ int expire_midx_packs(struct odb_source *source, unsigned flags)
1660
1661 free(count);
1662
1644 - if (packs_to_drop.nr)
1645 - result = write_midx_internal(source, NULL,
1646 - &packs_to_drop, NULL, NULL, flags);
1663 + if (packs_to_drop.nr) {
1664 + struct write_midx_opts opts = {
1665 + .source = source,
1666 + .packs_to_drop = &packs_to_drop,
1667 + .flags = flags & MIDX_PROGRESS,
1668 + };
1669 + result = write_midx_internal(&opts);
1670 + }
1671
1672 string_list_clear(&packs_to_drop, 0);
1673
@@ -1776,6 +1800,10 @@ int midx_repack(struct odb_source *source, size_t batch_size, unsigned flags)
1800 struct child_process cmd = CHILD_PROCESS_INIT;
1801 FILE *cmd_in;
1802 struct multi_pack_index *m = get_multi_pack_index(source);
1803 + struct write_midx_opts opts = {
1804 + .source = source,
1805 + .flags = flags,
1806 + };
1807
1808 /*
1809 * When updating the default for these configuration
@@ -1850,8 +1878,7 @@ int midx_repack(struct odb_source *source, size_t batch_size, unsigned flags)
1878 goto cleanup;
1879 }
1880
1853 - result = write_midx_internal(source, NULL, NULL, NULL, NULL,
1854 - flags);
1881 + result = write_midx_internal(&opts);
1882
1883 cleanup:
1884 free(include_pack);