git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v3 00/30] pack-bitmap: pseudo-merge reachability bitmaps

From
Taylor Blau <me@ttaylorr.com>
Date
May 21, 2024, 19:01 UTC
Message-ID
<cover.1716318088.git.me@ttaylorr.com>
In-Reply-To
<cover.1710972293.git.me@ttaylorr.com>
Here is another reroll my topic to introduce pseudo-merge bitmaps.

The implementation is relatively unchanged compared to last time, save for the review that Patrick provided on the first half or so of this series.

The notable change from last time is a significant reorganization of the documentation, description, motivation, and examples around what pseudo-merge bitmaps are why you might want to use them. I took Peff's suggestion to create a new gitpacking(7) manual page which I hope will eventually grow to cover many of the more advanced concepts related to packing objects [^1].

The other change is that this series is now based on 'tb/pack-bitmap-write-cleanups'.

Otherwise, a range-diff is included below for convenience. Thanks in advance for your review!

[^1]: At present, the new manual page is rather bare :-). I want to
  separate the task of collecting all of the existing documentation
  around advanced packing concepts from pseudo-merge bitmaps and not add
  a new dependency here.
Taylor Blau (30):
  object.h: add flags allocated by pack-bitmap.h
  pack-bitmap-write.c: move commit_positions into commit_pos fields
  pack-bitmap: avoid use of static `bitmap_writer`
  pack-bitmap: drop unused `max_bitmaps` parameter
  pack-bitmap-write.c: avoid uninitialized 'write_as' field
  pack-bitmap: introduce `bitmap_writer_free()`
  Documentation/gitpacking.txt: initial commit
  Documentation/gitpacking.txt: describe pseudo-merge bitmaps
  Documentation/technical: describe pseudo-merge bitmaps format
  ewah: implement `ewah_bitmap_is_subset()`
  pack-bitmap: move some initialization to `bitmap_writer_init()`
  pseudo-merge.ch: initial commit
  pack-bitmap-write: support storing pseudo-merge commits
  pack-bitmap: implement `bitmap_writer_has_bitmapped_object_id()`
  pack-bitmap: make `bitmap_writer_push_bitmapped_commit()` public
  config: introduce git_config_float()
  pseudo-merge: implement support for selecting pseudo-merge commits
  pack-bitmap-write.c: write pseudo-merge table
  pack-bitmap: extract `read_bitmap()` function
  pseudo-merge: scaffolding for reads
  pack-bitmap.c: read pseudo-merge extension
  pseudo-merge: implement support for reading pseudo-merge commits
  ewah: implement `ewah_bitmap_popcount()`
  pack-bitmap: implement test helpers for pseudo-merge
  t/test-lib-functions.sh: support `--date` in `test_commit_bulk()`
  pack-bitmap.c: use pseudo-merges during traversal
  pack-bitmap: extra trace2 information
  ewah: `bitmap_equals_ewah()`
  pseudo-merge: implement support for finding existing merges
  t/perf: implement performace tests for pseudo-merge bitmaps
 Documentation/Makefile                       |   1 +
 Documentation/config.txt                     |   2 +
 Documentation/config/bitmap-pseudo-merge.txt |  90 +++
 Documentation/gitpacking.txt                 | 186 +++++
 Documentation/technical/bitmap-format.txt    | 132 ++++
 Makefile                                     |   1 +
 builtin/pack-objects.c                       |  20 +-
 config.c                                     |   9 +
 config.h                                     |   6 +
 ewah/bitmap.c                                |  76 ++
 ewah/ewok.h                                  |   8 +
 midx-write.c                                 |  17 +-
 object.h                                     |   1 +
 pack-bitmap-write.c                          | 488 ++++++++----
 pack-bitmap.c                                | 359 ++++++++-
 pack-bitmap.h                                |  55 +-
 parse.c                                      |  29 +
 parse.h                                      |   1 +
 pseudo-merge.c                               | 752 +++++++++++++++++++
 pseudo-merge.h                               | 216 ++++++
 t/helper/test-bitmap.c                       |  34 +-
 t/perf/p5333-pseudo-merge-bitmaps.sh         |  32 +
 t/t5333-pseudo-merge-bitmaps.sh              | 387 ++++++++++
 t/test-lib-functions.sh                      |  12 +-
 24 files changed, 2742 insertions(+), 172 deletions(-)
 create mode 100644 Documentation/config/bitmap-pseudo-merge.txt
 create mode 100644 Documentation/gitpacking.txt
 create mode 100644 pseudo-merge.c
 create mode 100644 pseudo-merge.h
 create mode 100755 t/perf/p5333-pseudo-merge-bitmaps.sh
 create mode 100755 t/t5333-pseudo-merge-bitmaps.sh
