@@ -650,20 +650,19 @@ static const struct object_id *oid_access(size_t pos, const void *table)
static void write_selected_commits_v1(struct hashfile *f,
struct pack_idx_entry **index,
- uint32_t index_nr)
+ uint32_t index_nr,
+ off_t *offsets,
+ uint32_t *commit_positions)
{
int i;
for (i = 0; i < writer.selected_nr; ++i) {
struct bitmapped_commit *stored = &writer.selected[i];
- int commit_pos =
- oid_pos(&stored->commit->object.oid, index, index_nr, oid_access);
+ if (offsets)
+ offsets[i] = hashfile_total(f);
- if (commit_pos < 0)
- BUG("trying to write commit not in index");
-
- hashwrite_be32(f, commit_pos);
+ hashwrite_be32(f, commit_positions[i]);
hashwrite_u8(f, stored->xor_offset);
hashwrite_u8(f, stored->flags);
@@ -671,6 +670,81 @@ static void write_selected_commits_v1(struct hashfile *f,
}
}
+static int table_cmp(const void *_va, const void *_vb, void *_data)
+{
+ uint32_t *commit_positions = _data;
+ uint32_t a = commit_positions[*(uint32_t *)_va];
+ uint32_t b = commit_positions[*(uint32_t *)_vb];
+
+ if (a > b)
+ return 1;
+ else if (a < b)
+ return -1;
+
+ return 0;
+}
+
+static void write_lookup_table(struct hashfile *f,
+ struct pack_idx_entry **index,
+ uint32_t index_nr,
+ off_t *offsets,
+ uint32_t *commit_positions)
+{
+ uint32_t i;
+ uint32_t *table, *table_inv;
+
+ ALLOC_ARRAY(table, writer.selected_nr);
+ ALLOC_ARRAY(table_inv, writer.selected_nr);
+
+ for (i = 0; i < writer.selected_nr; i++)
+ table[i] = i;
+
+ /*
+ * At the end of this sort table[j] = i means that the i'th
+ * bitmap corresponds to j'th bitmapped commit (among the selected
+ * commits) in lex order of OIDs.
+ */
+ QSORT_S(table, writer.selected_nr, table_cmp, commit_positions);
+
+ /* table_inv helps us discover that relationship (i'th bitmap
+ * to j'th commit by j = table_inv[i])
+ */
+ for (i = 0; i < writer.selected_nr; i++)
+ table_inv[table[i]] = i;
+
+ trace2_region_enter("pack-bitmap-write", "writing_lookup_table", the_repository);
+ for (i = 0; i < writer.selected_nr; i++) {
+ struct bitmapped_commit *selected = &writer.selected[table[i]];
+ uint32_t xor_offset = selected->xor_offset;
+ uint32_t xor_row;
+
+ if (xor_offset) {
+ /*
+ * xor_index stores the index (in the bitmap entries)
+ * of the corresponding xor bitmap. But we need to convert
+ * this index into lookup table's index. So, table_inv[xor_index]
+ * gives us the index position w.r.t. the lookup table.
+ *
+ * If "k = table[i] - xor_offset" then the xor base is the k'th
+ * bitmap. `table_inv[k]` gives us the position of that bitmap
+ * in the lookup table.
+ */
+ uint32_t xor_index = table[i] - xor_offset;
+ xor_row = table_inv[xor_index];
+ } else {
+ xor_row = 0xffffffff;
+ }
+
+ hashwrite_be32(f, commit_positions[table[i]]);
+ hashwrite_be64(f, (uint64_t)offsets[table[i]]);
+ hashwrite_be32(f, xor_row);
+ }
+ trace2_region_leave("pack-bitmap-write", "writing_lookup_table", the_repository);
+
+ free(table);
+ free(table_inv);
+}
+
static void write_hash_cache(struct hashfile *f,
struct pack_idx_entry **index,
uint32_t index_nr)
@@ -695,8 +769,10 @@ void bitmap_writer_finish(struct pack_idx_entry **index,
{
static uint16_t default_version = 1;
static uint16_t flags = BITMAP_OPT_FULL_DAG;
+ off_t *offsets = NULL;
struct strbuf tmp_file = STRBUF_INIT;
struct hashfile *f;
+ uint32_t *commit_positions = NULL;
struct bitmap_disk_header header;
@@ -715,7 +791,25 @@ void bitmap_writer_finish(struct pack_idx_entry **index,
dump_bitmap(f, writer.trees);
dump_bitmap(f, writer.blobs);
dump_bitmap(f, writer.tags);
- write_selected_commits_v1(f, index, index_nr);
+
+ ALLOC_ARRAY(commit_positions, writer.selected_nr);
+ for (uint32_t i = 0; i < writer.selected_nr; ++i) {
+ struct bitmapped_commit *stored = &writer.selected[i];
+ int commit_pos = oid_pos(&stored->commit->object.oid, index, index_nr, oid_access);
+
+ if (commit_pos < 0)
+ BUG(_("trying to write commit not in index"));
+
+ commit_positions[i] = commit_pos;
+ }
+
+ if (options & BITMAP_OPT_LOOKUP_TABLE)
+ CALLOC_ARRAY(offsets, index_nr);
+
+ write_selected_commits_v1(f, index, index_nr, offsets, commit_positions);
+
+ if (options & BITMAP_OPT_LOOKUP_TABLE)
+ write_lookup_table(f, index, index_nr, offsets, commit_positions);
if (options & BITMAP_OPT_HASH_CACHE)
write_hash_cache(f, index, index_nr);
@@ -730,4 +824,6 @@ void bitmap_writer_finish(struct pack_idx_entry **index,
die_errno("unable to rename temporary bitmap file to '%s'", filename);
strbuf_release(&tmp_file);
+ free(offsets);
+ free(commit_positions);
}
@@ -24,8 +24,9 @@ struct bitmap_disk_header {
#define NEEDS_BITMAP (1u<<22)
enum pack_bitmap_opts {
- BITMAP_OPT_FULL_DAG = 1,
- BITMAP_OPT_HASH_CACHE = 4,
+ BITMAP_OPT_FULL_DAG = 0x1,
+ BITMAP_OPT_HASH_CACHE = 0x4,
+ BITMAP_OPT_LOOKUP_TABLE = 0x10,
};
enum pack_bitmap_flags {