aboutsummaryrefslogtreecommitdiff
path: root/midx-write.c
diff options
context:
space:
mode:
Diffstat (limited to 'midx-write.c')
-rw-r--r--midx-write.c525
1 files changed, 410 insertions, 115 deletions
diff --git a/midx-write.c b/midx-write.c
index 6485cb6706..0ff2e45aa7 100644
--- a/midx-write.c
+++ b/midx-write.c
@@ -36,10 +36,13 @@ extern int cmp_idx_or_pack_name(const char *idx_or_pack_name,
static size_t write_midx_header(const struct git_hash_algo *hash_algo,
struct hashfile *f, unsigned char num_chunks,
- uint32_t num_packs)
+ uint32_t num_packs, int version)
{
+ if (version != MIDX_VERSION_V1 && version != MIDX_VERSION_V2)
+ BUG("unexpected MIDX version: %d", version);
+
hashwrite_be32(f, MIDX_SIGNATURE);
- hashwrite_u8(f, MIDX_VERSION);
+ hashwrite_u8(f, version);
hashwrite_u8(f, oid_version(hash_algo));
hashwrite_u8(f, num_chunks);
hashwrite_u8(f, 0); /* unused */
@@ -105,15 +108,29 @@ struct write_midx_context {
uint32_t preferred_pack_idx;
+ int version; /* must be MIDX_VERSION_V1 or _V2 */
+
int incremental;
uint32_t num_multi_pack_indexes_before;
+ struct multi_pack_index *compact_from;
+ struct multi_pack_index *compact_to;
+ int compact;
+
struct string_list *to_include;
struct repository *repo;
struct odb_source *source;
};
+static uint32_t midx_pack_perm(struct write_midx_context *ctx,
+ uint32_t orig_pack_int_id)
+{
+ if (ctx->compact)
+ orig_pack_int_id -= ctx->compact_from->num_packs_in_base;
+ return ctx->pack_perm[orig_pack_int_id];
+}
+
static int should_include_pack(const struct write_midx_context *ctx,
const char *file_name)
{
@@ -257,18 +274,14 @@ static void midx_fanout_sort(struct midx_fanout *fanout)
QSORT(fanout->entries, fanout->nr, midx_oid_compare);
}
-static void midx_fanout_add_midx_fanout(struct midx_fanout *fanout,
- struct multi_pack_index *m,
- uint32_t cur_fanout,
- uint32_t preferred_pack)
+static void midx_fanout_add_midx_fanout_1(struct midx_fanout *fanout,
+ struct multi_pack_index *m,
+ uint32_t cur_fanout,
+ uint32_t preferred_pack)
{
uint32_t start = m->num_objects_in_base, end;
uint32_t cur_object;
- if (m->base_midx)
- midx_fanout_add_midx_fanout(fanout, m->base_midx, cur_fanout,
- preferred_pack);
-
if (cur_fanout)
start += ntohl(m->chunk_oid_fanout[cur_fanout - 1]);
end = m->num_objects_in_base + ntohl(m->chunk_oid_fanout[cur_fanout]);
@@ -292,6 +305,17 @@ static void midx_fanout_add_midx_fanout(struct midx_fanout *fanout,
}
}
+static void midx_fanout_add_midx_fanout(struct midx_fanout *fanout,
+ struct multi_pack_index *m,
+ uint32_t cur_fanout,
+ uint32_t preferred_pack)
+{
+ if (m->base_midx)
+ midx_fanout_add_midx_fanout(fanout, m->base_midx, cur_fanout,
+ preferred_pack);
+ midx_fanout_add_midx_fanout_1(fanout, m, cur_fanout, preferred_pack);
+}
+
static void midx_fanout_add_pack_fanout(struct midx_fanout *fanout,
struct pack_info *info,
uint32_t cur_pack,
@@ -317,6 +341,45 @@ static void midx_fanout_add_pack_fanout(struct midx_fanout *fanout,
}
}
+static void midx_fanout_add(struct midx_fanout *fanout,
+ struct write_midx_context *ctx,
+ uint32_t start_pack,
+ uint32_t cur_fanout)
+{
+ uint32_t cur_pack;
+
+ if (ctx->m && !ctx->incremental)
+ midx_fanout_add_midx_fanout(fanout, ctx->m, cur_fanout,
+ ctx->preferred_pack_idx);
+
+ for (cur_pack = start_pack; cur_pack < ctx->nr; cur_pack++) {
+ int preferred = cur_pack == ctx->preferred_pack_idx;
+ midx_fanout_add_pack_fanout(fanout, ctx->info, cur_pack,
+ preferred, cur_fanout);
+ }
+
+ if (ctx->preferred_pack_idx != NO_PREFERRED_PACK &&
+ ctx->preferred_pack_idx < start_pack)
+ midx_fanout_add_pack_fanout(fanout, ctx->info,
+ ctx->preferred_pack_idx, 1,
+ cur_fanout);
+}
+
+static void midx_fanout_add_compact(struct midx_fanout *fanout,
+ struct write_midx_context *ctx,
+ uint32_t cur_fanout)
+{
+ struct multi_pack_index *m = ctx->compact_to;
+
+ ASSERT(ctx->compact);
+
+ while (m && m != ctx->compact_from->base_midx) {
+ midx_fanout_add_midx_fanout_1(fanout, m, cur_fanout,
+ NO_PREFERRED_PACK);
+ m = m->base_midx;
+ }
+}
+
/*
* It is possible to artificially get into a state where there are many
* duplicate copies of objects. That can create high memory pressure if
@@ -335,6 +398,9 @@ static void compute_sorted_entries(struct write_midx_context *ctx,
size_t alloc_objects, total_objects = 0;
struct midx_fanout fanout = { 0 };
+ if (ctx->compact)
+ ASSERT(!start_pack);
+
for (cur_pack = start_pack; cur_pack < ctx->nr; cur_pack++)
total_objects = st_add(total_objects,
ctx->info[cur_pack].p->num_objects);
@@ -353,23 +419,10 @@ static void compute_sorted_entries(struct write_midx_context *ctx,
for (cur_fanout = 0; cur_fanout < 256; cur_fanout++) {
fanout.nr = 0;
- if (ctx->m && !ctx->incremental)
- midx_fanout_add_midx_fanout(&fanout, ctx->m, cur_fanout,
- ctx->preferred_pack_idx);
-
- for (cur_pack = start_pack; cur_pack < ctx->nr; cur_pack++) {
- int preferred = cur_pack == ctx->preferred_pack_idx;
- midx_fanout_add_pack_fanout(&fanout,
- ctx->info, cur_pack,
- preferred, cur_fanout);
- }
-
- if (ctx->preferred_pack_idx != NO_PREFERRED_PACK &&
- ctx->preferred_pack_idx < start_pack)
- midx_fanout_add_pack_fanout(&fanout, ctx->info,
- ctx->preferred_pack_idx, 1,
- cur_fanout);
-
+ if (ctx->compact)
+ midx_fanout_add_compact(&fanout, ctx, cur_fanout);
+ else
+ midx_fanout_add(&fanout, ctx, start_pack, cur_fanout);
midx_fanout_sort(&fanout);
/*
@@ -410,7 +463,9 @@ static int write_midx_pack_names(struct hashfile *f, void *data)
if (ctx->info[i].expired)
continue;
- if (i && strcmp(ctx->info[i].pack_name, ctx->info[i - 1].pack_name) <= 0)
+ if (ctx->version == MIDX_VERSION_V1 &&
+ i && strcmp(ctx->info[i].pack_name,
+ ctx->info[i - 1].pack_name) <= 0)
BUG("incorrect pack-file order: %s before %s",
ctx->info[i - 1].pack_name,
ctx->info[i].pack_name);
@@ -514,12 +569,12 @@ static int write_midx_object_offsets(struct hashfile *f,
for (i = 0; i < ctx->entries_nr; i++) {
struct pack_midx_entry *obj = list++;
- if (ctx->pack_perm[obj->pack_int_id] == PACK_EXPIRED)
+ if (midx_pack_perm(ctx, obj->pack_int_id) == PACK_EXPIRED)
BUG("object %s is in an expired pack with int-id %d",
oid_to_hex(&obj->oid),
obj->pack_int_id);
- hashwrite_be32(f, ctx->pack_perm[obj->pack_int_id]);
+ hashwrite_be32(f, midx_pack_perm(ctx, obj->pack_int_id));
if (ctx->large_offsets_needed && obj->offset >> 31)
hashwrite_be32(f, MIDX_LARGE_OFFSET_NEEDED | nr_large_offset++);
@@ -620,8 +675,8 @@ static uint32_t *midx_pack_order(struct write_midx_context *ctx)
for (i = 0; i < ctx->entries_nr; i++) {
struct pack_midx_entry *e = &ctx->entries[i];
data[i].nr = i;
- data[i].pack = ctx->pack_perm[e->pack_int_id];
- if (!e->preferred)
+ data[i].pack = midx_pack_perm(ctx, e->pack_int_id);
+ if (!e->preferred || ctx->compact)
data[i].pack |= (1U << 31);
data[i].offset = e->offset;
}
@@ -630,14 +685,14 @@ static uint32_t *midx_pack_order(struct write_midx_context *ctx)
for (i = 0; i < ctx->entries_nr; i++) {
struct pack_midx_entry *e = &ctx->entries[data[i].nr];
- struct pack_info *pack = &ctx->info[ctx->pack_perm[e->pack_int_id]];
+ struct pack_info *pack = &ctx->info[midx_pack_perm(ctx, e->pack_int_id)];
if (pack->bitmap_pos == BITMAP_POS_UNKNOWN)
pack->bitmap_pos = i + base_objects;
pack->bitmap_nr++;
pack_order[i] = data[i].nr;
}
for (i = 0; i < ctx->nr; i++) {
- struct pack_info *pack = &ctx->info[ctx->pack_perm[i]];
+ struct pack_info *pack = &ctx->info[i];
if (pack->bitmap_pos == BITMAP_POS_UNKNOWN)
pack->bitmap_pos = 0;
}
@@ -691,7 +746,7 @@ static void prepare_midx_packing_data(struct packing_data *pdata,
struct object_entry *to = packlist_alloc(pdata, &from->oid);
oe_set_in_pack(pdata, to,
- ctx->info[ctx->pack_perm[from->pack_int_id]].p);
+ ctx->info[midx_pack_perm(ctx, from->pack_int_id)].p);
}
trace2_region_leave("midx", "prepare_midx_packing_data", ctx->repo);
@@ -900,6 +955,21 @@ cleanup:
return ret;
}
+static int fill_pack_from_midx(struct pack_info *info,
+ struct multi_pack_index *m,
+ uint32_t pack_int_id)
+{
+ if (prepare_midx_pack(m, pack_int_id))
+ return error(_("could not load pack %d"), pack_int_id);
+
+ fill_pack_info(info,
+ m->packs[pack_int_id - m->num_packs_in_base],
+ m->pack_names[pack_int_id - m->num_packs_in_base],
+ pack_int_id);
+
+ return 0;
+}
+
static int fill_packs_from_midx(struct write_midx_context *ctx)
{
struct multi_pack_index *m;
@@ -907,19 +977,88 @@ static int fill_packs_from_midx(struct write_midx_context *ctx)
for (m = ctx->m; m; m = m->base_midx) {
uint32_t i;
- for (i = 0; i < m->num_packs; i++) {
- if (prepare_midx_pack(m, m->num_packs_in_base + i))
- return error(_("could not load pack"));
-
+ for (i = m->num_packs_in_base;
+ i < m->num_packs_in_base + m->num_packs; i++) {
ALLOC_GROW(ctx->info, ctx->nr + 1, ctx->alloc);
- fill_pack_info(&ctx->info[ctx->nr++], m->packs[i],
- m->pack_names[i],
- m->num_packs_in_base + i);
+
+ if (fill_pack_from_midx(&ctx->info[ctx->nr], m, i) < 0)
+ return -1;
+
+ ctx->nr++;
}
}
return 0;
}
+static uint32_t compactible_packs_between(const struct multi_pack_index *from,
+ const struct multi_pack_index *to)
+{
+ uint32_t nr;
+
+ ASSERT(from && to);
+
+ if (unsigned_add_overflows(to->num_packs, to->num_packs_in_base))
+ die(_("too many packs, unable to compact"));
+
+ nr = to->num_packs + to->num_packs_in_base;
+ if (nr < from->num_packs_in_base)
+ BUG("unexpected number of packs in base during compaction: "
+ "%"PRIu32" < %"PRIu32, nr, from->num_packs_in_base);
+
+ return nr - from->num_packs_in_base;
+}
+
+static int fill_packs_from_midx_range(struct write_midx_context *ctx,
+ int bitmap_order)
+{
+ struct multi_pack_index *m = ctx->compact_to;
+ uint32_t packs_nr;
+
+ ASSERT(ctx->compact && !ctx->nr);
+ ASSERT(ctx->compact_from);
+ ASSERT(ctx->compact_to);
+
+ packs_nr = compactible_packs_between(ctx->compact_from,
+ ctx->compact_to);
+
+ ALLOC_GROW(ctx->info, packs_nr, ctx->alloc);
+
+ while (m != ctx->compact_from->base_midx) {
+ uint32_t pack_int_id, preferred_pack_id;
+ uint32_t i;
+
+ if (bitmap_order) {
+ if (midx_preferred_pack(m, &preferred_pack_id) < 0)
+ die(_("could not determine preferred pack"));
+ } else {
+ preferred_pack_id = m->num_packs_in_base;
+ }
+
+ pack_int_id = m->num_packs_in_base - ctx->compact_from->num_packs_in_base;
+
+ if (fill_pack_from_midx(&ctx->info[pack_int_id++], m,
+ preferred_pack_id) < 0)
+ return -1;
+
+ for (i = m->num_packs_in_base;
+ i < m->num_packs_in_base + m->num_packs; i++) {
+ if (preferred_pack_id == i)
+ continue;
+
+ if (fill_pack_from_midx(&ctx->info[pack_int_id++], m,
+ i) < 0)
+ return -1;
+ }
+
+ ctx->nr += m->num_packs;
+ m = m->base_midx;
+ }
+
+ ASSERT(ctx->nr == packs_nr);
+
+ return 0;
+}
+
static struct {
const char *non_split;
const char *split;
@@ -946,7 +1085,7 @@ static int link_midx_to_chain(struct multi_pack_index *m)
}
for (i = 0; i < ARRAY_SIZE(midx_exts); i++) {
- const unsigned char *hash = get_midx_checksum(m);
+ const unsigned char *hash = midx_get_checksum_hash(m);
get_midx_filename_ext(m->source, &from,
hash, midx_exts[i].non_split);
@@ -1026,6 +1165,12 @@ static bool midx_needs_update(struct multi_pack_index *midx, struct write_midx_c
goto out;
/*
+ * If the version differs, we need to update.
+ */
+ if (midx->version != ctx->version)
+ goto out;
+
+ /*
* Ignore incremental updates for now. The assumption is that any
* incremental update would be either empty (in which case we will bail
* out later) or it would actually cover at least one new pack.
@@ -1033,6 +1178,9 @@ static bool midx_needs_update(struct multi_pack_index *midx, struct write_midx_c
if (ctx->incremental)
goto out;
+ if (ctx->compact)
+ goto out; /* Compaction always requires an update. */
+
/*
* Otherwise, we need to verify that the packs covered by the existing
* MIDX match the packs that we already have. The logic to do so is way
@@ -1078,14 +1226,31 @@ out:
return needed;
}
-static int write_midx_internal(struct odb_source *source,
- struct string_list *packs_to_include,
- struct string_list *packs_to_drop,
- const char *preferred_pack_name,
- const char *refs_snapshot,
- unsigned flags)
+static int midx_hashcmp(const struct multi_pack_index *a,
+ const struct multi_pack_index *b,
+ const struct git_hash_algo *algop)
{
- struct repository *r = source->odb->repo;
+ return hashcmp(midx_get_checksum_hash(a), midx_get_checksum_hash(b),
+ algop);
+}
+
+struct write_midx_opts {
+ struct odb_source *source; /* non-optional */
+
+ struct string_list *packs_to_include;
+ struct string_list *packs_to_drop;
+
+ struct multi_pack_index *compact_from;
+ struct multi_pack_index *compact_to;
+
+ const char *preferred_pack_name;
+ const char *refs_snapshot;
+ unsigned flags;
+};
+
+static int write_midx_internal(struct write_midx_opts *opts)
+{
+ struct repository *r = opts->source->odb->repo;
struct strbuf midx_name = STRBUF_INIT;
unsigned char midx_hash[GIT_MAX_RAWSZ];
uint32_t start_pack;
@@ -1094,6 +1259,7 @@ static int write_midx_internal(struct odb_source *source,
struct tempfile *incr;
struct write_midx_context ctx = {
.preferred_pack_idx = NO_PREFERRED_PACK,
+ .version = MIDX_VERSION_V2,
};
struct multi_pack_index *midx_to_free = NULL;
int bitmapped_packs_concat_len = 0;
@@ -1101,27 +1267,45 @@ static int write_midx_internal(struct odb_source *source,
int dropped_packs = 0;
int result = -1;
const char **keep_hashes = NULL;
+ size_t keep_hashes_nr = 0;
struct chunkfile *cf;
trace2_region_enter("midx", "write_midx_internal", r);
ctx.repo = r;
- ctx.source = source;
+ ctx.source = opts->source;
+
+ repo_config_get_int(ctx.repo, "midx.version", &ctx.version);
+ if (ctx.version != MIDX_VERSION_V1 && ctx.version != MIDX_VERSION_V2)
+ die(_("unknown MIDX version: %d"), ctx.version);
+
+ ctx.incremental = !!(opts->flags & MIDX_WRITE_INCREMENTAL);
+ ctx.compact = !!(opts->flags & MIDX_WRITE_COMPACT);
+
+ if (ctx.compact) {
+ if (ctx.version != MIDX_VERSION_V2)
+ die(_("cannot perform MIDX compaction with v1 format"));
+ if (!opts->compact_from)
+ BUG("expected non-NULL 'from' MIDX during compaction");
+ if (!opts->compact_to)
+ BUG("expected non-NULL 'to' MIDX during compaction");
- ctx.incremental = !!(flags & MIDX_WRITE_INCREMENTAL);
+ ctx.compact_from = opts->compact_from;
+ ctx.compact_to = opts->compact_to;
+ }
if (ctx.incremental)
strbuf_addf(&midx_name,
"%s/pack/multi-pack-index.d/tmp_midx_XXXXXX",
- source->path);
+ opts->source->path);
else
- get_midx_filename(source, &midx_name);
+ get_midx_filename(opts->source, &midx_name);
if (safe_create_leading_directories(r, midx_name.buf))
die_errno(_("unable to create leading directories of %s"),
midx_name.buf);
- if (!packs_to_include || ctx.incremental) {
- struct multi_pack_index *m = get_multi_pack_index(source);
+ if (!opts->packs_to_include || ctx.incremental) {
+ struct multi_pack_index *m = get_multi_pack_index(opts->source);
if (m && !midx_checksum_valid(m)) {
warning(_("ignoring existing multi-pack-index; checksum mismatch"));
m = NULL;
@@ -1136,11 +1320,18 @@ static int write_midx_internal(struct odb_source *source,
*/
if (ctx.incremental)
ctx.base_midx = m;
- else if (!packs_to_include)
+ if (!opts->packs_to_include)
ctx.m = m;
}
}
+ /*
+ * If compacting MIDX layer(s) in the range [from, to], then the
+ * compacted MIDX will share the same base MIDX as 'from'.
+ */
+ if (ctx.compact)
+ ctx.base_midx = ctx.compact_from->base_midx;
+
ctx.nr = 0;
ctx.alloc = ctx.m ? ctx.m->num_packs + ctx.m->num_packs_in_base : 16;
ctx.info = NULL;
@@ -1149,34 +1340,42 @@ static int write_midx_internal(struct odb_source *source,
if (ctx.incremental) {
struct multi_pack_index *m = ctx.base_midx;
while (m) {
- if (flags & MIDX_WRITE_BITMAP && load_midx_revindex(m)) {
+ if (opts->flags & MIDX_WRITE_BITMAP && load_midx_revindex(m)) {
error(_("could not load reverse index for MIDX %s"),
- hash_to_hex_algop(get_midx_checksum(m),
- m->source->odb->repo->hash_algo));
+ midx_get_checksum_hex(m));
goto cleanup;
}
ctx.num_multi_pack_indexes_before++;
m = m->base_midx;
}
- } else if (ctx.m && fill_packs_from_midx(&ctx)) {
+ } else if (ctx.m && !ctx.compact && fill_packs_from_midx(&ctx)) {
goto cleanup;
}
start_pack = ctx.nr;
ctx.pack_paths_checked = 0;
- if (flags & MIDX_PROGRESS)
+ if (opts->flags & MIDX_PROGRESS)
ctx.progress = start_delayed_progress(r,
_("Adding packfiles to multi-pack-index"), 0);
else
ctx.progress = NULL;
- ctx.to_include = packs_to_include;
+ if (ctx.compact) {
+ int bitmap_order = 0;
+ if (opts->preferred_pack_name)
+ bitmap_order |= 1;
+ else if (opts->flags & (MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP))
+ bitmap_order |= 1;
- for_each_file_in_pack_dir(source->path, add_pack_to_midx, &ctx);
+ fill_packs_from_midx_range(&ctx, bitmap_order);
+ } else {
+ ctx.to_include = opts->packs_to_include;
+ for_each_file_in_pack_dir(opts->source->path, add_pack_to_midx, &ctx);
+ }
stop_progress(&ctx.progress);
- if (!packs_to_drop) {
+ if (!opts->packs_to_drop) {
/*
* If there is no MIDX then either it doesn't exist, or we're
* doing a geometric repack. Try to load it from the source to
@@ -1189,7 +1388,7 @@ static int write_midx_internal(struct odb_source *source,
if (midx && !midx_needs_update(midx, &ctx)) {
struct bitmap_index *bitmap_git;
int bitmap_exists;
- int want_bitmap = flags & MIDX_WRITE_BITMAP;
+ int want_bitmap = opts->flags & MIDX_WRITE_BITMAP;
bitmap_git = prepare_midx_bitmap_git(midx);
bitmap_exists = bitmap_git && bitmap_is_midx(bitmap_git);
@@ -1201,7 +1400,7 @@ static int write_midx_internal(struct odb_source *source,
* corresponding bitmap (or one wasn't requested).
*/
if (!want_bitmap)
- clear_midx_files_ext(source, "bitmap", NULL);
+ clear_midx_files_ext(ctx.source, "bitmap", NULL);
result = 0;
goto cleanup;
}
@@ -1216,11 +1415,11 @@ static int write_midx_internal(struct odb_source *source,
goto cleanup; /* nothing to do */
}
- if (preferred_pack_name) {
+ if (opts->preferred_pack_name) {
ctx.preferred_pack_idx = NO_PREFERRED_PACK;
for (size_t i = 0; i < ctx.nr; i++) {
- if (!cmp_idx_or_pack_name(preferred_pack_name,
+ if (!cmp_idx_or_pack_name(opts->preferred_pack_name,
ctx.info[i].pack_name)) {
ctx.preferred_pack_idx = i;
break;
@@ -1229,9 +1428,9 @@ static int write_midx_internal(struct odb_source *source,
if (ctx.preferred_pack_idx == NO_PREFERRED_PACK)
warning(_("unknown preferred pack: '%s'"),
- preferred_pack_name);
+ opts->preferred_pack_name);
} else if (ctx.nr &&
- (flags & (MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP))) {
+ (opts->flags & (MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP))) {
struct packed_git *oldest = ctx.info[0].p;
ctx.preferred_pack_idx = 0;
@@ -1242,7 +1441,7 @@ static int write_midx_internal(struct odb_source *source,
*/
open_pack_index(oldest);
- if (packs_to_drop && packs_to_drop->nr)
+ if (opts->packs_to_drop && opts->packs_to_drop->nr)
BUG("cannot write a MIDX bitmap during expiration");
/*
@@ -1302,22 +1501,30 @@ static int write_midx_internal(struct odb_source *source,
ctx.large_offsets_needed = 1;
}
- QSORT(ctx.info, ctx.nr, pack_info_compare);
+ if (ctx.compact) {
+ if (ctx.version != MIDX_VERSION_V2)
+ BUG("performing MIDX compaction with v1 MIDX");
+ } else {
+ QSORT(ctx.info, ctx.nr, pack_info_compare);
+ }
- if (packs_to_drop && packs_to_drop->nr) {
+ if (opts->packs_to_drop && opts->packs_to_drop->nr) {
size_t drop_index = 0;
int missing_drops = 0;
- for (size_t i = 0; i < ctx.nr && drop_index < packs_to_drop->nr; i++) {
+ ASSERT(!ctx.compact);
+
+ for (size_t i = 0;
+ i < ctx.nr && drop_index < opts->packs_to_drop->nr; i++) {
int cmp = strcmp(ctx.info[i].pack_name,
- packs_to_drop->items[drop_index].string);
+ opts->packs_to_drop->items[drop_index].string);
if (!cmp) {
drop_index++;
ctx.info[i].expired = 1;
} else if (cmp > 0) {
error(_("did not see pack-file %s to drop"),
- packs_to_drop->items[drop_index].string);
+ opts->packs_to_drop->items[drop_index].string);
drop_index++;
missing_drops++;
i--;
@@ -1338,12 +1545,20 @@ static int write_midx_internal(struct odb_source *source,
*/
ALLOC_ARRAY(ctx.pack_perm, ctx.nr);
for (size_t i = 0; i < ctx.nr; i++) {
+ uint32_t from = ctx.info[i].orig_pack_int_id;
+ uint32_t to;
+
if (ctx.info[i].expired) {
+ to = PACK_EXPIRED;
dropped_packs++;
- ctx.pack_perm[ctx.info[i].orig_pack_int_id] = PACK_EXPIRED;
} else {
- ctx.pack_perm[ctx.info[i].orig_pack_int_id] = i - dropped_packs;
+ to = i - dropped_packs;
}
+
+ if (ctx.compact)
+ from -= ctx.compact_from->num_packs_in_base;
+
+ ctx.pack_perm[from] = to;
}
for (size_t i = 0; i < ctx.nr; i++) {
@@ -1354,16 +1569,16 @@ static int write_midx_internal(struct odb_source *source,
}
/* Check that the preferred pack wasn't expired (if given). */
- if (preferred_pack_name) {
- struct pack_info *preferred = bsearch(preferred_pack_name,
+ if (opts->preferred_pack_name) {
+ struct pack_info *preferred = bsearch(opts->preferred_pack_name,
ctx.info, ctx.nr,
sizeof(*ctx.info),
idx_or_pack_name_cmp);
if (preferred) {
- uint32_t perm = ctx.pack_perm[preferred->orig_pack_int_id];
+ uint32_t perm = midx_pack_perm(&ctx, preferred->orig_pack_int_id);
if (perm == PACK_EXPIRED)
warning(_("preferred pack '%s' is expired"),
- preferred_pack_name);
+ opts->preferred_pack_name);
}
}
@@ -1377,15 +1592,15 @@ static int write_midx_internal(struct odb_source *source,
}
if (!ctx.entries_nr) {
- if (flags & MIDX_WRITE_BITMAP)
+ if (opts->flags & MIDX_WRITE_BITMAP)
warning(_("refusing to write multi-pack .bitmap without any objects"));
- flags &= ~(MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP);
+ opts->flags &= ~(MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP);
}
if (ctx.incremental) {
struct strbuf lock_name = STRBUF_INIT;
- get_midx_chain_filename(source, &lock_name);
+ get_midx_chain_filename(opts->source, &lock_name);
hold_lock_file_for_update(&lk, lock_name.buf, LOCK_DIE_ON_ERROR);
strbuf_release(&lock_name);
@@ -1428,7 +1643,7 @@ static int write_midx_internal(struct odb_source *source,
MIDX_CHUNK_LARGE_OFFSET_WIDTH),
write_midx_large_offsets);
- if (flags & (MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP)) {
+ if (opts->flags & (MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP)) {
ctx.pack_order = midx_pack_order(&ctx);
add_chunk(cf, MIDX_CHUNKID_REVINDEX,
st_mult(ctx.entries_nr, sizeof(uint32_t)),
@@ -1439,18 +1654,18 @@ static int write_midx_internal(struct odb_source *source,
}
write_midx_header(r->hash_algo, f, get_num_chunks(cf),
- ctx.nr - dropped_packs);
+ ctx.nr - dropped_packs, ctx.version);
write_chunkfile(cf, &ctx);
finalize_hashfile(f, midx_hash, FSYNC_COMPONENT_PACK_METADATA,
CSUM_FSYNC | CSUM_HASH_IN_STREAM);
free_chunkfile(cf);
- if (flags & MIDX_WRITE_REV_INDEX &&
+ if (opts->flags & MIDX_WRITE_REV_INDEX &&
git_env_bool("GIT_TEST_MIDX_WRITE_REV", 0))
write_midx_reverse_index(&ctx, midx_hash);
- if (flags & MIDX_WRITE_BITMAP) {
+ if (opts->flags & MIDX_WRITE_BITMAP) {
struct packing_data pdata;
struct commit_stack commits = COMMIT_STACK_INIT;
@@ -1459,7 +1674,7 @@ static int write_midx_internal(struct odb_source *source,
prepare_midx_packing_data(&pdata, &ctx);
- find_commits_for_midx_bitmap(&commits, refs_snapshot, &ctx);
+ find_commits_for_midx_bitmap(&commits, opts->refs_snapshot, &ctx);
/*
* The previous steps translated the information from
@@ -1470,8 +1685,8 @@ static int write_midx_internal(struct odb_source *source,
FREE_AND_NULL(ctx.entries);
ctx.entries_nr = 0;
- if (write_midx_bitmap(&ctx, midx_hash, &pdata,
- commits.items, commits.nr, flags) < 0) {
+ if (write_midx_bitmap(&ctx, midx_hash, &pdata, commits.items,
+ commits.nr, opts->flags) < 0) {
error(_("could not write multi-pack bitmap"));
clear_packing_data(&pdata);
commit_stack_clear(&commits);
@@ -1489,7 +1704,24 @@ static int write_midx_internal(struct odb_source *source,
if (ctx.num_multi_pack_indexes_before == UINT32_MAX)
die(_("too many multi-pack-indexes"));
- CALLOC_ARRAY(keep_hashes, ctx.num_multi_pack_indexes_before + 1);
+ if (ctx.compact) {
+ struct multi_pack_index *m;
+
+ /*
+ * Keep all MIDX layers excluding those in the range [from, to].
+ */
+ for (m = ctx.base_midx; m; m = m->base_midx)
+ keep_hashes_nr++;
+ for (m = ctx.m;
+ m && midx_hashcmp(m, ctx.compact_to, r->hash_algo);
+ m = m->base_midx)
+ keep_hashes_nr++;
+
+ keep_hashes_nr++; /* include the compacted layer */
+ } else {
+ keep_hashes_nr = ctx.num_multi_pack_indexes_before + 1;
+ }
+ CALLOC_ARRAY(keep_hashes, keep_hashes_nr);
if (ctx.incremental) {
FILE *chainf = fdopen_lock_file(&lk, "w");
@@ -1504,7 +1736,7 @@ static int write_midx_internal(struct odb_source *source,
if (link_midx_to_chain(ctx.base_midx) < 0)
goto cleanup;
- get_split_midx_filename_ext(source, &final_midx_name,
+ get_split_midx_filename_ext(opts->source, &final_midx_name,
midx_hash, MIDX_EXT_MIDX);
if (rename_tempfile(&incr, final_midx_name.buf) < 0) {
@@ -1514,18 +1746,47 @@ static int write_midx_internal(struct odb_source *source,
strbuf_release(&final_midx_name);
- keep_hashes[ctx.num_multi_pack_indexes_before] =
- xstrdup(hash_to_hex_algop(midx_hash, r->hash_algo));
+ if (ctx.compact) {
+ struct multi_pack_index *m;
+ uint32_t num_layers_before_from = 0;
+ uint32_t i;
- for (uint32_t i = 0; i < ctx.num_multi_pack_indexes_before; i++) {
- uint32_t j = ctx.num_multi_pack_indexes_before - i - 1;
+ for (m = ctx.base_midx; m; m = m->base_midx)
+ num_layers_before_from++;
- keep_hashes[j] = xstrdup(hash_to_hex_algop(get_midx_checksum(m),
+ m = ctx.base_midx;
+ for (i = 0; i < num_layers_before_from; i++) {
+ uint32_t j = num_layers_before_from - i - 1;
+
+ keep_hashes[j] = xstrdup(midx_get_checksum_hex(m));
+ m = m->base_midx;
+ }
+
+ keep_hashes[i] = xstrdup(hash_to_hex_algop(midx_hash,
r->hash_algo));
- m = m->base_midx;
+
+ i = 0;
+ for (m = ctx.m;
+ m && midx_hashcmp(m, ctx.compact_to, r->hash_algo);
+ m = m->base_midx) {
+ keep_hashes[keep_hashes_nr - i - 1] =
+ xstrdup(midx_get_checksum_hex(m));
+ i++;
+ }
+ } else {
+ keep_hashes[ctx.num_multi_pack_indexes_before] =
+ xstrdup(hash_to_hex_algop(midx_hash,
+ r->hash_algo));
+
+ for (uint32_t i = 0; i < ctx.num_multi_pack_indexes_before; i++) {
+ uint32_t j = ctx.num_multi_pack_indexes_before - i - 1;
+
+ keep_hashes[j] = xstrdup(midx_get_checksum_hex(m));
+ m = m->base_midx;
+ }
}
- for (uint32_t i = 0; i <= ctx.num_multi_pack_indexes_before; i++)
+ for (uint32_t i = 0; i < keep_hashes_nr; i++)
fprintf(get_lock_file_fp(&lk), "%s\n", keep_hashes[i]);
} else {
keep_hashes[ctx.num_multi_pack_indexes_before] =
@@ -1538,8 +1799,7 @@ static int write_midx_internal(struct odb_source *source,
if (commit_lock_file(&lk) < 0)
die_errno(_("could not write multi-pack-index"));
- clear_midx_files(source, keep_hashes,
- ctx.num_multi_pack_indexes_before + 1,
+ clear_midx_files(opts->source, keep_hashes, keep_hashes_nr,
ctx.incremental);
result = 0;
@@ -1557,7 +1817,7 @@ cleanup:
free(ctx.pack_perm);
free(ctx.pack_order);
if (keep_hashes) {
- for (uint32_t i = 0; i <= ctx.num_multi_pack_indexes_before; i++)
+ for (uint32_t i = 0; i < keep_hashes_nr; i++)
free((char *)keep_hashes[i]);
free(keep_hashes);
}
@@ -1573,9 +1833,14 @@ int write_midx_file(struct odb_source *source,
const char *preferred_pack_name,
const char *refs_snapshot, unsigned flags)
{
- return write_midx_internal(source, NULL, NULL,
- preferred_pack_name, refs_snapshot,
- flags);
+ struct write_midx_opts opts = {
+ .source = source,
+ .preferred_pack_name = preferred_pack_name,
+ .refs_snapshot = refs_snapshot,
+ .flags = flags,
+ };
+
+ return write_midx_internal(&opts);
}
int write_midx_file_only(struct odb_source *source,
@@ -1583,8 +1848,30 @@ int write_midx_file_only(struct odb_source *source,
const char *preferred_pack_name,
const char *refs_snapshot, unsigned flags)
{
- return write_midx_internal(source, packs_to_include, NULL,
- preferred_pack_name, refs_snapshot, flags);
+ struct write_midx_opts opts = {
+ .source = source,
+ .packs_to_include = packs_to_include,
+ .preferred_pack_name = preferred_pack_name,
+ .refs_snapshot = refs_snapshot,
+ .flags = flags,
+ };
+
+ return write_midx_internal(&opts);
+}
+
+int write_midx_file_compact(struct odb_source *source,
+ struct multi_pack_index *from,
+ struct multi_pack_index *to,
+ unsigned flags)
+{
+ struct write_midx_opts opts = {
+ .source = source,
+ .compact_from = from,
+ .compact_to = to,
+ .flags = flags | MIDX_WRITE_COMPACT,
+ };
+
+ return write_midx_internal(&opts);
}
int expire_midx_packs(struct odb_source *source, unsigned flags)
@@ -1643,9 +1930,14 @@ int expire_midx_packs(struct odb_source *source, unsigned flags)
free(count);
- if (packs_to_drop.nr)
- result = write_midx_internal(source, NULL,
- &packs_to_drop, NULL, NULL, flags);
+ if (packs_to_drop.nr) {
+ struct write_midx_opts opts = {
+ .source = source,
+ .packs_to_drop = &packs_to_drop,
+ .flags = flags & MIDX_PROGRESS,
+ };
+ result = write_midx_internal(&opts);
+ }
string_list_clear(&packs_to_drop, 0);
@@ -1778,6 +2070,10 @@ int midx_repack(struct odb_source *source, size_t batch_size, unsigned flags)
struct child_process cmd = CHILD_PROCESS_INIT;
FILE *cmd_in;
struct multi_pack_index *m = get_multi_pack_index(source);
+ struct write_midx_opts opts = {
+ .source = source,
+ .flags = flags,
+ };
/*
* When updating the default for these configuration
@@ -1852,8 +2148,7 @@ int midx_repack(struct odb_source *source, size_t batch_size, unsigned flags)
goto cleanup;
}
- result = write_midx_internal(source, NULL, NULL, NULL, NULL,
- flags);
+ result = write_midx_internal(&opts);
cleanup:
free(include_pack);