git
/
pack-bitmap-write.c
1071 строка · 27.3 Кб
1#define USE_THE_REPOSITORY_VARIABLE2
3#include "git-compat-util.h"4#include "environment.h"5#include "gettext.h"6#include "hex.h"7#include "object-store-ll.h"8#include "commit.h"9#include "diff.h"10#include "revision.h"11#include "progress.h"12#include "pack.h"13#include "pack-bitmap.h"14#include "hash-lookup.h"15#include "pack-objects.h"16#include "path.h"17#include "commit-reach.h"18#include "prio-queue.h"19#include "trace2.h"20#include "tree.h"21#include "tree-walk.h"22#include "pseudo-merge.h"23#include "oid-array.h"24#include "config.h"25#include "alloc.h"26#include "refs.h"27#include "strmap.h"28
29struct bitmapped_commit {30struct commit *commit;31struct ewah_bitmap *bitmap;32struct ewah_bitmap *write_as;33int flags;34int xor_offset;35uint32_t commit_pos;36unsigned pseudo_merge : 1;37};38
39static inline int bitmap_writer_nr_selected_commits(struct bitmap_writer *writer)40{
41return writer->selected_nr - writer->pseudo_merges_nr;42}
43
44void bitmap_writer_init(struct bitmap_writer *writer, struct repository *r,45struct packing_data *pdata)46{
47memset(writer, 0, sizeof(struct bitmap_writer));48if (writer->bitmaps)49BUG("bitmap writer already initialized");50writer->bitmaps = kh_init_oid_map();51writer->pseudo_merge_commits = kh_init_oid_map();52writer->to_pack = pdata;53
54string_list_init_dup(&writer->pseudo_merge_groups);55
56load_pseudo_merges_from_config(r, &writer->pseudo_merge_groups);57}
58
59static void free_pseudo_merge_commit_idx(struct pseudo_merge_commit_idx *idx)60{
61if (!idx)62return;63free(idx->pseudo_merge);64free(idx);65}
66
67void bitmap_writer_free(struct bitmap_writer *writer)68{
69uint32_t i;70struct pseudo_merge_commit_idx *idx;71
72if (!writer)73return;74
75ewah_free(writer->commits);76ewah_free(writer->trees);77ewah_free(writer->blobs);78ewah_free(writer->tags);79
80kh_destroy_oid_map(writer->bitmaps);81
82kh_foreach_value(writer->pseudo_merge_commits, idx,83free_pseudo_merge_commit_idx(idx));84kh_destroy_oid_map(writer->pseudo_merge_commits);85
86for (i = 0; i < writer->selected_nr; i++) {87struct bitmapped_commit *bc = &writer->selected[i];88if (bc->write_as != bc->bitmap)89ewah_free(bc->write_as);90ewah_free(bc->bitmap);91}92free(writer->selected);93}
94
95void bitmap_writer_show_progress(struct bitmap_writer *writer, int show)96{
97writer->show_progress = show;98}
99
100/**
101* Build the initial type index for the packfile or multi-pack-index
102*/
103void bitmap_writer_build_type_index(struct bitmap_writer *writer,104struct pack_idx_entry **index)105{
106uint32_t i;107
108writer->commits = ewah_new();109writer->trees = ewah_new();110writer->blobs = ewah_new();111writer->tags = ewah_new();112ALLOC_ARRAY(writer->to_pack->in_pack_pos, writer->to_pack->nr_objects);113
114for (i = 0; i < writer->to_pack->nr_objects; ++i) {115struct object_entry *entry = (struct object_entry *)index[i];116enum object_type real_type;117
118oe_set_in_pack_pos(writer->to_pack, entry, i);119
120switch (oe_type(entry)) {121case OBJ_COMMIT:122case OBJ_TREE:123case OBJ_BLOB:124case OBJ_TAG:125real_type = oe_type(entry);126break;127
128default:129real_type = oid_object_info(writer->to_pack->repo,130&entry->idx.oid, NULL);131break;132}133
134switch (real_type) {135case OBJ_COMMIT:136ewah_set(writer->commits, i);137break;138
139case OBJ_TREE:140ewah_set(writer->trees, i);141break;142
143case OBJ_BLOB:144ewah_set(writer->blobs, i);145break;146
147case OBJ_TAG:148ewah_set(writer->tags, i);149break;150
151default:152die("Missing type information for %s (%d/%d)",153oid_to_hex(&entry->idx.oid), real_type,154oe_type(entry));155}156}157}
158
159int bitmap_writer_has_bitmapped_object_id(struct bitmap_writer *writer,160const struct object_id *oid)161{
162return kh_get_oid_map(writer->bitmaps, *oid) != kh_end(writer->bitmaps);163}
164
165/**
166* Compute the actual bitmaps
167*/
168
169void bitmap_writer_push_commit(struct bitmap_writer *writer,170struct commit *commit, unsigned pseudo_merge)171{
172if (writer->selected_nr >= writer->selected_alloc) {173writer->selected_alloc = (writer->selected_alloc + 32) * 2;174REALLOC_ARRAY(writer->selected, writer->selected_alloc);175}176
177if (!pseudo_merge) {178int hash_ret;179khiter_t hash_pos = kh_put_oid_map(writer->bitmaps,180commit->object.oid,181&hash_ret);182
183if (!hash_ret)184die(_("duplicate entry when writing bitmap index: %s"),185oid_to_hex(&commit->object.oid));186kh_value(writer->bitmaps, hash_pos) = NULL;187}188
189writer->selected[writer->selected_nr].commit = commit;190writer->selected[writer->selected_nr].bitmap = NULL;191writer->selected[writer->selected_nr].write_as = NULL;192writer->selected[writer->selected_nr].flags = 0;193writer->selected[writer->selected_nr].pseudo_merge = pseudo_merge;194
195writer->selected_nr++;196}
197
198static uint32_t find_object_pos(struct bitmap_writer *writer,199const struct object_id *oid, int *found)200{
201struct object_entry *entry = packlist_find(writer->to_pack, oid);202
203if (!entry) {204if (found)205*found = 0;206warning("Failed to write bitmap index. Packfile doesn't have full closure "207"(object %s is missing)", oid_to_hex(oid));208return 0;209}210
211if (found)212*found = 1;213return oe_in_pack_pos(writer->to_pack, entry);214}
215
216static void compute_xor_offsets(struct bitmap_writer *writer)217{
218static const int MAX_XOR_OFFSET_SEARCH = 10;219
220int i, next = 0;221
222while (next < writer->selected_nr) {223struct bitmapped_commit *stored = &writer->selected[next];224int best_offset = 0;225struct ewah_bitmap *best_bitmap = stored->bitmap;226struct ewah_bitmap *test_xor;227
228if (stored->pseudo_merge)229goto next;230
231for (i = 1; i <= MAX_XOR_OFFSET_SEARCH; ++i) {232int curr = next - i;233
234if (curr < 0)235break;236if (writer->selected[curr].pseudo_merge)237continue;238
239test_xor = ewah_pool_new();240ewah_xor(writer->selected[curr].bitmap, stored->bitmap, test_xor);241
242if (test_xor->buffer_size < best_bitmap->buffer_size) {243if (best_bitmap != stored->bitmap)244ewah_pool_free(best_bitmap);245
246best_bitmap = test_xor;247best_offset = i;248} else {249ewah_pool_free(test_xor);250}251}252
253next:254stored->xor_offset = best_offset;255stored->write_as = best_bitmap;256
257next++;258}259}
260
261struct bb_commit {262struct commit_list *reverse_edges;263struct bitmap *commit_mask;264struct bitmap *bitmap;265unsigned selected:1,266maximal:1,267pseudo_merge:1;268unsigned idx; /* within selected array */269};270
271static void clear_bb_commit(struct bb_commit *commit)272{
273free_commit_list(commit->reverse_edges);274bitmap_free(commit->commit_mask);275bitmap_free(commit->bitmap);276}
277
278define_commit_slab(bb_data, struct bb_commit);279
280struct bitmap_builder {281struct bb_data data;282struct commit **commits;283size_t commits_nr, commits_alloc;284};285
286static void bitmap_builder_init(struct bitmap_builder *bb,287struct bitmap_writer *writer,288struct bitmap_index *old_bitmap)289{
290struct rev_info revs;291struct commit *commit;292struct commit_list *reusable = NULL;293struct commit_list *r;294unsigned int i, num_maximal = 0;295
296memset(bb, 0, sizeof(*bb));297init_bb_data(&bb->data);298
299reset_revision_walk();300repo_init_revisions(writer->to_pack->repo, &revs, NULL);301revs.topo_order = 1;302revs.first_parent_only = 1;303
304for (i = 0; i < writer->selected_nr; i++) {305struct bitmapped_commit *bc = &writer->selected[i];306struct bb_commit *ent = bb_data_at(&bb->data, bc->commit);307
308ent->selected = 1;309ent->maximal = 1;310ent->pseudo_merge = bc->pseudo_merge;311ent->idx = i;312
313ent->commit_mask = bitmap_new();314bitmap_set(ent->commit_mask, i);315
316add_pending_object(&revs, &bc->commit->object, "");317}318
319if (prepare_revision_walk(&revs))320die("revision walk setup failed");321
322while ((commit = get_revision(&revs))) {323struct commit_list *p = commit->parents;324struct bb_commit *c_ent;325
326parse_commit_or_die(commit);327
328c_ent = bb_data_at(&bb->data, commit);329
330/*331* If there is no commit_mask, there is no reason to iterate
332* over this commit; it is not selected (if it were, it would
333* not have a blank commit mask) and all its children have
334* existing bitmaps (see the comment starting with "This commit
335* has an existing bitmap" below), so it does not contribute
336* anything to the final bitmap file or its descendants.
337*/
338if (!c_ent->commit_mask)339continue;340
341if (old_bitmap && bitmap_for_commit(old_bitmap, commit)) {342/*343* This commit has an existing bitmap, so we can
344* get its bits immediately without an object
345* walk. That is, it is reusable as-is and there is no
346* need to continue walking beyond it.
347*
348* Mark it as such and add it to bb->commits separately
349* to avoid allocating a position in the commit mask.
350*/
351commit_list_insert(commit, &reusable);352goto next;353}354
355if (c_ent->maximal) {356num_maximal++;357ALLOC_GROW(bb->commits, bb->commits_nr + 1, bb->commits_alloc);358bb->commits[bb->commits_nr++] = commit;359}360
361if (p) {362struct bb_commit *p_ent = bb_data_at(&bb->data, p->item);363int c_not_p, p_not_c;364
365if (!p_ent->commit_mask) {366p_ent->commit_mask = bitmap_new();367c_not_p = 1;368p_not_c = 0;369} else {370c_not_p = bitmap_is_subset(c_ent->commit_mask, p_ent->commit_mask);371p_not_c = bitmap_is_subset(p_ent->commit_mask, c_ent->commit_mask);372}373
374if (!c_not_p)375continue;376
377bitmap_or(p_ent->commit_mask, c_ent->commit_mask);378
379if (p_not_c)380p_ent->maximal = 1;381else {382p_ent->maximal = 0;383free_commit_list(p_ent->reverse_edges);384p_ent->reverse_edges = NULL;385}386
387if (c_ent->maximal) {388commit_list_insert(commit, &p_ent->reverse_edges);389} else {390struct commit_list *cc = c_ent->reverse_edges;391
392for (; cc; cc = cc->next) {393if (!commit_list_contains(cc->item, p_ent->reverse_edges))394commit_list_insert(cc->item, &p_ent->reverse_edges);395}396}397}398
399next:400bitmap_free(c_ent->commit_mask);401c_ent->commit_mask = NULL;402}403
404for (r = reusable; r; r = r->next) {405ALLOC_GROW(bb->commits, bb->commits_nr + 1, bb->commits_alloc);406bb->commits[bb->commits_nr++] = r->item;407}408
409trace2_data_intmax("pack-bitmap-write", the_repository,410"num_selected_commits", writer->selected_nr);411trace2_data_intmax("pack-bitmap-write", the_repository,412"num_maximal_commits", num_maximal);413
414release_revisions(&revs);415free_commit_list(reusable);416}
417
418static void bitmap_builder_clear(struct bitmap_builder *bb)419{
420deep_clear_bb_data(&bb->data, clear_bb_commit);421free(bb->commits);422bb->commits_nr = bb->commits_alloc = 0;423}
424
425static int fill_bitmap_tree(struct bitmap_writer *writer,426struct bitmap *bitmap,427struct tree *tree)428{
429int found;430uint32_t pos;431struct tree_desc desc;432struct name_entry entry;433
434/*435* If our bit is already set, then there is nothing to do. Both this
436* tree and all of its children will be set.
437*/
438pos = find_object_pos(writer, &tree->object.oid, &found);439if (!found)440return -1;441if (bitmap_get(bitmap, pos))442return 0;443bitmap_set(bitmap, pos);444
445if (parse_tree(tree) < 0)446die("unable to load tree object %s",447oid_to_hex(&tree->object.oid));448init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);449
450while (tree_entry(&desc, &entry)) {451switch (object_type(entry.mode)) {452case OBJ_TREE:453if (fill_bitmap_tree(writer, bitmap,454lookup_tree(the_repository, &entry.oid)) < 0)455return -1;456break;457case OBJ_BLOB:458pos = find_object_pos(writer, &entry.oid, &found);459if (!found)460return -1;461bitmap_set(bitmap, pos);462break;463default:464/* Gitlink, etc; not reachable */465break;466}467}468
469free_tree_buffer(tree);470return 0;471}
472
473static int reused_bitmaps_nr;474static int reused_pseudo_merge_bitmaps_nr;475
476static int fill_bitmap_commit(struct bitmap_writer *writer,477struct bb_commit *ent,478struct commit *commit,479struct prio_queue *queue,480struct prio_queue *tree_queue,481struct bitmap_index *old_bitmap,482const uint32_t *mapping)483{
484int found;485uint32_t pos;486if (!ent->bitmap)487ent->bitmap = bitmap_new();488
489prio_queue_put(queue, commit);490
491while (queue->nr) {492struct commit_list *p;493struct commit *c = prio_queue_get(queue);494
495if (old_bitmap && mapping) {496struct ewah_bitmap *old;497struct bitmap *remapped = bitmap_new();498
499if (commit->object.flags & BITMAP_PSEUDO_MERGE)500old = pseudo_merge_bitmap_for_commit(old_bitmap, c);501else502old = bitmap_for_commit(old_bitmap, c);503/*504* If this commit has an old bitmap, then translate that
505* bitmap and add its bits to this one. No need to walk
506* parents or the tree for this commit.
507*/
508if (old && !rebuild_bitmap(mapping, old, remapped)) {509bitmap_or(ent->bitmap, remapped);510bitmap_free(remapped);511if (commit->object.flags & BITMAP_PSEUDO_MERGE)512reused_pseudo_merge_bitmaps_nr++;513else514reused_bitmaps_nr++;515continue;516}517bitmap_free(remapped);518}519
520/*521* Mark ourselves and queue our tree. The commit
522* walk ensures we cover all parents.
523*/
524if (!(c->object.flags & BITMAP_PSEUDO_MERGE)) {525pos = find_object_pos(writer, &c->object.oid, &found);526if (!found)527return -1;528bitmap_set(ent->bitmap, pos);529prio_queue_put(tree_queue,530repo_get_commit_tree(the_repository, c));531}532
533for (p = c->parents; p; p = p->next) {534pos = find_object_pos(writer, &p->item->object.oid,535&found);536if (!found)537return -1;538if (!bitmap_get(ent->bitmap, pos)) {539bitmap_set(ent->bitmap, pos);540prio_queue_put(queue, p->item);541}542}543}544
545while (tree_queue->nr) {546if (fill_bitmap_tree(writer, ent->bitmap,547prio_queue_get(tree_queue)) < 0)548return -1;549}550return 0;551}
552
553static void store_selected(struct bitmap_writer *writer,554struct bb_commit *ent, struct commit *commit)555{
556struct bitmapped_commit *stored = &writer->selected[ent->idx];557khiter_t hash_pos;558
559stored->bitmap = bitmap_to_ewah(ent->bitmap);560
561if (ent->pseudo_merge)562return;563
564hash_pos = kh_get_oid_map(writer->bitmaps, commit->object.oid);565if (hash_pos == kh_end(writer->bitmaps))566die(_("attempted to store non-selected commit: '%s'"),567oid_to_hex(&commit->object.oid));568
569kh_value(writer->bitmaps, hash_pos) = stored;570}
571
572int bitmap_writer_build(struct bitmap_writer *writer)573{
574struct bitmap_builder bb;575size_t i;576int nr_stored = 0; /* for progress */577struct prio_queue queue = { compare_commits_by_gen_then_commit_date };578struct prio_queue tree_queue = { NULL };579struct bitmap_index *old_bitmap;580uint32_t *mapping;581int closed = 1; /* until proven otherwise */582
583if (writer->show_progress)584writer->progress = start_progress("Building bitmaps",585writer->selected_nr);586trace2_region_enter("pack-bitmap-write", "building_bitmaps_total",587the_repository);588
589old_bitmap = prepare_bitmap_git(writer->to_pack->repo);590if (old_bitmap)591mapping = create_bitmap_mapping(old_bitmap, writer->to_pack);592else593mapping = NULL;594
595bitmap_builder_init(&bb, writer, old_bitmap);596for (i = bb.commits_nr; i > 0; i--) {597struct commit *commit = bb.commits[i-1];598struct bb_commit *ent = bb_data_at(&bb.data, commit);599struct commit *child;600int reused = 0;601
602if (fill_bitmap_commit(writer, ent, commit, &queue, &tree_queue,603old_bitmap, mapping) < 0) {604closed = 0;605break;606}607
608if (ent->selected) {609store_selected(writer, ent, commit);610nr_stored++;611display_progress(writer->progress, nr_stored);612}613
614while ((child = pop_commit(&ent->reverse_edges))) {615struct bb_commit *child_ent =616bb_data_at(&bb.data, child);617
618if (child_ent->bitmap)619bitmap_or(child_ent->bitmap, ent->bitmap);620else if (reused)621child_ent->bitmap = bitmap_dup(ent->bitmap);622else {623child_ent->bitmap = ent->bitmap;624reused = 1;625}626}627if (!reused)628bitmap_free(ent->bitmap);629ent->bitmap = NULL;630}631clear_prio_queue(&queue);632clear_prio_queue(&tree_queue);633bitmap_builder_clear(&bb);634free_bitmap_index(old_bitmap);635free(mapping);636
637trace2_region_leave("pack-bitmap-write", "building_bitmaps_total",638the_repository);639trace2_data_intmax("pack-bitmap-write", the_repository,640"building_bitmaps_reused", reused_bitmaps_nr);641trace2_data_intmax("pack-bitmap-write", the_repository,642"building_bitmaps_pseudo_merge_reused",643reused_pseudo_merge_bitmaps_nr);644
645stop_progress(&writer->progress);646
647if (closed)648compute_xor_offsets(writer);649return closed ? 0 : -1;650}
651
652/**
653* Select the commits that will be bitmapped
654*/
655static inline unsigned int next_commit_index(unsigned int idx)656{
657static const unsigned int MIN_COMMITS = 100;658static const unsigned int MAX_COMMITS = 5000;659
660static const unsigned int MUST_REGION = 100;661static const unsigned int MIN_REGION = 20000;662
663unsigned int offset, next;664
665if (idx <= MUST_REGION)666return 0;667
668if (idx <= MIN_REGION) {669offset = idx - MUST_REGION;670return (offset < MIN_COMMITS) ? offset : MIN_COMMITS;671}672
673offset = idx - MIN_REGION;674next = (offset < MAX_COMMITS) ? offset : MAX_COMMITS;675
676return (next > MIN_COMMITS) ? next : MIN_COMMITS;677}
678
679static int date_compare(const void *_a, const void *_b)680{
681struct commit *a = *(struct commit **)_a;682struct commit *b = *(struct commit **)_b;683return (long)b->date - (long)a->date;684}
685
686void bitmap_writer_select_commits(struct bitmap_writer *writer,687struct commit **indexed_commits,688unsigned int indexed_commits_nr)689{
690unsigned int i = 0, j, next;691
692QSORT(indexed_commits, indexed_commits_nr, date_compare);693
694if (indexed_commits_nr < 100) {695for (i = 0; i < indexed_commits_nr; ++i)696bitmap_writer_push_commit(writer, indexed_commits[i], 0);697
698select_pseudo_merges(writer);699
700return;701}702
703if (writer->show_progress)704writer->progress = start_progress("Selecting bitmap commits", 0);705
706for (;;) {707struct commit *chosen = NULL;708
709next = next_commit_index(i);710
711if (i + next >= indexed_commits_nr)712break;713
714if (next == 0) {715chosen = indexed_commits[i];716} else {717chosen = indexed_commits[i + next];718
719for (j = 0; j <= next; ++j) {720struct commit *cm = indexed_commits[i + j];721
722if ((cm->object.flags & NEEDS_BITMAP) != 0) {723chosen = cm;724break;725}726
727if (cm->parents && cm->parents->next)728chosen = cm;729}730}731
732bitmap_writer_push_commit(writer, chosen, 0);733
734i += next + 1;735display_progress(writer->progress, i);736}737
738stop_progress(&writer->progress);739
740select_pseudo_merges(writer);741}
742
743
744static int hashwrite_ewah_helper(void *f, const void *buf, size_t len)745{
746/* hashwrite will die on error */747hashwrite(f, buf, len);748return len;749}
750
751/**
752* Write the bitmap index to disk
753*/
754static inline void dump_bitmap(struct hashfile *f, struct ewah_bitmap *bitmap)755{
756if (ewah_serialize_to(bitmap, hashwrite_ewah_helper, f) < 0)757die("Failed to write bitmap index");758}
759
760static const struct object_id *oid_access(size_t pos, const void *table)761{
762const struct pack_idx_entry * const *index = table;763return &index[pos]->oid;764}
765
766static void write_selected_commits_v1(struct bitmap_writer *writer,767struct hashfile *f, off_t *offsets)768{
769int i;770
771for (i = 0; i < bitmap_writer_nr_selected_commits(writer); ++i) {772struct bitmapped_commit *stored = &writer->selected[i];773if (stored->pseudo_merge)774BUG("unexpected pseudo-merge among selected: %s",775oid_to_hex(&stored->commit->object.oid));776
777if (offsets)778offsets[i] = hashfile_total(f);779
780hashwrite_be32(f, stored->commit_pos);781hashwrite_u8(f, stored->xor_offset);782hashwrite_u8(f, stored->flags);783
784dump_bitmap(f, stored->write_as);785}786}
787
788static void write_pseudo_merges(struct bitmap_writer *writer,789struct hashfile *f)790{
791struct oid_array commits = OID_ARRAY_INIT;792struct bitmap **commits_bitmap = NULL;793off_t *pseudo_merge_ofs = NULL;794off_t start, table_start, next_ext;795
796uint32_t base = bitmap_writer_nr_selected_commits(writer);797size_t i, j = 0;798
799CALLOC_ARRAY(commits_bitmap, writer->pseudo_merges_nr);800CALLOC_ARRAY(pseudo_merge_ofs, writer->pseudo_merges_nr);801
802for (i = 0; i < writer->pseudo_merges_nr; i++) {803struct bitmapped_commit *merge = &writer->selected[base + i];804struct commit_list *p;805
806if (!merge->pseudo_merge)807BUG("found non-pseudo merge commit at %"PRIuMAX, (uintmax_t)i);808
809commits_bitmap[i] = bitmap_new();810
811for (p = merge->commit->parents; p; p = p->next)812bitmap_set(commits_bitmap[i],813find_object_pos(writer, &p->item->object.oid,814NULL));815}816
817start = hashfile_total(f);818
819for (i = 0; i < writer->pseudo_merges_nr; i++) {820struct ewah_bitmap *commits_ewah = bitmap_to_ewah(commits_bitmap[i]);821
822pseudo_merge_ofs[i] = hashfile_total(f);823
824dump_bitmap(f, commits_ewah);825dump_bitmap(f, writer->selected[base+i].write_as);826
827ewah_free(commits_ewah);828}829
830next_ext = st_add(hashfile_total(f),831st_mult(kh_size(writer->pseudo_merge_commits),832sizeof(uint64_t)));833
834table_start = hashfile_total(f);835
836commits.alloc = kh_size(writer->pseudo_merge_commits);837CALLOC_ARRAY(commits.oid, commits.alloc);838
839for (i = kh_begin(writer->pseudo_merge_commits); i != kh_end(writer->pseudo_merge_commits); i++) {840if (!kh_exist(writer->pseudo_merge_commits, i))841continue;842oid_array_append(&commits, &kh_key(writer->pseudo_merge_commits, i));843}844
845oid_array_sort(&commits);846
847/* write lookup table (non-extended) */848for (i = 0; i < commits.nr; i++) {849int hash_pos;850struct pseudo_merge_commit_idx *c;851
852hash_pos = kh_get_oid_map(writer->pseudo_merge_commits,853commits.oid[i]);854if (hash_pos == kh_end(writer->pseudo_merge_commits))855BUG("could not find pseudo-merge commit %s",856oid_to_hex(&commits.oid[i]));857
858c = kh_value(writer->pseudo_merge_commits, hash_pos);859
860hashwrite_be32(f, find_object_pos(writer, &commits.oid[i],861NULL));862if (c->nr == 1)863hashwrite_be64(f, pseudo_merge_ofs[c->pseudo_merge[0]]);864else if (c->nr > 1) {865if (next_ext & ((uint64_t)1<<63))866die(_("too many pseudo-merges"));867hashwrite_be64(f, next_ext | ((uint64_t)1<<63));868next_ext = st_add3(next_ext,869sizeof(uint32_t),870st_mult(c->nr, sizeof(uint64_t)));871} else872BUG("expected commit '%s' to have at least one "873"pseudo-merge", oid_to_hex(&commits.oid[i]));874}875
876/* write lookup table (extended) */877for (i = 0; i < commits.nr; i++) {878int hash_pos;879struct pseudo_merge_commit_idx *c;880
881hash_pos = kh_get_oid_map(writer->pseudo_merge_commits,882commits.oid[i]);883if (hash_pos == kh_end(writer->pseudo_merge_commits))884BUG("could not find pseudo-merge commit %s",885oid_to_hex(&commits.oid[i]));886
887c = kh_value(writer->pseudo_merge_commits, hash_pos);888if (c->nr == 1)889continue;890
891hashwrite_be32(f, c->nr);892for (j = 0; j < c->nr; j++)893hashwrite_be64(f, pseudo_merge_ofs[c->pseudo_merge[j]]);894}895
896/* write positions for all pseudo merges */897for (i = 0; i < writer->pseudo_merges_nr; i++)898hashwrite_be64(f, pseudo_merge_ofs[i]);899
900hashwrite_be32(f, writer->pseudo_merges_nr);901hashwrite_be32(f, kh_size(writer->pseudo_merge_commits));902hashwrite_be64(f, table_start - start);903hashwrite_be64(f, hashfile_total(f) - start + sizeof(uint64_t));904
905for (i = 0; i < writer->pseudo_merges_nr; i++)906bitmap_free(commits_bitmap[i]);907
908free(pseudo_merge_ofs);909free(commits_bitmap);910}
911
912static int table_cmp(const void *_va, const void *_vb, void *_data)913{
914struct bitmap_writer *writer = _data;915struct bitmapped_commit *a = &writer->selected[*(uint32_t *)_va];916struct bitmapped_commit *b = &writer->selected[*(uint32_t *)_vb];917
918if (a->commit_pos < b->commit_pos)919return -1;920else if (a->commit_pos > b->commit_pos)921return 1;922
923return 0;924}
925
926static void write_lookup_table(struct bitmap_writer *writer, struct hashfile *f,927off_t *offsets)928{
929uint32_t i;930uint32_t *table, *table_inv;931
932ALLOC_ARRAY(table, bitmap_writer_nr_selected_commits(writer));933ALLOC_ARRAY(table_inv, bitmap_writer_nr_selected_commits(writer));934
935for (i = 0; i < bitmap_writer_nr_selected_commits(writer); i++)936table[i] = i;937
938/*939* At the end of this sort table[j] = i means that the i'th
940* bitmap corresponds to j'th bitmapped commit (among the selected
941* commits) in lex order of OIDs.
942*/
943QSORT_S(table, bitmap_writer_nr_selected_commits(writer), table_cmp, writer);944
945/* table_inv helps us discover that relationship (i'th bitmap946* to j'th commit by j = table_inv[i])
947*/
948for (i = 0; i < bitmap_writer_nr_selected_commits(writer); i++)949table_inv[table[i]] = i;950
951trace2_region_enter("pack-bitmap-write", "writing_lookup_table", the_repository);952for (i = 0; i < bitmap_writer_nr_selected_commits(writer); i++) {953struct bitmapped_commit *selected = &writer->selected[table[i]];954uint32_t xor_offset = selected->xor_offset;955uint32_t xor_row;956
957if (xor_offset) {958/*959* xor_index stores the index (in the bitmap entries)
960* of the corresponding xor bitmap. But we need to convert
961* this index into lookup table's index. So, table_inv[xor_index]
962* gives us the index position w.r.t. the lookup table.
963*
964* If "k = table[i] - xor_offset" then the xor base is the k'th
965* bitmap. `table_inv[k]` gives us the position of that bitmap
966* in the lookup table.
967*/
968uint32_t xor_index = table[i] - xor_offset;969xor_row = table_inv[xor_index];970} else {971xor_row = 0xffffffff;972}973
974hashwrite_be32(f, writer->selected[table[i]].commit_pos);975hashwrite_be64(f, (uint64_t)offsets[table[i]]);976hashwrite_be32(f, xor_row);977}978trace2_region_leave("pack-bitmap-write", "writing_lookup_table", the_repository);979
980free(table);981free(table_inv);982}
983
984static void write_hash_cache(struct hashfile *f,985struct pack_idx_entry **index,986uint32_t index_nr)987{
988uint32_t i;989
990for (i = 0; i < index_nr; ++i) {991struct object_entry *entry = (struct object_entry *)index[i];992hashwrite_be32(f, entry->hash);993}994}
995
996void bitmap_writer_set_checksum(struct bitmap_writer *writer,997const unsigned char *sha1)998{
999hashcpy(writer->pack_checksum, sha1, the_repository->hash_algo);1000}
1001
1002void bitmap_writer_finish(struct bitmap_writer *writer,1003struct pack_idx_entry **index,1004const char *filename,1005uint16_t options)1006{
1007static uint16_t default_version = 1;1008static uint16_t flags = BITMAP_OPT_FULL_DAG;1009struct strbuf tmp_file = STRBUF_INIT;1010struct hashfile *f;1011off_t *offsets = NULL;1012uint32_t i;1013
1014struct bitmap_disk_header header;1015
1016int fd = odb_mkstemp(&tmp_file, "pack/tmp_bitmap_XXXXXX");1017
1018if (writer->pseudo_merges_nr)1019options |= BITMAP_OPT_PSEUDO_MERGES;1020
1021f = hashfd(fd, tmp_file.buf);1022
1023memcpy(header.magic, BITMAP_IDX_SIGNATURE, sizeof(BITMAP_IDX_SIGNATURE));1024header.version = htons(default_version);1025header.options = htons(flags | options);1026header.entry_count = htonl(bitmap_writer_nr_selected_commits(writer));1027hashcpy(header.checksum, writer->pack_checksum, the_repository->hash_algo);1028
1029hashwrite(f, &header, sizeof(header) - GIT_MAX_RAWSZ + the_hash_algo->rawsz);1030dump_bitmap(f, writer->commits);1031dump_bitmap(f, writer->trees);1032dump_bitmap(f, writer->blobs);1033dump_bitmap(f, writer->tags);1034
1035if (options & BITMAP_OPT_LOOKUP_TABLE)1036CALLOC_ARRAY(offsets, writer->to_pack->nr_objects);1037
1038for (i = 0; i < bitmap_writer_nr_selected_commits(writer); i++) {1039struct bitmapped_commit *stored = &writer->selected[i];1040int commit_pos = oid_pos(&stored->commit->object.oid, index,1041writer->to_pack->nr_objects,1042oid_access);1043
1044if (commit_pos < 0)1045BUG(_("trying to write commit not in index"));1046stored->commit_pos = commit_pos;1047}1048
1049write_selected_commits_v1(writer, f, offsets);1050
1051if (options & BITMAP_OPT_PSEUDO_MERGES)1052write_pseudo_merges(writer, f);1053
1054if (options & BITMAP_OPT_LOOKUP_TABLE)1055write_lookup_table(writer, f, offsets);1056
1057if (options & BITMAP_OPT_HASH_CACHE)1058write_hash_cache(f, index, writer->to_pack->nr_objects);1059
1060finalize_hashfile(f, NULL, FSYNC_COMPONENT_PACK_METADATA,1061CSUM_HASH_IN_STREAM | CSUM_FSYNC | CSUM_CLOSE);1062
1063if (adjust_shared_perm(tmp_file.buf))1064die_errno("unable to make temporary bitmap file readable");1065
1066if (rename(tmp_file.buf, filename))1067die_errno("unable to rename temporary bitmap file to '%s'", filename);1068
1069strbuf_release(&tmp_file);1070free(offsets);1071}
1072