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

Re: [PATCH 04/20] refs_verify_refname_available(): implement once for all backends

From
Michael Haggerty <mhagger@alum.mit.edu>
Date
Mar 20, 2017, 22:20 UTC
Message-ID
<6ff4a9f9-23a5-89c9-f478-00449132d410@alum.mit.edu>
In-Reply-To
<20170320174240.gykldqzbqyva6kbs@sigill.intra.peff.net>
On 03/20/2017 06:42 PM, Jeff King wrote:
Show 11 quoted lines
> On Mon, Mar 20, 2017 at 05:33:09PM +0100, Michael Haggerty wrote:
> 
>> It turns out that we can now implement
>> `refs_verify_refname_available()` based on the other virtual
>> functions, so there is no need for it to be defined at the backend
>> level. Instead, define it once in `refs.c` and remove the
>> `files_backend` definition.
> 
> Does this mean that backends can no longer provide storage for
> D/F-conflicted refnames (i.e., "refs/foo" and "refs/foo/bar")? It looks
> like the global verify_refname_available() has that logic baked in.

The `verify_refname_available()` function implements the "no D/F conflict" policy. But it's called from the backends, not from the common code, and nobody says that a backend needs to call the function.

Show 27 quoted lines
> [...]
>>  int refs_verify_refname_available(struct ref_store *refs,
>>  				  const char *refname,
>> -				  const struct string_list *extra,
>> +				  const struct string_list *extras,
>>  				  const struct string_list *skip,
>>  				  struct strbuf *err)
>>  {
>> [...]
>> +		/*
>> +		 * We are still at a leading dir of the refname (e.g.,
>> +		 * "refs/foo"; if there is a reference with that name,
>> +		 * it is a conflict, *unless* it is in skip.
>> +		 */
>> +		if (skip && string_list_has_string(skip, dirname.buf))
>> +			continue;
>> +
>> +		if (!refs_read_raw_ref(refs, dirname.buf, oid.hash, &referent, &type)) {
>> +			strbuf_addf(err, "'%s' exists; cannot create '%s'",
>> +				    dirname.buf, refname);
>> +			goto cleanup;
>> +		}
> 
> We don't really care about reading the ref value here; we just care if
> it exists. Does that matter for efficiency (e.g., for the files backend
> it's a stat() versus an open/read/close)? I guess the difference only
> matters when it _does_ exist, which is the uncommon error case.

Yes, I assume that the conflict cases are unusual so I wasn't worrying too much about their performance.

Not quite so obvious is that the new code sometimes checks for conflicts against both loose and packed references in situations where the old code only checked against packed references. Specifically, this happens when the code has just read, or locked, or failed to find a loose reference, so it could infer that there are no loose references that could conflict. I don't think that will be noticeable, because it is the reading of the whole `packed-refs` file that is a big expensive operation that it is important to avoid. Anyway, later patches (i.e., after there is a `packed_ref_store`) can switch back to checking only packed references and get back the old optimization.

> (Also, I suspect the loose ref cache always just reads everything in the
> current code, though with the iterator approach in theory we could stop
> doing that).

The loose ref cache reads directories into the cache lazily, breadth-first. So it reads all of the entries in the directories leading to the reference being looked up, but no others. When iterating, it reads the parent directories of the prefix that is being iterated over plus the whole subtree under the prefix, and that's it (though this optimization is not yet wired through to `git for-each-ref`).

Michael
Previous: Jeff KingNext: Michael Haggerty
Message 29 of 38 in “Separate `ref_cache` into a separate module”
  1. 00/20 Separate `ref_cache` into a separate moduleMichael Haggerty, Mar 20, 2017
  2. 01/20 get_ref_dir(): don't call read_loose_refs() for "refs/bisect"Michael Haggerty, Mar 20, 2017
  3. 10/20 ref-cache: introduce a new type, ref_cacheMichael Haggerty, Mar 20, 2017
  4. 13/20 refs: handle "refs/bisect/" in `loose_fill_ref_dir()`Michael Haggerty, Mar 20, 2017
  5. 11/20 refs: record the ref_store in ref_cache, not ref_dirMichael Haggerty, Mar 20, 2017
  6. Jeff KingMar 20, 2017
  7. Michael HaggertyMar 20, 2017
  8. 08/20 Rename `remove_entry()` to `remove_entry_from_dir()`Michael Haggerty, Mar 20, 2017
  9. 18/20 commit_packed_refs(): use reference iterationMichael Haggerty, Mar 20, 2017
  10. Jeff KingMar 20, 2017
  11. Michael HaggertyMar 22, 2017
  12. Jeff KingMar 22, 2017
  13. 20/20 do_for_each_entry_in_dir(): delete functionMichael Haggerty, Mar 20, 2017
  14. 16/20 get_loose_ref_cache(): new functionMichael Haggerty, Mar 20, 2017
  15. 15/20 get_loose_ref_dir(): function renamed from get_loose_refs()Michael Haggerty, Mar 20, 2017
  16. 19/20 files_pack_refs(): use reference iterationMichael Haggerty, Mar 20, 2017
  17. 14/20 do_for_each_entry_in_dir(): eliminate `offset` argumentMichael Haggerty, Mar 20, 2017
  18. 03/20 refs_ref_iterator_begin(): new functionMichael Haggerty, Mar 20, 2017
  19. 17/20 cache_ref_iterator_begin(): make function smarterMichael Haggerty, Mar 20, 2017
  20. 07/20 Rename `find_ref()` to `find_ref_entry()`Michael Haggerty, Mar 20, 2017
  21. 12/20 ref-cache: use a callback function to fill the cacheMichael Haggerty, Mar 20, 2017
  22. 09/20 refs: split `ref_cache` code into separate filesMichael Haggerty, Mar 20, 2017
  23. Jeff KingMar 20, 2017
  24. Junio C HamanoMar 20, 2017
  25. Stefan BellerMar 20, 2017
  26. Junio C HamanoMar 20, 2017
  27. 04/20 refs_verify_refname_available(): implement once for all backendsMichael Haggerty, Mar 20, 2017
  28. Jeff KingMar 20, 2017
  29. Michael HaggertyMar 20, 2017
  30. 02/20 refs_read_raw_ref(): new functionMichael Haggerty, Mar 20, 2017
  31. 06/20 Rename `add_ref()` to `add_ref_entry()`Michael Haggerty, Mar 20, 2017
  32. 05/20 refs_verify_refname_available(): use function in more placesMichael Haggerty, Mar 20, 2017
  33. Junio C HamanoMar 20, 2017
  34. Jeff KingMar 20, 2017
  35. Ævar Arnfjörð BjarmasonMar 20, 2017
  36. Jeff KingMar 20, 2017
  37. Junio C HamanoMar 20, 2017
  38. Michael HaggertyMar 20, 2017

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.