diff options
Diffstat (limited to 'pack-bitmap.c')
| -rw-r--r-- | pack-bitmap.c | 572 |
1 files changed, 439 insertions, 133 deletions
diff --git a/pack-bitmap.c b/pack-bitmap.c index 60b5da9d0b..d14421ee20 100644 --- a/pack-bitmap.c +++ b/pack-bitmap.c @@ -17,8 +17,7 @@ #include "packfile.h" #include "repository.h" #include "trace2.h" -#include "object-file.h" -#include "object-store-ll.h" +#include "odb.h" #include "list-objects-filter-options.h" #include "midx.h" #include "config.h" @@ -32,6 +31,7 @@ struct stored_bitmap { struct object_id oid; struct ewah_bitmap *root; struct stored_bitmap *xor; + size_t map_pos; int flags; }; @@ -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) @@ -279,13 +315,14 @@ static struct stored_bitmap *store_bitmap(struct bitmap_index *index, struct ewah_bitmap *root, const struct object_id *oid, struct stored_bitmap *xor_with, - int flags) + int flags, size_t map_pos) { struct stored_bitmap *stored; khiter_t hash_pos; int ret; stored = xmalloc(sizeof(struct stored_bitmap)); + stored->map_pos = map_pos; stored->root = root; stored->xor = xor_with; stored->flags = flags; @@ -341,10 +378,12 @@ static int load_bitmap_entries_v1(struct bitmap_index *index) struct stored_bitmap *xor_bitmap = NULL; uint32_t commit_idx_pos; struct object_id oid; + size_t entry_map_pos; if (index->map_size - index->map_pos < 6) return error(_("corrupt ewah bitmap: truncated header for entry %d"), i); + entry_map_pos = index->map_pos; commit_idx_pos = read_be32(index->map, &index->map_pos); xor_offset = read_u8(index->map, &index->map_pos); flags = read_u8(index->map, &index->map_pos); @@ -353,10 +392,6 @@ static int load_bitmap_entries_v1(struct bitmap_index *index) return error(_("corrupt ewah bitmap: commit index %u out of range"), (unsigned)commit_idx_pos); - bitmap = read_bitmap_1(index); - if (!bitmap) - return -1; - if (xor_offset > MAX_XOR_OFFSET || xor_offset > i) return error(_("corrupted bitmap pack index")); @@ -367,8 +402,13 @@ static int load_bitmap_entries_v1(struct bitmap_index *index) return error(_("invalid XOR offset in bitmap pack index")); } - recent_bitmaps[i % MAX_XOR_OFFSET] = store_bitmap( - index, bitmap, &oid, xor_bitmap, flags); + bitmap = read_bitmap_1(index); + if (!bitmap) + return -1; + + recent_bitmaps[i % MAX_XOR_OFFSET] = + store_bitmap(index, bitmap, &oid, xor_bitmap, flags, + entry_map_pos); } return 0; @@ -377,8 +417,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 +492,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 +558,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 +578,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 +587,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); @@ -553,31 +635,28 @@ static int load_bitmap(struct repository *r, struct bitmap_index *bitmap_git) bitmap_git->ext_index.positions = kh_init_oid_pos(); if (load_reverse_index(r, bitmap_git)) - goto failed; + return -1; if (!(bitmap_git->commits = read_bitmap_1(bitmap_git)) || !(bitmap_git->trees = read_bitmap_1(bitmap_git)) || !(bitmap_git->blobs = read_bitmap_1(bitmap_git)) || !(bitmap_git->tags = read_bitmap_1(bitmap_git))) - goto failed; + return -1; if (!bitmap_git->table_lookup && load_bitmap_entries_v1(bitmap_git) < 0) - goto failed; - - return 0; - -failed: - munmap(bitmap_git->map, bitmap_git->map_size); - bitmap_git->map = NULL; - bitmap_git->map_size = 0; + return -1; - kh_destroy_oid_map(bitmap_git->bitmaps); - bitmap_git->bitmaps = NULL; + 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) + return -1; + } - kh_destroy_oid_pos(bitmap_git->ext_index.positions); - bitmap_git->ext_index.positions = NULL; + if (!recursing) + load_all_type_bitmaps(bitmap_git); - return -1; + return 0; } static int open_pack_bitmap(struct repository *r, @@ -604,13 +683,15 @@ static int open_pack_bitmap(struct repository *r, static int open_midx_bitmap(struct repository *r, struct bitmap_index *bitmap_git) { + struct odb_source *source; int ret = -1; - struct multi_pack_index *midx; assert(!bitmap_git->map); - for (midx = get_multi_pack_index(r); midx; midx = midx->next) { - if (!open_midx_bitmap_1(bitmap_git, midx)) + odb_prepare_alternates(r->objects); + for (source = r->objects->sources; source; source = source->next) { + struct multi_pack_index *midx = get_multi_pack_index(source); + if (midx && !open_midx_bitmap_1(bitmap_git, midx)) ret = 0; } return ret; @@ -639,7 +720,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,16 +729,30 @@ 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); return NULL; } +int bitmap_index_contains_pack(struct bitmap_index *bitmap, struct packed_git *pack) +{ + for (; bitmap; bitmap = bitmap->base) { + if (bitmap_is_midx(bitmap)) { + for (size_t i = 0; i < bitmap->midx->num_packs; i++) + if (bitmap->midx->packs[i] == pack) + return 1; + } else if (bitmap->pack == pack) { + return 1; + } + } + + return 0; +} + struct include_data { struct bitmap_index *bitmap_git; struct bitmap *base; @@ -781,6 +876,7 @@ static struct stored_bitmap *lazy_bitmap_for_commit(struct bitmap_index *bitmap_ int xor_flags; khiter_t hash_pos; struct bitmap_lookup_table_xor_item *xor_item; + size_t entry_map_pos; if (is_corrupt) return NULL; @@ -840,6 +936,7 @@ static struct stored_bitmap *lazy_bitmap_for_commit(struct bitmap_index *bitmap_ goto corrupt; } + entry_map_pos = bitmap_git->map_pos; bitmap_git->map_pos += sizeof(uint32_t) + sizeof(uint8_t); xor_flags = read_u8(bitmap_git->map, &bitmap_git->map_pos); bitmap = read_bitmap_1(bitmap_git); @@ -847,7 +944,8 @@ static struct stored_bitmap *lazy_bitmap_for_commit(struct bitmap_index *bitmap_ if (!bitmap) goto corrupt; - xor_bitmap = store_bitmap(bitmap_git, bitmap, &xor_item->oid, xor_bitmap, xor_flags); + xor_bitmap = store_bitmap(bitmap_git, bitmap, &xor_item->oid, + xor_bitmap, xor_flags, entry_map_pos); xor_items_nr--; } @@ -881,6 +979,7 @@ static struct stored_bitmap *lazy_bitmap_for_commit(struct bitmap_index *bitmap_ * Instead, we can skip ahead and immediately read the flags and * ewah bitmap. */ + entry_map_pos = bitmap_git->map_pos; bitmap_git->map_pos += sizeof(uint32_t) + sizeof(uint8_t); flags = read_u8(bitmap_git->map, &bitmap_git->map_pos); bitmap = read_bitmap_1(bitmap_git); @@ -888,7 +987,8 @@ static struct stored_bitmap *lazy_bitmap_for_commit(struct bitmap_index *bitmap_ if (!bitmap) goto corrupt; - return store_bitmap(bitmap_git, bitmap, oid, xor_bitmap, flags); + return store_bitmap(bitmap_git, bitmap, oid, xor_bitmap, flags, + entry_map_pos); corrupt: free(xor_items); @@ -896,26 +996,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 +1040,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 +1108,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 +1140,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; @@ -1241,8 +1362,8 @@ static struct bitmap *find_boundary_objects(struct bitmap_index *bitmap_git, bitmap_set(roots_bitmap, pos); } - if (!cascade_pseudo_merges_1(bitmap_git, cb.base, roots_bitmap)) - bitmap_free(roots_bitmap); + cascade_pseudo_merges_1(bitmap_git, cb.base, roots_bitmap); + bitmap_free(roots_bitmap); } /* @@ -1301,7 +1422,7 @@ static struct bitmap *find_boundary_objects(struct bitmap_index *bitmap_git, revs->tag_objects = tmp_tags; reset_revision_walk(); - clear_object_flags(UNINTERESTING); + clear_object_flags(repo, UNINTERESTING); /* * Then add the boundary commit(s) as fill-in traversal tips. @@ -1342,11 +1463,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 +1627,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]; @@ -1509,29 +1638,33 @@ static void show_extended_objects(struct bitmap_index *bitmap_git, (obj->type == OBJ_TAG && !revs->tag_objects)) continue; - show_reach(&obj->oid, obj->type, 0, eindex->hashes[i], NULL, 0); + show_reach(&obj->oid, obj->type, 0, eindex->hashes[i], NULL, 0, NULL); } } -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: @@ -1542,21 +1675,21 @@ static void init_type_iterator(struct ewah_iterator *it, static void show_objects_for_type( struct bitmap_index *bitmap_git, + struct bitmap *objects, enum object_type object_type, - show_reachable_fn show_reach) + show_reachable_fn show_reach, + void *payload) { 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; - 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 +1716,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); @@ -1595,9 +1728,11 @@ static void show_objects_for_type( if (bitmap_git->hashes) hash = get_be32(bitmap_git->hashes + index_pos); - show_reach(&oid, object_type, 0, hash, pack, ofs); + show_reach(&oid, object_type, 0, hash, pack, ofs, payload); } } + + ewah_or_iterator_release(&it); } static int in_bitmapped_pack(struct bitmap_index *bitmap_git, @@ -1649,7 +1784,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 +1801,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 +1814,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 +1841,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 +1849,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,10 +1864,11 @@ 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)]; - if (oid_object_info_extended(bitmap_repo(bitmap_git), &obj->oid, - &oi, 0) < 0) + struct object *obj = eindex->objects[eindex_pos]; + if (odb_read_object_info_extended(bitmap_repo(bitmap_git)->objects, &obj->oid, + &oi, 0) < 0) die(_("unable to get size of %s"), oid_to_hex(&obj->oid)); } @@ -1745,14 +1882,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 +1917,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 +2020,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) @@ -1899,6 +2037,50 @@ static void filter_packed_objects_from_bitmap(struct bitmap_index *bitmap_git, } } +int for_each_bitmapped_object(struct bitmap_index *bitmap_git, + struct list_objects_filter_options *filter, + show_reachable_fn show_reach, + void *payload) +{ + struct bitmap *filtered_bitmap = NULL; + uint32_t objects_nr; + size_t full_word_count; + int ret; + + if (!can_filter_bitmap(filter)) { + ret = -1; + goto out; + } + + objects_nr = bitmap_num_objects(bitmap_git); + full_word_count = objects_nr / BITS_IN_EWORD; + + /* We start from the all-1 bitmap and then filter down from there. */ + filtered_bitmap = bitmap_word_alloc(full_word_count + !!(objects_nr % BITS_IN_EWORD)); + memset(filtered_bitmap->words, 0xff, full_word_count * sizeof(*filtered_bitmap->words)); + for (size_t i = full_word_count * BITS_IN_EWORD; i < objects_nr; i++) + bitmap_set(filtered_bitmap, i); + + if (filter_bitmap(bitmap_git, NULL, filtered_bitmap, filter) < 0) { + ret = -1; + goto out; + } + + show_objects_for_type(bitmap_git, filtered_bitmap, + OBJ_COMMIT, show_reach, payload); + show_objects_for_type(bitmap_git, filtered_bitmap, + OBJ_TREE, show_reach, payload); + show_objects_for_type(bitmap_git, filtered_bitmap, + OBJ_BLOB, show_reach, payload); + show_objects_for_type(bitmap_git, filtered_bitmap, + OBJ_TAG, show_reach, payload); + + ret = 0; +out: + bitmap_free(filtered_bitmap); + return ret; +} + struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs, int filter_provided_objects) { @@ -1935,7 +2117,7 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs, struct object *object = revs->pending.objects[i].item; if (object->type == OBJ_NONE) - parse_object_or_die(&object->oid, NULL); + parse_object_or_die(revs->repo, &object->oid, NULL); while (object->type == OBJ_TAG) { struct tag *tag = (struct tag *) object; @@ -1945,7 +2127,7 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs, else object_list_insert(object, &wants); - object = parse_object_or_die(get_tagged_oid(tag), NULL); + object = parse_object_or_die(revs->repo, get_tagged_oid(tag), NULL); object->flags |= (tag->object.flags & UNINTERESTING); } @@ -1980,7 +2162,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 +2463,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 +2490,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; @@ -2388,13 +2575,17 @@ void traverse_bitmap_commit_list(struct bitmap_index *bitmap_git, { assert(bitmap_git->result); - show_objects_for_type(bitmap_git, OBJ_COMMIT, show_reachable); + show_objects_for_type(bitmap_git, bitmap_git->result, + OBJ_COMMIT, show_reachable, NULL); if (revs->tree_objects) - show_objects_for_type(bitmap_git, OBJ_TREE, show_reachable); + show_objects_for_type(bitmap_git, bitmap_git->result, + OBJ_TREE, show_reachable, NULL); if (revs->blob_objects) - show_objects_for_type(bitmap_git, OBJ_BLOB, show_reachable); + show_objects_for_type(bitmap_git, bitmap_git->result, + OBJ_BLOB, show_reachable, NULL); if (revs->tag_objects) - show_objects_for_type(bitmap_git, OBJ_TAG, show_reachable); + show_objects_for_type(bitmap_git, bitmap_git->result, + OBJ_TAG, show_reachable, NULL); show_extended_objects(bitmap_git, revs, show_reachable); } @@ -2406,12 +2597,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 +2610,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 +2647,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 +2657,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 +2725,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 +2784,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,14 +2822,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); - tdata.prg = start_progress("Verifying bitmap entries", result_popcnt); - tdata.seen = 0; + bitmap_test_data_prepare(&tdata, bitmap_git); + tdata.prg = start_progress(revs->repo, + "Verifying bitmap entries", + result_popcnt); traverse_commit_list(revs, &test_show_commit, &test_show_object, &tdata); @@ -2586,11 +2837,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); } @@ -2604,8 +2851,9 @@ int test_bitmap_commits(struct repository *r) die(_("failed to load bitmap indexes")); /* - * As this function is only used to print bitmap selected - * commits, we don't have to read the commit table. + * Since this function needs to print the bitmapped + * commits, bypass the commit lookup table (if one exists) + * by forcing the bitmap to eagerly load its entries. */ if (bitmap_git->table_lookup) { if (load_bitmap_entries_v1(bitmap_git) < 0) @@ -2621,6 +2869,48 @@ int test_bitmap_commits(struct repository *r) return 0; } +int test_bitmap_commits_with_offset(struct repository *r) +{ + struct object_id oid; + struct stored_bitmap *stored; + struct bitmap_index *bitmap_git; + size_t commit_idx_pos_map_pos, xor_offset_map_pos, flag_map_pos, + ewah_bitmap_map_pos; + + bitmap_git = prepare_bitmap_git(r); + if (!bitmap_git) + die(_("failed to load bitmap indexes")); + + /* + * Since this function needs to know the position of each individual + * bitmap, bypass the commit lookup table (if one exists) by forcing + * the bitmap to eagerly load its entries. + */ + if (bitmap_git->table_lookup) { + if (load_bitmap_entries_v1(bitmap_git) < 0) + die(_("failed to load bitmap indexes")); + } + + kh_foreach (bitmap_git->bitmaps, oid, stored, { + commit_idx_pos_map_pos = stored->map_pos; + xor_offset_map_pos = stored->map_pos + sizeof(uint32_t); + flag_map_pos = xor_offset_map_pos + sizeof(uint8_t); + ewah_bitmap_map_pos = flag_map_pos + sizeof(uint8_t); + + printf_ln("%s %"PRIuMAX" %"PRIuMAX" %"PRIuMAX" %"PRIuMAX, + oid_to_hex(&oid), + (uintmax_t)commit_idx_pos_map_pos, + (uintmax_t)xor_offset_map_pos, + (uintmax_t)flag_map_pos, + (uintmax_t)ewah_bitmap_map_pos); + }) + ; + + free_bitmap_index(bitmap_git); + + return 0; +} + int test_bitmap_hashes(struct repository *r) { struct bitmap_index *bitmap_git = prepare_bitmap_git(r); @@ -2818,7 +3108,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) { @@ -2854,6 +3144,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, { @@ -2881,6 +3175,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); } @@ -2896,13 +3191,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; @@ -2922,7 +3217,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; @@ -2943,6 +3238,8 @@ static off_t get_disk_usage_for_type(struct bitmap_index *bitmap_git, } } + ewah_or_iterator_release(&it); + return total; } @@ -2961,11 +3258,12 @@ 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, - &oi, 0) < 0) + if (odb_read_object_info_extended(bitmap_repo(bitmap_git)->objects, + &obj->oid, &oi, 0) < 0) die(_("unable to get disk usage of '%s'"), oid_to_hex(&obj->oid)); @@ -3022,7 +3320,8 @@ int bitmap_is_preferred_refname(struct repository *r, const char *refname) return 0; } -static int verify_bitmap_file(const char *name) +static int verify_bitmap_file(const struct git_hash_algo *algop, + const char *name) { struct stat st; unsigned char *data; @@ -3038,7 +3337,7 @@ static int verify_bitmap_file(const char *name) data = xmmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); close(fd); - if (!hashfile_checksum_valid(data, st.st_size)) + if (!hashfile_checksum_valid(algop, data, st.st_size)) res = error(_("bitmap file '%s' has invalid checksum"), name); @@ -3048,19 +3347,26 @@ static int verify_bitmap_file(const char *name) int verify_bitmap_files(struct repository *r) { + struct odb_source *source; int res = 0; - for (struct multi_pack_index *m = get_multi_pack_index(r); - m; m = m->next) { - char *midx_bitmap_name = midx_bitmap_filename(m); - res |= verify_bitmap_file(midx_bitmap_name); + odb_prepare_alternates(r->objects); + for (source = r->objects->sources; source; source = source->next) { + struct multi_pack_index *m = get_multi_pack_index(source); + char *midx_bitmap_name; + + if (!m) + continue; + + midx_bitmap_name = midx_bitmap_filename(m); + res |= verify_bitmap_file(r->hash_algo, midx_bitmap_name); free(midx_bitmap_name); } for (struct packed_git *p = get_all_packs(r); p; p = p->next) { char *pack_bitmap_name = pack_bitmap_filename(p); - res |= verify_bitmap_file(pack_bitmap_name); + res |= verify_bitmap_file(r->hash_algo, pack_bitmap_name); free(pack_bitmap_name); } |
