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

Re: [PATCH 1/9] refs: make _advance() check struct repo, not flag

From
Junio C Hamano <gitster@pobox.com>
Date
Sep 23, 2021, 01:00 UTC
Message-ID
<xmqq1r5g3y2j.fsf@gitster.g>
In-Reply-To
<493fff7f4716d889da751b5f8c6740cc1e3aa360.1632242495.git.jonathantanmy@google.com>
Jonathan Tan <jonathantanmy@google.com> writes:
Show 7 quoted lines
> As a first step in resolving both these problems, replace the
> DO_FOR_EACH_INCLUDE_BROKEN flag with a struct repository pointer. This
> commit is a mechanical conversion - whenever DO_FOR_EACH_INCLUDE_BROKEN
> is set, a NULL repository (representing access to no object store) is
> used instead, and whenever DO_FOR_EACH_INCLUDE_BROKEN is unset, a
> non-NULL repository (representing access to that repository's object
> store) is used instead.

Hmph, so the lack of "include broken" is a signal to validate the object the ref points at, and the new parameter is "if this pointer is not NULL, then expect to find the object in this repository and validate it" that replaces the original "validate it" with a bit more detailed instruction (i.e. "how to validate--use the object store associated to this repository")?

> Right now, the locations in which
> non-the_repository support needs to be added are marked with BUG()
> statements - in a future patch, these will be replaced. (NEEDSWORK: in
> this RFC patch set, this has not been done)
Show 6 quoted lines
> - Change the _advance() callback to also have a repository object
>   parameter, and either skip or not skip depending on whether that
>   parameter is NULL. This burdens callers to have to carry this
>   information along with the iterator, and such calling code may be
>   unclear as to why that parameter can be NULL in some cases and cannot
>   in others.
Hmph.  
Show 21 quoted lines
> diff --git a/refs.c b/refs.c
> index 8b9f7c3a80..49ddcdac53 100644
> --- a/refs.c
> +++ b/refs.c
> @@ -1413,16 +1413,16 @@ int head_ref(each_ref_fn fn, void *cb_data)
>  
>  struct ref_iterator *refs_ref_iterator_begin(
>  		struct ref_store *refs,
> -		const char *prefix, int trim, int flags)
> +		const char *prefix, int trim, struct repository *repo,
> +		int flags)
>  {
>  	struct ref_iterator *iter;
>  
>  	if (ref_paranoia < 0)
>  		ref_paranoia = git_env_bool("GIT_REF_PARANOIA", 0);
> -	if (ref_paranoia)
> -		flags |= DO_FOR_EACH_INCLUDE_BROKEN;
>  
>  	iter = refs->be->iterator_begin(refs, prefix, flags);
> +	iter->repo = ref_paranoia ? NULL : repo;

OK. "flags" is still kept because there are bits other than "include broken" that need to be propagated.

Show 18 quoted lines
> @@ -1442,13 +1442,16 @@ struct ref_iterator *refs_ref_iterator_begin(
>   * Call fn for each reference in the specified submodule for which the
>   * refname begins with prefix. If trim is non-zero, then trim that
>   * many characters off the beginning of each refname before passing
> - * the refname to fn. flags can be DO_FOR_EACH_INCLUDE_BROKEN to
> - * include broken references in the iteration. If fn ever returns a
> + * the refname to fn. If fn ever returns a
>   * non-zero value, stop the iteration and return that value;
>   * otherwise, return 0.
> + *
> + * See the documentation of refs_ref_iterator_begin() for more information on
> + * the repo parameter.
>   */
>  static int do_for_each_repo_ref(struct repository *r, const char *prefix,
> -				each_repo_ref_fn fn, int trim, int flags,
> +				each_repo_ref_fn fn, int trim,
> +				struct repository *repo, int flags,
>  				void *cb_data)

Confusing. We are iterating refs that exists in the repository "r", right? Why do we need to have an extra "repo" parameter? Can they ever diverge (beyond repo could be NULL to signal now-lost "include broken" bit wanted to convey)? It's not like a valid caller can pass the superproject in 'r' and a submodule in 'repo', right?

Enhancing an interface this way, and allowing an arbitrary repository instance to be passed only to convey one bit of information, by adding a "repo" smells like inviting bugs in the future.

I have a feeling that the function signature for this one should stay as before, and "repo" should be a local variable that is initialized as

	struct repository *repo = (flags & DO_FOR_EACH_INCLUDE_BROKEN)
				? r
				: NULL;

to avoid such a future bug, but given that there is only one caller to this helper, I do not mind

	if (repo && r != repo)
		BUG(...);
to catch any such mistake.
Show 7 quoted lines
>  int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data)
>  {
>  	return do_for_each_repo_ref(r, git_replace_ref_base, fn,
>  				    strlen(git_replace_ref_base),
> -				    DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
> +				    NULL, 0, cb_data);
>  }
And this is the only such caller, if I am reading the code right.

Do we ever pass non-NULL "repo" to do_for_each_repo_ref() in future steps?

If not, perhaps we do not even have to add "repo" as a new parameter to do_for_each_repo_ref(), and instead always pass NULL down to refs_ref_iterator_begin() from do_for_each_repo_ref()?

Show 27 quoted lines
> diff --git a/refs/files-backend.c b/refs/files-backend.c
> index 677b7e4cdd..cd145301d0 100644
> --- a/refs/files-backend.c
> +++ b/refs/files-backend.c
> @@ -744,12 +744,6 @@ static int files_ref_iterator_advance(struct ref_iterator *ref_iterator)
>  		    ref_type(iter->iter0->refname) != REF_TYPE_PER_WORKTREE)
>  			continue;
>  
> -		if (!(iter->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
> -		    !ref_resolves_to_object(iter->iter0->refname,
> -					    iter->iter0->oid,
> -					    iter->iter0->flags))
> -			continue;
> -
>  		iter->base.refname = iter->iter0->refname;
>  		iter->base.oid = iter->iter0->oid;
>  		iter->base.flags = iter->iter0->flags;
> @@ -801,9 +795,6 @@ static struct ref_iterator *files_ref_iterator_begin(
>  	struct ref_iterator *ref_iterator;
>  	unsigned int required_flags = REF_STORE_READ;
>  
> -	if (!(flags & DO_FOR_EACH_INCLUDE_BROKEN))
> -		required_flags |= REF_STORE_ODB;
> -
>  	refs = files_downcast(ref_store, required_flags, "ref_iterator_begin");
>  
>  	/*

Hmph, I am not sure where the lossage in these two hunks are compensated. Perhaps in the backend independent layer in refs/iterator.c? Let's read on.

Show 12 quoted lines
> @@ -836,10 +827,13 @@ static struct ref_iterator *files_ref_iterator_begin(
>  	 * references, and (if needed) do our own check for broken
>  	 * ones in files_ref_iterator_advance(), after we have merged
>  	 * the packed and loose references.
> +	 *
> +	 * Do this by not supplying any repo, regardless of whether a repo was
> +	 * supplied to files_ref_iterator_begin().
>  	 */
>  	packed_iter = refs_ref_iterator_begin(
>  			refs->packed_ref_store, prefix, 0,
> -			DO_FOR_EACH_INCLUDE_BROKEN);
> +			NULL, 0);
OK.
Show 12 quoted lines
> diff --git a/refs/iterator.c b/refs/iterator.c
> index a89d132d4f..5af6554887 100644
> --- a/refs/iterator.c
> +++ b/refs/iterator.c
> @@ -10,7 +10,23 @@
>  
>  int ref_iterator_advance(struct ref_iterator *ref_iterator)
>  {
> -	return ref_iterator->vtable->advance(ref_iterator);
> +	int ok;
> +
> +	if (ref_iterator->repo && ref_iterator->repo != the_repository)

OK. refs_ref_interator_begin() assigned the "repo" parameter that tells which repository to consult to validate the objects at the tip of refs to the .repo member of the iterator object, and we check it here.

It is a bit surprising that ref_iterator does not know which repository it is working in (regardless of "include broken" bit). Do you think it will stay that way? I have this nagging feeling that it won't, and having "struct repository *repository" pointer that always points at the repository the ref-store belongs to in a ref_iterator instance would become necessary in the longer run.

In which case, this .repo member this patch adds would become a big problem, no? If we were to validate objects at the tip of the refs against object store, we will always use the object store that belongs to the iterator->repository, so the only valid states for iterator->repo are either NULL or iterator->repository. That again is the same problem I pointed out already about the parameter the do_for_each_repo_ref() helper that is inviting future bugs, it seems to me. Wouldn't it make more sense to add

 * iterator->repository that points at the repository in which we
   are iterating the refs
 * a bit in iterator that chooses between "do not bother checking"
   and "do check the tip of refs against the object store of
   iterator->repository

to avoid such a mess? Perhaps we already have such a bit in the flags word in the ref_iterator but I didn't check.

Thanks.
Previous: Jonathan TanNext: Jonathan Tan
Message 3 of 65 in “No more adding submodule ODB as alternate”
  1. 0/9 No more adding submodule ODB as alternateJonathan Tan, Sep 21, 2021
  2. 1/9 refs: make _advance() check struct repo, not flagJonathan Tan, Sep 21, 2021
  3. Junio C HamanoSep 23, 2021
  4. Jonathan TanSep 24, 2021
  5. Junio C HamanoSep 24, 2021
  6. Jeff KingSep 24, 2021
  7. Jonathan TanSep 24, 2021
  8. 2/9 refs: add repo paramater to _iterator_peel()Jonathan Tan, Sep 21, 2021
  9. 3/9 refs iterator: support non-the_repository advanceJonathan Tan, Sep 21, 2021
  10. 4/9 refs: teach refs_for_each_ref() arbitrary reposJonathan Tan, Sep 21, 2021
  11. 5/9 merge-{ort,recursive}: remove add_submodule_odb()Jonathan Tan, Sep 21, 2021
  12. Elijah NewrenSep 28, 2021
  13. 6/9 object-file: only register submodule ODB if neededJonathan Tan, Sep 21, 2021
  14. 7/9 submodule: pass repo to check_has_commit()Jonathan Tan, Sep 21, 2021
  15. 8/9 refs: change refs_for_each_ref_in() to take repoJonathan Tan, Sep 21, 2021
  16. 9/9 submodule: trace adding submodule ODB as alternateJonathan Tan, Sep 21, 2021
  17. Junio C HamanoSep 23, 2021
  18. 0/9 No more adding submodule ODB as alternateJonathan Tan, Sep 28, 2021
  19. 1/9 refs: plumb repo param in begin-iterator functionsJonathan Tan, Sep 28, 2021
  20. Junio C HamanoSep 28, 2021
  21. 2/9 refs: teach arbitrary repo support to iteratorsJonathan Tan, Sep 28, 2021
  22. Junio C HamanoSep 28, 2021
  23. Jonathan TanSep 29, 2021
  24. 3/9 refs: peeling non-the_repository iterators is BUGJonathan Tan, Sep 28, 2021
  25. 4/9 refs: teach refs_for_each_ref() arbitrary reposJonathan Tan, Sep 28, 2021
  26. Junio C HamanoSep 28, 2021
  27. 5/9 merge-{ort,recursive}: remove add_submodule_odb()Jonathan Tan, Sep 28, 2021
  28. 6/9 object-file: only register submodule ODB if neededJonathan Tan, Sep 28, 2021
  29. 7/9 submodule: pass repo to check_has_commit()Jonathan Tan, Sep 28, 2021
  30. 8/9 refs: change refs_for_each_ref_in() to take repoJonathan Tan, Sep 28, 2021
  31. 9/9 submodule: trace adding submodule ODB as alternateJonathan Tan, Sep 28, 2021
  32. 0/7 No more adding submodule ODB as alternateJonathan Tan, Sep 29, 2021
  33. 1/7 refs: plumb repo into ref storesJonathan Tan, Sep 29, 2021
  34. fixup! refs: plumb repo into ref storesCarlo Marcelo Arenas Belón, Sep 30, 2021
  35. fixup! refs: plumb repo into ref storesGlen Choo, Oct 6, 2021
  36. Jonathan TanOct 8, 2021
  37. Jonathan TanOct 8, 2021
  38. Josh SteadmonOct 7, 2021
  39. Jonathan TanOct 8, 2021
  40. 2/7 refs: teach arbitrary repo support to iteratorsJonathan Tan, Sep 29, 2021
  41. Glen ChooOct 7, 2021
  42. Jonathan TanOct 8, 2021
  43. 3/7 refs: peeling non-the_repository iterators is BUGJonathan Tan, Sep 29, 2021
  44. 5/7 object-file: only register submodule ODB if neededJonathan Tan, Sep 29, 2021
  45. Josh SteadmonOct 7, 2021
  46. Jonathan TanOct 8, 2021
  47. 4/7 merge-{ort,recursive}: remove add_submodule_odb()Jonathan Tan, Sep 29, 2021
  48. Josh SteadmonOct 7, 2021
  49. Jonathan TanOct 8, 2021
  50. 6/7 submodule: pass repo to check_has_commit()Jonathan Tan, Sep 29, 2021
  51. 7/7 submodule: trace adding submodule ODB as alternateJonathan Tan, Sep 29, 2021
  52. Josh SteadmonOct 7, 2021
  53. Jonathan TanOct 8, 2021
  54. Josh SteadmonOct 7, 2021
  55. 0/7 No more adding submodule ODB as alternateJonathan Tan, Oct 8, 2021
  56. 1/7 refs: plumb repo into ref storesJonathan Tan, Oct 8, 2021
  57. 2/7 refs: teach arbitrary repo support to iteratorsJonathan Tan, Oct 8, 2021
  58. 3/7 refs: peeling non-the_repository iterators is BUGJonathan Tan, Oct 8, 2021
  59. 4/7 merge-{ort,recursive}: remove add_submodule_odb()Jonathan Tan, Oct 8, 2021
  60. 5/7 object-file: only register submodule ODB if neededJonathan Tan, Oct 8, 2021
  61. 6/7 submodule: pass repo to check_has_commit()Jonathan Tan, Oct 8, 2021
  62. 7/7 submodule: trace adding submodule ODB as alternateJonathan Tan, Oct 8, 2021
  63. Glen ChooOct 12, 2021
  64. Josh SteadmonOct 12, 2021
  65. Junio C HamanoOct 12, 2021

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.