From: René Scharfe <hidden> Date: 2021-09-11 07:59:22
All callers have full object IDs, so pass them on instead of just their
hash member.
Signed-off-by: René Scharfe <redacted>
---
object-file.c | 2 +-
packfile.c | 12 ++++++------
packfile.h | 2 +-
3 files changed, 8 insertions(+), 8 deletions(-)
From: René Scharfe <hidden> Date: 2021-09-11 08:00:44
The single caller has a full object ID, so pass it on instead of just
its hash member.
Signed-off-by: René Scharfe <redacted>
---
object-file.c | 2 +-
packfile.c | 4 ++--
packfile.h | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
From: René Scharfe <hidden> Date: 2021-09-11 08:01:55
Store the object ID of broken pack entries in an oidset instead of
keeping only their hashes in an unsorted array. The resulting code is
shorter and easier to read. It also handles the (hopefully) very rare
case of having a high number of bad objects better.
Signed-off-by: René Scharfe <redacted>
---
midx.c | 13 ++++---------
object-store.h | 4 ++--
packfile.c | 27 +++++----------------------
3 files changed, 11 insertions(+), 33 deletions(-)
From: Jeff King <hidden> Date: 2021-09-11 14:26:46
On Sat, Sep 11, 2021 at 10:01:40AM +0200, René Scharfe wrote:
Store the object ID of broken pack entries in an oidset instead of
keeping only their hashes in an unsorted array. The resulting code is
shorter and easier to read. It also handles the (hopefully) very rare
case of having a high number of bad objects better.
Yay, I'm very happy to see this kind of cleanup replacing ad hoc data
structures with well-tested ones.
quoted hunk
@@ -303,15 +304,9 @@ static int nth_midxed_pack_entry(struct repository *r, if (!is_pack_valid(p)) return 0;- if (p->num_bad_objects) {- uint32_t i;- struct object_id oid;- nth_midxed_object_oid(&oid, m, pos);- for (i = 0; i < p->num_bad_objects; i++)- if (hasheq(oid.hash,- p->bad_object_sha1 + the_hash_algo->rawsz * i))- return 0;- }+ nth_midxed_object_oid(&oid, m, pos);+ if (oidset_contains(&p->bad_objects, &oid))+ return 0;
Calling nth_midxed_object_oid() implies a memcpy() under the hood. In
the old code, we'd skip that in the common case that we had no corrupt
objects, but now we'll pay the cost regardless. memcpy() isn't _that_
expensive, but I'd expect this to be a relatively hot code path.
Is it worth sticking all of this inside:
if (oidset_size(&p->bad_objects))
?
So now marking a bad object is a one-liner. We _could_ just inline it
at the callers, but I like keeping the implementation abstract.
const struct packed_git *has_packed_and_bad(struct repository *r,
const struct object_id *oid)
{
struct packed_git *p;
- unsigned i;
for (p = r->objects->packed_git; p; p = p->next)
- for (i = 0; i < p->num_bad_objects; i++)
- if (hasheq(oid->hash,
- p->bad_object_sha1 + the_hash_algo->rawsz * i))
- return p;
+ if (oidset_contains(&p->bad_objects, oid))
+ return p;
return NULL;
}
Not related to your patch, but I noticed how terribly inefficient this
function could be in a repo with a lot of packs. But we only call it
once in the error case right before we die(), so a linear scan is no
problem.
quoted hunk
@@ -2016,13 +2004,8 @@ static int fill_pack_entry(const struct object_id *oid, { off_t offset;- if (p->num_bad_objects) {- unsigned i;- for (i = 0; i < p->num_bad_objects; i++)- if (hasheq(oid->hash,- p->bad_object_sha1 + the_hash_algo->rawsz * i))- return 0;- }+ if (oidset_contains(&p->bad_objects, oid))+ return 0;
And this one (and the previous) have the oid already, so they don't have
to worry about optimizing the is-it-empty check first.
-Peff
From: Jeff King <hidden> Date: 2021-09-11 14:27:38
On Sat, Sep 11, 2021 at 09:50:36AM +0200, René Scharfe wrote:
Replace the custom hash array for remembering corrupt pack entries with
an oidset. This shortens and simplifies the code.
Thanks, these were a pleasure to read.
I noticed one possible small performance change in the third patch. It
should be easy to remedy if we want (but I could also believe that it
doesn't matter either way, if you care to argue that :) ).
-Peff
From: René Scharfe <hidden> Date: 2021-09-11 16:08:50
Am 11.09.21 um 16:26 schrieb Jeff King:
On Sat, Sep 11, 2021 at 10:01:40AM +0200, René Scharfe wrote:
quoted
Store the object ID of broken pack entries in an oidset instead of
keeping only their hashes in an unsorted array. The resulting code is
shorter and easier to read. It also handles the (hopefully) very rare
case of having a high number of bad objects better.
Yay, I'm very happy to see this kind of cleanup replacing ad hoc data
structures with well-tested ones.
quoted
@@ -303,15 +304,9 @@ static int nth_midxed_pack_entry(struct repository *r, if (!is_pack_valid(p)) return 0;- if (p->num_bad_objects) {- uint32_t i;- struct object_id oid;- nth_midxed_object_oid(&oid, m, pos);- for (i = 0; i < p->num_bad_objects; i++)- if (hasheq(oid.hash,- p->bad_object_sha1 + the_hash_algo->rawsz * i))- return 0;- }+ nth_midxed_object_oid(&oid, m, pos);+ if (oidset_contains(&p->bad_objects, &oid))+ return 0;
Calling nth_midxed_object_oid() implies a memcpy() under the hood. In
the old code, we'd skip that in the common case that we had no corrupt
objects, but now we'll pay the cost regardless. memcpy() isn't _that_
expensive, but I'd expect this to be a relatively hot code path.
Is it worth sticking all of this inside:
if (oidset_size(&p->bad_objects))
?
Hard to say. It would certainly match the old code more closely. Is a
function call cheaper than copying 32 bytes? Depends on the CPU and
whether the hash is cached, I guess. And cached it probably is, because
the caller did a binary search for it..
We can pass on the original oid to avoid the nth_midxed_object_oid()
call, but inlining the whole thing might even be nicer.
René
From: René Scharfe <hidden> Date: 2021-09-11 16:08:52
fill_midx_entry() finds the position of an object ID and passes it to
nth_midxed_pack_entry(), which uses the position to look up the object
ID for its own purposes. Inline the latter into the former to avoid
that lookup.
Signed-off-by: René Scharfe <redacted>
---
midx.c | 29 +++++++++--------------------
1 file changed, 9 insertions(+), 20 deletions(-)
@@ -304,8 +307,7 @@ static int nth_midxed_pack_entry(struct repository *r,if(!is_pack_valid(p))return0;-nth_midxed_object_oid(&oid,m,pos);-if(oidset_contains(&p->bad_objects,&oid))+if(oidset_contains(&p->bad_objects,oid))return0;e->offset=nth_midxed_offset(m,pos);
@@ -314,19 +316,6 @@ static int nth_midxed_pack_entry(struct repository *r,return1;}-intfill_midx_entry(structrepository*r,-conststructobject_id*oid,-structpack_entry*e,-structmulti_pack_index*m)-{-uint32_tpos;--if(!bsearch_midx(oid,m,&pos))-return0;--returnnth_midxed_pack_entry(r,m,e,pos);-}-/* Match "foo.idx" against either "foo.pack" _or_ "foo.idx". */staticintcmp_idx_or_pack_name(constchar*idx_or_pack_name,constchar*idx_name)--
From: Jeff King <hidden> Date: 2021-09-11 17:03:23
On Sat, Sep 11, 2021 at 06:08:38PM +0200, René Scharfe wrote:
quoted
quoted
+ nth_midxed_object_oid(&oid, m, pos);
+ if (oidset_contains(&p->bad_objects, &oid))
+ return 0;
Calling nth_midxed_object_oid() implies a memcpy() under the hood. In
the old code, we'd skip that in the common case that we had no corrupt
objects, but now we'll pay the cost regardless. memcpy() isn't _that_
expensive, but I'd expect this to be a relatively hot code path.
Is it worth sticking all of this inside:
if (oidset_size(&p->bad_objects))
?
Hard to say. It would certainly match the old code more closely. Is a
function call cheaper than copying 32 bytes? Depends on the CPU and
whether the hash is cached, I guess. And cached it probably is, because
the caller did a binary search for it..
You already have a function call for nth_midxed_object_oid(), so
checking oidset_size() would be a strict improvement.
We can pass on the original oid to avoid the nth_midxed_object_oid()
call, but inlining the whole thing might even be nicer.
Yeah, it occurs to me that oidset_size() would be a good candidate for
inlining, if that's what you mean.
-Peff
From: René Scharfe <hidden> Date: 2021-09-11 17:03:32
Am 11.09.21 um 18:08 schrieb René Scharfe:
fill_midx_entry() finds the position of an object ID and passes it to
nth_midxed_pack_entry(), which uses the position to look up the object
ID for its own purposes. Inline the latter into the former to avoid
that lookup.
From: Jeff King <hidden> Date: 2021-09-11 17:07:54
On Sat, Sep 11, 2021 at 06:08:42PM +0200, René Scharfe wrote:
fill_midx_entry() finds the position of an object ID and passes it to
nth_midxed_pack_entry(), which uses the position to look up the object
ID for its own purposes. Inline the latter into the former to avoid
that lookup.
Ah, I see what you mean now by "inline" in the other part of the thread.
Yes, I think this makes sense since there is no other reasonable caller
of the nth_midxed_pack_entry() helper (and its one caller is itself
trivial).
quoted hunk
@@ -304,8 +307,7 @@ static int nth_midxed_pack_entry(struct repository *r, if (!is_pack_valid(p)) return 0;- nth_midxed_object_oid(&oid, m, pos);- if (oidset_contains(&p->bad_objects, &oid))+ if (oidset_contains(&p->bad_objects, oid)) return 0;
So we get to avoid the nth_midxed_object_oid() copy entirely. Very nice.
Compared to the code before your series, we still have an extra function
call to oidset_contains(), which will (in the common case) notice we
have no entries and immediately return. But I think that's getting into
pointless micro-optimization.
-Peff
From: René Scharfe <hidden> Date: 2021-09-11 17:17:09
Am 11.09.21 um 19:03 schrieb Jeff King:
On Sat, Sep 11, 2021 at 06:08:38PM +0200, René Scharfe wrote:
quoted
quoted
quoted
+ nth_midxed_object_oid(&oid, m, pos);
+ if (oidset_contains(&p->bad_objects, &oid))
+ return 0;
Calling nth_midxed_object_oid() implies a memcpy() under the hood. In
the old code, we'd skip that in the common case that we had no corrupt
objects, but now we'll pay the cost regardless. memcpy() isn't _that_
expensive, but I'd expect this to be a relatively hot code path.
Is it worth sticking all of this inside:
if (oidset_size(&p->bad_objects))
?
Hard to say. It would certainly match the old code more closely. Is a
function call cheaper than copying 32 bytes? Depends on the CPU and
whether the hash is cached, I guess. And cached it probably is, because
the caller did a binary search for it..
You already have a function call for nth_midxed_object_oid(), so
checking oidset_size() would be a strict improvement.
If I read the assembly correctly nth_midxed_object_oid() is inlined by the
compiler in my build, as is nth_midxed_pack_entry(). Both are defined in
the same file, so other compilers may easily do the same.
quoted
We can pass on the original oid to avoid the nth_midxed_object_oid()
call, but inlining the whole thing might even be nicer.
Yeah, it occurs to me that oidset_size() would be a good candidate for
inlining, if that's what you mean.
True, but I meant something else (see patch 4/3). :)
René
From: René Scharfe <hidden> Date: 2021-09-11 20:32:06
Am 11.09.21 um 19:07 schrieb Jeff King:
On Sat, Sep 11, 2021 at 06:08:42PM +0200, René Scharfe wrote:
quoted
@@ -304,8 +307,7 @@ static int nth_midxed_pack_entry(struct repository *r, if (!is_pack_valid(p)) return 0;- nth_midxed_object_oid(&oid, m, pos);- if (oidset_contains(&p->bad_objects, &oid))+ if (oidset_contains(&p->bad_objects, oid)) return 0;
So we get to avoid the nth_midxed_object_oid() copy entirely. Very nice.
Compared to the code before your series, we still have an extra function
call to oidset_contains(), which will (in the common case) notice we
have no entries and immediately return. But I think that's getting into
pointless micro-optimization.
Right. I measure a 0.5% slowdown for git multi-pack-index verify. An
inline oidset_size call avoids it. That's easy enough to add, so let's
have it!
René
From: René Scharfe <hidden> Date: 2021-09-11 20:32:06
Replace the custom hash array for remembering corrupt pack entries with
an oidset. This shortens and simplifies the code.
Changes since v1:
- inline oidset_size()
- inline nth_midxed_pack_entry() early
- use oidset_size() to avoid a function call if no bad objects exist
oidset: make oidset_size() an inline function
midx: inline nth_midxed_pack_entry()
packfile: convert mark_bad_packed_object() to object_id
packfile: convert has_packed_and_bad() to object_id
packfile: use oidset for bad objects
midx.c | 37 +++++++++++--------------------------
object-file.c | 4 ++--
object-store.h | 4 ++--
oidset.c | 5 -----
oidset.h | 5 ++++-
packfile.c | 38 +++++++++++---------------------------
packfile.h | 4 ++--
7 files changed, 32 insertions(+), 65 deletions(-)
--
2.33.0
From: René Scharfe <hidden> Date: 2021-09-11 20:36:47
oidset_size() just reads a single word from memory and returns it.
Avoid the function call overhead for this trivial operation by turning
it into an inline function.
While we're at it, declare its parameter const to allow it to be used
on read-only oidsets.
Suggested-by: Jeff King <redacted>
Signed-off-by: René Scharfe <redacted>
---
oidset.c | 5 -----
oidset.h | 5 ++++-
2 files changed, 4 insertions(+), 6 deletions(-)
From: René Scharfe <hidden> Date: 2021-09-11 20:39:47
fill_midx_entry() finds the position of an object ID and passes it to
nth_midxed_pack_entry(), which uses the position to look up the object
ID for its own purposes. Inline the latter into the former to avoid
that lookup.
Signed-off-by: René Scharfe <redacted>
---
midx.c | 29 +++++++++--------------------
1 file changed, 9 insertions(+), 20 deletions(-)
@@ -305,10 +309,8 @@ static int nth_midxed_pack_entry(struct repository *r,if(p->num_bad_objects){uint32_ti;-structobject_idoid;-nth_midxed_object_oid(&oid,m,pos);for(i=0;i<p->num_bad_objects;i++)-if(hasheq(oid.hash,+if(hasheq(oid->hash,p->bad_object_sha1+the_hash_algo->rawsz*i))return0;}
@@ -319,19 +321,6 @@ static int nth_midxed_pack_entry(struct repository *r,return1;}-intfill_midx_entry(structrepository*r,-conststructobject_id*oid,-structpack_entry*e,-structmulti_pack_index*m)-{-uint32_tpos;--if(!bsearch_midx(oid,m,&pos))-return0;--returnnth_midxed_pack_entry(r,m,e,pos);-}-/* Match "foo.idx" against either "foo.pack" _or_ "foo.idx". */staticintcmp_idx_or_pack_name(constchar*idx_or_pack_name,constchar*idx_name)--
From: René Scharfe <hidden> Date: 2021-09-11 20:40:41
All callers have full object IDs, so pass them on instead of just their
hash member.
Signed-off-by: René Scharfe <redacted>
---
object-file.c | 2 +-
packfile.c | 12 ++++++------
packfile.h | 2 +-
3 files changed, 8 insertions(+), 8 deletions(-)
From: René Scharfe <hidden> Date: 2021-09-11 20:42:29
The single caller has a full object ID, so pass it on instead of just
its hash member.
Signed-off-by: René Scharfe <redacted>
---
object-file.c | 2 +-
packfile.c | 4 ++--
packfile.h | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
From: René Scharfe <hidden> Date: 2021-09-11 20:43:33
Store the object ID of broken pack entries in an oidset instead of
keeping only their hashes in an unsorted array. The resulting code is
shorter and easier to read. It also handles the (hopefully) very rare
case of having a high number of bad objects better.
Helped-by: Jeff King [off-list ref]
Signed-off-by: René Scharfe <redacted>
---
midx.c | 10 +++-------
object-store.h | 4 ++--
packfile.c | 28 ++++++----------------------
3 files changed, 11 insertions(+), 31 deletions(-)
From: René Scharfe <hidden> Date: 2021-09-11 20:45:24
Am 11.09.21 um 22:31 schrieb René Scharfe:
Replace the custom hash array for remembering corrupt pack entries with
an oidset. This shortens and simplifies the code.
Changes since v1:
- inline oidset_size()
- inline nth_midxed_pack_entry() early
- use oidset_size() to avoid a function call if no bad objects exist
- forgot to add "v2" to the subject of patches 1, 2, 3 :-/
René
From: Jeff King <hidden> Date: 2021-09-11 21:20:07
On Sat, Sep 11, 2021 at 10:31:34PM +0200, René Scharfe wrote:
Am 11.09.21 um 19:07 schrieb Jeff King:
quoted
On Sat, Sep 11, 2021 at 06:08:42PM +0200, René Scharfe wrote:
quoted
@@ -304,8 +307,7 @@ static int nth_midxed_pack_entry(struct repository *r, if (!is_pack_valid(p)) return 0;- nth_midxed_object_oid(&oid, m, pos);- if (oidset_contains(&p->bad_objects, &oid))+ if (oidset_contains(&p->bad_objects, oid)) return 0;
So we get to avoid the nth_midxed_object_oid() copy entirely. Very nice.
Compared to the code before your series, we still have an extra function
call to oidset_contains(), which will (in the common case) notice we
have no entries and immediately return. But I think that's getting into
pointless micro-optimization.
Right. I measure a 0.5% slowdown for git multi-pack-index verify. An
inline oidset_size call avoids it. That's easy enough to add, so let's
have it!
I don't mind that, but I wonder if we can have our cake and eat it, too.
oidset_contains() is short, too, and could be inlined. Or if we're
worried about the size of the embedded kh_get_oid_set() getting inlined,
we could do something like:
static inline int oidset_contains(const struct oidset *set, const
struct object_id *oid)
{
if (!oidset_size(set))
return 0;
return oidset_contains_func(set, oid);
}
That saves callers from having to deal with it, at the expense of a
slightly complicated oidset implementation.
I guess it's an extra integer comparison for callers that _do_ expect to
have a non-empty set. So maybe it is better left to the caller to
decide whether to optimize in this way.
(A totally inline oidset_contains() avoids the extra check, but possibly
at the cost of larger code size).
-Peff
From: Jeff King <hidden> Date: 2021-09-11 21:22:16
On Sat, Sep 11, 2021 at 10:31:52PM +0200, René Scharfe wrote:
Replace the custom hash array for remembering corrupt pack entries with
an oidset. This shortens and simplifies the code.
Changes since v1:
- inline oidset_size()
- inline nth_midxed_pack_entry() early
- use oidset_size() to avoid a function call if no bad objects exist
Thanks, these all look fine to me. I raised a question elsewhere in the
thread about inlining oidset_contains(), but I think that can be
considered separately (and is less clear-cut; we might win by saving a
function call, but we might lose due to larger code size).
-Peff
From: René Scharfe <hidden> Date: 2021-09-11 23:40:08
Am 11.09.21 um 23:20 schrieb Jeff King:
On Sat, Sep 11, 2021 at 10:31:34PM +0200, René Scharfe wrote:
quoted
Am 11.09.21 um 19:07 schrieb Jeff King:
quoted
On Sat, Sep 11, 2021 at 06:08:42PM +0200, René Scharfe wrote:
quoted
@@ -304,8 +307,7 @@ static int nth_midxed_pack_entry(struct repository *r, if (!is_pack_valid(p)) return 0;- nth_midxed_object_oid(&oid, m, pos);- if (oidset_contains(&p->bad_objects, &oid))+ if (oidset_contains(&p->bad_objects, oid)) return 0;
So we get to avoid the nth_midxed_object_oid() copy entirely. Very nice.
Compared to the code before your series, we still have an extra function
call to oidset_contains(), which will (in the common case) notice we
have no entries and immediately return. But I think that's getting into
pointless micro-optimization.
Right. I measure a 0.5% slowdown for git multi-pack-index verify. An
inline oidset_size call avoids it. That's easy enough to add, so let's
have it!
I don't mind that, but I wonder if we can have our cake and eat it, too.
oidset_contains() is short, too, and could be inlined. Or if we're
worried about the size of the embedded kh_get_oid_set() getting inlined,
we could do something like:
static inline int oidset_contains(const struct oidset *set, const
struct object_id *oid)
{
if (!oidset_size(set))
return 0;
return oidset_contains_func(set, oid);
}
That saves callers from having to deal with it, at the expense of a
slightly complicated oidset implementation.
I guess it's an extra integer comparison for callers that _do_ expect to
have a non-empty set. So maybe it is better left to the caller to
decide whether to optimize in this way.
(A totally inline oidset_contains() avoids the extra check, but possibly
at the cost of larger code size).
I wondered the same.
Inlining oidset_contains() would follow the spirit of khash. It adds
16KB to my build (ca. 688 bytes per caller). Hmm.
I expected the hybrid approach with an inlined emptiness check and a
shared actual contains function to be as fast as the original code, due
to caching. I actually saw the 0.1% slowdown of git multi-pack-index
verify when I added a fake bad object at the end of prepare_midx_pack()
to simulate a non-empty oidset. Hmm!
Both are probably defensible, but for this series I took the more
targeted approach to limit the impact.
René
Replace the custom hash array for remembering corrupt pack entries with
an oidset. This shortens and simplifies the code.
Changes since v1:
- inline oidset_size()
- inline nth_midxed_pack_entry() early
- use oidset_size() to avoid a function call if no bad objects exist
oidset: make oidset_size() an inline function
midx: inline nth_midxed_pack_entry()
packfile: convert mark_bad_packed_object() to object_id
packfile: convert has_packed_and_bad() to object_id
packfile: use oidset for bad objects
These were easy reads, and I understand the value of them.
I initially hesitated to support the drop of
nth_midxed_pack_entry(), since it was designed with things
like midx bitmaps in mind (specifically, to also support
lex-order-to-stable-order conversions). However, it seems
that the midx bitmap series by Taylor is succeeding without
needing such a translation.
Thanks,
-Stolee
From: Taylor Blau <hidden> Date: 2021-09-12 01:51:52
On Sat, Sep 11, 2021 at 07:59:40PM -0400, Derrick Stolee wrote:
I initially hesitated to support the drop of
nth_midxed_pack_entry(), since it was designed with things
like midx bitmaps in mind (specifically, to also support
lex-order-to-stable-order conversions).
I didn't know that nth_midxed_pack_entry was designed with either
purpose in mind, since it predates midx bitmaps by quite a bit.
However, it seems that the midx bitmap series by Taylor is succeeding
without needing such a translation.
Right, it looks like that function is only called by fill_midx_entry()
where it was inlined.
Thanks,
Taylor
From: Taylor Blau <hidden> Date: 2021-09-12 02:29:07
On Sat, Sep 11, 2021 at 09:51:04PM -0400, Taylor Blau wrote:
On Sat, Sep 11, 2021 at 07:59:40PM -0400, Derrick Stolee wrote:
quoted
I initially hesitated to support the drop of
nth_midxed_pack_entry(), since it was designed with things
like midx bitmaps in mind (specifically, to also support
lex-order-to-stable-order conversions).
I didn't know that nth_midxed_pack_entry was designed with either
purpose in mind, since it predates midx bitmaps by quite a bit.
Thinking on it more, I can imagine that you wrote this function
aspirationally envisioning something like MIDX bitmaps. And since you
and I discussed the design together quite a bit, I imagine that that's
the case ;-).
But I agree that after reading this series again, that the inline-ing
suggested makes sense (and doesn't conflict with any series I have in
flight which don't add any new callers).
Thanks,
Taylor
On Sat, Sep 11, 2021 at 09:51:04PM -0400, Taylor Blau wrote:
quoted
On Sat, Sep 11, 2021 at 07:59:40PM -0400, Derrick Stolee wrote:
quoted
I initially hesitated to support the drop of
nth_midxed_pack_entry(), since it was designed with things
like midx bitmaps in mind (specifically, to also support
lex-order-to-stable-order conversions).
I didn't know that nth_midxed_pack_entry was designed with either
purpose in mind, since it predates midx bitmaps by quite a bit.
Thinking on it more, I can imagine that you wrote this function
aspirationally envisioning something like MIDX bitmaps. And since you
and I discussed the design together quite a bit, I imagine that that's
the case ;-).
But I agree that after reading this series again, that the inline-ing
suggested makes sense (and doesn't conflict with any series I have in
flight which don't add any new callers).
I'm thinking more to my original design of the multi-pack-index.
At that time, I was thinking about the possible integration
with bitmaps based on my experience in other systems which used
a stable object order to allow writing bitmaps asynchronously
with respect to the multi-pack-index write and object packing.
One thing that you did when first considering bitmaps over the
multi-pack-index was to demonstrate that a stable object order
is not required, which surprised and delighted me. It greatly
reduced the complexity of the problem, and being able to inline
this method is only one small fallout from that simplicity.
Thanks,
-Stolee
From: Taylor Blau <hidden> Date: 2021-09-12 04:01:45
On Sat, Sep 11, 2021 at 11:51:36PM -0400, Derrick Stolee wrote:
On 9/11/21 10:29 PM, Taylor Blau wrote:
quoted
On Sat, Sep 11, 2021 at 09:51:04PM -0400, Taylor Blau wrote:
quoted
On Sat, Sep 11, 2021 at 07:59:40PM -0400, Derrick Stolee wrote:
quoted
I initially hesitated to support the drop of
nth_midxed_pack_entry(), since it was designed with things
like midx bitmaps in mind (specifically, to also support
lex-order-to-stable-order conversions).
I didn't know that nth_midxed_pack_entry was designed with either
purpose in mind, since it predates midx bitmaps by quite a bit.
Thinking on it more, I can imagine that you wrote this function
aspirationally envisioning something like MIDX bitmaps. And since you
and I discussed the design together quite a bit, I imagine that that's
the case ;-).
But I agree that after reading this series again, that the inline-ing
suggested makes sense (and doesn't conflict with any series I have in
flight which don't add any new callers).
I'm thinking more to my original design of the multi-pack-index.
At that time, I was thinking about the possible integration
with bitmaps based on my experience in other systems which used
a stable object order to allow writing bitmaps asynchronously
with respect to the multi-pack-index write and object packing.
Makes sense, and thank you for clarifying. After re-reading my first
email, I figured that this is what you must have been talking about,
which is why I felt like I should rephrase (hence the follow-up email).
One thing that you did when first considering bitmaps over the
multi-pack-index was to demonstrate that a stable object order
is not required, which surprised and delighted me. It greatly
reduced the complexity of the problem, and being able to inline
this method is only one small fallout from that simplicity.
This was definitely a consequence of what I had observed from seeing
what was "slow" when running bitmaps in production at GitHub. There,
repacking a repository's objects all into one pack each time we ran our
automated background jobs far outpaced the amount of time we spent
generating bitmaps.
And with your and Peff's work on improving bitmap generation itself,
things are in a pretty good place. I do have some potential ideas for
future improvement, like a mode where bitmaps are only "fast forwarded",
meaning that new bitmaps are only added between the commits selected for
bitmapping in the previous round and the current reference tips.
I think things like that end up getting you pretty far, but it may be
interesting to come back eventually and revisit adding a stable object
order. In the meantime, though... ;)
Thanks,
Taylor