Merge branch 'tb/incremental-midx-part-2' into next
Incrementally updating multi-pack index files. * tb/incremental-midx-part-2: midx: implement writing incremental MIDX bitmaps pack-bitmap.c: use `ewah_or_iterator` for type bitmap iterators pack-bitmap.c: keep track of each layer's type bitmaps ewah: implement `struct ewah_or_iterator` pack-bitmap.c: apply pseudo-merge commits with incremental MIDXs pack-bitmap.c: compute disk-usage with incremental MIDXs pack-bitmap.c: teach `rev-list --test-bitmap` about incremental MIDXs pack-bitmap.c: support bitmap pack-reuse with incremental MIDXs pack-bitmap.c: teach `show_objects_for_type()` about incremental MIDXs pack-bitmap.c: teach `bitmap_for_commit()` about incremental MIDXs pack-bitmap.c: open and store incremental bitmap layers pack-revindex: prepare for incremental MIDX bitmaps Documentation: describe incremental MIDX bitmaps Documentation: remove a "future work" item from the MIDX docsnext
commit
1db17d1a9b
|
@ -164,19 +164,81 @@ objects_nr($H2) + objects_nr($H1) + i
|
|||
(in the C implementation, this is often computed as `i +
|
||||
m->num_objects_in_base`).
|
||||
|
||||
=== Pseudo-pack order for incremental MIDXs
|
||||
|
||||
The original implementation of multi-pack reachability bitmaps defined
|
||||
the pseudo-pack order in linkgit:gitformat-pack[5] (see the section
|
||||
titled "multi-pack-index reverse indexes") roughly as follows:
|
||||
|
||||
____
|
||||
In short, a MIDX's pseudo-pack is the de-duplicated concatenation of
|
||||
objects in packs stored by the MIDX, laid out in pack order, and the
|
||||
packs arranged in MIDX order (with the preferred pack coming first).
|
||||
____
|
||||
|
||||
In the incremental MIDX design, we extend this definition to include
|
||||
objects from multiple layers of the MIDX chain. The pseudo-pack order
|
||||
for incremental MIDXs is determined by concatenating the pseudo-pack
|
||||
ordering for each layer of the MIDX chain in order. Formally two objects
|
||||
`o1` and `o2` are compared as follows:
|
||||
|
||||
1. If `o1` appears in an earlier layer of the MIDX chain than `o2`, then
|
||||
`o1` sorts ahead of `o2`.
|
||||
|
||||
2. Otherwise, if `o1` and `o2` appear in the same MIDX layer, and that
|
||||
MIDX layer has no base, then if one of `pack(o1)` and `pack(o2)` is
|
||||
preferred and the other is not, then the preferred one sorts ahead of
|
||||
the non-preferred one. If there is a base layer (i.e. the MIDX layer
|
||||
is not the first layer in the chain), then if `pack(o1)` appears
|
||||
earlier in that MIDX layer's pack order, then `o1` sorts ahead of
|
||||
`o2`. Likewise if `pack(o2)` appears earlier, then the opposite is
|
||||
true.
|
||||
|
||||
3. Otherwise, `o1` and `o2` appear in the same pack, and thus in the
|
||||
same MIDX layer. Sort `o1` and `o2` by their offset within their
|
||||
containing packfile.
|
||||
|
||||
Note that the preferred pack is a property of the MIDX chain, not the
|
||||
individual layers themselves. Fundamentally we could introduce a
|
||||
per-layer preferred pack, but this is less relevant now that we can
|
||||
perform multi-pack reuse across the set of packs in a MIDX.
|
||||
|
||||
=== Reachability bitmaps and incremental MIDXs
|
||||
|
||||
Each layer of an incremental MIDX chain may have its objects (and the
|
||||
objects from any previous layer in the same MIDX chain) represented in
|
||||
its own `*.bitmap` file.
|
||||
|
||||
The structure of a `*.bitmap` file belonging to an incremental MIDX
|
||||
chain is identical to that of a non-incremental MIDX bitmap, or a
|
||||
classic single-pack bitmap. Since objects are added to the end of the
|
||||
incremental MIDX's pseudo-pack order (see above), it is possible to
|
||||
extend a bitmap when appending to the end of a MIDX chain.
|
||||
|
||||
(Note: it is possible likewise to compress a contiguous sequence of MIDX
|
||||
incremental layers, and their `*.bitmap` files into a single layer and
|
||||
`*.bitmap`, but this is not yet implemented.)
|
||||
|
||||
The object positions used are global within the pseudo-pack order, so
|
||||
subsequent layers will have, for example, `m->num_objects_in_base`
|
||||
number of `0` bits in each of their four type bitmaps. This follows from
|
||||
the fact that we only write type bitmap entries for objects present in
|
||||
the layer immediately corresponding to the bitmap).
|
||||
|
||||
Note also that only the bitmap pertaining to the most recent layer in an
|
||||
incremental MIDX chain is used to store reachability information about
|
||||
the interesting and uninteresting objects in a reachability query.
|
||||
Earlier bitmap layers are only used to look up commit and pseudo-merge
|
||||
bitmaps from that layer, as well as the type-level bitmaps for objects
|
||||
in that layer.
|
||||
|
||||
To simplify the implementation, type-level bitmaps are iterated
|
||||
simultaneously, and their results are OR'd together to avoid recursively
|
||||
calling internal bitmap functions.
|
||||
|
||||
Future Work
|
||||
-----------
|
||||
|
||||
- The multi-pack-index allows many packfiles, especially in a context
|
||||
where repacking is expensive (such as a very large repo), or
|
||||
unexpected maintenance time is unacceptable (such as a high-demand
|
||||
build machine). However, the multi-pack-index needs to be rewritten
|
||||
in full every time. We can extend the format to be incremental, so
|
||||
writes are fast. By storing a small "tip" multi-pack-index that
|
||||
points to large "base" MIDX files, we can keep writes fast while
|
||||
still reducing the number of binary searches required for object
|
||||
lookups.
|
||||
|
||||
- If the multi-pack-index is extended to store a "stable object order"
|
||||
(a function Order(hash) = integer that is constant for a given hash,
|
||||
even as the multi-pack-index is updated) then MIDX bitmaps could be
|
||||
|
|
|
@ -1398,7 +1398,8 @@ static void write_pack_file(void)
|
|||
|
||||
if (write_bitmap_index) {
|
||||
bitmap_writer_init(&bitmap_writer,
|
||||
the_repository, &to_pack);
|
||||
the_repository, &to_pack,
|
||||
NULL);
|
||||
bitmap_writer_set_checksum(&bitmap_writer, hash);
|
||||
bitmap_writer_build_type_index(&bitmap_writer,
|
||||
written_list);
|
||||
|
|
|
@ -371,6 +371,39 @@ void ewah_iterator_init(struct ewah_iterator *it, struct ewah_bitmap *parent)
|
|||
read_new_rlw(it);
|
||||
}
|
||||
|
||||
void ewah_or_iterator_init(struct ewah_or_iterator *it,
|
||||
struct ewah_bitmap **parents, size_t nr)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
memset(it, 0, sizeof(*it));
|
||||
|
||||
ALLOC_ARRAY(it->its, nr);
|
||||
for (i = 0; i < nr; i++)
|
||||
ewah_iterator_init(&it->its[it->nr++], parents[i]);
|
||||
}
|
||||
|
||||
int ewah_or_iterator_next(eword_t *next, struct ewah_or_iterator *it)
|
||||
{
|
||||
eword_t buf, out = 0;
|
||||
size_t i;
|
||||
int ret = 0;
|
||||
|
||||
for (i = 0; i < it->nr; i++)
|
||||
if (ewah_iterator_next(&buf, &it->its[i])) {
|
||||
out |= buf;
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
*next = out;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ewah_or_iterator_release(struct ewah_or_iterator *it)
|
||||
{
|
||||
free(it->its);
|
||||
}
|
||||
|
||||
void ewah_xor(
|
||||
struct ewah_bitmap *ewah_i,
|
||||
struct ewah_bitmap *ewah_j,
|
||||
|
|
12
ewah/ewok.h
12
ewah/ewok.h
|
@ -148,6 +148,18 @@ void ewah_iterator_init(struct ewah_iterator *it, struct ewah_bitmap *parent);
|
|||
*/
|
||||
int ewah_iterator_next(eword_t *next, struct ewah_iterator *it);
|
||||
|
||||
struct ewah_or_iterator {
|
||||
struct ewah_iterator *its;
|
||||
size_t nr;
|
||||
};
|
||||
|
||||
void ewah_or_iterator_init(struct ewah_or_iterator *it,
|
||||
struct ewah_bitmap **parents, size_t nr);
|
||||
|
||||
int ewah_or_iterator_next(eword_t *next, struct ewah_or_iterator *it);
|
||||
|
||||
void ewah_or_iterator_release(struct ewah_or_iterator *it);
|
||||
|
||||
void ewah_xor(
|
||||
struct ewah_bitmap *ewah_i,
|
||||
struct ewah_bitmap *ewah_j,
|
||||
|
|
57
midx-write.c
57
midx-write.c
|
@ -647,16 +647,22 @@ static uint32_t *midx_pack_order(struct write_midx_context *ctx)
|
|||
return pack_order;
|
||||
}
|
||||
|
||||
static void write_midx_reverse_index(char *midx_name, unsigned char *midx_hash,
|
||||
struct write_midx_context *ctx)
|
||||
static void write_midx_reverse_index(struct write_midx_context *ctx,
|
||||
const char *object_dir,
|
||||
unsigned char *midx_hash)
|
||||
{
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
char *tmp_file;
|
||||
|
||||
trace2_region_enter("midx", "write_midx_reverse_index", ctx->repo);
|
||||
|
||||
strbuf_addf(&buf, "%s-%s.rev", midx_name, hash_to_hex_algop(midx_hash,
|
||||
ctx->repo->hash_algo));
|
||||
if (ctx->incremental)
|
||||
get_split_midx_filename_ext(ctx->repo->hash_algo, &buf,
|
||||
object_dir, midx_hash,
|
||||
MIDX_EXT_REV);
|
||||
else
|
||||
get_midx_filename_ext(ctx->repo->hash_algo, &buf, object_dir,
|
||||
midx_hash, MIDX_EXT_REV);
|
||||
|
||||
tmp_file = write_rev_file_order(ctx->repo->hash_algo, NULL, ctx->pack_order,
|
||||
ctx->entries_nr, midx_hash, WRITE_REV);
|
||||
|
@ -829,22 +835,29 @@ static struct commit **find_commits_for_midx_bitmap(uint32_t *indexed_commits_nr
|
|||
return cb.commits;
|
||||
}
|
||||
|
||||
static int write_midx_bitmap(struct repository *r, const char *midx_name,
|
||||
static int write_midx_bitmap(struct write_midx_context *ctx,
|
||||
const char *object_dir,
|
||||
const unsigned char *midx_hash,
|
||||
struct packing_data *pdata,
|
||||
struct commit **commits,
|
||||
uint32_t commits_nr,
|
||||
uint32_t *pack_order,
|
||||
unsigned flags)
|
||||
{
|
||||
int ret, i;
|
||||
uint16_t options = 0;
|
||||
struct bitmap_writer writer;
|
||||
struct pack_idx_entry **index;
|
||||
char *bitmap_name = xstrfmt("%s-%s.bitmap", midx_name,
|
||||
hash_to_hex_algop(midx_hash, r->hash_algo));
|
||||
struct strbuf bitmap_name = STRBUF_INIT;
|
||||
|
||||
trace2_region_enter("midx", "write_midx_bitmap", r);
|
||||
trace2_region_enter("midx", "write_midx_bitmap", ctx->repo);
|
||||
|
||||
if (ctx->incremental)
|
||||
get_split_midx_filename_ext(ctx->repo->hash_algo, &bitmap_name,
|
||||
object_dir, midx_hash,
|
||||
MIDX_EXT_BITMAP);
|
||||
else
|
||||
get_midx_filename_ext(ctx->repo->hash_algo, &bitmap_name,
|
||||
object_dir, midx_hash, MIDX_EXT_BITMAP);
|
||||
|
||||
if (flags & MIDX_WRITE_BITMAP_HASH_CACHE)
|
||||
options |= BITMAP_OPT_HASH_CACHE;
|
||||
|
@ -861,7 +874,8 @@ static int write_midx_bitmap(struct repository *r, const char *midx_name,
|
|||
for (i = 0; i < pdata->nr_objects; i++)
|
||||
index[i] = &pdata->objects[i].idx;
|
||||
|
||||
bitmap_writer_init(&writer, r, pdata);
|
||||
bitmap_writer_init(&writer, ctx->repo, pdata,
|
||||
ctx->incremental ? ctx->base_midx : NULL);
|
||||
bitmap_writer_show_progress(&writer, flags & MIDX_PROGRESS);
|
||||
bitmap_writer_build_type_index(&writer, index);
|
||||
|
||||
|
@ -879,7 +893,7 @@ static int write_midx_bitmap(struct repository *r, const char *midx_name,
|
|||
* bitmap_writer_finish().
|
||||
*/
|
||||
for (i = 0; i < pdata->nr_objects; i++)
|
||||
index[pack_order[i]] = &pdata->objects[i].idx;
|
||||
index[ctx->pack_order[i]] = &pdata->objects[i].idx;
|
||||
|
||||
bitmap_writer_select_commits(&writer, commits, commits_nr);
|
||||
ret = bitmap_writer_build(&writer);
|
||||
|
@ -887,14 +901,14 @@ static int write_midx_bitmap(struct repository *r, const char *midx_name,
|
|||
goto cleanup;
|
||||
|
||||
bitmap_writer_set_checksum(&writer, midx_hash);
|
||||
bitmap_writer_finish(&writer, index, bitmap_name, options);
|
||||
bitmap_writer_finish(&writer, index, bitmap_name.buf, options);
|
||||
|
||||
cleanup:
|
||||
free(index);
|
||||
free(bitmap_name);
|
||||
strbuf_release(&bitmap_name);
|
||||
bitmap_writer_free(&writer);
|
||||
|
||||
trace2_region_leave("midx", "write_midx_bitmap", r);
|
||||
trace2_region_leave("midx", "write_midx_bitmap", ctx->repo);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1077,8 +1091,6 @@ static int write_midx_internal(struct repository *r, const char *object_dir,
|
|||
ctx.repo = r;
|
||||
|
||||
ctx.incremental = !!(flags & MIDX_WRITE_INCREMENTAL);
|
||||
if (ctx.incremental && (flags & MIDX_WRITE_BITMAP))
|
||||
die(_("cannot write incremental MIDX with bitmap"));
|
||||
|
||||
if (ctx.incremental)
|
||||
strbuf_addf(&midx_name,
|
||||
|
@ -1119,6 +1131,13 @@ static int write_midx_internal(struct repository *r, const char *object_dir,
|
|||
if (ctx.incremental) {
|
||||
struct multi_pack_index *m = ctx.base_midx;
|
||||
while (m) {
|
||||
if (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->repo->hash_algo));
|
||||
result = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
ctx.num_multi_pack_indexes_before++;
|
||||
m = m->base_midx;
|
||||
}
|
||||
|
@ -1387,7 +1406,7 @@ static int write_midx_internal(struct repository *r, const char *object_dir,
|
|||
|
||||
if (flags & MIDX_WRITE_REV_INDEX &&
|
||||
git_env_bool("GIT_TEST_MIDX_WRITE_REV", 0))
|
||||
write_midx_reverse_index(midx_name.buf, midx_hash, &ctx);
|
||||
write_midx_reverse_index(&ctx, object_dir, midx_hash);
|
||||
|
||||
if (flags & MIDX_WRITE_BITMAP) {
|
||||
struct packing_data pdata;
|
||||
|
@ -1410,8 +1429,8 @@ static int write_midx_internal(struct repository *r, const char *object_dir,
|
|||
FREE_AND_NULL(ctx.entries);
|
||||
ctx.entries_nr = 0;
|
||||
|
||||
if (write_midx_bitmap(r, midx_name.buf, midx_hash, &pdata,
|
||||
commits, commits_nr, ctx.pack_order,
|
||||
if (write_midx_bitmap(&ctx, object_dir,
|
||||
midx_hash, &pdata, commits, commits_nr,
|
||||
flags) < 0) {
|
||||
error(_("could not write multi-pack bitmap"));
|
||||
result = 1;
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include "alloc.h"
|
||||
#include "refs.h"
|
||||
#include "strmap.h"
|
||||
#include "midx.h"
|
||||
#include "pack-revindex.h"
|
||||
|
||||
struct bitmapped_commit {
|
||||
struct commit *commit;
|
||||
|
@ -43,7 +45,8 @@ static inline int bitmap_writer_nr_selected_commits(struct bitmap_writer *writer
|
|||
}
|
||||
|
||||
void bitmap_writer_init(struct bitmap_writer *writer, struct repository *r,
|
||||
struct packing_data *pdata)
|
||||
struct packing_data *pdata,
|
||||
struct multi_pack_index *midx)
|
||||
{
|
||||
memset(writer, 0, sizeof(struct bitmap_writer));
|
||||
if (writer->bitmaps)
|
||||
|
@ -51,6 +54,7 @@ void bitmap_writer_init(struct bitmap_writer *writer, struct repository *r,
|
|||
writer->bitmaps = kh_init_oid_map();
|
||||
writer->pseudo_merge_commits = kh_init_oid_map();
|
||||
writer->to_pack = pdata;
|
||||
writer->midx = midx;
|
||||
|
||||
string_list_init_dup(&writer->pseudo_merge_groups);
|
||||
|
||||
|
@ -113,6 +117,11 @@ void bitmap_writer_build_type_index(struct bitmap_writer *writer,
|
|||
struct pack_idx_entry **index)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t base_objects = 0;
|
||||
|
||||
if (writer->midx)
|
||||
base_objects = writer->midx->num_objects +
|
||||
writer->midx->num_objects_in_base;
|
||||
|
||||
writer->commits = ewah_new();
|
||||
writer->trees = ewah_new();
|
||||
|
@ -142,19 +151,19 @@ void bitmap_writer_build_type_index(struct bitmap_writer *writer,
|
|||
|
||||
switch (real_type) {
|
||||
case OBJ_COMMIT:
|
||||
ewah_set(writer->commits, i);
|
||||
ewah_set(writer->commits, i + base_objects);
|
||||
break;
|
||||
|
||||
case OBJ_TREE:
|
||||
ewah_set(writer->trees, i);
|
||||
ewah_set(writer->trees, i + base_objects);
|
||||
break;
|
||||
|
||||
case OBJ_BLOB:
|
||||
ewah_set(writer->blobs, i);
|
||||
ewah_set(writer->blobs, i + base_objects);
|
||||
break;
|
||||
|
||||
case OBJ_TAG:
|
||||
ewah_set(writer->tags, i);
|
||||
ewah_set(writer->tags, i + base_objects);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -207,19 +216,37 @@ void bitmap_writer_push_commit(struct bitmap_writer *writer,
|
|||
static uint32_t find_object_pos(struct bitmap_writer *writer,
|
||||
const struct object_id *oid, int *found)
|
||||
{
|
||||
struct object_entry *entry = packlist_find(writer->to_pack, oid);
|
||||
struct object_entry *entry;
|
||||
|
||||
entry = packlist_find(writer->to_pack, oid);
|
||||
if (entry) {
|
||||
uint32_t base_objects = 0;
|
||||
if (writer->midx)
|
||||
base_objects = writer->midx->num_objects +
|
||||
writer->midx->num_objects_in_base;
|
||||
|
||||
if (!entry) {
|
||||
if (found)
|
||||
*found = 0;
|
||||
warning("Failed to write bitmap index. Packfile doesn't have full closure "
|
||||
"(object %s is missing)", oid_to_hex(oid));
|
||||
return 0;
|
||||
*found = 1;
|
||||
return oe_in_pack_pos(writer->to_pack, entry) + base_objects;
|
||||
} else if (writer->midx) {
|
||||
uint32_t at, pos;
|
||||
|
||||
if (!bsearch_midx(oid, writer->midx, &at))
|
||||
goto missing;
|
||||
if (midx_to_pack_pos(writer->midx, at, &pos) < 0)
|
||||
goto missing;
|
||||
|
||||
if (found)
|
||||
*found = 1;
|
||||
return pos;
|
||||
}
|
||||
|
||||
missing:
|
||||
if (found)
|
||||
*found = 1;
|
||||
return oe_in_pack_pos(writer->to_pack, entry);
|
||||
*found = 0;
|
||||
warning("Failed to write bitmap index. Packfile doesn't have full closure "
|
||||
"(object %s is missing)", oid_to_hex(oid));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void compute_xor_offsets(struct bitmap_writer *writer)
|
||||
|
@ -586,7 +613,7 @@ int bitmap_writer_build(struct bitmap_writer *writer)
|
|||
struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
|
||||
struct prio_queue tree_queue = { NULL };
|
||||
struct bitmap_index *old_bitmap;
|
||||
uint32_t *mapping;
|
||||
uint32_t *mapping = NULL;
|
||||
int closed = 1; /* until proven otherwise */
|
||||
|
||||
if (writer->show_progress)
|
||||
|
@ -1021,7 +1048,7 @@ void bitmap_writer_finish(struct bitmap_writer *writer,
|
|||
struct strbuf tmp_file = STRBUF_INIT;
|
||||
struct hashfile *f;
|
||||
off_t *offsets = NULL;
|
||||
uint32_t i;
|
||||
uint32_t i, base_objects;
|
||||
|
||||
struct bitmap_disk_header header;
|
||||
|
||||
|
@ -1047,6 +1074,12 @@ void bitmap_writer_finish(struct bitmap_writer *writer,
|
|||
if (options & BITMAP_OPT_LOOKUP_TABLE)
|
||||
CALLOC_ARRAY(offsets, writer->to_pack->nr_objects);
|
||||
|
||||
if (writer->midx)
|
||||
base_objects = writer->midx->num_objects +
|
||||
writer->midx->num_objects_in_base;
|
||||
else
|
||||
base_objects = 0;
|
||||
|
||||
for (i = 0; i < bitmap_writer_nr_selected_commits(writer); i++) {
|
||||
struct bitmapped_commit *stored = &writer->selected[i];
|
||||
int commit_pos = oid_pos(&stored->commit->object.oid, index,
|
||||
|
@ -1055,7 +1088,7 @@ void bitmap_writer_finish(struct bitmap_writer *writer,
|
|||
|
||||
if (commit_pos < 0)
|
||||
BUG(_("trying to write commit not in index"));
|
||||
stored->commit_pos = commit_pos;
|
||||
stored->commit_pos = commit_pos + base_objects;
|
||||
}
|
||||
|
||||
write_selected_commits_v1(writer, f, offsets);
|
||||
|
|
344
pack-bitmap.c
344
pack-bitmap.c
|
@ -54,6 +54,16 @@ struct bitmap_index {
|
|||
struct packed_git *pack;
|
||||
struct multi_pack_index *midx;
|
||||
|
||||
/*
|
||||
* If using a multi-pack index chain, 'base' points to the
|
||||
* bitmap index corresponding to this bitmap's midx->base_midx.
|
||||
*
|
||||
* base_nr indicates how many layers precede this one, and is
|
||||
* zero when base is NULL.
|
||||
*/
|
||||
struct bitmap_index *base;
|
||||
uint32_t base_nr;
|
||||
|
||||
/* mmapped buffer of the whole bitmap index */
|
||||
unsigned char *map;
|
||||
size_t map_size; /* size of the mmaped buffer */
|
||||
|
@ -71,6 +81,23 @@ struct bitmap_index {
|
|||
struct ewah_bitmap *blobs;
|
||||
struct ewah_bitmap *tags;
|
||||
|
||||
/*
|
||||
* Type index arrays when this bitmap is associated with an
|
||||
* incremental multi-pack index chain.
|
||||
*
|
||||
* If n is the number of unique layers in the MIDX chain, then
|
||||
* commits_all[n-1] is this structs 'commits' field,
|
||||
* commits_all[n-2] is the commits field of this bitmap's
|
||||
* 'base', and so on.
|
||||
*
|
||||
* When associated either with a non-incremental MIDX or a
|
||||
* single packfile, these arrays each contain a single element.
|
||||
*/
|
||||
struct ewah_bitmap **commits_all;
|
||||
struct ewah_bitmap **trees_all;
|
||||
struct ewah_bitmap **blobs_all;
|
||||
struct ewah_bitmap **tags_all;
|
||||
|
||||
/* Map from object ID -> `stored_bitmap` for all the bitmapped commits */
|
||||
kh_oid_map_t *bitmaps;
|
||||
|
||||
|
@ -170,6 +197,15 @@ static struct ewah_bitmap *read_bitmap_1(struct bitmap_index *index)
|
|||
return read_bitmap(index->map, index->map_size, &index->map_pos);
|
||||
}
|
||||
|
||||
static uint32_t bitmap_num_objects_total(struct bitmap_index *index)
|
||||
{
|
||||
if (index->midx) {
|
||||
struct multi_pack_index *m = index->midx;
|
||||
return m->num_objects + m->num_objects_in_base;
|
||||
}
|
||||
return index->pack->num_objects;
|
||||
}
|
||||
|
||||
static uint32_t bitmap_num_objects(struct bitmap_index *index)
|
||||
{
|
||||
if (index->midx)
|
||||
|
@ -377,8 +413,15 @@ static int load_bitmap_entries_v1(struct bitmap_index *index)
|
|||
char *midx_bitmap_filename(struct multi_pack_index *midx)
|
||||
{
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
get_midx_filename_ext(midx->repo->hash_algo, &buf, midx->object_dir,
|
||||
get_midx_checksum(midx), MIDX_EXT_BITMAP);
|
||||
if (midx->has_chain)
|
||||
get_split_midx_filename_ext(midx->repo->hash_algo, &buf,
|
||||
midx->object_dir,
|
||||
get_midx_checksum(midx),
|
||||
MIDX_EXT_BITMAP);
|
||||
else
|
||||
get_midx_filename_ext(midx->repo->hash_algo, &buf,
|
||||
midx->object_dir, get_midx_checksum(midx),
|
||||
MIDX_EXT_BITMAP);
|
||||
|
||||
return strbuf_detach(&buf, NULL);
|
||||
}
|
||||
|
@ -445,16 +488,21 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git,
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
for (i = 0; i < bitmap_git->midx->num_packs; i++) {
|
||||
if (prepare_midx_pack(bitmap_repo(bitmap_git),
|
||||
bitmap_git->midx,
|
||||
i)) {
|
||||
for (i = 0; i < bitmap_git->midx->num_packs + bitmap_git->midx->num_packs_in_base; i++) {
|
||||
if (prepare_midx_pack(bitmap_repo(bitmap_git), bitmap_git->midx, i)) {
|
||||
warning(_("could not open pack %s"),
|
||||
bitmap_git->midx->pack_names[i]);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (midx->base_midx) {
|
||||
bitmap_git->base = prepare_midx_bitmap_git(midx->base_midx);
|
||||
bitmap_git->base_nr = bitmap_git->base->base_nr + 1;
|
||||
} else {
|
||||
bitmap_git->base_nr = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
|
@ -506,6 +554,7 @@ static int open_pack_bitmap_1(struct bitmap_index *bitmap_git, struct packed_git
|
|||
bitmap_git->map_size = xsize_t(st.st_size);
|
||||
bitmap_git->map = xmmap(NULL, bitmap_git->map_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
bitmap_git->map_pos = 0;
|
||||
bitmap_git->base_nr = 0;
|
||||
close(fd);
|
||||
|
||||
if (load_bitmap_header(bitmap_git) < 0) {
|
||||
|
@ -525,8 +574,7 @@ static int open_pack_bitmap_1(struct bitmap_index *bitmap_git, struct packed_git
|
|||
static int load_reverse_index(struct repository *r, struct bitmap_index *bitmap_git)
|
||||
{
|
||||
if (bitmap_is_midx(bitmap_git)) {
|
||||
uint32_t i;
|
||||
int ret;
|
||||
struct multi_pack_index *m;
|
||||
|
||||
/*
|
||||
* The multi-pack-index's .rev file is already loaded via
|
||||
|
@ -535,17 +583,47 @@ static int load_reverse_index(struct repository *r, struct bitmap_index *bitmap_
|
|||
* But we still need to open the individual pack .rev files,
|
||||
* since we will need to make use of them in pack-objects.
|
||||
*/
|
||||
for (i = 0; i < bitmap_git->midx->num_packs; i++) {
|
||||
ret = load_pack_revindex(r, bitmap_git->midx->packs[i]);
|
||||
if (ret)
|
||||
return ret;
|
||||
for (m = bitmap_git->midx; m; m = m->base_midx) {
|
||||
uint32_t i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < m->num_packs; i++) {
|
||||
ret = load_pack_revindex(r, m->packs[i]);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return load_pack_revindex(r, bitmap_git->pack);
|
||||
}
|
||||
|
||||
static int load_bitmap(struct repository *r, struct bitmap_index *bitmap_git)
|
||||
static void load_all_type_bitmaps(struct bitmap_index *bitmap_git)
|
||||
{
|
||||
struct bitmap_index *curr = bitmap_git;
|
||||
size_t i = bitmap_git->base_nr;
|
||||
|
||||
ALLOC_ARRAY(bitmap_git->commits_all, bitmap_git->base_nr + 1);
|
||||
ALLOC_ARRAY(bitmap_git->trees_all, bitmap_git->base_nr + 1);
|
||||
ALLOC_ARRAY(bitmap_git->blobs_all, bitmap_git->base_nr + 1);
|
||||
ALLOC_ARRAY(bitmap_git->tags_all, bitmap_git->base_nr + 1);
|
||||
|
||||
while (curr) {
|
||||
bitmap_git->commits_all[i] = curr->commits;
|
||||
bitmap_git->trees_all[i] = curr->trees;
|
||||
bitmap_git->blobs_all[i] = curr->blobs;
|
||||
bitmap_git->tags_all[i] = curr->tags;
|
||||
|
||||
curr = curr->base;
|
||||
if (curr && !i)
|
||||
BUG("unexpected number of bitmap layers, expected %"PRIu32,
|
||||
bitmap_git->base_nr + 1);
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int load_bitmap(struct repository *r, struct bitmap_index *bitmap_git,
|
||||
int recursing)
|
||||
{
|
||||
assert(bitmap_git->map);
|
||||
|
||||
|
@ -564,6 +642,16 @@ static int load_bitmap(struct repository *r, struct bitmap_index *bitmap_git)
|
|||
if (!bitmap_git->table_lookup && load_bitmap_entries_v1(bitmap_git) < 0)
|
||||
goto failed;
|
||||
|
||||
if (bitmap_git->base) {
|
||||
if (!bitmap_is_midx(bitmap_git))
|
||||
BUG("non-MIDX bitmap has non-NULL base bitmap index");
|
||||
if (load_bitmap(r, bitmap_git->base, 1) < 0)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (!recursing)
|
||||
load_all_type_bitmaps(bitmap_git);
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
|
@ -639,7 +727,7 @@ struct bitmap_index *prepare_bitmap_git(struct repository *r)
|
|||
{
|
||||
struct bitmap_index *bitmap_git = xcalloc(1, sizeof(*bitmap_git));
|
||||
|
||||
if (!open_bitmap(r, bitmap_git) && !load_bitmap(r, bitmap_git))
|
||||
if (!open_bitmap(r, bitmap_git) && !load_bitmap(r, bitmap_git, 0))
|
||||
return bitmap_git;
|
||||
|
||||
free_bitmap_index(bitmap_git);
|
||||
|
@ -648,10 +736,9 @@ struct bitmap_index *prepare_bitmap_git(struct repository *r)
|
|||
|
||||
struct bitmap_index *prepare_midx_bitmap_git(struct multi_pack_index *midx)
|
||||
{
|
||||
struct repository *r = midx->repo;
|
||||
struct bitmap_index *bitmap_git = xcalloc(1, sizeof(*bitmap_git));
|
||||
|
||||
if (!open_midx_bitmap_1(bitmap_git, midx) && !load_bitmap(r, bitmap_git))
|
||||
if (!open_midx_bitmap_1(bitmap_git, midx))
|
||||
return bitmap_git;
|
||||
|
||||
free_bitmap_index(bitmap_git);
|
||||
|
@ -896,26 +983,42 @@ corrupt:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct ewah_bitmap *bitmap_for_commit(struct bitmap_index *bitmap_git,
|
||||
struct commit *commit)
|
||||
static struct ewah_bitmap *find_bitmap_for_commit(struct bitmap_index *bitmap_git,
|
||||
struct commit *commit,
|
||||
struct bitmap_index **found)
|
||||
{
|
||||
khiter_t hash_pos = kh_get_oid_map(bitmap_git->bitmaps,
|
||||
commit->object.oid);
|
||||
khiter_t hash_pos;
|
||||
if (!bitmap_git)
|
||||
return NULL;
|
||||
|
||||
hash_pos = kh_get_oid_map(bitmap_git->bitmaps, commit->object.oid);
|
||||
if (hash_pos >= kh_end(bitmap_git->bitmaps)) {
|
||||
struct stored_bitmap *bitmap = NULL;
|
||||
if (!bitmap_git->table_lookup)
|
||||
return NULL;
|
||||
return find_bitmap_for_commit(bitmap_git->base, commit,
|
||||
found);
|
||||
|
||||
/* this is a fairly hot codepath - no trace2_region please */
|
||||
/* NEEDSWORK: cache misses aren't recorded */
|
||||
bitmap = lazy_bitmap_for_commit(bitmap_git, commit);
|
||||
if (!bitmap)
|
||||
return NULL;
|
||||
return find_bitmap_for_commit(bitmap_git->base, commit,
|
||||
found);
|
||||
if (found)
|
||||
*found = bitmap_git;
|
||||
return lookup_stored_bitmap(bitmap);
|
||||
}
|
||||
if (found)
|
||||
*found = bitmap_git;
|
||||
return lookup_stored_bitmap(kh_value(bitmap_git->bitmaps, hash_pos));
|
||||
}
|
||||
|
||||
struct ewah_bitmap *bitmap_for_commit(struct bitmap_index *bitmap_git,
|
||||
struct commit *commit)
|
||||
{
|
||||
return find_bitmap_for_commit(bitmap_git, commit, NULL);
|
||||
}
|
||||
|
||||
static inline int bitmap_position_extended(struct bitmap_index *bitmap_git,
|
||||
const struct object_id *oid)
|
||||
{
|
||||
|
@ -924,7 +1027,7 @@ static inline int bitmap_position_extended(struct bitmap_index *bitmap_git,
|
|||
|
||||
if (pos < kh_end(positions)) {
|
||||
int bitmap_pos = kh_value(positions, pos);
|
||||
return bitmap_pos + bitmap_num_objects(bitmap_git);
|
||||
return bitmap_pos + bitmap_num_objects_total(bitmap_git);
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
@ -992,7 +1095,7 @@ static int ext_index_add_object(struct bitmap_index *bitmap_git,
|
|||
bitmap_pos = kh_value(eindex->positions, hash_pos);
|
||||
}
|
||||
|
||||
return bitmap_pos + bitmap_num_objects(bitmap_git);
|
||||
return bitmap_pos + bitmap_num_objects_total(bitmap_git);
|
||||
}
|
||||
|
||||
struct bitmap_show_data {
|
||||
|
@ -1024,10 +1127,15 @@ static unsigned apply_pseudo_merges_for_commit_1(struct bitmap_index *bitmap_git
|
|||
struct commit *commit,
|
||||
uint32_t commit_pos)
|
||||
{
|
||||
int ret;
|
||||
struct bitmap_index *curr = bitmap_git;
|
||||
int ret = 0;
|
||||
|
||||
ret = apply_pseudo_merges_for_commit(&bitmap_git->pseudo_merges,
|
||||
result, commit, commit_pos);
|
||||
while (curr) {
|
||||
ret += apply_pseudo_merges_for_commit(&curr->pseudo_merges,
|
||||
result, commit,
|
||||
commit_pos);
|
||||
curr = curr->base;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
pseudo_merges_satisfied_nr += ret;
|
||||
|
@ -1342,11 +1450,17 @@ struct ewah_bitmap *pseudo_merge_bitmap_for_commit(struct bitmap_index *bitmap_g
|
|||
if (pos < 0 || pos >= bitmap_num_objects(bitmap_git))
|
||||
goto done;
|
||||
|
||||
/*
|
||||
* Use bitmap-relative positions instead of offsetting
|
||||
* by bitmap_git->num_objects_in_base because we use
|
||||
* this to find a match in pseudo_merge_for_parents(),
|
||||
* and pseudo-merge groups cannot span multiple bitmap
|
||||
* layers.
|
||||
*/
|
||||
bitmap_set(parents, pos);
|
||||
}
|
||||
|
||||
match = pseudo_merge_for_parents(&bitmap_git->pseudo_merges,
|
||||
parents);
|
||||
match = pseudo_merge_for_parents(&bitmap_git->pseudo_merges, parents);
|
||||
|
||||
done:
|
||||
bitmap_free(parents);
|
||||
|
@ -1500,7 +1614,9 @@ static void show_extended_objects(struct bitmap_index *bitmap_git,
|
|||
for (i = 0; i < eindex->count; ++i) {
|
||||
struct object *obj;
|
||||
|
||||
if (!bitmap_get(objects, st_add(bitmap_num_objects(bitmap_git), i)))
|
||||
if (!bitmap_get(objects,
|
||||
st_add(bitmap_num_objects_total(bitmap_git),
|
||||
i)))
|
||||
continue;
|
||||
|
||||
obj = eindex->objects[i];
|
||||
|
@ -1513,25 +1629,29 @@ static void show_extended_objects(struct bitmap_index *bitmap_git,
|
|||
}
|
||||
}
|
||||
|
||||
static void init_type_iterator(struct ewah_iterator *it,
|
||||
static void init_type_iterator(struct ewah_or_iterator *it,
|
||||
struct bitmap_index *bitmap_git,
|
||||
enum object_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case OBJ_COMMIT:
|
||||
ewah_iterator_init(it, bitmap_git->commits);
|
||||
ewah_or_iterator_init(it, bitmap_git->commits_all,
|
||||
bitmap_git->base_nr + 1);
|
||||
break;
|
||||
|
||||
case OBJ_TREE:
|
||||
ewah_iterator_init(it, bitmap_git->trees);
|
||||
ewah_or_iterator_init(it, bitmap_git->trees_all,
|
||||
bitmap_git->base_nr + 1);
|
||||
break;
|
||||
|
||||
case OBJ_BLOB:
|
||||
ewah_iterator_init(it, bitmap_git->blobs);
|
||||
ewah_or_iterator_init(it, bitmap_git->blobs_all,
|
||||
bitmap_git->base_nr + 1);
|
||||
break;
|
||||
|
||||
case OBJ_TAG:
|
||||
ewah_iterator_init(it, bitmap_git->tags);
|
||||
ewah_or_iterator_init(it, bitmap_git->tags_all,
|
||||
bitmap_git->base_nr + 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1548,7 +1668,7 @@ static void show_objects_for_type(
|
|||
size_t i = 0;
|
||||
uint32_t offset;
|
||||
|
||||
struct ewah_iterator it;
|
||||
struct ewah_or_iterator it;
|
||||
eword_t filter;
|
||||
|
||||
struct bitmap *objects = bitmap_git->result;
|
||||
|
@ -1556,7 +1676,7 @@ static void show_objects_for_type(
|
|||
init_type_iterator(&it, bitmap_git, object_type);
|
||||
|
||||
for (i = 0; i < objects->word_alloc &&
|
||||
ewah_iterator_next(&filter, &it); i++) {
|
||||
ewah_or_iterator_next(&filter, &it); i++) {
|
||||
eword_t word = objects->words[i] & filter;
|
||||
size_t pos = (i * BITS_IN_EWORD);
|
||||
|
||||
|
@ -1583,7 +1703,7 @@ static void show_objects_for_type(
|
|||
nth_midxed_object_oid(&oid, m, index_pos);
|
||||
|
||||
pack_id = nth_midxed_pack_int_id(m, index_pos);
|
||||
pack = bitmap_git->midx->packs[pack_id];
|
||||
pack = nth_midxed_pack(bitmap_git->midx, pack_id);
|
||||
} else {
|
||||
index_pos = pack_pos_to_index(bitmap_git->pack, pos + offset);
|
||||
ofs = pack_pos_to_offset(bitmap_git->pack, pos + offset);
|
||||
|
@ -1598,6 +1718,8 @@ static void show_objects_for_type(
|
|||
show_reach(&oid, object_type, 0, hash, pack, ofs);
|
||||
}
|
||||
}
|
||||
|
||||
ewah_or_iterator_release(&it);
|
||||
}
|
||||
|
||||
static int in_bitmapped_pack(struct bitmap_index *bitmap_git,
|
||||
|
@ -1649,7 +1771,7 @@ static void filter_bitmap_exclude_type(struct bitmap_index *bitmap_git,
|
|||
{
|
||||
struct eindex *eindex = &bitmap_git->ext_index;
|
||||
struct bitmap *tips;
|
||||
struct ewah_iterator it;
|
||||
struct ewah_or_iterator it;
|
||||
eword_t mask;
|
||||
uint32_t i;
|
||||
|
||||
|
@ -1666,7 +1788,7 @@ static void filter_bitmap_exclude_type(struct bitmap_index *bitmap_git,
|
|||
* packfile.
|
||||
*/
|
||||
for (i = 0, init_type_iterator(&it, bitmap_git, type);
|
||||
i < to_filter->word_alloc && ewah_iterator_next(&mask, &it);
|
||||
i < to_filter->word_alloc && ewah_or_iterator_next(&mask, &it);
|
||||
i++) {
|
||||
if (i < tips->word_alloc)
|
||||
mask &= ~tips->words[i];
|
||||
|
@ -1679,13 +1801,14 @@ static void filter_bitmap_exclude_type(struct bitmap_index *bitmap_git,
|
|||
* them individually.
|
||||
*/
|
||||
for (i = 0; i < eindex->count; i++) {
|
||||
size_t pos = st_add(i, bitmap_num_objects(bitmap_git));
|
||||
size_t pos = st_add(i, bitmap_num_objects_total(bitmap_git));
|
||||
if (eindex->objects[i]->type == type &&
|
||||
bitmap_get(to_filter, pos) &&
|
||||
!bitmap_get(tips, pos))
|
||||
bitmap_unset(to_filter, pos);
|
||||
}
|
||||
|
||||
ewah_or_iterator_release(&it);
|
||||
bitmap_free(tips);
|
||||
}
|
||||
|
||||
|
@ -1705,7 +1828,7 @@ static unsigned long get_size_by_pos(struct bitmap_index *bitmap_git,
|
|||
|
||||
oi.sizep = &size;
|
||||
|
||||
if (pos < bitmap_num_objects(bitmap_git)) {
|
||||
if (pos < bitmap_num_objects_total(bitmap_git)) {
|
||||
struct packed_git *pack;
|
||||
off_t ofs;
|
||||
|
||||
|
@ -1713,7 +1836,7 @@ static unsigned long get_size_by_pos(struct bitmap_index *bitmap_git,
|
|||
uint32_t midx_pos = pack_pos_to_midx(bitmap_git->midx, pos);
|
||||
uint32_t pack_id = nth_midxed_pack_int_id(bitmap_git->midx, midx_pos);
|
||||
|
||||
pack = bitmap_git->midx->packs[pack_id];
|
||||
pack = nth_midxed_pack(bitmap_git->midx, pack_id);
|
||||
ofs = nth_midxed_offset(bitmap_git->midx, midx_pos);
|
||||
} else {
|
||||
pack = bitmap_git->pack;
|
||||
|
@ -1728,8 +1851,9 @@ static unsigned long get_size_by_pos(struct bitmap_index *bitmap_git,
|
|||
die(_("unable to get size of %s"), oid_to_hex(&oid));
|
||||
}
|
||||
} else {
|
||||
size_t eindex_pos = pos - bitmap_num_objects_total(bitmap_git);
|
||||
struct eindex *eindex = &bitmap_git->ext_index;
|
||||
struct object *obj = eindex->objects[pos - bitmap_num_objects(bitmap_git)];
|
||||
struct object *obj = eindex->objects[eindex_pos];
|
||||
if (oid_object_info_extended(bitmap_repo(bitmap_git), &obj->oid,
|
||||
&oi, 0) < 0)
|
||||
die(_("unable to get size of %s"), oid_to_hex(&obj->oid));
|
||||
|
@ -1745,14 +1869,14 @@ static void filter_bitmap_blob_limit(struct bitmap_index *bitmap_git,
|
|||
{
|
||||
struct eindex *eindex = &bitmap_git->ext_index;
|
||||
struct bitmap *tips;
|
||||
struct ewah_iterator it;
|
||||
struct ewah_or_iterator it;
|
||||
eword_t mask;
|
||||
uint32_t i;
|
||||
|
||||
tips = find_tip_objects(bitmap_git, tip_objects, OBJ_BLOB);
|
||||
|
||||
for (i = 0, init_type_iterator(&it, bitmap_git, OBJ_BLOB);
|
||||
i < to_filter->word_alloc && ewah_iterator_next(&mask, &it);
|
||||
i < to_filter->word_alloc && ewah_or_iterator_next(&mask, &it);
|
||||
i++) {
|
||||
eword_t word = to_filter->words[i] & mask;
|
||||
unsigned offset;
|
||||
|
@ -1780,6 +1904,7 @@ static void filter_bitmap_blob_limit(struct bitmap_index *bitmap_git,
|
|||
bitmap_unset(to_filter, pos);
|
||||
}
|
||||
|
||||
ewah_or_iterator_release(&it);
|
||||
bitmap_free(tips);
|
||||
}
|
||||
|
||||
|
@ -1882,7 +2007,7 @@ static void filter_packed_objects_from_bitmap(struct bitmap_index *bitmap_git,
|
|||
uint32_t objects_nr;
|
||||
size_t i, pos;
|
||||
|
||||
objects_nr = bitmap_num_objects(bitmap_git);
|
||||
objects_nr = bitmap_num_objects_total(bitmap_git);
|
||||
pos = objects_nr / BITS_IN_EWORD;
|
||||
|
||||
if (pos > result->word_alloc)
|
||||
|
@ -1980,7 +2105,7 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs,
|
|||
* from disk. this is the point of no return; after this the rev_list
|
||||
* becomes invalidated and we must perform the revwalk through bitmaps
|
||||
*/
|
||||
if (load_bitmap(revs->repo, bitmap_git) < 0)
|
||||
if (load_bitmap(revs->repo, bitmap_git, 0) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (!use_boundary_traversal)
|
||||
|
@ -2281,7 +2406,8 @@ void reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git,
|
|||
multi_pack_reuse = 0;
|
||||
|
||||
if (multi_pack_reuse) {
|
||||
for (i = 0; i < bitmap_git->midx->num_packs; i++) {
|
||||
struct multi_pack_index *m = bitmap_git->midx;
|
||||
for (i = 0; i < m->num_packs + m->num_packs_in_base; i++) {
|
||||
struct bitmapped_pack pack;
|
||||
if (nth_bitmapped_pack(r, bitmap_git->midx, &pack, i) < 0) {
|
||||
warning(_("unable to load pack: '%s', disabling pack-reuse"),
|
||||
|
@ -2307,14 +2433,18 @@ void reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git,
|
|||
uint32_t pack_int_id;
|
||||
|
||||
if (bitmap_is_midx(bitmap_git)) {
|
||||
struct multi_pack_index *m = bitmap_git->midx;
|
||||
uint32_t preferred_pack_pos;
|
||||
|
||||
if (midx_preferred_pack(bitmap_git->midx, &preferred_pack_pos) < 0) {
|
||||
while (m->base_midx)
|
||||
m = m->base_midx;
|
||||
|
||||
if (midx_preferred_pack(m, &preferred_pack_pos) < 0) {
|
||||
warning(_("unable to compute preferred pack, disabling pack-reuse"));
|
||||
return;
|
||||
}
|
||||
|
||||
pack = bitmap_git->midx->packs[preferred_pack_pos];
|
||||
pack = nth_midxed_pack(m, preferred_pack_pos);
|
||||
pack_int_id = preferred_pack_pos;
|
||||
} else {
|
||||
pack = bitmap_git->pack;
|
||||
|
@ -2406,12 +2536,12 @@ static uint32_t count_object_type(struct bitmap_index *bitmap_git,
|
|||
struct eindex *eindex = &bitmap_git->ext_index;
|
||||
|
||||
uint32_t i = 0, count = 0;
|
||||
struct ewah_iterator it;
|
||||
struct ewah_or_iterator it;
|
||||
eword_t filter;
|
||||
|
||||
init_type_iterator(&it, bitmap_git, type);
|
||||
|
||||
while (i < objects->word_alloc && ewah_iterator_next(&filter, &it)) {
|
||||
while (i < objects->word_alloc && ewah_or_iterator_next(&filter, &it)) {
|
||||
eword_t word = objects->words[i++] & filter;
|
||||
count += ewah_bit_popcount64(word);
|
||||
}
|
||||
|
@ -2419,10 +2549,12 @@ static uint32_t count_object_type(struct bitmap_index *bitmap_git,
|
|||
for (i = 0; i < eindex->count; ++i) {
|
||||
if (eindex->objects[i]->type == type &&
|
||||
bitmap_get(objects,
|
||||
st_add(bitmap_num_objects(bitmap_git), i)))
|
||||
st_add(bitmap_num_objects_total(bitmap_git), i)))
|
||||
count++;
|
||||
}
|
||||
|
||||
ewah_or_iterator_release(&it);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -2454,6 +2586,8 @@ struct bitmap_test_data {
|
|||
struct bitmap *tags;
|
||||
struct progress *prg;
|
||||
size_t seen;
|
||||
|
||||
struct bitmap_test_data *base_tdata;
|
||||
};
|
||||
|
||||
static void test_bitmap_type(struct bitmap_test_data *tdata,
|
||||
|
@ -2462,6 +2596,11 @@ static void test_bitmap_type(struct bitmap_test_data *tdata,
|
|||
enum object_type bitmap_type = OBJ_NONE;
|
||||
int bitmaps_nr = 0;
|
||||
|
||||
if (bitmap_is_midx(tdata->bitmap_git)) {
|
||||
while (pos < tdata->bitmap_git->midx->num_objects_in_base)
|
||||
tdata = tdata->base_tdata;
|
||||
}
|
||||
|
||||
if (bitmap_get(tdata->commits, pos)) {
|
||||
bitmap_type = OBJ_COMMIT;
|
||||
bitmaps_nr++;
|
||||
|
@ -2525,13 +2664,57 @@ static void test_show_commit(struct commit *commit, void *data)
|
|||
display_progress(tdata->prg, ++tdata->seen);
|
||||
}
|
||||
|
||||
static uint32_t bitmap_total_entry_count(struct bitmap_index *bitmap_git)
|
||||
{
|
||||
uint32_t total = 0;
|
||||
do {
|
||||
total = st_add(total, bitmap_git->entry_count);
|
||||
bitmap_git = bitmap_git->base;
|
||||
} while (bitmap_git);
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
static void bitmap_test_data_prepare(struct bitmap_test_data *tdata,
|
||||
struct bitmap_index *bitmap_git)
|
||||
{
|
||||
memset(tdata, 0, sizeof(struct bitmap_test_data));
|
||||
|
||||
tdata->bitmap_git = bitmap_git;
|
||||
tdata->base = bitmap_new();
|
||||
tdata->commits = ewah_to_bitmap(bitmap_git->commits);
|
||||
tdata->trees = ewah_to_bitmap(bitmap_git->trees);
|
||||
tdata->blobs = ewah_to_bitmap(bitmap_git->blobs);
|
||||
tdata->tags = ewah_to_bitmap(bitmap_git->tags);
|
||||
|
||||
if (bitmap_git->base) {
|
||||
tdata->base_tdata = xmalloc(sizeof(struct bitmap_test_data));
|
||||
bitmap_test_data_prepare(tdata->base_tdata, bitmap_git->base);
|
||||
}
|
||||
}
|
||||
|
||||
static void bitmap_test_data_release(struct bitmap_test_data *tdata)
|
||||
{
|
||||
if (!tdata)
|
||||
return;
|
||||
|
||||
bitmap_test_data_release(tdata->base_tdata);
|
||||
free(tdata->base_tdata);
|
||||
|
||||
bitmap_free(tdata->base);
|
||||
bitmap_free(tdata->commits);
|
||||
bitmap_free(tdata->trees);
|
||||
bitmap_free(tdata->blobs);
|
||||
bitmap_free(tdata->tags);
|
||||
}
|
||||
|
||||
void test_bitmap_walk(struct rev_info *revs)
|
||||
{
|
||||
struct object *root;
|
||||
struct bitmap *result = NULL;
|
||||
size_t result_popcnt;
|
||||
struct bitmap_test_data tdata;
|
||||
struct bitmap_index *bitmap_git;
|
||||
struct bitmap_index *bitmap_git, *found;
|
||||
struct ewah_bitmap *bm;
|
||||
|
||||
if (!(bitmap_git = prepare_bitmap_git(revs->repo)))
|
||||
|
@ -2540,17 +2723,28 @@ void test_bitmap_walk(struct rev_info *revs)
|
|||
if (revs->pending.nr != 1)
|
||||
die(_("you must specify exactly one commit to test"));
|
||||
|
||||
fprintf_ln(stderr, "Bitmap v%d test (%d entries%s)",
|
||||
fprintf_ln(stderr, "Bitmap v%d test (%d entries%s, %d total)",
|
||||
bitmap_git->version,
|
||||
bitmap_git->entry_count,
|
||||
bitmap_git->table_lookup ? "" : " loaded");
|
||||
bitmap_git->table_lookup ? "" : " loaded",
|
||||
bitmap_total_entry_count(bitmap_git));
|
||||
|
||||
root = revs->pending.objects[0].item;
|
||||
bm = bitmap_for_commit(bitmap_git, (struct commit *)root);
|
||||
bm = find_bitmap_for_commit(bitmap_git, (struct commit *)root, &found);
|
||||
|
||||
if (bm) {
|
||||
fprintf_ln(stderr, "Found bitmap for '%s'. %d bits / %08x checksum",
|
||||
oid_to_hex(&root->oid), (int)bm->bit_size, ewah_checksum(bm));
|
||||
oid_to_hex(&root->oid),
|
||||
(int)bm->bit_size, ewah_checksum(bm));
|
||||
|
||||
if (bitmap_is_midx(found))
|
||||
fprintf_ln(stderr, "Located via MIDX '%s'.",
|
||||
hash_to_hex_algop(get_midx_checksum(found->midx),
|
||||
revs->repo->hash_algo));
|
||||
else
|
||||
fprintf_ln(stderr, "Located via pack '%s'.",
|
||||
hash_to_hex_algop(found->pack->hash,
|
||||
revs->repo->hash_algo));
|
||||
|
||||
result = ewah_to_bitmap(bm);
|
||||
}
|
||||
|
@ -2567,16 +2761,10 @@ void test_bitmap_walk(struct rev_info *revs)
|
|||
if (prepare_revision_walk(revs))
|
||||
die(_("revision walk setup failed"));
|
||||
|
||||
tdata.bitmap_git = bitmap_git;
|
||||
tdata.base = bitmap_new();
|
||||
tdata.commits = ewah_to_bitmap(bitmap_git->commits);
|
||||
tdata.trees = ewah_to_bitmap(bitmap_git->trees);
|
||||
tdata.blobs = ewah_to_bitmap(bitmap_git->blobs);
|
||||
tdata.tags = ewah_to_bitmap(bitmap_git->tags);
|
||||
bitmap_test_data_prepare(&tdata, bitmap_git);
|
||||
tdata.prg = start_progress(revs->repo,
|
||||
"Verifying bitmap entries",
|
||||
result_popcnt);
|
||||
tdata.seen = 0;
|
||||
|
||||
traverse_commit_list(revs, &test_show_commit, &test_show_object, &tdata);
|
||||
|
||||
|
@ -2588,11 +2776,7 @@ void test_bitmap_walk(struct rev_info *revs)
|
|||
die(_("mismatch in bitmap results"));
|
||||
|
||||
bitmap_free(result);
|
||||
bitmap_free(tdata.base);
|
||||
bitmap_free(tdata.commits);
|
||||
bitmap_free(tdata.trees);
|
||||
bitmap_free(tdata.blobs);
|
||||
bitmap_free(tdata.tags);
|
||||
bitmap_test_data_release(&tdata);
|
||||
free_bitmap_index(bitmap_git);
|
||||
}
|
||||
|
||||
|
@ -2820,7 +3004,7 @@ uint32_t *create_bitmap_mapping(struct bitmap_index *bitmap_git,
|
|||
BUG("rebuild_existing_bitmaps: missing required rev-cache "
|
||||
"extension");
|
||||
|
||||
num_objects = bitmap_num_objects(bitmap_git);
|
||||
num_objects = bitmap_num_objects_total(bitmap_git);
|
||||
CALLOC_ARRAY(reposition, num_objects);
|
||||
|
||||
for (i = 0; i < num_objects; ++i) {
|
||||
|
@ -2856,6 +3040,10 @@ void free_bitmap_index(struct bitmap_index *b)
|
|||
ewah_pool_free(b->trees);
|
||||
ewah_pool_free(b->blobs);
|
||||
ewah_pool_free(b->tags);
|
||||
free(b->commits_all);
|
||||
free(b->trees_all);
|
||||
free(b->blobs_all);
|
||||
free(b->tags_all);
|
||||
if (b->bitmaps) {
|
||||
struct stored_bitmap *sb;
|
||||
kh_foreach_value(b->bitmaps, sb, {
|
||||
|
@ -2883,6 +3071,7 @@ void free_bitmap_index(struct bitmap_index *b)
|
|||
close_midx_revindex(b->midx);
|
||||
}
|
||||
free_pseudo_merge_map(&b->pseudo_merges);
|
||||
free_bitmap_index(b->base);
|
||||
free(b);
|
||||
}
|
||||
|
||||
|
@ -2898,13 +3087,13 @@ static off_t get_disk_usage_for_type(struct bitmap_index *bitmap_git,
|
|||
{
|
||||
struct bitmap *result = bitmap_git->result;
|
||||
off_t total = 0;
|
||||
struct ewah_iterator it;
|
||||
struct ewah_or_iterator it;
|
||||
eword_t filter;
|
||||
size_t i;
|
||||
|
||||
init_type_iterator(&it, bitmap_git, object_type);
|
||||
for (i = 0; i < result->word_alloc &&
|
||||
ewah_iterator_next(&filter, &it); i++) {
|
||||
ewah_or_iterator_next(&filter, &it); i++) {
|
||||
eword_t word = result->words[i] & filter;
|
||||
size_t base = (i * BITS_IN_EWORD);
|
||||
unsigned offset;
|
||||
|
@ -2924,7 +3113,7 @@ static off_t get_disk_usage_for_type(struct bitmap_index *bitmap_git,
|
|||
off_t offset = nth_midxed_offset(bitmap_git->midx, midx_pos);
|
||||
|
||||
uint32_t pack_id = nth_midxed_pack_int_id(bitmap_git->midx, midx_pos);
|
||||
struct packed_git *pack = bitmap_git->midx->packs[pack_id];
|
||||
struct packed_git *pack = nth_midxed_pack(bitmap_git->midx, pack_id);
|
||||
|
||||
if (offset_to_pack_pos(pack, offset, &pack_pos) < 0) {
|
||||
struct object_id oid;
|
||||
|
@ -2945,6 +3134,8 @@ static off_t get_disk_usage_for_type(struct bitmap_index *bitmap_git,
|
|||
}
|
||||
}
|
||||
|
||||
ewah_or_iterator_release(&it);
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
|
@ -2963,7 +3154,8 @@ static off_t get_disk_usage_for_extended(struct bitmap_index *bitmap_git)
|
|||
struct object *obj = eindex->objects[i];
|
||||
|
||||
if (!bitmap_get(result,
|
||||
st_add(bitmap_num_objects(bitmap_git), i)))
|
||||
st_add(bitmap_num_objects_total(bitmap_git),
|
||||
i)))
|
||||
continue;
|
||||
|
||||
if (oid_object_info_extended(bitmap_repo(bitmap_git), &obj->oid,
|
||||
|
|
|
@ -111,6 +111,7 @@ struct bitmap_writer {
|
|||
|
||||
kh_oid_map_t *bitmaps;
|
||||
struct packing_data *to_pack;
|
||||
struct multi_pack_index *midx; /* if appending to a MIDX chain */
|
||||
|
||||
struct bitmapped_commit *selected;
|
||||
unsigned int selected_nr, selected_alloc;
|
||||
|
@ -125,7 +126,8 @@ struct bitmap_writer {
|
|||
};
|
||||
|
||||
void bitmap_writer_init(struct bitmap_writer *writer, struct repository *r,
|
||||
struct packing_data *pdata);
|
||||
struct packing_data *pdata,
|
||||
struct multi_pack_index *midx);
|
||||
void bitmap_writer_show_progress(struct bitmap_writer *writer, int show);
|
||||
void bitmap_writer_set_checksum(struct bitmap_writer *writer,
|
||||
const unsigned char *sha1);
|
||||
|
|
|
@ -383,8 +383,14 @@ int load_midx_revindex(struct multi_pack_index *m)
|
|||
trace2_data_string("load_midx_revindex", the_repository,
|
||||
"source", "rev");
|
||||
|
||||
get_midx_filename_ext(m->repo->hash_algo, &revindex_name, m->object_dir,
|
||||
get_midx_checksum(m), MIDX_EXT_REV);
|
||||
if (m->has_chain)
|
||||
get_split_midx_filename_ext(m->repo->hash_algo, &revindex_name,
|
||||
m->object_dir, get_midx_checksum(m),
|
||||
MIDX_EXT_REV);
|
||||
else
|
||||
get_midx_filename_ext(m->repo->hash_algo, &revindex_name,
|
||||
m->object_dir, get_midx_checksum(m),
|
||||
MIDX_EXT_REV);
|
||||
|
||||
ret = load_revindex_from_disk(revindex_name.buf,
|
||||
m->num_objects,
|
||||
|
@ -471,11 +477,15 @@ off_t pack_pos_to_offset(struct packed_git *p, uint32_t pos)
|
|||
|
||||
uint32_t pack_pos_to_midx(struct multi_pack_index *m, uint32_t pos)
|
||||
{
|
||||
while (m && pos < m->num_objects_in_base)
|
||||
m = m->base_midx;
|
||||
if (!m)
|
||||
BUG("NULL multi-pack-index for object position: %"PRIu32, pos);
|
||||
if (!m->revindex_data)
|
||||
BUG("pack_pos_to_midx: reverse index not yet loaded");
|
||||
if (m->num_objects <= pos)
|
||||
if (m->num_objects + m->num_objects_in_base <= pos)
|
||||
BUG("pack_pos_to_midx: out-of-bounds object at %"PRIu32, pos);
|
||||
return get_be32(m->revindex_data + pos);
|
||||
return get_be32(m->revindex_data + pos - m->num_objects_in_base);
|
||||
}
|
||||
|
||||
struct midx_pack_key {
|
||||
|
@ -491,7 +501,8 @@ static int midx_pack_order_cmp(const void *va, const void *vb)
|
|||
const struct midx_pack_key *key = va;
|
||||
struct multi_pack_index *midx = key->midx;
|
||||
|
||||
uint32_t versus = pack_pos_to_midx(midx, (uint32_t*)vb - (const uint32_t *)midx->revindex_data);
|
||||
size_t pos = (uint32_t *)vb - (const uint32_t *)midx->revindex_data;
|
||||
uint32_t versus = pack_pos_to_midx(midx, pos + midx->num_objects_in_base);
|
||||
uint32_t versus_pack = nth_midxed_pack_int_id(midx, versus);
|
||||
off_t versus_offset;
|
||||
|
||||
|
@ -529,9 +540,9 @@ static int midx_key_to_pack_pos(struct multi_pack_index *m,
|
|||
{
|
||||
uint32_t *found;
|
||||
|
||||
if (key->pack >= m->num_packs)
|
||||
if (key->pack >= m->num_packs + m->num_packs_in_base)
|
||||
BUG("MIDX pack lookup out of bounds (%"PRIu32" >= %"PRIu32")",
|
||||
key->pack, m->num_packs);
|
||||
key->pack, m->num_packs + m->num_packs_in_base);
|
||||
/*
|
||||
* The preferred pack sorts first, so determine its identifier by
|
||||
* looking at the first object in pseudo-pack order.
|
||||
|
@ -551,7 +562,8 @@ static int midx_key_to_pack_pos(struct multi_pack_index *m,
|
|||
if (!found)
|
||||
return -1;
|
||||
|
||||
*pos = found - m->revindex_data;
|
||||
*pos = (found - m->revindex_data) + m->num_objects_in_base;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -559,9 +571,13 @@ int midx_to_pack_pos(struct multi_pack_index *m, uint32_t at, uint32_t *pos)
|
|||
{
|
||||
struct midx_pack_key key;
|
||||
|
||||
while (m && at < m->num_objects_in_base)
|
||||
m = m->base_midx;
|
||||
if (!m)
|
||||
BUG("NULL multi-pack-index for object position: %"PRIu32, at);
|
||||
if (!m->revindex_data)
|
||||
BUG("midx_to_pack_pos: reverse index not yet loaded");
|
||||
if (m->num_objects <= at)
|
||||
if (m->num_objects + m->num_objects_in_base <= at)
|
||||
BUG("midx_to_pack_pos: out-of-bounds object at %"PRIu32, at);
|
||||
|
||||
key.pack = nth_midxed_pack_int_id(m, at);
|
||||
|
|
|
@ -44,4 +44,91 @@ test_expect_success 'convert incremental to non-incremental' '
|
|||
|
||||
compare_results_with_midx 'non-incremental MIDX conversion'
|
||||
|
||||
write_midx_layer () {
|
||||
n=1
|
||||
if test -f $midx_chain
|
||||
then
|
||||
n="$(($(wc -l <$midx_chain) + 1))"
|
||||
fi
|
||||
|
||||
for i in 1 2
|
||||
do
|
||||
test_commit $n.$i &&
|
||||
git repack -d || return 1
|
||||
done &&
|
||||
git multi-pack-index write --bitmap --incremental
|
||||
}
|
||||
|
||||
test_expect_success 'write initial MIDX layer' '
|
||||
git repack -ad &&
|
||||
write_midx_layer
|
||||
'
|
||||
|
||||
test_expect_success 'read bitmap from first MIDX layer' '
|
||||
git rev-list --test-bitmap 1.2
|
||||
'
|
||||
|
||||
test_expect_success 'write another MIDX layer' '
|
||||
write_midx_layer
|
||||
'
|
||||
|
||||
test_expect_success 'midx verify with multiple layers' '
|
||||
test_path_is_file "$midx_chain" &&
|
||||
test_line_count = 2 "$midx_chain" &&
|
||||
|
||||
git multi-pack-index verify
|
||||
'
|
||||
|
||||
test_expect_success 'read bitmap from second MIDX layer' '
|
||||
git rev-list --test-bitmap 2.2
|
||||
'
|
||||
|
||||
test_expect_success 'read earlier bitmap from second MIDX layer' '
|
||||
git rev-list --test-bitmap 1.2
|
||||
'
|
||||
|
||||
test_expect_success 'show object from first pack' '
|
||||
git cat-file -p 1.1
|
||||
'
|
||||
|
||||
test_expect_success 'show object from second pack' '
|
||||
git cat-file -p 2.2
|
||||
'
|
||||
|
||||
for reuse in false single multi
|
||||
do
|
||||
test_expect_success "full clone (pack.allowPackReuse=$reuse)" '
|
||||
rm -fr clone.git &&
|
||||
|
||||
git config pack.allowPackReuse $reuse &&
|
||||
git clone --no-local --bare . clone.git
|
||||
'
|
||||
done
|
||||
|
||||
test_expect_success 'relink existing MIDX layer' '
|
||||
rm -fr "$midxdir" &&
|
||||
|
||||
GIT_TEST_MIDX_WRITE_REV=1 git multi-pack-index write --bitmap &&
|
||||
|
||||
midx_hash="$(test-tool read-midx --checksum $objdir)" &&
|
||||
|
||||
test_path_is_file "$packdir/multi-pack-index" &&
|
||||
test_path_is_file "$packdir/multi-pack-index-$midx_hash.bitmap" &&
|
||||
test_path_is_file "$packdir/multi-pack-index-$midx_hash.rev" &&
|
||||
|
||||
test_commit another &&
|
||||
git repack -d &&
|
||||
git multi-pack-index write --bitmap --incremental &&
|
||||
|
||||
test_path_is_missing "$packdir/multi-pack-index" &&
|
||||
test_path_is_missing "$packdir/multi-pack-index-$midx_hash.bitmap" &&
|
||||
test_path_is_missing "$packdir/multi-pack-index-$midx_hash.rev" &&
|
||||
|
||||
test_path_is_file "$midxdir/multi-pack-index-$midx_hash.midx" &&
|
||||
test_path_is_file "$midxdir/multi-pack-index-$midx_hash.bitmap" &&
|
||||
test_path_is_file "$midxdir/multi-pack-index-$midx_hash.rev" &&
|
||||
test_line_count = 2 "$midx_chain"
|
||||
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
Loading…
Reference in New Issue