Range-diff against v2:
 -:  ----------- >  1:  38c96fc1909 object.h: add flags allocated by pack-bitmap.h
 -:  ----------- >  2:  cbedff02ed1 pack-bitmap-write.c: move commit_positions into commit_pos fields
 -:  ----------- >  3:  65ee69acfeb pack-bitmap: avoid use of static `bitmap_writer`
 -:  ----------- >  4:  b38dd5464d5 pack-bitmap: drop unused `max_bitmaps` parameter
 -:  ----------- >  5:  f16175295f5 pack-bitmap-write.c: avoid uninitialized 'write_as' field
 -:  ----------- >  6:  bf65967764f pack-bitmap: introduce `bitmap_writer_free()`
 -:  ----------- >  7:  0f20c9becf4 Documentation/gitpacking.txt: initial commit
 -:  ----------- >  8:  528b591bd84 Documentation/gitpacking.txt: describe pseudo-merge bitmaps
 1:  43fd5e35971 !  9:  12f318b3d7e Documentation/technical: describe pseudo-merge bitmaps format
    @@ Commit message
         format, making it compatible with previous versions of Git, as well as
         the original .bitmap implementation within JGit.
     
    -    The format (as well as a general description of pseudo-merge bitmaps,
    -    and motivating use-case(s)) is described in detail in the patch contents
    -    below, but the high-level description is as follows:
    +    The format is described in detail in the patch contents below, but the
    +    high-level description is as follows:
     
           - An array of pseudo-merge bitmaps, each containing a pair of EWAH
             bitmaps: one describing the set of pseudo-merge "parents", and
    @@ Documentation/technical/bitmap-format.txt: triplet is -
     +bytes (preceding the name-hash cache, commit lookup table, and trailing
     +checksum) of the `.bitmap` file is used to store pseudo-merge bitmaps.
     +
    -+A "pseudo-merge bitmap" is used to refer to a pair of bitmaps, as
    -+follows:
    -+
    -+Commit bitmap::
    -+
    -+  A bitmap whose set bits describe the set of commits included in the
    -+  pseudo-merge's "merge" bitmap (as below).
    -+
    -+Merge bitmap::
    -+
    -+  A bitmap whose set bits describe the reachability closure over the set
    -+  of commits in the pseudo-merge's "commits" bitmap (as above). An
    -+  identical bitmap would be generated for an octopus merge with the same
    -+  set of parents as described in the commits bitmap.
    -+
    -+Pseudo-merge bitmaps can accelerate bitmap traversals when all commits
    -+for a given pseudo-merge are listed on either side of the traversal,
    -+either directly (by explicitly asking for them as part of the `HAVES`
    -+or `WANTS`) or indirectly (by encountering them during a fill-in
    -+traversal).
    -+
    -+=== Use-cases
    -+
    -+For example, suppose there exists a pseudo-merge bitmap with a large
    -+number of commits, all of which are listed in the `WANTS` section of
    -+some bitmap traversal query. When pseudo-merge bitmaps are enabled, the
    -+bitmap machinery can quickly determine there is a pseudo-merge which
    -+satisfies some subset of the wanted objects on either side of the query.
    -+Then, we can inflate the EWAH-compressed bitmap, and `OR` it in to the
    -+resulting bitmap. By contrast, without pseudo-merge bitmaps, we would
    -+have to repeat the decompression and `OR`-ing step over a potentially
    -+large number of individual bitmaps, which can take proportionally more
    -+time.
    -+
    -+Another benefit of pseudo-merges arises when there is some combination
    -+of (a) a large number of references, with (b) poor bitmap coverage, and
    -+(c) deep, nested trees, making fill-in traversal relatively expensive.
    -+For example, suppose that there are a large enough number of tags where
    -+bitmapping each of the tags individually is infeasible. Without
    -+pseudo-merge bitmaps, computing the result of, say, `git rev-list
    -+--use-bitmap-index --count --objects --tags` would likely require a
    -+large amount of fill-in traversal. But when a large quantity of those
    -+tags are stored together in a pseudo-merge bitmap, the bitmap machinery
    -+can take advantage of the fact that we only care about the union of
    -+objects reachable from all of those tags, and answer the query much
    -+faster.
    ++For more information on what pseudo-merges are, why they are useful, and
    ++how to configure them, see the information in linkgit:gitpacking[7].
     +
     +=== File format
     +
    @@ Documentation/technical/bitmap-format.txt: triplet is -
     ++-------------------------------------------+
     +|                                           |
     +|  Lookup Table                             |
    -+|  +------------+--------------+            |
    -+|  | commit_pos |    offset    |            |
    -+|  +------------+--------------+            |
    -+|  |  4 bytes   |   8 bytes    |            |
    ++|  +---------------------------+            |
    ++|  | commit_pos (4 bytes)      |            |
    ++|  +---------------------------+            |
    ++|  | offset (8 bytes)          |            |
     +|  +------------+--------------+            |
     +|                                           |
     +|  Offset Cases:                            |
    @@ Documentation/technical/bitmap-format.txt: triplet is -
     ++-------------------------------------------+
     +|                                           |
     +|  Extended Lookup Table (Optional)         |
    -+|                                           |
     +|  +----+----------+----------+----------+  |
     +|  | N  | Offset 1 |   ....   | Offset N |  |
     +|  +----+----------+----------+----------+  |
    @@ Documentation/technical/bitmap-format.txt: triplet is -
     ++-------------------------------------------+
     +|                                           |
     +|  Pseudo-merge Metadata                    |
    -+|  +------------------+----------------+    |
    -+|  | # pseudo-merges  | # Commits      |    |
    -+|  +------------------+----------------+    |
    -+|  | 4 bytes          | 4 bytes        |    |
    -+|  +------------------+----------------+    |
    -+|                                           |
    -+|  +------------------+----------------+    |
    -+|  | Lookup offset    | Extension size |    |
    -+|  +------------------+----------------+    |
    -+|  | 8 bytes          | 8 bytes        |    |
    -+|  +------------------+----------------+    |
    ++|  +-----------------------------------+    |
    ++|  | # pseudo-merges (4 bytes)         |    |
    ++|  +-----------------------------------+    |
    ++|  | # commits (4 bytes)               |    |
    ++|  +-----------------------------------+    |
    ++|  | Lookup offset (8 bytes)           |    |
    ++|  +-----------------------------------+    |
    ++|  | Extension size (8 bytes)          |    |
    ++|  +-----------------------------------+    |
     +|                                           |
     ++-------------------------------------------+
     +....
    @@ Documentation/technical/bitmap-format.txt: triplet is -
     +
     +* Positions for all pseudo-merges, each stored as an 8-byte unsigned
     +  value (in network byte-order) containing the offset (relative to the
    -+  beginnign of the `.bitmap` file) of each consecutive pseudo-merge.
    ++  beginning of the `.bitmap` file) of each consecutive pseudo-merge.
     +
     +* A 4-byte unsigned value (in network byte-order) equal to the number of
     +  pseudo-merges.
 2:  290d928325d = 10:  40eb6137618 ewah: implement `ewah_bitmap_is_subset()`
 3:  5160859f7f3 <  -:  ----------- pack-bitmap: drop unused `max_bitmaps` parameter
 4:  3d7d930b1c5 <  -:  ----------- pack-bitmap: move some initialization to `bitmap_writer_init()`
 -:  ----------- > 11:  487fb7c6e9c pack-bitmap: move some initialization to `bitmap_writer_init()`
 5:  e7a87cf7d4e = 12:  827732acf99 pseudo-merge.ch: initial commit
 6:  ee33a703245 ! 13:  8608dd1860f pack-bitmap-write: support storing pseudo-merge commits
    @@ Commit message
     
         Signed-off-by: Taylor Blau <me@ttaylorr.com>
     
    + ## object.h ##
    +@@ object.h: void object_array_init(struct object_array *array);
    +  * reflog.c:                           10--12
    +  * builtin/show-branch.c:    0-------------------------------------------26
    +  * builtin/unpack-objects.c:                                 2021
    +- * pack-bitmap.h:                                                22
    ++ * pack-bitmap.h:                                              2122
    +  */
    + #define FLAG_BITS  28
    + 
    +
      ## pack-bitmap-write.c ##
     @@ pack-bitmap-write.c: struct bitmapped_commit {
    - 	struct ewah_bitmap *write_as;
      	int flags;
      	int xor_offset;
    --	uint32_t commit_pos;
    + 	uint32_t commit_pos;
     +	unsigned pseudo_merge : 1;
      };
      
    - struct bitmap_writer {
    -@@ pack-bitmap-write.c: struct bitmap_writer {
    - 	struct bitmapped_commit *selected;
    - 	unsigned int selected_nr, selected_alloc;
    - 
    -+	uint32_t pseudo_merges_nr;
    -+
    - 	struct progress *progress;
    - 	int show_progress;
    - 	unsigned char pack_checksum[GIT_MAX_RAWSZ];
    -@@ pack-bitmap-write.c: struct bitmap_writer {
    - 
    - static struct bitmap_writer writer;
    - 
    -+static inline int bitmap_writer_selected_nr(void)
    ++static inline int bitmap_writer_nr_selected_commits(struct bitmap_writer *writer)
     +{
    -+	return writer.selected_nr - writer.pseudo_merges_nr;
    ++	return writer->selected_nr - writer->pseudo_merges_nr;
     +}
     +
    - void bitmap_writer_init(struct repository *r)
    + void bitmap_writer_init(struct bitmap_writer *writer, struct repository *r)
      {
    - 	writer.bitmaps = kh_init_oid_map();
    -@@ pack-bitmap-write.c: void bitmap_writer_build_type_index(struct packing_data *to_pack,
    -  * Compute the actual bitmaps
    + 	memset(writer, 0, sizeof(struct bitmap_writer));
    +@@ pack-bitmap-write.c: void bitmap_writer_build_type_index(struct bitmap_writer *writer,
       */
      
    --static inline void push_bitmapped_commit(struct commit *commit)
    -+static void bitmap_writer_push_bitmapped_commit(struct commit *commit,
    -+						unsigned pseudo_merge)
    + static inline void push_bitmapped_commit(struct bitmap_writer *writer,
    +-					 struct commit *commit)
    ++					 struct commit *commit,
    ++					 unsigned pseudo_merge)
      {
     -	int hash_ret;
     -	khiter_t hash_pos;
     -
    - 	if (writer.selected_nr >= writer.selected_alloc) {
    - 		writer.selected_alloc = (writer.selected_alloc + 32) * 2;
    - 		REALLOC_ARRAY(writer.selected, writer.selected_alloc);
    + 	if (writer->selected_nr >= writer->selected_alloc) {
    + 		writer->selected_alloc = (writer->selected_alloc + 32) * 2;
    + 		REALLOC_ARRAY(writer->selected, writer->selected_alloc);
      	}
      
    --	hash_pos = kh_put_oid_map(writer.bitmaps, commit->object.oid, &hash_ret);
    +-	hash_pos = kh_put_oid_map(writer->bitmaps, commit->object.oid,
    +-				  &hash_ret);
     -	if (!hash_ret)
     -		die(_("duplicate entry when writing bitmap index: %s"),
     -		    oid_to_hex(&commit->object.oid));
    --	kh_value(writer.bitmaps, hash_pos) = NULL;
    +-	kh_value(writer->bitmaps, hash_pos) = NULL;
     +	if (!pseudo_merge) {
     +		int hash_ret;
    -+		khiter_t hash_pos = kh_put_oid_map(writer.bitmaps,
    ++		khiter_t hash_pos = kh_put_oid_map(writer->bitmaps,
     +						   commit->object.oid,
     +						   &hash_ret);
     +
     +		if (!hash_ret)
     +			die(_("duplicate entry when writing bitmap index: %s"),
     +			    oid_to_hex(&commit->object.oid));
    -+		kh_value(writer.bitmaps, hash_pos) = NULL;
    ++		kh_value(writer->bitmaps, hash_pos) = NULL;
     +	}
      
    - 	writer.selected[writer.selected_nr].commit = commit;
    - 	writer.selected[writer.selected_nr].bitmap = NULL;
    - 	writer.selected[writer.selected_nr].flags = 0;
    -+	writer.selected[writer.selected_nr].pseudo_merge = pseudo_merge;
    + 	writer->selected[writer->selected_nr].commit = commit;
    + 	writer->selected[writer->selected_nr].bitmap = NULL;
    + 	writer->selected[writer->selected_nr].write_as = NULL;
    + 	writer->selected[writer->selected_nr].flags = 0;
    ++	writer->selected[writer->selected_nr].pseudo_merge = pseudo_merge;
      
    - 	writer.selected_nr++;
    + 	writer->selected_nr++;
      }
    -@@ pack-bitmap-write.c: static void compute_xor_offsets(void)
    +@@ pack-bitmap-write.c: static void compute_xor_offsets(struct bitmap_writer *writer)
      
    - 	while (next < writer.selected_nr) {
    - 		struct bitmapped_commit *stored = &writer.selected[next];
    + 	while (next < writer->selected_nr) {
    + 		struct bitmapped_commit *stored = &writer->selected[next];
     -
      		int best_offset = 0;
      		struct ewah_bitmap *best_bitmap = stored->bitmap;
    @@ pack-bitmap-write.c: static void compute_xor_offsets(void)
      
      			if (curr < 0)
      				break;
    -+			if (writer.selected[curr].pseudo_merge)
    ++			if (writer->selected[curr].pseudo_merge)
     +				continue;
      
      			test_xor = ewah_pool_new();
    - 			ewah_xor(writer.selected[curr].bitmap, stored->bitmap, test_xor);
    -@@ pack-bitmap-write.c: static void compute_xor_offsets(void)
    + 			ewah_xor(writer->selected[curr].bitmap, stored->bitmap, test_xor);
    +@@ pack-bitmap-write.c: static void compute_xor_offsets(struct bitmap_writer *writer)
      			}
      		}
      
    @@ pack-bitmap-write.c: static void bitmap_builder_init(struct bitmap_builder *bb,
      	}
      
      	if (prepare_revision_walk(&revs))
    -@@ pack-bitmap-write.c: static int fill_bitmap_commit(struct bb_commit *ent,
    +@@ pack-bitmap-write.c: static int fill_bitmap_commit(struct bitmap_writer *writer,
      		struct commit *c = prio_queue_get(queue);
      
      		if (old_bitmap && mapping) {
    @@ pack-bitmap-write.c: static int fill_bitmap_commit(struct bb_commit *ent,
      			/*
      			 * If this commit has an old bitmap, then translate that
      			 * bitmap and add its bits to this one. No need to walk
    -@@ pack-bitmap-write.c: static int fill_bitmap_commit(struct bb_commit *ent,
    +@@ pack-bitmap-write.c: static int fill_bitmap_commit(struct bitmap_writer *writer,
      		 * Mark ourselves and queue our tree. The commit
      		 * walk ensures we cover all parents.
      		 */
    --		pos = find_object_pos(&c->object.oid, &found);
    +-		pos = find_object_pos(writer, &c->object.oid, &found);
     -		if (!found)
     -			return -1;
     -		bitmap_set(ent->bitmap, pos);
     -		prio_queue_put(tree_queue,
     -			       repo_get_commit_tree(the_repository, c));
     +		if (!(c->object.flags & BITMAP_PSEUDO_MERGE)) {
    -+			pos = find_object_pos(&c->object.oid, &found);
    ++			pos = find_object_pos(writer, &c->object.oid, &found);
     +			if (!found)
     +				return -1;
     +			bitmap_set(ent->bitmap, pos);
    @@ pack-bitmap-write.c: static int fill_bitmap_commit(struct bb_commit *ent,
     +		}
      
      		for (p = c->parents; p; p = p->next) {
    - 			pos = find_object_pos(&p->item->object.oid, &found);
    -@@ pack-bitmap-write.c: static void store_selected(struct bb_commit *ent, struct commit *commit)
    + 			pos = find_object_pos(writer, &p->item->object.oid,
    +@@ pack-bitmap-write.c: static void store_selected(struct bitmap_writer *writer,
      
      	stored->bitmap = bitmap_to_ewah(ent->bitmap);
      
     +	if (ent->pseudo_merge)
     +		return;
     +
    - 	hash_pos = kh_get_oid_map(writer.bitmaps, commit->object.oid);
    - 	if (hash_pos == kh_end(writer.bitmaps))
    + 	hash_pos = kh_get_oid_map(writer->bitmaps, commit->object.oid);
    + 	if (hash_pos == kh_end(writer->bitmaps))
      		die(_("attempted to store non-selected commit: '%s'"),
    -@@ pack-bitmap-write.c: void bitmap_writer_select_commits(struct commit **indexed_commits,
    +@@ pack-bitmap-write.c: void bitmap_writer_select_commits(struct bitmap_writer *writer,
      
      	if (indexed_commits_nr < 100) {
      		for (i = 0; i < indexed_commits_nr; ++i)
    --			push_bitmapped_commit(indexed_commits[i]);
    -+			bitmap_writer_push_bitmapped_commit(indexed_commits[i], 0);
    +-			push_bitmapped_commit(writer, indexed_commits[i]);
    ++			push_bitmapped_commit(writer, indexed_commits[i], 0);
      		return;
      	}
      
    -@@ pack-bitmap-write.c: void bitmap_writer_select_commits(struct commit **indexed_commits,
    +@@ pack-bitmap-write.c: void bitmap_writer_select_commits(struct bitmap_writer *writer,
      			}
      		}
      
    --		push_bitmapped_commit(chosen);
    -+		bitmap_writer_push_bitmapped_commit(chosen, 0);
    +-		push_bitmapped_commit(writer, chosen);
    ++		push_bitmapped_commit(writer, chosen, 0);
      
      		i += next + 1;
    - 		display_progress(writer.progress, i);
    -@@ pack-bitmap-write.c: static void write_selected_commits_v1(struct hashfile *f,
    + 		display_progress(writer->progress, i);
    +@@ pack-bitmap-write.c: static void write_selected_commits_v1(struct bitmap_writer *writer,
      {
      	int i;
      
    --	for (i = 0; i < writer.selected_nr; ++i) {
    -+	for (i = 0; i < bitmap_writer_selected_nr(); ++i) {
    - 		struct bitmapped_commit *stored = &writer.selected[i];
    +-	for (i = 0; i < writer->selected_nr; ++i) {
    ++	for (i = 0; i < bitmap_writer_nr_selected_commits(writer); ++i) {
    + 		struct bitmapped_commit *stored = &writer->selected[i];
     +		if (stored->pseudo_merge)
     +			BUG("unexpected pseudo-merge among selected: %s",
     +			    oid_to_hex(&stored->commit->object.oid));
      
      		if (offsets)
      			offsets[i] = hashfile_total(f);
    -@@ pack-bitmap-write.c: static void write_lookup_table(struct hashfile *f,
    +@@ pack-bitmap-write.c: static void write_lookup_table(struct bitmap_writer *writer, struct hashfile *f,
      	uint32_t i;
      	uint32_t *table, *table_inv;
      
    --	ALLOC_ARRAY(table, writer.selected_nr);
    --	ALLOC_ARRAY(table_inv, writer.selected_nr);
    -+	ALLOC_ARRAY(table, bitmap_writer_selected_nr());
    -+	ALLOC_ARRAY(table_inv, bitmap_writer_selected_nr());
    +-	ALLOC_ARRAY(table, writer->selected_nr);
    +-	ALLOC_ARRAY(table_inv, writer->selected_nr);
    ++	ALLOC_ARRAY(table, bitmap_writer_nr_selected_commits(writer));
    ++	ALLOC_ARRAY(table_inv, bitmap_writer_nr_selected_commits(writer));
      
    --	for (i = 0; i < writer.selected_nr; i++)
    -+	for (i = 0; i < bitmap_writer_selected_nr(); i++)
    +-	for (i = 0; i < writer->selected_nr; i++)
    ++	for (i = 0; i < bitmap_writer_nr_selected_commits(writer); i++)
      		table[i] = i;
      
      	/*
    -@@ pack-bitmap-write.c: static void write_lookup_table(struct hashfile *f,
    +@@ pack-bitmap-write.c: static void write_lookup_table(struct bitmap_writer *writer, struct hashfile *f,
      	 * 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);
    -+	QSORT_S(table, bitmap_writer_selected_nr(), table_cmp, commit_positions);
    +-	QSORT_S(table, writer->selected_nr, table_cmp, writer);
    ++	QSORT_S(table, bitmap_writer_nr_selected_commits(writer), table_cmp, writer);
      
      	/* 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++)
    -+	for (i = 0; i < bitmap_writer_selected_nr(); i++)
    +-	for (i = 0; i < writer->selected_nr; i++)
    ++	for (i = 0; i < bitmap_writer_nr_selected_commits(writer); 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++) {
    -+	for (i = 0; i < bitmap_writer_selected_nr(); i++) {
    - 		struct bitmapped_commit *selected = &writer.selected[table[i]];
    +-	for (i = 0; i < writer->selected_nr; i++) {
    ++	for (i = 0; i < bitmap_writer_nr_selected_commits(writer); i++) {
    + 		struct bitmapped_commit *selected = &writer->selected[table[i]];
      		uint32_t xor_offset = selected->xor_offset;
      		uint32_t xor_row;
    -@@ pack-bitmap-write.c: void bitmap_writer_finish(struct pack_idx_entry **index,
    +@@ pack-bitmap-write.c: void bitmap_writer_finish(struct bitmap_writer *writer,
      	memcpy(header.magic, BITMAP_IDX_SIGNATURE, sizeof(BITMAP_IDX_SIGNATURE));
      	header.version = htons(default_version);
      	header.options = htons(flags | options);
    --	header.entry_count = htonl(writer.selected_nr);
    -+	header.entry_count = htonl(bitmap_writer_selected_nr());
    - 	hashcpy(header.checksum, writer.pack_checksum);
    +-	header.entry_count = htonl(writer->selected_nr);
    ++	header.entry_count = htonl(bitmap_writer_nr_selected_commits(writer));
    + 	hashcpy(header.checksum, writer->pack_checksum);
      
      	hashwrite(f, &header, sizeof(header) - GIT_MAX_RAWSZ + the_hash_algo->rawsz);
    -@@ pack-bitmap-write.c: void bitmap_writer_finish(struct pack_idx_entry **index,
    +@@ pack-bitmap-write.c: void bitmap_writer_finish(struct bitmap_writer *writer,
      	if (options & BITMAP_OPT_LOOKUP_TABLE)
      		CALLOC_ARRAY(offsets, index_nr);
      
    --	ALLOC_ARRAY(commit_positions, writer.selected_nr);
    -+	ALLOC_ARRAY(commit_positions, bitmap_writer_selected_nr());
    - 
    --	for (i = 0; i < writer.selected_nr; i++) {
    -+	for (i = 0; i < bitmap_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);
    - 
    +-	for (i = 0; i < writer->selected_nr; i++) {
    ++	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,
    + 					 index_nr, oid_access);
     
      ## pack-bitmap.h ##
     @@ pack-bitmap.h: struct bitmap_disk_header {
    @@ pack-bitmap.h: struct bitmap_disk_header {
      #define NEEDS_BITMAP (1u<<22)
      
      /*
    +@@ pack-bitmap.h: struct bitmap_writer {
    + 	struct bitmapped_commit *selected;
    + 	unsigned int selected_nr, selected_alloc;
    + 
    ++	uint32_t pseudo_merges_nr;
    ++
    + 	struct progress *progress;
    + 	int show_progress;
    + 	unsigned char pack_checksum[GIT_MAX_RAWSZ];
 7:  9c6d09bf874 <  -:  ----------- pack-bitmap: implement `bitmap_writer_has_bitmapped_object_id()`
 8:  dfd4b73d12e <  -:  ----------- pack-bitmap: make `bitmap_writer_push_bitmapped_commit()` public
 -:  ----------- > 14:  99d2b6872ba pack-bitmap: implement `bitmap_writer_has_bitmapped_object_id()`
 -:  ----------- > 15:  e7209c60fa5 pack-bitmap: make `bitmap_writer_push_bitmapped_commit()` public
 -:  ----------- > 16:  3070135eb4b config: introduce git_config_float()
 9:  86a1e4b8b9b ! 17:  3029473c094 pseudo-merge: implement support for selecting pseudo-merge commits
    @@ Commit message
         for inclusion in different pseudo-merge group(s) based on a handful of
         criteria.
     
    -    Pseudo-merges are derived first from named pseudo-merge groups (see the
    -    `bitmapPseudoMerge.<name>.*` configuration options). They are
    -    (optionally) further segmented within an individual pseudo-merge group
    -    based on any capture group(s) within the pseudo-merge group's pattern.
    -
    -    For example, a configuration like so:
    -
    -        [bitmapPseudoMerge "all"]
    -            pattern = "refs/"
    -            threshold = now
    -            stableThreshold = never
    -            sampleRate = 100
    -            maxMerges = 64
    -
    -    would group all non-bitmapped commits into up to 64 individual
    -    pseudo-merge commits.
    -
    -    If you wanted to separate tags from branches when generating
    -    pseudo-merge commits, and further segment them by which fork they
    -    originate from (using the same "refs/virtual/" scheme as in the delta
    -    islands documentation), you would instead write something like:
    -
    -        [bitmapPseudoMerge "all"]
    -            pattern = "refs/virtual/([0-9]+)/(heads|tags)/"
    -            threshold = now
    -            stableThreshold = never
    -            sampleRate = 100
    -            maxMerges = 64
    -
    -    Which would generate pseudo-merge group identifiers like "1234-heads",
    -    and "5678-tags" (for branches in fork "1234", and tags in remote "5678",
    -    respectively).
    -
    -    Within pseudo-merge groups, there are a handful of other options used to
    -    control the distribution of matching commits among individual
    -    pseudo-merge commits:
    -
    -      - bitmapPseudoMerge.<name>.decay
    -      - bitmapPseudoMerge.<name>.sampleRate
    -      - bitmapPseudoMerge.<name>.threshold
    -      - bitmapPseudoMerge.<name>.maxMerges
    -      - bitmapPseudoMerge.<name>.stableThreshold
    -      - bitmapPseudoMerge.<name>.stableSize
    -
    -    The decay parameter roughly corresponds to "k" in `f(n) = C*n^(-k/100)`,
    -    where `f(n)` describes the size of the `n`-th pseudo-merge group. The
    -    sample rate controls what percentage of eligible commits are considered
    -    as candidates. The threshold parameter indicates the minimum age (so as
    -    to avoid including too-recent commits in a pseudo-merge group, making it
    -    less likely to be valid). The "maxMerges" parameter sets an upper-bound
    -    on the number of pseudo-merge commits an individual group
    -
    -    The latter two "stable"-related parameters control "stable" pseudo-merge
    -    groups, comprised of a fixed number of commits which are older than the
    -    configured "stable threshold" value and may be grouped together in
    -    chunks of "stableSize" in order of age.
    -
    -    This patch implements the aforementioned selection routine, as well as
    -    parsing the relevant configuration options.
    +    Note that the selected pseudo-merge commits aren't actually used or
    +    written anywhere yet. This will be done in the following commit.
     
         Signed-off-by: Taylor Blau <me@ttaylorr.com>
     
    + ## Documentation/config.txt ##
    +@@ Documentation/config.txt: include::config/apply.txt[]
    + 
    + include::config/attr.txt[]
    + 
    ++include::config/bitmap-pseudo-merge.txt[]
    ++
    + include::config/blame.txt[]
    + 
    + include::config/branch.txt[]
    +
    + ## Documentation/config/bitmap-pseudo-merge.txt (new) ##
    +@@
    ++NOTE: The configuration options in `bitmapPseudoMerge.*` are considered
    ++EXPERIMENTAL and may be subject to change or be removed entirely in the
    ++future.
    ++
    ++bitmapPseudoMerge.<name>.pattern::
    ++	Regular expression used to match reference names. Commits
    ++	pointed to by references matching this pattern (and meeting
    ++	the below criteria, like `bitmapPseudoMerge.<name>.sampleRate`
    ++	and `bitmapPseudoMerge.<name>.threshold`) will be considered
    ++	for inclusion in a pseudo-merge bitmap.
    +++
    ++Commits are grouped into pseudo-merge groups based on whether or not
    ++any reference(s) that point at a given commit match the pattern, which
    ++is an extended regular expression.
    +++
    ++Within a pseudo-merge group, commits may be further grouped into
    ++sub-groups based on the capture groups in the pattern. These
    ++sub-groupings are formed from the regular expressions by concatenating
    ++any capture groups from the regular expression, with a '-' dash in
    ++between.
    +++
    ++For example, if the pattern is `refs/tags/`, then all tags (provided
    ++they meet the below criteria) will be considered candidates for the
    ++same pseudo-merge group. However, if the pattern is instead
    ++`refs/remotes/([0-9])+/tags/`, then tags from different remotes will
    ++be grouped into separate pseudo-merge groups, based on the remote
    ++number.
    ++
    ++bitmapPseudoMerge.<name>.decay::
    ++	Determines the rate at which consecutive pseudo-merge bitmap
    ++	groups decrease in size. Must be non-negative. This parameter
    ++	can be thought of as `k` in the function `f(n) = C * n^-k`,
    ++	where `f(n)` is the size of the `n`th group.
    +++
    ++Setting the decay rate equal to `0` will cause all groups to be the
    ++same size. Setting the decay rate equal to `1` will cause the `n`th
    ++group to be `1/n` the size of the initial group.  Higher values of the
    ++decay rate cause consecutive groups to shrink at an increasing rate.
    ++The default is `1`.
    +++
    ++If all groups are the same size, it is possible that groups containing
    ++newer commits will be able to be used less often than earlier groups,
    ++since it is more likely that the references pointing at newer commits
    ++will be updated more often than a reference pointing at an old commit.
    ++
    ++bitmapPseudoMerge.<name>.sampleRate::
    ++	Determines the proportion of non-bitmapped commits (among
    ++	reference tips) which are selected for inclusion in an
    ++	unstable pseudo-merge bitmap. Must be between `0` and `1`
    ++	(inclusive). The default is `1`.
    ++
    ++bitmapPseudoMerge.<name>.threshold::
    ++	Determines the minimum age of non-bitmapped commits (among
    ++	reference tips, as above) which are candidates for inclusion
    ++	in an unstable pseudo-merge bitmap. The default is
    ++	`1.week.ago`.
    ++
    ++bitmapPseudoMerge.<name>.maxMerges::
    ++	Determines the maximum number of pseudo-merge commits among
    ++	which commits may be distributed.
    +++
    ++For pseudo-merge groups whose pattern does not contain any capture
    ++groups, this setting is applied for all commits matching the regular
    ++expression. For patterns that have one or more capture groups, this
    ++setting is applied for each distinct capture group.
    +++
    ++For example, if your capture group is `refs/tags/`, then this setting
    ++will distribute all tags into a maximum of `maxMerges` pseudo-merge
    ++commits. However, if your capture group is, say,
    ++`refs/remotes/([0-9]+)/tags/`, then this setting will be applied to
    ++each remote's set of tags individually.
    +++
    ++Must be non-negative. The default value is 64.
    ++
    ++bitmapPseudoMerge.<name>.stableThreshold::
    ++	Determines the minimum age of commits (among reference tips,
    ++	as above, however stable commits are still considered
    ++	candidates even when they have been covered by a bitmap) which
    ++	are candidates for a stable a pseudo-merge bitmap. The default
    ++	is `1.month.ago`.
    +++
    ++Setting this threshold to a smaller value (e.g., 1.week.ago) will cause
    ++more stable groups to be generated (which impose a one-time generation
    ++cost) but those groups will likely become stale over time. Using a
    ++larger value incurs the opposite penalty (fewer stable groups which are
    ++more useful).
    ++
    ++bitmapPseudoMerge.<name>.stableSize::
    ++	Determines the size (in number of commits) of a stable
    ++	psuedo-merge bitmap. The default is `512`.
    +
    + ## Documentation/gitpacking.txt ##
    +@@ Documentation/gitpacking.txt: can take advantage of the fact that we only care about the union of
    + objects reachable from all of those tags, and answer the query much
    + faster.
    + 
    ++=== Configuration
    ++
    ++Reference tips are grouped into different pseudo-merge groups according
    ++to two criteria. A reference name matches one or more of the defined
    ++pseudo-merge patterns, and optionally one or more capture groups within
    ++that pattern which further partition the group.
    ++
    ++Within a group, commits may be considered "stable", or "unstable"
    ++depending on their age. These are adjusted by setting the
    ++`bitmapPseudoMerge.<name>.stableThreshold` and
    ++`bitmapPseudoMerge.<name>.threshold` configuration values, respectively.
    ++
    ++All stable commits are grouped into pseudo-merges of equal size
    ++(`bitmapPseudoMerge.<name>.stableSize`). If the `stableSize`
    ++configuration is set to, say, 100, then the first 100 commits (ordered
    ++by committer date) which are older than the `stableThreshold` value will
    ++form one group, the next 100 commits will form another group, and so on.
    ++
    ++Among unstable commits, the pseudo-merge machinery will attempt to
    ++combine older commits into large groups as opposed to newer commits
    ++which will appear in smaller groups. This is based on the heuristic that
    ++references whose tip commit is older are less likely to be modified to
    ++point at a different commit than a reference whose tip commit is newer.
    ++
    ++The size of groups is determined by a power-law decay function, and the
    ++decay parameter roughly corresponds to "k" in `f(n) = C*n^(-k/100)`,
    ++where `f(n)` describes the size of the `n`-th pseudo-merge group. The
    ++sample rate controls what percentage of eligible commits are considered
    ++as candidates. The threshold parameter indicates the minimum age (so as
    ++to avoid including too-recent commits in a pseudo-merge group, making it
    ++less likely to be valid). The "maxMerges" parameter sets an upper-bound
    ++on the number of pseudo-merge commits an individual group
    ++
    ++The "stable"-related parameters control "stable" pseudo-merge groups,
    ++comprised of a fixed number of commits which are older than the
    ++configured "stable threshold" value and may be grouped together in
    ++chunks of "stableSize" in order of age.
    ++
    ++The exact configuration for pseudo-merges is as follows:
    ++
    ++include::config/bitmap-pseudo-merge.txt[]
    ++
    ++=== Examples
    ++
    ++Suppose that you have a repository with a large number of references,
    ++and you want a bare-bones configuration of pseudo-merge bitmaps that
    ++will enhance bitmap coverage of the `refs/` namespace. You may start
    ++wiht a configuration like so:
    ++
    ++    [bitmapPseudoMerge "all"]
    ++	pattern = "refs/"
    ++	threshold = now
    ++	stableThreshold = never
    ++	sampleRate = 100
    ++	maxMerges = 64
    ++
    ++This will create pseudo-merge bitmaps for all references, regardless of
    ++their age, and group them into 64 pseudo-merge commits.
    ++
    ++If you wanted to separate tags from branches when generating
    ++pseudo-merge commits, you would instead define the pattern with a
    ++capture group, like so:
    ++
    ++    [bitmapPseudoMerge "all"]
    ++	pattern = "refs/(heads/tags)/"
    ++
    ++Suppose instead that you are working in a fork-network repository, with
    ++each fork specified by some numeric ID, and whose refs reside in
    ++`refs/virtual/NNN/` (where `NNN` is the numeric ID corresponding to some
    ++fork) in the network. In this instance, you may instead write something
    ++like:
    ++
    ++    [bitmapPseudoMerge "all"]
    ++	pattern = "refs/virtual/([0-9]+)/(heads|tags)/"
    ++	threshold = now
    ++	stableThreshold = never
    ++	sampleRate = 100
    ++	maxMerges = 64
    ++
    ++Which would generate pseudo-merge group identifiers like "1234-heads",
    ++and "5678-tags" (for branches in fork "1234", and tags in remote "5678",
    ++respectively).
    ++
    + SEE ALSO
    + --------
    + linkgit:git-pack-objects[1]
    +
    + ## pack-bitmap-write.c ##
    +@@
    + #include "trace2.h"
    + #include "tree.h"
    + #include "tree-walk.h"
    ++#include "pseudo-merge.h"
    + 
    + struct bitmapped_commit {
    + 	struct commit *commit;
    +@@ pack-bitmap-write.c: void bitmap_writer_init(struct bitmap_writer *writer, struct repository *r)
    + 	if (writer->bitmaps)
    + 		BUG("bitmap writer already initialized");
    + 	writer->bitmaps = kh_init_oid_map();
    ++	writer->pseudo_merge_commits = kh_init_oid_map();
    ++
    ++	string_list_init_dup(&writer->pseudo_merge_groups);
    ++
    ++	load_pseudo_merges_from_config(&writer->pseudo_merge_groups);
    ++}
    ++
    ++static void free_pseudo_merge_commit_idx(struct pseudo_merge_commit_idx *idx)
    ++{
    ++	if (!idx)
    ++		return;
    ++	free(idx->pseudo_merge);
    ++	free(idx);
    + }
    + 
    + void bitmap_writer_free(struct bitmap_writer *writer)
    + {
    + 	uint32_t i;
    ++	struct pseudo_merge_commit_idx *idx;
    + 
    + 	if (!writer)
    + 		return;
    +@@ pack-bitmap-write.c: void bitmap_writer_free(struct bitmap_writer *writer)
    + 
    + 	kh_destroy_oid_map(writer->bitmaps);
    + 
    ++	kh_foreach_value(writer->pseudo_merge_commits, idx,
    ++			 free_pseudo_merge_commit_idx(idx));
    ++	kh_destroy_oid_map(writer->pseudo_merge_commits);
    ++
    + 	for (i = 0; i < writer->selected_nr; i++) {
    + 		struct bitmapped_commit *bc = &writer->selected[i];
    + 		if (bc->write_as != bc->bitmap)
    +@@ pack-bitmap-write.c: void bitmap_writer_select_commits(struct bitmap_writer *writer,
    + 	}
    + 
    + 	stop_progress(&writer->progress);
    ++
    ++	select_pseudo_merges(writer, indexed_commits, indexed_commits_nr);
    + }
    + 
    + 
    +
    + ## pack-bitmap.h ##
    +@@ pack-bitmap.h: struct bitmap_writer {
    + 	struct bitmapped_commit *selected;
    + 	unsigned int selected_nr, selected_alloc;
    + 
    ++	struct string_list pseudo_merge_groups;
    ++	kh_oid_map_t *pseudo_merge_commits; /* oid -> pseudo merge(s) */
    + 	uint32_t pseudo_merges_nr;
    + 
    + 	struct progress *progress;
    +
      ## pseudo-merge.c ##
     @@
      #include "git-compat-util.h"
    @@ pseudo-merge.c
     +
     +#define DEFAULT_PSEUDO_MERGE_DECAY 1.0f
     +#define DEFAULT_PSEUDO_MERGE_MAX_MERGES 64
    -+#define DEFAULT_PSEUDO_MERGE_SAMPLE_RATE 100
    ++#define DEFAULT_PSEUDO_MERGE_SAMPLE_RATE 1
     +#define DEFAULT_PSEUDO_MERGE_THRESHOLD approxidate("1.week.ago")
     +#define DEFAULT_PSEUDO_MERGE_STABLE_THRESHOLD approxidate("1.month.ago")
     +#define DEFAULT_PSEUDO_MERGE_STABLE_SIZE 512
    @@ pseudo-merge.c
     +		C += 1.0f / gitexp(n + 1, group->decay);
     +	C = matches->unstable_nr / C;
     +
    -+	return (int)((C / gitexp(i + 1, group->decay)) + 0.5);
    ++	return (uint32_t)((C / gitexp(i + 1, group->decay)) + 0.5);
     +}
     +
    -+static void init_pseudo_merge_group(struct pseudo_merge_group *group)
    ++static void pseudo_merge_group_init(struct pseudo_merge_group *group)
     +{
     +	memset(group, 0, sizeof(struct pseudo_merge_group));
     +
    @@ pseudo-merge.c
     +	struct strbuf buf = STRBUF_INIT;
     +	const char *sub, *key;
     +	size_t sub_len;
    ++	int ret = 0;
     +
     +	if (parse_config_key(var, "bitmappseudomerge", &sub, &sub_len, &key))
    -+		return 0;
    ++		goto done;
     +
     +	if (!sub_len)
    -+		return 0;
    ++		goto done;
     +
     +	strbuf_add(&buf, sub, sub_len);
     +
    @@ pseudo-merge.c
     +		item = string_list_insert(list, buf.buf);
     +
     +		item->util = xmalloc(sizeof(struct pseudo_merge_group));
    -+		init_pseudo_merge_group(item->util);
    ++		pseudo_merge_group_init(item->util);
     +	}
     +
     +	group = item->util;
    @@ pseudo-merge.c
     +
     +		strbuf_release(&re);
     +	} else if (!strcmp(key, "decay")) {
    -+		group->decay = git_config_int(var, value, ctx->kvi);
    ++		group->decay = git_config_float(var, value, ctx->kvi);
     +		if (group->decay < 0) {
     +			warning(_("%s must be non-negative, using default"), var);
     +			group->decay = DEFAULT_PSEUDO_MERGE_DECAY;
     +		}
     +	} else if (!strcmp(key, "samplerate")) {
    -+		group->sample_rate = git_config_int(var, value, ctx->kvi);
    -+		if (!(0 <= group->sample_rate && group->sample_rate <= 100)) {
    -+			warning(_("%s must be between 0 and 100, using default"), var);
    ++		group->sample_rate = git_config_float(var, value, ctx->kvi);
    ++		if (!(0 <= group->sample_rate && group->sample_rate <= 1)) {
    ++			warning(_("%s must be between 0 and 1, using default"), var);
     +			group->sample_rate = DEFAULT_PSEUDO_MERGE_SAMPLE_RATE;
     +		}
     +	} else if (!strcmp(key, "threshold")) {
     +		if (git_config_expiry_date(&group->threshold, var, value)) {
    -+			strbuf_release(&buf);
    -+			return -1;
    ++			ret = -1;
    ++			goto done;
     +		}
     +	} else if (!strcmp(key, "maxmerges")) {
     +		group->max_merges = git_config_int(var, value, ctx->kvi);
    @@ pseudo-merge.c
     +		}
     +	} else if (!strcmp(key, "stablethreshold")) {
     +		if (git_config_expiry_date(&group->stable_threshold, var, value)) {
    -+			strbuf_release(&buf);
    -+			return -1;
    ++			ret = -1;
    ++			goto done;
     +		}
     +	} else if (!strcmp(key, "stablesize")) {
     +		group->stable_size = git_config_int(var, value, ctx->kvi);
    @@ pseudo-merge.c
     +		}
     +	}
     +
    ++done:
     +	strbuf_release(&buf);
     +
    -+	return 0;
    ++	return ret;
     +}
     +
     +void load_pseudo_merges_from_config(struct string_list *list)
    @@ pseudo-merge.c
     +					   int flags UNUSED,
     +					   void *_data)
     +{
    -+	struct string_list *list = _data;
    ++	struct bitmap_writer *writer = _data;
     +	struct object_id peeled;
     +	struct commit *c;
     +	uint32_t i;
    @@ pseudo-merge.c
     +	if (!c)
     +		return 0;
     +
    -+	has_bitmap = bitmap_writer_has_bitmapped_object_id(oid);
    ++	has_bitmap = bitmap_writer_has_bitmapped_object_id(writer, oid);
     +
    -+	for (i = 0; i < list->nr; i++) {
    ++	for (i = 0; i < writer->pseudo_merge_groups.nr; i++) {
     +		struct pseudo_merge_group *group;
     +		struct pseudo_merge_matches *matches;
     +		struct strbuf group_name = STRBUF_INIT;
     +		regmatch_t captures[16];
     +		size_t j;
     +
    -+		group = list->items[i].util;
    ++		group = writer->pseudo_merge_groups.items[i].util;
     +		if (regexec(group->pattern, refname, ARRAY_SIZE(captures),
     +			    captures, 0))
     +			continue;
    @@ pseudo-merge.c
     +
     +{
     +	struct pseudo_merge_commit_idx *pmc;
    -+	khiter_t hash_pos;
    -+
    -+	hash_pos = kh_get_oid_map(pseudo_merge_commits, *oid);
    -+	if (hash_pos == kh_end(pseudo_merge_commits)) {
    -+		int hash_ret;
    -+		hash_pos = kh_put_oid_map(pseudo_merge_commits, *oid, &hash_ret);
    ++	int hash_ret;
    ++	khiter_t hash_pos = kh_put_oid_map(pseudo_merge_commits, *oid,
    ++					   &hash_ret);
     +
    ++	if (hash_ret) {
     +		CALLOC_ARRAY(pmc, 1);
    -+
     +		kh_value(pseudo_merge_commits, hash_pos) = pmc;
     +	} else {
     +		pmc = kh_value(pseudo_merge_commits, hash_pos);
    @@ pseudo-merge.c
     +
     +#define MIN_PSEUDO_MERGE_SIZE 8
     +
    -+static void select_pseudo_merges_1(struct pseudo_merge_group *group,
    -+				   struct pseudo_merge_matches *matches,
    -+				   kh_oid_map_t *pseudo_merge_commits,
    -+				   uint32_t *pseudo_merges_nr)
    ++static void select_pseudo_merges_1(struct bitmap_writer *writer,
    ++				   struct pseudo_merge_group *group,
    ++				   struct pseudo_merge_matches *matches)
     +{
     +	uint32_t i, j;
     +	uint32_t stable_merges_nr;
    @@ pseudo-merge.c
     +		merge = push_pseudo_merge(group);
     +		p = &merge->parents;
     +
    ++		/*
    ++		 * For each pseudo-merge created above, add parents to the
    ++		 * allocated commit node from the stable set of commits
    ++		 * (un-bitmapped, newer than the stable threshold).
    ++		 */
     +		do {
     +			struct commit *c;
     +			struct pseudo_merge_commit_idx *pmc;
    @@ pseudo-merge.c
     +				break;
     +
     +			c = matches->stable[j++];
    -+			pmc = pseudo_merge_idx(pseudo_merge_commits,
    ++			/*
    ++			 * Here and below, make sure that we keep our mapping of
    ++			 * commits -> pseudo-merge(s) which include the key'd
    ++			 * commit up-to-date.
    ++			 */
    ++			pmc = pseudo_merge_idx(writer->pseudo_merge_commits,
     +					       &c->object.oid);
     +
     +			ALLOC_GROW(pmc->pseudo_merge, pmc->nr + 1, pmc->alloc);
     +
    -+			pmc->pseudo_merge[pmc->nr++] = *pseudo_merges_nr;
    ++			pmc->pseudo_merge[pmc->nr++] = writer->pseudo_merges_nr;
     +			p = commit_list_append(c, p);
     +		} while (j % group->stable_size);
     +
    -+		bitmap_writer_push_bitmapped_commit(merge, 1);
    -+		(*pseudo_merges_nr)++;
    ++		bitmap_writer_push_commit(writer, merge, 1);
    ++		writer->pseudo_merges_nr++;
     +	}
     +
     +	/* make up to group->max_merges pseudo merges for unstable commits */
    @@ pseudo-merge.c
     +		size = pseudo_merge_group_size(group, matches, i);
     +		end = size < MIN_PSEUDO_MERGE_SIZE ? matches->unstable_nr : j + size;
     +
    ++		/*
    ++		 * For each pseudo-merge commit created above, add parents to
    ++		 * the allocated commit node from the unstable set of commits
    ++		 * (newer than the stable threshold).
    ++		 *
    ++		 * Account for the sample rate, since not every candidate from
    ++		 * the set of stable commits will be included as a pseudo-merge
    ++		 * parent.
    ++		 */
     +		for (; j < end && j < matches->unstable_nr; j++) {
     +			struct commit *c = matches->unstable[j];
     +			struct pseudo_merge_commit_idx *pmc;
     +
    -+			if (j % (100 / group->sample_rate))
    ++			if (j % (uint32_t)(1.0f / group->sample_rate))
     +				continue;
     +
    -+			pmc = pseudo_merge_idx(pseudo_merge_commits,
    ++			pmc = pseudo_merge_idx(writer->pseudo_merge_commits,
     +					       &c->object.oid);
     +
     +			ALLOC_GROW(pmc->pseudo_merge, pmc->nr + 1, pmc->alloc);
     +
    -+			pmc->pseudo_merge[pmc->nr++] = *pseudo_merges_nr;
    ++			pmc->pseudo_merge[pmc->nr++] = writer->pseudo_merges_nr;
     +			p = commit_list_append(c, p);
     +		}
     +
    -+		bitmap_writer_push_bitmapped_commit(merge, 1);
    -+		(*pseudo_merges_nr)++;
    ++		bitmap_writer_push_commit(writer, merge, 1);
    ++		writer->pseudo_merges_nr++;
     +		if (end >= matches->unstable_nr)
     +			break;
     +	}
    @@ pseudo-merge.c
     +	QSORT(matches->unstable, matches->unstable_nr, commit_date_cmp);
     +}
     +
    -+void select_pseudo_merges(struct string_list *list,
    -+			  struct commit **commits, size_t commits_nr,
    -+			  kh_oid_map_t *pseudo_merge_commits,
    -+			  uint32_t *pseudo_merges_nr,
    -+			  unsigned show_progress)
    ++void select_pseudo_merges(struct bitmap_writer *writer,
    ++			  struct commit **commits, size_t commits_nr)
     +{
     +	struct progress *progress = NULL;
     +	uint32_t i;
     +
    -+	if (!list->nr)
    ++	if (!writer->pseudo_merge_groups.nr)
     +		return;
     +
    -+	if (show_progress)
    -+		progress = start_progress("Selecting pseudo-merge commits", list->nr);
    ++	if (writer->show_progress)
    ++		progress = start_progress("Selecting pseudo-merge commits",
    ++					  writer->pseudo_merge_groups.nr);
     +
    -+	for_each_ref(find_pseudo_merge_group_for_ref, list);
    ++	for_each_ref(find_pseudo_merge_group_for_ref, writer);
     +
    -+	for (i = 0; i < list->nr; i++) {
    ++	for (i = 0; i < writer->pseudo_merge_groups.nr; i++) {
     +		struct pseudo_merge_group *group;
     +		struct hashmap_iter iter;
     +		struct strmap_entry *e;
     +
    -+		group = list->items[i].util;
    ++		group = writer->pseudo_merge_groups.items[i].util;
     +		strmap_for_each_entry(&group->matches, &iter, e) {
     +			struct pseudo_merge_matches *matches = e->value;
     +
     +			sort_pseudo_merge_matches(matches);
     +
    -+			select_pseudo_merges_1(group, matches,
    -+					       pseudo_merge_commits,
    -+					       pseudo_merges_nr);
    ++			select_pseudo_merges_1(writer, group, matches);
     +		}
     +
     +		display_progress(progress, i + 1);
    @@ pseudo-merge.h
     +struct commit;
     +struct string_list;
     +struct bitmap_index;
    ++struct bitmap_writer;
     +
     +/*
     + * A pseudo-merge group tracks the set of non-bitmapped reference tips
    @@ pseudo-merge.h
     +	 */
     +	float decay;
     +	int max_merges;
    -+	int sample_rate;
    ++	float sample_rate;
     +	int stable_size;
     +	timestamp_t threshold;
     +	timestamp_t stable_threshold;
    @@ pseudo-merge.h
     + *
     + * Optionally shows a progress meter.
     + */
    -+void select_pseudo_merges(struct string_list *list,
    -+			  struct commit **commits, size_t commits_nr,
    -+			  kh_oid_map_t *pseudo_merge_commits,
    -+			  uint32_t *pseudo_merges_nr,
    -+			  unsigned show_progress);
    ++void select_pseudo_merges(struct bitmap_writer *writer,
    ++			  struct commit **commits, size_t commits_nr);
      
      #endif
10:  12b432e3a8a <  -:  ----------- pack-bitmap-write.c: select pseudo-merge commits
11:  6ce805d061e ! 18:  311226f65c2 pack-bitmap-write.c: write pseudo-merge table
    @@ pack-bitmap-write.c
      
      struct bitmapped_commit {
      	struct commit *commit;
    -@@ pack-bitmap-write.c: static void write_selected_commits_v1(struct hashfile *f,
    +@@ pack-bitmap-write.c: static void write_selected_commits_v1(struct bitmap_writer *writer,
      	}
      }
      
    -+static void write_pseudo_merges(struct hashfile *f)
    ++static void write_pseudo_merges(struct bitmap_writer *writer,
    ++				struct hashfile *f)
     +{
     +	struct oid_array commits = OID_ARRAY_INIT;
     +	struct bitmap **commits_bitmap = NULL;
     +	off_t *pseudo_merge_ofs = NULL;
     +	off_t start, table_start, next_ext;
     +
    -+	uint32_t base = bitmap_writer_selected_nr();
    ++	uint32_t base = bitmap_writer_nr_selected_commits(writer);
     +	size_t i, j = 0;
     +
    -+	CALLOC_ARRAY(commits_bitmap, writer.pseudo_merges_nr);
    -+	CALLOC_ARRAY(pseudo_merge_ofs, writer.pseudo_merges_nr);
    ++	CALLOC_ARRAY(commits_bitmap, writer->pseudo_merges_nr);
    ++	CALLOC_ARRAY(pseudo_merge_ofs, writer->pseudo_merges_nr);
     +
    -+	for (i = 0; i < writer.pseudo_merges_nr; i++) {
    -+		struct bitmapped_commit *merge = &writer.selected[base + i];
    ++	for (i = 0; i < writer->pseudo_merges_nr; i++) {
    ++		struct bitmapped_commit *merge = &writer->selected[base + i];
     +		struct commit_list *p;
     +
     +		if (!merge->pseudo_merge)
    @@ pack-bitmap-write.c: static void write_selected_commits_v1(struct hashfile *f,
     +
     +		for (p = merge->commit->parents; p; p = p->next)
     +			bitmap_set(commits_bitmap[i],
    -+				   find_object_pos(&p->item->object.oid, NULL));
    ++				   find_object_pos(writer, &p->item->object.oid,
    ++						   NULL));
     +	}
     +
     +	start = hashfile_total(f);
     +
    -+	for (i = 0; i < writer.pseudo_merges_nr; i++) {
    ++	for (i = 0; i < writer->pseudo_merges_nr; i++) {
     +		struct ewah_bitmap *commits_ewah = bitmap_to_ewah(commits_bitmap[i]);
     +
     +		pseudo_merge_ofs[i] = hashfile_total(f);
     +
     +		dump_bitmap(f, commits_ewah);
    -+		dump_bitmap(f, writer.selected[base+i].write_as);
    ++		dump_bitmap(f, writer->selected[base+i].write_as);
     +
     +		ewah_free(commits_ewah);
     +	}
     +
     +	next_ext = st_add(hashfile_total(f),
    -+			  st_mult(kh_size(writer.pseudo_merge_commits),
    ++			  st_mult(kh_size(writer->pseudo_merge_commits),
     +				  sizeof(uint64_t)));
     +
     +	table_start = hashfile_total(f);
     +
    -+	commits.alloc = kh_size(writer.pseudo_merge_commits);
    ++	commits.alloc = kh_size(writer->pseudo_merge_commits);
     +	CALLOC_ARRAY(commits.oid, commits.alloc);
     +
    -+	for (i = kh_begin(writer.pseudo_merge_commits); i != kh_end(writer.pseudo_merge_commits); i++) {
    -+		if (!kh_exist(writer.pseudo_merge_commits, i))
    ++	for (i = kh_begin(writer->pseudo_merge_commits); i != kh_end(writer->pseudo_merge_commits); i++) {
    ++		if (!kh_exist(writer->pseudo_merge_commits, i))
     +			continue;
    -+		oid_array_append(&commits, &kh_key(writer.pseudo_merge_commits, i));
    ++		oid_array_append(&commits, &kh_key(writer->pseudo_merge_commits, i));
     +	}
     +
     +	oid_array_sort(&commits);
    @@ pack-bitmap-write.c: static void write_selected_commits_v1(struct hashfile *f,
     +		int hash_pos;
     +		struct pseudo_merge_commit_idx *c;
     +
    -+		hash_pos = kh_get_oid_map(writer.pseudo_merge_commits,
    ++		hash_pos = kh_get_oid_map(writer->pseudo_merge_commits,
     +					  commits.oid[i]);
    -+		if (hash_pos == kh_end(writer.pseudo_merge_commits))
    ++		if (hash_pos == kh_end(writer->pseudo_merge_commits))
     +			BUG("could not find pseudo-merge commit %s",
     +			    oid_to_hex(&commits.oid[i]));
     +
    -+		c = kh_value(writer.pseudo_merge_commits, hash_pos);
    ++		c = kh_value(writer->pseudo_merge_commits, hash_pos);
     +
    -+		hashwrite_be32(f, find_object_pos(&commits.oid[i], NULL));
    ++		hashwrite_be32(f, find_object_pos(writer, &commits.oid[i],
    ++						  NULL));
     +		if (c->nr == 1)
     +			hashwrite_be64(f, pseudo_merge_ofs[c->pseudo_merge[0]]);
     +		else if (c->nr > 1) {
    @@ pack-bitmap-write.c: static void write_selected_commits_v1(struct hashfile *f,
     +		int hash_pos;
     +		struct pseudo_merge_commit_idx *c;
     +
    -+		hash_pos = kh_get_oid_map(writer.pseudo_merge_commits,
    ++		hash_pos = kh_get_oid_map(writer->pseudo_merge_commits,
     +					  commits.oid[i]);
    -+		if (hash_pos == kh_end(writer.pseudo_merge_commits))
    ++		if (hash_pos == kh_end(writer->pseudo_merge_commits))
     +			BUG("could not find pseudo-merge commit %s",
     +			    oid_to_hex(&commits.oid[i]));
     +
    -+		c = kh_value(writer.pseudo_merge_commits, hash_pos);
    ++		c = kh_value(writer->pseudo_merge_commits, hash_pos);
     +		if (c->nr == 1)
     +			continue;
     +
    @@ pack-bitmap-write.c: static void write_selected_commits_v1(struct hashfile *f,
     +	}
     +
     +	/* write positions for all pseudo merges */
    -+	for (i = 0; i < writer.pseudo_merges_nr; i++)
    ++	for (i = 0; i < writer->pseudo_merges_nr; i++)
     +		hashwrite_be64(f, pseudo_merge_ofs[i]);
     +
    -+	hashwrite_be32(f, writer.pseudo_merges_nr);
    -+	hashwrite_be32(f, kh_size(writer.pseudo_merge_commits));
    ++	hashwrite_be32(f, writer->pseudo_merges_nr);
    ++	hashwrite_be32(f, kh_size(writer->pseudo_merge_commits));
     +	hashwrite_be64(f, table_start - start);
     +	hashwrite_be64(f, hashfile_total(f) - start + sizeof(uint64_t));
     +
    -+	for (i = 0; i < writer.pseudo_merges_nr; i++)
    ++	for (i = 0; i < writer->pseudo_merges_nr; i++)
     +		bitmap_free(commits_bitmap[i]);
     +
     +	free(pseudo_merge_ofs);
    @@ pack-bitmap-write.c: 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;
    -@@ pack-bitmap-write.c: void bitmap_writer_finish(struct pack_idx_entry **index,
    + 	struct bitmap_writer *writer = _data;
    +@@ pack-bitmap-write.c: void bitmap_writer_finish(struct bitmap_writer *writer,
      
      	int fd = odb_mkstemp(&tmp_file, "pack/tmp_bitmap_XXXXXX");
      
    -+	if (writer.pseudo_merges_nr)
    ++	if (writer->pseudo_merges_nr)
     +		options |= BITMAP_OPT_PSEUDO_MERGES;
     +
      	f = hashfd(fd, tmp_file.buf);
      
      	memcpy(header.magic, BITMAP_IDX_SIGNATURE, sizeof(BITMAP_IDX_SIGNATURE));
    -@@ pack-bitmap-write.c: void bitmap_writer_finish(struct pack_idx_entry **index,
    +@@ pack-bitmap-write.c: void bitmap_writer_finish(struct bitmap_writer *writer,
      
    - 	write_selected_commits_v1(f, commit_positions, offsets);
    + 	write_selected_commits_v1(writer, f, offsets);
      
     +	if (options & BITMAP_OPT_PSEUDO_MERGES)
    -+		write_pseudo_merges(f);
    ++		write_pseudo_merges(writer, f);
     +
      	if (options & BITMAP_OPT_LOOKUP_TABLE)
    - 		write_lookup_table(f, commit_positions, offsets);
    + 		write_lookup_table(writer, f, offsets);
      
     
      ## pack-bitmap.h ##
12:  60f6b310213 = 19:  55dd7a8023e pack-bitmap: extract `read_bitmap()` function
13:  9465313691b ! 20:  3cc5434e44e pseudo-merge: scaffolding for reads
    @@ Commit message
         Signed-off-by: Taylor Blau <me@ttaylorr.com>
     
      ## pseudo-merge.c ##
    -@@ pseudo-merge.c: void select_pseudo_merges(struct string_list *list,
    +@@ pseudo-merge.c: void select_pseudo_merges(struct bitmap_writer *writer,
      
      	stop_progress(&progress);
      }
    @@ pseudo-merge.c: void select_pseudo_merges(struct string_list *list,
     +}
     
      ## pseudo-merge.h ##
    -@@ pseudo-merge.h: void select_pseudo_merges(struct string_list *list,
    - 			  uint32_t *pseudo_merges_nr,
    - 			  unsigned show_progress);
    +@@ pseudo-merge.h: struct pseudo_merge_commit_idx {
    + void select_pseudo_merges(struct bitmap_writer *writer,
    + 			  struct commit **commits, size_t commits_nr);
      
     +/*
     + * Represents a serialized view of a file containing pseudo-merge(s)
14:  5894f3d5369 = 21:  7664f5f9648 pack-bitmap.c: read pseudo-merge extension
15:  7dbee8bcbdf = 22:  8ba0a9c5402 pseudo-merge: implement support for reading pseudo-merge commits
16:  09650aa53e9 = 23:  2c02f303b6f ewah: implement `ewah_bitmap_popcount()`
17:  7b5ea56d053 = 24:  82cce72bf55 pack-bitmap: implement test helpers for pseudo-merge
18:  006abdd1698 = 25:  890f6c4b9de t/test-lib-functions.sh: support `--date` in `test_commit_bulk()`
19:  3f85e5b90f5 ! 26:  41691824f78 pack-bitmap.c: use pseudo-merges during traversal
    @@ t/t5333-pseudo-merge-bitmaps.sh (new)
     +
     +test_expect_success 'bitmapPseudoMerge.sampleRate adjusts commit selection rate' '
     +	test_config bitmapPseudoMerge.test.pattern "refs/tags/" &&
    -+	test_config bitmapPseudoMerge.test.maxMerges 8 &&
    ++	test_config bitmapPseudoMerge.test.maxMerges 1 &&
     +	test_config bitmapPseudoMerge.test.stableThreshold never &&
     +
     +	commits_nr=$(git rev-list --all --count) &&
     +
    -+	for rate in 100 50 10
    ++	for rate in 1.0 0.5 0.25
     +	do
     +		git -c bitmapPseudoMerge.test.sampleRate=$rate repack -adb &&
     +
     +		test_pseudo_merges >merges &&
    -+		for i in $(test_seq 0 $(($(wc -l <merges)-1)))
    -+		do
    -+			test_pseudo_merge_commits $i || return 1
    -+		done >commits &&
    ++		test_line_count = 1 merges &&
    ++		test_pseudo_merge_commits 0 >commits &&
     +
     +		test-tool bitmap list-commits >bitmaps &&
     +		bitmaps_nr="$(wc -l <bitmaps)" &&
     +
    -+		perl -MPOSIX -e "print ceil((\$ARGV[0]/100)*(\$ARGV[1]-\$ARGV[2]))" \
    ++		perl -MPOSIX -e "print ceil(\$ARGV[0]*(\$ARGV[1]-\$ARGV[2]))" \
     +			"$rate" "$commits_nr" "$bitmaps_nr" >expect &&
     +
     +		test $(cat expect) -eq $(wc -l <commits) || return 1
20:  5fac186df64 = 27:  a34a60c3ef8 pack-bitmap: extra trace2 information
21:  b5aea8e57f8 = 28:  da2fb5b4b48 ewah: `bitmap_equals_ewah()`
22:  61ddb574285 ! 29:  ff21247281f pseudo-merge: implement support for finding existing merges
    @@ pack-bitmap-write.c
      
      struct bitmapped_commit {
      	struct commit *commit;
    -@@ pack-bitmap-write.c: static int fill_bitmap_tree(struct bitmap *bitmap,
    +@@ pack-bitmap-write.c: static int fill_bitmap_tree(struct bitmap_writer *writer,
      }
      
      static int reused_bitmaps_nr;
     +static int reused_pseudo_merge_bitmaps_nr;
      
    - static int fill_bitmap_commit(struct bb_commit *ent,
    - 			      struct commit *commit,
    -@@ pack-bitmap-write.c: static int fill_bitmap_commit(struct bb_commit *ent,
    + static int fill_bitmap_commit(struct bitmap_writer *writer,
    + 			      struct bb_commit *ent,
    +@@ pack-bitmap-write.c: static int fill_bitmap_commit(struct bitmap_writer *writer,
      			struct bitmap *remapped = bitmap_new();
      
      			if (commit->object.flags & BITMAP_PSEUDO_MERGE)
    @@ pack-bitmap-write.c: static int fill_bitmap_commit(struct bb_commit *ent,
      			else
      				old = bitmap_for_commit(old_bitmap, c);
      			/*
    -@@ pack-bitmap-write.c: static int fill_bitmap_commit(struct bb_commit *ent,
    +@@ pack-bitmap-write.c: static int fill_bitmap_commit(struct bitmap_writer *writer,
      			if (old && !rebuild_bitmap(mapping, old, remapped)) {
      				bitmap_or(ent->bitmap, remapped);
      				bitmap_free(remapped);
    @@ pack-bitmap-write.c: static int fill_bitmap_commit(struct bb_commit *ent,
      				continue;
      			}
      			bitmap_free(remapped);
    -@@ pack-bitmap-write.c: int bitmap_writer_build(struct packing_data *to_pack)
    +@@ pack-bitmap-write.c: int bitmap_writer_build(struct bitmap_writer *writer,
      			    the_repository);
      	trace2_data_intmax("pack-bitmap-write", the_repository,
      			   "building_bitmaps_reused", reused_bitmaps_nr);
    @@ pack-bitmap-write.c: int bitmap_writer_build(struct packing_data *to_pack)
     +			   "building_bitmaps_pseudo_merge_reused",
     +			   reused_pseudo_merge_bitmaps_nr);
      
    - 	stop_progress(&writer.progress);
    + 	stop_progress(&writer->progress);
      
     
      ## pack-bitmap.c ##
    @@ pack-bitmap.h: int rebuild_bitmap(const uint32_t *reposition,
      				      struct commit *commit);
     +struct ewah_bitmap *pseudo_merge_bitmap_for_commit(struct bitmap_index *bitmap_git,
     +						   struct commit *commit);
    - void bitmap_writer_select_commits(struct commit **indexed_commits,
    + void bitmap_writer_select_commits(struct bitmap_writer *writer,
    + 				  struct commit **indexed_commits,
      				  unsigned int indexed_commits_nr);
    - int bitmap_writer_build(struct packing_data *to_pack);
     
      ## pseudo-merge.c ##
     @@ pseudo-merge.c: int cascade_pseudo_merges(const struct pseudo_merge_map *pm,
23:  2bd830d35dd = 30:  6a6d88fa512 t/perf: implement performace tests for pseudo-merge bitmaps
-- 
2.45.1.175.gbea44add9db
Previous: Taylor BlauNext: Taylor Blau
Message 85 of 157 in “pack-bitmap: pseudo-merge reachability bitmaps”
  1. 00/24 pack-bitmap: pseudo-merge reachability bitmapsTaylor Blau, Mar 20, 2024
  2. 01/24 Documentation/technical: describe pseudo-merge bitmaps formatTaylor Blau, Mar 20, 2024
  3. Junio C HamanoMar 21, 2024
  4. Taylor BlauMar 21, 2024
  5. Junio C HamanoMar 21, 2024
  6. 02/24 config: repo_config_get_expiry()Taylor Blau, Mar 20, 2024
  7. Jeff KingApr 10, 2024
  8. Taylor BlauApr 29, 2024
  9. 03/24 ewah: implement `ewah_bitmap_is_subset()`Taylor Blau, Mar 20, 2024
  10. Jeff KingApr 10, 2024
  11. Taylor BlauApr 29, 2024
  12. 04/24 pack-bitmap: drop unused `max_bitmaps` parameterTaylor Blau, Mar 20, 2024
  13. Jeff KingApr 10, 2024
  14. 05/24 pack-bitmap: move some initialization to `bitmap_writer_init()`Taylor Blau, Mar 20, 2024
  15. Jeff KingApr 10, 2024
  16. 06/24 pseudo-merge.ch: initial commitTaylor Blau, Mar 20, 2024
  17. 07/24 pack-bitmap-write: support storing pseudo-merge commitsTaylor Blau, Mar 20, 2024
  18. 08/24 pack-bitmap: implement `bitmap_writer_has_bitmapped_object_id()`Taylor Blau, Mar 20, 2024
  19. 09/24 pack-bitmap: make `bitmap_writer_push_bitmapped_commit()` publicTaylor Blau, Mar 20, 2024
  20. 10/24 pseudo-merge: implement support for selecting pseudo-merge commitsTaylor Blau, Mar 20, 2024
  21. 11/24 pack-bitmap-write.c: select pseudo-merge commitsTaylor Blau, Mar 20, 2024
  22. 12/24 pack-bitmap-write.c: write pseudo-merge tableTaylor Blau, Mar 20, 2024
  23. 13/24 pack-bitmap: extract `read_bitmap()` functionTaylor Blau, Mar 20, 2024
  24. 14/24 pseudo-merge: scaffolding for readsTaylor Blau, Mar 20, 2024
  25. 15/24 pack-bitmap.c: read pseudo-merge extensionTaylor Blau, Mar 20, 2024
  26. 16/24 pseudo-merge: implement support for reading pseudo-merge commitsTaylor Blau, Mar 20, 2024
  27. 17/24 ewah: implement `ewah_bitmap_popcount()`Taylor Blau, Mar 20, 2024
  28. 18/24 pack-bitmap: implement test helpers for pseudo-mergeTaylor Blau, Mar 20, 2024
  29. 19/24 t/test-lib-functions.sh: support `--date` in `test_commit_bulk()`Taylor Blau, Mar 20, 2024
  30. 20/24 pack-bitmap.c: use pseudo-merges during traversalTaylor Blau, Mar 20, 2024
  31. 21/24 pack-bitmap: extra trace2 informationTaylor Blau, Mar 20, 2024
  32. 22/24 ewah: `bitmap_equals_ewah()`Taylor Blau, Mar 20, 2024
  33. 23/24 pseudo-merge: implement support for finding existing mergesTaylor Blau, Mar 20, 2024
  34. 24/24 t/perf: implement performace tests for pseudo-merge bitmapsTaylor Blau, Mar 20, 2024
  35. Junio C HamanoMar 21, 2024
  36. 00/23 pack-bitmap: pseudo-merge reachability bitmapsTaylor Blau, Apr 29, 2024
  37. 01/23 Documentation/technical: describe pseudo-merge bitmaps formatTaylor Blau, Apr 29, 2024
  38. Patrick SteinhardtMay 6, 2024
  39. Taylor BlauMay 6, 2024
  40. Patrick SteinhardtMay 10, 2024
  41. Taylor BlauMay 13, 2024
  42. Patrick SteinhardtMay 14, 2024
  43. 02/23 ewah: implement `ewah_bitmap_is_subset()`Taylor Blau, Apr 29, 2024
  44. 03/23 pack-bitmap: drop unused `max_bitmaps` parameterTaylor Blau, Apr 29, 2024
  45. 04/23 pack-bitmap: move some initialization to `bitmap_writer_init()`Taylor Blau, Apr 29, 2024
  46. Patrick SteinhardtMay 6, 2024
  47. Taylor BlauMay 6, 2024
  48. 05/23 pseudo-merge.ch: initial commitTaylor Blau, Apr 29, 2024
  49. 06/23 pack-bitmap-write: support storing pseudo-merge commitsTaylor Blau, Apr 29, 2024
  50. Patrick SteinhardtMay 6, 2024
  51. Taylor BlauMay 6, 2024
  52. Patrick SteinhardtMay 10, 2024
  53. Jeff KingMay 13, 2024
  54. Taylor BlauMay 13, 2024
  55. 07/23 pack-bitmap: implement `bitmap_writer_has_bitmapped_object_id()`Taylor Blau, Apr 29, 2024
  56. 08/23 pack-bitmap: make `bitmap_writer_push_bitmapped_commit()` publicTaylor Blau, Apr 29, 2024
  57. Jeff KingMay 13, 2024
  58. Taylor BlauMay 14, 2024
  59. 09/23 pseudo-merge: implement support for selecting pseudo-merge commitsTaylor Blau, Apr 29, 2024
  60. Patrick SteinhardtMay 6, 2024
  61. Taylor BlauMay 6, 2024
  62. Jeff KingMay 13, 2024
  63. Taylor BlauMay 14, 2024
  64. Jeff KingMay 16, 2024
  65. Junio C HamanoMay 16, 2024
  66. 10/23 pack-bitmap-write.c: select pseudo-merge commitsTaylor Blau, Apr 29, 2024
  67. Patrick SteinhardtMay 6, 2024
  68. Taylor BlauMay 6, 2024
  69. Patrick SteinhardtMay 10, 2024
  70. 11/23 pack-bitmap-write.c: write pseudo-merge tableTaylor Blau, Apr 29, 2024
  71. 12/23 pack-bitmap: extract `read_bitmap()` functionTaylor Blau, Apr 29, 2024
  72. 13/23 pseudo-merge: scaffolding for readsTaylor Blau, Apr 29, 2024
  73. 14/23 pack-bitmap.c: read pseudo-merge extensionTaylor Blau, Apr 29, 2024
  74. 15/23 pseudo-merge: implement support for reading pseudo-merge commitsTaylor Blau, Apr 29, 2024
  75. 16/23 ewah: implement `ewah_bitmap_popcount()`Taylor Blau, Apr 29, 2024
  76. 17/23 pack-bitmap: implement test helpers for pseudo-mergeTaylor Blau, Apr 29, 2024
  77. 18/23 t/test-lib-functions.sh: support `--date` in `test_commit_bulk()`Taylor Blau, Apr 29, 2024
  78. 19/23 pack-bitmap.c: use pseudo-merges during traversalTaylor Blau, Apr 29, 2024
  79. 20/23 pack-bitmap: extra trace2 informationTaylor Blau, Apr 29, 2024
  80. 21/23 ewah: `bitmap_equals_ewah()`Taylor Blau, Apr 29, 2024
  81. 22/23 pseudo-merge: implement support for finding existing mergesTaylor Blau, Apr 29, 2024
  82. 23/23 t/perf: implement performace tests for pseudo-merge bitmapsTaylor Blau, Apr 29, 2024
  83. Junio C HamanoApr 30, 2024
  84. Taylor BlauMay 1, 2024
  85. 00/30 pack-bitmap: pseudo-merge reachability bitmapsTaylor Blau, May 21, 2024
  86. 01/30 object.h: add flags allocated by pack-bitmap.hTaylor Blau, May 21, 2024
  87. Taylor BlauMay 21, 2024
  88. 07/30 Documentation/gitpacking.txt: initial commitTaylor Blau, May 21, 2024
  89. 08/30 Documentation/gitpacking.txt: describe pseudo-merge bitmapsTaylor Blau, May 21, 2024
  90. 09/30 Documentation/technical: describe pseudo-merge bitmaps formatTaylor Blau, May 21, 2024
  91. 10/30 ewah: implement `ewah_bitmap_is_subset()`Taylor Blau, May 21, 2024
  92. 11/30 pack-bitmap: move some initialization to `bitmap_writer_init()`Taylor Blau, May 21, 2024
  93. 12/30 pseudo-merge.ch: initial commitTaylor Blau, May 21, 2024
  94. 13/30 pack-bitmap-write: support storing pseudo-merge commitsTaylor Blau, May 21, 2024
  95. 14/30 pack-bitmap: implement `bitmap_writer_has_bitmapped_object_id()`Taylor Blau, May 21, 2024
  96. 15/30 pack-bitmap: make `bitmap_writer_push_bitmapped_commit()` publicTaylor Blau, May 21, 2024
  97. 16/30 config: introduce git_config_float()Taylor Blau, May 21, 2024
  98. Jeff KingMay 23, 2024
  99. Taylor BlauMay 23, 2024
  100. 17/30 pseudo-merge: implement support for selecting pseudo-merge commitsTaylor Blau, May 21, 2024
  101. Jeff KingMay 23, 2024
  102. Taylor BlauMay 23, 2024
  103. 18/30 pack-bitmap-write.c: write pseudo-merge tableTaylor Blau, May 21, 2024
  104. 19/30 pack-bitmap: extract `read_bitmap()` functionTaylor Blau, May 21, 2024
  105. 20/30 pseudo-merge: scaffolding for readsTaylor Blau, May 21, 2024
  106. 21/30 pack-bitmap.c: read pseudo-merge extensionTaylor Blau, May 21, 2024
  107. 22/30 pseudo-merge: implement support for reading pseudo-merge commitsTaylor Blau, May 21, 2024
  108. Jeff KingMay 23, 2024
  109. Taylor BlauMay 23, 2024
  110. 23/30 ewah: implement `ewah_bitmap_popcount()`Taylor Blau, May 21, 2024
  111. 24/30 pack-bitmap: implement test helpers for pseudo-mergeTaylor Blau, May 21, 2024
  112. 25/30 t/test-lib-functions.sh: support `--date` in `test_commit_bulk()`Taylor Blau, May 21, 2024
  113. Jeff KingMay 23, 2024
  114. Junio C HamanoMay 23, 2024
  115. Taylor BlauMay 23, 2024
  116. 26/30 pack-bitmap.c: use pseudo-merges during traversalTaylor Blau, May 21, 2024
  117. Jeff KingMay 23, 2024
  118. Taylor BlauMay 23, 2024
  119. 27/30 pack-bitmap: extra trace2 informationTaylor Blau, May 21, 2024
  120. 28/30 ewah: `bitmap_equals_ewah()`Taylor Blau, May 21, 2024
  121. 29/30 pseudo-merge: implement support for finding existing mergesTaylor Blau, May 21, 2024
  122. 30/30 t/perf: implement performace tests for pseudo-merge bitmapsTaylor Blau, May 21, 2024
  123. Jeff KingMay 23, 2024
  124. Taylor BlauMay 23, 2024
  125. Jeff KingMay 25, 2024
  126. Jeff KingMay 23, 2024
  127. Taylor BlauMay 23, 2024
  128. Jeff KingMay 25, 2024
  129. Taylor BlauMay 23, 2024
  130. 00/24 pack-bitmap: pseudo-merge reachability bitmapsTaylor Blau, May 23, 2024
  131. 01/24 Documentation/gitpacking.txt: initial commitTaylor Blau, May 23, 2024
  132. 02/24 Documentation/gitpacking.txt: describe pseudo-merge bitmapsTaylor Blau, May 23, 2024
  133. 03/24 Documentation/technical: describe pseudo-merge bitmaps formatTaylor Blau, May 23, 2024
  134. 04/24 ewah: implement `ewah_bitmap_is_subset()`Taylor Blau, May 23, 2024
  135. 05/24 pack-bitmap: move some initialization to `bitmap_writer_init()`Taylor Blau, May 23, 2024
  136. 06/24 pseudo-merge.ch: initial commitTaylor Blau, May 23, 2024
  137. 07/24 pack-bitmap-write: support storing pseudo-merge commitsTaylor Blau, May 23, 2024
  138. 08/24 pack-bitmap: implement `bitmap_writer_has_bitmapped_object_id()`Taylor Blau, May 23, 2024
  139. 09/24 pack-bitmap: make `bitmap_writer_push_bitmapped_commit()` publicTaylor Blau, May 23, 2024
  140. 10/24 config: introduce `git_config_double()`Taylor Blau, May 23, 2024
  141. 11/24 pseudo-merge: implement support for selecting pseudo-merge commitsTaylor Blau, May 23, 2024
  142. Jeff KingMay 25, 2024
  143. 12/24 pack-bitmap-write.c: write pseudo-merge tableTaylor Blau, May 23, 2024
  144. 13/24 pack-bitmap: extract `read_bitmap()` functionTaylor Blau, May 23, 2024
  145. 14/24 pseudo-merge: scaffolding for readsTaylor Blau, May 23, 2024
  146. 15/24 pack-bitmap.c: read pseudo-merge extensionTaylor Blau, May 23, 2024
  147. 16/24 pseudo-merge: implement support for reading pseudo-merge commitsTaylor Blau, May 23, 2024
  148. 17/24 ewah: implement `ewah_bitmap_popcount()`Taylor Blau, May 23, 2024
  149. 18/24 pack-bitmap: implement test helpers for pseudo-mergeTaylor Blau, May 23, 2024
  150. 19/24 t/test-lib-functions.sh: support `--notick` in `test_commit_bulk()`Taylor Blau, May 23, 2024
  151. Jeff KingMay 25, 2024
  152. 20/24 pack-bitmap.c: use pseudo-merges during traversalTaylor Blau, May 23, 2024
  153. 21/24 pack-bitmap: extra trace2 informationTaylor Blau, May 23, 2024
  154. 22/24 ewah: `bitmap_equals_ewah()`Taylor Blau, May 23, 2024
  155. 23/24 pseudo-merge: implement support for finding existing mergesTaylor Blau, May 23, 2024
  156. 24/24 t/perf: implement performance tests for pseudo-merge bitmapsTaylor Blau, May 23, 2024
  157. Jeff KingMay 25, 2024

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.