* [PATCH 0/3] connected: search promisor objects generically
@ 2026-06-22 8:49 Patrick Steinhardt
2026-06-22 8:49 ` [PATCH 1/3] odb/source-packed: extract logic to skip certain packs Patrick Steinhardt
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Patrick Steinhardt @ 2026-06-22 8:49 UTC (permalink / raw)
To: git
Hi,
this patch series refactors "connected.c" so that we search for promisor
objects in a generic way instead of reaching into internal of the object
database. As a result, the connectivity checks will work properly in
repos that don't use packfiles in the first place.
The series is built on top of 8d96f09e92 (Merge branch
'js/objects-larger-than-4gb-on-windows', 2026-06-19) with
ps/odb-source-packed at 1bba3c035d (odb/source-packed: drop pointer to
"files" parent source, 2026-06-17) merged into it.
Thanks!
Patrick
---
Patrick Steinhardt (3):
odb/source-packed: extract logic to skip certain packs
odb/source-packed: support flags when iterating an object prefix
connected: search promisor objects generically
connected.c | 39 +++++++++++++++++++++++++--------------
odb/source-packed.c | 50 +++++++++++++++++++++++++++++++++++++-------------
2 files changed, 62 insertions(+), 27 deletions(-)
---
base-commit: 4a8e7a446f41435e157131162dfe901eca9250fe
change-id: 20260612-pks-connected-generic-promisor-checks-2933bff3028d
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/3] odb/source-packed: extract logic to skip certain packs
2026-06-22 8:49 [PATCH 0/3] connected: search promisor objects generically Patrick Steinhardt
@ 2026-06-22 8:49 ` Patrick Steinhardt
2026-06-22 17:51 ` Junio C Hamano
2026-06-22 8:49 ` [PATCH 2/3] odb/source-packed: support flags when iterating an object prefix Patrick Steinhardt
2026-06-22 8:49 ` [PATCH 3/3] connected: search promisor objects generically Patrick Steinhardt
2 siblings, 1 reply; 6+ messages in thread
From: Patrick Steinhardt @ 2026-06-22 8:49 UTC (permalink / raw)
To: git
The caller can pass flags that allow them to filter out specific kinds
of objects when iterating objects via `odb_for_each_object()`. This only
works for "normal" iteration though, as we `BUG()` when the user passes
flags and specifies an object prefix.
This limitation will be lifted in the next commit. Prepare for this by
extracting the logic that skips certain kinds of packs so that we can
easily reuse it.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
odb/source-packed.c | 28 ++++++++++++++++++----------
1 file changed, 18 insertions(+), 10 deletions(-)
diff --git a/odb/source-packed.c b/odb/source-packed.c
index 42c28fba0e..3afc4bf01f 100644
--- a/odb/source-packed.c
+++ b/odb/source-packed.c
@@ -126,6 +126,22 @@ static int match_hash(unsigned len, const unsigned char *a, const unsigned char
return 1;
}
+static bool should_exclude_pack(struct packed_git *p, enum odb_for_each_object_flags flags)
+{
+ if ((flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
+ return true;
+ if ((flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY) &&
+ !p->pack_promisor)
+ return true;
+ if ((flags & ODB_FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS) &&
+ p->pack_keep_in_core)
+ return true;
+ if ((flags & ODB_FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS) &&
+ p->pack_keep)
+ return true;
+ return false;
+}
+
static int for_each_prefixed_object_in_midx(
struct odb_source_packed *store,
struct multi_pack_index *m,
@@ -306,17 +322,9 @@ static int odb_source_packed_for_each_object(struct odb_source *source,
for (e = packfile_store_get_packs(packed); e; e = e->next) {
struct packed_git *p = e->pack;
- if ((opts->flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
- continue;
- if ((opts->flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY) &&
- !p->pack_promisor)
- continue;
- if ((opts->flags & ODB_FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS) &&
- p->pack_keep_in_core)
- continue;
- if ((opts->flags & ODB_FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS) &&
- p->pack_keep)
+ if (should_exclude_pack(p, opts->flags))
continue;
+
if (open_pack_index(p)) {
pack_errors = 1;
continue;
--
2.55.0.rc1.745.g43192e7977.dirty
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/3] odb/source-packed: support flags when iterating an object prefix
2026-06-22 8:49 [PATCH 0/3] connected: search promisor objects generically Patrick Steinhardt
2026-06-22 8:49 ` [PATCH 1/3] odb/source-packed: extract logic to skip certain packs Patrick Steinhardt
@ 2026-06-22 8:49 ` Patrick Steinhardt
2026-06-22 8:49 ` [PATCH 3/3] connected: search promisor objects generically Patrick Steinhardt
2 siblings, 0 replies; 6+ messages in thread
From: Patrick Steinhardt @ 2026-06-22 8:49 UTC (permalink / raw)
To: git
Callers of `odb_for_each_object()` can specify an optional object name
prefix so that we only yield objects that match it. This is incompatible
though with passing flags at the same time, as we don't yet know to
handle them.
Loosen this restriction by calling `should_exclude_pack()`.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
odb/source-packed.c | 22 +++++++++++++++++++---
1 file changed, 19 insertions(+), 3 deletions(-)
diff --git a/odb/source-packed.c b/odb/source-packed.c
index 3afc4bf01f..6f31f0ff94 100644
--- a/odb/source-packed.c
+++ b/odb/source-packed.c
@@ -148,6 +148,7 @@ static int for_each_prefixed_object_in_midx(
const struct odb_for_each_object_options *opts,
struct odb_source_packed_for_each_object_wrapper_data *data)
{
+ bool pack_errors = false;
int ret;
for (; m; m = m->base_midx) {
@@ -171,6 +172,20 @@ static int for_each_prefixed_object_in_midx(
const struct object_id *current = NULL;
struct object_id oid;
+ if (opts->flags) {
+ uint32_t pack_id = nth_midxed_pack_int_id(m, i);
+ struct packed_git *pack;
+
+ if (prepare_midx_pack(m, pack_id)) {
+ pack_errors = true;
+ continue;
+ }
+
+ pack = nth_midxed_pack(m, pack_id);
+ if (should_exclude_pack(pack, opts->flags))
+ continue;
+ }
+
current = nth_midxed_object_oid(&oid, m, i);
if (!match_hash(len, opts->prefix->hash, current->hash))
@@ -198,6 +213,8 @@ static int for_each_prefixed_object_in_midx(
ret = 0;
out:
+ if (!ret && pack_errors)
+ ret = -1;
return ret;
}
@@ -260,9 +277,6 @@ static int odb_source_packed_for_each_prefixed_object(
bool pack_errors = false;
int ret;
- if (opts->flags)
- BUG("flags unsupported");
-
store->skip_mru_updates = true;
m = get_multi_pack_index(store);
@@ -275,6 +289,8 @@ static int odb_source_packed_for_each_prefixed_object(
for (e = packfile_store_get_packs(store); e; e = e->next) {
if (e->pack->multi_pack_index)
continue;
+ if (should_exclude_pack(e->pack, opts->flags))
+ continue;
if (open_pack_index(e->pack)) {
pack_errors = true;
--
2.55.0.rc1.745.g43192e7977.dirty
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 3/3] connected: search promisor objects generically
2026-06-22 8:49 [PATCH 0/3] connected: search promisor objects generically Patrick Steinhardt
2026-06-22 8:49 ` [PATCH 1/3] odb/source-packed: extract logic to skip certain packs Patrick Steinhardt
2026-06-22 8:49 ` [PATCH 2/3] odb/source-packed: support flags when iterating an object prefix Patrick Steinhardt
@ 2026-06-22 8:49 ` Patrick Steinhardt
2026-06-22 17:57 ` Junio C Hamano
2 siblings, 1 reply; 6+ messages in thread
From: Patrick Steinhardt @ 2026-06-22 8:49 UTC (permalink / raw)
To: git
When performing connectivity checks we have to figure out whether any of
the new objects are promisor objects, as we cannot assume full
connectivity if so.
This check is performed by iterating through all packfiles in the
repository and searching each of them for the given object. Of course,
this mechanism is quite specific to implementation details of the object
database, as we assume that it uses packfiles in the first place.
Refactor the logic so that we instead use `odb_for_each_object_ext()`
with an object prefix filter and the `ODB_FOR_EACH_OBJECT_PROMISOR_ONLY`
flag. This will yield all objects that have the exact object name and
that are part of a promisor pack in a generic way.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
connected.c | 39 +++++++++++++++++++++++++--------------
1 file changed, 25 insertions(+), 14 deletions(-)
diff --git a/connected.c b/connected.c
index 7e26976832..9a666f0cdf 100644
--- a/connected.c
+++ b/connected.c
@@ -11,6 +11,13 @@
#include "packfile.h"
#include "promisor-remote.h"
+static int promised_object_cb(const struct object_id *oid UNUSED,
+ struct object_info *oi UNUSED,
+ void *payload UNUSED)
+{
+ return 1;
+}
+
/*
* If we feed all the commits we want to verify to this command
*
@@ -46,6 +53,11 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
}
if (repo_has_promisor_remote(the_repository)) {
+ struct odb_for_each_object_options opts = {
+ .flags = ODB_FOR_EACH_OBJECT_PROMISOR_ONLY,
+ .prefix_hex_len = the_repository->hash_algo->hexsz,
+ };
+
/*
* For partial clones, we don't want to have to do a regular
* connectivity check because we have to enumerate and exclude
@@ -54,31 +66,30 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
* object is a promisor object. Instead, just make sure we
* received, in a promisor packfile, the objects pointed to by
* each wanted ref.
- *
- * Before checking for promisor packs, be sure we have the
- * latest pack-files loaded into memory.
*/
- odb_reprepare(the_repository->objects);
do {
- struct packed_git *p;
-
- repo_for_each_pack(the_repository, p) {
- if (!p->pack_promisor)
- continue;
- if (find_pack_entry_one(oid, p))
- goto promisor_pack_found;
+ opts.prefix = oid;
+
+ err = odb_for_each_object_ext(the_repository->objects,
+ NULL, promised_object_cb,
+ NULL, &opts);
+ if (err < 0)
+ break;
+ if (err > 0) {
+ err = 0;
+ continue;
}
+
/*
* Fallback to rev-list with oid and the rest of the
* object IDs provided by fn.
*/
goto no_promisor_pack_found;
-promisor_pack_found:
- ;
} while ((oid = fn(cb_data)) != NULL);
+
if (opt->err_fd)
close(opt->err_fd);
- return 0;
+ return err;
}
no_promisor_pack_found:
--
2.55.0.rc1.745.g43192e7977.dirty
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 1/3] odb/source-packed: extract logic to skip certain packs
2026-06-22 8:49 ` [PATCH 1/3] odb/source-packed: extract logic to skip certain packs Patrick Steinhardt
@ 2026-06-22 17:51 ` Junio C Hamano
0 siblings, 0 replies; 6+ messages in thread
From: Junio C Hamano @ 2026-06-22 17:51 UTC (permalink / raw)
To: Patrick Steinhardt; +Cc: git
Patrick Steinhardt <ps@pks.im> writes:
> The caller can pass flags that allow them to filter out specific kinds
> of objects when iterating objects via `odb_for_each_object()`. This only
> works for "normal" iteration though, as we `BUG()` when the user passes
> flags and specifies an object prefix.
>
> This limitation will be lifted in the next commit. Prepare for this by
> extracting the logic that skips certain kinds of packs so that we can
> easily reuse it.
>
> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
> odb/source-packed.c | 28 ++++++++++++++++++----------
> 1 file changed, 18 insertions(+), 10 deletions(-)
Quite straight-forward creation of a simple helper function.
> diff --git a/odb/source-packed.c b/odb/source-packed.c
> index 42c28fba0e..3afc4bf01f 100644
> --- a/odb/source-packed.c
> +++ b/odb/source-packed.c
> @@ -126,6 +126,22 @@ static int match_hash(unsigned len, const unsigned char *a, const unsigned char
> return 1;
> }
>
> +static bool should_exclude_pack(struct packed_git *p, enum odb_for_each_object_flags flags)
> +{
> + if ((flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
> + return true;
> + if ((flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY) &&
> + !p->pack_promisor)
> + return true;
> + if ((flags & ODB_FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS) &&
> + p->pack_keep_in_core)
> + return true;
> + if ((flags & ODB_FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS) &&
> + p->pack_keep)
> + return true;
> + return false;
> +}
> +
> static int for_each_prefixed_object_in_midx(
> struct odb_source_packed *store,
> struct multi_pack_index *m,
> @@ -306,17 +322,9 @@ static int odb_source_packed_for_each_object(struct odb_source *source,
> for (e = packfile_store_get_packs(packed); e; e = e->next) {
> struct packed_git *p = e->pack;
>
> - if ((opts->flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
> - continue;
> - if ((opts->flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY) &&
> - !p->pack_promisor)
> - continue;
> - if ((opts->flags & ODB_FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS) &&
> - p->pack_keep_in_core)
> - continue;
> - if ((opts->flags & ODB_FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS) &&
> - p->pack_keep)
> + if (should_exclude_pack(p, opts->flags))
> continue;
> +
> if (open_pack_index(p)) {
> pack_errors = 1;
> continue;
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 3/3] connected: search promisor objects generically
2026-06-22 8:49 ` [PATCH 3/3] connected: search promisor objects generically Patrick Steinhardt
@ 2026-06-22 17:57 ` Junio C Hamano
0 siblings, 0 replies; 6+ messages in thread
From: Junio C Hamano @ 2026-06-22 17:57 UTC (permalink / raw)
To: Patrick Steinhardt; +Cc: git
Patrick Steinhardt <ps@pks.im> writes:
> When performing connectivity checks we have to figure out whether any of
> the new objects are promisor objects, as we cannot assume full
> connectivity if so.
>
> This check is performed by iterating through all packfiles in the
> repository and searching each of them for the given object. Of course,
> this mechanism is quite specific to implementation details of the object
> database, as we assume that it uses packfiles in the first place.
>
> Refactor the logic so that we instead use `odb_for_each_object_ext()`
> with an object prefix filter and the `ODB_FOR_EACH_OBJECT_PROMISOR_ONLY`
> flag. This will yield all objects that have the exact object name and
> that are part of a promisor pack in a generic way.
> ...
> - *
> - * Before checking for promisor packs, be sure we have the
> - * latest pack-files loaded into memory.
> */
> - odb_reprepare(the_repository->objects);
Hmph?
> do {
> - struct packed_git *p;
> -
> - repo_for_each_pack(the_repository, p) {
> - if (!p->pack_promisor)
> - continue;
> - if (find_pack_entry_one(oid, p))
> - goto promisor_pack_found;
> + opts.prefix = oid;
> +
> + err = odb_for_each_object_ext(the_repository->objects,
> + NULL, promised_object_cb,
> + NULL, &opts);
> + if (err < 0)
> + break;
> + if (err > 0) {
> + err = 0;
> + continue;
> }
So we used to manually iterate and stop when we have a matching pack
entry, but now "stop when we find" is done by promisor_object_cb
callback that returns 1.
What is the reason why we no longer odb_(re)prepare() upfront before
going into the loop? Would it make us miss a newly added promisor
packs? We will fall back to rev-list for correctness, so it may not
matter, though.
> +
> /*
> * Fallback to rev-list with oid and the rest of the
> * object IDs provided by fn.
> */
> goto no_promisor_pack_found;
> -promisor_pack_found:
> - ;
> } while ((oid = fn(cb_data)) != NULL);
> +
> if (opt->err_fd)
> close(opt->err_fd);
> - return 0;
> + return err;
> }
>
> no_promisor_pack_found:
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-06-22 17:57 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-22 8:49 [PATCH 0/3] connected: search promisor objects generically Patrick Steinhardt
2026-06-22 8:49 ` [PATCH 1/3] odb/source-packed: extract logic to skip certain packs Patrick Steinhardt
2026-06-22 17:51 ` Junio C Hamano
2026-06-22 8:49 ` [PATCH 2/3] odb/source-packed: support flags when iterating an object prefix Patrick Steinhardt
2026-06-22 8:49 ` [PATCH 3/3] connected: search promisor objects generically Patrick Steinhardt
2026-06-22 17:57 ` Junio C Hamano
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox